ponyc icon indicating copy to clipboard operation
ponyc copied to clipboard

Can call constructors on generic if constraint is union (and get a compiler assertion failure)

Open jasoncarr0 opened this issue 3 years ago • 8 comments
trafficstars

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

jasoncarr0 avatar Apr 14 '22 02:04 jasoncarr0

The union type should not be constructible with create() feels more correct to me. But I've put only a little thought into it.

SeanTAllen avatar Apr 14 '22 12:04 SeanTAllen

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.

jasoncarr0 avatar Apr 14 '22 14:04 jasoncarr0

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?

SeanTAllen avatar Apr 14 '22 15:04 SeanTAllen

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.

ergl avatar Apr 14 '22 15:04 ergl

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()

jasoncarr0 avatar Apr 19 '22 17:04 jasoncarr0

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?

ergl avatar Apr 21 '22 08:04 ergl

Yup, the code can definitely be adjusted. What you're suggesting is option 2

jasoncarr0 avatar Apr 21 '22 14:04 jasoncarr0

We agreed in the sync call that extending the special case error that @ergl mentioned is the right fix.

jemc avatar Apr 26 '22 18:04 jemc