teal-language / tl

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

Allow `function(...: any)` to be compatable with `function(x: <some type>, y: <some type>, etc)` #781

Open Frityet opened 2 months ago

Frityet commented 2 months ago

Motivating example:

local interface ICreatable
    create: function(...: any): self
end

local record Person is ICreatable
    name: string
    age: integer
end

function Person:create(name: string, age: integer): Person
    return setmetatable({name = name, age = age}, { __index = Person })
end

Currently this fails because

type signature of 'create' does not match its declaration in Person: different number of input arguments: method and non-method are not the same type
hishamhm commented 2 months ago

Teal in general is pretty lax with bivariant function matching, so if we're going with bivariance for functions everywhere, then yes, ideally this should be accepted. (With the caveat of course that bivariant function matching is unsound by design — but a lot simpler to use in general...)

After all, this currently works without complaints:

local type FnType = function(...: any)

local f: FnType

f = function(name: string, age: integer)
end
hishamhm commented 2 months ago

...and this is a little trickier because generally we've been stricter about redeclarations of record functions. Which is, in general a good thing, because a function implementation not matching its forward-declarations done inside the record is usually a sign of a mistake somewhere.

However, here the "redeclaration" is implicit, because the function field was originally declared in an interface, and it is more likely that non-identical function types are used, as in your example. Gonna think a bit more about this!

That's good feedback, keep it coming!