Exisential typeclass constraints on data type members name resolution problems when handling multiple modules with circular dependencies.
C4Cypher opened this issue · 1 comments
I've written multiple modules with multiple circular type dependencies ... and I've run into a strange visibility issue with one of my type classes when I try to implement said typeclass into it's own module. The problem exhibits when I try to constrain an existentially qualified member of a data type.
In my current project at my Mad Hatter project (public Github repo), I've run into an odd case where I have multiple modules describing types in a manner that requires multiple circular dependencies between modules.
Attempting to constrain an existentially typed member to a data type is causing strange inter-module typeclass visibility issues.
I'll attempt to describe the dependencies in question.
Context
mh_term.m
defines :- type mh_term.
, an enum type that relies on relation types and rule types. Imports mh_relation and mh_rule.
mh_relation.m
defines :- type proc_relation.
enum type tree, which are implemented as array(mh_term)
s, said relation implements the index(T)
typeclass defined in mh_index.m, Imports mh_term and mh_index
mh_rule.m
defines :- type proc_rule.
, defined as follows
:- type proc_rule
---> clause_rule(proc_relation, list(literal)) %literal is an equivalence type of a subtype of mh_term
; some [T] primitive_rule(function_relation, T) => primitive(T). %function_relation is a subtype of proc_relation
It imports mh_term, mh_relation and mh_primitive.
And finally,
mh_primitive.m
which defines the primitive(T)
typeclass, whose interface uses subtypes of mh_term
and proc_relation
in it's where clause, although experimentation has shown that I could not import anything and have an empty where clause and I'd still run into the problem
It imports both mh_term and mh_relation
Problem
Attempting to mmc --make libmh_rule
will cause the following compilation error
Making Mercury\cs\mh_relation.c
Mercury\int2s\mh_rule.int2:008: In declaration for type `mh_rule.proc_rule'/0:
Mercury\int2s\mh_rule.int2:008: error: the type class
Mercury\int2s\mh_rule.int2:008: `mh_primitive.primitive'/1 does not exist.
** Error making `Mercury\cs\mh_relation.c'.
I can change the class constraint on proc_rule
to enum(T)
and it will compile, however, trying to constrain some [T]
in proc_rule
to any typeclass defined in another local module, even an empty :- typeclass foo(T) where [].
in an empty foo.m
module causes the above error.
If I remove all imports to any module that imports mh_relation
in mh_rule
then primitive(T)
becomes visible and it compiles.
I tried to replicate the issue with dummy types. foo.m
bar.m
baz.m
... and I couldn't reproduce the error message, I might try again if I have a better understanding of what is going on, or if I run into the issue again.
I'm not exactly sure what is going on here, but my gut tells me it has something to do with the deeply nested circular dependencies I'm using, or some issue with the subclassing, but going import by import, commenting it out (and removing all references to imported types in the process) .. to try to isolate what causes primitive(T)
to lose visibility is only leading me in circles. I lost the trail of dependency somewhere in mh_relation.m
Fix Action/Workaround
Ditching mh_primitive.m entirely and moving the declaration of typeclass primtive/1
to mh_term.m resolves the visibility issue in a manner that I can happily work with. I just wanted to document the issue and, if it's a known thing, I'd love to understand what limitation was causing it. Please let me know if I can assist reproducing the issue.
I've changed my implementation to the point where even the workaround of elevating my typeclass to a shallower module in the dependency isn't necessary. I wanted to document that this occurred. It would be nice to know why this happened, but at this time I'm not going to waste other people's time on an issue that is not obstructing me. Thank you for continuing to work on this language.