[m-rev.] for review: report an error for obviously redundant functional dependencies

Julien Fischer jfischer at opturion.com
Sat Sep 20 14:33:03 AEST 2025


For review by anyone.

Question for reviewers: should these be warnings rather than errors?

The reference manual also needs to be updated, but I will do that separately.

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

Report an error for obviously redundant functional dependencies.

Report an error where the same type variable occurs in both the domain and
range of a functional dependency (e.g. A -> A or A, B -> A). Such dependencies
are redundant, but they are probably not something the programmer intended to
write.

compiler/parse_class.m:
    Report an error where a functional dependency has the same type variable
    in both its domain and range.

tests/invalid_nodepend/Mmakefile:
tests/invalid_nodepend/self_fundep.{m,err_exp}:
    Add a test case for the above error message.

Julien.

diff --git a/compiler/parse_class.m b/compiler/parse_class.m
index 6162d2add..a31934700 100644
--- a/compiler/parse_class.m
+++ b/compiler/parse_class.m
@@ -1086,7 +1086,32 @@ parse_fundep(VarSet, Term, Result) :-
         MaybeDomain = ok1(Domain),
         MaybeRange = ok1(Range)
     then
-        Result = ok1(ac_fundep(prog_fundep(Domain, Range), Context))
+        ( if
+            list_to_set(Domain, DomainSet),
+            list_to_set(Range, RangeSet),
+            set.intersect(DomainSet, RangeSet, CommonTypeVarSet),
+            set.is_non_empty(CommonTypeVarSet)
+        then
+            varset.coerce(VarSet, TVarSet),
+            set.to_sorted_list(CommonTypeVarSet, CommonTypeVars),
+            CommonTypeVarPieces = list.map(var_to_quote_piece(TVarSet),
+                CommonTypeVars),
+            CommonTypeVarsPieces = piece_list_to_color_pieces(color_subject,
+                "and", [], CommonTypeVarPieces),
+            Pieces = [
+                words("Error: type"),
+                words(choose_number(CommonTypeVars, "variable", "variables"))
+            ] ++
+            CommonTypeVarsPieces ++
+            color_as_incorrect([
+                words(choose_number(CommonTypeVars, "occurs", "occur")),
+                words("in both the domain and range of a functional
dependency.")
+            ]),
+            Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
+            Result = error1([Spec])
+        else
+            Result = ok1(ac_fundep(prog_fundep(Domain, Range), Context))
+        )
     else
         Specs = get_any_errors1(MaybeDomain) ++ get_any_errors1(MaybeRange),
         Result = error1(Specs)
diff --git a/tests/invalid_nodepend/Mmakefile b/tests/invalid_nodepend/Mmakefile
index 87b872a6f..d4ecb08f2 100644
--- a/tests/invalid_nodepend/Mmakefile
+++ b/tests/invalid_nodepend/Mmakefile
@@ -76,6 +76,7 @@ PROGS = \
     require_tailrec_invalid \
     reserved \
     reserved_type_name \
+    self_fundep \
     specified \
     subtype_invalid_supertype \
     subtype_syntax \
diff --git a/tests/invalid_nodepend/self_fundep.err_exp
b/tests/invalid_nodepend/self_fundep.err_exp
new file mode 100644
index 000000000..08dcf362a
--- /dev/null
+++ b/tests/invalid_nodepend/self_fundep.err_exp
@@ -0,0 +1,10 @@
+self_fundep.m:013: Error: type variable  [38;5;87m`A' [39;49m
 [38;5;203moccurs in both the domain and range [39;49m
+self_fundep.m:013:    [38;5;203mof a functional dependency. [39;49m
+self_fundep.m:015: Error: type variable  [38;5;87m`A' [39;49m
 [38;5;203moccurs in both the domain and range [39;49m
+self_fundep.m:015:    [38;5;203mof a functional dependency. [39;49m
+self_fundep.m:017: Error: type variable  [38;5;87m`B' [39;49m
 [38;5;203moccurs in both the domain and range [39;49m
+self_fundep.m:017:    [38;5;203mof a functional dependency. [39;49m
+self_fundep.m:019: Error: type variables  [38;5;87m`A' [39;49m and
 [38;5;87m`B' [39;49m  [38;5;203moccur in both the domain [39;49m
+self_fundep.m:019:    [38;5;203mand range of a functional dependency. [39;49m
+self_fundep.m:021: Error: type variables  [38;5;87m`A', [39;49m
 [38;5;87m`B' [39;49m and  [38;5;87m`C' [39;49m  [38;5;203moccur in
both the [39;49m
+self_fundep.m:021:    [38;5;203mdomain and range of a functional
dependency. [39;49m
diff --git a/tests/invalid_nodepend/self_fundep.m
b/tests/invalid_nodepend/self_fundep.m
new file mode 100644
index 000000000..729360578
--- /dev/null
+++ b/tests/invalid_nodepend/self_fundep.m
@@ -0,0 +1,21 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
+% Test that obviously redundant functional dependencies are reported as an
+% error.
+%---------------------------------------------------------------------------%
+
+:- module self_fundep.
+:- interface.
+
+:- type suppress_warnings ---> suppress_warnings.
+
+:- typeclass foo(A) <= (A -> A) where [].
+
+:- typeclass bar(A, B) <= (A -> A, B) where [].
+
+:- typeclass baaz(A, B) <= (A, B -> B) where [].
+
+:- typeclass quux(A, B) <= (A, B -> B, A) where [].
+
+:- typeclass thud(A, B, C) <= (A, B, C -> A, B, C) where [].


More information about the reviews mailing list