[m-rev.] for review: report an error for typeclasses with no parameters

Julien Fischer jfischer at opturion.com
Wed Nov 4 17:00:37 AEDT 2015


The error message we produce for the bug #191 test case is not very good,
it refers to the wrapper procedure introduced for class methods -- I'm 
working on a change to fix this.  Also, ideally the compiler should not
produce the spurious warning for the new typeclass_no_params test case.

--------------

For review by anyone.

Report an error for a type class with no parameters.

The compiler was not rejecting typeclass declarations without any class
parameters, for example:

     :- typeclass foo where [].

Mercury requires typeclass declarations to have at least one class
parameter.

compiler/prog_io_typeclass.m:
     Emit an error if we encounter a typeclass declaration with no parameters.

tests/invalid/Mmakefile:
tests/invalid/typeclass_no_param.{m,err_exp:
     Add a regression test for the above.

tests/invalid/bug191.{m,err_exp}:
     Avoid having a typeclass with no parameters.

Julien.

diff --git a/compiler/prog_io_typeclass.m b/compiler/prog_io_typeclass.m
index 804537f..3f055fe 100644
--- a/compiler/prog_io_typeclass.m
+++ b/compiler/prog_io_typeclass.m
@@ -307,25 +307,37 @@ parse_unconstrained_class(ModuleName, NameTerm, TVarSet, Context, SeqNum,
      (
          MaybeClassName = ok2(ClassName, TermVars0),
          list.map(term.coerce, TermVars0, TermVars),
-        ( if
-            term.term_list_to_var_list(TermVars, Vars),
-            list.sort_and_remove_dups(TermVars, SortedTermVars),
-            list.length(SortedTermVars, NumSortedTermVars),
-            list.length(TermVars, NumTermVars),
-            NumSortedTermVars = NumTermVars
-        then
-            % XXX Would this be a better context?
-            % Context = get_term_context(NameTerm),
-            TypeClassInfo = item_typeclass_info(ClassName, Vars, [], [],
-                class_interface_abstract, TVarSet, Context, SeqNum),
-            MaybeTypeClassInfo = ok1(TypeClassInfo)
-        else
-            Pieces = [words("Error: expected distinct variables"),
-                words("as class parameters."), nl],
-            % XXX Would Context be better than get_term_context(NameTerm)?
+        (
+            TermVars = [],
+            Pieces = [
+                words("Error: typeclass declarations require"),
+                words("at least one class parameter.")
+            ],
              Spec = error_spec(severity_error, phase_term_to_parse_tree,
                  [simple_msg(get_term_context(NameTerm), [always(Pieces)])]),
              MaybeTypeClassInfo = error1([Spec])
+        ;
+            TermVars = [_ | _],
+            ( if
+                term.term_list_to_var_list(TermVars, Vars),
+                list.sort_and_remove_dups(TermVars, SortedTermVars),
+                list.length(SortedTermVars, NumSortedTermVars),
+                list.length(TermVars, NumTermVars),
+                NumSortedTermVars = NumTermVars
+            then
+                % XXX Would this be a better context?
+                % Context = get_term_context(NameTerm),
+                TypeClassInfo = item_typeclass_info(ClassName, Vars, [], [],
+                    class_interface_abstract, TVarSet, Context, SeqNum),
+                MaybeTypeClassInfo = ok1(TypeClassInfo)
+            else
+                Pieces = [words("Error: expected distinct variables"),
+                    words("as class parameters."), nl],
+                % XXX Would Context be better than get_term_context(NameTerm)?
+                Spec = error_spec(severity_error, phase_term_to_parse_tree,
+                    [simple_msg(get_term_context(NameTerm), [always(Pieces)])]),
+                MaybeTypeClassInfo = error1([Spec])
+            )
          )
      ;
          MaybeClassName = error2(Specs),
diff --git a/tests/invalid/Mmakefile b/tests/invalid/Mmakefile
index 06db53a..5c56d34 100644
--- a/tests/invalid/Mmakefile
+++ b/tests/invalid/Mmakefile
@@ -247,6 +247,7 @@ SINGLEMODULE= \
  	typeclass_mode_2 \
  	typeclass_mode_3 \
  	typeclass_mode_4 \
+	typeclass_no_param \
  	typeclass_test_1 \
  	typeclass_test_10 \
  	typeclass_test_11 \
diff --git a/tests/invalid/bug191.err_exp b/tests/invalid/bug191.err_exp
index 5138762..3caeb3d 100644
--- a/tests/invalid/bug191.err_exp
+++ b/tests/invalid/bug191.err_exp
@@ -1,6 +1,6 @@
  bug191.m:020: In clause for
-bug191.m:020:   `'ClassMethod_for_bug191__foo________bug191__baz_2'(in,
-bug191.m:020:   out((bug191.a)))':
-bug191.m:020:   mode error: argument 2 did not get sufficiently instantiated.
-bug191.m:020:   Final instantiatedness of `HeadVar__2' was `ground',
+bug191.m:020:   `'ClassMethod_for_bug191__foo____int__arity0______bug191__baz_3'(in,
+bug191.m:020:   in, out((bug191.a)))':
+bug191.m:020:   mode error: argument 3 did not get sufficiently instantiated.
+bug191.m:020:   Final instantiatedness of `HeadVar__3' was `ground',
  bug191.m:020:   expected final instantiatedness was `bound(bug191.a(ground))'.
diff --git a/tests/invalid/bug191.m b/tests/invalid/bug191.m
index 3076dc5..0c06936 100644
--- a/tests/invalid/bug191.m
+++ b/tests/invalid/bug191.m
@@ -16,17 +16,17 @@

  :- inst a ---> a(ground).

-:- typeclass foo where [pred baz(int::in, foo::out(a)) is det].
-:- instance foo where [pred(baz/2) is bar].
+:- typeclass foo(T) where [pred baz(T::in, int::in, foo::out(a)) is det].
+:- instance foo(int) where [pred(baz/3) is bar].

  :- pred foo(foo::in(a), int::out) is det.
  foo(a(I), I).

  % should be bar(int::in, foo::out(a))
-:- pred bar(int::in, foo::out) is det.
-bar(_S, b("GOTCHA")).
+:- pred bar(int::in, int::in, foo::out) is det.
+bar(_, _S, b("GOTCHA")).

  main(!IO) :-
-    baz(42, F),
+    baz(561, 42, F),
      foo(F, I),
      print(I, !IO), nl(!IO).
diff --git a/tests/invalid/typeclass_no_param.err_exp b/tests/invalid/typeclass_no_param.err_exp
new file mode 100644
index 0000000..6605c23
--- /dev/null
+++ b/tests/invalid/typeclass_no_param.err_exp
@@ -0,0 +1,5 @@
+typeclass_no_param.m:004: Warning: interface for module `typeclass_no_param'
+typeclass_no_param.m:004:   does not export anything.
+typeclass_no_param.m:007: Error: typeclass declarations require at least one
+typeclass_no_param.m:007:   class parameter.
+For more information, recompile with `-E'.
diff --git a/tests/invalid/typeclass_no_param.m b/tests/invalid/typeclass_no_param.m
new file mode 100644
index 0000000..d11b141
--- /dev/null
+++ b/tests/invalid/typeclass_no_param.m
@@ -0,0 +1,7 @@
+% rotd-2015-11-04 and before(!) did not report an error for typeclasses with no
+% parameters.
+
+:- module typeclass_no_param.
+:- interface.
+
+:- typeclass foo where [].



More information about the reviews mailing list