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.
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_______________________________________________________________ *)
15 module Ref = NReference
17 exception CircularDependency of string Lazy.t;;
18 exception ObjectNotFound of string Lazy.t;;
19 exception BadDependency of string Lazy.t * exn;;
20 exception BadConstraint of string Lazy.t;;
21 exception AlreadyDefined of string Lazy.t;;
23 let cache = NUri.UriHash.create 313;;
24 let history = ref [];;
25 let frozen_list = ref [];;
27 let get_obj = ref (fun _ _ -> assert false);;
28 let set_get_obj = (:=) get_obj;;
32 let rec ppsort f = function
33 | C.Prop -> F.fprintf f "Prop"
34 | (C.Type []) -> F.fprintf f "Type0"
35 | (C.Type [`Type, u]) -> F.fprintf f "%s" (NUri.name_of_uri u)
36 | (C.Type [`Succ, u]) -> F.fprintf f "S(%s)" (NUri.name_of_uri u)
37 | (C.Type [`CProp, u]) -> F.fprintf f "P(%s)" (NUri.name_of_uri u)
40 ppsort f ((C.Type [List.hd l]));
41 List.iter (fun x -> F.fprintf f ",";ppsort f ((C.Type [x]))) (List.tl l);
45 let string_of_univ u =
46 let b = Buffer.create 100 in
47 let f = Format.formatter_of_buffer b in
48 ppsort f (NCic.Type u);
49 Format.fprintf f "@?";
53 let eq_univ (b1,u1) (b2,u2) = b1=b2 && NUri.eq u1 u2;;
55 let max (l1:NCic.universe) (l2:NCic.universe) =
58 let rest = List.filter (fun y -> not (eq_univ x y)) (l1@tl) in
59 x :: HExtlib.list_uniq ~eq:eq_univ
60 (List.sort (fun (b1,u1) (b2,u2) ->
61 let res = compare b1 b2 in
62 if res = 0 then NUri.compare u1 u2 else res)
67 | ((`Type|`Succ), _)::_ -> l1
68 | (`CProp, u)::tl -> (`Type, u)::tl
71 let lt_constraints = ref [] (* a,b := a < b *)
73 let rec lt_path_uri avoid a b =
78 (not (List.exists (NUri.eq x) avoid) &&
79 lt_path_uri (x::avoid) a x))
83 let lt_path a b = lt_path_uri [b] a b;;
87 | [(`Type|`CProp) as b1, u1], [(`Type|`CProp) as b2, u2] ->
88 b1 = b2 && NUri.eq u1 u2
89 | _, [(`Type|`CProp),_]
90 | [(`Type|`CProp),_],_ -> false
93 (lazy "trying to check if two inferred universes are equal"))
96 let universe_leq a b =
98 | (((`Type|`Succ),_)::_ | []) , [`CProp,_] -> false
99 | l, [((`Type|`CProp),b)] ->
102 | `Succ,a -> lt_path a b
103 | _, a -> NUri.eq a b || lt_path a b) l
104 | _, ([] | [`Succ,_] | _::_::_) ->
105 raise (BadConstraint (lazy (
106 "trying to check if "^string_of_univ a^
107 " is leq than the inferred universe " ^ string_of_univ b)))
110 let are_sorts_convertible ~test_eq_only s1 s2 =
112 | C.Type a, C.Type b when not test_eq_only -> universe_leq a b
113 | C.Type a, C.Type b -> universe_eq a b
114 | C.Prop,C.Type _ -> (not test_eq_only)
115 | C.Prop, C.Prop -> true
119 let pp_constraint x y =
120 NUri.name_of_uri x ^ " < " ^ NUri.name_of_uri y
123 let pp_constraints () =
124 String.concat "\n" (List.map (fun (x,y) -> pp_constraint x y) !lt_constraints)
127 let universes = ref [];;
129 let get_universes () =
130 List.map (fun x -> [`Type,x]) !universes @
131 List.map (fun x -> [`CProp,x]) !universes
136 | [(`CProp|`Type),x] -> List.exists (fun y -> NUri.eq x y) !universes
140 exception UntypableSort of string Lazy.t
141 exception AssertFailure of string Lazy.t
143 let typeof_sort = function
144 | C.Type ([(`Type|`CProp),u] as univ) ->
145 if is_declared univ then (C.Type [`Succ, u])
147 let universes = !universes in
148 raise (UntypableSort (lazy ("undeclared universe " ^
149 NUri.string_of_uri u ^ "\ndeclared ones are: " ^
150 String.concat ", " (List.map NUri.string_of_uri universes)
153 raise (AssertFailure (lazy (
154 "Cannot type an inferred type: "^ string_of_univ t)))
155 | C.Prop -> (C.Type [])
158 let add_lt_constraint a b =
160 | [`Type,a2],[`Type,b2] ->
161 if not (lt_path_uri [] a2 b2) then (
162 if lt_path_uri [] b2 a2 || NUri.eq a2 b2 then
163 (raise(BadConstraint(lazy("universe inconsistency adding "^
165 ^ " to:\n" ^ pp_constraints ()))));
166 universes := a2 :: b2 ::
167 List.filter (fun x -> not (NUri.eq x a2 || NUri.eq x b2)) !universes;
168 lt_constraints := (a2,b2) :: !lt_constraints);
169 history := (`Constr (a,b))::!history;
170 | _ -> raise (BadConstraint
171 (lazy "trying to add a constraint on an inferred universe"))
174 let family_of = function (`CProp,_)::_ -> `CProp | _ -> `Type ;;
178 | [(`Type|`CProp),_] -> Some l
180 let bigger_than acc (s1,n1) =
182 (fun x -> lt_path_uri [] n1 x || (s1 <> `Succ && NUri.eq n1 x)) acc
184 let solutions = List.fold_left bigger_than !universes l in
185 let rec aux = function
188 if List.exists (fun x -> lt_path_uri [] x u) solutions then aux tl
194 let sup l = sup (family_of l) l;;
196 let inf ~strict fam l =
198 | [(`Type|`CProp),_] -> Some l
201 let smaller_than acc (_s1,n1) =
203 (fun x -> lt_path_uri [] x n1 || (not strict && NUri.eq n1 x)) acc
205 let solutions = List.fold_left smaller_than !universes l in
206 let rec aux = function
209 if List.exists (lt_path_uri [] u) solutions then aux tl
215 let inf ~strict l = inf ~strict (family_of l) l;;
217 let rec universe_lt a b =
219 | (((`Type|`Succ),_)::_ | []) , [`CProp,_] -> false
220 | l, ([((`Type|`CProp),b)] as orig_b) ->
226 | Some x -> universe_lt x orig_b)
227 | _, a -> lt_path a b) l
228 | _, ([] | [`Succ,_] | _::_::_) ->
229 raise (BadConstraint (lazy (
230 "trying to check if "^string_of_univ a^
231 " is lt than the inferred universe " ^ string_of_univ b)))
235 let allowed_sort_elimination s1 s2 =
237 | C.Type (((`Type|`Succ),_)::_ | []), C.Type (((`Type|`Succ),_)::_ | [])
238 | C.Type _, C.Type ((`CProp,_)::_)
240 | C.Prop, C.Prop -> `Yes
242 | C.Type ((`CProp,_)::_), C.Type (((`Type|`Succ),_)::_ | [])
243 | C.Prop, C.Type _ -> `UnitOnly
246 let typecheck_obj,already_set = ref (fun _ _ -> assert false), ref false;;
247 let set_typecheck_obj f =
257 (* CSC: old code that performs recursive invalidation; to be removed
258 * once we understand what we really want. Once we removed it, we can
259 * also remove the !history
260 let invalidate_item item =
263 | `Obj (u1,_), `Obj (u2,_) -> NUri.eq u1 u2
264 | `Constr _, `Constr _ -> a=b (* MAKE EFFICIENT *)
267 let rec aux to_be_deleted =
270 | item'::tl when item_eq item item' -> item'::to_be_deleted,tl
271 | item'::tl -> aux (item'::to_be_deleted) tl
273 let to_be_deleted,h = aux [] !history in
277 | `Obj (uri,_) -> NUri.UriHash.remove cache uri
278 | `Constr ([_,u1],[_,u2]) as c ->
280 if not(List.mem c !history) then
281 lt_constraints := List.filter ((<>) w) !lt_constraints;
282 | `Constr _ -> assert false
287 let invalidate_item =
289 `Obj (uri,_) -> NUri.UriHash.remove cache uri
290 | `Constr ([_,u1],[_,u2]) ->
292 lt_constraints := List.filter ((<>) w) !lt_constraints;
293 | `Constr _ -> assert false
296 exception Propagate of NUri.uri * exn;;
304 let check_and_add_obj (status:#NCic.status) ((u,_,_,_,_) as obj) =
305 let saved_frozen_list = !frozen_list in
307 frozen_list := (u,obj)::saved_frozen_list;
308 HLog.warn ("Typechecking of " ^ NUri.string_of_uri u);
309 !typecheck_obj (status :> NCic.status) obj;
310 frozen_list := saved_frozen_list;
311 let obj' = `WellTyped obj in
312 NUri.UriHash.add cache u obj';
313 history := (`Obj (u,obj))::!history;
317 frozen_list := saved_frozen_list;
319 | Propagate (u',old_exn) as e' ->
320 frozen_list := saved_frozen_list;
321 let exn = `Exn (BadDependency (lazy (NUri.string_of_uri u ^
322 " depends (recursively) on " ^ NUri.string_of_uri u' ^
323 " which is not well-typed"),
324 match old_exn with BadDependency (_,e) -> e | _ -> old_exn)) in
325 NUri.UriHash.add cache u exn;
326 history := (`Obj (u,obj))::!history;
327 if saved_frozen_list = [] then
332 frozen_list := saved_frozen_list;
334 history := (`Obj (u,obj))::!history;
335 if saved_frozen_list = [] then
339 NUri.UriHash.add cache u exn;
340 raise (Propagate (u,e))
344 let get_checked_obj status u =
345 if List.exists (fun (k,_) -> NUri.eq u k) !frozen_list
347 raise (CircularDependency (lazy (NUri.string_of_uri u)))
349 try NUri.UriHash.find cache u
350 with Not_found -> check_and_add_obj status (!get_obj (status :> NCic.status) u)
353 let get_checked_obj (status:#NCic.status) u = to_exn (get_checked_obj status) u;;
355 let check_and_add_obj status ((u,_,_,_,_) as obj) =
356 if NUri.UriHash.mem cache u then
357 raise (AlreadyDefined (lazy (NUri.string_of_uri u)))
359 ignore (to_exn (check_and_add_obj status) obj)
362 let get_checked_decl status = function
363 | Ref.Ref (uri, Ref.Decl) ->
364 (match get_checked_obj status uri with
365 | _,height,_,_, C.Constant (rlv,name,None,ty,att) ->
366 rlv,name,ty,att,height
367 | _,_,_,_, C.Constant (_,_,Some _,_,_) ->
368 prerr_endline "get_checked_decl on a definition"; assert false
369 | _ -> prerr_endline "get_checked_decl on a non decl 2"; assert false)
370 | _ -> prerr_endline "get_checked_decl on a non decl"; assert false
373 let get_checked_def status = function
374 | Ref.Ref (uri, Ref.Def _) ->
375 (match get_checked_obj status uri with
376 | _,height,_,_, C.Constant (rlv,name,Some bo,ty,att) ->
377 rlv,name,bo,ty,att,height
378 | _,_,_,_, C.Constant (_,_,None,_,_) ->
379 prerr_endline "get_checked_def on an axiom"; assert false
380 | _ -> prerr_endline "get_checked_def on a non def 2"; assert false)
381 | _ -> prerr_endline "get_checked_def on a non def"; assert false
384 let get_checked_indtys status = function
385 | Ref.Ref (uri, (Ref.Ind (_,n,_)|Ref.Con (n,_,_))) ->
386 (match get_checked_obj status uri with
387 | _,_,_,_, C.Inductive (inductive,leftno,tys,att) ->
388 inductive,leftno,tys,att,n
389 | _ -> prerr_endline "get_checked_indtys on a non ind 2"; assert false)
390 | _ -> prerr_endline "get_checked_indtys on a non ind"; assert false
393 let get_checked_fixes_or_cofixes status = function
394 | Ref.Ref (uri, (Ref.Fix _|Ref.CoFix _))->
395 (match get_checked_obj status uri with
396 | _,height,_,_, C.Fixpoint (_,funcs,att) ->
398 | _ ->prerr_endline "get_checked_(co)fix on a non (co)fix 2";assert false)
399 | _ -> prerr_endline "get_checked_(co)fix on a non (co)fix"; assert false
402 let get_relevance status (Ref.Ref (_, infos) as r) =
404 Ref.Def _ -> let res,_,_,_,_,_ = get_checked_def status r in res
405 | Ref.Decl -> let res,_,_,_,_ = get_checked_decl status r in res
407 let _,_,tl,_,n = get_checked_indtys status r in
408 let res,_,_,_ = List.nth tl n in
411 let _,_,tl,_,n = get_checked_indtys status r in
412 let _,_,_,cl = List.nth tl n in
413 let res,_,_ = List.nth cl (i - 1) in
415 | Ref.Fix (fixno,_,_)
417 let fl,_,_ = get_checked_fixes_or_cofixes status r in
418 let res,_,_,_,_ = List.nth fl fixno in
424 assert (!frozen_list = []);
425 NUri.UriHash.clear cache