diff options
author | Hugo Herbelin <Hugo.Herbelin@inria.fr> | 2014-11-02 22:13:27 +0100 |
---|---|---|
committer | Hugo Herbelin <Hugo.Herbelin@inria.fr> | 2014-11-02 22:15:41 +0100 |
commit | 4df1ddc6d6bd0707396337869b663b4c8f930f60 (patch) | |
tree | 6bbc012b84c3b7a6390f2096fbcfa21c5c357e36 /tactics/tactics.ml | |
parent | bddc12b5f8706882bd870445891351b2cd8e8156 (diff) |
Some reorganization of the code for destruct/induction:
- It removes some redundancies.
- It fixes failures when destructing a term mentioning goal hypotheses
x1, ..., xn or a term which is a section variable x when this term
is in a type with indices, and the indices also occur in the type of
one of x1, ..., xn, or of x.
- It fixes non-respect of eliminator type when completing pattern possibly
given by a prefix.
- It fixes b2e1d4ea930c which was dealing with the case when the term
was a section variable (it was unfortunately also breaking some
compatibility about which variables variable were generalized in
induction and which variables were automatically cleared because
unselected).
Diffstat (limited to 'tactics/tactics.ml')
-rw-r--r-- | tactics/tactics.ml | 207 |
1 files changed, 91 insertions, 116 deletions
diff --git a/tactics/tactics.ml b/tactics/tactics.ml index 23ec74db0..56568c599 100644 --- a/tactics/tactics.ml +++ b/tactics/tactics.ml @@ -2779,11 +2779,17 @@ let find_atomic_param_of_ind nparams indtyp = exception Shunt of Id.t move_location +let add_vars_of_defined_term env id vars = + match lookup_named id env with + | (_,Some c,_) -> Id.Set.union (collect_vars c) vars + | (_,None,_) -> vars + let cook_sign hyp0_opt indvars env = - let hyp0,inhyps = + let hyp0,inhyps,fixedvars = match hyp0_opt with - | None -> List.hd (List.rev indvars), [] - | Some (hyp0,at_least_in_hyps) -> hyp0, at_least_in_hyps in + | None -> List.hd (List.rev indvars), [], Id.Set.empty + | Some (hyp0,at_least_in_hyps,fixedvars) -> hyp0, at_least_in_hyps, fixedvars in + let fixedvars = List.fold_right (add_vars_of_defined_term env) indvars fixedvars in (* First phase from L to R: get [indhyps], [decldep] and [statuslist] for the hypotheses before (= more ancient than) hyp0 (see above) *) let allindhyps = hyp0::indvars in @@ -2807,7 +2813,7 @@ let cook_sign hyp0_opt indvars env = rhyp end else if not (List.is_empty inhyps) && Id.List.mem hyp inhyps || - List.is_empty inhyps && + List.is_empty inhyps && not (Id.Set.mem hyp fixedvars) && (List.exists (fun id -> occur_var_in_decl env id decl) allindhyps || List.exists (fun (id,_,_) -> occur_var_in_decl env id decl) !decldeps) then begin @@ -3497,21 +3503,21 @@ type scheme_signature = type eliminator_source = | ElimUsing of (eliminator * types) * scheme_signature - | ElimOver of bool * Id.t * Id.t + | ElimOver of bool * Id.t -let find_induction_type isrec elim hyp0 base_id gl = +let find_induction_type isrec elim hyp0 gl = let evd,scheme,elim = match elim with | None -> let evd, (elimc,elimt),_ = guess_elim isrec hyp0 gl in let scheme = compute_elim_sig ~elimc elimt in (* We drop the scheme waiting to know if it is dependent *) - evd, scheme, ElimOver (isrec,hyp0,base_id) + evd, scheme, ElimOver (isrec,hyp0) | Some e -> let evd, (elimc,elimt),ind_guess = given_elim hyp0 e gl in let scheme = compute_elim_sig ~elimc elimt in if Option.is_empty scheme.indarg then error "Cannot find induction type"; - let indsign = compute_scheme_signature scheme base_id ind_guess in + let indsign = compute_scheme_signature scheme hyp0 ind_guess in let elim = ({elimindex = Some(-1); elimbody = elimc; elimrename = None},elimt) in evd, scheme, ElimUsing (elim,indsign) in evd,(Option.get scheme.indref,scheme.nparams, elim) @@ -3535,9 +3541,9 @@ let is_functional_induction elim gl = let get_eliminator elim gl = match elim with | ElimUsing (elim,indsign) -> Proofview.Goal.sigma gl, (* bugged, should be computed *) true, elim, indsign - | ElimOver (isrec,id,base_id) -> + | ElimOver (isrec,id) -> let evd, (elimc,elimt),_ as elims = guess_elim isrec id gl in - let _, (l, s) = compute_elim_signature elims base_id in + let _, (l, s) = compute_elim_signature elims id in let branchlengthes = List.map (fun (_,b,c) -> assert (b=None); pi1 (decompose_prod_letin c)) (List.rev s.branches) in evd, isrec, ({elimindex = None; elimbody = elimc; elimrename = Some (isrec,Array.of_list branchlengthes)}, elimt), l @@ -3694,7 +3700,7 @@ let induction_tac with_evars elim (varname,lbind) typ gl = Proofview.V82.of_tactic (elimination_clause_scheme with_evars ~with_classes:false rename i (elimc, elimt, lbindelimc) indclause) gl -let induction_from_context isrec with_evars (indref,nparams,elim) hyp0 names inhyps = +let induction_from_context isrec with_evars (indref,nparams,elim) hyp0 fixedvars names inhyps = Proofview.Goal.nf_enter begin fun gl -> let tmptyp0 = Tacmach.New.pf_get_hyp_typ hyp0 gl in let reduce_to_quantified_ref = @@ -3705,27 +3711,19 @@ let induction_from_context isrec with_evars (indref,nparams,elim) hyp0 names inh let induct_tac elim = Proofview.V82.tactic (tclTHENLIST [ induction_tac with_evars elim (hyp0,NoBindings) typ0; tclTRY (unfold_body hyp0); - if mem_named_context hyp0 (Global.named_context()) - then (* Compat: can be dropped for more uniformity of behavior *) tclIDTAC - else thin [hyp0] + thin [hyp0] ]) in apply_induction_in_context - (Some (hyp0,inhyps)) elim indvars names induct_tac + (Some (hyp0,inhyps,fixedvars)) elim indvars names induct_tac end -let induction_with_atomization_of_ind_arg isrec with_evars elim names hyp0 inhyps = +let induction_with_atomization_of_ind_arg isrec with_evars elim names hyp0 inhyps fixedvars = Proofview.Goal.nf_enter begin fun gl -> - let base_id = if mem_named_context hyp0 (Global.named_context()) - then (* Compat: can be dropped for more uniformity of naming *) - let t = typ_of (Proofview.Goal.env gl) (Proofview.Goal.sigma gl) (mkVar hyp0) in - let x = id_of_name_using_hdchar (Global.env()) t Anonymous in - new_fresh_id [] x gl - else hyp0 in - let sigma, elim_info = find_induction_type isrec elim hyp0 base_id gl in + let sigma, elim_info = find_induction_type isrec elim hyp0 gl in Tacticals.New.tclTHENLIST [Proofview.Unsafe.tclEVARS sigma; (atomize_param_of_ind elim_info hyp0); (induction_from_context isrec with_evars elim_info - hyp0 names inhyps)] + hyp0 fixedvars names inhyps)] end (* Induction on a list of induction arguments. Analyse the elim @@ -3766,60 +3764,35 @@ let clear_unselected_context id inhyps cls gl = thin ids gl | None -> tclIDTAC gl -let use_bindings env sigma (c,lbind) typ = - (* We don't try to normalize the type to an inductive type because *) - (* we want to support cases such that "nat_rect ?A ?o ?s n" of type ?A *) - (* where the type "?A" is known only by matching *) +let use_bindings env sigma elim (c,lbind) typ = + let typ = + if elim == None then + (* w/o an scheme, the term has to be applied at least until + obtaining an inductive type (even though the arity might be + known only by pattern-matching, as in the case of a term of + the form "nat_rect ?A ?o ?s n", with ?A to be inferred by + matching. *) + let sign,t = splay_prod env sigma typ in it_mkProd t sign + else + (* Otherwise, we exclude the case of an induction argument in an + explicitly functional type. Henceforth, we can complete the + pattern until it has as type an atomic type (even though this + atomic type can hide a functional type, for which the "using" + clause has a scheme). *) + typ in let rec find_clause typ = - try make_clenv_binding env sigma (c,typ) lbind + try + let indclause = make_clenv_binding env sigma (c,typ) lbind in + (* We lose the possibility of coercions in with-bindings *) + pose_all_metas_as_evars env indclause.evd (clenv_value indclause) with e when catchable_exception e -> try find_clause (try_red_product env sigma typ) with Redelimination -> raise e in - let indclause = find_clause typ in - (* We lose the possibility of coercions in with-bindings *) - pose_all_metas_as_evars env indclause.evd (clenv_value indclause) + find_clause typ -let clear_induction_arg_if_hyp is_arg_pure_hyp c env ccl = - if is_arg_pure_hyp then - try - let id = destVar c in - if occur_var env id ccl then env - else - snd (fold_named_context (fun _ (id',_,_ as d) (found,env) -> - if Id.equal id id' then (true,env) else - if occur_var_in_decl env id d then raise Exit - else (found,push_named d env)) - env ~init:(false,reset_context env)) - with Exit -> env - else - env - -let make_body env0 env sigma (is_arg_pure_hyp,_) c lbind t = - let decls,t = splay_prod env sigma t in - let typ = it_mkProd t decls in - let indclause = make_clenv_binding env0 sigma (c,typ) lbind in - let evdref = ref indclause.evd in - let rec aux c = match kind_of_term c with - | Meta mv -> - (match Evd.meta_opt_fvalue !evdref mv with - | Some ({rebus=c},_) -> c - | None -> - let {rebus=ty;freemetas=mvs} = Evd.meta_ftype !evdref mv in - let ty = if Evd.Metaset.is_empty mvs then ty else aux ty in - let src = Evd.evar_source_of_meta mv !evdref in - let ev = Evarutil.e_new_evar env evdref ~src ty in - evdref := meta_assign mv (ev,(Conv,TypeNotProcessed)) !evdref; - ev) - | _ -> - Constr.map aux c in - let c = aux (clenv_value indclause) in - (* side-effect *) - (!evdref, c) - -let check_expected_type env sigma (elimc,bl) = +let check_expected_type env sigma (elimc,bl) elimt = (* Compute the expected template type of the term in case a using clause is given *) - let elimt = typ_of env sigma elimc in let sign,_ = splay_prod env sigma elimt in let n = List.length sign in if n == 0 then error "Scheme cannot be applied."; @@ -3845,36 +3818,62 @@ let check_enough_applied env sigma elim = fun _ -> true | Some _ -> (* Last argument is supposed to be the induction argument *) - check_expected_type env sigma elimc + check_expected_type env sigma elimc elimt -let pose_induction_arg clear_flag isrec with_evars info_arg elim - id ((pending,(c0,lbind)),(eqname,names)) t0 inhyps cls = +let pose_induction_arg_then clear_flag isrec with_evars + (is_arg_pure_hyp,from_prefix) elim + id ((pending,(c0,lbind)),(eqname,names)) t0 inhyps cls tac = Proofview.Goal.nf_enter begin fun gl -> let env = Proofview.Goal.env gl in + let sigma = Proofview.Goal.sigma gl in let ccl = Proofview.Goal.concl gl in - Proofview.Refine.refine ~unsafe:true begin fun sigma -> - let (sigma',c') = use_bindings env sigma (c0,lbind) t0 in let check = check_enough_applied env sigma elim in - let abs = AbstractPattern (snd info_arg,check,Name id,(pending,c'),cls,false) in + let (sigma',c) = use_bindings env sigma elim (c0,lbind) t0 in + let abs = AbstractPattern (from_prefix,check,Name id,(pending,c),cls,false) in let (id,sign,_,lastlhyp,ccl,res) = make_abstraction env sigma' ccl abs in match res with | None -> (* pattern not found *) - let (sigma,c0) = finish_evar_resolution ~flags:(tactic_infer_flags with_evars) env sigma (pending,c0) in - let env' = clear_induction_arg_if_hyp (fst info_arg) c0 env ccl in - let (sigma,c) = make_body env env' sigma info_arg c0 lbind t0 in - let t = Retyping.get_type_of env sigma c in + let fixedvars = collect_vars c in let with_eq = Option.map (fun eq -> (false,eq)) eqname in - mkletin_goal env' sigma with_eq false (id,lastlhyp,ccl,c) (Some t) + (* we restart using bindings after having tried type-class + resolution etc. on the term given by the user *) + let flags = tactic_infer_flags (with_evars && (* do not give a success semantics to edestruct on an open term yet *) false) in + let (sigma,c0) = finish_evar_resolution ~flags env sigma (pending,c0) in + (if isrec then + (* Historically, induction has side conditions last *) + Tacticals.New.tclTHENFIRST + else + (* and destruct has side conditions first *) + Tacticals.New.tclTHENLAST) + (Tacticals.New.tclTHENLIST [ + Proofview.Unsafe.tclEVARS sigma; + Proofview.Refine.refine ~unsafe:true (fun sigma -> + let (sigma,c) = use_bindings env sigma elim (c0,lbind) t0 in + let t = Retyping.get_type_of env sigma c in + mkletin_goal env sigma with_eq false (id,lastlhyp,ccl,c) (Some t)); + if is_arg_pure_hyp + then Tacticals.New.tclTRY (Proofview.V82.tactic (thin [destVar c0])) + else Proofview.tclUNIT (); + Proofview.(if with_evars then shelve_unifiable else guard_no_unifiable); + Proofview.shelve_unifiable; + if isrec then Proofview.cycle (-1) else Proofview.tclUNIT () + ]) + (tac fixedvars) | Some (sigma',c) -> (* pattern found *) + let fixedvars = collect_vars c in let with_eq = Option.map (fun eq -> (false,eq)) eqname in (* TODO: if ind has predicate parameters, use JMeq instead of eq *) let env = reset_with_named_context sign env in - (mkletin_goal env sigma' with_eq true (id,lastlhyp,ccl,c) None) + Tacticals.New.tclTHENLIST [ + Proofview.Unsafe.tclEVARS sigma'; + Proofview.Refine.refine ~unsafe:true (fun sigma -> + mkletin_goal env sigma with_eq true (id,lastlhyp,ccl,c) None); + tac fixedvars + ] end -end let has_generic_occurrences_but_goal cls id env ccl = clause_with_generic_context_selection cls && @@ -3893,7 +3892,8 @@ let induction_gen clear_flag isrec with_evars elim let cls = Option.default allHypsAndConcl cls in let t = typ_of env sigma c in let is_arg_pure_hyp = - isVar c && lbind == NoBindings && not with_evars && Option.is_empty eqname + isVar c && not (mem_named_context (destVar c) (Global.named_context())) + && lbind == NoBindings && not with_evars && Option.is_empty eqname && has_generic_occurrences_but_goal cls (destVar c) env ccl in let enough_applied = check_enough_applied env sigma elim t in if is_arg_pure_hyp && enough_applied then @@ -3906,44 +3906,19 @@ let induction_gen clear_flag isrec with_evars elim Tacticals.New.tclTHEN (Proofview.V82.tactic (clear_unselected_context id inhyps cls)) (induction_with_atomization_of_ind_arg - isrec with_evars elim names id inhyps) + isrec with_evars elim names id inhyps Id.Set.empty) else - (* Otherwise, we find for the pattern, possibly adding missing arguments and + (* Otherwise, we look for the pattern, possibly adding missing arguments and declaring the induction argument as a new local variable *) let id = (* Type not the right one if partially applied but anyway for internal use*) let x = id_of_name_using_hdchar (Global.env()) t Anonymous in new_fresh_id [] x gl in let info_arg = (is_arg_pure_hyp, not enough_applied) in - if isrec then - (* Historically, induction has side conditions last *) - Tacticals.New.tclTHENFIRST - (Tacticals.New.tclTHENLIST [ - pose_induction_arg clear_flag isrec with_evars info_arg elim id arg t inhyps cls; - if with_evars - (* do not give a success semantics to edestruct on an - open term yet *) - && true - then Proofview.shelve_unifiable - else Proofview.guard_no_unifiable; - Proofview.cycle (-1); - ]) - (induction_with_atomization_of_ind_arg - isrec with_evars elim names id inhyps) - else - (* Historically, destruct has side conditions first *) - Tacticals.New.tclTHENLAST - (Tacticals.New.tclTHENLIST [ - pose_induction_arg clear_flag isrec with_evars info_arg elim id arg t inhyps cls; - if with_evars - (* do not give a success semantics to edestruct on an - open term yet *) - && true - then Proofview.shelve_unifiable - else Proofview.guard_no_unifiable - ]) - (induction_with_atomization_of_ind_arg - isrec with_evars elim names id inhyps) + pose_induction_arg_then + clear_flag isrec with_evars info_arg elim id arg t inhyps cls + (induction_with_atomization_of_ind_arg + isrec with_evars elim names id inhyps) end (* Induction on a list of arguments. First make induction arguments |