Skip to content

Conversation

HertzDevil
Copy link
Contributor

Resolves #12616.

The following snippet, which does not compile, complains about an invalid union type:

def foo(x : Array | String) # Error: can't use Array(T) in unions yet, use a more specific type
end

foo(1)

But this union is permitted here, because def parameter restrictions do not name an actual type of a variable:

foo([1] || "a")        # okay
foo(['x', 2.3] || "a") # okay

The compiler already knows that there is a "no overload matches" error here. However, while producing the error message, the compiler attempts to resolve the Array type in order to show which argument types are not covered by the parameter restriction. This lookup is allowed to fail, but it should never raise, otherwise the use a more specific type error prevails, as shown above. It is up to other places in the compiler to reject union types that cannot be stored, e.g. instance variable declarations.

Some other uses of Crystal::Type#lookup_type? are more subtle. For example, overload ordering between Generic and Path nodes calls this method:

def foo(x : Array(Array | String)) # Error: can't use Array(T) in unions yet, use a more specific type
end

# no compilation error if this overload is deleted
def foo(y : Int32)
end

foo(["a", [1]])

The first overload is now ordered before the second overload. (This is a simplified rule that happens to work for common uses of generics with free variables, and is not 100% correct.)

@HertzDevil HertzDevil added kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler:semantic labels Aug 29, 2025
@HertzDevil HertzDevil marked this pull request as draft August 30, 2025 05:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler:semantic

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Confusing error message when attempting to log types which can't be stored in a Metadata::Value

1 participant