crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.3k stars 1.61k forks source link

Ambiguous autocasts from unions not reported for assignments #10703

Open HertzDevil opened 3 years ago

HertzDevil commented 3 years ago

None of the following integer literals trigger an ambiguous autocast error:

class A
  @x : Int8 | UInt8 = 1
  @y : Int8 | UInt8

  def initialize
    @y = 2
    z : Int8 | UInt8 = 3

    w = uninitialized Int8 | UInt8
    w = 4
  end
end

A.new

def foo(x : Int8 | UInt8 = 5)
end

foo

On the other hand foo(5) triggers the error. Similar (lack of) errors can be done with enum types. This happens only since 0.35.0; previous versions will report can't restrict Int32 to Int8 | UInt8 or type must be (Int8 | UInt8), not (Int32 | Int8 | UInt8). This might be due to #9366.

In these cases the compiler chooses the first variant type of the normalized union, i.e. the type whose name comes first alphabetically, which would be Int8 in the above cases. For enums we have:

enum Foo
  X
end

enum Foe
  X
end

enum Fox
  X
end

a : Foo | Foe = :x # "Foo" > "Foe"
a.class            # => Foe

b : Foo | Fox = :x # "Foo" < "Fox"
b.class             # => Foo

This is certainly unexpected, so assignments like these should trigger an error unless that union already contains an exact match (e.g. Symbol for enums). The question is whether such a fix would constitute a post-1.0 breaking change.

straight-shoota commented 3 years ago

I would argue that the unexpected behaviour is potentially a cause for failure and thus legitimizes a bug-fix, even if it is a breaking change.