wybe
wybe copied to clipboard
Type checking fails with on equality of user-defined types that use a concrete instance of a generic type
Example:
pub type foo { foo(int, list(int)) }
The error produced is:
Error detected during type checking of module(s) test, test.foo
Type error in call to =, argument 1
Type error in call to =, argument 2
Just ran into this too, with incidentally the exact same test case of xyz(int, list(int))
Below is a dump of the members of the module just before typechecking.
It looks like it tries to automatically derive an implementation of =
for the structure type, but then it fails to type-check as I assume list(int) doesn't have an implementation of =
AFTER FLATTENING:
Module out_by_ref_directly_into_structure
representation : address
public submods :
public resources:
public procs : out_by_ref_directly_into_structure.=<0>
out_by_ref_directly_into_structure.out_by_ref_directly_into_structure<0>
out_by_ref_directly_into_structure.out_by_ref_directly_into_structure<1>
out_by_ref_directly_into_structure.~=<0>
imports : use wybe
use wybe.int
use wybe.list
resources :
procs :
= > public {test,inline} (0 calls)
0: =(#left:out_by_ref_directly_into_structure, #right:out_by_ref_directly_into_structure):
if {( foreign llvm icmp_uge(#left:!wybe.int, 0, ?tmp#0:!wybe.bool)
& testbool tmp#0:!wybe.bool)::
( out_by_ref_directly_into_structure(?#left#x, ?#left#y, #left)
& out_by_ref_directly_into_structure(?#right#x, ?#right#y, #right)
& =(#left#x, #right#x)
& =(#left#y, #right#y))
else::
fail
}
out_by_ref_directly_into_structure > public {inline} (0 calls)
0: out_by_ref_directly_into_structure(x:wybe.int, y:wybe.list(wybe.int), ?#result:out_by_ref_directly_into_structure):
foreign lpvm alloc(16, ?#rec:out_by_ref_directly_into_structure)
foreign lpvm mutate(#rec:out_by_ref_directly_into_structure, ?#rec:out_by_ref_directly_into_structure, 0, 1, 16, 0, x:wybe.int)
foreign lpvm mutate(#rec:out_by_ref_directly_into_structure, ?#rec:out_by_ref_directly_into_structure, 8, 1, 16, 0, y:wybe.list(wybe.int))
foreign llvm or(#rec:out_by_ref_directly_into_structure, 0, ?#result:out_by_ref_directly_into_structure)
out_by_ref_directly_into_structure > public {inline} (0 calls)
1: out_by_ref_directly_into_structure(?x:wybe.int, ?y:wybe.list(wybe.int), #result:out_by_ref_directly_into_structure):
pass
foreign lpvm access(#result, 0, 16, 0, ?x)
foreign lpvm access(#result, 8, 16, 0, ?y)
x > {inline} (0 calls)
0: x(#rec:out_by_ref_directly_into_structure, ?#result:wybe.int):
pass
foreign lpvm access(#rec, 0, 16, 0, ?#result)
x > {inline} (0 calls)
1: x(!#rec:out_by_ref_directly_into_structure, #field:wybe.int):
pass
foreign lpvm mutate(#rec:out_by_ref_directly_into_structure, ?#rec:out_by_ref_directly_into_structure, 0, 0, 16, 0, #field)
y > {inline} (0 calls)
0: y(#rec:out_by_ref_directly_into_structure, ?#result:wybe.list(wybe.int)):
pass
foreign lpvm access(#rec, 8, 16, 0, ?#result)
y > {inline} (0 calls)
1: y(!#rec:out_by_ref_directly_into_structure, #field:wybe.list(wybe.int)):
pass
foreign lpvm {noalias} mutate(#rec:out_by_ref_directly_into_structure, ?#rec:out_by_ref_directly_into_structure, 8, 0, 16, 0, #field)
~= > public {test,inline} (0 calls)
0: ~=(#left:out_by_ref_directly_into_structure, #right:out_by_ref_directly_into_structure):
~(=(#left, #right))
Kinda annoying that there is no pos
for this error, I guess since the =
implementation is generated internally so there's no obvious source position to attach to it?
Yep. It's a little bit annoying when there's no source pos.
Regardless, I believe the ultimate for this again is... Drum roll type classes.
We can fake it right now, though, by jerry-rigging our own type classes. Ala:
def {test} `=`(`eqX`{test}(X, X), left:list(X), right:list(X)) {
if { left = [?l | ?left] & right = [?right | ?r] ::
eqX(l, r)
left = right
| else ::
# simple test for constant constructors
# I forget the foreign proc right now...
}
}
This should generalise to any structure with no higher order members
One annoying point about the current end-user usage of such a test requires manual `=`
args, but you could hypothetically generate these automatically :)
Yes, exactly. I agree about the source position, but also the code for generating the equality predicate should not try to generate one in the first place when it won't type check.
The code James gave above is exactly the code that should be generated for equality when we do support type classes.
As a temporary fix for this we could check for equality for generic fields in the automatically generated =
procs. I know this isn't correct, but at least for now it's better than the annoying error message and requiring writing a stub =
every time there is a list field.