teal-language / tl

The compiler for Teal, a typed dialect of Lua
MIT License
2.14k stars 107 forks source link

cannot match types if union is behind a type alias #787

Open Frityet opened 1 month ago

Frityet commented 1 month ago
local type nilable<T> = T | nil
local function divide(a: number, b: number): nilable<number>, nilable<string>
    if b == 0 then
        return nil, "division by zero"
    end
    return a / b, nil
end

local x, err = divide(10, 2)
if err is nil and not x is nil then
    print("Result: "..x)
else
    print("Error: "..err)
end

Results in x being inferred as nil, and err being inferred as nilable<string>. I am using the next branch.

hishamhm commented 1 month ago

Can you reproduce this with types other than nil? Teal does not support discriminating nil in unions, so you cannot implement nil-strictness by hand, it will need to be added to the language eventually.

hishamhm commented 1 month ago

I've confirmed this misbehavior with a non-nil-related minimized example

local type Maybe<T> = T | boolean
local x: Maybe<string>
if not x is boolean then
    print("Result: "..x)
end
hishamhm commented 6 days ago

Note to self: the solution to this bug is that union types need to be handled as generic types the same way as functions and records currently are — that is, the type object for the union needs to store type variables, so that resolve_decl_into_nominal can run match_typevals on it correctly — my current plan is to solve this by generalizing all generic types into a single internal $\Lambda$ type, so that we can do beta-reduction at the type level like $(Λα.t^α)(T) \rightarrow t[α := T]$.