aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pretyping/clenv.ml34
-rw-r--r--pretyping/evd.ml14
-rw-r--r--pretyping/evd.mli12
-rw-r--r--pretyping/reductionops.ml22
-rw-r--r--pretyping/unification.ml123
-rw-r--r--pretyping/unification.mli2
-rw-r--r--tactics/decl_proof_instr.ml6
-rw-r--r--test-suite/success/apply.v51
-rw-r--r--toplevel/cerrors.ml10
9 files changed, 169 insertions, 105 deletions
diff --git a/pretyping/clenv.ml b/pretyping/clenv.ml
index edf905641..5f4293abf 100644
--- a/pretyping/clenv.ml
+++ b/pretyping/clenv.ml
@@ -196,7 +196,9 @@ let clenv_assign mv rhs clenv =
error_incompatible_inst clenv mv
else
clenv
- else {clenv with evd = meta_assign mv (rhs_fls.rebus,ConvUpToEta 0) clenv.evd}
+ else
+ let st = (ConvUpToEta 0,TypeNotProcessed) in
+ {clenv with evd = meta_assign mv (rhs_fls.rebus,st) clenv.evd}
with Not_found ->
error "clenv_assign: undefined meta"
@@ -241,25 +243,7 @@ let clenv_unify allow_K cv_pb t1 t2 clenv =
{ clenv with evd = w_unify allow_K clenv.env cv_pb t1 t2 clenv.evd }
let clenv_unify_meta_types clenv =
- List.fold_left (fun clenv (k,m) ->
- match m with
- | Cltyp _ -> clenv
- | Clval (na,(c,s),k_typ) ->
- let k_typ = clenv_hnf_constr clenv k_typ.rebus in
- match s with
- | Coercible c_typ when not (occur_meta k_typ) ->
- let evd,c' = w_coerce (cl_env clenv) c.rebus c_typ k_typ clenv.evd in
- {clenv with evd = meta_reassign k (c',ConvUpToEta 0) clenv.evd}
- | _ ->
- (* nf_betaiota was before in type_of - useful to reduce
- types like (x:A)([x]P u) *)
- let c_typ = nf_betaiota (clenv_get_type_of clenv c.rebus) in
- let c_typ = clenv_hnf_constr clenv c_typ in
- (* Try to infer some Meta/Evar from the type of [c] *)
- try clenv_unify true CUMUL c_typ k_typ clenv
- with e when precatchable_exception e -> clenv)
- clenv (meta_list clenv.evd)
-
+ { clenv with evd = w_unify_meta_types clenv.env clenv.evd }
let clenv_unique_resolver allow_K clenv gl =
if isMeta (fst (whd_stack clenv.templtyp.rebus)) then
@@ -398,13 +382,13 @@ let rec similar_type_shapes t u =
let clenv_unify_similar_types clenv c t u =
if occur_meta u then
if similar_type_shapes t u then
- try Processed, clenv_unify true CUMUL t u clenv, c
- with e when precatchable_exception e -> Coercible t, clenv, c
+ try TypeProcessed, clenv_unify true CUMUL t u clenv, c
+ with e when precatchable_exception e -> TypeNotProcessed, clenv, c
else
- Coercible t, clenv, c
+ TypeNotProcessed, clenv, c
else
let evd,c = w_coerce (cl_env clenv) c t u clenv.evd in
- Processed, { clenv with evd = evd }, c
+ TypeProcessed, { clenv with evd = evd }, c
let clenv_assign_binding clenv k (sigma,c) =
let k_typ = clenv_hnf_constr clenv (clenv_meta_type clenv k) in
@@ -413,7 +397,7 @@ let clenv_assign_binding clenv k (sigma,c) =
let c_typ = clenv_hnf_constr clenv' c_typ in
let status,clenv'',c = clenv_unify_similar_types clenv' c c_typ k_typ in
(* let evd,c' = w_coerce (cl_env clenv') c c_typ k_typ clenv'.evd in*)
- { clenv'' with evd = meta_assign k (c,status) clenv''.evd }
+ { clenv'' with evd = meta_assign k (c,(UserGiven,status)) clenv''.evd }
let clenv_match_args bl clenv =
if bl = [] then
diff --git a/pretyping/evd.ml b/pretyping/evd.ml
index 7b5690e2c..439f46264 100644
--- a/pretyping/evd.ml
+++ b/pretyping/evd.ml
@@ -334,9 +334,13 @@ let map_fl f cfl = { cfl with rebus=f cfl.rebus }
(e.g. the solution [P] to [?X u v = P u v] can be eta-expanded twice)
*)
-type instance_status =
- | IsSuperType | IsSubType
- | ConvUpToEta of int | Coercible of types | Processed
+type instance_constraint =
+ IsSuperType | IsSubType | ConvUpToEta of int | UserGiven
+
+type instance_typing_status =
+ TypeNotProcessed | TypeProcessed
+
+type instance_status = instance_constraint * instance_typing_status
(* Clausal environments *)
@@ -543,7 +547,7 @@ let retract_coercible_metas evd =
let mc,ml =
Metamap.fold (fun n v (mc,ml) ->
match v with
- | Clval (na,(b,s),typ) when s <> Processed ->
+ | Clval (na,(b,(UserGiven,TypeNotProcessed as s)),typ) ->
(n,b.rebus,s)::mc, Metamap.add n (Cltyp (na,typ)) ml
| v ->
mc, Metamap.add n v ml)
@@ -556,7 +560,7 @@ let rec list_assoc_in_triple x = function
let subst_defined_metas bl c =
let rec substrec c = match kind_of_term c with
- | Meta i -> list_assoc_in_triple i bl
+ | Meta i -> substrec (list_assoc_in_triple i bl)
| _ -> map_constr substrec c
in try Some (substrec c) with Not_found -> None
diff --git a/pretyping/evd.mli b/pretyping/evd.mli
index b6ffd02c1..4375f5471 100644
--- a/pretyping/evd.mli
+++ b/pretyping/evd.mli
@@ -104,16 +104,20 @@ val metavars_of : constr -> Metaset.t
val mk_freelisted : constr -> constr freelisted
val map_fl : ('a -> 'b) -> 'a freelisted -> 'b freelisted
-(* Status of an instance wrt to the meta it solves:
+(* Possible constraints over the instance of a metavariable:
- a supertype of the meta (e.g. the solution to ?X <= T is a supertype of ?X)
- a subtype of the meta (e.g. the solution to T <= ?X is a supertype of ?X)
- a term that can be eta-expanded n times while still being a solution
(e.g. the solution [P] to [?X u v = P u v] can be eta-expanded twice)
*)
-type instance_status =
- | IsSuperType | IsSubType
- | ConvUpToEta of int | Coercible of types | Processed
+type instance_constraint =
+ IsSuperType | IsSubType | ConvUpToEta of int | UserGiven
+
+type instance_typing_status =
+ TypeNotProcessed | TypeProcessed
+
+type instance_status = instance_constraint * instance_typing_status
type clbinding =
| Cltyp of name * constr freelisted
diff --git a/pretyping/reductionops.ml b/pretyping/reductionops.ml
index 7f05b1cbf..f247f47b6 100644
--- a/pretyping/reductionops.ml
+++ b/pretyping/reductionops.ml
@@ -896,8 +896,8 @@ let meta_value evd mv =
let meta_reducible_instance evd b =
let fm = Metaset.elements b.freemetas in
- let s = List.fold_left (fun l mv ->
- try let g,s = meta_fvalue evd mv in (mv,(g.rebus,s))::l
+ let metas = List.fold_left (fun l mv ->
+ try let g,(_,s) = meta_fvalue evd mv in (mv,(g.rebus,s))::l
with Anomaly _ | Not_found -> l) [] fm in
let rec irec u =
let u = whd_betaiota u in
@@ -906,8 +906,8 @@ let meta_reducible_instance evd b =
let m = try destMeta c with _ -> destMeta (pi1 (destCast c)) in
(match
try
- let g,s = List.assoc m s in
- if isConstruct g or s = Processed then Some g else None
+ let g,s = List.assoc m metas in
+ if isConstruct g or s = TypeProcessed then Some g else None
with Not_found -> None
with
| Some g -> irec (mkCase (ci,p,g,bl))
@@ -916,15 +916,15 @@ let meta_reducible_instance evd b =
let m = try destMeta f with _ -> destMeta (pi1 (destCast f)) in
(match
try
- let g,s = List.assoc m s in
- if isLambda g or s = Processed then Some g else None
+ let g,s = List.assoc m metas in
+ if isLambda g or s = TypeProcessed then Some g else None
with Not_found -> None
- with
- | Some g -> irec (mkApp (g,l))
- | None -> mkApp (f,Array.map irec l))
+ with
+ | Some g -> irec (mkApp (g,l))
+ | None -> mkApp (f,Array.map irec l))
| Meta m ->
- (try let g,s = List.assoc m s in if s = Processed then irec g else u
- with Not_found -> u)
+ (try let g,s = List.assoc m metas in if s=TypeProcessed then irec g else u
+ with Not_found -> u)
| _ -> map_constr irec u
in
if fm = [] then (* nf_betaiota? *) b.rebus else irec b.rebus
diff --git a/pretyping/unification.ml b/pretyping/unification.ml
index 372188e8a..4116445e1 100644
--- a/pretyping/unification.ml
+++ b/pretyping/unification.ml
@@ -65,11 +65,13 @@ let prod_pb = function ConvUnderApp _ -> topconv | pb -> pb
let opp_status = function
| IsSuperType -> IsSubType
| IsSubType -> IsSuperType
- | ConvUpToEta _ | Coercible _ | Processed as x -> x
+ | ConvUpToEta _ | UserGiven as x -> x
+
+let add_type_status (x,y) = ((x,TypeNotProcessed),(y,TypeNotProcessed))
let extract_instance_status = function
- | Cumul -> (IsSubType,IsSuperType)
- | ConvUnderApp (n1,n2) -> ConvUpToEta n1, ConvUpToEta n2
+ | Cumul -> add_type_status (IsSubType, IsSuperType)
+ | ConvUnderApp (n1,n2) -> add_type_status (ConvUpToEta n1, ConvUpToEta n2)
let rec assoc_pair x = function
[] -> raise Not_found
@@ -83,7 +85,7 @@ let rec subst_meta_instances bl c =
let solve_pattern_eqn_array env f l c (metasubst,evarsubst) =
match kind_of_term f with
| Meta k ->
- let pb = ConvUpToEta (Array.length l) in
+ let pb = (ConvUpToEta (Array.length l),TypeNotProcessed) in
(k,solve_pattern_eqn env (Array.to_list l) c,pb)::metasubst,evarsubst
| Evar ev ->
(* Currently unused: incompatible with eauto/eassumption backtracking *)
@@ -183,9 +185,9 @@ let unify_0_with_initial_metas metas env sigma cv_pb mod_delta m n =
(if mod_delta then is_fconv (conv_pb_of cv_pb) env sigma m n
else eq_constr m n)
then
- ([],[])
+ (metas,[])
else
- let (mc,ec) = unirec_rec env cv_pb ([],[]) m n in
+ let (mc,ec) = unirec_rec env cv_pb (metas,[]) m n in
((*sort_eqns*) mc, (*sort_eqns*) ec)
let unify_0 = unify_0_with_initial_metas []
@@ -228,19 +230,25 @@ let rec unify_with_eta keptside mod_delta env sigma k1 k2 c1 c2 =
let merge_instances env sigma mod_delta st1 st2 c1 c2 =
match (opp_status st1, st2) with
+ | (UserGiven, ConvUpToEta n2) ->
+ unify_with_eta left mod_delta env sigma 0 n2 c1 c2
+ | (ConvUpToEta n1, UserGiven) ->
+ unify_with_eta right mod_delta env sigma n1 0 c1 c2
| (ConvUpToEta n1, ConvUpToEta n2) ->
let side = left (* arbitrary choice, but agrees with compatibility *) in
unify_with_eta side mod_delta env sigma n1 n2 c1 c2
- | ((IsSubType | ConvUpToEta _ | Coercible _ | Processed as oppst1),
- (IsSubType | ConvUpToEta _ | Coercible _ | Processed)) ->
+ | ((IsSubType | ConvUpToEta _ | UserGiven as oppst1),
+ (IsSubType | ConvUpToEta _ | UserGiven)) ->
let res = unify_0 env sigma Cumul mod_delta c2 c1 in
if oppst1=st2 then (* arbitrary choice *) (left, st1, res)
- else (st2=IsSubType, ConvUpToEta 0, res)
- | ((IsSuperType | ConvUpToEta _ | Coercible _ | Processed as oppst1),
- (IsSuperType | ConvUpToEta _ | Coercible _ | Processed)) ->
+ else if st2=IsSubType or st1=UserGiven then (left, st1, res)
+ else (right, st2, res)
+ | ((IsSuperType | ConvUpToEta _ | UserGiven as oppst1),
+ (IsSuperType | ConvUpToEta _ | UserGiven)) ->
let res = unify_0 env sigma Cumul mod_delta c1 c2 in
if oppst1=st2 then (* arbitrary choice *) (left, st1, res)
- else (st2=IsSuperType, ConvUpToEta 0, res)
+ else if st2=IsSuperType or st1=UserGiven then (left, st1, res)
+ else (right, st2, res)
| (IsSuperType,IsSubType) ->
(try (left, IsSubType, unify_0 env sigma Cumul mod_delta c2 c1)
with _ -> (right, IsSubType, unify_0 env sigma Cumul mod_delta c1 c2))
@@ -323,7 +331,25 @@ let w_coerce env c ctyp target evd =
(evd',j'.uj_val)
with e when precatchable_exception e ->
evd,c
-
+
+let unify_0_meta_type env evd mod_delta mv c =
+ let sigma = evars_of evd in
+ let metamap = metas_of evd in
+ let mvty = Typing.meta_type evd mv in
+ let mvty = Tacred.hnf_constr env sigma mvty in
+ (* nf_betaiota was before in type_of - useful to reduce
+ types like (x:A)([x]P u) *)
+ let c = refresh_universes c in
+ let nty = get_type_of_with_meta env sigma metamap c in
+ let nty = Tacred.hnf_constr env sigma (nf_betaiota nty) in
+ if occur_meta mvty then
+ try (evd,c),(unify_0 env sigma Cumul mod_delta nty mvty)
+ with e when precatchable_exception e -> (evd,c),([],[])
+ else
+ (* Try to coerce to the type of [k]; cannot merge with the
+ previous case because Coercion does not handle Meta *)
+ w_coerce env c nty mvty evd,([],[])
+
(* [w_merge env sigma b metas evars] merges common instances in metas
or in evars, possibly generating new unification problems; if [b]
is true, unification of types of metas is required *)
@@ -335,17 +361,19 @@ let w_merge env with_types mod_delta metas evars evd =
match (evars,metas) with
| [], [] -> evd
- | ((evn,_ as ev),rhs)::t, metas ->
+ | ((evn,_ as ev),rhs)::evars', metas ->
(match kind_of_term rhs with
- | Meta k -> w_merge_rec evd ((k,mkEvar ev,ConvUpToEta 0)::metas) t
+ | Meta k ->
+ w_merge_rec evd ((k,mkEvar ev,(ConvUpToEta 0,TypeNotProcessed))::metas)
+ evars
| krhs ->
if is_defined_evar evd ev then
let v = Evd.existential_value (evars_of evd) ev in
- let (metas',evars') =
+ let (metas',evars'') =
unify_0 env (evars_of evd) topconv mod_delta rhs v in
- w_merge_rec evd (metas'@metas) (evars'@t)
+ w_merge_rec evd (metas'@metas) (evars''@evars')
else begin
let rhs' =
if occur_meta rhs then subst_meta_instances metas rhs
@@ -356,56 +384,41 @@ let w_merge env with_types mod_delta metas evars evd =
match krhs with
| App (f,cl) when is_mimick_head f ->
(try
- w_merge_rec (fst (evar_define env ev rhs' evd)) metas t
+ w_merge_rec (fst (evar_define env ev rhs' evd))
+ metas evars'
with ex when precatchable_exception ex ->
let evd' =
mimick_evar evd mod_delta f (Array.length cl) evn in
w_merge_rec evd' metas evars)
| _ ->
(* ensure tail recursion in non-mimickable case! *)
- w_merge_rec (fst (evar_define env ev rhs' evd)) metas t
+ w_merge_rec (fst (evar_define env ev rhs' evd))
+ metas evars'
end)
- | ([], (mv,n,status)::t) ->
+ | ([], (mv,n,(status,to_type))::metas) ->
+ let evd,n =
+ if with_types & to_type = TypeNotProcessed then
+ let evd_n,(mc,ec) = unify_0_meta_type env evd mod_delta mv n in
+ ty_metas := mc @ !ty_metas;
+ ty_evars := ec @ !ty_evars;
+ evd_n
+ else
+ evd,n in
if meta_defined evd mv then
- let n',status' = meta_fvalue evd mv in
+ let n',(status',_) = meta_fvalue evd mv in
let n' = n'.rebus in
let (take_left,st,(metas',evars')) =
merge_instances env (evars_of evd) mod_delta status' status n' n
in
- let evd' = if take_left then evd else meta_reassign mv (n,st) evd
+ let evd' =
+ if take_left then evd
+ else meta_reassign mv (n,(st,TypeProcessed)) evd
in
- w_merge_rec evd' (metas'@t) evars'
+ w_merge_rec evd' (metas'@metas) evars'
else
- begin
- let evd,n =
- if with_types & status <> Processed then
- let sigma = evars_of evd in
- let metas = metas_of evd in
- let mvty = Typing.meta_type evd mv in
- let mvty = Tacred.hnf_constr env sigma mvty in
- (* nf_betaiota was before in type_of - useful to reduce
- types like (x:A)([x]P u) *)
- let n = refresh_universes n in
- let nty = get_type_of_with_meta env sigma metas n in
- let nty = Tacred.hnf_constr env sigma (nf_betaiota nty) in
- if occur_meta mvty then
- (try
- let (mc,ec) = unify_0 env sigma Cumul mod_delta nty mvty
- in
- ty_metas := mc @ !ty_metas;
- ty_evars := ec @ !ty_evars;
- evd,n
- with e when precatchable_exception e -> evd,n)
- else
- (* Try to coerce to the type of [k]; cannot merge with the
- previous case because Coercion does not handle Meta *)
- w_coerce env n nty mvty evd
- else
- evd,n in
- let evd' = meta_assign mv (n,status) evd in
- w_merge_rec evd' t []
- end
+ let evd' = meta_assign mv (n,(status,TypeProcessed)) evd in
+ w_merge_rec evd' metas []
and mimick_evar evd mod_delta hdc nargs sp =
let ev = Evd.find (evars_of evd) sp in
@@ -428,6 +441,10 @@ let w_merge env with_types mod_delta metas evars evd =
else
evd'
+let w_unify_meta_types env evd =
+ let metas,evd = retract_coercible_metas evd in
+ w_merge env true true metas [] evd
+
(* [w_unify env evd M N]
performs a unification of M and N, generating a bunch of
unification constraints in the process. These constraints
@@ -442,7 +459,7 @@ let w_unify_core_0 env with_types cv_pb mod_delta m n evd =
let (mc1,evd') = retract_coercible_metas evd in
let (mc2,ec) =
unify_0_with_initial_metas mc1 env (evars_of evd') cv_pb mod_delta m n in
- w_merge env with_types mod_delta (mc1@mc2) ec evd'
+ w_merge env with_types mod_delta mc2 ec evd'
let w_unify_0 env = w_unify_core_0 env false
let w_typed_unify env = w_unify_core_0 env true
diff --git a/pretyping/unification.mli b/pretyping/unification.mli
index 441b2e495..f163e95f6 100644
--- a/pretyping/unification.mli
+++ b/pretyping/unification.mli
@@ -24,6 +24,8 @@ val w_unify :
val w_unify_to_subterm :
env -> ?mod_delta:bool -> constr * constr -> evar_defs -> evar_defs * constr
+val w_unify_meta_types : env -> evar_defs -> evar_defs
+
(*i This should be in another module i*)
(* [abstract_list_all env sigma t c l] *)
diff --git a/tactics/decl_proof_instr.ml b/tactics/decl_proof_instr.ml
index 99507f56c..28fc640d1 100644
--- a/tactics/decl_proof_instr.ml
+++ b/tactics/decl_proof_instr.ml
@@ -351,7 +351,8 @@ let enstack_subsubgoals env se stack gls=
let (nlast,holes,nmetas) =
meta_aux se.se_last_meta [] (List.rev rc) in
let refiner = applist (appterm,List.rev holes) in
- let evd = meta_assign se.se_meta (refiner,ConvUpToEta 0) se.se_evd in
+ let evd = meta_assign se.se_meta
+ (refiner,(ConvUpToEta 0,TypeProcessed (* ? *))) se.se_evd in
let ncreated = replace_in_list
se.se_meta nmetas se.se_meta_list in
let evd0 = List.fold_left
@@ -397,7 +398,8 @@ let find_subsubgoal c ctyp skip submetas gls =
ctyp se.se_type se.se_evd in
if n <= 0 then
{se with
- se_evd=meta_assign se.se_meta (c,ConvUpToEta 0) unifier;
+ se_evd=meta_assign se.se_meta
+ (c,(ConvUpToEta 0,TypeNotProcessed (* ?? *))) unifier;
se_meta_list=replace_in_list
se.se_meta submetas se.se_meta_list}
else
diff --git a/test-suite/success/apply.v b/test-suite/success/apply.v
index adb55cf2c..014f6ffcd 100644
--- a/test-suite/success/apply.v
+++ b/test-suite/success/apply.v
@@ -112,3 +112,54 @@ Goal forall p q1 q2, f (f q1 (Zpos p)) (f q2 (Zpos p)) = Z0.
intros; rewrite g with (p:=p).
reflexivity.
Qed.
+
+(* A funny example where the behavior differs depending on which of a
+ multiple solution to a unification problem is chosen (an instance
+ of this case can be found in the proof of Buchberger.BuchRed.nf_divp) *)
+
+Definition succ x := S x.
+Goal forall (I : nat -> Set) (P : nat -> Prop) (Q : forall n:nat, I n -> Prop),
+ (forall x y, P x -> Q x y) ->
+ (forall x, P (S x)) -> forall y: I (S 0), Q (succ 0) y.
+intros.
+apply H with (y:=y).
+(* [x] had two possible instances: [S 0], coming from unifying the
+ type of [y] with [I ?n] and [succ 0] coming from the unification with
+ the goal; only the first one allows to make the next apply (which
+ does not work modulo delta) working *)
+apply H0.
+Qed.
+
+(* A similar example with a arbitrary long conversion between the two
+ possible instances *)
+
+Fixpoint compute_succ x :=
+ match x with O => S 0 | S n => S (compute_succ n) end.
+
+Goal forall (I : nat -> Set) (P : nat -> Prop) (Q : forall n:nat, I n -> Prop),
+ (forall x y, P x -> Q x y) ->
+ (forall x, P (S x)) -> forall y: I (S 100), Q (compute_succ 100) y.
+intros.
+apply H with (y:=y).
+apply H0.
+Qed.
+
+(* Another example with multiple convertible solutions to the same
+ metavariable (extracted from Algebra.Hom_module.Hom_module, 10th
+ subgoal which precisely fails) *)
+
+Definition ID (A:Type) := A.
+Goal forall f:Type -> Type,
+ forall (P : forall A:Type, A -> Prop),
+ (forall (B:Type) x, P (f B) x -> P (f B) x) ->
+ (forall (A:Type) x, P (f (f A)) x) ->
+ forall (A:Type) (x:f (f A)), P (f (ID (f A))) x.
+intros.
+apply H.
+(* The parameter [B] had two possible instances: [ID (f A)] by direct
+ unification and [f A] by unification of the type of [x]; only the
+ first choice makes the next command fail, as it was
+ (unfortunately?) in Hom_module *)
+try apply H.
+unfold ID; apply H0.
+Qed.
diff --git a/toplevel/cerrors.ml b/toplevel/cerrors.ml
index 9d1d8d184..4c600bc66 100644
--- a/toplevel/cerrors.ml
+++ b/toplevel/cerrors.ml
@@ -28,10 +28,6 @@ let guill s = "\""^s^"\""
let where s =
if !Options.debug then (str"in " ++ str s ++ str":" ++ spc ()) else (mt ())
-let anomaly_string () = str "Anomaly: "
-
-let report () = (str "." ++ spc () ++ str "Please report.")
-
(* assumption : explain_sys_exn does NOT end with a 'FNL anymore! *)
let rec explain_exn_default_aux anomaly_string report_fn = function
@@ -127,8 +123,12 @@ let rec explain_exn_default_aux anomaly_string report_fn = function
hov 0 (anomaly_string () ++ str "Uncaught exception " ++
str (Printexc.to_string reraise) ++ report_fn ())
+let anomaly_string () = str "Anomaly: "
+
+let report () = (str "." ++ spc () ++ str "Please report.")
+
let explain_exn_default =
- explain_exn_default_aux (fun () -> str "Anomaly: ") report
+ explain_exn_default_aux anomaly_string report
let raise_if_debug e =
if !Options.debug then raise e