1 (* Copyright (C) 2000, HELM Team.
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.
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.
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.
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,
22 * For details, see the HELM World-Wide-Web page,
23 * http://cs.unibo.it/helm/.
28 exception UnificationFailure of string;;
29 exception Uncertain of string;;
30 exception AssertFailure of string;;
32 let debug_print = prerr_endline
34 let type_of_aux' metasenv subst context term =
36 CicMetaSubst.type_of_aux' metasenv subst context term
38 | CicMetaSubst.MetaSubstFailure msg ->
41 "Type checking error: %s in context\n%s\nand metasenv\n%s.\nException: %s.\nBroken invariant: unification must be invoked only on well typed terms"
42 (CicMetaSubst.ppterm subst term)
43 (CicMetaSubst.ppcontext subst context)
44 (CicMetaSubst.ppmetasenv metasenv subst) msg)))
46 let rec eta_expand test_equality_only metasenv subst context t arg =
47 let module T = CicTypeChecker in
48 let module S = CicSubstitution in
50 let rec aux metasenv subst n context t' =
53 fo_unif_subst test_equality_only subst context metasenv arg t'
55 subst,metasenv,C.Rel (1 + n)
58 | UnificationFailure _ ->
60 | C.Rel m -> subst,metasenv, if m <= n then C.Rel m else C.Rel (m+1)
61 | C.Var (uri,exp_named_subst) ->
62 let subst,metasenv,exp_named_subst' =
63 aux_exp_named_subst metasenv subst n context exp_named_subst
65 subst,metasenv,C.Var (uri,exp_named_subst')
68 let t' = List.assoc i subst in
69 aux metasenv subst n context t'
71 Not_found -> subst,metasenv,t)
73 | C.Implicit _ as t -> subst,metasenv,t
75 let subst,metasenv,te' = aux metasenv subst n context te in
76 let subst,metasenv,ty' = aux metasenv subst n context ty in
77 subst,metasenv,C.Cast (te', ty')
79 let subst,metasenv,s' = aux metasenv subst n context s in
80 let subst,metasenv,t' =
81 aux metasenv subst (n+1) ((Some (nn, C.Decl s))::context) t
83 subst,metasenv,C.Prod (nn, s', t')
84 | C.Lambda (nn,s,t) ->
85 let subst,metasenv,s' = aux metasenv subst n context s in
86 let subst,metasenv,t' =
87 aux metasenv subst (n+1) ((Some (nn, C.Decl s))::context) t
89 subst,metasenv,C.Lambda (nn, s', t')
91 let subst,metasenv,s' = aux metasenv subst n context s in
92 let subst,metasenv,t' =
93 aux metasenv subst (n+1) ((Some (nn, C.Def (s,None)))::context) t
95 subst,metasenv,C.LetIn (nn, s', t')
97 let subst,metasenv,revl' =
99 (fun (subst,metasenv,appl) t ->
100 let subst,metasenv,t' = aux metasenv subst n context t in
101 subst,metasenv,t'::appl
102 ) (subst,metasenv,[]) l
104 subst,metasenv,C.Appl (List.rev revl')
105 | C.Const (uri,exp_named_subst) ->
106 let subst,metasenv,exp_named_subst' =
107 aux_exp_named_subst metasenv subst n context exp_named_subst
109 subst,metasenv,C.Const (uri,exp_named_subst')
110 | C.MutInd (uri,i,exp_named_subst) ->
111 let subst,metasenv,exp_named_subst' =
112 aux_exp_named_subst metasenv subst n context exp_named_subst
114 subst,metasenv,C.MutInd (uri,i,exp_named_subst')
115 | C.MutConstruct (uri,i,j,exp_named_subst) ->
116 let subst,metasenv,exp_named_subst' =
117 aux_exp_named_subst metasenv subst n context exp_named_subst
119 subst,metasenv,C.MutConstruct (uri,i,j,exp_named_subst')
120 | C.MutCase (sp,i,outt,t,pl) ->
121 let subst,metasenv,outt' = aux metasenv subst n context outt in
122 let subst,metasenv,t' = aux metasenv subst n context t in
123 let subst,metasenv,revpl' =
125 (fun (subst,metasenv,pl) t ->
126 let subst,metasenv,t' = aux metasenv subst n context t in
127 subst,metasenv,t'::pl
128 ) (subst,metasenv,[]) pl
130 subst,metasenv,C.MutCase (sp,i,outt', t', List.rev revpl')
132 (*CSC: not implemented
133 let tylen = List.length fl in
136 (fun (name,i,ty,bo) -> (name, i, aux n ty, aux (n+tylen) bo))
139 C.Fix (i, substitutedfl)
140 *) subst,metasenv,CicMetaSubst.lift subst 1 t'
142 (*CSC: not implemented
143 let tylen = List.length fl in
146 (fun (name,ty,bo) -> (name, aux n ty, aux (n+tylen) bo))
149 C.CoFix (i, substitutedfl)
150 *) subst,metasenv,CicMetaSubst.lift subst 1 t'
152 and aux_exp_named_subst metasenv subst n context ens =
154 (fun (uri,t) (subst,metasenv,l) ->
155 let subst,metasenv,t' = aux metasenv subst n context t in
156 subst,metasenv,(uri,t')::l) ens (subst,metasenv,[])
159 T.type_of_aux' metasenv context arg
162 FreshNamesGenerator.mk_fresh_name
163 metasenv context (Cic.Name "Heta") ~typ:argty
165 let subst,metasenv,t' = aux metasenv subst 0 context t in
166 subst,metasenv, C.Appl [C.Lambda (fresh_name,argty,t') ; arg]
168 and eta_expand_many test_equality_only metasenv subst context t =
170 (fun (subst,metasenv,t) arg ->
171 eta_expand test_equality_only metasenv subst context t arg
174 (* NUOVA UNIFICAZIONE *)
175 (* A substitution is a (int * Cic.term) list that associates a
176 metavariable i with its body.
177 A metaenv is a (int * Cic.term) list that associate a metavariable
179 fo_unif_new takes a metasenv, a context, two terms t1 and t2 and gives back
180 a new substitution which is _NOT_ unwinded. It must be unwinded before
183 and fo_unif_subst test_equality_only subst context metasenv t1 t2 =
184 let module C = Cic in
185 let module R = CicMetaSubst in
186 let module S = CicSubstitution in
188 (C.Meta (n,ln), C.Meta (m,lm)) when n=m ->
189 let ok,subst,metasenv =
192 (fun (b,subst,metasenv) t1 t2 ->
193 if b then true,subst,metasenv else
196 | _,None -> true,subst,metasenv
197 | Some t1', Some t2' ->
198 (* First possibility: restriction *)
199 (* Second possibility: unification *)
200 (* Third possibility: convertibility *)
201 if R.are_convertible subst context t1' t2' then
207 test_equality_only subst context metasenv t1' t2'
211 Not_found -> false,subst,metasenv)
212 ) (true,subst,metasenv) ln lm
214 Invalid_argument _ ->
215 raise (UnificationFailure (sprintf
216 "Error trying to unify %s with %s: the lengths of the two local contexts do not match." (CicMetaSubst.ppterm subst t1) (CicMetaSubst.ppterm subst t2)))
221 raise (UnificationFailure (sprintf
222 "Error trying to unify %s with %s: the algorithm tried to check whether the two substitutions are convertible; if they are not, it tried to unify the two substitutions. No restriction was attempted."
223 (CicMetaSubst.ppterm subst t1) (CicMetaSubst.ppterm subst t2)))
224 | (C.Meta (n,_), C.Meta (m,_)) when n>m ->
225 fo_unif_subst test_equality_only subst context metasenv t2 t1
227 | (t, C.Meta (n,l)) ->
230 C.Meta (n,_), C.Meta (m,_) when n < m -> false
231 | _, C.Meta _ -> false
234 let lower = fun x y -> if swap then y else x in
235 let upper = fun x y -> if swap then x else y in
236 let fo_unif_subst_ordered
237 test_equality_only subst context metasenv m1 m2 =
238 fo_unif_subst test_equality_only subst context metasenv
239 (lower m1 m2) (upper m1 m2)
241 let subst'',metasenv' =
243 let oldt = (List.assoc n subst) in
244 let lifted_oldt = S.lift_meta l oldt in
245 fo_unif_subst_ordered
246 test_equality_only subst context metasenv t lifted_oldt
248 let t',metasenv',subst' =
250 CicMetaSubst.delift n subst context metasenv l t
252 (CicMetaSubst.MetaSubstFailure msg)-> raise(UnificationFailure msg)
253 | (CicMetaSubst.Uncertain msg) -> raise (Uncertain msg)
257 C.Sort (C.Type u) when not test_equality_only ->
258 let u' = CicUniv.fresh () in
259 let s = C.Sort (C.Type u') in
260 ignore (CicUniv.add_ge (upper u u') (lower u u')) ;
264 (n, t'')::subst', metasenv'
266 let (_,_,meta_type) = CicUtil.lookup_meta n metasenv' in
269 type_of_aux' metasenv' subst'' context t
273 subst'' context metasenv' tyt (S.lift_meta l meta_type)
274 with AssertFailure _ ->
275 (* TODO huge hack!!!!
276 * we keep on unifying/refining in the hope that the problem will be
277 * eventually solved. In the meantime we're breaking a big invariant:
278 * the terms that we are unifying are no longer well typed in the
279 * current context (in the worst case we could even diverge)
282 prerr_endline "********* FROM NOW ON EVERY REASONABLE INVARIANT IS BROKEN.";
283 prerr_endline "********* PROCEED AT YOUR OWN RISK. AND GOOD LUCK." ;
285 (subst'', metasenv'))
286 | (C.Var (uri1,exp_named_subst1),C.Var (uri2,exp_named_subst2))
287 | (C.Const (uri1,exp_named_subst1),C.Const (uri2,exp_named_subst2)) ->
288 if UriManager.eq uri1 uri2 then
289 fo_unif_subst_exp_named_subst test_equality_only subst context metasenv
290 exp_named_subst1 exp_named_subst2
292 raise (UnificationFailure (sprintf
293 "Can't unify %s with %s due to different constants"
294 (CicMetaSubst.ppterm subst t1) (CicMetaSubst.ppterm subst t2)))
295 | C.MutInd (uri1,i1,exp_named_subst1),C.MutInd (uri2,i2,exp_named_subst2) ->
296 if UriManager.eq uri1 uri2 && i1 = i2 then
297 fo_unif_subst_exp_named_subst test_equality_only subst context metasenv
298 exp_named_subst1 exp_named_subst2
300 raise (UnificationFailure (sprintf
301 "Can't unify %s with %s due to different inductive principles"
302 (CicMetaSubst.ppterm subst t1) (CicMetaSubst.ppterm subst t2)))
303 | C.MutConstruct (uri1,i1,j1,exp_named_subst1),
304 C.MutConstruct (uri2,i2,j2,exp_named_subst2) ->
305 if UriManager.eq uri1 uri2 && i1 = i2 && j1 = j2 then
306 fo_unif_subst_exp_named_subst test_equality_only subst context metasenv
307 exp_named_subst1 exp_named_subst2
309 raise (UnificationFailure (sprintf
310 "Can't unify %s with %s due to different inductive constructors"
311 (CicMetaSubst.ppterm subst t1) (CicMetaSubst.ppterm subst t2)))
312 | (C.Implicit _, _) | (_, C.Implicit _) -> assert false
313 | (C.Cast (te,ty), t2) -> fo_unif_subst test_equality_only
314 subst context metasenv te t2
315 | (t1, C.Cast (te,ty)) -> fo_unif_subst test_equality_only
316 subst context metasenv t1 te
317 | (C.Prod (n1,s1,t1), C.Prod (_,s2,t2)) ->
318 (* TASSI: this is the only case in which we want == *)
319 let subst',metasenv' = fo_unif_subst true
320 subst context metasenv s1 s2 in
321 fo_unif_subst test_equality_only
322 subst' ((Some (n1,(C.Decl s1)))::context) metasenv' t1 t2
323 | (C.Lambda (n1,s1,t1), C.Lambda (_,s2,t2)) ->
324 (* TASSI: ask someone a reason for not putting true here *)
325 let subst',metasenv' = fo_unif_subst test_equality_only
326 subst context metasenv s1 s2 in
327 fo_unif_subst test_equality_only
328 subst' ((Some (n1,(C.Decl s1)))::context) metasenv' t1 t2
329 | (C.LetIn (_,s1,t1), t2)
330 | (t2, C.LetIn (_,s1,t1)) ->
332 test_equality_only subst context metasenv t2 (S.subst s1 t1)
333 | (C.Appl l1, C.Appl l2) ->
334 let subst,metasenv,t1',t2' =
336 (* In the first two cases when we reach the next begin ... end
337 section useless work is done since, by construction, the list
338 of arguments will be equal.
340 C.Meta (i,l)::args, _ ->
341 let subst,metasenv,t2' =
342 eta_expand_many test_equality_only metasenv subst context t2 args
344 subst,metasenv,t1,t2'
345 | _, C.Meta (i,l)::args ->
346 let subst,metasenv,t1' =
347 eta_expand_many test_equality_only metasenv subst context t1 args
349 subst,metasenv,t1',t2
350 | _,_ -> subst,metasenv,t1,t2
354 C.Appl l1, C.Appl l2 ->
355 let lr1 = List.rev l1 in
356 let lr2 = List.rev l2 in
357 let rec fo_unif_l test_equality_only subst metasenv =
360 | _,[] -> assert false
362 fo_unif_subst test_equality_only subst context metasenv h1 h2
366 test_equality_only subst context metasenv h (C.Appl (List.rev l))
367 | ((h1::l1),(h2::l2)) ->
368 let subst', metasenv' =
369 fo_unif_subst test_equality_only subst context metasenv h1 h2
371 fo_unif_l test_equality_only subst' metasenv' (l1,l2)
373 fo_unif_l test_equality_only subst metasenv (lr1, lr2)
376 | (C.MutCase (_,_,outt1,t1',pl1), C.MutCase (_,_,outt2,t2',pl2))->
377 let subst', metasenv' =
378 fo_unif_subst test_equality_only subst context metasenv outt1 outt2 in
379 let subst'',metasenv'' =
380 fo_unif_subst test_equality_only subst' context metasenv' t1' t2' in
383 (function (subst,metasenv) ->
384 fo_unif_subst test_equality_only subst context metasenv
385 ) (subst'',metasenv'') pl1 pl2
387 Invalid_argument _ ->
388 raise (UnificationFailure (sprintf
389 "Error trying to unify %s with %s: the number of branches is not the same." (CicMetaSubst.ppterm subst t1) (CicMetaSubst.ppterm subst t2))))
390 | (C.Rel _, _) | (_, C.Rel _)
391 | (C.Sort _ ,_) | (_, C.Sort _)
392 | (C.Const _, _) | (_, C.Const _)
393 | (C.MutInd _, _) | (_, C.MutInd _)
394 | (C.MutConstruct _, _) | (_, C.MutConstruct _)
395 | (C.Fix _, _) | (_, C.Fix _)
396 | (C.CoFix _, _) | (_, C.CoFix _) ->
397 if R.are_convertible subst context t1 t2 then
400 raise (UnificationFailure (sprintf
401 "Can't unify %s with %s because they are not convertible"
402 (CicMetaSubst.ppterm subst t1) (CicMetaSubst.ppterm subst t2)))
404 if R.are_convertible subst context t1 t2 then
407 raise (UnificationFailure (sprintf
408 "Can't unify %s with %s because they are not convertible"
409 (CicMetaSubst.ppterm subst t1) (CicMetaSubst.ppterm subst t2)))
411 and fo_unif_subst_exp_named_subst test_equality_only subst context metasenv
412 exp_named_subst1 exp_named_subst2
416 (fun (subst,metasenv) (uri1,t1) (uri2,t2) ->
418 fo_unif_subst test_equality_only subst context metasenv t1 t2
419 ) (subst,metasenv) exp_named_subst1 exp_named_subst2
421 Invalid_argument _ ->
426 UriManager.string_of_uri uri ^ " := " ^ (CicMetaSubst.ppterm subst t)
429 raise (UnificationFailure (sprintf
430 "Error trying to unify the two explicit named substitutions (local contexts) %s and %s: their lengths is different." (print_ens exp_named_subst1) (print_ens exp_named_subst2)))
432 (* A substitution is a (int * Cic.term) list that associates a *)
433 (* metavariable i with its body. *)
434 (* metasenv is of type Cic.metasenv *)
435 (* fo_unif takes a metasenv, a context, two terms t1 and t2 and gives back *)
436 (* a new substitution which is already unwinded and ready to be applied and *)
437 (* a new metasenv in which some hypothesis in the contexts of the *)
438 (* metavariables may have been restricted. *)
439 let fo_unif metasenv context t1 t2 =
440 fo_unif_subst false [] context metasenv t1 t2 ;;
442 let fo_unif_subst subst context metasenv t1 t2 =
444 sprintf "Unification error unifying %s of type %s with %s of type %s in context\n%s\nand metasenv\n%s\nbecause %s"
445 (CicMetaSubst.ppterm subst t1)
447 CicPp.ppterm (type_of_aux' metasenv subst context t1)
448 with _ -> "MALFORMED")
449 (CicMetaSubst.ppterm subst t2)
451 CicPp.ppterm (type_of_aux' metasenv subst context t2)
452 with _ -> "MALFORMED")
453 (CicMetaSubst.ppcontext subst context)
454 (CicMetaSubst.ppmetasenv metasenv subst) msg
457 fo_unif_subst false subst context metasenv t1 t2
459 | AssertFailure msg -> raise (AssertFailure (enrich_msg msg))
460 | UnificationFailure msg -> raise (UnificationFailure (enrich_msg msg))