diff --git a/compiler/parse_type_defn.m b/compiler/parse_type_defn.m index c75c98e13..2f1bc3050 100644 --- a/compiler/parse_type_defn.m +++ b/compiler/parse_type_defn.m @@ -379,6 +379,17 @@ parse_maybe_exist_quant_constructor(ModuleName, VarSet, Ordinal, Term, parse_constructor(ModuleName, VarSet, Ordinal, ExistQVars, Term, MaybeConstructor) :- + ( if Term = term.functor(term.atom(":"), [_, _], ColonContext) then + ColonNameArity = name_arity(":", 2), + Pieces = [words("Error: attempt to define a data constructor"), + words("named"), name_arity(ColonNameArity), suffix(","), + words("which is a sign that a typo has replaced the")] ++ + color_as_correct([words("semicolon")]) ++ + [words("between two data constructors with a")] ++ + color_as_incorrect([words("colon.")]) ++ [nl], + Spec = spec($pred, severity_error, phase_t2pt, ColonContext, Pieces), + MaybeConstructor = error1(one_or_more(Spec, [])) + else get_existential_constraints_from_term(ModuleName, VarSet, Term, BeforeConstraintsTerm, MaybeConstraints), ( @@ -391,7 +402,8 @@ parse_constructor(ModuleName, VarSet, Ordinal, ExistQVars, Term, % the constructor are ignored. This is to allow you to define % ';'/2 and 'some'/2 constructors. % XXX I (zs) don't think that this is a good idea; I think such - % constructors are much more likely to be confusing than useful. + % constructors are much more likely to be confusing + % than useful. BeforeConstraintsTerm = term.functor(term.atom("{}"), [InsideBracesTerm], _Context) then @@ -399,7 +411,8 @@ parse_constructor(ModuleName, VarSet, Ordinal, ExistQVars, Term, else MainTerm = BeforeConstraintsTerm ), - ContextPieces = cord.singleton(words("In constructor definition:")), + ContextPieces = + cord.singleton(words("In constructor definition:")), parse_implicitly_qualified_sym_name_and_args(ModuleName, VarSet, ContextPieces, MainTerm, MaybeFunctorAndArgTerms), ( @@ -492,6 +505,7 @@ parse_constructor(ModuleName, VarSet, Ordinal, ExistQVars, Term, det_list_to_one_or_more(Specs, OoMSpecs), MaybeConstructor = error1(OoMSpecs) ) + ) ). %---------------------% diff --git a/tests/invalid/Mmakefile b/tests/invalid/Mmakefile index 567a41dbd..0561f3702 100644 --- a/tests/invalid/Mmakefile +++ b/tests/invalid/Mmakefile @@ -157,6 +157,7 @@ BORING_SINGLEMODULE_PROGS = \ det_errors_and_io \ det_errors_cc \ det_errors_deep \ + du_type_with_colon \ duplicate_mutable \ ee_invalid \ erroneous_throw_promise \ diff --git a/tests/invalid/du_type_with_colon.err_exp b/tests/invalid/du_type_with_colon.err_exp new file mode 100644 index 000000000..2bc87b1eb --- /dev/null +++ b/tests/invalid/du_type_with_colon.err_exp @@ -0,0 +1,8 @@ +du_type_with_colon.m:023: Error: attempt to define a data constructor named +du_type_with_colon.m:023: `:'/2, which is a sign that a typo has replaced the +du_type_with_colon.m:023: semicolon between two data constructors with a +du_type_with_colon.m:023: colon. +du_type_with_colon.m:028: Error: attempt to define a data constructor named +du_type_with_colon.m:028: `:'/2, which is a sign that a typo has replaced the +du_type_with_colon.m:028: semicolon between two data constructors with a +du_type_with_colon.m:028: colon. diff --git a/tests/invalid/du_type_with_colon.m b/tests/invalid/du_type_with_colon.m new file mode 100644 index 000000000..a36642721 --- /dev/null +++ b/tests/invalid/du_type_with_colon.m @@ -0,0 +1,32 @@ +%---------------------------------------------------------------------------% +% vim: ts=4 sw=4 et ft=mercury +%---------------------------------------------------------------------------% +% +% The first typo below used to generate this confusing error message: +% +% du_type_with_colon.m:010: In the first argument of function symbol `:' of +% du_type_with_colon.m:010: the type `foo'/0: +% du_type_with_colon.m:010: error: the type `foo_a'/0 is undefined. +% du_type_with_colon.m:010: (Did you mean `foo'?) +% du_type_with_colon.m:011: In the second argument of function symbol `:' of +% du_type_with_colon.m:011: the type `foo'/0: +% du_type_with_colon.m:011: error: the type `foo_b'/0 is undefined. +% du_type_with_colon.m:011: (Did you mean `foo'?) +% + +:- module du_type_with_colon. + +:- interface. + +:- type foo + ---> foo_a + : foo_b. % This colon should be a SEMIcolon. + +:- type bar + ---> bar_a + : bar_b % This colon should be a SEMIcolon. + : bar_c. % This colon should be a SEMIcolon. + +% Export something to avoid a warning we don't want to test. +:- type dummy + ---> dummy.