diff options
author | coq <coq@85f007b7-540e-0410-9357-904b9bb8a0f7> | 2006-02-20 17:34:11 +0000 |
---|---|---|
committer | coq <coq@85f007b7-540e-0410-9357-904b9bb8a0f7> | 2006-02-20 17:34:11 +0000 |
commit | c0559a85d38941945c36e2d1b5f6691c510e846f (patch) | |
tree | 78741a153dbd823a7975b120b0899fa0c032a649 /contrib | |
parent | 51c078b1cb9e052d32f7f4df3fb70d1fc5968be1 (diff) |
Monday work, working with coercions and implicit args
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@8067 85f007b7-540e-0410-9357-904b9bb8a0f7
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/subtac/context.ml | 2 | ||||
-rw-r--r-- | contrib/subtac/interp.ml | 1116 | ||||
-rw-r--r-- | contrib/subtac/scoq.ml | 38 |
3 files changed, 617 insertions, 539 deletions
diff --git a/contrib/subtac/context.ml b/contrib/subtac/context.ml index dc19ff9ee..9ea5e7501 100644 --- a/contrib/subtac/context.ml +++ b/contrib/subtac/context.ml @@ -43,3 +43,5 @@ let names_context_of ctx = let env_of_ctx env (ctx : t) = Environ.push_rel_context ctx env + +let subst_env env c = (env, c) diff --git a/contrib/subtac/interp.ml b/contrib/subtac/interp.ml index b6b763055..1be49ef27 100644 --- a/contrib/subtac/interp.ml +++ b/contrib/subtac/interp.ml @@ -1,42 +1,44 @@ -open Term -open Evarutil -open Evd -open Libnames +(************************************************************************) +(* v * The Coq Proof Assistant / The Coq Development Team *) +(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *) +(* \VV/ **************************************************************) +(* // * This file is distributed under the terms of the *) +(* * GNU Lesser General Public License Version 2.1 *) +(************************************************************************) + +(* $Id$ *) + open Global +open Pp +open Util open Names +open Sign +open Evd +open Term +open Termops +open Reductionops +open Environ +open Type_errors +open Typeops +open Libnames +open Classops +open List +open Recordops +open Evarutil +open Pretype_errors +open Rawterm +open Evarconv +open Coercion +open Pattern +open Dyn + open Scoq open Coqlib -open Pp open Printer open Subtac_errors -open Util -open Rawterm open Context open Eterm -(* match t with - | RRef(loc, gr) -> - | RVar(loc, id) -> - | REvar(loc, e_key, arglopt) -> - | RPatVar(loc, (b * pvar)) -> - | RApp(loc, fn, args) -> - | RLambda(loc, name, typ, body) -> - | RProd(loc, name, dom, codom) -> - | RLetIn(loc, var, def, body) -> - | RLetTuple(loc, names, (name, expr), def, body) -> - | RIf(loc, cond, (name, expr), bodyl, bodyr) -> - | RRec(loc, fix_kind, identifiersarr, rawdecllistarray, - rawconstrarray, rawconstrarray) -> - | RSort(loc, rsort) -> - | RHole(loc, hole_kind) -> - | RCast(loc, expr, cast_kind, toexpr) -> - | RCases _ (* of loc * rawconstr option * - (rawconstr * (name * (loc * inductive * name list) option)) list * - (loc * identifier list * cases_pattern list * rawconstr) list *) -> - | RDynamic(loc, dynobj) -> - *) - - type recursion_info = { arg_name: identifier; arg_type: types; (* A *) @@ -52,467 +54,524 @@ type prog_info = { rec_info: recursion_info option; } -let my_print_constr env ctx term = - Termops.print_constr_env (env_of_ctx env ctx) term - -let my_print_context env ctx = - Termops.print_rel_context (env_of_ctx env ctx) - -let my_print_rawconstr env ctx term = - Printer.pr_rawconstr_env (env_of_ctx env ctx) term - -let filter_defs l = List.filter (fun (_, c, _) -> c = None) l - -let evar_args ctx = - let rec aux acc i = function - (_, c, _) :: tl -> - (match c with - | None -> aux (mkRel i :: acc) (succ i) tl - | Some _ -> aux acc (succ i) tl) - | [] -> acc - in Array.of_list (aux [] 1 ctx) - -let evar_ctx prog_info ctx = - let ctx' = - match prog_info.rec_info with - Some ri -> - let len = List.length ctx in - assert(len >= 2); - let rec aux l acc = function - 0 -> - (match l with - (id, _, recf) :: arg :: [] -> arg :: (id, None, ri.f_fulltype) :: acc - | _ -> assert(false)) - | n -> (match l with - hd :: tl -> aux tl (hd :: acc) (pred n) - | _ -> assert(false)) - in - List.rev (aux ctx [] (len - 2)) - | None -> ctx - in filter_defs ctx' - - -let lookup_local env ctx (loc, id) = - try - let name = Name id in - let index, term, typ = Context.assoc_and_index name ctx in - let index = succ index in - let typ' = lift index typ in - debug 3 (str "Resolved " ++ str (string_of_id id) ++ str " locally as rel " ++ int index ++ str " : " ++ - my_print_constr env ctx typ' ++ str " in context: " ++ - my_print_context env ctx); - mkRel index, typ' + +(* Taken from pretyping.ml *) +let evd_comb0 f isevars = + let (evd',x) = f !isevars in + isevars := evd'; + x +let evd_comb1 f isevars x = + let (evd',y) = f !isevars x in + isevars := evd'; + y +let evd_comb2 f isevars x y = + let (evd',z) = f !isevars x y in + isevars := evd'; + z +let evd_comb3 f isevars x y z = + let (evd',t) = f !isevars x y z in + isevars := evd'; + t + +(************************************************************************) +(* This concerns Cases *) +open Declarations +open Inductive +open Inductiveops + +(************************************************************************) + +let mt_evd = Evd.empty + +let vect_lift_type = Array.mapi (fun i t -> type_app (lift i) t) + +(* Utilisé pour inférer le prédicat des Cases *) +(* Semble exagérement fort *) +(* Faudra préférer une unification entre les types de toutes les clauses *) +(* et autoriser des ? à rester dans le résultat de l'unification *) + +let evar_type_fixpoint loc env isevars lna lar vdefj = + let lt = Array.length vdefj in + if Array.length lar = lt then + for i = 0 to lt-1 do + if not (e_cumul env isevars (vdefj.(i)).uj_type + (lift lt lar.(i))) then + error_ill_typed_rec_body_loc loc env (evars_of !isevars) + i lna vdefj lar + done + +let check_branches_message loc env isevars c (explft,lft) = + for i = 0 to Array.length explft - 1 do + if not (e_cumul env isevars lft.(i) explft.(i)) then + let sigma = evars_of !isevars in + error_ill_formed_branch_loc loc env sigma c i lft.(i) explft.(i) + done + +(* coerce to tycon if any *) +let inh_conv_coerce_to_tycon loc env isevars j = function + | None -> j + | Some typ -> evd_comb2 (inh_conv_coerce_to loc env) isevars j typ + +let push_rels vars env = List.fold_right push_rel vars env + +let strip_meta id = (* For Grammar v7 compatibility *) + let s = string_of_id id in + if s.[0]='$' then id_of_string (String.sub s 1 (String.length s - 1)) + else id + +let pretype_id loc env (lvar,unbndltacvars) id = + let id = strip_meta id in (* May happen in tactics defined by Grammar *) + try + let (n,typ) = lookup_rel_id id (rel_context env) in + { uj_val = mkRel n; uj_type = type_app (lift n) typ } with Not_found -> - try - let (n,typ) = Termops.lookup_rel_id id (Environ.rel_context env) in - let index = List.length ctx + n in - mkRel index, (lift index) typ + try + List.assoc id lvar with Not_found -> try - let (_,_,typ) = Environ.lookup_named id env in - mkVar id, typ + let (_,_,typ) = lookup_named id env in + { uj_val = mkVar id; uj_type = typ } with Not_found -> - Pretype_errors.error_var_not_found_loc loc id - -let pair_of_array a = (a.(0), a.(1)) -let make_name s = Name (id_of_string s) - -let app_opt c e = - match c with - Some constr -> constr e - | None -> e - -let rec disc_subset x = - match kind_of_term x with - | App (c, l) -> - (match kind_of_term c with - Ind i -> - let len = Array.length l in - let sig_ = Lazy.force sig_ in - if len = 2 && i = Term.destInd sig_.typ - then - let (a, b) = pair_of_array l in - Some (a, b) - else None - | _ -> None) - | _ -> None - -and disc_exist env ctx x = - trace (str "Disc_exist: " ++ my_print_constr env ctx x); - match kind_of_term x with - | App (c, l) -> - (match kind_of_term c with - Construct c -> - if c = Term.destConstruct (Lazy.force sig_).intro - then Some (l.(0), l.(1), l.(2), l.(3)) - else None - | _ -> None) - | _ -> None - - -let disc_proj_exist env ctx x = - trace (str "disc_proj_exist: " ++ my_print_constr env ctx x); - match kind_of_term x with - | App (c, l) -> - (if Term.eq_constr c (Lazy.force sig_).proj1 - && Array.length l = 3 - then disc_exist env ctx l.(2) - else None) - | _ -> None - - -let sort_rel s1 s2 = - match s1, s2 with - Prop Pos, Prop Pos -> Prop Pos - | Prop Pos, Prop Null -> Prop Null - | Prop Null, Prop Null -> Prop Null - | Prop Null, Prop Pos -> Prop Pos - | Type _, Prop Pos -> Prop Pos - | Type _, Prop Null -> Prop Null - | _, Type _ -> s2 - -let rec mu prog_info env ctx t = - match disc_subset t with - Some (u, p) -> - let f, ct = mu prog_info env ctx u in - (Some (fun x -> - app_opt f (mkApp ((Lazy.force sig_).proj1, - [| u; p; x |]))), - ct) - | None -> (None, t) - -and coerce prog_info env ctx (x : Term.constr) (y : Term.constr) - : (Term.constr -> Term.constr) option - = - let rec coerce_unify ctx etyp argtyp = - match kind_of_term etyp, kind_of_term argtyp with - Evar (ev, args), _ -> - let evm = evars_of !(prog_info.evd) in - (*if is_defined evm ev then - coerce' ctx etyp (existential_value evm (ev, args)) - else ( *) - prog_info.evd := evar_define ev argtyp !(prog_info.evd); - debug 1 (str "Defining evar (evar to type) " ++ int ev ++ str " := " ++ my_print_constr env ctx argtyp); - None - | _, Evar (ev, args) -> - let evm = evars_of !(prog_info.evd) in - if is_defined evm ev then - coerce' ctx etyp (existential_value evm (ev, args)) - else ( - debug 1 (str "Defining evar (term to evar)" ++ int ev ++ str " := " ++ my_print_constr env ctx etyp); - prog_info.evd := evar_define ev etyp !(prog_info.evd); - None) - | _, _ -> coerce' ctx etyp argtyp - and coerce' ctx x y : (Term.constr -> Term.constr) option = - let subco () = subset_coerce ctx x y in - trace (str "Coercion from " ++ (my_print_constr env ctx x) ++ - str " to "++ my_print_constr env ctx y); - match (kind_of_term x, kind_of_term y) with - | Sort s, Sort s' -> - (match s, s' with - Prop x, Prop y when x = y -> None - | Prop _, Type _ -> None - | Type x, Type y when x = y -> None (* false *) - | _ -> subco ()) - | Prod (name, a, b), Prod (name', a', b') -> - let c1 = coerce_unify ctx a' a in - let c2 = coerce_unify ((name', None, a') :: ctx) b b' in - (match c1, c2 with - None, None -> None - | _, _ -> - Some - (fun f -> - mkLambda (name', a', - app_opt c2 - (mkApp (Term.lift 1 f, - [| app_opt c1 (mkRel 1) |]))))) - - | App (c, l), App (c', l') -> - (match kind_of_term c, kind_of_term c' with - Ind i, Ind i' -> - let len = Array.length l in - let existS = Lazy.force existS in - if len = Array.length l' && len = 2 - && i = i' && i = Term.destInd existS.typ - then - begin (* Sigma types *) - debug 1 (str "In coerce sigma types"); - let (a, pb), (a', pb') = - pair_of_array l, pair_of_array l' - in - let c1 = coerce_unify ctx a a' in - let remove_head c = - let (_, _, x) = Term.destProd c in - x - in - let b, b' = remove_head pb, remove_head pb' in - let ctx' = (make_name "x", None, a) :: ctx in - let c2 = coerce_unify ctx' b b' in - match c1, c2 with - None, None -> None - | _, _ -> - Some - (fun x -> - let x, y = - app_opt c1 (mkApp (existS.proj1, - [| a; pb; x |])), - app_opt c2 (mkApp (existS.proj2, - [| a; pb'; x |])) - in - mkApp (existS.intro, [| x ; y |])) - end - else subco () - | _ -> subco ()) - | _, _ -> subco () - - and subset_coerce ctx x y = - match disc_subset x with - Some (u, p) -> - let c = coerce_unify ctx u y in - let f x = - app_opt c (mkApp ((Lazy.force sig_).proj1, - [| u; p; x |])) - in Some f - | None -> - match disc_subset y with - Some (u, p) -> - let c = coerce_unify ctx x u in - let evarinfo x = - let cx = app_opt c x in - let pcx = mkApp (p, [| cx |]) in - let ctx', pcx' = subst_ctx ctx pcx in - cx, { - Evd.evar_concl = pcx'; - Evd.evar_hyps = - Environ.val_of_named_context (evar_ctx prog_info ctx'); - Evd.evar_body = Evd.Evar_empty; - } - in - Some - (fun x -> - let key = mknewexist () in - let cx, evi = evarinfo x in - prog_info.evm <- Evd.add prog_info.evm key evi; - (mkApp - ((Lazy.force sig_).intro, - [| u; p; cx; - mkEvar (key, evar_args ctx) |]))) - | None -> - (try - let cstrs = Reduction.conv (Global.env ()) x y - in - ignore(Univ.merge_constraints cstrs (Global.universes ())); - Some (fun x -> - mkCast (x, DEFAULTcast, y)) - with - Reduction.NotConvertible -> - subtyping_error - (UncoercibleRewrite (my_print_constr env ctx x, - my_print_constr env ctx y)) - | e -> raise e) + try (* To build a nicer ltac error message *) + match List.assoc id unbndltacvars with + | None -> user_err_loc (loc,"", + str (string_of_id id ^ " ist not bound to a term")) + | Some id0 -> Pretype_errors.error_var_not_found_loc loc id0 + with Not_found -> + error_var_not_found_loc loc id +(* make a dependent predicate from an undependent one *) +let make_dep_of_undep env (IndType (indf,realargs)) pj = + let n = List.length realargs in + let rec decomp n p = + if n=0 then p else + match kind_of_term p with + | Lambda (_,_,c) -> decomp (n-1) c + | _ -> decomp (n-1) (applist (lift 1 p, [mkRel 1])) in - try ignore(Reduction.conv_leq (Global.env ()) x y); None - with Reduction.NotConvertible -> coerce_unify ctx x y (* head recutions needed *) - - -and interp prog_info env ctx t : constr * constr (* The term -> its coq translation, its coq (not algorithmic) type *) = - let error s = anomaly ("subtac.interp: " ^ s) in - debug 1 (str "Interpreting term: " ++ my_print_rawconstr env ctx t ++ str " in env : " ++ - my_print_context env ctx); - - let rec type_app ctx (locf, coqf, ftyp) (e : rawconstr) = - let coercef, support = mu prog_info env ctx ftyp in - let narg, argtyp, restyp = - try - match decompose_prod_n 1 support with - [x, y], z -> x, y, z - | _ -> typing_error (NonFunctionalApp (locf, my_print_constr env ctx coqf, my_print_constr env ctx support, - my_print_rawconstr env ctx e)) - with _ -> typing_error (NonFunctionalApp (locf, my_print_constr env ctx coqf, my_print_constr env ctx support, - my_print_rawconstr env ctx e)) - in - let coqe, etyp = aux ctx e in - let _ = debug 2 (str "Coercion for application: " ++ - my_print_constr env ctx coqf ++ str " : " ++ - my_print_constr env ctx ftyp ++ str " and " ++ - my_print_constr env ctx coqe ++ str " : " ++ - my_print_constr env ctx etyp) - in - let coercee = coerce prog_info env ctx etyp argtyp in - let coqe' = app_opt coercee coqe in - let restype' = Term.subst1 coqe' restyp in - let call = - let len = List.length ctx in - let cf = app_opt coercef coqf in - match prog_info.rec_info with - Some r -> - (match kind_of_term cf with - Rel i when i = (pred len) -> - debug 3 (str "Spotted recursive call!"); - let ctx', proof = - subst_ctx ctx (mkApp (r.wf_relation, - [| coqe'; mkRel len |])) - in - let evarinfo = - { - Evd.evar_concl = proof; - Evd.evar_hyps = - Environ.val_of_named_context - (evar_ctx prog_info ctx'); - Evd.evar_body = Evd.Evar_empty; - } - in - let key = mknewexist () in - prog_info.evm <- Evd.add prog_info.evm key evarinfo; - mkApp (cf, [| coqe'; mkEvar(key, evar_args ctx) |]) - | _ -> mkApp (cf, [| coqe' |])) - | None -> mkApp (cf, [| coqe' |]) - in - debug 2 (str "Term obtained after coercion (at application): " ++ - Termops.print_constr_env (env_of_ctx env ctx) call); - call, restype' - - and aux ctx = function - | RRef(loc, gr) -> - (match gr with - | VarRef var -> - let coqt = type_of_global gr in - mkVar var, coqt - | ConstRef const -> - let coqt = type_of_global gr in - mkConst const, coqt - | IndRef ind -> - let coqt = type_of_global gr in - mkInd ind, coqt - | ConstructRef constr -> - let coqt = type_of_global gr in - mkConstruct constr, coqt) - - | RVar(loc, id) -> lookup_local env ctx (loc, id) + let sign,s = decompose_prod_n n pj.uj_type in + let ind = build_dependent_inductive env indf in + let s' = mkProd (Anonymous, ind, s) in + let ccl = lift 1 (decomp n pj.uj_val) in + let ccl' = mkLambda (Anonymous, ind, ccl) in + {uj_val=lam_it ccl' sign; uj_type=prod_it s' sign} + +(*************************************************************************) +(* Main pretyping function *) + +let pretype_ref isevars env ref = + let c = constr_of_global ref in + make_judge c (Retyping.get_type_of env Evd.empty c) + +let pretype_sort = function + | RProp c -> judge_of_prop_contents c + | RType _ -> judge_of_new_Type () + +(* [pretype tycon env isevars lvar lmeta cstr] attempts to type [cstr] *) +(* in environment [env], with existential variables [(evars_of isevars)] and *) +(* the type constraint tycon *) +let rec pretype tycon env isevars lvar = function + + | RRef (loc,ref) -> + inh_conv_coerce_to_tycon loc env isevars + (pretype_ref isevars env ref) + tycon + + | RVar (loc, id) -> + inh_conv_coerce_to_tycon loc env isevars + (pretype_id loc env lvar id) + tycon + + | REvar (loc, ev, instopt) -> + (* Ne faudrait-il pas s'assurer que hyps est bien un + sous-contexte du contexte courant, et qu'il n'y a pas de Rel "caché" *) + let hyps = evar_context (Evd.map (evars_of !isevars) ev) in + let args = match instopt with + | None -> instance_from_named_context hyps + | Some inst -> failwith "Evar subtitutions not implemented" in + let c = mkEvar (ev, args) in + let j = (Retyping.get_judgment_of env (evars_of !isevars) c) in + inh_conv_coerce_to_tycon loc env isevars j tycon + + | RPatVar (loc,(someta,n)) -> + anomaly "Found a pattern variable in a rawterm to type" + + | RHole (loc,k) -> + let ty = + match tycon with + | Some ty -> ty + | None -> + e_new_evar isevars env ~src:(loc,InternalHole) (new_Type ()) in + { uj_val = e_new_evar isevars env ~src:(loc,k) ty; uj_type = ty } + + | RRec (loc,fixkind,names,bl,lar,vdef) -> + let rec type_bl env ctxt = function + [] -> ctxt + | (na,None,ty)::bl -> + let ty' = pretype_type empty_valcon env isevars lvar ty in + let dcl = (na,None,ty'.utj_val) in + type_bl (push_rel dcl env) (add_rel_decl dcl ctxt) bl + | (na,Some bd,ty)::bl -> + let ty' = pretype_type empty_valcon env isevars lvar ty in + let bd' = pretype (mk_tycon ty'.utj_val) env isevars lvar ty in + let dcl = (na,Some bd'.uj_val,ty'.utj_val) in + type_bl (push_rel dcl env) (add_rel_decl dcl ctxt) bl in + let ctxtv = Array.map (type_bl env empty_rel_context) bl in + let larj = + array_map2 + (fun e ar -> + pretype_type empty_valcon (push_rel_context e env) isevars lvar ar) + ctxtv lar in + let lara = Array.map (fun a -> a.utj_val) larj in + let ftys = array_map2 (fun e a -> it_mkProd_or_LetIn a e) ctxtv lara in + let nbfix = Array.length lar in + let names = Array.map (fun id -> Name id) names in + (* Note: bodies are not used by push_rec_types, so [||] is safe *) + let newenv = push_rec_types (names,ftys,[||]) env in + let vdefj = + array_map2_i + (fun i ctxt def -> + (* we lift nbfix times the type in tycon, because of + * the nbfix variables pushed to newenv *) + let (ctxt,ty) = + decompose_prod_n_assum (rel_context_length ctxt) + (lift nbfix ftys.(i)) in + let nenv = push_rel_context ctxt newenv in + let j = pretype (mk_tycon ty) nenv isevars lvar def in + { uj_val = it_mkLambda_or_LetIn j.uj_val ctxt; + uj_type = it_mkProd_or_LetIn j.uj_type ctxt }) + ctxtv vdef in + evar_type_fixpoint loc env isevars names ftys vdefj; + let fixj = + match fixkind with + | RFix (vn,i as vni) -> + let fix = (vni,(names,ftys,Array.map j_val vdefj)) in + (try check_fix env fix with e -> Stdpp.raise_with_loc loc e); + make_judge (mkFix fix) ftys.(i) + | RCoFix i -> + let cofix = (i,(names,ftys,Array.map j_val vdefj)) in + (try check_cofix env cofix with e -> Stdpp.raise_with_loc loc e); + make_judge (mkCoFix cofix) ftys.(i) in + inh_conv_coerce_to_tycon loc env isevars fixj tycon + + | RSort (loc,s) -> + inh_conv_coerce_to_tycon loc env isevars (pretype_sort s) tycon + + | RApp (loc,f,args) -> + let fj = pretype empty_tycon env isevars lvar f in + let floc = loc_of_rawconstr f in + let rec apply_rec env n resj = function + | [] -> resj + | c::rest -> + let argloc = loc_of_rawconstr c in + let resj = evd_comb1 (inh_app_fun env) isevars resj in + let resty = + whd_betadeltaiota env (evars_of !isevars) resj.uj_type in + let coercef, resty = Subtac_coercion.mu env isevars resj in + match kind_of_term resty with + | Prod (na,c1,c2) -> + let hj = pretype (mk_tycon c1) env isevars lvar c in + let newresj = + { uj_val = applist (app_opt coercef (j_val resj), [j_val hj]); + uj_type = subst1 hj.uj_val c2 } in + apply_rec env (n+1) newresj rest + + | _ -> + let hj = pretype empty_tycon env isevars lvar c in + error_cant_apply_not_functional_loc + (join_loc floc argloc) env (evars_of !isevars) + resj [hj] + in let resj = apply_rec env 1 fj args in + inh_conv_coerce_to_tycon loc env isevars resj tycon + + | RLambda(loc,name,c1,c2) -> + let (name',dom,rng) = evd_comb1 (split_tycon loc env) isevars tycon in + let dom_valcon = valcon_of_tycon dom in + let j = pretype_type dom_valcon env isevars lvar c1 in + let var = (name,None,j.utj_val) in + let j' = pretype rng (push_rel var env) isevars lvar c2 in + judge_of_abstraction env name j j' + + | RProd(loc,name,c1,c2) -> + let j = pretype_type empty_valcon env isevars lvar c1 in + let var = (name,j.utj_val) in + let env' = push_rel_assum var env in + let j' = pretype_type empty_valcon env' isevars lvar c2 in + let resj = + try judge_of_product env name j j' + with TypeError _ as e -> Stdpp.raise_with_loc loc e in + inh_conv_coerce_to_tycon loc env isevars resj tycon - | RApp(loc, fn, args) as x -> - let loc = loc_of_rawconstr fn in - debug 1 (str "Interpreting application: " ++ my_print_rawconstr env ctx x); - let coqfn, fntyp = aux ctx fn in -(* let coqfn, fntyp, args = - match kind_of_term coqfn with - Ind i -> - let len = List.length args in - debug 1 (my_print_constr env ctx coqfn ++ str " inductive applied to " ++ int len ++ str " arguments: " ++ - List.fold_left (fun acc arg -> acc ++ str " " ++ my_print_rawconstr env ctx arg) (str "") args - ); - let sig_ = Lazy.force sig_ in - if len = 2 && i = Term.destInd sig_.typ - then - let b = match args with [a;b] -> b | _ -> error "Partially applied subset type constructor" in - let coqb, btyp = aux ctx b in - (match kind_of_term coqb with - | Lambda (n, t, b) -> - mkApp (coqfn, [|t; coqb|]), mkSort (mk_Set), [] - | _ -> - debug 1 (my_print_constr env ctx btyp ++ str " is not a lambda") ; - error "Ill-typed subset type: ") - else if len = 3 && i = Term.destInd (Lazy.force eqind) - then - let b,c = match args with [a;b;c] -> b,c | _ -> error "Partially applied eq type constructor" in - let coqb, btyp = aux ctx b in - mkApp (coqfn, [|btyp; coqb|]), mkProd (Anonymous, btyp, mkSort (mk_Prop)), [c] - else ( - debug 1 (str "Not an eq or sig: " ++ my_print_constr env ctx coqfn); - coqfn, fntyp, args) - | x -> - debug 1 (str "Not an inductive: " ++ my_print_constr env ctx coqfn); - coqfn, fntyp, args - in*) - let _, term, typ = - List.fold_left (fun (loc, coqfn, fntyp) (e : rawconstr) -> - let coqfn', fntyp' = type_app ctx (loc, coqfn, fntyp) e in - join_loc loc (loc_of_rawconstr e), coqfn', fntyp') - (loc, coqfn, fntyp) args - in term, typ - - | RLambda(loc, name, argtyp, body) -> - let coqargtyp, argtyptyp = aux ctx argtyp in - let coqbody, bodytyp = aux ((name, None, coqargtyp) :: ctx) body in - let prod = mkProd (name, coqargtyp, bodytyp) in - (* Check it is well sorted *) - (*let coqprod, prodtyp = aux ctx prod in - if not (isSort prodtyp) then - typing_error (IllSorted (loc, my_print_constr env ctx prodtyp));*) - let coqlambda = mkLambda (name, coqargtyp, coqbody) in - (coqlambda, prod) - - | RProd(loc, name, dom, codom) -> - let coqdom, domtyp = aux ctx dom in - let coqcodom, codomtyp = aux ((name, None, coqdom) :: ctx) codom in - let s1, s2 = destSort domtyp, destSort codomtyp in - let s3 = sort_rel s1 s2 in - mkProd (name, coqdom, coqcodom), mkSort s3 - - | RLetIn(loc, var, def, body) -> - let coqdef, deftyp = aux ctx def in - let coqbody, bodytyp = aux ((var, Some coqdef, deftyp) :: ctx) body in - mkLetIn (var, coqdef, deftyp, coqbody), - Term.subst1 coqdef bodytyp - - | RLetTuple(loc, names, (name, expr), def, body) -> error "Let tuple : Not implemented" - - | RIf(loc, cond, (name, expr), bodyl, bodyr) -> - error "If: not implemented" - - | RRec(loc, fix_kind, identifiersarr, rawdecllistarray, - rawconstrarray, rawconstrarray2) -> - error "Rec : Not implemented" - - | RSort(loc, rsort) -> - let x, y = - (match rsort with - RProp Pos -> mk_Set, type_0 - | RProp Null -> mk_Prop, type_0 - | RType None -> type_0, type_0 - | RType (Some u) -> Type u, type_0) - in mkSort x, mkSort y - - | RHole(loc, k) -> - let ty = Evarutil.e_new_evar prog_info.evd env ~src:(loc,InternalHole) (Termops.new_Type ()) in - (Evarutil.e_new_evar prog_info.evd env ~src:(loc,k) ty), ty - - | RCast(loc, expr, cast_kind, toexpr) -> - let coqexpr, exprtyp = aux ctx expr in - let coqtoexpr, toexprtyp = aux ctx toexpr in - mkCast (coqexpr, cast_kind, coqtoexpr), toexprtyp - - - | RCases _ (* of loc * rawconstr option * - (rawconstr * (name * (loc * inductive * name list) option)) list * - (loc * identifier list * cases_pattern list * rawconstr) list *) -> - anomaly "Not implemented" - - | REvar(loc, e_key, arglopt) -> - let evm = evars_of !(prog_info.evd) in - let evi = map evm e_key in - let args = - match arglopt with - Some l -> Array.of_list (List.map (fun e -> fst (aux ctx e)) l) - | None -> [||] - in - (match evi.evar_body with - Evar_defined v -> mkApp (v, args), evi.evar_concl - | _ -> - mkEvar (e_key, args), evi.evar_concl) - - | RPatVar(loc, (b, pvar)) -> error "Found a pattern variable in a term to be typed" - | RDynamic(loc, d) -> - if (Dyn.tag d) = "constr" then - let c = Pretyping.constr_out d in - let j = (Retyping.get_type_of env Evd.empty c) in - j, c - else - user_err_loc (loc,"subtac.interp",(str "Not a constr tagged Dynamic")) - in aux ctx t - + | RLetIn(loc,name,c1,c2) -> + let j = pretype empty_tycon env isevars lvar c1 in + let t = refresh_universes j.uj_type in + let var = (name,Some j.uj_val,t) in + let tycon = option_app (lift 1) tycon in + let j' = pretype tycon (push_rel var env) isevars lvar c2 in + { uj_val = mkLetIn (name, j.uj_val, t, j'.uj_val) ; + uj_type = subst1 j.uj_val j'.uj_type } + + | RLetTuple (loc,nal,(na,po),c,d) -> + let cj = pretype empty_tycon env isevars lvar c in + let (IndType (indf,realargs)) = + try find_rectype env (evars_of !isevars) cj.uj_type + with Not_found -> + let cloc = loc_of_rawconstr c in + error_case_not_inductive_loc cloc env (evars_of !isevars) cj + in + let cstrs = get_constructors env indf in + if Array.length cstrs <> 1 then + user_err_loc (loc,"",str "Destructing let is only for inductive types with one constructor"); + let cs = cstrs.(0) in + if List.length nal <> cs.cs_nargs then + user_err_loc (loc,"", str "Destructing let on this type expects " ++ int cs.cs_nargs ++ str " variables"); + let fsign = List.map2 (fun na (_,c,t) -> (na,c,t)) + (List.rev nal) cs.cs_args in + let env_f = push_rels fsign env in + (* Make dependencies from arity signature impossible *) + let arsgn,_ = get_arity env indf in + let arsgn = List.map (fun (_,b,t) -> (Anonymous,b,t)) arsgn in + let psign = (na,None,build_dependent_inductive env indf)::arsgn in + let nar = List.length arsgn in + (match po with + | Some p -> + let env_p = push_rels psign env in + let pj = pretype_type empty_valcon env_p isevars lvar p in + let ccl = nf_evar (evars_of !isevars) pj.utj_val in + let psign = make_arity_signature env true indf in (* with names *) + let p = it_mkLambda_or_LetIn ccl psign in + let inst = + (Array.to_list cs.cs_concl_realargs) + @[build_dependent_constructor cs] in + let lp = lift cs.cs_nargs p in + let fty = hnf_lam_applist env (evars_of !isevars) lp inst in + let fj = pretype (mk_tycon fty) env_f isevars lvar d in + let f = it_mkLambda_or_LetIn fj.uj_val fsign in + let v = + let mis,_ = dest_ind_family indf in + let ci = make_default_case_info env LetStyle mis in + mkCase (ci, p, cj.uj_val,[|f|]) in + { uj_val = v; uj_type = substl (realargs@[cj.uj_val]) ccl } + + | None -> + let tycon = option_app (lift cs.cs_nargs) tycon in + let fj = pretype tycon env_f isevars lvar d in + let f = it_mkLambda_or_LetIn fj.uj_val fsign in + let ccl = nf_evar (evars_of !isevars) fj.uj_type in + let ccl = + if noccur_between 1 cs.cs_nargs ccl then + lift (- cs.cs_nargs) ccl + else + error_cant_find_case_type_loc loc env (evars_of !isevars) + cj.uj_val in + let p = it_mkLambda_or_LetIn (lift (nar+1) ccl) psign in + let v = + let mis,_ = dest_ind_family indf in + let ci = make_default_case_info env LetStyle mis in + mkCase (ci, p, cj.uj_val,[|f|] ) + in + { uj_val = v; uj_type = ccl }) + + | RIf (loc,c,(na,po),b1,b2) -> + let cj = pretype empty_tycon env isevars lvar c in + let (IndType (indf,realargs)) = + try find_rectype env (evars_of !isevars) cj.uj_type + with Not_found -> + let cloc = loc_of_rawconstr c in + error_case_not_inductive_loc cloc env (evars_of !isevars) cj in + let cstrs = get_constructors env indf in + if Array.length cstrs <> 2 then + user_err_loc (loc,"", + str "If is only for inductive types with two constructors"); + + (* Make dependencies from arity signature impossible *) + let arsgn,_ = get_arity env indf in + let arsgn = List.map (fun (_,b,t) -> (Anonymous,b,t)) arsgn in + let nar = List.length arsgn in + let psign = (na,None,build_dependent_inductive env indf)::arsgn in + let pred,p = match po with + | Some p -> + let env_p = push_rels psign env in + let pj = pretype_type empty_valcon env_p isevars lvar p in + let ccl = nf_evar (evars_of !isevars) pj.utj_val in + let pred = it_mkLambda_or_LetIn ccl psign in + pred, lift (- nar) (beta_applist (pred,[cj.uj_val])) + | None -> + let p = match tycon with + | Some ty -> ty + | None -> + e_new_evar isevars env ~src:(loc,InternalHole) (new_Type ()) + in + it_mkLambda_or_LetIn (lift (nar+1) p) psign, p in + let f cs b = + let n = rel_context_length cs.cs_args in + let pi = liftn n 2 pred in + let pi = beta_applist (pi, [build_dependent_constructor cs]) in + let csgn = List.map (fun (_,b,t) -> (Anonymous,b,t)) cs.cs_args in + let env_c = push_rels csgn env in + let bj = pretype (Some pi) env_c isevars lvar b in + it_mkLambda_or_LetIn bj.uj_val cs.cs_args in + let b1 = f cstrs.(0) b1 in + let b2 = f cstrs.(1) b2 in + let pred = nf_evar (evars_of !isevars) pred in + let p = nf_evar (evars_of !isevars) p in + let v = + let mis,_ = dest_ind_family indf in + let ci = make_default_case_info env IfStyle mis in + mkCase (ci, pred, cj.uj_val, [|b1;b2|]) + in + { uj_val = v; uj_type = p } + + | RCases (loc,po,tml,eqns) -> + Cases.compile_cases loc + ((fun vtyc env -> pretype vtyc env isevars lvar),isevars) + tycon env (* loc *) (po,tml,eqns) + + | RCast(loc,c,k,t) -> + let tj = pretype_type empty_tycon env isevars lvar t in + let cj = pretype (mk_tycon tj.utj_val) env isevars lvar c in + (* User Casts are for helping pretyping, experimentally not to be kept*) + (* ... except for Correctness *) + let v = mkCast (cj.uj_val, k, tj.utj_val) in + let cj = { uj_val = v; uj_type = tj.utj_val } in + inh_conv_coerce_to_tycon loc env isevars cj tycon + + | RDynamic (loc,d) -> + if (tag d) = "constr" then + let c = Pretyping.constr_out d in + let j = (Retyping.get_judgment_of env (evars_of !isevars) c) in + j + (*inh_conv_coerce_to_tycon loc env isevars j tycon*) + else + user_err_loc (loc,"pretype",(str "Not a constr tagged Dynamic")) + +(* [pretype_type valcon env isevars lvar c] coerces [c] into a type *) +and pretype_type valcon env isevars lvar = function + | RHole loc -> + (match valcon with + | Some v -> + let s = + let sigma = evars_of !isevars in + let t = Retyping.get_type_of env sigma v in + match kind_of_term (whd_betadeltaiota env sigma t) with + | Sort s -> s + | Evar v when is_Type (existential_type sigma v) -> + evd_comb1 (define_evar_as_sort) isevars v + | _ -> anomaly "Found a type constraint which is not a type" + in + { utj_val = v; + utj_type = s } + | None -> + let s = new_Type_sort () in + { utj_val = e_new_evar isevars env ~src:loc (mkSort s); + utj_type = s}) + | c -> + let j = pretype empty_tycon env isevars lvar c in + let loc = loc_of_rawconstr c in + let tj = evd_comb1 (inh_coerce_to_sort loc env) isevars j in + match valcon with + | None -> tj + | Some v -> + if e_cumul env isevars v tj.utj_val then tj + else + error_unexpected_type_loc + (loc_of_rawconstr c) env (evars_of !isevars) tj.utj_val v + + +type typing_constraint = OfType of types option | IsType + +let pretype_gen isevars env lvar kind c = + let c' = match kind with + | OfType exptyp -> + let tycon = match exptyp with None -> empty_tycon | Some t -> mk_tycon t in + (pretype tycon env isevars lvar c).uj_val + | IsType -> + (pretype_type empty_valcon env isevars lvar c).utj_val in + nf_evar (evars_of !isevars) c' + +(* [check_evars] fails if some unresolved evar remains *) +(* it assumes that the defined existentials have already been substituted + (should be done in unsafe_infer and unsafe_infer_type) *) + +let check_evars env initial_sigma isevars c = + let sigma = evars_of !isevars in + let rec proc_rec c = + match kind_of_term c with + | Evar (ev,args) -> + assert (Evd.in_dom sigma ev); + if not (Evd.in_dom initial_sigma ev) then + let (loc,k) = evar_source ev !isevars in + error_unsolvable_implicit loc env sigma k + | _ -> iter_constr proc_rec c + in + proc_rec c(*; + let (_,pbs) = get_conv_pbs !isevars (fun _ -> true) in + if pbs <> [] then begin + pperrnl + (str"TYPING OF "++Termops.print_constr_env env c++fnl()++ + prlist_with_sep fnl + (fun (pb,c1,c2) -> + Termops.print_constr c1 ++ + (if pb=Reduction.CUMUL then str " <="++ spc() + else str" =="++spc()) ++ + Termops.print_constr c2) + pbs ++ fnl()) + end*) + +(* TODO: comment faire remonter l'information si le typage a resolu des + variables du sigma original. il faudrait que la fonction de typage + retourne aussi le nouveau sigma... +*) + +let understand_judgment sigma env c = + let isevars = ref (create_evar_defs sigma) in + let j = pretype empty_tycon env isevars ([],[]) c in + let j = j_nf_evar (evars_of !isevars) j in + check_evars env sigma isevars (mkCast(j.uj_val,DEFAULTcast, j.uj_type)); + j + +(* Raw calls to the unsafe inference machine: boolean says if we must + fail on unresolved evars; the unsafe_judgment list allows us to + extend env with some bindings *) + +let ise_pretype_gen fail_evar sigma env lvar kind c = + let isevars = ref (create_evar_defs sigma) in + let c = pretype_gen isevars env lvar kind c in + if fail_evar then check_evars env sigma isevars c; + (!isevars, c) + +(** Entry points of the high-level type synthesis algorithm *) + +type var_map = (identifier * unsafe_judgment) list +type unbound_ltac_var_map = (identifier * identifier option) list + +let understand_gen kind sigma env c = + snd (ise_pretype_gen true sigma env ([],[]) kind c) + +let understand sigma env ?expected_type:exptyp c = + snd (ise_pretype_gen true sigma env ([],[]) (OfType exptyp) c) + +let understand_type sigma env c = + snd (ise_pretype_gen true sigma env ([],[]) IsType c) + +let understand_ltac sigma env lvar kind c = + ise_pretype_gen false sigma env lvar kind c + +let understand_tcc sigma env ?expected_type:exptyp c = + let evars,c = ise_pretype_gen false sigma env ([],[]) (OfType exptyp) c in + evars_of evars,c + +(** Miscellaneous interpretation functions *) + +let interp_sort = function + | RProp c -> Prop c + | RType _ -> new_Type_sort () + +let interp_elimination_sort = function + | RProp Null -> InProp + | RProp Pos -> InSet + | RType _ -> InType let global_kind = Decl_kinds.IsDefinition Decl_kinds.Definition let goal_kind = Decl_kinds.Global, Decl_kinds.DefinitionBody Decl_kinds.Definition @@ -526,27 +585,27 @@ let make_fixpoint t id term = let merge_evms x y = Evd.fold (fun ev evi evm -> Evd.add evm ev evi) x y +let interp env isevars c = + let j = pretype empty_tycon env isevars ([],[]) c in + j.uj_val, j.uj_type + let subtac' recursive id env (s, t) = check_required_library ["Coq";"Init";"Datatypes"]; check_required_library ["Coq";"Init";"Specif"]; try - let evm = Evd.empty in - let coqintern = Constrintern.intern_constr evm env in - let coqinterp = Constrintern.interp_constr evm env in - let s, t = coqintern s, coqintern t in - let prog_info = { evd = ref (Evd.create_evar_defs evm); evm = evm; rec_info = None } in + let evd = ref (create_evar_defs Evd.empty) in + let nonimplicit = ref Gset.empty in + let coqintern evd = Constrintern.intern_constr (evars_of evd) env in + let coqinterp evd = Constrintern.interp_constr (evars_of evd) env in + let s, t = coqintern !evd s, coqintern !evd t in trace (str "Begin infer_type of given spec"); - let (evs, coqs) = Pretyping.understand_tcc evm env s and (evt, coqt) = Pretyping.understand_tcc evm env t in - debug 1 (str "Coq understands as : " ++ my_print_constr env [] coqs ++ str " : " ++ my_print_constr env [] coqt); - - - let coqtype, prog_info, ctx = + let coqtype, rec_info, ctx = match recursive with Some (n, t, rel, proof) -> - let coqrel = coqinterp rel in - let t', ttyp = interp prog_info env [] (coqintern t) in + let coqrel = coqinterp !evd rel in + let t', ttyp = interp env evd (coqintern !evd t) in let namen = Name n in - let coqs, styp = interp prog_info env [namen, None, t'] s in + let coqs, styp = interp (push_rel (namen, None, t') env) evd s in let ftype = mkProd (namen, t', coqs) in let fulltype = mkProd (namen, t', @@ -557,61 +616,50 @@ let subtac' recursive id env (s, t) = let proof = match proof with ManualProof p -> (* TODO: Check that t is a proof of well_founded rel *) - coqinterp p + coqinterp !evd p | AutoProof -> (try Lazy.force (Hashtbl.find wf_relations coqrel) with Not_found -> msg_warning (str "No proof found for relation " - ++ my_print_constr env [] coqrel); + ++ my_print_constr env coqrel); raise Not_found) | ExistentialProof -> let wf_rel = mkApp (Lazy.force well_founded, [| t'; coqrel |]) in - let key = mknewexist () in - prog_info.evm <- Evd.add prog_info.evm key - { Evd.evar_concl = wf_rel; - Evd.evar_hyps = Environ.empty_named_context_val; - Evd.evar_body = Evd.Evar_empty }; - mkEvar (key, [| |]) - in - let prog_info = - let rec_info = - { arg_name = n; - arg_type = t'; - wf_relation = coqrel; - wf_proof = proof; - f_type = ftype; - f_fulltype = fulltype; - } - in { prog_info with rec_info = Some rec_info } + make_existential dummy_loc env nonimplicit evd wf_rel in - let coqctx = - [(Name id, None, ftype); (namen, None, t')] - in coqs, prog_info, coqctx + let rec_info = + { arg_name = n; + arg_type = t'; + wf_relation = coqrel; + wf_proof = proof; + f_type = ftype; + f_fulltype = fulltype; + } + in + let coqctx = push_rel (namen, None, t') (push_rel (Name id, None, ftype) env) in + coqs, Some rec_info, coqctx | None -> - let coqs, _ = interp prog_info env [] s in - coqs, prog_info, [] + let coqs, _ = interp env evd s in + coqs, None, env in - trace (str "Rewrite of spec done:" ++ my_print_constr env ctx coqtype); - let coqt, ttyp = interp prog_info env ctx t in - trace (str "Interpretation done:" ++ spc () ++ - str "Interpreted term: " ++ my_print_constr env ctx coqt ++ spc () ++ - str "Infered type: " ++ my_print_constr env ctx ttyp); - - let coercespec = coerce prog_info env ctx ttyp coqtype in + trace (str "Interpreted type: " ++ my_print_constr env coqtype); + let coqt, ttyp = interp env evd t in + trace (str "Interpreted term: " ++ my_print_constr env coqt ++ spc () ++ + str "Infered type: " ++ my_print_constr env ttyp); + let coercespec = Subtac_coercion.coerce dummy_loc env nonimplicit evd ttyp coqtype in trace (str "Specs coercion successfull"); let realt = app_opt coercespec coqt in - trace (str "Term Specs coercion successfull" ++ - my_print_constr env ctx realt); + trace (str "Term Specs coercion successfull: " ++ my_print_constr env realt); let realt = - match prog_info.rec_info with + match rec_info with Some t -> make_fixpoint t id realt | None -> realt in - let realt = Evarutil.whd_ise (evars_of !(prog_info.evd)) realt in - trace (str "Coq term" ++ my_print_constr env [] realt); - trace (str "Coq type" ++ my_print_constr env [] coqtype); - let evm = prog_info.evm in + let realt = Evarutil.nf_evar (evars_of !evd) realt in + trace (str "Coq term: " ++ my_print_constr env realt ++ spc () + ++ str "Coq type: " ++ my_print_constr env coqtype); + let evm = non_instanciated_map env nonimplicit evd in (try trace (str "Original evar map: " ++ Evd.pr_evar_map evm); with Not_found -> trace (str "Not found in pr_evar_map")); let tac = Eterm.etermtac (evm, realt) in diff --git a/contrib/subtac/scoq.ml b/contrib/subtac/scoq.ml index a864b95c9..1fbb0d745 100644 --- a/contrib/subtac/scoq.ml +++ b/contrib/subtac/scoq.ml @@ -34,26 +34,30 @@ let extsort s = Constrextern.extern_constr true (Global.env ()) (mkSort s) open Pp +let my_print_constr = Termops.print_constr_env +let my_print_context = Termops.print_rel_context +let my_print_rawconstr = Printer.pr_rawconstr_env + let mknewexist = let exist_counter = ref 0 in fun () -> let i = exist_counter in incr exist_counter; !i - let debug_level = ref 0 let debug n s = - if n >= !debug_level then - msgnl s - else () + if n >= !debug_level then ( + msgnl s; + msg_warning s; + ) else () let debug_msg n s = if n >= !debug_level then s else mt () let trace s = - if !debug_level < 2 then msgnl s + if !debug_level < 2 then (msgnl s) else () let wf_relations = Hashtbl.create 10 @@ -69,3 +73,27 @@ type wf_proof_type = AutoProof | ManualProof of Topconstr.constr_expr | ExistentialProof + +let app_opt c e = + match c with + Some constr -> constr e + | None -> e + +let make_existential loc env nonimplicit isevars c = + let key = mknewexist () in + let args = Sign.instance_from_named_context (Environ.named_context env) in + isevars := + Evd.evar_declare (Environ.named_context_val env) key c ~src:(loc, InternalHole) !isevars; + nonimplicit := Gset.add key !nonimplicit; + mkEvar(key, args) + +let non_instanciated_map env nonimplicit evd = + let evm = evars_of !evd in + List.fold_left + (fun evm (key, evi) -> + if Gset.mem key !nonimplicit then + Evd.add evm key evi + else + let (loc,k) = evar_source key !evd in + Pretype_errors.error_unsolvable_implicit loc env evm k) + Evd.empty (Evarutil.non_instantiated evm) |