]> matita.cs.unibo.it Git - helm.git/blob - helm/software/components/ng_refiner/nCicUnification.ml
1) ppmetasenv and ppcontext to reduce the amount of printed information during
[helm.git] / helm / software / components / ng_refiner / nCicUnification.ml
1 (*
2     ||M||  This file is part of HELM, an Hypertextual, Electronic        
3     ||A||  Library of Mathematics, developed at the Computer Science     
4     ||T||  Department, University of Bologna, Italy.                     
5     ||I||                                                                
6     ||T||  HELM is free software; you can redistribute it and/or         
7     ||A||  modify it under the terms of the GNU General Public License   
8     \   /  version 2 or (at your option) any later version.      
9      \ /   This software is distributed as is, NO WARRANTY.     
10       V_______________________________________________________________ *)
11
12 (* $Id$ *)
13
14 exception UnificationFailure of string Lazy.t;;
15 exception Uncertain of string Lazy.t;;
16 exception AssertFailure of string Lazy.t;;
17
18 let (===) x y = Pervasives.compare x y = 0 ;;
19
20 let uncert_exc metasenv subst context t1 t2 = 
21   Uncertain (lazy (
22   "Can't unify " ^ NCicPp.ppterm ~metasenv ~subst ~context t1 ^
23   " with " ^ NCicPp.ppterm ~metasenv ~subst ~context t2))
24 ;;
25
26 let fail_exc metasenv subst context t1 t2 = 
27   UnificationFailure (lazy (
28   "Can't unify " ^ NCicPp.ppterm ~metasenv ~subst ~context t1 ^
29   " with " ^ NCicPp.ppterm ~metasenv ~subst ~context t2));
30 ;;
31
32 let mk_appl ~upto hd tl =
33   NCicReduction.head_beta_reduce ~upto
34     (match hd with
35     | NCic.Appl l -> NCic.Appl (l@tl)
36     | _ -> NCic.Appl (hd :: tl))
37 ;;
38
39 exception WrongShape;;
40
41 let eta_reduce subst t = 
42   let delift_if_not_occur body =
43     try 
44         Some (NCicSubstitution.psubst ~avoid_beta_redexes:true
45           (fun () -> raise WrongShape) [()] body)
46     with WrongShape -> None
47   in 
48   let rec eat_lambdas ctx = function
49     | NCic.Lambda (name, src, tgt) -> 
50         eat_lambdas ((name, src) :: ctx) tgt
51     | NCic.Meta (i,lc) as t->
52         (try 
53           let _,_,t,_ = NCicUtils.lookup_subst i subst in
54           let t = NCicSubstitution.subst_meta lc t in
55           eat_lambdas ctx t
56         with Not_found -> ctx, t)
57     | t -> ctx, t
58   in
59   let context_body = eat_lambdas [] t in
60   let rec aux = function
61     | [],body -> body
62     | (name, src)::ctx, (NCic.Appl (hd::[NCic.Rel 1]) as bo) -> 
63         (match delift_if_not_occur hd with
64         | None -> aux (ctx,NCic.Lambda(name,src, bo)) 
65         | Some bo -> aux (ctx,bo))
66     | (name, src)::ctx, (NCic.Appl args as bo) 
67       when HExtlib.list_last args = NCic.Rel 1 -> 
68         let args, _ = HExtlib.split_nth (List.length args - 1) args in
69         (match delift_if_not_occur (NCic.Appl args) with
70         | None -> aux (ctx,NCic.Lambda(name,src, bo)) 
71         | Some bo -> aux (ctx,bo))
72     | (name, src) :: ctx, t ->
73         aux (ctx,NCic.Lambda(name,src, t)) 
74   in
75     aux context_body
76 ;;
77
78 module C = NCic;;
79 module Ref = NReference;;
80
81 let indent = ref "";;
82 let inside c = indent := !indent ^ String.make 1 c;;
83 let outside () = indent := String.sub !indent 0 (String.length !indent -1);;
84
85 let pp s = 
86   prerr_endline (Printf.sprintf "%-20s" !indent ^ " " ^ Lazy.force s)
87 ;;
88
89 let ppcontext = NCicPp.ppcontext;;
90 let ppmetasenv = NCicPp.ppmetasenv;;
91
92 (*let ppcontext ~metasenv ~subst context = "...";;
93 let ppmetasenv ~subst metasenv = "...";;*)
94
95 let pp _ = ();;
96
97 let fix_sorts swap metasenv subst context meta t =
98   let rec aux () = function
99     | NCic.Sort (NCic.Type u) as orig ->
100         if swap then
101          match NCicEnvironment.sup u with
102          | None -> prerr_endline "no sup for" ;
103             raise (fail_exc metasenv subst context meta t)
104          | Some u1 -> if u = u1 then orig else NCic.Sort (NCic.Type u1)
105         else
106          NCic.Sort (NCic.Type (
107            match NCicEnvironment.sup NCicEnvironment.type0 with 
108            | Some x -> x
109            | _ -> assert false))
110     | NCic.Meta _ as orig -> orig
111     | t -> NCicUtils.map (fun _ _ -> ()) () aux t
112   in
113     aux () t
114 ;;
115
116 let is_locked n subst =
117    try
118      match NCicUtils.lookup_subst n subst with
119      | Some tag, _,_,_ when NCicMetaSubst.is_out_scope_tag tag -> true
120      | _ -> false
121    with NCicUtils.Subst_not_found _ -> false
122 ;;
123
124
125 let rec lambda_intros metasenv subst context t args =
126  let tty = NCicTypeChecker.typeof ~metasenv ~subst context t in
127  let argsty = List.map (NCicTypeChecker.typeof ~metasenv ~subst context) args in
128  let rec mk_lambda context n = function
129    | [] -> 
130        let metasenv, _, bo, _ = 
131          NCicMetaSubst.mk_meta metasenv context 
132            (`WithType (NCicSubstitution.lift n tty))
133        in
134        metasenv, bo
135    | ty::tail -> 
136        let name = "HBeta"^string_of_int n in
137        let ty = NCicSubstitution.lift n ty in
138        let metasenv, bo = mk_lambda ((name,NCic.Decl ty)::context) (n+1) tail in
139        metasenv, NCic.Lambda (name, ty, bo)
140  in
141    mk_lambda context 0 argsty
142
143 and instantiate rdb test_eq_only metasenv subst context n lc t swap =
144  (*D*)  inside 'I'; try let rc =  
145          pp (lazy(string_of_int n ^ " :=?= "^
146            NCicPp.ppterm ~metasenv ~subst ~context t));
147   let unify test_eq_only m s c t1 t2 = 
148     if swap then unify rdb test_eq_only m s c t2 t1 
149     else unify rdb test_eq_only m s c t1 t2
150   in
151   let name, ctx, ty = NCicUtils.lookup_meta n metasenv in
152   let metasenv, subst, t = 
153     match ty with 
154     | NCic.Implicit (`Typeof _) -> 
155        metasenv,subst, t
156          (* fix_sorts swap metasenv subst context (NCic.Meta(n,lc)) t *)
157     | _ ->
158        pp (lazy (
159          "typeof: " ^ NCicPp.ppterm ~metasenv ~subst ~context t ^ "\nctx:\n"^
160           ppcontext ~metasenv ~subst context ^ "\nmenv:\n"^
161           ppmetasenv ~subst metasenv));
162        let t, ty_t = 
163          try t, NCicTypeChecker.typeof ~subst ~metasenv context t 
164          with 
165          | NCicTypeChecker.AssertFailure msg -> 
166            (pp (lazy "fine typeof (fallimento)");
167            let ft=fix_sorts swap metasenv subst context (NCic.Meta (n,lc)) t in
168            if ft == t then 
169              (prerr_endline ( ("ILLTYPED: " ^ 
170                 NCicPp.ppterm ~metasenv ~subst ~context t
171             ^ "\nBECAUSE:" ^ Lazy.force msg ^ "\nCONTEXT:\n" ^
172             ppcontext ~metasenv ~subst context ^ "\nMENV:\n" ^
173             ppmetasenv ~subst metasenv
174             ));
175                      assert false)
176            else
177             try 
178               pp (lazy ("typeof: " ^ 
179                 NCicPp.ppterm ~metasenv ~subst ~context ft));
180               ft, NCicTypeChecker.typeof ~subst ~metasenv context ft 
181             with NCicTypeChecker.AssertFailure _ -> 
182               assert false)
183          | NCicTypeChecker.TypeCheckerFailure msg ->
184               prerr_endline (Lazy.force msg);
185               pp msg; assert false
186        in
187        let lty = NCicSubstitution.subst_meta lc ty in
188        match ty_t with
189        | NCic.Implicit _ -> 
190            raise (UnificationFailure 
191              (lazy "trying to unify a term with a type"))
192        | ty_t -> 
193           pp (lazy ("On the types: " ^
194            NCicPp.ppterm ~metasenv ~subst ~context:ctx ty ^ " ~~~ " ^
195            NCicPp.ppterm ~metasenv ~subst ~context lty ^ " === "
196             ^ NCicPp.ppterm ~metasenv ~subst ~context ty_t)); 
197           let metasenv,subst = 
198             unify test_eq_only metasenv subst context lty ty_t in
199           metasenv, subst, t
200   in
201          pp (lazy(string_of_int n ^ " := 111 = "^
202            NCicPp.ppterm ~metasenv ~subst ~context t));
203   let (metasenv, subst), t = 
204     try 
205       NCicMetaSubst.delift 
206        ~unify:(fun m s c t1 t2 -> 
207          let ind = !indent in
208          let res = 
209            try Some (unify test_eq_only m s c t1 t2 )
210            with UnificationFailure _ | Uncertain _ -> None
211          in
212          indent := ind; res) 
213        metasenv subst context n lc t
214     with NCicMetaSubst.Uncertain msg -> 
215          pp (lazy ("delift fails: " ^ Lazy.force msg));
216          raise (Uncertain msg)
217     | NCicMetaSubst.MetaSubstFailure msg -> 
218          pp (lazy ("delift fails: " ^ Lazy.force msg));
219          raise (UnificationFailure msg)
220   in
221          pp (lazy(string_of_int n ^ " := 222 = "^
222            NCicPp.ppterm ~metasenv ~subst ~context:ctx t
223          ^ "\n" ^ ppmetasenv ~subst metasenv));
224   (* Unifying the types may have already instantiated n. *)
225   try
226     let _, _,oldt,_ = NCicUtils.lookup_subst n subst in
227     let oldt = NCicSubstitution.subst_meta lc oldt in
228     let t = NCicSubstitution.subst_meta lc t in
229     (* conjecture: always fail --> occur check *)
230     unify test_eq_only metasenv subst context oldt t
231   with NCicUtils.Subst_not_found _ -> 
232     (* by cumulativity when unify(?,Type_i) 
233      * we could ? := Type_j with j <= i... *)
234     let subst = (n, (name, ctx, t, ty)) :: subst in
235     pp (lazy ("?"^string_of_int n^" := "^NCicPp.ppterm
236       ~metasenv ~subst ~context (NCicSubstitution.subst_meta lc t)));
237     let metasenv = 
238       List.filter (fun (m,_) -> not (n = m)) metasenv 
239     in
240     metasenv, subst
241  (*D*)  in outside(); rc with exn -> outside (); raise exn 
242
243 and unify rdb test_eq_only metasenv subst context t1 t2 =
244  (*D*) inside 'U'; try let rc =
245    let fo_unif test_eq_only metasenv subst t1 t2 =
246     (*D*) inside 'F'; try let rc =  
247      pp (lazy("  " ^ NCicPp.ppterm ~metasenv ~subst ~context t1 ^ " ==?== " ^ 
248          NCicPp.ppterm ~metasenv ~subst ~context t2 ^ "\n" ^ ppmetasenv
249          ~subst metasenv));
250      if t1 === t2 then
251        metasenv, subst
252      else
253        match (t1,t2) with
254        | C.Appl [_], _ | _, C.Appl [_] | C.Appl [], _ | _, C.Appl [] 
255        | C.Appl (C.Appl _::_), _ | _, C.Appl (C.Appl _::_) -> 
256            prerr_endline "Appl [Appl _;_] or Appl [] or Appl [_] invariant";
257            assert false 
258        | (C.Sort (C.Type a), C.Sort (C.Type b)) when not test_eq_only -> 
259            if NCicEnvironment.universe_leq a b then metasenv, subst
260            else raise (fail_exc metasenv subst context t1 t2)
261        | (C.Sort (C.Type a), C.Sort (C.Type b)) -> 
262            if NCicEnvironment.universe_eq a b then metasenv, subst
263            else raise (fail_exc metasenv subst context t1 t2)
264        | (C.Sort C.Prop,C.Sort (C.Type _)) -> 
265            if (not test_eq_only) then metasenv, subst
266            else raise (fail_exc metasenv subst context t1 t2)
267
268        | (C.Lambda (name1,s1,t1), C.Lambda(_,s2,t2)) 
269        | (C.Prod (name1,s1,t1), C.Prod(_,s2,t2)) ->
270            let metasenv, subst = unify rdb true metasenv subst context s1 s2 in
271            unify rdb test_eq_only metasenv subst ((name1, C.Decl s1)::context) t1 t2
272        | (C.LetIn (name1,ty1,s1,t1), C.LetIn(_,ty2,s2,t2)) ->
273            let metasenv,subst=unify rdb test_eq_only metasenv subst context ty1 ty2 in
274            let metasenv,subst=unify rdb test_eq_only metasenv subst context s1 s2 in
275            let context = (name1, C.Def (s1,ty1))::context in
276            unify rdb test_eq_only metasenv subst context t1 t2
277
278        | (C.Meta (n1,(s1,l1 as lc1)),C.Meta (n2,(s2,l2 as lc2))) when n1 = n2 ->
279           (try 
280            let l1 = NCicUtils.expand_local_context l1 in
281            let l2 = NCicUtils.expand_local_context l2 in
282            let metasenv, subst, to_restrict, _ =
283             List.fold_right2 
284              (fun t1 t2 (metasenv, subst, to_restrict, i) -> 
285                 try 
286                   let metasenv, subst = 
287                    unify rdb test_eq_only metasenv subst context 
288                     (NCicSubstitution.lift s1 t1) (NCicSubstitution.lift s2 t2)
289                   in
290                   metasenv, subst, to_restrict, i-1  
291                 with UnificationFailure _ | Uncertain _ ->
292                   metasenv, subst, i::to_restrict, i-1)
293              l1 l2 (metasenv, subst, [], List.length l1)
294            in
295            if to_restrict <> [] then
296              let metasenv, subst, _ = 
297                NCicMetaSubst.restrict metasenv subst n1 to_restrict
298              in
299                metasenv, subst
300            else metasenv, subst
301           with 
302            | Invalid_argument _ -> assert false
303            | NCicMetaSubst.MetaSubstFailure msg ->
304               try 
305                 let _,_,term,_ = NCicUtils.lookup_subst n1 subst in
306                 let term1 = NCicSubstitution.subst_meta lc1 term in
307                 let term2 = NCicSubstitution.subst_meta lc2 term in
308                   unify rdb test_eq_only metasenv subst context term1 term2
309               with NCicUtils.Subst_not_found _-> raise (UnificationFailure msg))
310        
311        | _, NCic.Meta (n, _) when is_locked n subst ->
312            (let (metasenv, subst), i = 
313               match NCicReduction.whd ~subst context t1 with
314               | NCic.Appl (NCic.Meta (i,l)::args) when
315                   not (NCicMetaSubst.flexible subst args) 
316                 ->
317                  let metasenv, lambda_Mj =
318                    lambda_intros metasenv subst context t1 args
319                  in
320                    unify rdb test_eq_only metasenv subst context 
321                     (C.Meta (i,l)) lambda_Mj,
322                    i
323               | NCic.Meta (i,_) -> (metasenv, subst), i
324               | _ -> assert false
325              in
326               let t1 = NCicReduction.whd ~subst context t1 in
327               let j, lj = 
328                 match t1 with NCic.Meta (j,l) -> j, l | _ -> assert false
329               in
330               let metasenv, subst = 
331                 instantiate rdb test_eq_only metasenv subst context j lj t2 true
332               in
333               (* We need to remove the out_scope_tags to avoid propagation of
334                  them that triggers again the ad-hoc case *)
335               let subst =
336                List.map (fun (i,(tag,ctx,bo,ty)) ->
337                 let tag =
338                  match tag with
339                     Some tag when
340                         tag = NCicMetaSubst.in_scope_tag
341                      || NCicMetaSubst.is_out_scope_tag tag -> None
342                   | _ -> tag
343                 in
344                   i,(tag,ctx,bo,ty)
345                 ) subst
346               in
347               (try
348                 let name, ctx, term, ty = NCicUtils.lookup_subst i subst in
349                 let term = eta_reduce subst term in
350                 let subst = List.filter (fun (j,_) -> j <> i) subst in
351                 metasenv, ((i, (name, ctx, term, ty)) :: subst)
352               with Not_found -> assert false))
353
354        | C.Meta (n,lc), t -> 
355            (try 
356              let _,_,term,_ = NCicUtils.lookup_subst n subst in
357              let term = NCicSubstitution.subst_meta lc term in
358                unify rdb test_eq_only metasenv subst context term t
359            with NCicUtils.Subst_not_found _-> 
360              instantiate rdb test_eq_only metasenv subst context n lc 
361                (NCicReduction.head_beta_reduce ~subst t) false)
362
363        | t, C.Meta (n,lc) -> 
364            (try 
365              let _,_,term,_ = NCicUtils.lookup_subst n subst in
366              let term = NCicSubstitution.subst_meta lc term in
367                unify rdb test_eq_only metasenv subst context t term
368            with NCicUtils.Subst_not_found _-> 
369              instantiate rdb test_eq_only metasenv subst context n lc 
370               (NCicReduction.head_beta_reduce ~subst t) true)
371
372        | NCic.Appl (NCic.Meta (i,l)::args), _ when List.mem_assoc i subst ->
373             let _,_,term,_ = NCicUtils.lookup_subst i subst in
374             let term = NCicSubstitution.subst_meta l term in
375               unify rdb test_eq_only metasenv subst context 
376                 (mk_appl ~upto:(List.length args) term args) t2
377
378        | _, NCic.Appl (NCic.Meta (i,l)::args) when List.mem_assoc i subst ->
379             let _,_,term,_ = NCicUtils.lookup_subst i subst in
380             let term = NCicSubstitution.subst_meta l term in
381               unify rdb test_eq_only metasenv subst context t1 
382                 (mk_appl ~upto:(List.length args) term args)
383
384        |  NCic.Appl (NCic.Meta (i,_)::_ as l1),
385           NCic.Appl (NCic.Meta (j,_)::_ as l2) when i=j ->
386             (try
387               List.fold_left2 
388                 (fun (metasenv, subst) t1 t2 ->
389                   unify rdb test_eq_only metasenv subst context t1 t2)
390                 (metasenv,subst) l1 l2
391             with Invalid_argument _ -> 
392               raise (fail_exc metasenv subst context t1 t2))
393
394        | NCic.Appl (NCic.Meta (i,l)::args), _ when 
395          not (NCicMetaSubst.flexible subst args) ->
396            (* we verify that none of the args is a Meta, 
397               since beta expanding w.r.t a metavariable makes no sense  *)
398               let metasenv, lambda_Mj =
399                 lambda_intros metasenv subst context t1 args
400               in
401               let metasenv, subst = 
402                 unify rdb test_eq_only metasenv subst context 
403                   (C.Meta (i,l)) lambda_Mj
404               in
405               let metasenv, subst = 
406                 unify rdb test_eq_only metasenv subst context t1 t2 
407               in
408               (try
409                 let name, ctx, term, ty = NCicUtils.lookup_subst i subst in
410                 let term = eta_reduce subst term in
411                 let subst = List.filter (fun (j,_) -> j <> i) subst in
412                 metasenv, ((i, (name, ctx, term, ty)) :: subst)
413               with Not_found -> assert false)
414
415        | _, NCic.Appl (NCic.Meta (i,l)::args) when 
416          not(NCicMetaSubst.flexible subst args) ->
417               let metasenv, lambda_Mj =
418                 lambda_intros metasenv subst context t2 args
419               in
420               let metasenv, subst =
421                 unify rdb test_eq_only metasenv subst context 
422                  lambda_Mj (C.Meta (i,l))
423               in
424               let metasenv, subst = 
425                 unify rdb test_eq_only metasenv subst context t1 t2 
426               in
427               (try
428                 let name, ctx, term, ty = NCicUtils.lookup_subst i subst in
429                 let term = eta_reduce subst term in
430                 let subst = List.filter (fun (j,_) -> j <> i) subst in
431                 metasenv, ((i, (name, ctx, term, ty)) :: subst)
432               with Not_found -> assert false)
433
434        (* processing this case here we avoid a useless small delta step *)
435        | (C.Appl ((C.Const r1) as _hd1::tl1), C.Appl (C.Const r2::tl2)) 
436          when Ref.eq r1 r2 ->
437            let relevance = NCicEnvironment.get_relevance r1 in
438            let relevance = match r1 with
439              | Ref.Ref (_,Ref.Con (_,_,lno)) ->
440                  let relevance =
441                   try snd (HExtlib.split_nth lno relevance)
442                   with Failure _ -> []
443                  in
444                    HExtlib.mk_list false lno @ relevance
445              | _ -> relevance
446            in
447            let metasenv, subst, _ = 
448              try
449                List.fold_left2 
450                  (fun (metasenv, subst, relevance) t1 t2 ->
451                     let b, relevance = 
452                       match relevance with b::tl -> b,tl | _ -> true, [] in
453                     let metasenv, subst = 
454                       try unify rdb test_eq_only metasenv subst context t1 t2
455                       with UnificationFailure _ | Uncertain _ when not b ->
456                         metasenv, subst
457                     in
458                       metasenv, subst, relevance)
459                  (metasenv, subst, relevance) tl1 tl2
460              with Invalid_argument _ -> 
461                raise (uncert_exc metasenv subst context t1 t2)
462            in 
463              metasenv, subst
464
465        | (C.Match (Ref.Ref (_,Ref.Ind (_,tyno,_)) as ref1,outtype1,term1,pl1),
466           C.Match (ref2,outtype2,term2,pl2)) ->
467            let _,_,itl,_,_ = NCicEnvironment.get_checked_indtys ref1 in
468            let _,_,ty,_ = List.nth itl tyno in
469            let rec remove_prods ~subst context ty = 
470              let ty = NCicReduction.whd ~subst context ty in
471              match ty with
472              | C.Sort _ -> ty
473              | C.Prod (name,so,ta) -> 
474                    remove_prods ~subst ((name,(C.Decl so))::context) ta
475              | _ -> assert false
476            in
477            let is_prop = 
478              match remove_prods ~subst [] ty with
479              | C.Sort C.Prop -> true
480              | _ -> false 
481            in
482            if not (Ref.eq ref1 ref2) then 
483              raise (uncert_exc metasenv subst context t1 t2) 
484            else
485              let metasenv, subst = 
486               unify rdb test_eq_only metasenv subst context outtype1 outtype2 in
487              let metasenv, subst = 
488                try unify rdb test_eq_only metasenv subst context term1 term2 
489                with UnificationFailure _ | Uncertain _ when is_prop -> 
490                  metasenv, subst
491              in
492              (try
493               List.fold_left2 
494                (fun (metasenv,subst) -> 
495                   unify rdb test_eq_only metasenv subst context)
496                (metasenv, subst) pl1 pl2
497              with Invalid_argument _ -> 
498                raise (uncert_exc metasenv subst context t1 t2))
499        | (C.Implicit _, _) | (_, C.Implicit _) -> assert false
500        | _ when NCicUntrusted.metas_of_term subst context t1 = [] && 
501                 NCicUntrusted.metas_of_term subst context t2 = [] -> 
502                   raise (fail_exc metasenv subst context t1 t2)
503        | _ -> raise (uncert_exc metasenv subst context t1 t2)
504      (*D*)  in outside(); rc with exn -> outside (); raise exn 
505     in
506     let try_hints metasenv subst t1 t2 (* exc*) =
507 (*
508       prerr_endline ("\nProblema:\n" ^
509         NCicPp.ppterm ~metasenv ~subst ~context t1 ^ " =?= " ^
510         NCicPp.ppterm ~metasenv ~subst ~context t2);
511 *)
512       let candidates = 
513         NCicUnifHint.look_for_hint rdb metasenv subst context t1 t2
514       in
515       let rec cand_iter = function
516         | [] -> None (* raise exc *)
517         | (metasenv,(c1,c2),premises)::tl -> 
518 (*
519             prerr_endline ("\nProvo il candidato:\n" ^ 
520               String.concat "\n"
521                 (List.map 
522                   (fun (a,b) ->
523                    NCicPp.ppterm ~metasenv ~subst ~context a ^  " =?= " ^
524                    NCicPp.ppterm ~metasenv ~subst ~context b) premises) ^
525               "\n-------------------------------------------\n"^
526               NCicPp.ppterm ~metasenv ~subst ~context c1 ^  " = " ^
527               NCicPp.ppterm ~metasenv ~subst ~context c2);
528 *)
529             try 
530               let metasenv,subst = 
531                 fo_unif test_eq_only metasenv subst t1 c1 in
532               let metasenv,subst = 
533                 fo_unif test_eq_only metasenv subst c2 t2 in
534               let metasenv,subst = 
535                 List.fold_left 
536                   (fun (metasenv, subst) (x,y) ->
537                      unify rdb test_eq_only metasenv subst context x y)
538                   (metasenv, subst) premises
539               in
540               Some (metasenv, subst)
541             with
542               UnificationFailure _ | Uncertain _ ->
543                 cand_iter tl
544       in
545         cand_iter candidates
546     in
547     let height_of = function
548      | NCic.Const (Ref.Ref (_,Ref.Def h)) 
549      | NCic.Const (Ref.Ref (_,Ref.Fix (_,_,h))) 
550      | NCic.Appl(NCic.Const(Ref.Ref(_,Ref.Def h))::_) 
551      | NCic.Appl(NCic.Const(Ref.Ref(_,Ref.Fix (_,_,h)))::_) -> h
552      | _ -> 0
553     in
554     let put_in_whd m1 m2 =
555       NCicReduction.reduce_machine ~delta:max_int ~subst context m1,
556       NCicReduction.reduce_machine ~delta:max_int ~subst context m2
557     in
558     let small_delta_step ~subst  
559       ((_,_,t1,_ as m1, norm1) as x1) ((_,_,t2,_ as m2, norm2) as x2)
560     =
561      assert (not (norm1 && norm2));
562      if norm1 then
563       x1,NCicReduction.reduce_machine ~delta:(height_of t2 -1) ~subst context m2
564      else if norm2 then
565       NCicReduction.reduce_machine ~delta:(height_of t1 -1) ~subst context m1,x2
566      else 
567       let h1 = height_of t1 in 
568       let h2 = height_of t2 in
569       let delta = if h1 = h2 then max 0 (h1 -1) else min h1 h2 in
570       NCicReduction.reduce_machine ~delta ~subst context m1,
571       NCicReduction.reduce_machine ~delta ~subst context m2
572     in
573     let rec unif_machines metasenv subst = 
574       function
575       | ((k1,e1,t1,s1),norm1 as m1),((k2,e2,t2,s2),norm2 as m2) ->
576      (*D*) inside 'M'; try let rc = 
577          pp (lazy("UM: " ^
578            NCicPp.ppterm ~metasenv ~subst ~context 
579              (NCicReduction.unwind (k1,e1,t1,s1)) ^
580            " === " ^ 
581            NCicPp.ppterm ~metasenv ~subst ~context 
582              (NCicReduction.unwind (k2,e2,t2,s2))));
583 pp (lazy (string_of_bool norm1 ^ " ?? " ^ string_of_bool norm2));
584           let relevance = [] (* TO BE UNDERSTOOD 
585             match t1 with
586             | C.Const r -> NCicEnvironment.get_relevance r
587             | _ -> [] *) in
588           let unif_from_stack t1 t2 b metasenv subst =
589               try
590                 let t1 = NCicReduction.from_stack t1 in
591                 let t2 = NCicReduction.from_stack t2 in
592                 unif_machines metasenv subst (put_in_whd t1 t2)
593               with UnificationFailure _ | Uncertain _ when not b ->
594                 metasenv, subst
595           in
596           let rec check_stack l1 l2 r todo =
597             match l1,l2,r with
598             | x1::tl1, x2::tl2, r::tr-> check_stack tl1 tl2 tr ((x1,x2,r)::todo)
599             | x1::tl1, x2::tl2, []-> check_stack tl1 tl2 [] ((x1,x2,true)::todo)
600             | l1, l2, _ -> 
601                NCicReduction.unwind (k1,e1,t1,List.rev l1),
602                 NCicReduction.unwind (k2,e2,t2,List.rev l2),
603                 todo
604           in
605         let hh1,hh2,todo=check_stack (List.rev s1) (List.rev s2) relevance [] in
606         try
607          let metasenv,subst = fo_unif test_eq_only metasenv subst hh1 hh2 in
608          List.fold_left
609           (fun (metasenv,subst) (x1,x2,r) ->
610             unif_from_stack x1 x2 r metasenv subst
611           ) (metasenv,subst) todo
612         with UnificationFailure _ | Uncertain _ when not (norm1 && norm2) ->
613             unif_machines metasenv subst (small_delta_step ~subst m1 m2)
614       (*D*)  in outside(); rc with exn -> outside (); raise exn 
615      in
616      try fo_unif test_eq_only metasenv subst t1 t2
617      with 
618      | UnificationFailure msg as exn ->
619           (try 
620             unif_machines metasenv subst 
621              (put_in_whd (0,[],t1,[]) (0,[],t2,[]))
622           with 
623           | UnificationFailure _ -> raise (UnificationFailure msg)
624           | Uncertain _ -> raise exn)
625      | Uncertain msg as exn -> 
626        match try_hints metasenv subst t1 t2 with
627        | Some x -> x
628        | None -> 
629           try 
630             unif_machines metasenv subst 
631              (put_in_whd (0,[],t1,[]) (0,[],t2,[]))
632           with 
633           | UnificationFailure _ -> raise (UnificationFailure msg)
634           | Uncertain _ -> raise exn
635  (*D*)  in outside(); rc with exn -> outside (); raise exn 
636 ;;
637
638 let unify rdb ?(test_eq_only=false) = 
639   indent := "";      
640   unify rdb test_eq_only;;