~ubuntu-branches/ubuntu/wily/coq-doc/wily

« back to all changes in this revision

Viewing changes to kernel/inductive.ml

  • Committer: Bazaar Package Importer
  • Author(s): Stéphane Glondu, Stéphane Glondu, Samuel Mimram
  • Date: 2010-01-07 22:50:39 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20100107225039-n3cq82589u0qt0s2
Tags: 8.2pl1-1
[ Stéphane Glondu ]
* New upstream release (Closes: #563669)
  - remove patches
* Packaging overhaul:
  - use git, advertise it in Vcs-* fields of debian/control
  - use debhelper 7 and dh with override
  - use source format 3.0 (quilt)
* debian/control:
  - set Maintainer to d-o-m, set Uploaders to Sam and myself
  - add Homepage field
  - bump Standards-Version to 3.8.3
* Register PDF documentation into doc-base
* Add debian/watch
* Update debian/copyright

[ Samuel Mimram ]
* Change coq-doc's description to mention that it provides documentation in
  pdf format, not postscript, closes: #543545.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(************************************************************************)
 
2
(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
 
3
(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
 
4
(*   \VV/  **************************************************************)
 
5
(*    //   *      This file is distributed under the terms of the       *)
 
6
(*         *       GNU Lesser General Public License Version 2.1        *)
 
7
(************************************************************************)
 
8
 
 
9
(* $Id: inductive.ml 11647 2008-12-02 10:40:11Z barras $ *)
 
10
 
 
11
open Util
 
12
open Names
 
13
open Univ
 
14
open Term
 
15
open Sign
 
16
open Declarations
 
17
open Environ
 
18
open Reduction
 
19
open Type_errors
 
20
 
 
21
type mind_specif = mutual_inductive_body * one_inductive_body
 
22
 
 
23
(* raise Not_found if not an inductive type *)
 
24
let lookup_mind_specif env (kn,tyi) =
 
25
  let mib = Environ.lookup_mind kn env in
 
26
  if tyi >= Array.length mib.mind_packets then
 
27
    error "Inductive.lookup_mind_specif: invalid inductive index";
 
28
  (mib, mib.mind_packets.(tyi))
 
29
 
 
30
let find_rectype env c =
 
31
  let (t, l) = decompose_app (whd_betadeltaiota env c) in
 
32
  match kind_of_term t with
 
33
  | Ind ind -> (ind, l)
 
34
  | _ -> raise Not_found
 
35
 
 
36
let find_inductive env c =
 
37
  let (t, l) = decompose_app (whd_betadeltaiota env c) in
 
38
  match kind_of_term t with
 
39
    | Ind ind
 
40
        when (fst (lookup_mind_specif env ind)).mind_finite -> (ind, l)
 
41
    | _ -> raise Not_found
 
42
 
 
43
let find_coinductive env c =
 
44
  let (t, l) = decompose_app (whd_betadeltaiota env c) in
 
45
  match kind_of_term t with
 
46
    | Ind ind
 
47
        when not (fst (lookup_mind_specif env ind)).mind_finite -> (ind, l)
 
48
    | _ -> raise Not_found
 
49
 
 
50
let inductive_params (mib,_) = mib.mind_nparams
 
51
 
 
52
(************************************************************************)
 
53
 
 
54
(* Build the substitution that replaces Rels by the appropriate *)
 
55
(* inductives *)
 
56
let ind_subst mind mib =
 
57
  let ntypes = mib.mind_ntypes in
 
58
  let make_Ik k = mkInd (mind,ntypes-k-1) in 
 
59
  list_tabulate make_Ik ntypes
 
60
 
 
61
(* Instantiate inductives in constructor type *)
 
62
let constructor_instantiate mind mib c =
 
63
  let s = ind_subst mind mib in
 
64
  substl s c
 
65
 
 
66
let instantiate_params full t args sign =
 
67
  let fail () = 
 
68
    anomaly "instantiate_params: type, ctxt and args mismatch" in
 
69
  let (rem_args, subs, ty) =
 
70
    Sign.fold_rel_context
 
71
      (fun (_,copt,_) (largs,subs,ty) ->
 
72
        match (copt, largs, kind_of_term ty) with
 
73
          | (None, a::args, Prod(_,_,t)) -> (args, a::subs, t)
 
74
          | (Some b,_,LetIn(_,_,_,t))    -> (largs, (substl subs b)::subs, t)
 
75
          | (_,[],_)                -> if full then fail() else ([], subs, ty)
 
76
          | _                       -> fail ())
 
77
      sign
 
78
      ~init:(args,[],t) 
 
79
  in
 
80
  if rem_args <> [] then fail();
 
81
  substl subs ty
 
82
 
 
83
let instantiate_partial_params = instantiate_params false
 
84
 
 
85
let full_inductive_instantiate mib params sign =
 
86
  let dummy = prop_sort in
 
87
  let t = mkArity (sign,dummy) in
 
88
  fst (destArity (instantiate_params true t params mib.mind_params_ctxt))
 
89
 
 
90
let full_constructor_instantiate ((mind,_),(mib,_),params) =
 
91
  let inst_ind = constructor_instantiate mind mib in
 
92
  (fun t ->
 
93
    instantiate_params true (inst_ind t) params mib.mind_params_ctxt)
 
94
 
 
95
(************************************************************************)
 
96
(************************************************************************)
 
97
 
 
98
(* Functions to build standard types related to inductive *)
 
99
 
 
100
 
 
101
let number_of_inductives mib = Array.length mib.mind_packets
 
102
let number_of_constructors mip = Array.length mip.mind_consnames
 
103
 
 
104
(* 
 
105
Computing the actual sort of an applied or partially applied inductive type:
 
106
 
 
107
I_i: forall uniformparams:utyps, forall otherparams:otyps, Type(a)
 
108
uniformargs : utyps 
 
109
otherargs : otyps
 
110
I_1:forall ...,s_1;...I_n:forall ...,s_n |- sort(C_kj(uniformargs)) = s_kj
 
111
s'_k = max(..s_kj..)
 
112
merge(..s'_k..) = ..s''_k..
 
113
--------------------------------------------------------------------
 
114
Gamma |- I_i uniformargs otherargs : phi(s''_i)
 
115
 
 
116
where
 
117
 
 
118
- if p=0, phi() = Prop
 
119
- if p=1, phi(s) = s
 
120
- if p<>1, phi(s) = sup(Set,s)
 
121
 
 
122
Remark: Set (predicative) is encoded as Type(0)
 
123
*)
 
124
 
 
125
let sort_as_univ = function
 
126
| Type u -> u
 
127
| Prop Null -> type0m_univ
 
128
| Prop Pos -> type0_univ
 
129
 
 
130
let cons_subst u su subst =
 
131
  try (u, sup su (List.assoc u subst)) :: List.remove_assoc u subst
 
132
  with Not_found -> (u, su) :: subst
 
133
 
 
134
let actualize_decl_level env lev t =
 
135
  let sign,s = dest_arity env t in
 
136
  mkArity (sign,lev)
 
137
 
 
138
let polymorphism_on_non_applied_parameters = false
 
139
 
 
140
(* Bind expected levels of parameters to actual levels *)
 
141
(* Propagate the new levels in the signature *)
 
142
let rec make_subst env = function
 
143
  | (_,Some _,_ as t)::sign, exp, args ->
 
144
      let ctx,subst = make_subst env (sign, exp, args) in
 
145
      t::ctx, subst
 
146
  | d::sign, None::exp, args ->
 
147
      let args = match args with _::args -> args | [] -> [] in
 
148
      let ctx,subst = make_subst env (sign, exp, args) in
 
149
      d::ctx, subst
 
150
  | d::sign, Some u::exp, a::args ->
 
151
      (* We recover the level of the argument, but we don't change the *)
 
152
      (* level in the corresponding type in the arity; this level in the *)
 
153
      (* arity is a global level which, at typing time, will be enforce *)
 
154
      (* to be greater than the level of the argument; this is probably *)
 
155
      (* a useless extra constraint *)
 
156
      let s = sort_as_univ (snd (dest_arity env a)) in
 
157
      let ctx,subst = make_subst env (sign, exp, args) in
 
158
      d::ctx, cons_subst u s subst
 
159
  | (na,None,t as d)::sign, Some u::exp, [] ->
 
160
      (* No more argument here: we instantiate the type with a fresh level *)
 
161
      (* which is first propagated to the corresponding premise in the arity *)
 
162
      (* (actualize_decl_level), then to the conclusion of the arity (via *)
 
163
      (* the substitution) *)
 
164
      let ctx,subst = make_subst env (sign, exp, []) in
 
165
      if polymorphism_on_non_applied_parameters then
 
166
        let s = fresh_local_univ () in
 
167
        let t = actualize_decl_level env (Type s) t in
 
168
        (na,None,t)::ctx, cons_subst u s subst
 
169
      else
 
170
        d::ctx, subst
 
171
  | sign, [], _ ->
 
172
      (* Uniform parameters are exhausted *)
 
173
      sign,[]
 
174
  | [], _, _ ->
 
175
      assert false
 
176
 
 
177
let instantiate_universes env ctx ar argsorts =
 
178
  let args = Array.to_list argsorts in
 
179
  let ctx,subst = make_subst env (ctx,ar.poly_param_levels,args) in
 
180
  let level = subst_large_constraints subst ar.poly_level in
 
181
  ctx,
 
182
  (* Singleton type not containing types are interpretable in Prop *)
 
183
  if is_type0m_univ level then prop_sort
 
184
  (* Non singleton type not containing types are interpretable in Set *)
 
185
  else if is_type0_univ level then set_sort
 
186
  (* This is a Type with constraints *)
 
187
 else Type level
 
188
 
 
189
let type_of_inductive_knowing_parameters env mip paramtyps =
 
190
  match mip.mind_arity with
 
191
  | Monomorphic s ->
 
192
      s.mind_user_arity
 
193
  | Polymorphic ar ->
 
194
      let ctx = List.rev mip.mind_arity_ctxt in
 
195
      let ctx,s = instantiate_universes env ctx ar paramtyps in
 
196
      mkArity (List.rev ctx,s)
 
197
 
 
198
(* Type of a (non applied) inductive type *)
 
199
 
 
200
let type_of_inductive env (_,mip) =
 
201
  type_of_inductive_knowing_parameters env mip [||]
 
202
 
 
203
(* The max of an array of universes *)
 
204
 
 
205
let cumulate_constructor_univ u = function
 
206
  | Prop Null -> u
 
207
  | Prop Pos -> sup type0_univ u
 
208
  | Type u' -> sup u u'
 
209
 
 
210
let max_inductive_sort =
 
211
  Array.fold_left cumulate_constructor_univ type0m_univ
 
212
 
 
213
(************************************************************************)
 
214
(* Type of a constructor *)
 
215
 
 
216
let type_of_constructor cstr (mib,mip) =
 
217
  let ind = inductive_of_constructor cstr in
 
218
  let specif = mip.mind_user_lc in
 
219
  let i = index_of_constructor cstr in
 
220
  let nconstr = Array.length mip.mind_consnames in
 
221
  if i > nconstr then error "Not enough constructors in the type.";
 
222
  constructor_instantiate (fst ind) mib specif.(i-1)
 
223
 
 
224
let arities_of_specif kn (mib,mip) = 
 
225
  let specif = mip.mind_nf_lc in
 
226
  Array.map (constructor_instantiate kn mib) specif
 
227
 
 
228
let arities_of_constructors ind specif = 
 
229
  arities_of_specif (fst ind) specif
 
230
 
 
231
let type_of_constructors ind (mib,mip) =
 
232
  let specif = mip.mind_user_lc in
 
233
  Array.map (constructor_instantiate (fst ind) mib) specif
 
234
 
 
235
(************************************************************************)
 
236
 
 
237
let error_elim_expln kp ki =
 
238
  match kp,ki with
 
239
  | (InType | InSet), InProp -> NonInformativeToInformative
 
240
  | InType, InSet -> StrongEliminationOnNonSmallType (* if Set impredicative *)
 
241
  | _ -> WrongArity
 
242
 
 
243
(* Type of case predicates *)
 
244
 
 
245
let local_rels ctxt =
 
246
  let (rels,_) =
 
247
    Sign.fold_rel_context_reverse
 
248
      (fun (rels,n) (_,copt,_) ->
 
249
        match copt with
 
250
            None   -> (mkRel n :: rels, n+1)
 
251
          | Some _ -> (rels, n+1))
 
252
      ~init:([],1)
 
253
      ctxt 
 
254
  in
 
255
  rels
 
256
 
 
257
(* Get type of inductive, with parameters instantiated *)
 
258
 
 
259
let inductive_sort_family mip =
 
260
  match mip.mind_arity with
 
261
   | Monomorphic s -> family_of_sort s.mind_sort 
 
262
   | Polymorphic _ -> InType
 
263
 
 
264
let mind_arity mip =
 
265
  mip.mind_arity_ctxt, inductive_sort_family mip
 
266
 
 
267
let get_instantiated_arity (mib,mip) params =
 
268
  let sign, s = mind_arity mip in
 
269
  full_inductive_instantiate mib params sign, s
 
270
 
 
271
let elim_sorts (_,mip) = mip.mind_kelim
 
272
 
 
273
let rel_list n m = 
 
274
  let rec reln l p = 
 
275
    if p>m then l else reln (mkRel(n+p)::l) (p+1)
 
276
  in 
 
277
  reln [] 1
 
278
 
 
279
let build_dependent_inductive ind (_,mip) params =
 
280
  let nrealargs = mip.mind_nrealargs in
 
281
  applist 
 
282
    (mkInd ind, (List.map (lift nrealargs) params)@(rel_list 0 nrealargs))
 
283
 
 
284
(* This exception is local *)
 
285
exception LocalArity of (sorts_family * sorts_family * arity_error) option
 
286
 
 
287
let check_allowed_sort ksort specif =
 
288
  if not (List.exists ((=) ksort) (elim_sorts specif)) then 
 
289
    let s = inductive_sort_family (snd specif) in
 
290
    raise (LocalArity (Some(ksort,s,error_elim_expln ksort s)))
 
291
 
 
292
let is_correct_arity env c pj ind specif params = 
 
293
  let arsign,_ = get_instantiated_arity specif params in
 
294
  let rec srec env pt ar u =
 
295
    let pt' = whd_betadeltaiota env pt in
 
296
    match kind_of_term pt', ar with
 
297
      | Prod (na1,a1,t), (_,None,a1')::ar' ->
 
298
          let univ =
 
299
            try conv env a1 a1'
 
300
            with NotConvertible -> raise (LocalArity None) in
 
301
          srec (push_rel (na1,None,a1) env) t ar' (Constraint.union u univ)
 
302
      | Prod (_,a1,a2), [] -> (* whnf of t was not needed here! *)
 
303
          let ksort = match kind_of_term (whd_betadeltaiota env a2) with
 
304
            | Sort s -> family_of_sort s 
 
305
            | _ -> raise (LocalArity None) in
 
306
          let dep_ind = build_dependent_inductive ind specif params in 
 
307
          let univ =
 
308
            try conv env a1 dep_ind
 
309
            with NotConvertible -> raise (LocalArity None) in
 
310
          check_allowed_sort ksort specif;
 
311
          (true, Constraint.union u univ)
 
312
      | Sort s', [] ->
 
313
          check_allowed_sort (family_of_sort s') specif;
 
314
          (false, u)
 
315
      | _ ->
 
316
          raise (LocalArity None)
 
317
  in 
 
318
  try srec env pj.uj_type (List.rev arsign) Constraint.empty
 
319
  with LocalArity kinds ->
 
320
    error_elim_arity env ind (elim_sorts specif) c pj kinds
 
321
 
 
322
 
 
323
(************************************************************************)
 
324
(* Type of case branches *)
 
325
 
 
326
(* [p] is the predicate, [i] is the constructor number (starting from 0),
 
327
   and [cty] is the type of the constructor (params not instantiated) *)
 
328
let build_branches_type ind (_,mip as specif) params dep p =
 
329
  let build_one_branch i cty =
 
330
    let typi = full_constructor_instantiate (ind,specif,params) cty in
 
331
    let (args,ccl) = decompose_prod_assum typi in
 
332
    let nargs = rel_context_length args in
 
333
    let (_,allargs) = decompose_app ccl in
 
334
    let (lparams,vargs) = list_chop (inductive_params specif) allargs in
 
335
    let cargs =
 
336
      if dep then
 
337
        let cstr = ith_constructor_of_inductive ind (i+1) in
 
338
        let dep_cstr = applist (mkConstruct cstr,lparams@(local_rels args)) in
 
339
        vargs @ [dep_cstr]
 
340
      else
 
341
        vargs in
 
342
    let base = beta_appvect (lift nargs p) (Array.of_list cargs) in
 
343
    it_mkProd_or_LetIn base args in
 
344
  Array.mapi build_one_branch mip.mind_nf_lc
 
345
 
 
346
(* [p] is the predicate, [c] is the match object, [realargs] is the
 
347
   list of real args of the inductive type *)
 
348
let build_case_type dep p c realargs =
 
349
  let args = if dep then realargs@[c] else realargs in
 
350
  beta_appvect p (Array.of_list args)
 
351
 
 
352
let type_case_branches env (ind,largs) pj c =
 
353
  let specif = lookup_mind_specif env ind in 
 
354
  let nparams = inductive_params specif in
 
355
  let (params,realargs) = list_chop nparams largs in
 
356
  let p = pj.uj_val in
 
357
  let (dep,univ) = is_correct_arity env c pj ind specif params in
 
358
  let lc = build_branches_type ind specif params dep p in
 
359
  let ty = build_case_type dep p c realargs in
 
360
  (lc, ty, univ)
 
361
 
 
362
 
 
363
(************************************************************************)
 
364
(* Checking the case annotation is relevent *)
 
365
 
 
366
let rec inductive_kn_equiv env kn1 kn2 =
 
367
  match (lookup_mind kn1 env).mind_equiv with
 
368
    | Some kn1' -> inductive_kn_equiv env kn2 kn1'
 
369
    | None -> match (lookup_mind kn2 env).mind_equiv with
 
370
        | Some kn2' -> inductive_kn_equiv env kn2' kn1
 
371
        | None -> false
 
372
 
 
373
let inductive_equiv env (kn1,i1) (kn2,i2) =
 
374
  i1=i2 & inductive_kn_equiv env kn1 kn2
 
375
 
 
376
let check_case_info env indsp ci =
 
377
  let (mib,mip) = lookup_mind_specif env indsp in
 
378
  if
 
379
    not (Closure.mind_equiv env indsp ci.ci_ind) or
 
380
    (mib.mind_nparams <> ci.ci_npar) or
 
381
    (mip.mind_consnrealdecls <> ci.ci_cstr_nargs)
 
382
  then raise (TypeError(env,WrongCaseInfo(indsp,ci)))
 
383
 
 
384
(************************************************************************)
 
385
(************************************************************************)
 
386
 
 
387
(* Guard conditions for fix and cofix-points *)
 
388
 
 
389
(* Check if t is a subterm of Rel n, and gives its specification, 
 
390
   assuming lst already gives index of
 
391
   subterms with corresponding specifications of recursive arguments *)
 
392
 
 
393
(* A powerful notion of subterm *)
 
394
 
 
395
(* To each inductive definition corresponds an array describing the
 
396
   structure of recursive arguments for each constructor, we call it
 
397
   the recursive spec of the type (it has type recargs vect).  For
 
398
   checking the guard, we start from the decreasing argument (Rel n)
 
399
   with its recursive spec.  During checking the guardness condition,
 
400
   we collect patterns variables corresponding to subterms of n, each
 
401
   of them with its recursive spec.  They are organised in a list lst
 
402
   of type (int * recargs) list which is sorted with respect to the
 
403
   first argument.
 
404
*)
 
405
 
 
406
(*************************************************************)
 
407
(* Environment annotated with marks on recursive arguments *)
 
408
 
 
409
(* tells whether it is a strict or loose subterm *)
 
410
type size = Large | Strict
 
411
 
 
412
(* merging information *)
 
413
let size_glb s1 s2 =
 
414
  match s1,s2 with
 
415
      Strict, Strict -> Strict
 
416
    | _ -> Large
 
417
 
 
418
(* possible specifications for a term:
 
419
   - Not_subterm: when the size of a term is not related to the
 
420
     recursive argument of the fixpoint
 
421
   - Subterm: when the term is a subterm of the recursive argument
 
422
       the wf_paths argument specifies which subterms are recursive
 
423
   - Dead_code: when the term has been built by elimination over an
 
424
       empty type
 
425
 *)
 
426
 
 
427
type subterm_spec =
 
428
    Subterm of (size * wf_paths)
 
429
  | Dead_code
 
430
  | Not_subterm
 
431
 
 
432
let spec_of_tree t =
 
433
  if Rtree.eq_rtree (=) t mk_norec then Not_subterm else Subterm(Strict,t)
 
434
 
 
435
let subterm_spec_glb =
 
436
  let glb2 s1 s2 =
 
437
    match s1,s2 with
 
438
        _, Dead_code -> s1
 
439
      | Dead_code, _ -> s2
 
440
      | Not_subterm, _ -> Not_subterm
 
441
      | _, Not_subterm -> Not_subterm
 
442
      | Subterm (a1,t1), Subterm (a2,t2) ->
 
443
          if Rtree.eq_rtree (=) t1 t2 then Subterm (size_glb a1 a2, t1)
 
444
          (* branches do not return objects with same spec *)
 
445
          else Not_subterm in
 
446
  Array.fold_left glb2 Dead_code
 
447
          
 
448
type guard_env =
 
449
  { env     : env;
 
450
    (* dB of last fixpoint *)
 
451
    rel_min : int;
 
452
    (* inductive of recarg of each fixpoint *)
 
453
    inds    : inductive array;
 
454
    (* the recarg information of inductive family *)
 
455
    recvec  : wf_paths array;
 
456
    (* dB of variables denoting subterms *)
 
457
    genv    : subterm_spec list;
 
458
  }
 
459
 
 
460
let make_renv env minds recarg (kn,tyi) =
 
461
  let mib = Environ.lookup_mind kn env in
 
462
  let mind_recvec =
 
463
    Array.map (fun mip -> mip.mind_recargs) mib.mind_packets in
 
464
  { env = env;
 
465
    rel_min = recarg+2;
 
466
    inds = minds;
 
467
    recvec = mind_recvec;
 
468
    genv = [Subterm(Large,mind_recvec.(tyi))] }
 
469
 
 
470
let push_var renv (x,ty,spec) =
 
471
  { renv with 
 
472
    env = push_rel (x,None,ty) renv.env;
 
473
    rel_min = renv.rel_min+1;
 
474
    genv = spec:: renv.genv }
 
475
 
 
476
let assign_var_spec renv (i,spec) =
 
477
  { renv with genv = list_assign renv.genv (i-1) spec }
 
478
 
 
479
let push_var_renv renv (x,ty) =
 
480
  push_var renv (x,ty,Not_subterm)
 
481
 
 
482
(* Fetch recursive information about a variable p *)
 
483
let subterm_var p renv = 
 
484
  try List.nth renv.genv (p-1)
 
485
  with Failure _ | Invalid_argument _ -> Not_subterm
 
486
 
 
487
(* Add a variable and mark it as strictly smaller with information [spec]. *)
 
488
let add_subterm renv (x,a,spec) =
 
489
  push_var renv (x,a,spec_of_tree spec)
 
490
 
 
491
let push_ctxt_renv renv ctxt =
 
492
  let n = rel_context_length ctxt in
 
493
  { renv with 
 
494
    env = push_rel_context ctxt renv.env;
 
495
    rel_min = renv.rel_min+n;
 
496
    genv = iterate (fun ge -> Not_subterm::ge) n renv.genv }
 
497
 
 
498
let push_fix_renv renv (_,v,_ as recdef) =
 
499
  let n = Array.length v in
 
500
  { renv with
 
501
    env = push_rec_types recdef renv.env;
 
502
    rel_min = renv.rel_min+n;
 
503
    genv = iterate (fun ge -> Not_subterm::ge) n renv.genv }
 
504
 
 
505
 
 
506
(******************************)
 
507
(* Computing the recursive subterms of a term (propagation of size
 
508
   information through Cases). *)
 
509
 
 
510
(*
 
511
   c is a branch of an inductive definition corresponding to the spec
 
512
   lrec.  mind_recvec is the recursive spec of the inductive
 
513
   definition of the decreasing argument n.
 
514
 
 
515
   case_branches_specif renv lrec lc will pass the lambdas
 
516
   of c corresponding to pattern variables and collect possibly new
 
517
   subterms variables and returns the bodies of the branches with the
 
518
   correct envs and decreasing args.
 
519
*)
 
520
 
 
521
let lookup_subterms env ind =
 
522
  let (_,mip) = lookup_mind_specif env ind in
 
523
  mip.mind_recargs
 
524
 
 
525
(*********************************)
 
526
 
 
527
(* Propagation of size information through Cases: if the matched
 
528
   object is a recursive subterm then compute the information
 
529
   associated to its own subterms.
 
530
   Rq: if branch is not eta-long, then the recursive information
 
531
   is not propagated to the missing abstractions *)
 
532
let case_branches_specif renv c_spec ind lbr = 
 
533
  let rec push_branch_args renv lrec c = 
 
534
    match lrec with
 
535
        ra::lr ->
 
536
          let c' = whd_betadeltaiota renv.env c in
 
537
          (match kind_of_term c' with
 
538
              Lambda(x,a,b) ->
 
539
                let renv' = push_var renv (x,a,ra) in
 
540
                push_branch_args renv' lr b
 
541
            | _ -> (* branch not in eta-long form: cannot perform rec. calls *)
 
542
                (renv,c'))
 
543
      | [] -> (renv, c) in
 
544
  match c_spec with
 
545
      Subterm (_,t) ->
 
546
        let sub_spec = Array.map (List.map spec_of_tree) (dest_subterms t) in
 
547
        assert (Array.length sub_spec = Array.length lbr);
 
548
        array_map2 (push_branch_args renv) sub_spec lbr
 
549
    | Dead_code -> 
 
550
        let t = dest_subterms (lookup_subterms renv.env ind) in
 
551
        let sub_spec = Array.map (List.map (fun _ -> Dead_code)) t in
 
552
        assert (Array.length sub_spec = Array.length lbr);
 
553
        array_map2 (push_branch_args renv) sub_spec lbr
 
554
    | Not_subterm -> Array.map (fun c -> (renv,c)) lbr
 
555
 
 
556
(* [subterm_specif renv t] computes the recursive structure of [t] and
 
557
   compare its size with the size of the initial recursive argument of
 
558
   the fixpoint we are checking. [renv] collects such information
 
559
   about variables.
 
560
*)
 
561
 
 
562
let rec subterm_specif renv t = 
 
563
  (* maybe reduction is not always necessary! *)
 
564
  let f,l = decompose_app (whd_betadeltaiota renv.env t) in
 
565
  match kind_of_term f with 
 
566
    | Rel k -> subterm_var k renv
 
567
 
 
568
    | Case (ci,_,c,lbr) ->
 
569
        if Array.length lbr = 0 then Dead_code
 
570
        else
 
571
          let c_spec = subterm_specif renv c in
 
572
          let lbr_spec = case_branches_specif renv c_spec ci.ci_ind lbr in
 
573
          let stl  =
 
574
            Array.map (fun (renv',br') -> subterm_specif renv' br')
 
575
              lbr_spec in
 
576
          subterm_spec_glb stl
 
577
               
 
578
    | Fix ((recindxs,i),(_,typarray,bodies as recdef)) ->
 
579
(* when proving that the fixpoint f(x)=e is less than n, it is enough
 
580
   to prove that e is less than n assuming f is less than n
 
581
   furthermore when f is applied to a term which is strictly less than
 
582
   n, one may assume that x itself is strictly less than n
 
583
*)
 
584
        let (ctxt,clfix) = dest_prod renv.env typarray.(i) in
 
585
        let oind =
 
586
          let env' = push_rel_context ctxt renv.env in
 
587
          try Some(fst(find_inductive env' clfix))
 
588
          with Not_found -> None in
 
589
        (match oind with
 
590
            None -> Not_subterm (* happens if fix is polymorphic *)
 
591
          | Some ind ->
 
592
              let nbfix = Array.length typarray in
 
593
              let recargs = lookup_subterms renv.env ind in
 
594
              (* pushing the fixpoints *)
 
595
              let renv' = push_fix_renv renv recdef in
 
596
              let renv' =
 
597
                (* Why Strict here ? To be general, it could also be
 
598
                   Large... *)
 
599
                assign_var_spec renv' (nbfix-i, Subterm(Strict,recargs)) in
 
600
              let decrArg = recindxs.(i) in 
 
601
              let theBody = bodies.(i)   in
 
602
              let nbOfAbst = decrArg+1 in
 
603
              let sign,strippedBody = decompose_lam_n_assum nbOfAbst theBody in
 
604
              (* pushing the fix parameters *)
 
605
              let renv'' = push_ctxt_renv renv' sign in
 
606
              let renv'' =
 
607
                if List.length l < nbOfAbst then renv''
 
608
                else
 
609
                  let theDecrArg  = List.nth l decrArg in
 
610
                  let arg_spec    = subterm_specif renv theDecrArg in
 
611
                  assign_var_spec renv'' (1, arg_spec) in
 
612
              subterm_specif renv'' strippedBody)
 
613
 
 
614
    | Lambda (x,a,b) -> 
 
615
        assert (l=[]);
 
616
        subterm_specif (push_var_renv renv (x,a)) b
 
617
 
 
618
    (* Metas and evars are considered OK *)
 
619
    | (Meta _|Evar _) -> Dead_code
 
620
 
 
621
    (* Other terms are not subterms *)
 
622
    | _ -> Not_subterm
 
623
 
 
624
 
 
625
(* Check term c can be applied to one of the mutual fixpoints. *)
 
626
let check_is_subterm renv c = 
 
627
  match subterm_specif renv c with
 
628
    Subterm (Strict,_) | Dead_code -> true
 
629
  |  _ -> false
 
630
 
 
631
(************************************************************************)
 
632
 
 
633
exception FixGuardError of env * guard_error
 
634
 
 
635
let error_illegal_rec_call renv fx arg =
 
636
  let (_,le_vars,lt_vars) =
 
637
    List.fold_left
 
638
      (fun (i,le,lt) sbt ->
 
639
        match sbt with
 
640
            (Subterm(Strict,_) | Dead_code) -> (i+1, le, i::lt)
 
641
          | (Subterm(Large,_)) -> (i+1, i::le, lt)
 
642
          | _ -> (i+1, le ,lt))
 
643
      (1,[],[]) renv.genv in
 
644
  raise (FixGuardError (renv.env,
 
645
                        RecursionOnIllegalTerm(fx,arg,le_vars,lt_vars)))
 
646
 
 
647
let error_partial_apply renv fx =
 
648
  raise (FixGuardError (renv.env,NotEnoughArgumentsForFixCall fx))
 
649
 
 
650
(* Check if [def] is a guarded fixpoint body with decreasing arg.
 
651
   given [recpos], the decreasing arguments of each mutually defined
 
652
   fixpoint. *)
 
653
let check_one_fix renv recpos def =
 
654
  let nfi = Array.length recpos in 
 
655
 
 
656
  (* Checks if [t] only make valid recursive calls *)
 
657
  let rec check_rec_call renv t = 
 
658
    (* if [t] does not make recursive calls, it is guarded: *)
 
659
    if noccur_with_meta renv.rel_min nfi t then ()
 
660
    else
 
661
      let (f,l) = decompose_app (whd_betaiotazeta t) in
 
662
      match kind_of_term f with
 
663
        | Rel p -> 
 
664
            (* Test if [p] is a fixpoint (recursive call) *) 
 
665
            if renv.rel_min <= p & p < renv.rel_min+nfi then
 
666
              begin
 
667
                List.iter (check_rec_call renv) l;
 
668
                (* the position of the invoked fixpoint: *) 
 
669
                let glob = renv.rel_min+nfi-1-p in
 
670
                (* the decreasing arg of the rec call: *)
 
671
                let np = recpos.(glob) in
 
672
                if List.length l <= np then error_partial_apply renv glob
 
673
                else
 
674
                  (* Check the decreasing arg is smaller *)
 
675
                  let z = List.nth l np in
 
676
                  if not (check_is_subterm renv z) then
 
677
                    error_illegal_rec_call renv glob z
 
678
              end
 
679
            else
 
680
              begin
 
681
                match pi2 (lookup_rel p renv.env) with
 
682
                | None ->
 
683
                    List.iter (check_rec_call renv) l
 
684
                | Some c ->
 
685
                    try List.iter (check_rec_call renv) l
 
686
                    with FixGuardError _ ->
 
687
                      check_rec_call renv (applist(lift p c,l))
 
688
              end
 
689
 
 
690
        | Case (ci,p,c_0,lrest) ->
 
691
            List.iter (check_rec_call renv) (c_0::p::l);
 
692
            (* compute the recarg information for the arguments of
 
693
               each branch *)
 
694
            let c_spec = subterm_specif renv c_0 in
 
695
            let lbr = case_branches_specif renv c_spec ci.ci_ind lrest in
 
696
            Array.iter (fun (renv',br') -> check_rec_call renv' br') lbr
 
697
 
 
698
        (* Enables to traverse Fixpoint definitions in a more intelligent
 
699
           way, ie, the rule :
 
700
           if - g = Fix g/p := [y1:T1]...[yp:Tp]e &
 
701
              - f is guarded with respect to the set of pattern variables S 
 
702
                in a1 ... am        &
 
703
              - f is guarded with respect to the set of pattern variables S 
 
704
                in T1 ... Tp        &
 
705
              - ap is a sub-term of the formal argument of f &
 
706
              - f is guarded with respect to the set of pattern variables
 
707
                S+{yp} in e
 
708
           then f is guarded with respect to S in (g a1 ... am).
 
709
           Eduardo 7/9/98 *)
 
710
 
 
711
        | Fix ((recindxs,i),(_,typarray,bodies as recdef)) ->
 
712
            List.iter (check_rec_call renv) l;
 
713
            Array.iter (check_rec_call renv) typarray;
 
714
            let decrArg = recindxs.(i) in
 
715
            let renv' = push_fix_renv renv recdef in 
 
716
            if (List.length l < (decrArg+1)) then
 
717
              Array.iter (check_rec_call renv') bodies
 
718
            else 
 
719
              Array.iteri
 
720
                (fun j body ->
 
721
                  if i=j then
 
722
                    let theDecrArg  = List.nth l decrArg in
 
723
                    let arg_spec = subterm_specif renv theDecrArg in
 
724
                    check_nested_fix_body renv' (decrArg+1) arg_spec body
 
725
                  else check_rec_call renv' body)
 
726
                bodies
 
727
 
 
728
        | Const kn -> 
 
729
            if evaluable_constant kn renv.env then 
 
730
              try List.iter (check_rec_call renv) l
 
731
              with (FixGuardError _ ) ->
 
732
                check_rec_call renv(applist(constant_value renv.env kn, l))
 
733
            else List.iter (check_rec_call renv) l
 
734
 
 
735
        (* The cases below simply check recursively the condition on the
 
736
           subterms *)
 
737
        | Cast (a,_, b) -> 
 
738
            List.iter (check_rec_call renv) (a::b::l)
 
739
 
 
740
        | Lambda (x,a,b) ->
 
741
            List.iter (check_rec_call renv) (a::l);
 
742
            check_rec_call (push_var_renv renv (x,a)) b
 
743
 
 
744
        | Prod (x,a,b) -> 
 
745
            List.iter (check_rec_call renv) (a::l);
 
746
            check_rec_call (push_var_renv renv (x,a)) b
 
747
 
 
748
        | CoFix (i,(_,typarray,bodies as recdef)) ->
 
749
            List.iter (check_rec_call renv) l;
 
750
            Array.iter (check_rec_call renv) typarray;
 
751
            let renv' = push_fix_renv renv recdef in
 
752
            Array.iter (check_rec_call renv') bodies
 
753
 
 
754
        | (Ind _ | Construct _ | Sort _) ->
 
755
            List.iter (check_rec_call renv) l
 
756
 
 
757
        | Var id ->
 
758
            begin
 
759
              match pi2 (lookup_named id renv.env) with
 
760
              | None ->
 
761
                  List.iter (check_rec_call renv) l
 
762
              | Some c ->
 
763
                  try List.iter (check_rec_call renv) l
 
764
                  with (FixGuardError _) -> check_rec_call renv (applist(c,l))
 
765
            end
 
766
 
 
767
        (* l is not checked because it is considered as the meta's context *)
 
768
        | (Evar _ | Meta _) -> ()
 
769
 
 
770
        | (App _ | LetIn _) -> assert false (* beta zeta reduction *)
 
771
 
 
772
  and check_nested_fix_body renv decr recArgsDecrArg body =
 
773
    if decr = 0 then
 
774
      check_rec_call (assign_var_spec renv (1,recArgsDecrArg)) body
 
775
    else
 
776
      match kind_of_term body with
 
777
        | Lambda (x,a,b) ->
 
778
            check_rec_call renv a;
 
779
            let renv' = push_var_renv renv (x,a) in
 
780
            check_nested_fix_body renv' (decr-1) recArgsDecrArg b
 
781
        | _ -> anomaly "Not enough abstractions in fix body"
 
782
 
 
783
  in
 
784
  check_rec_call renv def
 
785
 
 
786
let judgment_of_fixpoint (_, types, bodies) =
 
787
  array_map2 (fun typ body -> { uj_val = body ; uj_type = typ }) types bodies
 
788
 
 
789
let inductive_of_mutfix env ((nvect,bodynum),(names,types,bodies as recdef)) =
 
790
  let nbfix = Array.length bodies in 
 
791
  if nbfix = 0
 
792
    or Array.length nvect <> nbfix 
 
793
    or Array.length types <> nbfix
 
794
    or Array.length names <> nbfix
 
795
    or bodynum < 0
 
796
    or bodynum >= nbfix
 
797
  then anomaly "Ill-formed fix term";
 
798
  let fixenv = push_rec_types recdef env in
 
799
  let vdefj = judgment_of_fixpoint recdef in
 
800
  let raise_err env i err =
 
801
    error_ill_formed_rec_body env err names i fixenv vdefj in
 
802
  (* Check the i-th definition with recarg k *)
 
803
  let find_ind i k def = 
 
804
    (* check fi does not appear in the k+1 first abstractions, 
 
805
       gives the type of the k+1-eme abstraction (must be an inductive)  *)
 
806
    let rec check_occur env n def = 
 
807
      match kind_of_term (whd_betadeltaiota env def) with
 
808
        | Lambda (x,a,b) -> 
 
809
            if noccur_with_meta n nbfix a then
 
810
              let env' = push_rel (x, None, a) env in
 
811
              if n = k+1 then
 
812
                (* get the inductive type of the fixpoint *)
 
813
                let (mind, _) = 
 
814
                  try find_inductive env a 
 
815
                  with Not_found ->
 
816
                    raise_err env i (RecursionNotOnInductiveType a) in
 
817
                (mind, (env', b))
 
818
              else check_occur env' (n+1) b
 
819
            else anomaly "check_one_fix: Bad occurrence of recursive call"
 
820
        | _ -> raise_err env i NotEnoughAbstractionInFixBody in
 
821
    check_occur fixenv 1 def in
 
822
  (* Do it on every fixpoint *)
 
823
  let rv = array_map2_i find_ind nvect bodies in
 
824
  (Array.map fst rv, Array.map snd rv)
 
825
 
 
826
 
 
827
let check_fix env ((nvect,_),(names,_,bodies as recdef) as fix) =
 
828
  let (minds, rdef) = inductive_of_mutfix env fix in
 
829
  for i = 0 to Array.length bodies - 1 do
 
830
    let (fenv,body) = rdef.(i) in
 
831
    let renv = make_renv fenv minds nvect.(i) minds.(i) in
 
832
    try check_one_fix renv nvect body
 
833
    with FixGuardError (fixenv,err) ->
 
834
      error_ill_formed_rec_body fixenv err names i 
 
835
        (push_rec_types recdef env) (judgment_of_fixpoint recdef)
 
836
  done
 
837
 
 
838
(*
 
839
let cfkey = Profile.declare_profile "check_fix";;
 
840
let check_fix env fix = Profile.profile3 cfkey check_fix env fix;;
 
841
*)
 
842
 
 
843
(************************************************************************)
 
844
(* Co-fixpoints. *)
 
845
 
 
846
exception CoFixGuardError of env * guard_error
 
847
 
 
848
let anomaly_ill_typed () =
 
849
  anomaly "check_one_cofix: too many arguments applied to constructor"
 
850
 
 
851
let rec codomain_is_coind env c =
 
852
  let b = whd_betadeltaiota env c in
 
853
  match kind_of_term b with
 
854
    | Prod (x,a,b) ->
 
855
        codomain_is_coind (push_rel (x, None, a) env) b 
 
856
    | _ -> 
 
857
        (try find_coinductive env b
 
858
        with Not_found ->
 
859
          raise (CoFixGuardError (env, CodomainNotInductiveType b)))
 
860
 
 
861
let check_one_cofix env nbfix def deftype = 
 
862
  let rec check_rec_call env alreadygrd n vlra  t =
 
863
    if not (noccur_with_meta n nbfix t) then
 
864
      let c,args = decompose_app (whd_betadeltaiota env t) in
 
865
      match kind_of_term c with 
 
866
        | Rel p when  n <= p && p < n+nbfix ->
 
867
            (* recursive call: must be guarded and no nested recursive
 
868
               call allowed *)
 
869
            if not alreadygrd then
 
870
              raise (CoFixGuardError (env,UnguardedRecursiveCall t))
 
871
            else if not(List.for_all (noccur_with_meta n nbfix) args) then
 
872
              raise (CoFixGuardError (env,NestedRecursiveOccurrences))
 
873
                 
 
874
        | Construct (_,i as cstr_kn)  ->
 
875
            let lra = vlra.(i-1) in 
 
876
            let mI = inductive_of_constructor cstr_kn in
 
877
            let (mib,mip) = lookup_mind_specif env mI in
 
878
            let realargs = list_skipn mib.mind_nparams args in
 
879
            let rec process_args_of_constr = function
 
880
              | (t::lr), (rar::lrar) -> 
 
881
                  if rar = mk_norec then
 
882
                    if noccur_with_meta n nbfix t
 
883
                    then process_args_of_constr (lr, lrar)
 
884
                    else raise (CoFixGuardError
 
885
                                 (env,RecCallInNonRecArgOfConstructor t))
 
886
                  else
 
887
                    let spec = dest_subterms rar in
 
888
                    check_rec_call env true n spec t;
 
889
                    process_args_of_constr (lr, lrar)
 
890
              | [],_ -> ()
 
891
              | _ -> anomaly_ill_typed () 
 
892
            in process_args_of_constr (realargs, lra)
 
893
                 
 
894
        | Lambda (x,a,b) ->
 
895
             assert (args = []);
 
896
            if noccur_with_meta n nbfix a then
 
897
              let env' = push_rel (x, None, a) env in
 
898
              check_rec_call env' alreadygrd (n+1)  vlra b
 
899
            else 
 
900
              raise (CoFixGuardError (env,RecCallInTypeOfAbstraction a))
 
901
              
 
902
        | CoFix (j,(_,varit,vdefs as recdef)) ->
 
903
            if (List.for_all (noccur_with_meta n nbfix) args)
 
904
            then 
 
905
              let nbfix = Array.length vdefs in
 
906
              if (array_for_all (noccur_with_meta n nbfix) varit) then
 
907
                let env' = push_rec_types recdef env in
 
908
                (Array.iter (check_rec_call env' alreadygrd (n+1) vlra) vdefs;
 
909
                 List.iter (check_rec_call env alreadygrd n vlra) args)
 
910
              else 
 
911
                raise (CoFixGuardError (env,RecCallInTypeOfDef c))
 
912
            else
 
913
              raise (CoFixGuardError (env,UnguardedRecursiveCall c))
 
914
 
 
915
        | Case (_,p,tm,vrest) ->
 
916
            if (noccur_with_meta n nbfix p) then
 
917
              if (noccur_with_meta n nbfix tm) then
 
918
                if (List.for_all (noccur_with_meta n nbfix) args) then
 
919
                  Array.iter (check_rec_call env alreadygrd n vlra) vrest
 
920
                else 
 
921
                  raise (CoFixGuardError (env,RecCallInCaseFun c))
 
922
              else 
 
923
                raise (CoFixGuardError (env,RecCallInCaseArg c))
 
924
            else 
 
925
              raise (CoFixGuardError (env,RecCallInCasePred c))
 
926
              
 
927
        | Meta _ -> ()
 
928
        | Evar _ ->
 
929
            List.iter (check_rec_call env alreadygrd n vlra) args
 
930
              
 
931
        | _    -> raise (CoFixGuardError (env,NotGuardedForm t)) in 
 
932
 
 
933
  let (mind, _) = codomain_is_coind env deftype in
 
934
  let vlra = lookup_subterms env mind in
 
935
  check_rec_call env false 1 (dest_subterms vlra) def
 
936
 
 
937
(* The  function which checks that the whole block of definitions 
 
938
   satisfies the guarded condition *)
 
939
 
 
940
let check_cofix env (bodynum,(names,types,bodies as recdef)) = 
 
941
  let nbfix = Array.length bodies in 
 
942
  for i = 0 to nbfix-1 do
 
943
    let fixenv = push_rec_types recdef env in
 
944
    try check_one_cofix fixenv nbfix bodies.(i) types.(i)
 
945
    with CoFixGuardError (errenv,err) -> 
 
946
      error_ill_formed_rec_body errenv err names i 
 
947
        fixenv (judgment_of_fixpoint recdef)
 
948
  done