1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
|
(************************************************************************)
(* * The Rocq Prover / The Rocq Development Team *)
(* v * Copyright INRIA, CNRS and contributors *)
(* <O___,, * (see version control and CREDITS file for authors & dates) *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(* * (see LICENSE file for the text of the license) *)
(************************************************************************)
open Rocqlib
open CErrors
open Util
open Termops
open EConstr
open Retyping
open Typing
open Inductiveops
module RelDecl = Context.Rel.Declaration
(**************)
(** Telescope *)
let get_sigmatypes sigma ~sort ~predsort =
let open EConstr in
let open Sorts.Quality in
let which, sigsort = match predsort, sort with
| QConstant QSProp, _ | _, QConstant QSProp ->
user_err Pp.(str "SProp arguments not supported by Program Fixpoint yet.")
| QConstant QProp, QConstant QProp -> "ex", qprop
| QConstant QProp, QConstant QType -> "sig", qtype
| QConstant QType, QConstant (QProp|QType) -> "sigT", qtype
| _ -> assert false
in
let sigma, ty = Evd.fresh_global (Global.env ()) sigma (lib_ref ("core."^which^".type")) in
let uinstance = snd (destRef sigma ty) in
let intro = mkRef (lib_ref ("core."^which^".intro"), uinstance) in
let p1 = mkRef (lib_ref ("core."^which^".proj1"), uinstance) in
let p2 = mkRef (lib_ref ("core."^which^".proj2"), uinstance) in
sigma, ty, intro, p1, p2, sigsort
let rec telescope sigma l =
let open EConstr in
let open Vars in
match l with
| [] -> assert false
| [RelDecl.LocalAssum (n, t), _] ->
sigma, t, [RelDecl.LocalDef (n, mkRel 1, t)], mkRel 1
| (LocalAssum (n, t), tsort) :: tl ->
let sigma, ty, _tysort, tys, (k, constr) =
List.fold_left
(fun (sigma, ty, tysort, tys, (k, constr)) (decl,sort) ->
let t = RelDecl.get_type decl in
let pred = mkLambda (RelDecl.get_annot decl, t, ty) in
let sigma, ty, intro, p1, p2, sigsort = get_sigmatypes sigma ~predsort:tysort ~sort in
let sigty = mkApp (ty, [|t; pred|]) in
let intro = mkApp (intro, [|lift k t; lift k pred; mkRel k; constr|]) in
(sigma, sigty, sigsort, (pred, p1, p2) :: tys, (succ k, intro)))
(sigma, t, tsort, [], (2, mkRel 1)) tl
in
let sigma, last, subst = List.fold_right2
(fun (pred,p1,p2) (decl,_) (sigma, prev, subst) ->
let t = RelDecl.get_type decl in
let proj1 = applist (p1, [t; pred; prev]) in
let proj2 = applist (p2, [t; pred; prev]) in
(sigma, lift 1 proj2, RelDecl.(LocalDef (get_annot decl, proj1, t) :: subst)))
(List.rev tys) tl (sigma, mkRel 1, [])
in sigma, ty, (LocalDef (n, last, t) :: subst), constr
| (LocalDef (n, b, t), _) :: tl ->
let sigma, ty, subst, term = telescope sigma tl in
sigma, ty, (LocalDef (n, b, t) :: subst), lift 1 term
type telescope = {
telescope_type : EConstr.types;
telescope_value : EConstr.constr;
}
let telescope env sigma ctx =
let ctx, _ = List.fold_right_map (fun d env ->
let s = Retyping.get_sort_quality_of env sigma (RelDecl.get_type d) in
let env = EConstr.push_rel d env in
(d, UnivGen.QualityOrSet.quality s), env) ctx env
in
let sigma, telescope_type, letcontext, telescope_value = telescope sigma ctx in
sigma, letcontext, { telescope_type; telescope_value }
(****************************************************)
(** Closure of a term according to its dependencies *)
(* [make_tuple env sigma (rterm,rty) lind] assumes [lind] is the lesser
index bound in [rty]
Then it builds the term
[(existT A P (mkRel lind) rterm)] of type [(sigT A P)]
where [A] is the type of [mkRel lind] and [P] is [fun na:A => rty{1/lind}]
*)
let make_tuple env sigma (rterm,rty) lind =
assert (not (Vars.noccurn sigma lind rty));
let sigdata = build_sigma_type () in
let sigma, a = type_of ~refresh:true env sigma (mkRel lind) in
let a = Tacred.simpl env sigma a in
let na = Context.Rel.Declaration.get_annot (lookup_rel lind env) in
(* We move [lind] to [1] and lift other rels > [lind] by 1 *)
let rty = Vars.lift (1-lind) (Vars.liftn lind (lind+1) rty) in
(* Now [lind] is [mkRel 1] and we abstract on (na:a) *)
let p = mkLambda (na, a, rty) in
let sigma, exist_term = Evd.fresh_global env sigma sigdata.intro in
let sigma, sig_term = Evd.fresh_global env sigma sigdata.typ in
sigma,
(applist(exist_term,[a;p;(mkRel lind);rterm]),
applist(sig_term,[a;p]))
(* check that the free-references of the type of [c] are contained in
the free-references of the normal-form of that type. Strictly
computing the exact set of free rels would require full
normalization but this is not reasonable (e.g. in presence of
records that contains proofs). We restrict ourself to a "simpl"
normalization *)
let minimal_free_rels env sigma (c,cty) =
let cty_rels = free_rels sigma cty in
let cty' = Tacred.simpl env sigma cty in
let rels' = free_rels sigma cty' in
if Int.Set.subset cty_rels rels' then
(cty,cty_rels)
else
(cty',rels')
(* Like the above, but recurse over all the rels found until there are
no more rels to be found *)
let minimal_free_rels_rec env sigma =
let rec minimalrec_free_rels_rec prev_rels (c,cty) =
let (cty,direct_rels) = minimal_free_rels env sigma (c,cty) in
let combined_rels = Int.Set.union prev_rels direct_rels in
let folder rels i = snd (minimalrec_free_rels_rec rels (c, get_type_of env sigma (mkRel i)))
in (cty, List.fold_left folder combined_rels (Int.Set.elements (Int.Set.diff direct_rels prev_rels)))
in minimalrec_free_rels_rec Int.Set.empty
(** [sig_clausal_form siglen ty]
Will explode [siglen] [sigT ]'s on [ty] (depending on the
type of ty), and return:
(1) a pattern, with meta-variables in it for various arguments,
which, when the metavariables are replaced with appropriate
terms, will have type [ty]
(2) an integer, which is the last argument - the one which we just
returned.
(3) a pattern, for the type of that last meta
(4) a typing for each patvar
WARNING: No checking is done to make sure that the
sigT's are actually there.
- Only homogeneous pairs are built i.e. pairs where all the
dependencies are of the same sort
[sig_clausal_form] proceeds as follows: the default tuple is
constructed by taking the tuple-type, exploding the first [tuplen]
[sigT]'s, and replacing at each step the binder in the
right-hand-type by a fresh metavariable. In addition, on the way
back out, we will construct the pattern for the tuple which uses
these meta-vars.
This gives us a pattern, which we use to match against the type of
[dflt]; if that fails, then against the S(TRONG)NF of that type. If
both fail, then we just cannot construct our tuple. If one of
those succeed, then we can construct our value easily - we just use
the tuple-pattern.
*)
let sig_clausal_form env sigma sort_of_ty siglen ty dflt =
let sigdata = build_sigma_type () in
let rec sigrec_clausal_form sigma siglen p_i =
if Int.equal siglen 0 then
(* is the default value typable with the expected type *)
let dflt_typ = Retyping.get_type_of env sigma dflt in
try
let sigma = Evarconv.unify_leq_delay env sigma dflt_typ p_i in
let sigma = Evarconv.solve_unif_constraints_with_heuristics env sigma in
sigma, dflt
with Evarconv.UnableToUnify _ ->
user_err Pp.(str "Cannot solve a unification problem.")
else
let (a,p_i_minus_1) = match Reductionops.whd_beta_stack env sigma p_i with
| (_sigT,[a;p]) -> (a, p)
| _ -> anomaly ~label:"sig_clausal_form" (Pp.str "should be a sigma type.") in
let typeclass_candidate = Typeclasses.is_maybe_class_type sigma a in
let sigma, ev = Evarutil.new_evar ~typeclass_candidate env sigma a in
let rty = Reductionops.beta_applist sigma (p_i_minus_1,[ev]) in
let sigma, tuple_tail = sigrec_clausal_form sigma (siglen-1) rty in
if EConstr.isEvar sigma ev then
(* This at least happens if what has been detected as a
dependency is not one; use an evasive error message;
even if the problem is upwards: unification should be
tried in the first place in make_iterated_tuple instead
of approximatively computing the free rels; then
unsolved evars would mean not binding rel *)
user_err Pp.(str "Cannot solve a unification problem.")
else
let sigma, exist_term = Evd.fresh_global env sigma sigdata.intro in
sigma, applist(exist_term,[a;p_i_minus_1;ev;tuple_tail])
in
let sigma, scf = sigrec_clausal_form sigma siglen ty in
sigma, Evarutil.nf_evar sigma scf
(** [make_iterated_tuple env sigma default c ctype] retruns
To do this, we find the free (relative) references of the strong NF
of [c]'s type, gather them together in left-to-right order
(i.e. highest-numbered is farthest-left), and construct a big
iterated pair out of it. This only works when the references are
all themselves to members of [Set]s, because we use [sigT] to
construct the tuple.
Suppose now that our constructed tuple is of length [tuplen]. We
need also to construct a default value for the other branches of
the destructor. As default value, we take a tuple of the form
[existT [xn]Pn ?n (... existT [x2]P2 ?2 (existT [x1]P1 ?1 term))]
but for this we have to solve the following unification problem:
typ = cty[i1/?1;...;in/?n]
This is done by [sig_clausal_form].
*)
let make_iterated_tuple env sigma ~default c cty =
let (cty,rels) = minimal_free_rels_rec env sigma (c,cty) in
let sort_of_cty = get_sort_of env sigma cty in
let sorted_rels = Int.Set.elements rels in
let sigma, (telescope_value, telescope_type) =
List.fold_left (fun (sigma, t) -> make_tuple env sigma t) (sigma, (c,cty)) sorted_rels
in
assert (Vars.closed0 sigma telescope_type);
let n = List.length sorted_rels in
let sigma, dfltval = sig_clausal_form env sigma sort_of_cty n telescope_type default in
sigma, { telescope_value; telescope_type }, dfltval
(** [make_selector env sigma dirn c ind special default]]
constructs a case-split on [c] of type [ind], with the [dirn]-th
branch giving [special], and all the rest giving [default]. *)
let make_selector env sigma ~pos ~special ~default c ctype =
let IndType(indf,_) as indt =
try find_rectype env sigma ctype
with Not_found ->
(* one can find Rel(k) in case of dependent constructors
like T := c : (A:Set)A->T and a discrimination
on (c bool true) = (c bool false)
CP : changed assert false in a more informative error
*)
user_err
Pp.(str "Cannot discriminate on inductive constructors with \
dependent types.") in
let (ind, _),_ = dest_ind_family indf in
let () = Tacred.check_privacy env ind in
let typ = Retyping.get_type_of env sigma default in
let (mib,mip) = Inductive.lookup_mind_specif env ind in
let deparsign = make_arity_signature env sigma true indf in
let p = it_mkLambda_or_LetIn typ deparsign in
let cstrs = get_constructors env indf in
let build_branch i =
let endpt = if Int.equal i pos then special else default in
let args = cstrs.(i-1).cs_args in
it_mkLambda_or_LetIn endpt args in
let brl =
List.map build_branch(List.interval 1 (Array.length mip.mind_consnames)) in
let rci = ERelevance.relevant in (* TODO relevance *)
let ci = make_case_info env ind RegularStyle in
Inductiveops.make_case_or_project env sigma indt ci (p, rci) c (Array.of_list brl)
|