(************************************************************************) (* * The Coq Proof Assistant / The Coq Development Team *) (* v * Copyright INRIA, CNRS and contributors *) (* sigma, body | Some red -> let red, _ = reduction_of_red_expr env red in red env sigma body let warn_implicits_in_term = CWarnings.create ~name:"implicits-in-term" ~category:"implicits" (fun () -> strbrk "Implicit arguments declaration relies on type." ++ spc () ++ strbrk "Discarding incompatible declaration in term.") let check_imps ~impsty ~impsbody = let rec aux impsty impsbody = match impsty, impsbody with | a1 :: impsty, a2 :: impsbody -> (match a1.CAst.v, a2.CAst.v with | None , None -> aux impsty impsbody | Some _ , Some _ -> aux impsty impsbody | _, _ -> warn_implicits_in_term ?loc:a2.CAst.loc ()) | _ :: _, [] | [], _ :: _ -> (* Information only on one side *) () | [], [] -> () in aux impsty impsbody let protect_pattern_in_binder bl c ctypopt = (* We turn "Definition d binders := body : typ" into *) (* "Definition d := fun binders => body:type" *) (* This is a hack while waiting for LocalPattern in regular environments *) if List.exists (function Constrexpr.CLocalPattern _ -> true | _ -> false) bl then let t = match ctypopt with | None -> CAst.make ?loc:c.CAst.loc (Constrexpr.CHole (None,Namegen.IntroAnonymous,None)) | Some t -> t in let loc = Loc.merge_opt c.CAst.loc t.CAst.loc in let c = CAst.make ?loc @@ Constrexpr.CCast (c, Glob_term.CastConv t) in let loc = match List.hd bl with | Constrexpr.CLocalAssum (a::_,_,_) | Constrexpr.CLocalDef (a,_,_) -> a.CAst.loc | Constrexpr.CLocalPattern {CAst.loc} -> loc | Constrexpr.CLocalAssum ([],_,_) -> assert false in let apply_under_binders f env evd c = let rec aux env evd c = let open Constr in let open EConstr in let open Context.Rel.Declaration in match kind evd c with | Lambda (x,t,c) -> let evd,c = aux (push_rel (LocalAssum (x,t)) env) evd c in evd, mkLambda (x,t,c) | LetIn (x,b,t,c) -> let evd,c = aux (push_rel (LocalDef (x,b,t)) env) evd c in evd, mkLetIn (x,t,b,c) | Case (ci,p,a,bl) -> let evd,bl = Array.fold_left_map (aux env) evd bl in evd, mkCase (ci,p,a,bl) | Cast (c,_,_) -> f env evd c (* we remove the cast we had set *) (* This last case may happen when reaching the proof of an impossible case, as when pattern-matching on a vector of length 1 *) | _ -> (evd,c) in aux env evd c in ([], Constrexpr_ops.mkLambdaCN ?loc:(Loc.merge_opt loc c.CAst.loc) bl c, None, apply_under_binders) else (bl, c, ctypopt, fun f env evd c -> f env evd c) let interp_definition ~program_mode pl bl ~poly red_option c ctypopt = let env = Global.env() in (* Explicitly bound universes and constraints *) let evd, udecl = Constrexpr_ops.interp_univ_decl_opt env pl in let (bl, c, ctypopt, apply_under_binders) = protect_pattern_in_binder bl c ctypopt in (* Build the parameters *) let evd, (impls, ((env_bl, ctx), imps1)) = interp_context_evars ~program_mode env evd bl in (* Build the type *) let evd, tyopt = Option.fold_left_map (interp_type_evars_impls ~program_mode ~impls env_bl) evd ctypopt in (* Build the body, and merge implicits from parameters and from type/body *) let evd, c, imps, tyopt = match tyopt with | None -> let evd, (c, impsbody) = interp_constr_evars_impls ~program_mode ~impls env_bl evd c in evd, c, imps1@impsbody, None | Some (ty, impsty) -> let evd, (c, impsbody) = interp_casted_constr_evars_impls ~program_mode ~impls env_bl evd c ty in check_imps ~impsty ~impsbody; evd, c, imps1@impsty, Some ty in (* Do the reduction *) let evd, c = apply_under_binders (red_constant_body red_option) env_bl evd c in (* Declare the definition *) let c = EConstr.it_mkLambda_or_LetIn c ctx in let tyopt = Option.map (fun ty -> EConstr.it_mkProd_or_LetIn ty ctx) tyopt in let evd, ce = DeclareDef.prepare_definition ~allow_evars:program_mode ~opaque:false ~poly evd ~udecl ~types:tyopt ~body:c in (ce, evd, udecl, imps) let check_definition ~program_mode (ce, evd, _, imps) = let env = Global.env () in check_evars_are_solved ~program_mode env evd; ce let do_definition ~program_mode ?hook ~name ~scope ~poly ~kind udecl bl red_option c ctypopt = let (ce, evd, udecl, impargs as def) = interp_definition ~program_mode udecl bl ~poly red_option c ctypopt in if program_mode then let env = Global.env () in let (c,ctx), sideff = Future.force ce.Declare.proof_entry_body in assert(Safe_typing.empty_private_constants = sideff.Evd.seff_private); assert(Univ.ContextSet.is_empty ctx); Obligations.check_evars env evd; let c = EConstr.of_constr c in let typ = match ce.Declare.proof_entry_type with | Some t -> EConstr.of_constr t | None -> Retyping.get_type_of env evd c in let obls, _, c, cty = Obligations.eterm_obligations env name evd 0 c typ in let uctx = Evd.evar_universe_context evd in ignore(Obligations.add_definition ~name ~term:c cty ~uctx ~udecl ~impargs ~scope ~poly ~kind ?hook obls) else let ce = check_definition ~program_mode def in let uctx = Evd.evar_universe_context evd in let hook_data = Option.map (fun hook -> hook, uctx, []) hook in let kind = Decls.IsDefinition kind in ignore(DeclareDef.declare_definition ~name ~scope ~kind ?hook_data ~ubind:(Evd.universe_binders evd) ce ~impargs)