let set_indirect_accessor f = indirect_accessor := f
let register_opacified_constant env opac kn cb = let rec gather_consts s c = match Constr.kind c with
| Constr.Const (c, _) -> Cset.add c s
| _ -> Constr.fold gather_consts s c in let wo_body =
Cset.fold
(fun kn s -> if Declareops.constant_has_body (lookup_constant kn env) then s else match Cmap.find_opt kn opac with
| None -> Cset.add kn s
| Some s' -> Cset.union s' s)
(gather_consts Cset.empty cb)
Cset.empty in
Cmap.add kn wo_body opac
exception BadConstant of Constant.t * Pp.t
let check_constant_declaration env opac kn cb opacify =
Flags.if_verbose Feedback.msg_notice (str " checking cst:" ++ Constant.print kn); let env = CheckFlags.set_local_flags cb.const_typing_flags env in let poly, env = match cb.const_universes with
| Monomorphic -> (* Monomorphic universes are stored at the library level, the
ones in const_universes should not be needed *) false, env
| Polymorphic auctx -> let ctx = UVars.AbstractContext.repr auctx in (* [env] contains De Bruijn universe variables *) let env = push_context ~strict:false ctx env in true, env in let ty = cb.const_type in let jty = Typeops.infer_type env ty in ifnot (Sorts.relevance_equal cb.const_relevance (Sorts.relevance_of_sort jty.utj_type)) thenraise Pp.(BadConstant (kn, str "incorrect const_relevance")); let body, env = match cb.const_body with
| Undef _ | Primitive _ | Symbol _ -> None, env
| Def c -> Some c, env
| OpaqueDef o -> let c, u = !indirect_accessor o in let env = match u, cb.const_universes with
| Opaqueproof.PrivateMonomorphic (), Monomorphic -> env
| Opaqueproof.PrivatePolymorphic local, Polymorphic _ ->
push_subgraph local env
| _ -> assert false in
Some c, env in let () = match body with
| Some bd -> let j = Typeops.infer env bd in beginmatch conv_leq env j.uj_type ty with
| Result.Ok () -> ()
| Result.Error () -> Type_errors.error_actual_type env j ty end
| None -> () in match body with
| Some body when opacify -> register_opacified_constant env opac kn body
| Some _ | None -> opac
let check_quality_mask env qmask lincheck = letopen Sorts.Quality in match qmask with
| PQConstant QSProp -> if Environ.sprop_allowed env then lincheck else Type_errors.error_disallowed_sprop env
| PQConstant (QProp | QType) -> lincheck
| PQVar qio -> Partial_subst.maybe_add_quality qio () lincheck
let check_instance_mask env udecl umask lincheck = match udecl, umask with
| Monomorphic, ([||], [||]) -> lincheck
| Polymorphic uctx, (qmask, umask) -> let lincheck = Array.fold_left_i (fun i lincheck mask -> check_quality_mask env mask lincheck) lincheck qmask in let lincheck = Array.fold_left_i (fun i lincheck mask -> Partial_subst.maybe_add_univ mask () lincheck) lincheck umask in if (Array.length qmask, Array.length umask) <> UVars.AbstractContext.size uctx then CErrors.anomaly Pp.(str "Bad univ mask length.");
lincheck
| _ -> CErrors.anomaly Pp.(str "Bad univ mask length.")
let rec get_holes_profiles env nargs ndecls lincheck el = List.fold_left (get_holes_profiles_elim env nargs ndecls) lincheck el
and get_holes_profiles_elim env nargs ndecls lincheck = function
| PEApp args -> Array.fold_left (get_holes_profiles_parg env nargs ndecls) lincheck args
| PECase (ind, u, ret, brs) -> let mib, mip = Inductive.lookup_mind_specif env ind in let lincheck = check_instance_mask env mib.mind_universes u lincheck in let lincheck = get_holes_profiles_parg env (nargs + mip.mind_nrealargs + 1) (ndecls + mip.mind_nrealdecls + 1) lincheck ret in
Array.fold_left3 (fun lincheck nargs_b ndecls_b -> get_holes_profiles_parg env (nargs + nargs_b) (ndecls + ndecls_b) lincheck) lincheck mip.mind_consnrealargs mip.mind_consnrealdecls brs
| PEProj proj -> let () = lookup_projection (Projection.make proj false) env |> ignore in
lincheck
and get_holes_profiles_parg env nargs ndecls lincheck = function
| EHoleIgnored -> lincheck
| EHole i -> Partial_subst.add_term i nargs lincheck
| ERigid (h, el) -> let lincheck = get_holes_profiles_head env nargs ndecls lincheck h in
get_holes_profiles env nargs ndecls lincheck el
and get_holes_profiles_head env nargs ndecls lincheck = function
| PHRel n -> if n <= ndecls then lincheck else Type_errors.error_unbound_rel env n
| PHSymbol (c, u) -> let cb = lookup_constant c env in
check_instance_mask env cb.const_universes u lincheck
| PHConstr (c, u) -> let (mib, _) = Inductive.lookup_mind_specif env (inductive_of_constructor c) in
check_instance_mask env mib.mind_universes u lincheck
| PHInd (ind, u) -> let (mib, _) = Inductive.lookup_mind_specif env ind in
check_instance_mask env mib.mind_universes u lincheck
| PHInt _ | PHFloat _ | PHString _ -> lincheck
| PHSort PSSProp -> if Environ.sprop_allowed env then lincheck else Type_errors.error_disallowed_sprop env
| PHSort PSType io -> Partial_subst.maybe_add_univ io () lincheck
| PHSort PSQSort (qio, uio) ->
lincheck
|> Partial_subst.maybe_add_quality qio ()
|> Partial_subst.maybe_add_univ uio ()
| PHSort _ -> lincheck
| PHLambda (tys, bod) | PHProd (tys, bod) -> let lincheck = Array.fold_left_i (fun i -> get_holes_profiles_parg env (nargs + i) (ndecls + i)) lincheck tys in let lincheck = get_holes_profiles_parg env (nargs + Array.length tys) (ndecls + Array.length tys) lincheck bod in
lincheck
let check_rhs env holes_profile rhs = let rec check i c = match Constr.kind c with
| App (f, args) when Constr.isRel f -> let n = Constr.destRel f in if n <= i then () else if n - i > Array.length holes_profile then CErrors.anomaly Pp.(str "Malformed right-hand-side substitution site"); let d = holes_profile.(n-i-1) in if Array.length args >= d then () else CErrors.anomaly Pp.(str "Malformed right-hand-side substitution site")
| Rel n when n > i -> if n - i > Array.length holes_profile then CErrors.anomaly Pp.(str "Malformed right-hand-side substitution site"); let d = holes_profile.(n-i-1) in if d = 0 then () else CErrors.anomaly Pp.(str "Malformed right-hand-side substitution site")
| _ -> Constr.iter_with_binders succ check i c in
check 0 rhs
let check_rewrite_rule env lab i (symb, rule) =
Flags.if_verbose Feedback.msg_notice (str " checking rule:" ++ Label.print lab ++ str"#" ++ Pp.int i); let { nvars; lhs_pat; rhs } = rule in let symb_cb = Environ.lookup_constant symb env in let () = match symb_cb.const_body with Symbol _ -> ()
| _ -> ignore @@ invalid_arg "Rule defined on non-symbol" in let lincheck = Partial_subst.make nvars in let lincheck = check_instance_mask env symb_cb.const_universes (fst lhs_pat) lincheck in let lincheck = get_holes_profiles env 0 0 lincheck (snd lhs_pat) in let holes_profile, _, _ = Partial_subst.to_arrays lincheck in let () = check_rhs env holes_profile rhs in
()
(** We currently ignore the [mod_type_alg] and [typ_expr_alg] fields. The only delicate part is when [mod_expr] is an algebraic expression : we need to expand it before checking it is indeed a subtype of [mod_type].
Fortunately, [mod_expr] cannot contain any [MEwith]. *)
let lookup_module mp env = try Environ.lookup_module mp env with Not_found ->
failwith ("Unknown module: "^ModPath.to_string mp)
let mk_mtb sign delta = Mod_declarations.make_module_type sign delta
let rec collect_constants_without_body sign mp accu = let collect_field s lab = function
| SFBconst cb -> let c = Constant.make2 mp lab in if Declareops.constant_has_body cb then s else Cset.add c s
| SFBmodule msb -> collect_constants_without_body (mod_type msb) (MPdot(mp,lab)) s
| SFBmind _ | SFBrules _ | SFBmodtype _ -> s in match sign with
| MoreFunctor _ -> Cset.empty (* currently ignored *)
| NoFunctor struc -> List.fold_left (fun s (lab,mb) -> collect_field s lab mb) accu struc
let rec check_mexpr env opac mse mp_mse res = match mse with
| MEident mp -> let mb = lookup_module mp env in let mb = Modops.strengthen_and_subst_module_body mp mb mp_mse falsein
mod_type mb, mod_delta mb
| MEapply (f,mp) -> let sign, delta = check_mexpr env opac f mp_mse res in let farg_id, farg_b, fbody_b = Modops.destr_functor sign in let mtb = Modops.module_type_of_module (lookup_module mp env) in let state = (Environ.universes env, Conversion.checked_universes) in let _ : UGraph.t = Subtyping.check_subtypes state env mp mtb (MPbound farg_id) farg_b in let subst = Mod_subst.map_mbid farg_id mp (Mod_subst.empty_delta_resolver mp) in
Modops.subst_signature subst mp_mse fbody_b, Mod_subst.subst_codom_delta_resolver subst delta
| MEwith _ -> CErrors.user_err Pp.(str "Unsupported 'with' constraint in module implementation")
let rec check_mexpression env opac sign mbtyp mp_mse res = match sign with
| MEMoreFunctor body -> let arg_id, mtb, mbtyp = Modops.destr_functor mbtyp in let env' = Modops.add_module_parameter arg_id mtb env in let body, delta = check_mexpression env' opac body mbtyp mp_mse res in
MoreFunctor(arg_id,mtb,body), delta
| MENoFunctor me -> check_mexpr env opac me mp_mse res
let rec check_module env opac mp mb opacify =
Flags.if_verbose Feedback.msg_notice (str " checking module: " ++ str (ModPath.to_string mp)); let env = Modops.add_retroknowledge (mod_retroknowledge mb) env in let delta_mb = mod_delta mb in let opac =
check_signature env opac (mod_type mb) mp delta_mb opacify in let optsign, opac = match Mod_declarations.mod_expr mb with
| Struct sign_struct -> let opacify = collect_constants_without_body (mod_type mb) mp opacify in (* TODO: a bit wasteful, we recheck the types of parameters twice *) let sign_struct = Modops.annotate_struct_body sign_struct (mod_type mb) in let opac = check_signature env opac sign_struct mp delta_mb opacify in
Some (sign_struct, delta_mb), opac
| Algebraic me -> Some (check_mexpression env opac me (mod_type mb) mp delta_mb), opac
| Abstract|FullStruct -> None, opac in let () = match optsign with
| None -> ()
| Some (sign,delta) -> let mtb1 = mk_mtb sign delta and mtb2 = mk_mtb (mod_type mb) delta_mb in let state = (Environ.universes env, Conversion.checked_universes) in let _ : UGraph.t = Subtyping.check_subtypes state env mp mtb1 mp mtb2 in
() in
opac
and check_structure_field env opac mp lab res opacify = function
| SFBconst cb -> let kn = KerName.make mp lab in let kn = Mod_subst.constant_of_delta_kn res kn in
check_constant_declaration env opac kn cb (Cset.mem kn opacify)
| SFBmind mib -> let kn = KerName.make mp lab in let kn = Mod_subst.mind_of_delta_kn res kn in
CheckInductive.check_inductive env kn mib, opac
| SFBmodule msb -> let mp = MPdot(mp, lab) in let opac = check_module env opac mp msb opacify in
Modops.add_module mp msb env, opac
| SFBmodtype mty -> let mp = MPdot (mp, lab) in let () = check_module_type env mp mty in
add_modtype mp mty env, opac
| SFBrules rrb ->
check_rewrite_rules_body env lab rrb;
Environ.add_rewrite_rules rrb.rewrules_rules env, opac
and check_signature env opac sign mp_mse res opacify = match sign with
| MoreFunctor (arg_id, mtb, body) -> let () = check_module_type env (MPbound arg_id) mtb in let env' = Modops.add_module_parameter arg_id mtb env in let opac = check_signature env' opac body mp_mse res Cset.empty in
opac
| NoFunctor struc -> let (_:env), opac = List.fold_left (fun (env, opac) (lab,mb) ->
check_structure_field env opac mp_mse lab res opacify mb) (env, opac) struc in
opac