ponyc
ponyc copied to clipboard
Can call constructors on generic if constraint is union (and get a compiler assertion failure)
primitive A
primitive B
actor Main
new create(env: Env) =>
let bad = Generic[(A | B)].get()
env.out.print(match bad
| let _: A => "D"
| let _: B => "B"
end)
interface val Default
new val create()
class Generic[T: (Default val | None val)]
let x: T = T.create()
fun get(): T =>
x
https://playground.ponylang.io/?gist=60bfbb2f304c0ad519cf0d68dc9243c2
Results in:
/tmp/cirrus-ci-build/src/libponyc/ast/ast.c:1831: ast_error_frame: Assertion ast != NULL failed.
This is a bug in one of two ways:
- The union type should not be constructible with create() OR
- The union instantiation should be correctly rejected as the constraint is constructible
The union type should not be constructible with create() feels more correct to me. But I've put only a little thought into it.
Yeah, it's not perfectly straightforward. I worded it incorrectly, what it really is is: The instantiation of the type, which is in the union constraint, should [not] be constructible.
If the second check were correct, then any such generic would be concrete.
I think we are saying the same thing. It should fail with an error that this generic requires T to be constructable but type unions aren't. Correct?
Isn't this related to #4073, in that:
If a method call is valid for all members of a union, it should be possible to call on the union.
If we consider the above to be correct, then it's not that we're "creating" an union type, rather, we're calling create on whatever type the union is at the time we're instantiating the generic type.
It's not quite the same @ergl , but similar idea. Under option 2, the union is instantiated with a single concrete type which has a create method()
Yeah, I'm not sure how to go about fixing this. If you remove the | None val) from the type constraint on Generic, the error message is "a constructable constraint can only be fulfilled by a concrete type argument". Perhaps we should try to have the same error in this case?
Yup, the code can definitely be adjusted. What you're suggesting is option 2
We agreed in the sync call that extending the special case error that @ergl mentioned is the right fix.