]> matita.cs.unibo.it Git - helm.git/blob - components/tactics/proofEngineHelpers.ml
matita 0.5.1 tagged
[helm.git] / components / tactics / proofEngineHelpers.ml
1 (* Copyright (C) 2002, HELM Team.
2  * 
3  * This file is part of HELM, an Hypertextual, Electronic
4  * Library of Mathematics, developed at the Computer Science
5  * Department, University of Bologna, Italy.
6  * 
7  * HELM is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * 
12  * HELM is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with HELM; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20  * MA  02111-1307, USA.
21  * 
22  * For details, see the HELM World-Wide-Web page,
23  * http://cs.unibo.it/helm/.
24  *)
25
26 (* $Id$ *)
27
28 exception Bad_pattern of string Lazy.t
29
30 let new_meta_of_proof ~proof:(_, metasenv, _, _, _, _) =
31   CicMkImplicit.new_meta metasenv []
32
33 let subst_meta_in_proof proof meta term newmetasenv =
34  let uri,metasenv,initial_subst,bo,ty, attrs = proof in
35    (* empty context is ok for term since it wont be used by apply_subst *)
36    (* hack: since we do not know the context and the type of term, we
37       create a substitution with cc =[] and type = Implicit; they will be
38       in  any case dropped by apply_subst, but it would be better to rewrite
39       the code. Cannot we just use apply_subst_metasenv, etc. ?? *)
40   let subst_in = CicMetaSubst.apply_subst [meta,([], term,Cic.Implicit None)] in
41    let metasenv' =
42     newmetasenv @ (List.filter (function (m,_,_) -> m <> meta) metasenv)
43    in
44     let metasenv'' =
45      List.map
46       (function i,canonical_context,ty ->
47         let canonical_context' =
48          List.map
49           (function
50               Some (n,Cic.Decl s) -> Some (n,Cic.Decl (subst_in s))
51             | None -> None
52             | Some (n,Cic.Def (bo,ty)) ->
53                Some (n,Cic.Def (subst_in bo,subst_in ty))
54           ) canonical_context
55         in
56          i,canonical_context',(subst_in ty)
57       ) metasenv'
58     in
59      let bo' = subst_in bo in
60      (* Metavariables can appear also in the *statement* of the theorem
61       * since the parser does not reject as statements terms with
62       * metavariable therein *)
63      let ty' = subst_in ty in
64       let newproof = uri,metasenv'',initial_subst,bo',ty', attrs in
65        (newproof, metasenv'')
66
67 (*CSC: commento vecchio *)
68 (* refine_meta_with_brand_new_metasenv meta term subst_in newmetasenv     *)
69 (* This (heavy) function must be called when a tactic can instantiate old *)
70 (* metavariables (i.e. existential variables). It substitues the metasenv *)
71 (* of the proof with the result of removing [meta] from the domain of     *)
72 (* [newmetasenv]. Then it replaces Cic.Meta [meta] with [term] everywhere *)
73 (* in the current proof. Finally it applies [apply_subst_replacing] to    *)
74 (*  current proof.                                                        *)
75 (*CSC: A questo punto perche' passare un bo' gia' istantiato, se tanto poi *)
76 (*CSC: ci ripasso sopra apply_subst!!!                                     *)
77 (*CSC: Attenzione! Ora questa funzione applica anche [subst_in] a *)
78 (*CSC: [newmetasenv].                                             *)
79 let subst_meta_and_metasenv_in_proof proof meta subst newmetasenv =
80  let (uri,_,initial_subst,bo,ty, attrs) = proof in
81   let subst_in = CicMetaSubst.apply_subst subst in
82   let bo' = subst_in bo in
83   (* Metavariables can appear also in the *statement* of the theorem
84    * since the parser does not reject as statements terms with
85    * metavariable therein *)
86   let ty' = subst_in ty in
87   let metasenv' =
88    List.fold_right
89     (fun metasenv_entry i ->
90       match metasenv_entry with
91          (m,canonical_context,ty) when m <> meta ->
92            let canonical_context' =
93             List.map
94              (function
95                  None -> None
96                | Some (i,Cic.Decl t) -> Some (i,Cic.Decl (subst_in t))
97                | Some (i,Cic.Def (bo,ty)) ->
98                   Some (i,Cic.Def (subst_in bo,subst_in ty))
99              ) canonical_context
100            in
101             (m,canonical_context',subst_in ty)::i
102        | _ -> i
103     ) newmetasenv []
104   in
105   (* qui da capire se per la fase transitoria si fa initial_subst @ subst
106    * oppure subst *)
107    let newproof = uri,metasenv',subst,bo',ty', attrs in
108     (newproof, metasenv')
109
110 let compare_metasenvs ~oldmetasenv ~newmetasenv =
111  List.map (function (i,_,_) -> i)
112   (List.filter
113    (function (i,_,_) ->
114      not (List.exists (fun (j,_,_) -> i=j) oldmetasenv)) newmetasenv)
115 ;;
116
117 (** finds the _pointers_ to subterms that are alpha-equivalent to wanted in t *)
118 let find_subterms ~subst ~metasenv ~ugraph ~wanted ~context t =
119   let rec find subst metasenv ugraph context w t =
120    try
121     let subst,metasenv,ugraph =
122      CicUnification.fo_unif_subst subst context metasenv w t ugraph
123     in
124       subst,metasenv,ugraph,[context,t]
125    with
126      CicUnification.UnificationFailure _
127    | CicUnification.Uncertain _ ->
128       match t with
129       | Cic.Sort _ 
130       | Cic.Rel _ -> subst,metasenv,ugraph,[]
131       | Cic.Meta (_, ctx) -> 
132           List.fold_left (
133             fun (subst,metasenv,ugraph,acc) e -> 
134               match e with 
135               | None -> subst,metasenv,ugraph,acc 
136               | Some t ->
137                  let subst,metasenv,ugraph,res =
138                   find subst metasenv ugraph context w t
139                  in
140                   subst,metasenv,ugraph, res @ acc
141           ) (subst,metasenv,ugraph,[]) ctx
142       | Cic.Lambda (name, t1, t2) 
143       | Cic.Prod (name, t1, t2) ->
144          let subst,metasenv,ugraph,rest1 =
145           find subst metasenv ugraph context w t1 in
146          let subst,metasenv,ugraph,rest2 =
147           find subst metasenv ugraph (Some (name, Cic.Decl t1)::context)
148            (CicSubstitution.lift 1 w) t2
149          in
150           subst,metasenv,ugraph,rest1 @ rest2
151       | Cic.LetIn (name, t1, t2, t3) -> 
152          let subst,metasenv,ugraph,rest1 =
153           find subst metasenv ugraph context w t1 in
154          let subst,metasenv,ugraph,rest2 =
155           find subst metasenv ugraph context w t2 in
156          let subst,metasenv,ugraph,rest3 =
157           find subst metasenv ugraph (Some (name, Cic.Def (t1,t2))::context)
158            (CicSubstitution.lift 1 w) t3
159          in
160           subst,metasenv,ugraph,rest1 @ rest2 @ rest3
161       | Cic.Appl l -> 
162           List.fold_left
163            (fun (subst,metasenv,ugraph,acc) t ->
164              let subst,metasenv,ugraph,res =
165               find subst metasenv ugraph context w t
166              in
167               subst,metasenv,ugraph,res @ acc)
168            (subst,metasenv,ugraph,[]) l
169       | Cic.Cast (t, ty) ->
170          let subst,metasenv,ugraph,rest =
171           find subst metasenv ugraph context w t in
172          let subst,metasenv,ugraph,resty =
173           find subst metasenv ugraph context w ty
174          in
175           subst,metasenv,ugraph,rest @ resty
176       | Cic.Implicit _ -> assert false
177       | Cic.Const (_, esubst)
178       | Cic.Var (_, esubst) 
179       | Cic.MutInd (_, _, esubst) 
180       | Cic.MutConstruct (_, _, _, esubst) -> 
181           List.fold_left
182            (fun (subst,metasenv,ugraph,acc) (_, t) ->
183              let subst,metasenv,ugraph,res =
184               find subst metasenv ugraph context w t
185              in
186               subst,metasenv,ugraph,res @ acc)
187            (subst,metasenv,ugraph,[]) esubst
188       | Cic.MutCase (_, _, outty, indterm, patterns) -> 
189          let subst,metasenv,ugraph,resoutty =
190           find subst metasenv ugraph context w outty in
191          let subst,metasenv,ugraph,resindterm =
192           find subst metasenv ugraph context w indterm in
193          let subst,metasenv,ugraph,respatterns =
194           List.fold_left
195            (fun (subst,metasenv,ugraph,acc) p ->
196              let subst,metaseng,ugraph,res =
197               find subst metasenv ugraph context w p
198              in
199               subst,metasenv,ugraph,res @ acc
200            ) (subst,metasenv,ugraph,[]) patterns
201          in
202           subst,metasenv,ugraph,resoutty @ resindterm @ respatterns
203       | Cic.Fix (_, funl) -> 
204          let tys =
205           List.map (fun (n,_,ty,_) -> Some (Cic.Name n,(Cic.Decl ty))) funl
206          in
207           List.fold_left (
208             fun (subst,metasenv,ugraph,acc) (_, _, ty, bo) ->
209              let subst,metasenv,ugraph,resty =
210               find subst metasenv ugraph context w ty in
211              let subst,metasenv,ugraph,resbo =
212               find subst metasenv ugraph (tys @ context) w bo
213              in
214               subst,metasenv,ugraph, resty @ resbo @ acc
215           ) (subst,metasenv,ugraph,[]) funl
216       | Cic.CoFix (_, funl) ->
217          let tys =
218           List.map (fun (n,ty,_) -> Some (Cic.Name n,(Cic.Decl ty))) funl
219          in
220           List.fold_left (
221             fun (subst,metasenv,ugraph,acc) (_, ty, bo) ->
222              let subst,metasenv,ugraph,resty =
223               find subst metasenv ugraph context w ty in
224              let subst,metasenv,ugraph,resbo =
225               find subst metasenv ugraph (tys @ context) w bo
226              in
227               subst,metasenv,ugraph, resty @ resbo @ acc
228           ) (subst,metasenv,ugraph,[]) funl
229   in
230   find subst metasenv ugraph context wanted t
231   
232 let select_in_term ~metasenv ~context ~ugraph ~term ~pattern:(wanted,where) =
233   let add_ctx context name entry = (Some (name, entry)) :: context in
234   let map2 error_msg f l1 l2 = 
235     try 
236       List.map2 f l1 l2 
237     with
238     | Invalid_argument _ -> raise (Bad_pattern (lazy error_msg))
239   in
240   let rec aux context where term =
241     match (where, term) with
242     | Cic.Implicit (Some `Hole), t -> [context,t]
243     | Cic.Implicit (Some `Type), t -> []
244     | Cic.Implicit None,_ -> []
245     | Cic.Meta (_, ctxt1), Cic.Meta (_, ctxt2) ->
246         List.concat
247           (map2 "wrong number of argument in explicit substitution"
248             (fun t1 t2 ->
249               (match (t1, t2) with
250                   Some t1, Some t2 -> aux context t1 t2
251                 | _ -> []))
252             ctxt1 ctxt2)
253     | Cic.Cast (te1, ty1), Cic.Cast (te2, ty2) ->
254        aux context te1 te2 @ aux context ty1 ty2
255     | Cic.Prod (Cic.Anonymous, s1, t1), Cic.Prod (name, s2, t2)
256     | Cic.Lambda (Cic.Anonymous, s1, t1), Cic.Lambda (name, s2, t2) ->
257         aux context s1 s2 @ aux (add_ctx context name (Cic.Decl s2)) t1 t2
258     | Cic.Prod (Cic.Name n1, s1, t1), 
259       Cic.Prod ((Cic.Name n2) as name , s2, t2)
260     | Cic.Lambda (Cic.Name n1, s1, t1), 
261       Cic.Lambda ((Cic.Name n2) as name, s2, t2) when n1 = n2->
262         aux context s1 s2 @ aux (add_ctx context name (Cic.Decl s2)) t1 t2
263     | Cic.Prod (name1, s1, t1), Cic.Prod (name2, s2, t2)
264     | Cic.Lambda (name1, s1, t1), Cic.Lambda (name2, s2, t2) -> []
265     | Cic.LetIn (Cic.Anonymous, s1, ty1, t1), Cic.LetIn (name, s2, ty2, t2) -> 
266         aux context s1 s2 @
267         aux context ty1 ty2 @
268         aux (add_ctx context name (Cic.Def (s2,ty2))) t1 t2
269     | Cic.LetIn (Cic.Name n1, s1, ty1, t1), 
270       Cic.LetIn ((Cic.Name n2) as name, s2, ty2, t2) when n1 = n2-> 
271         aux context s1 s2 @
272         aux context ty1 ty2 @
273         aux (add_ctx context name (Cic.Def (s2,ty2))) t1 t2
274     | Cic.LetIn (name1, s1, ty1, t1), Cic.LetIn (name2, s2, ty2, t2) -> []
275     | Cic.Appl terms1, Cic.Appl terms2 -> auxs context terms1 terms2
276     | Cic.Var (_, subst1), Cic.Var (_, subst2)
277     | Cic.Const (_, subst1), Cic.Const (_, subst2)
278     | Cic.MutInd (_, _, subst1), Cic.MutInd (_, _, subst2)
279     | Cic.MutConstruct (_, _, _, subst1), Cic.MutConstruct (_, _, _, subst2) ->
280         auxs context (List.map snd subst1) (List.map snd subst2)
281     | Cic.MutCase (_, _, out1, t1, pat1), Cic.MutCase (_ , _, out2, t2, pat2) ->
282         aux context out1 out2 @ aux context t1 t2 @ auxs context pat1 pat2
283     | Cic.Fix (_, funs1), Cic.Fix (_, funs2) ->
284        let tys =
285         List.map (fun (n,_,ty,_) -> Some (Cic.Name n,(Cic.Decl ty))) funs2
286        in
287         List.concat
288           (map2 "wrong number of mutually recursive functions"
289             (fun (_, _, ty1, bo1) (_, _, ty2, bo2) -> 
290               aux context ty1 ty2 @ aux (tys @ context) bo1 bo2)
291             funs1 funs2)
292     | Cic.CoFix (_, funs1), Cic.CoFix (_, funs2) ->
293        let tys =
294         List.map (fun (n,ty,_) -> Some (Cic.Name n,(Cic.Decl ty))) funs2
295        in
296         List.concat
297           (map2 "wrong number of mutually co-recursive functions"
298             (fun (_, ty1, bo1) (_, ty2, bo2) ->
299               aux context ty1 ty2 @ aux (tys @ context) bo1 bo2)
300             funs1 funs2)
301     | x,y -> 
302         raise (Bad_pattern 
303                 (lazy (Printf.sprintf "Pattern %s versus term %s" 
304                   (CicPp.ppterm x)
305                   (CicPp.ppterm y))))
306   and auxs context terms1 terms2 =  (* as aux for list of terms *)
307     List.concat (map2 "wrong number of arguments in application"
308       (fun t1 t2 -> aux context t1 t2) terms1 terms2)
309   in
310    let roots =
311      match where with
312      | None -> []
313      | Some where -> aux context where term
314    in
315     match wanted with
316        None -> [],metasenv,ugraph,roots
317      | Some wanted ->
318         let rec find_in_roots =
319          function
320             [] -> [],metasenv,ugraph,[]
321           | (context',where)::tl ->
322              let subst,metasenv,ugraph,tl' = find_in_roots tl in
323              let subst,metasenv,ugraph,found =
324               let wanted, metasenv, ugraph = wanted context' metasenv ugraph in
325                find_subterms ~subst ~metasenv ~ugraph ~wanted ~context:context'
326                 where
327              in
328               subst,metasenv,ugraph,found @ tl'
329         in
330          find_in_roots roots
331
332 (** create a pattern from a term and a list of subterms.
333 * the pattern is granted to have a ? for every subterm that has no selected
334 * subterms
335 * @param equality equality function used while walking the term. Defaults to
336 * physical equality (==) *)
337 let pattern_of ?(equality=(==)) ~term terms =
338   let (===) x y = equality x y in
339   let not_found = false, Cic.Implicit None in
340   let rec aux t =
341     match t with
342     | t when List.exists (fun t' -> t === t') terms ->
343        true,Cic.Implicit (Some `Hole)
344     | Cic.Var (uri, subst) ->
345        let b,subst = aux_subst subst in
346         if b then
347          true,Cic.Var (uri, subst)
348         else
349          not_found
350     | Cic.Meta (i, ctxt) ->
351         let b,ctxt =
352           List.fold_right
353            (fun e (b,ctxt) ->
354              match e with
355                 None -> b,None::ctxt
356               | Some t -> let bt,t = aux t in b||bt ,Some t::ctxt
357            ) ctxt (false,[])
358         in
359          if b then
360           true,Cic.Meta (i, ctxt)
361          else
362           not_found
363     | Cic.Cast (te, ty) ->
364        let b1,te = aux te in
365        let b2,ty = aux ty in
366         if b1||b2 then true,Cic.Cast (te, ty)
367         else
368          not_found
369     | Cic.Prod (_, s, t) ->
370        let b1,s = aux s in
371        let b2,t = aux t in
372         if b1||b2 then
373          true, Cic.Prod (Cic.Anonymous, s, t)
374         else
375          not_found
376     | Cic.Lambda (_, s, t) ->
377        let b1,s = aux s in
378        let b2,t = aux t in
379         if b1||b2 then
380          true, Cic.Lambda (Cic.Anonymous, s, t)
381         else
382          not_found
383     | Cic.LetIn (_, s, ty, t) ->
384        let b1,s = aux s in
385        let b2,ty = aux ty in
386        let b3,t = aux t in
387         if b1||b2||b3 then
388          true, Cic.LetIn (Cic.Anonymous, s, ty, t)
389         else
390          not_found
391     | Cic.Appl terms ->
392        let b,terms =
393         List.fold_right
394          (fun t (b,terms) ->
395            let bt,t = aux t in
396             b||bt,t::terms
397          ) terms (false,[])
398        in
399         if b then
400          true,Cic.Appl terms
401         else
402          not_found
403     | Cic.Const (uri, subst) ->
404        let b,subst = aux_subst subst in
405         if b then
406          true, Cic.Const (uri, subst)
407         else
408          not_found
409     | Cic.MutInd (uri, tyno, subst) ->
410        let b,subst = aux_subst subst in
411         if b then
412          true, Cic.MutInd (uri, tyno, subst)
413         else
414          not_found
415     | Cic.MutConstruct (uri, tyno, consno, subst) ->
416        let b,subst = aux_subst subst in
417         if b then
418          true, Cic.MutConstruct (uri, tyno, consno, subst)
419         else
420          not_found
421     | Cic.MutCase (uri, tyno, outty, t, pat) ->
422        let b1,outty = aux outty in
423        let b2,t = aux t in
424        let b3,pat =
425         List.fold_right
426          (fun t (b,pat) ->
427            let bt,t = aux t in
428             bt||b,t::pat
429          ) pat (false,[])
430        in
431         if b1 || b2 || b3 then
432          true, Cic.MutCase (uri, tyno, outty, t, pat)
433         else
434          not_found
435     | Cic.Fix (funno, funs) ->
436         let b,funs =
437           List.fold_right
438            (fun (name, i, ty, bo) (b,funs) ->
439              let b1,ty = aux ty in
440              let b2,bo = aux bo in
441               b||b1||b2, (name, i, ty, bo)::funs) funs (false,[])
442         in
443          if b then
444           true, Cic.Fix (funno, funs)
445          else
446           not_found
447     | Cic.CoFix (funno, funs) ->
448         let b,funs =
449           List.fold_right
450            (fun (name, ty, bo) (b,funs) ->
451              let b1,ty = aux ty in
452              let b2,bo = aux bo in
453               b||b1||b2, (name, ty, bo)::funs) funs (false,[])
454         in
455          if b then
456           true, Cic.CoFix (funno, funs)
457          else
458           not_found
459     | Cic.Rel _
460     | Cic.Sort _
461     | Cic.Implicit _ -> not_found
462   and aux_subst subst =
463     List.fold_right
464      (fun (uri, t) (b,subst) ->
465        let b1,t = aux t in
466         b||b1,(uri, t)::subst) subst (false,[])
467   in
468    snd (aux term)
469
470 exception Fail of string Lazy.t
471
472   (** select metasenv conjecture pattern
473   * select all subterms of [conjecture] matching [pattern].
474   * It returns the set of matched terms (that can be compared using physical
475   * equality to the subterms of [conjecture]) together with their contexts.
476   * The representation of the set mimics the ProofEngineTypes.pattern type:
477   * a list of hypothesis (names of) together with the list of its matched
478   * subterms (and their contexts) + the list of matched subterms of the
479   * with their context conclusion. Note: in the result the list of hypothesis
480   * has an entry for each entry in the context and in the same order.
481   * Of course the list of terms (with their context) associated to the
482   * hypothesis name may be empty. 
483   *
484   * @raise Bad_pattern
485   * *)
486   let select ~metasenv ~ugraph ~conjecture:(_,context,ty)
487        ~(pattern: (Cic.term, Cic.lazy_term) ProofEngineTypes.pattern)
488   =
489    let what, hyp_patterns, goal_pattern = pattern in
490    let find_pattern_for name =
491      try Some (snd (List.find (fun (n, pat) -> Cic.Name n = name) hyp_patterns))
492      with Not_found -> None in
493    (* Multiple hypotheses with the same name can be in the context.
494       In this case we need to pick the last one, but we will perform
495       a fold_right on the context. Thus we pre-process hyp_patterns. *)
496    let full_hyp_pattern =
497     let rec aux blacklist =
498      function
499         [] -> []
500       | None::tl -> None::aux blacklist tl
501       | Some (name,_)::tl ->
502          if List.mem name blacklist then
503           None::aux blacklist tl
504          else
505           find_pattern_for name::aux (name::blacklist) tl
506     in
507      aux [] context
508    in
509    let subst,metasenv,ugraph,ty_terms =
510     select_in_term ~metasenv ~context ~ugraph ~term:ty
511      ~pattern:(what,goal_pattern) in
512    let subst,metasenv,ugraph,context_terms =
513     let subst,metasenv,ugraph,res,_ =
514      (List.fold_right
515       (fun (pattern,entry) (subst,metasenv,ugraph,res,context) ->
516         match entry with
517           None -> subst,metasenv,ugraph,None::res,None::context
518         | Some (name,Cic.Decl term) ->
519             (match pattern with
520             | None ->
521                subst,metasenv,ugraph,((Some (`Decl []))::res),(entry::context)
522             | Some pat ->
523                 let subst,metasenv,ugraph,terms =
524                  select_in_term ~metasenv ~context ~ugraph ~term
525                   ~pattern:(what, Some pat)
526                 in
527                  subst,metasenv,ugraph,((Some (`Decl terms))::res),
528                   (entry::context))
529         | Some (name,Cic.Def (bo, ty)) ->
530             (match pattern with
531             | None ->
532                let selected_ty = [] in
533                 subst,metasenv,ugraph,((Some (`Def ([],selected_ty)))::res),
534                  (entry::context)
535             | Some pat -> 
536                 let subst,metasenv,ugraph,terms_bo =
537                  select_in_term ~metasenv ~context ~ugraph ~term:bo
538                   ~pattern:(what, Some pat) in
539                 let subst,metasenv,ugraph,terms_ty =
540                  let subst,metasenv,ugraph,res =
541                   select_in_term ~metasenv ~context ~ugraph ~term:ty
542                    ~pattern:(what, Some pat)
543                  in
544                   subst,metasenv,ugraph,res
545                 in
546                  subst,metasenv,ugraph,((Some (`Def (terms_bo,terms_ty)))::res),
547                   (entry::context))
548       ) (List.combine full_hyp_pattern context) (subst,metasenv,ugraph,[],[]))
549     in
550      subst,metasenv,ugraph,res
551    in
552     subst,metasenv,ugraph,context_terms, ty_terms
553
554 (** locate_in_term equality what where context
555 * [what] must match a subterm of [where] according to [equality]
556 * It returns the matched terms together with their contexts in [where]
557 * [equality] defaults to physical equality
558 * [context] must be the context of [where]
559 *)
560 let locate_in_term ?(equality=(fun _ -> (==))) what ~where context =
561   let add_ctx context name entry =
562       (Some (name, entry)) :: context in
563   let rec aux context where =
564    if equality context what where then [context,where]
565    else
566     match where with
567     | Cic.Implicit _
568     | Cic.Meta _
569     | Cic.Rel _
570     | Cic.Sort _
571     | Cic.Var _
572     | Cic.Const _
573     | Cic.MutInd _
574     | Cic.MutConstruct _ -> []
575     | Cic.Cast (te, ty) -> aux context te @ aux context ty
576     | Cic.Prod (name, s, t)
577     | Cic.Lambda (name, s, t) ->
578         aux context s @ aux (add_ctx context name (Cic.Decl s)) t
579     | Cic.LetIn (name, s, ty, t) -> 
580         aux context s @
581         aux context ty @
582         aux (add_ctx context name (Cic.Def (s,ty))) t
583     | Cic.Appl tl -> auxs context tl
584     | Cic.MutCase (_, _, out, t, pat) ->
585         aux context out @ aux context t @ auxs context pat
586     | Cic.Fix (_, funs) ->
587        let tys =
588         List.map (fun (n,_,ty,_) -> Some (Cic.Name n,(Cic.Decl ty))) funs
589        in
590         List.concat
591           (List.map
592             (fun (_, _, ty, bo) -> 
593               aux context ty @ aux (tys @ context) bo)
594             funs)
595     | Cic.CoFix (_, funs) ->
596        let tys =
597         List.map (fun (n,ty,_) -> Some (Cic.Name n,(Cic.Decl ty))) funs
598        in
599         List.concat
600           (List.map
601             (fun (_, ty, bo) ->
602               aux context ty @ aux (tys @ context) bo)
603             funs)
604   and auxs context tl =  (* as aux for list of terms *)
605     List.concat (List.map (fun t -> aux context t) tl)
606   in
607    aux context where
608
609 (** locate_in_conjecture equality what where context
610 * [what] must match a subterm of [where] according to [equality]
611 * It returns the matched terms together with their contexts in [where]
612 * [equality] defaults to physical equality
613 * [context] must be the context of [where]
614 *)
615 let locate_in_conjecture ?(equality=fun _ -> (==)) what (_,context,ty) =
616  let context,res =
617   List.fold_right
618    (fun entry (context,res) ->
619      match entry with
620         None -> entry::context, res
621       | Some (_, Cic.Decl ty) ->
622          let res = res @ locate_in_term what ~where:ty context in
623          let context' = entry::context in
624           context',res
625       | Some (_, Cic.Def (bo,ty)) ->
626          let res = res @ locate_in_term what ~where:bo context in
627          let res = res @ locate_in_term what ~where:ty context in
628          let context' = entry::context in
629           context',res
630    ) context ([],[])
631  in
632   res @ locate_in_term what ~where:ty context
633
634 let lookup_type metasenv context hyp =
635    let rec aux p = function
636       | Some (Cic.Name name, Cic.Decl t) :: _ when name = hyp -> p, t
637       | Some (Cic.Name name, Cic.Def (_,t)) :: _ when name = hyp -> p, t
638       | _ :: tail -> aux (succ p) tail
639       | [] -> raise (ProofEngineTypes.Fail (lazy "lookup_type: not premise in the current goal"))
640    in
641    aux 1 context
642
643 (* FG: **********************************************************************)
644
645 let get_name context index =
646    try match List.nth context (pred index) with
647       | Some (Cic.Name name, _)     -> Some name
648       | _                           -> None
649    with Invalid_argument "List.nth" -> None
650
651 let get_rel context name =
652    let rec aux i = function
653       | []                                      -> None
654       | Some (Cic.Name s, _) :: _ when s = name -> Some (Cic.Rel i)
655       | _ :: tl                                 -> aux (succ i) tl
656    in
657    aux 1 context
658
659 let split_with_whd (c, t) =
660    let add s v c = Some (s, Cic.Decl v) :: c in
661    let rec aux whd a n c = function
662       | Cic.Prod (s, v, t)  -> aux false ((c, v) :: a) (succ n) (add s v c) t
663       | v when whd          -> (c, v) :: a, n
664       | v                   -> aux true a n c (CicReduction.whd c v)
665     in
666     aux false [] 0 c t
667
668 let split_with_normalize (c, t) =
669    let add s v c = Some (s, Cic.Decl v) :: c in
670    let rec aux a n c = function
671       | Cic.Prod (s, v, t)  -> aux ((c, v) :: a) (succ n) (add s v c) t
672       | v                   -> (c, v) :: a, n
673     in
674     aux [] 0 c (CicReduction.normalize c t)
675
676   (* menv sorting *)
677 module OT = 
678   struct 
679     type t = Cic.conjecture
680     let compare (i,_,_) (j,_,_) = Pervasives.compare i j
681   end
682 module MS = HTopoSort.Make(OT)
683 let relations_of_menv m c =
684   let i, ctx, ty = c in
685   let m = List.filter (fun (j,_,_) -> j <> i) m in
686   let m_ty = List.map fst (CicUtil.metas_of_term ty) in
687   let m_ctx = 
688     List.flatten
689       (List.map 
690         (function 
691          | None -> []
692          | Some (_,Cic.Decl t) ->
693              List.map fst (CicUtil.metas_of_term ty)
694          | Some (_,Cic.Def (t,ty)) -> 
695              List.map fst (CicUtil.metas_of_term ty) @
696              List.map fst (CicUtil.metas_of_term t))
697         ctx)
698   in
699   let metas = HExtlib.list_uniq (List.sort compare (m_ty @ m_ctx)) in
700   List.filter (fun (i,_,_) -> List.exists ((=) i) metas) m
701 ;;
702 let sort_metasenv (m : Cic.metasenv) =
703   (MS.topological_sort m (relations_of_menv m) : Cic.metasenv)
704 ;;