Mercury-Language/mercury

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.