aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--kernel/modops.ml62
-rw-r--r--kernel/modops.mli24
-rw-r--r--kernel/reduction.ml6
-rw-r--r--kernel/reduction.mli4
-rw-r--r--kernel/subtyping.ml79
-rw-r--r--lib/util.ml9
-rw-r--r--lib/util.mli2
-rw-r--r--test-suite/modules/errors.v70
8 files changed, 214 insertions, 42 deletions
diff --git a/kernel/modops.ml b/kernel/modops.ml
index 2bcfada96..302d25194 100644
--- a/kernel/modops.ml
+++ b/kernel/modops.ml
@@ -38,7 +38,67 @@ let error_incompatible_modtypes _ _ = error "Incompatible module types."
let error_not_equal _ _ = error "Non equal modules."
-let error_not_match l _ = error ("Signature components for label "^string_of_label l^" do not match.")
+type signature_mismatch_error =
+ | InductiveFieldExpected of mutual_inductive_body
+ | DefinitionFieldExpected
+ | ModuleFieldExpected
+ | ModuleTypeFieldExpected
+ | NotConvertibleInductiveField of identifier
+ | NotConvertibleConstructorField of identifier
+ | NotConvertibleBodyField
+ | NotConvertibleTypeField
+ | NotSameConstructorNamesField
+ | NotSameInductiveNameInBlockField
+ | FiniteInductiveFieldExpected of bool
+ | InductiveNumbersFieldExpected of int
+ | InductiveParamsNumberField of int
+ | RecordFieldExpected of bool
+ | RecordProjectionsExpected of name list
+ | NotEqualInductiveAliases
+ | NoTypeConstraintExpected
+
+let explain_not_match_error = function
+ | InductiveFieldExpected _ ->
+ strbrk "an inductive definition is expected"
+ | DefinitionFieldExpected ->
+ strbrk "a definition is expected"
+ | ModuleFieldExpected ->
+ strbrk "a module is expected"
+ | ModuleTypeFieldExpected ->
+ strbrk "a module type is expected"
+ | NotConvertibleInductiveField id | NotConvertibleConstructorField id ->
+ str "types given to " ++ str (string_of_id id) ++ str " differ"
+ | NotConvertibleBodyField ->
+ str "the body of definitions differs"
+ | NotConvertibleTypeField ->
+ str "types differ"
+ | NotSameConstructorNamesField ->
+ str "constructor names differ"
+ | NotSameInductiveNameInBlockField ->
+ str "inductive types names differ"
+ | FiniteInductiveFieldExpected isfinite ->
+ str "type is expected to be " ++
+ str (if isfinite then "coinductive" else "inductive")
+ | InductiveNumbersFieldExpected n ->
+ str "number of inductive types differs"
+ | InductiveParamsNumberField n ->
+ str "inductive type has not the right number of parameters"
+ | RecordFieldExpected isrecord ->
+ str "type is expected " ++ str (if isrecord then "" else "not ") ++
+ str "to be a record"
+ | RecordProjectionsExpected nal ->
+ (if List.length nal >= 2 then str "expected projection names are "
+ else str "expected projection name is ") ++
+ pr_enum (function Name id -> str (string_of_id id) | _ -> str "_") nal
+ | NotEqualInductiveAliases ->
+ str "Aliases to inductive types do not match"
+ | NoTypeConstraintExpected ->
+ strbrk "a definition whose type is constrained can only be subtype of a definition whose type is itself constrained"
+
+let error_not_match l _ why =
+ errorlabstrm ""
+ (str "Signature components for label " ++ str (string_of_label l) ++
+ str " do not match:" ++ spc () ++ explain_not_match_error why ++ str ".")
let error_no_such_label l = error ("No such label "^string_of_label l^".")
diff --git a/kernel/modops.mli b/kernel/modops.mli
index f34fa88c4..cf8d62043 100644
--- a/kernel/modops.mli
+++ b/kernel/modops.mli
@@ -51,6 +51,27 @@ val subst_modtype_and_resolver : module_type_body -> module_path -> env ->
val clean_bounded_mod_expr : struct_expr_body -> struct_expr_body
+(** Errors *)
+
+type signature_mismatch_error =
+ | InductiveFieldExpected of mutual_inductive_body
+ | DefinitionFieldExpected
+ | ModuleFieldExpected
+ | ModuleTypeFieldExpected
+ | NotConvertibleInductiveField of identifier
+ | NotConvertibleConstructorField of identifier
+ | NotConvertibleBodyField
+ | NotConvertibleTypeField
+ | NotSameConstructorNamesField
+ | NotSameInductiveNameInBlockField
+ | FiniteInductiveFieldExpected of bool
+ | InductiveNumbersFieldExpected of int
+ | InductiveParamsNumberField of int
+ | RecordFieldExpected of bool
+ | RecordProjectionsExpected of name list
+ | NotEqualInductiveAliases
+ | NoTypeConstraintExpected
+
val error_existing_label : label -> 'a
val error_declaration_not_path : module_struct_entry -> 'a
@@ -64,7 +85,8 @@ val error_incompatible_modtypes :
val error_not_equal : module_path -> module_path -> 'a
-val error_not_match : label -> structure_field_body -> 'a
+val error_not_match :
+ label -> structure_field_body -> signature_mismatch_error -> 'a
val error_incompatible_labels : label -> label -> 'a
diff --git a/kernel/reduction.ml b/kernel/reduction.ml
index c865c92bf..8252ffb9e 100644
--- a/kernel/reduction.ml
+++ b/kernel/reduction.ml
@@ -534,15 +534,17 @@ let dest_prod_assum env =
in
prodec_rec env empty_rel_context
+exception NotArity
+
let dest_arity env c =
let l, c = dest_prod_assum env c in
match kind_of_term c with
| Sort s -> l,s
- | _ -> error "not an arity"
+ | _ -> raise NotArity
let is_arity env c =
try
let _ = dest_arity env c in
true
- with UserError _ -> false
+ with NotArity -> false
diff --git a/kernel/reduction.mli b/kernel/reduction.mli
index e0f9c375b..525651493 100644
--- a/kernel/reduction.mli
+++ b/kernel/reduction.mli
@@ -76,5 +76,7 @@ val hnf_prod_applist : env -> types -> constr list -> types
val dest_prod : env -> types -> rel_context * types
val dest_prod_assum : env -> types -> rel_context * types
-val dest_arity : env -> types -> arity
+exception NotArity
+
+val dest_arity : env -> types -> arity (* raise NotArity if not an arity *)
val is_arity : env -> types -> bool
diff --git a/kernel/subtyping.ml b/kernel/subtyping.ml
index 2612afca6..808557521 100644
--- a/kernel/subtyping.ml
+++ b/kernel/subtyping.ml
@@ -67,26 +67,26 @@ let make_label_map mp list =
in
List.fold_right add_one list Labmap.empty
-let check_conv_error error cst f env a1 a2 =
+let check_conv_error error why cst f env a1 a2 =
try
union_constraints cst (f env a1 a2)
with
- NotConvertible -> error ()
+ NotConvertible -> error why
(* for now we do not allow reorderings *)
let check_inductive cst env mp1 l info1 mp2 mib2 spec2 subst1 subst2 reso1 reso2=
let kn1 = make_mind mp1 empty_dirpath l in
let kn2 = make_mind mp2 empty_dirpath l in
- let error () = error_not_match l spec2 in
- let check_conv cst f = check_conv_error error cst f in
+ let error why = error_not_match l spec2 why in
+ let check_conv why cst f = check_conv_error error why cst f in
let mib1 =
match info1 with
| IndType ((_,0), mib) -> subst_mind subst1 mib
- | _ -> error ()
+ | _ -> error (InductiveFieldExpected mib2)
in
let mib2 = subst_mind subst2 mib2 in
- let check_inductive_type cst env t1 t2 =
+ let check_inductive_type cst name env t1 t2 =
(* Due to sort-polymorphism in inductive types, the conclusions of
t1 and t2, if in Type, are generated as the least upper bounds
@@ -115,40 +115,43 @@ let check_inductive cst env mp1 l info1 mp2 mib2 spec2 subst1 subst2 reso1 reso2
let s1,s2 =
match s1, s2 with
| Type _, Type _ -> (* shortcut here *) prop_sort, prop_sort
- | (Prop _, Type _) | (Type _,Prop _) -> error ()
+ | (Prop _, Type _) | (Type _,Prop _) ->
+ error (NotConvertibleInductiveField name)
| _ -> (s1, s2) in
- check_conv cst conv_leq env (mkArity (ctx1,s1)) (mkArity (ctx2,s2))
+ check_conv (NotConvertibleInductiveField name)
+ cst conv_leq env (mkArity (ctx1,s1)) (mkArity (ctx2,s2))
in
let check_packet cst p1 p2 =
- let check f = if f p1 <> f p2 then error () in
- check (fun p -> p.mind_consnames);
- check (fun p -> p.mind_typename);
+ let check f why = if f p1 <> f p2 then error why in
+ check (fun p -> p.mind_consnames) NotSameConstructorNamesField;
+ check (fun p -> p.mind_typename) NotSameInductiveNameInBlockField;
(* nf_lc later *)
(* nf_arity later *)
(* user_lc ignored *)
(* user_arity ignored *)
- check (fun p -> p.mind_nrealargs);
+ check (fun p -> p.mind_nrealargs) (NotConvertibleInductiveField p2.mind_typename); (* How can it fail since the type of inductive are checked below? [HH] *)
(* kelim ignored *)
(* listrec ignored *)
(* finite done *)
(* nparams done *)
(* params_ctxt done because part of the inductive types *)
(* Don't check the sort of the type if polymorphic *)
- let cst = check_inductive_type cst env (type_of_inductive env (mib1,p1)) (type_of_inductive env (mib2,p2))
+ let cst = check_inductive_type cst p2.mind_typename env (type_of_inductive env (mib1,p1)) (type_of_inductive env (mib2,p2))
in
cst
in
let check_cons_types i cst p1 p2 =
- array_fold_left2
- (fun cst t1 t2 -> check_conv cst conv env t1 t2)
+ array_fold_left3
+ (fun cst id t1 t2 -> check_conv (NotConvertibleConstructorField id) cst conv env t1 t2)
cst
+ p2.mind_consnames
(arities_of_specif kn1 (mib1,p1))
(arities_of_specif kn1 (mib2,p2))
in
- let check f = if f mib1 <> f mib2 then error () in
- check (fun mib -> mib.mind_finite);
- check (fun mib -> mib.mind_ntypes);
+ let check f why = if f mib1 <> f mib2 then error (why (f mib2)) in
+ check (fun mib -> mib.mind_finite) (fun x -> FiniteInductiveFieldExpected x);
+ check (fun mib -> mib.mind_ntypes) (fun x -> InductiveNumbersFieldExpected x);
assert (mib1.mind_hyps=[] && mib2.mind_hyps=[]);
assert (Array.length mib1.mind_packets >= 1
&& Array.length mib2.mind_packets >= 1);
@@ -158,17 +161,17 @@ let check_inductive cst env mp1 l info1 mp2 mib2 spec2 subst1 subst2 reso1 reso2
(* at the time of checking the inductive arities in check_packet. *)
(* Notice that we don't expect the local definitions to match: only *)
(* the inductive types and constructors types have to be convertible *)
- check (fun mib -> mib.mind_nparams);
+ check (fun mib -> mib.mind_nparams) (fun x -> InductiveParamsNumberField x);
begin
match mind_of_delta reso2 kn2 with
| kn2' when kn2=kn2' -> ()
| kn2' ->
if not (eq_mind (mind_of_delta reso1 kn1) (subst_ind subst2 kn2')) then
- error ()
+ error NotEqualInductiveAliases
end;
(* we check that records and their field names are preserved. *)
- check (fun mib -> mib.mind_record);
+ check (fun mib -> mib.mind_record) (fun x -> RecordFieldExpected x);
if mib1.mind_record then begin
let rec names_prod_letin t = match kind_of_term t with
| Prod(n,_,t) -> n::(names_prod_letin t)
@@ -183,7 +186,8 @@ let check_inductive cst env mp1 l info1 mp2 mib2 spec2 subst1 subst2 reso1 reso2
check (fun mib ->
let nparamdecls = List.length mib.mind_params_ctxt in
let names = names_prod_letin (mib.mind_packets.(0).mind_user_lc.(0)) in
- snd (list_chop nparamdecls names));
+ snd (list_chop nparamdecls names))
+ (fun x -> RecordProjectionsExpected x);
end;
(* we first check simple things *)
let cst =
@@ -197,7 +201,7 @@ let check_inductive cst env mp1 l info1 mp2 mib2 spec2 subst1 subst2 reso1 reso2
let check_constant cst env mp1 l info1 cb2 spec2 subst1 subst2 =
- let error () = error_not_match l spec2 in
+ let error why = error_not_match l spec2 why in
let check_conv cst f = check_conv_error error cst f in
let check_type cst env t1 t2 =
@@ -237,13 +241,14 @@ let check_constant cst env mp1 l info1 cb2 spec2 subst1 subst2 =
constraints of the form "univ <= max(...)" are not
expressible in the system of algebraic universes: we fail
(the user has to use an explicit type in the interface *)
- error ()
- with UserError _ (* "not an arity" *) ->
- error () end
- | _ -> t1,t2
+ error NoTypeConstraintExpected
+ with NotArity ->
+ error NotConvertibleTypeField end
+ | _ ->
+ t1,t2
else
(t1,t2) in
- check_conv cst conv_leq env t1 t2
+ check_conv NotConvertibleTypeField cst conv_leq env t1 t2
in
match info1 with
@@ -284,7 +289,7 @@ let check_constant cst env mp1 l info1 cb2 spec2 subst1 subst2 =
end
| None -> mkConst con
in
- check_conv cst conv env c1 c2
+ check_conv NotConvertibleBodyField cst conv env c1 c2
else
match cb2.const_body with
| None -> cst
@@ -294,7 +299,7 @@ let check_constant cst env mp1 l info1 cb2 spec2 subst1 subst2 =
| Some lc1 -> Declarations.force lc1
| None -> mkConst con
in
- check_conv cst conv env c1 c2
+ check_conv NotConvertibleBodyField cst conv env c1 c2
in
cst
| IndType ((kn,i),mind1) ->
@@ -304,10 +309,10 @@ let check_constant cst env mp1 l info1 cb2 spec2 subst1 subst2 =
"inductive type and give a definition to map the old name to the new " ^
"name."));
assert (mind1.mind_hyps=[] && cb2.const_hyps=[]) ;
- if cb2.const_body <> None then error () ;
+ if cb2.const_body <> None then error DefinitionFieldExpected;
let arity1 = type_of_inductive env (mind1,mind1.mind_packets.(i)) in
let typ2 = Typeops.type_of_constant_type env cb2.const_type in
- check_conv cst conv_leq env arity1 typ2
+ check_conv NotConvertibleTypeField cst conv_leq env arity1 typ2
| IndConstr (((kn,i),j) as cstr,mind1) ->
ignore (Util.error (
"The kernel does not recognize yet that a parameter can be " ^
@@ -315,11 +320,11 @@ let check_constant cst env mp1 l info1 cb2 spec2 subst1 subst2 =
"constructor and give a definition to map the old name to the new " ^
"name."));
assert (mind1.mind_hyps=[] && cb2.const_hyps=[]) ;
- if cb2.const_body <> None then error () ;
+ if cb2.const_body <> None then error DefinitionFieldExpected;
let ty1 = type_of_constructor cstr (mind1,mind1.mind_packets.(i)) in
let ty2 = Typeops.type_of_constant_type env cb2.const_type in
- check_conv cst conv env ty1 ty2
- | _ -> error ()
+ check_conv NotConvertibleTypeField cst conv env ty1 ty2
+ | _ -> error DefinitionFieldExpected
let rec check_modules cst env msb1 msb2 subst1 subst2 =
let mty1 = module_type_of_module env None msb1 in
@@ -348,13 +353,13 @@ and check_signatures cst env mp1 sig1 mp2 sig2 subst1 subst2 reso1 reso2=
match info1 with
| Module msb -> check_modules cst env msb msb2
subst1 subst2
- | _ -> error_not_match l spec2
+ | _ -> error_not_match l spec2 ModuleFieldExpected
end
| SFBmodtype mtb2 ->
let mtb1 =
match info1 with
| Modtype mtb -> mtb
- | _ -> error_not_match l spec2
+ | _ -> error_not_match l spec2 ModuleTypeFieldExpected
in
let env = add_module (module_body_of_type mtb2.typ_mp mtb2)
(add_module (module_body_of_type mtb1.typ_mp mtb1) env) in
diff --git a/lib/util.ml b/lib/util.ml
index a8e716e0f..242c20321 100644
--- a/lib/util.ml
+++ b/lib/util.ml
@@ -1000,6 +1000,15 @@ let array_fold_left2_i f a v1 v2 =
if Array.length v2 <> lv1 then invalid_arg "array_fold_left2";
fold a 0
+let array_fold_left3 f a v1 v2 v3 =
+ let lv1 = Array.length v1 in
+ let rec fold a n =
+ if n >= lv1 then a else fold (f a v1.(n) v2.(n) v3.(n)) (succ n)
+ in
+ if Array.length v2 <> lv1 || Array.length v3 <> lv1 then
+ invalid_arg "array_fold_left2";
+ fold a 0
+
let array_fold_left_from n f a v =
let rec fold a n =
if n >= Array.length v then a else fold (f a v.(n)) (succ n)
diff --git a/lib/util.mli b/lib/util.mli
index 5248d0e6b..2216ba981 100644
--- a/lib/util.mli
+++ b/lib/util.mli
@@ -259,6 +259,8 @@ val array_fold_right2 :
('a -> 'b -> 'c -> 'c) -> 'a array -> 'b array -> 'c -> 'c
val array_fold_left2 :
('a -> 'b -> 'c -> 'a) -> 'a -> 'b array -> 'c array -> 'a
+val array_fold_left3 :
+ ('a -> 'b -> 'c -> 'd -> 'a) -> 'a -> 'b array -> 'c array -> 'd array -> 'a
val array_fold_left2_i :
(int -> 'a -> 'b -> 'c -> 'a) -> 'a -> 'b array -> 'c array -> 'a
val array_fold_left_from : int -> ('a -> 'b -> 'a) -> 'a -> 'b array -> 'a
diff --git a/test-suite/modules/errors.v b/test-suite/modules/errors.v
new file mode 100644
index 000000000..d1658786e
--- /dev/null
+++ b/test-suite/modules/errors.v
@@ -0,0 +1,70 @@
+(* Inductive mismatches *)
+
+Module Type SA. Inductive TA : nat -> Prop := CA : nat -> TA 0. End SA.
+Module MA : SA. Inductive TA : Prop := CA : bool -> TA. Fail End MA.
+
+Module Type SA. Inductive TA := CA : nat -> TA. End SA.
+Module MA : SA. Inductive TA := CA : bool -> TA. Fail End MA.
+
+Module Type SA. Inductive TA := CA : nat -> TA. End SA.
+Module MA : SA. Inductive TA := CA : bool -> nat -> TA. Fail End MA.
+
+Module Type SA2. Inductive TA2 := CA2 : nat -> TA2. End SA2.
+Module MA2 : SA2. Inductive TA2 := CA2 : nat -> TA2 | DA2 : TA2. Fail End MA2.
+
+Module Type SA3. Inductive TA3 := CA3 : nat -> TA3. End SA3.
+Module MA3 : SA3. Inductive TA3 := CA3 : nat -> TA3 with UA3 := DA3. Fail End MA3.
+
+Module Type SA4. Inductive TA4 := CA4 : nat -> TA4 with UA4 := DA4. End SA4.
+Module MA4 : SA4. Inductive TA4 := CA4 : nat -> TA4 with VA4 := DA4. Fail End MA4.
+
+Module Type SA5. Inductive TA5 := CA5 : nat -> TA5 with UA5 := DA5. End SA5.
+Module MA5 : SA5. Inductive TA5 := CA5 : nat -> TA5 with UA5 := EA5. Fail End MA5.
+
+Module Type SA6. Inductive TA6 (A:Type) := CA6 : A -> TA6 A. End SA6.
+Module MA6 : SA6. Inductive TA6 (A B:Type):= CA6 : A -> TA6 A B. Fail End MA6.
+
+Module Type SA7. Inductive TA7 (A:Type) := CA7 : A -> TA7 A. End SA7.
+Module MA7 : SA7. CoInductive TA7 (A:Type):= CA7 : A -> TA7 A. Fail End MA7.
+
+Module Type SA8. CoInductive TA8 (A:Type) := CA8 : A -> TA8 A. End SA8.
+Module MA8 : SA8. Inductive TA8 (A:Type):= CA8 : A -> TA8 A. Fail End MA8.
+
+Module Type SA9. Record TA9 (A:Type) := { CA9 : A }. End SA9.
+Module MA9 : SA9. Inductive TA9 (A:Type):= CA9 : A -> TA9 A. Fail End MA9.
+
+Module Type SA10. Inductive TA10 (A:Type) := CA10 : A -> TA10 A. End SA10.
+Module MA10 : SA10. Record TA10 (A:Type):= { CA10 : A }. Fail End MA10.
+
+Module Type SA11. Record TA11 (A:Type):= { CA11 : A }. End SA11.
+Module MA11 : SA11. Record TA11 (A:Type):= { DA11 : A }. Fail End MA11.
+
+(* Basic mismatches *)
+Module Type SB. Inductive TB := CB : nat -> TB. End SB.
+Module MB : SB. Module Type TB. End TB. Fail End MB.
+
+Module Type SC. Module Type TC. End TC. End SC.
+Module MC : SC. Inductive TC := CC : nat -> TC. Fail End MC.
+
+Module Type SD. Module TD. End TD. End SD.
+Module MD : SD. Inductive TD := DD : nat -> TD. Fail End MD.
+
+Module Type SE. Definition DE := nat. End SE.
+Module ME : SE. Definition DE := bool. Fail End ME.
+
+Module Type SF. Parameter DF : nat. End SF.
+Module MF : SF. Definition DF := bool. Fail End MF.
+
+(* Needs a type constraint in module type *)
+Module Type SG. Definition DG := Type. End SG.
+Module MG : SG. Definition DG := Type : Type. Fail End MG.
+
+(* Should work *)
+Module Type SA7. Inductive TA7 (A:Type) := CA7 : A -> TA7 A. End SA7.
+Module MA7 : SA7. Inductive TA7 (B:Type):= CA7 : B -> TA7 B. End MA7.
+
+Module Type SA11. Record TA11 (B:Type):= { CA11 : B }. End SA11.
+Module MA11 : SA11. Record TA11 (A:Type):= { CA11 : A }. End MA11.
+
+Module Type SE. Parameter DE : Type. End SE.
+Module ME : SE. Definition DE := Type : Type. End ME.