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/.
26 exception Impossible of int;;
27 exception NotRefinable of string;;
28 exception Uncertain of string;;
29 exception WrongUriToConstant of string;;
30 exception WrongUriToVariable of string;;
31 exception ListTooShort;;
32 exception WrongUriToMutualInductiveDefinitions of string;;
33 exception RelToHiddenHypothesis;;
34 exception MetasenvInconsistency;;
35 exception MutCaseFixAndCofixRefineNotImplemented;;
36 exception FreeMetaFound of int;;
37 exception WrongArgumentNumber;;
41 let rec debug_aux t i =
43 let module U = UriManager in
44 CicPp.ppobj (C.Variable ("DEBUG", None, t, [])) ^ "\n" ^ i
47 raise (NotRefinable ("\n" ^ List.fold_right debug_aux (t::context) ""))
48 (*print_endline ("\n" ^ List.fold_right debug_aux (t::context) "") ; flush stdout*)
54 | (he::tl, n) -> let (l1,l2) = split tl (n-1) in (he::l1,l2)
55 | (_,_) -> raise ListTooShort
58 let rec type_of_constant uri =
60 let module R = CicReduction in
61 let module U = UriManager in
62 match CicEnvironment.get_cooked_obj uri with
63 C.Constant (_,_,ty,_) -> ty
64 | C.CurrentProof (_,_,_,ty,_) -> ty
65 | _ -> raise (WrongUriToConstant (U.string_of_uri uri))
67 and type_of_variable uri =
69 let module R = CicReduction in
70 let module U = UriManager in
71 match CicEnvironment.get_cooked_obj uri with
72 C.Variable (_,_,ty,_) -> ty
73 | _ -> raise (WrongUriToVariable (UriManager.string_of_uri uri))
75 and type_of_mutual_inductive_defs uri i =
77 let module R = CicReduction in
78 let module U = UriManager in
79 match CicEnvironment.get_cooked_obj uri with
80 C.InductiveDefinition (dl,_,_) ->
81 let (_,_,arity,_) = List.nth dl i in
83 | _ -> raise (WrongUriToMutualInductiveDefinitions (U.string_of_uri uri))
85 and type_of_mutual_inductive_constr uri i j =
87 let module R = CicReduction in
88 let module U = UriManager in
89 match CicEnvironment.get_cooked_obj uri with
90 C.InductiveDefinition (dl,_,_) ->
91 let (_,_,_,cl) = List.nth dl i in
92 let (_,ty) = List.nth cl (j-1) in
94 | _ -> raise (WrongUriToMutualInductiveDefinitions (U.string_of_uri uri))
96 (* type_of_aux' is just another name (with a different scope) for type_of_aux *)
98 (* the check_branch function checks if a branch of a case is refinable.
99 It returns a pair (outype_instance,args), a subst and a metasenv.
100 outype_instance is the expected result of applying the case outtype
102 The problem is that outype is in general unknown, and we should
103 try to synthesize it from the above information, that is in general
104 a second order unification problem. *)
106 and check_branch context metasenv subst left_args_no actualtype term expectedtype =
107 let module C = Cic in
108 let module R = CicReduction in
109 let module Un = CicUnification in
110 match R.whd context expectedtype with
112 (actualtype, [term]), subst, metasenv
113 | C.Appl (C.MutInd (_,_,_)::tl) ->
114 let (_,arguments) = split tl left_args_no in
115 (actualtype, arguments@[term]), subst, metasenv
116 | C.Prod (name,so,de) ->
117 (* we expect that the actual type of the branch has the due
119 (match R.whd context actualtype with
120 C.Prod (name',so',de') ->
122 Un.fo_unif_subst subst context metasenv so so' in
124 (match CicSubstitution.lift 1 term with
125 C.Appl l -> C.Appl (l@[C.Rel 1])
126 | t -> C.Appl [t ; C.Rel 1]) in
127 (* we should also check that the name variable is anonymous in
128 the actual type de' ?? *)
129 check_branch ((Some (name,(C.Decl so)))::context) metasenv subst left_args_no de' term' de
130 | _ -> raise WrongArgumentNumber)
131 | _ -> raise (NotRefinable "Prod or MutInd expected")
133 and type_of_aux' metasenv context t =
134 let rec type_of_aux subst metasenv context =
135 let module C = Cic in
136 let module S = CicSubstitution in
137 let module U = UriManager in
138 let module Un = CicUnification in
142 match List.nth context (n - 1) with
143 Some (_,C.Decl t) -> S.lift n t,subst,metasenv
144 | Some (_,C.Def (_,Some ty)) -> S.lift n ty,subst,metasenv
145 | Some (_,C.Def (bo,None)) ->
146 prerr_endline "##### DA INVESTIGARE E CAPIRE" ;
147 type_of_aux subst metasenv context (S.lift n bo)
148 | None -> raise RelToHiddenHypothesis
150 _ -> raise (NotRefinable "Not a close term")
152 | C.Var (uri,exp_named_subst) ->
154 let subst',metasenv' =
155 check_exp_named_subst subst metasenv context exp_named_subst in
157 CicSubstitution.subst_vars exp_named_subst (type_of_variable uri)
162 let (_,canonical_context,ty) =
164 List.find (function (m,_,_) -> n = m) metasenv
166 Not_found -> raise (FreeMetaFound n)
168 let subst',metasenv' =
169 check_metasenv_consistency subst metasenv context canonical_context l
171 CicSubstitution.lift_meta l ty, subst', metasenv'
173 C.Sort C.Type, (*CSC manca la gestione degli universi!!! *)
175 | C.Implicit -> raise (Impossible 21)
177 let _,subst',metasenv' =
178 type_of_aux subst metasenv context ty in
179 let inferredty,subst'',metasenv'' =
180 type_of_aux subst' metasenv' context ty
183 let subst''',metasenv''' =
184 Un.fo_unif_subst subst'' context metasenv'' inferredty ty
186 ty,subst''',metasenv'''
188 _ -> raise (NotRefinable "Cast"))
189 | C.Prod (name,s,t) ->
190 let sort1,subst',metasenv' = type_of_aux subst metasenv context s in
191 let sort2,subst'',metasenv'' =
192 type_of_aux subst' metasenv' ((Some (name,(C.Decl s)))::context) t
194 sort_of_prod subst'' metasenv'' context (name,s) (sort1,sort2)
195 | C.Lambda (n,s,t) ->
196 let sort1,subst',metasenv' = type_of_aux subst metasenv context s in
197 let type2,subst'',metasenv'' =
198 type_of_aux subst' metasenv' ((Some (n,(C.Decl s)))::context) t
200 let sort2,subst''',metasenv''' =
201 type_of_aux subst'' metasenv''((Some (n,(C.Decl s)))::context) type2
203 (* only to check if the product is well-typed *)
204 let _,subst'''',metasenv'''' =
205 sort_of_prod subst''' metasenv''' context (n,s) (sort1,sort2)
207 C.Prod (n,s,type2),subst'''',metasenv''''
209 (* only to check if s is well-typed *)
210 let ty,subst',metasenv' = type_of_aux subst metasenv context s in
211 let inferredty,subst'',metasenv'' =
212 type_of_aux subst' metasenv' ((Some (n,(C.Def (s,Some ty))))::context) t
214 (* One-step LetIn reduction. Even faster than the previous solution.
215 Moreover the inferred type is closer to the expected one. *)
216 CicSubstitution.subst s inferredty,subst',metasenv'
217 | C.Appl (he::tl) when List.length tl > 0 ->
218 let hetype,subst',metasenv' = type_of_aux subst metasenv context he in
219 let tlbody_and_type,subst'',metasenv'' =
221 (fun x (res,subst,metasenv) ->
222 let ty,subst',metasenv' =
223 type_of_aux subst metasenv context x
225 (x, ty)::res,subst',metasenv'
226 ) tl ([],subst',metasenv')
228 eat_prods subst'' metasenv'' context hetype tlbody_and_type
229 | C.Appl _ -> raise (NotRefinable "Appl: no arguments")
230 | C.Const (uri,exp_named_subst) ->
232 let subst',metasenv' =
233 check_exp_named_subst subst metasenv context exp_named_subst in
235 CicSubstitution.subst_vars exp_named_subst (type_of_constant uri)
239 | C.MutInd (uri,i,exp_named_subst) ->
241 let subst',metasenv' =
242 check_exp_named_subst subst metasenv context exp_named_subst in
244 CicSubstitution.subst_vars exp_named_subst
245 (type_of_mutual_inductive_defs uri i)
249 | C.MutConstruct (uri,i,j,exp_named_subst) ->
250 let subst',metasenv' =
251 check_exp_named_subst subst metasenv context exp_named_subst in
253 CicSubstitution.subst_vars exp_named_subst
254 (type_of_mutual_inductive_constr uri i j)
257 | C.MutCase (uri, i, outtype, term, pl) ->
258 (* first, get the inductive type (and noparams) in the environment *)
259 let (_,b,arity,constructors), expl_params, no_left_params =
260 match CicEnvironment.get_cooked_obj ~trust:true uri with
261 C.InductiveDefinition (l,expl_params,parsno) ->
262 List.nth l i , expl_params, parsno
265 (WrongUriToMutualInductiveDefinitions (U.string_of_uri uri)) in
266 let rec count_prod t =
267 match CicReduction.whd context t with
268 C.Prod (_, _, t) -> 1 + (count_prod t)
270 let no_args = count_prod arity in
271 (* now, create a "generic" MutInd *)
272 let metasenv,left_args =
273 CicMkImplicit.n_fresh_metas metasenv context no_left_params in
274 let metasenv,right_args =
275 let no_right_params = no_args - no_left_params in
276 if no_right_params < 0 then assert false
277 else CicMkImplicit.n_fresh_metas metasenv context no_right_params in
278 let metasenv,exp_named_subst =
279 CicMkImplicit.fresh_subst metasenv context expl_params in
282 C.MutInd (uri,i,exp_named_subst)
284 C.Appl (C.MutInd (uri,i,exp_named_subst)::(left_args @ right_args))
286 (* check consistency with the actual type of term *)
287 let actual_type,subst,metasenv =
288 type_of_aux subst metasenv context term in
293 metasenv expected_type (CicReduction.whd context actual_type) in
294 (* TODO: check if the sort elimination is allowed: [(I q1 ... qr)|B] *)
295 let (_,outtypeinstances,subst,metasenv) =
297 (fun (j,outtypeinstances,subst,metasenv) p ->
299 if left_args = [] then
300 (C.MutConstruct (uri,i,j,exp_named_subst))
303 (C.MutConstruct (uri,i,j,exp_named_subst)::left_args))
305 let actual_type,subst,metasenv =
306 type_of_aux subst metasenv context p in
307 let expected_type, subst, metasenv =
308 type_of_aux subst metasenv context constructor in
309 let outtypeinstance,subst,metasenv =
311 context metasenv subst
312 no_left_params actual_type constructor expected_type in
313 (j+1,outtypeinstance::outtypeinstances,subst,metasenv))
314 (1,[],subst,metasenv) pl in
315 (* we are left to check that the outype matches his instances.
316 The easy case is when the outype is specified, that amount
317 to a trivial check. Otherwise, we should guess a type from
320 let (subst,metasenv) =
322 (fun (subst,metasenv) (instance,args) ->
324 CicReduction.whd context (C.Appl(outtype::args)) in
325 Un.fo_unif_subst subst context metasenv instance instance')
326 (subst,metasenv) outtypeinstances in
328 context (C.Appl(outtype::right_args@[term])),subst,metasenv
330 | C.CoFix _ -> raise MutCaseFixAndCofixRefineNotImplemented
332 (* check_metasenv_consistency checks that the "canonical" context of a
333 metavariable is consitent - up to relocation via the relocation list l -
334 with the actual context *)
335 and check_metasenv_consistency subst metasenv context canonical_context l =
336 let module C = Cic in
337 let module R = CicReduction in
338 let module S = CicSubstitution in
339 let lifted_canonical_context =
343 | (Some (n,C.Decl t))::tl ->
344 (Some (n,C.Decl (S.lift_meta l (S.lift i t))))::(aux (i+1) tl)
345 | (Some (n,C.Def (t,None)))::tl ->
346 (Some (n,C.Def ((S.lift_meta l (S.lift i t)),None)))::(aux (i+1) tl)
347 | None::tl -> None::(aux (i+1) tl)
348 | (Some (_,C.Def (_,Some _)))::_ -> assert false
350 aux 1 canonical_context
353 (fun (subst,metasenv) t ct ->
355 _,None -> subst,metasenv
356 | Some t,Some (_,C.Def (ct,_)) ->
358 CicUnification.fo_unif_subst subst context metasenv t ct
359 with _ -> raise MetasenvInconsistency)
360 | Some t,Some (_,C.Decl ct) ->
361 let inferredty,subst',metasenv' =
362 type_of_aux subst metasenv context t
365 CicUnification.fo_unif_subst subst context metasenv inferredty ct
366 with _ -> raise MetasenvInconsistency)
367 | _, _ -> raise MetasenvInconsistency
368 ) (subst,metasenv) l lifted_canonical_context
370 and check_exp_named_subst metasubst metasenv context =
371 let rec check_exp_named_subst_aux metasubst metasenv substs =
373 [] -> metasubst,metasenv
374 | ((uri,t) as subst)::tl ->
376 CicSubstitution.subst_vars substs (type_of_variable uri) in
377 (match CicEnvironment.get_cooked_obj ~trust:false uri with
378 Cic.Variable (_,Some bo,_,_) ->
381 "A variable with a body can not be explicit substituted")
382 | Cic.Variable (_,None,_,_) -> ()
383 | _ -> raise (WrongUriToVariable (UriManager.string_of_uri uri))
385 let typeoft,metasubst',metasenv' =
386 type_of_aux metasubst metasenv context t
389 let metasubst'',metasenv'' =
390 CicUnification.fo_unif_subst
391 metasubst' context metasenv' typeoft typeofvar
393 check_exp_named_subst_aux metasubst'' metasenv'' (substs@[subst]) tl
395 raise (NotRefinable "Wrong Explicit Named Substitution")
397 check_exp_named_subst_aux metasubst metasenv []
399 and sort_of_prod subst metasenv context (name,s) (t1, t2) =
400 let module C = Cic in
401 (* ti could be a metavariable in the domain of the substitution *)
402 let subst',metasenv' = CicUnification.unwind_subst metasenv subst in
403 let t1' = CicUnification.apply_subst subst' t1 in
404 let t2' = CicUnification.apply_subst subst' t2 in
405 let t1'' = CicReduction.whd context t1' in
406 let t2'' = CicReduction.whd ((Some (name,C.Decl s))::context) t2' in
407 match (t1'', t2'') with
408 (C.Sort s1, C.Sort s2)
409 when (s2 = C.Prop or s2 = C.Set or s2 = C.CProp) -> (* different from Coq manual!!! *)
410 C.Sort s2,subst',metasenv'
411 | (C.Sort s1, C.Sort s2) ->
412 (*CSC manca la gestione degli universi!!! *)
413 C.Sort C.Type,subst',metasenv'
418 ("Two sorts were expected, found " ^ CicPp.ppterm t1'' ^ " and " ^
423 ("Prod: sort1= "^ CicPp.ppterm t1'' ^ " ; sort2= "^ CicPp.ppterm t2''))
425 and eat_prods subst metasenv context hetype =
427 [] -> hetype,subst,metasenv
428 | (hete, hety)::tl ->
429 (match (CicReduction.whd context hetype) with
431 let subst',metasenv' =
433 CicUnification.fo_unif_subst subst context metasenv s hety
435 raise (NotRefinable "Appl: wrong parameter-type")
437 CicReduction.fdebug := -1 ;
438 eat_prods subst' metasenv' context (CicSubstitution.subst hete t) tl
442 ("Prod expected, " ^ CicPp.ppterm t ^ " found"))
443 | _ -> raise (NotRefinable "Appl: wrong Prod-type")
446 let ty,subst',metasenv' =
447 type_of_aux [] metasenv context t
449 let subst'',metasenv'' = CicUnification.unwind_subst metasenv' subst' in
450 (* we get rid of the metavariables that have been instantiated *)
453 (function (i,_,_) -> not (List.exists (function (j,_) -> j=i) subst''))
456 CicUnification.apply_subst subst'' t,
457 CicUnification.apply_subst subst'' ty,
462 let type_of_aux' metasenv context term =
465 type_of_aux' metasenv context term
469 prerr_endline ("+ ?" ^ string_of_int i ^ " := " ^ CicPp.ppterm t)) s ;
472 prerr_endline ("+ ?" ^ string_of_int i ^ " : " ^ CicPp.ppterm t)) m ;
474 ("@@@ REFINE SUCCESSFUL: " ^ CicPp.ppterm t ^ " : " ^ CicPp.ppterm ty) ;
480 prerr_endline ("+ ?" ^ string_of_int i ^ " : " ^ CicPp.ppterm t))
482 prerr_endline ("@@@ REFINE FAILED: " ^ Printexc.to_string e) ;