]> matita.cs.unibo.it Git - helm.git/blob - helm/software/components/ng_kernel/nCicEnvironment.ml
912dad936ed5e042569a7a95004ebd6f1c3c4c2b
[helm.git] / helm / software / components / ng_kernel / nCicEnvironment.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 module C = NCic
15 module Ref = NReference
16
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;;
22
23 let cache = NUri.UriHash.create 313;;
24 let history = ref [];;
25 let frozen_list = ref [];;
26
27 let get_obj = ref (fun _ -> assert false);;
28 let set_get_obj f = get_obj := f;;
29
30 let type0 = []
31
32 module F = Format 
33
34 let rec ppsort f = function
35   | C.Prop -> F.fprintf f "Prop"
36   | (C.Type []) -> F.fprintf f "Type0"
37   | (C.Type [`Type, u]) -> F.fprintf f "%s" (NUri.name_of_uri u)
38   | (C.Type [`Succ, u]) -> F.fprintf f "S(%s)" (NUri.name_of_uri u)
39   | (C.Type [`CProp, u]) -> F.fprintf f "P(%s)" (NUri.name_of_uri u)
40   | (C.Type l) -> 
41       F.fprintf f "Max(";
42       ppsort f ((C.Type [List.hd l]));
43       List.iter (fun x -> F.fprintf f ",";ppsort f ((C.Type [x]))) (List.tl l);
44       F.fprintf f ")"
45 ;;
46
47 let string_of_univ u =
48   let b = Buffer.create 100 in
49   let f = Format.formatter_of_buffer b in
50   ppsort f (NCic.Type u);
51   Format.fprintf f "@?";
52   Buffer.contents b
53 ;;
54
55 let eq_univ (b1,u1) (b2,u2) = b1=b2 && NUri.eq u1 u2;;
56
57 let max (l1:NCic.universe) (l2:NCic.universe) =
58  match l2 with
59  | x::tl -> 
60     let rest = List.filter (fun y -> not (eq_univ x y)) (l1@tl) in
61     x :: HExtlib.list_uniq ~eq:eq_univ
62       (List.sort (fun (b1,u1) (b2,u2) ->
63          let res = compare b1 b2 in 
64          if res = 0 then NUri.compare u1 u2 else res)
65       rest)
66  | [] -> 
67      match l1 with
68      | [] -> []
69      | ((`Type|`Succ), _)::_ -> l1
70      | (`CProp, u)::tl -> (`Type, u)::tl
71 ;;
72
73 let lt_constraints = ref [] (* a,b := a < b *)
74
75 let rec lt_path_uri avoid a b = 
76  List.exists
77   (fun (x,y) ->
78       NUri.eq y b && 
79      (NUri.eq a x ||
80         (not (List.exists (NUri.eq x) avoid) &&
81         lt_path_uri (x::avoid) a x))
82   ) !lt_constraints
83 ;;
84
85 let lt_path a b = lt_path_uri [b] a b;;
86
87 let universe_eq a b = 
88   match a,b with 
89   | [(`Type|`CProp) as b1, u1], [(`Type|`CProp) as b2, u2] -> 
90          b1 = b2 && NUri.eq u1 u2
91   | _, [(`Type|`CProp),_]
92   | [(`Type|`CProp),_],_ -> false
93   | _ ->
94      raise (BadConstraint
95       (lazy "trying to check if two inferred universes are equal"))
96 ;;
97
98 let universe_leq a b = 
99   match a, b with
100   | (((`Type|`Succ),_)::_ | []) , [`CProp,_] -> false
101   | l, [((`Type|`CProp),b)] -> 
102        List.for_all 
103          (function 
104          | `Succ,a -> lt_path a b 
105          | _, a -> NUri.eq a b || lt_path a b) l
106   | _, ([] | [`Succ,_] | _::_::_) -> 
107      raise (BadConstraint (lazy (
108        "trying to check if "^string_of_univ a^
109        " is leq than the inferred universe " ^ string_of_univ b)))
110 ;;
111
112 let are_sorts_convertible ~test_eq_only s1 s2 =
113    match s1,s2 with
114    | C.Type a, C.Type b when not test_eq_only -> universe_leq a b
115    | C.Type a, C.Type b -> universe_eq a b
116    | C.Prop,C.Type _ -> (not test_eq_only)
117    | C.Prop, C.Prop -> true
118    | _ -> false
119 ;;
120
121 let pp_constraint x y =  
122   NUri.name_of_uri x ^ " < " ^ NUri.name_of_uri y
123 ;;
124
125 let pp_constraints () =
126   String.concat "\n" (List.map (fun (x,y) -> pp_constraint x y) !lt_constraints)
127 ;;
128
129 let universes = ref [];;
130
131 let get_universes () = 
132   List.map (fun x -> [`Type,x]) !universes @
133   List.map (fun x -> [`CProp,x]) !universes
134 ;;
135
136 let is_declared u =
137  match u with
138  | [(`CProp|`Type),x] -> List.exists (fun y -> NUri.eq x y) !universes
139  | _ -> assert false
140 ;;
141
142 exception UntypableSort of string Lazy.t
143 exception AssertFailure of string Lazy.t
144
145 let typeof_sort = function
146   | C.Type ([(`Type|`CProp),u] as univ) ->
147      if is_declared univ then (C.Type [`Succ, u])
148      else 
149        raise (UntypableSort (lazy ("undeclared universe " ^
150          NUri.string_of_uri u ^ "\ndeclared ones are: " ^ 
151          String.concat ", " (List.map NUri.string_of_uri !universes)
152      )))
153   | C.Type t -> 
154       raise (AssertFailure (lazy (
155               "Cannot type an inferred type: "^ string_of_univ t)))
156   | C.Prop -> (C.Type type0)
157 ;;
158
159 let add_lt_constraint a b = 
160   match a,b with
161   | [`Type,a2],[`Type,b2] -> 
162       if not (lt_path_uri [] a2 b2) then (
163         if lt_path_uri [] b2 a2 || NUri.eq a2 b2 then
164          (raise(BadConstraint(lazy("universe inconsistency adding "^
165                     pp_constraint a2 b2
166            ^ " to:\n" ^ pp_constraints ()))));
167         universes := a2 :: b2 :: 
168           List.filter (fun x -> not (NUri.eq x a2 || NUri.eq x b2)) !universes;
169         lt_constraints := (a2,b2) :: !lt_constraints);
170       history := (`Constr (a,b))::!history;
171   | _ -> raise (BadConstraint
172           (lazy "trying to add a constraint on an inferred universe"))
173 ;;
174
175 let sup l =
176   match l with
177   | [(`Type|`CProp),_] -> Some l
178   | l ->
179    let bigger_than acc (s1,n1) = 
180     List.filter
181      (fun x -> lt_path_uri [] n1 x || (s1 <> `Succ && NUri.eq n1 x)) acc 
182    in
183    let solutions = List.fold_left bigger_than !universes l in
184    let fam = match l with (`CProp,_)::_ -> `CProp | _ -> `Type in
185    let rec aux = function
186      | [] -> None
187      | u :: tl ->
188          if List.exists (fun x -> lt_path_uri [] x u) solutions then aux tl
189          else Some [fam,u]
190    in
191     aux solutions
192 ;;
193
194 let allowed_sort_elimination s1 s2 =
195   match s1, s2 with
196   | C.Type (((`Type|`Succ),_)::_ | []), C.Type (((`Type|`Succ),_)::_ | []) 
197   | C.Type _, C.Type ((`CProp,_)::_) 
198   | C.Type _, C.Prop
199   | C.Prop, C.Prop -> `Yes
200
201   | C.Type ((`CProp,_)::_), C.Type (((`Type|`Succ),_)::_ | [])
202   | C.Prop, C.Type _ -> `UnitOnly
203 ;;
204
205 let typecheck_obj,already_set = ref (fun _ -> assert false), ref false;;
206 let set_typecheck_obj f =
207  if !already_set then
208   assert false
209  else
210   begin
211    typecheck_obj := f;
212    already_set := true
213   end
214 ;;
215
216 let invalidate_item item =
217  let item_eq a b = 
218    match a, b with
219    | `Obj (u1,_), `Obj (u2,_) -> NUri.eq u1 u2
220    | `Constr _, `Constr _ -> a=b (* MAKE EFFICIENT *)
221    | _ -> false
222  in
223  let rec aux to_be_deleted =
224   function
225      [] -> assert false
226    | item'::tl when item_eq item item' -> item'::to_be_deleted,tl
227    | item'::tl -> aux (item'::to_be_deleted) tl
228  in
229   let to_be_deleted,h = aux [] !history in
230    history := h;
231    List.iter 
232      (function 
233      | `Obj (uri,_) -> NUri.UriHash.remove cache uri
234      | `Constr ([_,u1],[_,u2]) as c -> 
235           let w = u1,u2 in
236           if not(List.mem c !history) then 
237            lt_constraints := List.filter ((<>) w) !lt_constraints;
238      | `Constr _ -> assert false
239      ) to_be_deleted
240 ;;
241
242 exception Propagate of NUri.uri * exn;;
243
244 let to_exn f x =
245  match f x with
246     `WellTyped o -> o
247   | `Exn e -> raise e
248 ;;
249
250 let check_and_add_obj ((u,_,_,_,_) as obj) =
251  let saved_frozen_list = !frozen_list in
252  try
253    frozen_list := (u,obj)::saved_frozen_list;
254    !typecheck_obj obj;
255    frozen_list := saved_frozen_list;
256    let obj' = `WellTyped obj in
257    NUri.UriHash.add cache u obj';
258    history := (`Obj (u,obj))::!history;
259    obj'
260  with
261     Sys.Break as e ->
262      frozen_list := saved_frozen_list;
263      raise e
264   | Propagate (u',old_exn) as e' ->
265      frozen_list := saved_frozen_list;
266      let exn = `Exn (BadDependency (lazy (NUri.string_of_uri u ^
267        " depends (recursively) on " ^ NUri.string_of_uri u' ^
268        " which is not well-typed"), 
269        match old_exn with BadDependency (_,e) -> e | _ -> old_exn)) in
270      NUri.UriHash.add cache u exn;
271      history := (`Obj (u,obj))::!history;
272      if saved_frozen_list = [] then
273       exn
274      else
275       raise e'
276   | e ->
277      frozen_list := saved_frozen_list;
278      let exn = `Exn e in
279      NUri.UriHash.add cache u exn;
280      history := (`Obj (u,obj))::!history;
281      if saved_frozen_list = [] then
282       exn
283      else
284       raise (Propagate (u,e))
285 ;;
286
287 let get_checked_obj u =
288  if List.exists (fun (k,_) -> NUri.eq u k) !frozen_list
289  then
290   raise (CircularDependency (lazy (NUri.string_of_uri u)))
291  else
292   try NUri.UriHash.find cache u
293   with Not_found -> check_and_add_obj (!get_obj u)
294 ;;
295
296 let get_checked_obj u = to_exn get_checked_obj u;;
297
298 let check_and_add_obj ((u,_,_,_,_) as obj) =
299  if NUri.UriHash.mem cache u then
300   raise (AlreadyDefined (lazy (NUri.string_of_uri u)))
301  else
302   ignore (to_exn check_and_add_obj obj)
303 ;;
304
305 let get_checked_decl = function
306   | Ref.Ref (uri, Ref.Decl) ->
307       (match get_checked_obj uri with
308       | _,height,_,_, C.Constant (rlv,name,None,ty,att) ->
309           rlv,name,ty,att,height
310       | _,_,_,_, C.Constant (_,_,Some _,_,_) ->
311           prerr_endline "get_checked_decl on a definition"; assert false
312       | _ -> prerr_endline "get_checked_decl on a non decl 2"; assert false)
313   | _ -> prerr_endline "get_checked_decl on a non decl"; assert false
314 ;;
315
316 let get_checked_def = function
317   | Ref.Ref (uri, Ref.Def _) ->
318       (match get_checked_obj uri with
319       | _,height,_,_, C.Constant (rlv,name,Some bo,ty,att) ->
320           rlv,name,bo,ty,att,height
321       | _,_,_,_, C.Constant (_,_,None,_,_) ->
322           prerr_endline "get_checked_def on an axiom"; assert false
323       | _ -> prerr_endline "get_checked_def on a non def 2"; assert false)
324   | _ -> prerr_endline "get_checked_def on a non def"; assert false
325 ;;
326
327 let get_checked_indtys = function
328   | Ref.Ref (uri, (Ref.Ind (_,n,_)|Ref.Con (n,_,_))) ->
329       (match get_checked_obj uri with
330       | _,_,_,_, C.Inductive (inductive,leftno,tys,att) ->
331         inductive,leftno,tys,att,n
332       | _ -> prerr_endline "get_checked_indtys on a non ind 2"; assert false)
333   | _ -> prerr_endline "get_checked_indtys on a non ind"; assert false
334 ;;
335
336 let get_checked_fixes_or_cofixes = function
337   | Ref.Ref (uri, (Ref.Fix _|Ref.CoFix _))->
338       (match get_checked_obj uri with
339       | _,height,_,_, C.Fixpoint (_,funcs,att) ->
340          funcs, att, height
341       | _ ->prerr_endline "get_checked_(co)fix on a non (co)fix 2";assert false)
342   | _ -> prerr_endline "get_checked_(co)fix on a non (co)fix"; assert false
343 ;;
344
345 let get_relevance (Ref.Ref (_, infos) as r) =
346   match infos with
347      Ref.Def _ -> let res,_,_,_,_,_ = get_checked_def r in res
348    | Ref.Decl -> let res,_,_,_,_ = get_checked_decl r in res
349    | Ref.Ind _ ->
350        let _,_,tl,_,n = get_checked_indtys r in
351        let res,_,_,_ = List.nth tl n in
352          res
353     | Ref.Con (_,i,_) ->
354        let _,_,tl,_,n = get_checked_indtys r in
355        let _,_,_,cl = List.nth tl n in
356        let res,_,_ = List.nth cl (i - 1) in
357          res
358     | Ref.Fix (fixno,_,_)
359     | Ref.CoFix fixno ->
360         let fl,_,_ = get_checked_fixes_or_cofixes r in
361         let res,_,_,_,_ = List.nth fl fixno in
362           res
363 ;;
364
365
366 let invalidate _ = 
367   assert (!frozen_list = []);
368   NUri.UriHash.clear cache
369 ;;