[m-rev.] for review: improve error messages for missing foreign values in foreign_enum pragmas
Julien Fischer
jfischer at opturion.com
Tue Jun 7 11:41:46 AEST 2016
For review by anyone.
Improve error messages for missing foreign values in foreign_enum pragmas.
Currently, if a foreign_enum pragma is missing cases in the constructor -
foreign value mapping we report that there are some missing foreign values but
do not list the affected constructors unless --verbose-error-messages is
enabled. For cases where there are a small number of missing foreign values
this is a bit irritating as you need to recompile to find out what they are.
Change the compiler so the error messsage lists upto the first 10 constructors
that do not have a foreign value.
(If --verbose-error-messages is enabled then we list all of them as before.)
compiler/add_foreign_enum.m:
Make the above change.
In error messages for foreign_enum and foreign_export_enum pragmas, add
the word "type" before the name that is printed in error messages.
tests/invalid/Mmakefile:
tests/invalid/Mercury.options:
tests/fe_unmapped_nonverbose.{m,err_exp}:
tests/fe_napped_verbose.{m,err_exp}:
Test the new error messages for missing constructors in the constructor -
foreign value mapping.
tests/invalid/ee_invalid.err_exp:
tests/invalid/foreign_enum_import.err_exp:
tests/invalid/foreign_enum_invalid.err_exp:
Conform to the above changes.
Julien.
diff --git a/compiler/add_foreign_enum.m b/compiler/add_foreign_enum.m
index 0c61d65..e078406 100644
--- a/compiler/add_foreign_enum.m
+++ b/compiler/add_foreign_enum.m
@@ -48,7 +48,7 @@ add_pragma_foreign_export_enum(FEEInfo, _TypeStatus, Context,
TypeCtor = type_ctor(TypeName, TypeArity),
module_info_get_type_table(!.ModuleInfo, TypeTable),
ContextPieces = [words("In"), pragma_decl("foreign_export_enum"),
- words("declaration for"),
+ words("declaration for type"),
sym_name_and_arity(sym_name_arity(TypeName, TypeArity)),
suffix(":"), nl],
( if
@@ -370,7 +370,7 @@ add_pragma_foreign_enum(FEInfo, PragmaStatus, Context, !ModuleInfo, !Specs) :-
TypeCtor = type_ctor(TypeName, TypeArity),
module_info_get_type_table(!.ModuleInfo, TypeTable0),
ContextPieces = [words("In"), pragma_decl("foreign_enum"),
- words("declaration for"),
+ words("declaration for type"),
sym_name_and_arity(sym_name_arity(TypeName, TypeArity)),
suffix(":"), nl],
( if
@@ -608,28 +608,54 @@ make_foreign_tag(ForeignLanguage, ForeignTagMap, ConsId, _, !ConsTagValues,
!:UnmappedCtors = [ConsSymName | !.UnmappedCtors]
).
+%-----------------------------------------------------------------------------%
+
:- pred add_foreign_enum_unmapped_ctors_error(prog_context::in,
list(format_component)::in,
list(sym_name)::in(non_empty_list),
list(error_spec)::in, list(error_spec)::out) is det.
-add_foreign_enum_unmapped_ctors_error(Context, ContextPieces, UnmappedCtors0,
+add_foreign_enum_unmapped_ctors_error(Context, ContextPieces, Ctors0,
!Specs) :-
- ErrorPieces = [words("error: not all constructors have a foreign value.")],
- list.sort(UnmappedCtors0, UnmappedCtors),
- CtorComponents = list.map((func(S) = [sym_name(S)]), UnmappedCtors),
- CtorList = component_list_to_line_pieces(CtorComponents, [nl]),
- DoOrDoes = choose_number(UnmappedCtors,
- "constructor does not have a foreign value",
- "constructors do not have foreign values"),
- VerboseErrorPieces = [words("The following"), words(DoOrDoes),
- nl_indent_delta(2)] ++ CtorList,
- Msg = simple_msg(Context,
- [always(ContextPieces ++ ErrorPieces),
- verbose_only(verbose_always, VerboseErrorPieces)]),
+ list.sort(Ctors0, Ctors),
+ list.split_upto(10, Ctors, CtorsStart, CtorsEnd),
+ DoOrDoes = choose_number(Ctors, "constructor does", "constructors do"),
+ PrefixPieces = ContextPieces ++ [
+ words("error: the following"), words(DoOrDoes),
+ words("not have a foreign value:"),
+ nl_indent_delta(2)
+ ],
+ StartListPieces = ctors_to_line_pieces(CtorsStart),
+ (
+ CtorsEnd = [],
+ MsgComponents = [always(PrefixPieces ++ StartListPieces)]
+ ;
+ CtorsEnd = [_ | _],
+ AllListPieces = ctors_to_line_pieces(Ctors),
+ VerbosePieces= PrefixPieces ++ AllListPieces,
+ list.length(CtorsEnd, NumEndCtors),
+ NonVerbosePieces = PrefixPieces ++ StartListPieces ++
+ [nl, fixed("..."), words("plus"), int_fixed(NumEndCtors),
+ words("more.")],
+ MsgComponents = [verbose_and_nonverbose(VerbosePieces,
+ NonVerbosePieces)]
+ ),
+ Msg = simple_msg(Context, MsgComponents),
Spec = error_spec(severity_error, phase_parse_tree_to_hlds, [Msg]),
list.cons(Spec, !Specs).
+:- func ctors_to_line_pieces(list(sym_name)) = list(format_component).
+
+ctors_to_line_pieces(Ctors) = Pieces :-
+ Components = list.map(ctor_to_format_component, Ctors),
+ Pieces = component_list_to_line_pieces(Components, [nl]).
+
+:- func ctor_to_format_component(sym_name) = list(format_component).
+
+ctor_to_format_component(S) = [sym_name(unqualified(unqualify_name(S)))].
+
+%-----------------------------------------------------------------------------%
+
:- pred add_foreign_enum_bijection_error(prog_context::in,
format_components::in, list(error_spec)::in, list(error_spec)::out) is det.
@@ -641,6 +667,8 @@ add_foreign_enum_bijection_error(Context, ContextPieces, !Specs) :-
Spec = error_spec(severity_error, phase_parse_tree_to_hlds, [Msg]),
list.cons(Spec, !Specs).
+%-----------------------------------------------------------------------------%
+
:- pred add_foreign_enum_pragma_in_interface_error(prog_context::in,
sym_name::in, arity::in, list(error_spec)::in, list(error_spec)::out)
is det.
diff --git a/tests/invalid/Mercury.options b/tests/invalid/Mercury.options
index 46261cb..dfb0b5c 100644
--- a/tests/invalid/Mercury.options
+++ b/tests/invalid/Mercury.options
@@ -23,6 +23,7 @@ MCFLAGS-ee_invalid = --verbose-error-messages
MCFLAGS-exported_mode = --infer-all --no-intermodule-optimization
MCFLAGS-exported_unify = --no-intermodule-optimization
MCFLAGS-exported_unify3 = --no-intermodule-optimization
+MCFLAGS-fe_unmapped_verbose = --verbose-error-messages
MCFLAGS-foreign_decl_line_number = --no-errorcheck-only --line-numbers \
--line-numbers-for-c-headers \
--compile-only
diff --git a/tests/invalid/Mmakefile b/tests/invalid/Mmakefile
index 39cd4aa..1dba876 100644
--- a/tests/invalid/Mmakefile
+++ b/tests/invalid/Mmakefile
@@ -334,6 +334,8 @@ TRAILED_MODULES = \
# The following require that the back-end support the C interface
C_INTERFACE_MODULES = \
+ fe_unmapped_nonverbose \
+ fe_unmapped_verbose \
foreign_decl_line_number \
trace_goal_env
diff --git a/tests/invalid/ee_invalid.err_exp b/tests/invalid/ee_invalid.err_exp
index 7f5a687..673ffe3 100644
--- a/tests/invalid/ee_invalid.err_exp
+++ b/tests/invalid/ee_invalid.err_exp
@@ -1,40 +1,41 @@
-ee_invalid.m:039: In `:- pragma foreign_export_enum' declaration for `int'/0:
+ee_invalid.m:039: In `:- pragma foreign_export_enum' declaration for type
+ee_invalid.m:039: `int'/0:
ee_invalid.m:039: error: `int'/0 is a builtin type.
ee_invalid.m:043: In pragma foreign_export_enum:
ee_invalid.m:043: error: undefined type `undefined_type'/0.
-ee_invalid.m:047: In `:- pragma foreign_export_enum' declaration for
+ee_invalid.m:047: In `:- pragma foreign_export_enum' declaration for type
ee_invalid.m:047: `ee_invalid.foo'/1:
ee_invalid.m:047: error: `ee_invalid.foo'/1 is not an enumeration type. It
ee_invalid.m:047: has one or more non-zero arity constructors.
-ee_invalid.m:051: In `:- pragma foreign_export_enum' declaration for
+ee_invalid.m:051: In `:- pragma foreign_export_enum' declaration for type
ee_invalid.m:051: `ee_invalid.bar'/0:
ee_invalid.m:051: error: `ee_invalid.bar'/0 is not an enumeration type.
-ee_invalid.m:058: In `:- pragma foreign_export_enum' declaration for
+ee_invalid.m:058: In `:- pragma foreign_export_enum' declaration for type
ee_invalid.m:058: `ee_invalid.baz'/0:
ee_invalid.m:058: error: `ee_invalid.baz'/0 is not an enumeration type.
-ee_invalid.m:063: In `:- pragma foreign_export_enum' declaration for
+ee_invalid.m:063: In `:- pragma foreign_export_enum' declaration for type
ee_invalid.m:063: `ee_invalid.alphabet'/0:
ee_invalid.m:063: the following constructor does not match any of the
ee_invalid.m:063: constructors of `ee_invalid.alphabet'/0:
ee_invalid.m:063: `deg'.
-ee_invalid.m:068: In `:- pragma foreign_export_enum' declaration for
+ee_invalid.m:068: In `:- pragma foreign_export_enum' declaration for type
ee_invalid.m:068: `ee_invalid.alphabet'/0:
ee_invalid.m:068: the following constructor does not match any of the
ee_invalid.m:068: constructors of `ee_invalid.alphabet'/0:
ee_invalid.m:068: `foo.def'.
-ee_invalid.m:073: In `:- pragma foreign_export_enum' declaration for
+ee_invalid.m:073: In `:- pragma foreign_export_enum' declaration for type
ee_invalid.m:073: `ee_invalid.alphabet'/0:
ee_invalid.m:073: error: the user-specified mapping between Mercury and
ee_invalid.m:073: foreign names does not form a bijection.
-ee_invalid.m:075: In `:- pragma foreign_export_enum' declaration for
+ee_invalid.m:075: In `:- pragma foreign_export_enum' declaration for type
ee_invalid.m:075: `ee_invalid.alphabet'/0:
ee_invalid.m:075: error: the mapping between Mercury and foreign names does
ee_invalid.m:075: not form a bijection.
-ee_invalid.m:077: In `:- pragma foreign_export_enum' declaration for
+ee_invalid.m:077: In `:- pragma foreign_export_enum' declaration for type
ee_invalid.m:077: `ee_invalid.alphabet'/0:
ee_invalid.m:077: error: the user-specified mapping between Mercury and
ee_invalid.m:077: foreign names does not form a bijection.
-ee_invalid.m:083: In `:- pragma foreign_export_enum' declaration for
+ee_invalid.m:083: In `:- pragma foreign_export_enum' declaration for type
ee_invalid.m:083: `ee_invalid.strange_names'/0:
ee_invalid.m:083: error: not all the constructors of the type
ee_invalid.m:083: `ee_invalid.strange_names'/0 can be converted into valid C
diff --git a/tests/invalid/fe_unmapped_nonverbose.err_exp b/tests/invalid/fe_unmapped_nonverbose.err_exp
index e69de29..d82d8f9 100644
--- a/tests/invalid/fe_unmapped_nonverbose.err_exp
+++ b/tests/invalid/fe_unmapped_nonverbose.err_exp
@@ -0,0 +1,35 @@
+fe_unmapped_nonverbose.m:073: In `:- pragma foreign_enum' declaration for type
+fe_unmapped_nonverbose.m:073: `fe_unmapped_nonverbose.voice'/0:
+fe_unmapped_nonverbose.m:073: error: the following constructor does not have
+fe_unmapped_nonverbose.m:073: a foreign value:
+fe_unmapped_nonverbose.m:073: `alto'
+fe_unmapped_nonverbose.m:079: In `:- pragma foreign_enum' declaration for type
+fe_unmapped_nonverbose.m:079: `fe_unmapped_nonverbose.chordophone'/0:
+fe_unmapped_nonverbose.m:079: error: the following constructors do not have a
+fe_unmapped_nonverbose.m:079: foreign value:
+fe_unmapped_nonverbose.m:079: `banjo',
+fe_unmapped_nonverbose.m:079: `cello',
+fe_unmapped_nonverbose.m:079: `double_bass',
+fe_unmapped_nonverbose.m:079: `dulcimer',
+fe_unmapped_nonverbose.m:079: `harp',
+fe_unmapped_nonverbose.m:079: `lute',
+fe_unmapped_nonverbose.m:079: `piano',
+fe_unmapped_nonverbose.m:079: `sitar',
+fe_unmapped_nonverbose.m:079: `ukulele',
+fe_unmapped_nonverbose.m:079: `viola'
+fe_unmapped_nonverbose.m:085: In `:- pragma foreign_enum' declaration for type
+fe_unmapped_nonverbose.m:085: `fe_unmapped_nonverbose.shade_of_white'/0:
+fe_unmapped_nonverbose.m:085: error: the following constructors do not have a
+fe_unmapped_nonverbose.m:085: foreign value:
+fe_unmapped_nonverbose.m:085: `anitque_white',
+fe_unmapped_nonverbose.m:085: `blond',
+fe_unmapped_nonverbose.m:085: `cornsilk',
+fe_unmapped_nonverbose.m:085: `cosmic_latte',
+fe_unmapped_nonverbose.m:085: `cream',
+fe_unmapped_nonverbose.m:085: `eggshell',
+fe_unmapped_nonverbose.m:085: `floral_white',
+fe_unmapped_nonverbose.m:085: `ghost_white',
+fe_unmapped_nonverbose.m:085: `honeydew',
+fe_unmapped_nonverbose.m:085: `isabelline'
+fe_unmapped_nonverbose.m:085: ... plus 17 more.
+For more information, recompile with `-E'.
diff --git a/tests/invalid/fe_unmapped_nonverbose.m b/tests/invalid/fe_unmapped_nonverbose.m
index e69de29..5d4c89a 100644
--- a/tests/invalid/fe_unmapped_nonverbose.m
+++ b/tests/invalid/fe_unmapped_nonverbose.m
@@ -0,0 +1,91 @@
+%----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et wm=0 tw=0
+%----------------------------------------------------------------------------%
+% Test non-verbose error messages produced for missing construtors in the
+% constructor - foreign value mapping of foreign_enum pragmas.
+%----------------------------------------------------------------------------%
+
+:- module fe_unmapped_nonverbose.
+:- interface.
+
+ % Test for 1 missing foreign value.
+ %
+:- type voice
+ ---> soprano
+ ; alto
+ ; tenor
+ ; bass.
+
+ % Test for > 1 and < 11 missing foreign values.
+ %
+:- type chordophone
+ ---> guitar
+ ; violin
+ ; lyre
+ ; harp
+ ; cello
+ ; banjo
+ ; double_bass
+ ; dulcimer
+ ; lute
+ ; piano
+ ; sitar
+ ; ukulele
+ ; viola.
+
+ % Test for > 10 constructors missing foreign values.
+:- type shade_of_white
+ ---> anti_flash_white
+ ; anitque_white
+ ; beige
+ ; blond
+ ; cornsilk
+ ; cosmic_latte
+ ; cream
+ ; eggshell
+ ; floral_white
+ ; ghost_white
+ ; honeydew
+ ; isabelline
+ ; ivory
+ ; lavender_blush
+ ; lemon_chiffon
+ ; linen
+ ; magnolia
+ ; mint_cream
+ ; navajo_white
+ ; old_lace
+ ; papaya_whip
+ ; peach
+ ; pearl
+ ; seashell
+ ; snow
+ ; splashed_white
+ ; vanilla
+ ; white
+ ; white_smoke.
+
+%----------------------------------------------------------------------------%
+%----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- pragma foreign_enum("C", voice/0, [
+ soprano - "1",
+ tenor - "3",
+ bass - "4"
+]).
+
+:- pragma foreign_enum("C", chordophone/0, [
+ guitar - "0",
+ violin - "1",
+ lyre - "2"
+]).
+
+:- pragma foreign_enum("C", shade_of_white/0, [
+ anti_flash_white - "0xF2F3F4",
+ antique_white - "0xFAEBD7",
+ beige - "0xF5F5DC"
+]).
+
+%----------------------------------------------------------------------------%
diff --git a/tests/invalid/fe_unmapped_verbose.err_exp b/tests/invalid/fe_unmapped_verbose.err_exp
index e69de29..0f11cb1 100644
--- a/tests/invalid/fe_unmapped_verbose.err_exp
+++ b/tests/invalid/fe_unmapped_verbose.err_exp
@@ -0,0 +1,31 @@
+fe_unmapped_verbose.m:050: In `:- pragma foreign_enum' declaration for type
+fe_unmapped_verbose.m:050: `fe_unmapped_verbose.shade_of_white'/0:
+fe_unmapped_verbose.m:050: error: the following constructors do not have a
+fe_unmapped_verbose.m:050: foreign value:
+fe_unmapped_verbose.m:050: `anitque_white',
+fe_unmapped_verbose.m:050: `blond',
+fe_unmapped_verbose.m:050: `cornsilk',
+fe_unmapped_verbose.m:050: `cosmic_latte',
+fe_unmapped_verbose.m:050: `cream',
+fe_unmapped_verbose.m:050: `eggshell',
+fe_unmapped_verbose.m:050: `floral_white',
+fe_unmapped_verbose.m:050: `ghost_white',
+fe_unmapped_verbose.m:050: `honeydew',
+fe_unmapped_verbose.m:050: `isabelline',
+fe_unmapped_verbose.m:050: `ivory',
+fe_unmapped_verbose.m:050: `lavender_blush',
+fe_unmapped_verbose.m:050: `lemon_chiffon',
+fe_unmapped_verbose.m:050: `linen',
+fe_unmapped_verbose.m:050: `magnolia',
+fe_unmapped_verbose.m:050: `mint_cream',
+fe_unmapped_verbose.m:050: `navajo_white',
+fe_unmapped_verbose.m:050: `old_lace',
+fe_unmapped_verbose.m:050: `papaya_whip',
+fe_unmapped_verbose.m:050: `peach',
+fe_unmapped_verbose.m:050: `pearl',
+fe_unmapped_verbose.m:050: `seashell',
+fe_unmapped_verbose.m:050: `snow',
+fe_unmapped_verbose.m:050: `splashed_white',
+fe_unmapped_verbose.m:050: `vanilla',
+fe_unmapped_verbose.m:050: `white',
+fe_unmapped_verbose.m:050: `white_smoke'
diff --git a/tests/invalid/fe_unmapped_verbose.m b/tests/invalid/fe_unmapped_verbose.m
index e69de29..30a48a9 100644
--- a/tests/invalid/fe_unmapped_verbose.m
+++ b/tests/invalid/fe_unmapped_verbose.m
@@ -0,0 +1,56 @@
+%----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et wm=0 tw=0
+%----------------------------------------------------------------------------%
+% Test verbose error messages produced for missing construtors in the
+% constructor - foreign value mapping of foreign_enum pragmas.
+%----------------------------------------------------------------------------%
+
+:- module fe_unmapped_verbose.
+:- interface.
+
+ % If --verbose-error-messages is enabled then all the constructors missing
+ % foreign values should be listed.
+ %
+:- type shade_of_white
+ ---> anti_flash_white
+ ; anitque_white
+ ; beige
+ ; blond
+ ; cornsilk
+ ; cosmic_latte
+ ; cream
+ ; eggshell
+ ; floral_white
+ ; ghost_white
+ ; honeydew
+ ; isabelline
+ ; ivory
+ ; lavender_blush
+ ; lemon_chiffon
+ ; linen
+ ; magnolia
+ ; mint_cream
+ ; navajo_white
+ ; old_lace
+ ; papaya_whip
+ ; peach
+ ; pearl
+ ; seashell
+ ; snow
+ ; splashed_white
+ ; vanilla
+ ; white
+ ; white_smoke.
+
+%----------------------------------------------------------------------------%
+%----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- pragma foreign_enum("C", shade_of_white/0, [
+ anti_flash_white - "0xF2F3F4",
+ antique_white - "0xFAEBD7",
+ beige - "0xF5F5DC"
+]).
+
+%----------------------------------------------------------------------------%
diff --git a/tests/invalid/foreign_enum_import.err_exp b/tests/invalid/foreign_enum_import.err_exp
index f70035d..7237c21 100644
--- a/tests/invalid/foreign_enum_import.err_exp
+++ b/tests/invalid/foreign_enum_import.err_exp
@@ -1,4 +1,4 @@
-foreign_enum_import.m:014: In `:- pragma foreign_enum' declaration for
+foreign_enum_import.m:014: In `:- pragma foreign_enum' declaration for type
foreign_enum_import.m:014: `bool.bool'/0:
foreign_enum_import.m:014: error: `bool.bool'/0 is not defined in this
foreign_enum_import.m:014: module.
diff --git a/tests/invalid/foreign_enum_invalid.err_exp b/tests/invalid/foreign_enum_invalid.err_exp
index 958ddf9..46134a3 100644
--- a/tests/invalid/foreign_enum_invalid.err_exp
+++ b/tests/invalid/foreign_enum_invalid.err_exp
@@ -1,18 +1,17 @@
foreign_enum_invalid.m:021: Error: `:- pragma foreign_enum' declaration for
foreign_enum_invalid.m:021: `foreign_enum_invalid.in_int'/0 in module
foreign_enum_invalid.m:021: interface.
-foreign_enum_invalid.m:027: In `:- pragma foreign_enum' declaration for
+foreign_enum_invalid.m:027: In `:- pragma foreign_enum' declaration for type
foreign_enum_invalid.m:027: `foreign_enum_invalid.incomplete'/0:
-foreign_enum_invalid.m:027: error: not all constructors have a foreign value.
-foreign_enum_invalid.m:027: The following constructor does not have a foreign
-foreign_enum_invalid.m:027: value
-foreign_enum_invalid.m:027: `foreign_enum_invalid.baz'
-foreign_enum_invalid.m:032: In `:- pragma foreign_enum' declaration for
+foreign_enum_invalid.m:027: error: the following constructor does not have a
+foreign_enum_invalid.m:027: foreign value:
+foreign_enum_invalid.m:027: `baz'
+foreign_enum_invalid.m:032: In `:- pragma foreign_enum' declaration for type
foreign_enum_invalid.m:032: `foreign_enum_invalid.not_a_bijection'/0:
foreign_enum_invalid.m:032: error: the mapping between Mercury enumeration
foreign_enum_invalid.m:032: values and foreign values does not form a
foreign_enum_invalid.m:032: bijection.
-foreign_enum_invalid.m:040: In `:- pragma foreign_enum' declaration for
+foreign_enum_invalid.m:040: In `:- pragma foreign_enum' declaration for type
foreign_enum_invalid.m:040: `foreign_enum_invalid.dup_foreign_enum'/0:
foreign_enum_invalid.m:040: error: `foreign_enum_invalid.dup_foreign_enum'/0
foreign_enum_invalid.m:040: has multiple foreign_enum pragmas.
More information about the reviews
mailing list