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

« back to all changes in this revision

Viewing changes to proofs/logic.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: logic.ml 12168 2009-06-06 21:34:37Z herbelin $ *)
 
10
 
 
11
open Pp
 
12
open Util
 
13
open Names
 
14
open Nameops
 
15
open Evd
 
16
open Term
 
17
open Termops
 
18
open Sign
 
19
open Environ
 
20
open Reductionops
 
21
open Inductive
 
22
open Inductiveops
 
23
open Typing
 
24
open Proof_trees
 
25
open Proof_type
 
26
open Typeops
 
27
open Type_errors
 
28
open Retyping
 
29
open Evarutil
 
30
open Tacexpr
 
31
 
 
32
type refiner_error =
 
33
 
 
34
  (* Errors raised by the refiner *)
 
35
  | BadType of constr * constr * constr
 
36
  | UnresolvedBindings of name list
 
37
  | CannotApply of constr * constr
 
38
  | NotWellTyped of constr
 
39
  | NonLinearProof of constr
 
40
  | MetaInType of constr
 
41
 
 
42
  (* Errors raised by the tactics *)
 
43
  | IntroNeedsProduct
 
44
  | DoesNotOccurIn of constr * identifier
 
45
 
 
46
exception RefinerError of refiner_error
 
47
 
 
48
open Pretype_errors
 
49
 
 
50
let rec catchable_exception = function
 
51
  | Stdpp.Exc_located(_,e) -> catchable_exception e
 
52
  | LtacLocated(_,e) -> catchable_exception e
 
53
  | Util.UserError _ | TypeError _ 
 
54
  | RefinerError _ | Indrec.RecursionSchemeError _
 
55
  | Nametab.GlobalizationError _ | PretypeError (_,VarNotFound _)
 
56
  (* unification errors *)
 
57
  | PretypeError(_,(CannotUnify _|CannotUnifyLocal _|CannotGeneralize _
 
58
                   |NoOccurrenceFound _|CannotUnifyBindingType _|NotClean _
 
59
                   |CannotFindWellTypedAbstraction _
 
60
                   |UnsolvableImplicit _)) -> true
 
61
  | Typeclasses_errors.TypeClassError 
 
62
      (_, Typeclasses_errors.UnsatisfiableConstraints _) -> true
 
63
  | _ -> false
 
64
 
 
65
let error_no_such_hypothesis id =
 
66
  error ("No such hypothesis: " ^ string_of_id id ^ ".")
 
67
 
 
68
(* Tells if the refiner should check that the submitted rules do not
 
69
   produce invalid subgoals *)
 
70
let check = ref false
 
71
let with_check = Flags.with_option check
 
72
 
 
73
(* [apply_to_hyp sign id f] splits [sign] into [tail::[id,_,_]::head] and
 
74
   returns [tail::(f head (id,_,_) (rev tail))] *)
 
75
let apply_to_hyp sign id f =
 
76
  try apply_to_hyp sign id f 
 
77
  with Hyp_not_found -> 
 
78
    if !check then error "No such assumption."
 
79
    else sign
 
80
 
 
81
let apply_to_hyp_and_dependent_on sign id f g =
 
82
  try apply_to_hyp_and_dependent_on sign id f g 
 
83
  with Hyp_not_found -> 
 
84
    if !check then error "No such assumption."
 
85
    else sign
 
86
 
 
87
let check_typability env sigma c =
 
88
  if !check then let _ = type_of env sigma c in () 
 
89
 
 
90
(************************************************************************)
 
91
(************************************************************************)
 
92
(* Implementation of the structural rules (moving and deleting
 
93
   hypotheses around) *)
 
94
 
 
95
(* The Clear tactic: it scans the context for hypotheses to be removed
 
96
   (instead of iterating on the list of identifier to be removed, which
 
97
   forces the user to give them in order). *)
 
98
 
 
99
let clear_hyps sigma ids sign cl =
 
100
  let evdref = ref (Evd.create_goal_evar_defs sigma) in
 
101
  let (hyps,concl) = Evarutil.clear_hyps_in_evi evdref sign cl ids in
 
102
  (hyps,concl,evars_of !evdref)
 
103
 
 
104
(* The ClearBody tactic *)
 
105
 
 
106
let recheck_typability (what,id) env sigma t =
 
107
  try check_typability env sigma t
 
108
  with _ ->
 
109
    let s = match what with
 
110
      | None -> "the conclusion"
 
111
      | Some id -> "hypothesis "^(string_of_id id) in
 
112
    error
 
113
      ("The correctness of "^s^" relies on the body of "^(string_of_id id))
 
114
  
 
115
let remove_hyp_body env sigma id =
 
116
  let sign =
 
117
    apply_to_hyp_and_dependent_on (named_context_val env) id
 
118
      (fun (_,c,t) _ ->
 
119
        match c with
 
120
        | None -> error ((string_of_id id)^" is not a local definition.")
 
121
        | Some c ->(id,None,t))
 
122
      (fun (id',c,t as d) sign ->
 
123
        (if !check then
 
124
          begin 
 
125
            let env = reset_with_named_context sign env in
 
126
            match c with
 
127
            | None ->  recheck_typability (Some id',id) env sigma t
 
128
            | Some b ->
 
129
                let b' = mkCast (b,DEFAULTcast, t) in
 
130
                recheck_typability (Some id',id) env sigma b'
 
131
          end;d))
 
132
  in
 
133
  reset_with_named_context sign env 
 
134
 
 
135
(* Reordering of the context *)
 
136
 
 
137
(* faire le minimum d'echanges pour que l'ordre donne soit un *)
 
138
(* sous-ordre du resultat. Par exemple, 2 hyps non mentionnee ne sont *)
 
139
(* pas echangees. Choix: les hyps mentionnees ne peuvent qu'etre *)
 
140
(* reculees par rapport aux autres (faire le contraire!) *)
 
141
 
 
142
let mt_q = (Idmap.empty,[])
 
143
let push_val y = function
 
144
    (_,[] as q) -> q
 
145
  | (m, (x,l)::q) -> (m, (x,Idset.add y l)::q)
 
146
let push_item x v (m,l) =
 
147
  (Idmap.add x v m, (x,Idset.empty)::l)
 
148
let mem_q x (m,_) = Idmap.mem x m
 
149
let rec find_q x (m,q) =
 
150
  let v = Idmap.find x m in
 
151
  let m' = Idmap.remove x m in
 
152
  let rec find accs acc = function
 
153
      [] -> raise Not_found
 
154
    | [(x',l)] ->
 
155
        if x=x' then ((v,Idset.union accs l),(m',List.rev acc))
 
156
        else raise Not_found
 
157
    | (x',l as i)::((x'',l'')::q as itl) ->
 
158
        if x=x' then
 
159
          ((v,Idset.union accs l),
 
160
           (m',List.rev acc@(x'',Idset.add x (Idset.union l l''))::q))
 
161
        else find (Idset.union l accs) (i::acc) itl in
 
162
  find Idset.empty [] q
 
163
 
 
164
let occur_vars_in_decl env hyps d =
 
165
  if Idset.is_empty hyps then false else
 
166
    let ohyps = global_vars_set_of_decl env d in
 
167
    Idset.exists (fun h -> Idset.mem h ohyps) hyps
 
168
 
 
169
let reorder_context env sign ord =
 
170
  let ords = List.fold_right Idset.add ord Idset.empty in
 
171
  if List.length ord <> Idset.cardinal ords then
 
172
    error "Order list has duplicates";
 
173
  let rec step ord expected ctxt_head moved_hyps ctxt_tail =
 
174
    match ord with
 
175
      | [] -> List.rev ctxt_tail @ ctxt_head
 
176
      | top::ord' when mem_q top moved_hyps ->
 
177
          let ((d,h),mh) = find_q top moved_hyps in
 
178
          if occur_vars_in_decl env h d then
 
179
            errorlabstrm "reorder_context"
 
180
              (str "Cannot move declaration " ++ pr_id top ++ spc() ++
 
181
              str "before " ++
 
182
              prlist_with_sep pr_spc pr_id
 
183
                (Idset.elements (Idset.inter h
 
184
                  (global_vars_set_of_decl env d))));
 
185
          step ord' expected ctxt_head mh (d::ctxt_tail)
 
186
      | _ ->
 
187
          (match ctxt_head with
 
188
            | [] -> error_no_such_hypothesis (List.hd ord)
 
189
            | (x,_,_ as d) :: ctxt ->
 
190
                if Idset.mem x expected then
 
191
                  step ord (Idset.remove x expected)
 
192
                    ctxt (push_item x d moved_hyps) ctxt_tail
 
193
                else
 
194
                  step ord expected
 
195
                    ctxt (push_val x moved_hyps) (d::ctxt_tail)) in
 
196
  step ord ords sign mt_q []
 
197
 
 
198
let reorder_val_context env sign ord =
 
199
  val_of_named_context (reorder_context env (named_context_of_val sign) ord)
 
200
 
 
201
 
 
202
 
 
203
 
 
204
let check_decl_position env sign (x,_,_ as d) =
 
205
  let needed = global_vars_set_of_decl env d in
 
206
  let deps = dependency_closure env (named_context_of_val sign) needed in
 
207
  if List.mem x deps then
 
208
    error ("Cannot create self-referring hypothesis "^string_of_id x);
 
209
  x::deps
 
210
 
 
211
(* Auxiliary functions for primitive MOVE tactic
 
212
 *
 
213
 * [move_hyp with_dep toleft (left,(hfrom,typfrom),right) hto] moves
 
214
 * hyp [hfrom] at location [hto] which belongs to the hyps on the 
 
215
 * left side [left] of the full signature if [toleft=true] or to the hyps 
 
216
 * on the right side [right] if [toleft=false].
 
217
 * If [with_dep] then dependent hypotheses are moved accordingly. *)
 
218
 
 
219
let rec get_hyp_after h = function
 
220
  | [] -> error_no_such_hypothesis h
 
221
  | (hyp,_,_) :: right ->
 
222
      if hyp = h then
 
223
        match right with (id,_,_)::_ -> MoveBefore id | [] -> MoveToEnd false
 
224
      else
 
225
       get_hyp_after h right
 
226
 
 
227
let split_sign hfrom hto l =
 
228
  let rec splitrec left toleft = function
 
229
    | [] -> error_no_such_hypothesis hfrom
 
230
    | (hyp,c,typ) as d :: right ->
 
231
        if hyp = hfrom then 
 
232
          (left,right,d, toleft or hto = MoveToEnd true)
 
233
        else
 
234
          splitrec (d::left) 
 
235
            (toleft or hto = MoveAfter hyp or hto = MoveBefore hyp)
 
236
            right
 
237
  in 
 
238
    splitrec [] false l
 
239
 
 
240
let hyp_of_move_location = function
 
241
  | MoveAfter id -> id 
 
242
  | MoveBefore id -> id
 
243
  | _ -> assert false
 
244
 
 
245
let move_hyp with_dep toleft (left,(idfrom,_,_ as declfrom),right) hto =
 
246
  let env = Global.env() in
 
247
  let test_dep (hyp,c,typ as d) (hyp2,c,typ2 as d2) =
 
248
    if toleft
 
249
    then occur_var_in_decl env hyp2 d
 
250
    else occur_var_in_decl env hyp d2
 
251
  in
 
252
  let rec moverec first middle = function
 
253
    | [] ->
 
254
        if match hto with MoveToEnd _ -> false | _ -> true then
 
255
          error_no_such_hypothesis (hyp_of_move_location hto);
 
256
        List.rev first @ List.rev middle
 
257
    | (hyp,_,_) :: _ as right when hto = MoveBefore hyp ->
 
258
        List.rev first @ List.rev middle @ right
 
259
    | (hyp,_,_) as d :: right ->
 
260
        let (first',middle') =
 
261
          if List.exists (test_dep d) middle then 
 
262
            if with_dep & hto <> MoveAfter hyp then 
 
263
              (first, d::middle)
 
264
            else 
 
265
              errorlabstrm "" (str "Cannot move " ++ pr_id idfrom ++
 
266
                pr_move_location pr_id hto ++ 
 
267
                str (if toleft then ": it occurs in " else ": it depends on ")
 
268
                ++ pr_id hyp ++ str ".")
 
269
          else
 
270
            (d::first, middle)
 
271
        in
 
272
        if hto = MoveAfter hyp then
 
273
          List.rev first' @ List.rev middle' @ right
 
274
        else 
 
275
          moverec first' middle' right
 
276
  in
 
277
  if toleft then 
 
278
    let right = 
 
279
      List.fold_right push_named_context_val right empty_named_context_val in
 
280
    List.fold_left (fun sign d -> push_named_context_val d sign)
 
281
      right (moverec [] [declfrom] left) 
 
282
  else 
 
283
    let right = 
 
284
      List.fold_right push_named_context_val
 
285
        (moverec [] [declfrom] right) empty_named_context_val in
 
286
    List.fold_left (fun sign d -> push_named_context_val d sign)
 
287
      right left
 
288
 
 
289
let rename_hyp id1 id2 sign =
 
290
  apply_to_hyp_and_dependent_on sign id1
 
291
    (fun (_,b,t) _ -> (id2,b,t))
 
292
    (fun d _ -> map_named_declaration (replace_vars [id1,mkVar id2]) d)
 
293
 
 
294
(************************************************************************)
 
295
(************************************************************************)
 
296
(* Implementation of the logical rules *)
 
297
 
 
298
(* Will only be used on terms given to the Refine rule which have meta 
 
299
variables only in Application and Case *)
 
300
 
 
301
let error_unsupported_deep_meta c =
 
302
  errorlabstrm "" (strbrk "Application of lemmas whose beta-iota normal " ++
 
303
    strbrk "form contains metavariables deep inside the term is not " ++
 
304
    strbrk "supported; try \"refine\" instead.")
 
305
 
 
306
let collect_meta_variables c = 
 
307
  let rec collrec deep acc c = match kind_of_term c with
 
308
    | Meta mv -> if deep then error_unsupported_deep_meta () else mv::acc
 
309
    | Cast(c,_,_) -> collrec deep acc c
 
310
    | (App _| Case _) -> fold_constr (collrec deep) acc c
 
311
    | _ -> fold_constr (collrec true) acc c
 
312
  in
 
313
  List.rev (collrec false [] c)
 
314
 
 
315
let check_meta_variables c = 
 
316
  if not (list_distinct (collect_meta_variables c)) then
 
317
    raise (RefinerError (NonLinearProof c))
 
318
 
 
319
let check_conv_leq_goal env sigma arg ty conclty =
 
320
  if !check & not (is_conv_leq env sigma ty conclty) then 
 
321
    raise (RefinerError (BadType (arg,ty,conclty)))
 
322
 
 
323
let goal_type_of env sigma c =
 
324
  (if !check then type_of else Retyping.get_type_of) env sigma c
 
325
 
 
326
let rec mk_refgoals sigma goal goalacc conclty trm =
 
327
  let env = evar_env goal in
 
328
  let hyps = goal.evar_hyps in
 
329
  let mk_goal hyps concl = mk_goal hyps concl goal.evar_extra in
 
330
(*
 
331
   if  not (occur_meta trm) then
 
332
    let t'ty = (unsafe_machine env sigma trm).uj_type in        
 
333
    let _ = conv_leq_goal env sigma trm t'ty conclty in
 
334
      (goalacc,t'ty)
 
335
  else
 
336
*)
 
337
  match kind_of_term trm with
 
338
    | Meta _ ->
 
339
        let conclty = nf_betaiota sigma conclty in
 
340
          if !check && occur_meta conclty then
 
341
            raise (RefinerError (MetaInType conclty));
 
342
          (mk_goal hyps conclty)::goalacc, conclty
 
343
 
 
344
    | Cast (t,_, ty) ->
 
345
        check_typability env sigma ty;
 
346
        check_conv_leq_goal env sigma trm ty conclty;
 
347
        mk_refgoals sigma goal goalacc ty t
 
348
 
 
349
    | App (f,l) ->
 
350
        let (acc',hdty) =
 
351
          match kind_of_term f with
 
352
            | Ind _ | Const _
 
353
                when (isInd f or has_polymorphic_type (destConst f)) ->
 
354
                (* Sort-polymorphism of definition and inductive types *)
 
355
                goalacc, 
 
356
                type_of_global_reference_knowing_conclusion env sigma f conclty
 
357
            | _ -> 
 
358
                mk_hdgoals sigma goal goalacc f
 
359
        in
 
360
        let (acc'',conclty') =
 
361
          mk_arggoals sigma goal acc' hdty (Array.to_list l) in
 
362
        check_conv_leq_goal env sigma trm conclty' conclty;
 
363
        (acc'',conclty')
 
364
 
 
365
    | Case (_,p,c,lf) ->
 
366
        let (acc',lbrty,conclty') = mk_casegoals sigma goal goalacc p c in
 
367
        check_conv_leq_goal env sigma trm conclty' conclty;
 
368
        let acc'' = 
 
369
          array_fold_left2
 
370
            (fun lacc ty fi -> fst (mk_refgoals sigma goal lacc ty fi))
 
371
            acc' lbrty lf 
 
372
        in
 
373
        (acc'',conclty')
 
374
 
 
375
    | _ -> 
 
376
        if occur_meta trm then
 
377
          anomaly "refiner called with a meta in non app/case subterm";
 
378
 
 
379
        let t'ty = goal_type_of env sigma trm in
 
380
        check_conv_leq_goal env sigma trm t'ty conclty;
 
381
        (goalacc,t'ty)
 
382
 
 
383
(* Same as mkREFGOALS but without knowing te type of the term. Therefore,
 
384
 * Metas should be casted. *)
 
385
 
 
386
and mk_hdgoals sigma goal goalacc trm =
 
387
  let env = evar_env goal in
 
388
  let hyps = goal.evar_hyps in
 
389
  let mk_goal hyps concl = mk_goal hyps concl goal.evar_extra in
 
390
  match kind_of_term trm with
 
391
    | Cast (c,_, ty) when isMeta c ->
 
392
        check_typability env sigma ty;
 
393
        (mk_goal hyps (nf_betaiota sigma ty))::goalacc,ty
 
394
 
 
395
    | Cast (t,_, ty) ->
 
396
        check_typability env sigma ty;
 
397
        mk_refgoals sigma goal goalacc ty t
 
398
 
 
399
    | App (f,l) ->
 
400
        let (acc',hdty) = 
 
401
          if isInd f or isConst f 
 
402
             & not (array_exists occur_meta l) (* we could be finer *)
 
403
          then
 
404
            (goalacc,type_of_global_reference_knowing_parameters env sigma f l)
 
405
          else mk_hdgoals sigma goal goalacc f
 
406
        in
 
407
        mk_arggoals sigma goal acc' hdty (Array.to_list l)
 
408
 
 
409
    | Case (_,p,c,lf) ->
 
410
        let (acc',lbrty,conclty') = mk_casegoals sigma goal goalacc p c in
 
411
        let acc'' = 
 
412
          array_fold_left2
 
413
            (fun lacc ty fi -> fst (mk_refgoals sigma goal lacc ty fi))
 
414
            acc' lbrty lf 
 
415
        in
 
416
        (acc'',conclty')
 
417
 
 
418
    | _ ->
 
419
        if !check && occur_meta trm then
 
420
          anomaly "refined called with a dependent meta";
 
421
        goalacc, goal_type_of env sigma trm
 
422
 
 
423
and mk_arggoals sigma goal goalacc funty = function
 
424
  | [] -> goalacc,funty
 
425
  | harg::tlargs as allargs ->
 
426
      let t = whd_betadeltaiota (evar_env goal) sigma funty in
 
427
      match kind_of_term t with
 
428
        | Prod (_,c1,b) ->
 
429
            let (acc',hargty) = mk_refgoals sigma goal goalacc c1 harg in
 
430
            mk_arggoals sigma goal acc' (subst1 harg b) tlargs
 
431
        | LetIn (_,c1,_,b) ->
 
432
            mk_arggoals sigma goal goalacc (subst1 c1 b) allargs
 
433
        | _ -> raise (RefinerError (CannotApply (t,harg)))
 
434
 
 
435
and mk_casegoals sigma goal goalacc p c =
 
436
  let env = evar_env goal in
 
437
  let (acc',ct) = mk_hdgoals sigma goal goalacc c in 
 
438
  let (acc'',pt) = mk_hdgoals sigma goal acc' p in
 
439
  let pj = {uj_val=p; uj_type=pt} in 
 
440
  let indspec =
 
441
    try find_mrectype env sigma ct
 
442
    with Not_found -> anomaly "mk_casegoals" in
 
443
  let (lbrty,conclty) =
 
444
    type_case_branches_with_names env indspec pj c in
 
445
  (acc'',lbrty,conclty)
 
446
 
 
447
 
 
448
let convert_hyp sign sigma (id,b,bt as d) =
 
449
  let env = Global.env() in
 
450
  let reorder = ref [] in
 
451
  let sign' =
 
452
    apply_to_hyp sign id
 
453
      (fun _ (_,c,ct) _ ->
 
454
        let env = Global.env_of_context sign in
 
455
        if !check && not (is_conv env sigma bt ct) then
 
456
          error ("Incorrect change of the type of "^(string_of_id id)^".");
 
457
        if !check && not (Option.Misc.compare (is_conv env sigma) b c) then
 
458
          error ("Incorrect change of the body of "^(string_of_id id)^".");
 
459
       if !check then reorder := check_decl_position env sign d;
 
460
       d) in
 
461
  reorder_val_context env sign' !reorder
 
462
 
 
463
(* Normalizing evars in a goal. Called by tactic Local_constraints
 
464
   (i.e. when the sigma of the proof tree changes). Detect if the
 
465
   goal is unchanged *)
 
466
let norm_goal sigma gl =
 
467
  let red_fun = Evarutil.nf_evar sigma in
 
468
  let ncl = red_fun gl.evar_concl in
 
469
  let ngl =
 
470
    { gl with 
 
471
        evar_concl = ncl;
 
472
        evar_hyps = map_named_val red_fun gl.evar_hyps } in
 
473
    if Evd.eq_evar_info ngl gl then None else Some ngl
 
474
 
 
475
 
 
476
 
 
477
(************************************************************************)
 
478
(************************************************************************)
 
479
(* Primitive tactics are handled here *)
 
480
 
 
481
let prim_refiner r sigma goal =
 
482
  let env = evar_env goal in
 
483
  let sign = goal.evar_hyps in
 
484
  let cl = goal.evar_concl in
 
485
  let mk_goal hyps concl = mk_goal hyps concl goal.evar_extra in
 
486
  match r with
 
487
    (* Logical rules *)
 
488
    | Intro id ->
 
489
        if !check && mem_named_context id (named_context_of_val sign) then
 
490
          error "New variable is already declared";
 
491
        (match kind_of_term (strip_outer_cast cl) with
 
492
           | Prod (_,c1,b) ->
 
493
               let sg = mk_goal (push_named_context_val (id,None,c1) sign)
 
494
                          (subst1 (mkVar id) b) in
 
495
               ([sg], sigma)
 
496
           | LetIn (_,c1,t1,b) ->
 
497
               let sg =
 
498
                 mk_goal (push_named_context_val (id,Some c1,t1) sign)
 
499
                   (subst1 (mkVar id) b) in
 
500
               ([sg], sigma)
 
501
           | _ ->
 
502
               raise (RefinerError IntroNeedsProduct))
 
503
        
 
504
    | Cut (b,replace,id,t) ->
 
505
        let sg1 = mk_goal sign (nf_betaiota sigma t) in
 
506
        let sign,cl,sigma =
 
507
          if replace then
 
508
            let nexthyp = get_hyp_after id (named_context_of_val sign) in
 
509
            let sign,cl,sigma = clear_hyps sigma [id] sign cl in
 
510
            move_hyp true false ([],(id,None,t),named_context_of_val sign)
 
511
              nexthyp,
 
512
              cl,sigma
 
513
          else
 
514
            (if !check && mem_named_context id (named_context_of_val sign) then
 
515
                error "New variable is already declared";
 
516
             push_named_context_val (id,None,t) sign,cl,sigma) in
 
517
        let sg2 = mk_goal sign cl in
 
518
        if b then ([sg1;sg2],sigma) else ([sg2;sg1],sigma)
 
519
 
 
520
    | FixRule (f,n,rest,j) ->
 
521
        let rec check_ind env k cl = 
 
522
          match kind_of_term (strip_outer_cast cl) with 
 
523
            | Prod (na,c1,b) -> 
 
524
                if k = 1 then 
 
525
                  try 
 
526
                    fst (find_inductive env sigma c1)
 
527
                  with Not_found -> 
 
528
                    error "Cannot do a fixpoint on a non inductive type."
 
529
                else 
 
530
                  check_ind (push_rel (na,None,c1) env) (k-1) b
 
531
            | _ -> error "Not enough products."
 
532
        in
 
533
        let (sp,_) = check_ind env n cl in
 
534
        let firsts,lasts = list_chop j rest in
 
535
        let all = firsts@(f,n,cl)::lasts in
 
536
        let rec mk_sign sign = function 
 
537
          | (f,n,ar)::oth ->
 
538
              let (sp',_)  = check_ind env n ar in 
 
539
              if not (sp=sp') then 
 
540
                error ("Fixpoints should be on the same " ^ 
 
541
                       "mutual inductive declaration.");
 
542
              if !check && mem_named_context f (named_context_of_val sign) then
 
543
                error
 
544
                  ("Name "^string_of_id f^" already used in the environment");
 
545
              mk_sign (push_named_context_val (f,None,ar) sign) oth
 
546
          | [] -> 
 
547
              List.map (fun (_,_,c) -> mk_goal sign c) all
 
548
        in 
 
549
          (mk_sign sign all, sigma)
 
550
        
 
551
    | Cofix (f,others,j) ->
 
552
        let rec check_is_coind env cl = 
 
553
          let b = whd_betadeltaiota env sigma cl in
 
554
          match kind_of_term b with
 
555
            | Prod (na,c1,b) -> check_is_coind (push_rel (na,None,c1) env) b
 
556
            | _ -> 
 
557
                try 
 
558
                  let _ = find_coinductive env sigma b in ()
 
559
                with Not_found -> 
 
560
                  error ("All methods must construct elements " ^
 
561
                          "in coinductive types.")
 
562
        in
 
563
        let firsts,lasts = list_chop j others in
 
564
        let all = firsts@(f,cl)::lasts in
 
565
        List.iter (fun (_,c) -> check_is_coind env c) all;
 
566
        let rec mk_sign sign = function 
 
567
          | (f,ar)::oth ->
 
568
              (try
 
569
                (let _ = lookup_named_val f sign in
 
570
                error "Name already used in the environment.")
 
571
              with
 
572
              | Not_found ->
 
573
                  mk_sign (push_named_context_val (f,None,ar) sign) oth)
 
574
          | [] -> List.map (fun (_,c) -> mk_goal sign c) all
 
575
        in 
 
576
          (mk_sign sign all, sigma)
 
577
 
 
578
    | Refine c ->
 
579
        check_meta_variables c;
 
580
        let (sgl,cl') = mk_refgoals sigma goal [] cl c in
 
581
        let sgl = List.rev sgl in
 
582
          (sgl, sigma)
 
583
 
 
584
    (* Conversion rules *)
 
585
    | Convert_concl (cl',_) ->
 
586
        check_typability env sigma cl';
 
587
        if (not !check) || is_conv_leq env sigma cl' cl then
 
588
          let sg = mk_goal sign cl' in
 
589
          ([sg], sigma)
 
590
        else 
 
591
          error "convert-concl rule passed non-converting term"
 
592
 
 
593
    | Convert_hyp (id,copt,ty) ->
 
594
        ([mk_goal (convert_hyp sign sigma (id,copt,ty)) cl], sigma)
 
595
 
 
596
    (* And now the structural rules *)
 
597
    | Thin ids -> 
 
598
        let (hyps,concl,nsigma) = clear_hyps sigma ids sign cl in
 
599
          ([mk_goal hyps concl], nsigma)
 
600
        
 
601
    | ThinBody ids ->
 
602
        let clear_aux env id =
 
603
          let env' = remove_hyp_body env sigma id in
 
604
            if !check then recheck_typability (None,id) env' sigma cl;
 
605
            env'
 
606
        in
 
607
        let sign' = named_context_val (List.fold_left clear_aux env ids) in
 
608
        let sg = mk_goal sign' cl in
 
609
          ([sg], sigma)
 
610
 
 
611
    | Move (withdep, hfrom, hto) ->
 
612
        let (left,right,declfrom,toleft) = 
 
613
          split_sign hfrom hto (named_context_of_val sign) in
 
614
        let hyps' = 
 
615
          move_hyp withdep toleft (left,declfrom,right) hto in
 
616
          ([mk_goal hyps' cl], sigma)
 
617
 
 
618
    | Order ord ->
 
619
        let hyps' = reorder_val_context env sign ord in
 
620
        ([mk_goal hyps' cl], sigma)
 
621
 
 
622
    | Rename (id1,id2) ->
 
623
        if !check & id1 <> id2 &&
 
624
          List.mem id2 (ids_of_named_context (named_context_of_val sign)) then
 
625
          error ((string_of_id id2)^" is already used.");
 
626
        let sign' = rename_hyp id1 id2 sign in
 
627
        let cl' = replace_vars [id1,mkVar id2] cl in
 
628
          ([mk_goal sign' cl'], sigma)
 
629
 
 
630
    | Change_evars ->
 
631
        match norm_goal sigma goal with
 
632
            Some ngl -> ([ngl],sigma)
 
633
          | None -> ([goal], sigma)
 
634
 
 
635
(************************************************************************)
 
636
(************************************************************************)
 
637
(* Extracting a proof term from the proof tree *)
 
638
 
 
639
(* Util *)
 
640
 
 
641
type variable_proof_status = ProofVar | SectionVar of identifier
 
642
 
 
643
type proof_variable = name * variable_proof_status
 
644
 
 
645
let subst_proof_vars = 
 
646
  let rec aux p vars =
 
647
    let _,subst =
 
648
      List.fold_left (fun (n,l) var ->
 
649
        let t = match var with
 
650
          | Anonymous,_ -> l
 
651
          | Name id, ProofVar -> (id,mkRel n)::l
 
652
          | Name id, SectionVar id' -> (id,mkVar id')::l in
 
653
        (n+1,t)) (p,[]) vars
 
654
    in replace_vars (List.rev subst)
 
655
  in aux 1
 
656
         
 
657
let rec rebind id1 id2 = function
 
658
  | [] -> [Name id2,SectionVar id1]
 
659
  | (na,k as x)::l -> 
 
660
      if na = Name id1 then (Name id2,k)::l else
 
661
        let l' = rebind id1 id2 l in
 
662
        if na = Name id2 then (Anonymous,k)::l' else x::l'
 
663
 
 
664
let add_proof_var id vl = (Name id,ProofVar)::vl
 
665
 
 
666
let proof_variable_index x = 
 
667
  let rec aux n = function
 
668
    | (Name id,ProofVar)::l when x = id -> n
 
669
    | _::l ->  aux (n+1) l
 
670
    | [] -> raise Not_found
 
671
  in 
 
672
  aux 1
 
673
 
 
674
let prim_extractor subfun vl pft =
 
675
  let cl = pft.goal.evar_concl in
 
676
    match pft.ref with
 
677
      | Some (Prim (Intro id), [spf]) ->
 
678
          (match kind_of_term (strip_outer_cast cl) with
 
679
            | Prod (_,ty,_) ->
 
680
                let cty = subst_proof_vars vl ty in
 
681
                  mkLambda (Name id, cty, subfun (add_proof_var id vl) spf)
 
682
            | LetIn (_,b,ty,_) ->
 
683
                let cb = subst_proof_vars vl b in
 
684
                let cty = subst_proof_vars vl ty in
 
685
                  mkLetIn (Name id, cb, cty, subfun (add_proof_var id vl) spf)
 
686
            | _ -> error "Incomplete proof!")
 
687
            
 
688
      | Some (Prim (Cut (b,_,id,t)),[spf1;spf2]) ->
 
689
          let spf1, spf2 = if b then spf1, spf2 else spf2, spf1 in
 
690
            mkLetIn (Name id,subfun vl spf1,subst_proof_vars vl t,
 
691
                    subfun (add_proof_var id vl) spf2)
 
692
 
 
693
      | Some (Prim (FixRule (f,n,others,j)),spfl) ->
 
694
          let firsts,lasts = list_chop j others in
 
695
          let all = Array.of_list (firsts@(f,n,cl)::lasts) in
 
696
          let lcty = Array.map (fun (_,_,ar) -> subst_proof_vars vl ar) all in
 
697
          let names = Array.map (fun (f,_,_) -> Name f) all in
 
698
          let vn = Array.map (fun (_,n,_) -> n-1) all in
 
699
          let newvl = List.fold_left (fun vl (id,_,_) -> add_proof_var id vl)
 
700
            (add_proof_var f vl) others in
 
701
          let lfix = Array.map (subfun newvl) (Array.of_list spfl) in
 
702
            mkFix ((vn,j),(names,lcty,lfix))    
 
703
 
 
704
      | Some (Prim (Cofix (f,others,j)),spfl) ->
 
705
          let firsts,lasts = list_chop j others in
 
706
          let all = Array.of_list (firsts@(f,cl)::lasts) in
 
707
          let lcty = Array.map (fun (_,ar) -> subst_proof_vars vl ar) all in
 
708
          let names  = Array.map (fun (f,_) -> Name f) all in
 
709
          let newvl = List.fold_left (fun vl (id,_)-> add_proof_var id vl)
 
710
            (add_proof_var f vl) others in 
 
711
          let lfix = Array.map (subfun newvl) (Array.of_list spfl) in
 
712
            mkCoFix (j,(names,lcty,lfix))
 
713
              
 
714
      | Some (Prim (Refine c),spfl) ->
 
715
          let mvl = collect_meta_variables c in
 
716
          let metamap = List.combine mvl (List.map (subfun vl) spfl) in
 
717
          let cc = subst_proof_vars vl c in 
 
718
            plain_instance metamap cc
 
719
 
 
720
      (* Structural and conversion rules do not produce any proof *)
 
721
      | Some (Prim (Convert_concl (t,k)),[pf]) ->
 
722
          if k = DEFAULTcast then subfun vl pf
 
723
          else mkCast (subfun vl pf,k,subst_proof_vars vl cl)
 
724
      | Some (Prim (Convert_hyp _),[pf]) ->
 
725
          subfun vl pf
 
726
 
 
727
      | Some (Prim (Thin _),[pf]) ->
 
728
          (* No need to make ids Anon in vl: subst_proof_vars take the most recent*)
 
729
          subfun vl pf
 
730
            
 
731
      | Some (Prim (ThinBody _),[pf]) ->
 
732
          subfun vl pf
 
733
            
 
734
      | Some (Prim (Move _|Order _),[pf]) ->
 
735
          subfun vl pf
 
736
 
 
737
      | Some (Prim (Rename (id1,id2)),[pf]) ->
 
738
          subfun (rebind id1 id2 vl) pf
 
739
 
 
740
      | Some (Prim Change_evars, [pf]) ->
 
741
          subfun vl pf
 
742
 
 
743
      | Some _ -> anomaly "prim_extractor"
 
744
 
 
745
      | None-> error "prim_extractor handed incomplete proof"
 
746