-
Notifications
You must be signed in to change notification settings - Fork 47
Description
Right now, we allow variadic type expansion anywhere in a type expression. This leads to potential unsoundness where Variadic<T> are not properly unwrapped:
local t --- @type int...
local a, b, c, d = t
-- `a`, `b`, `c`, `d` are all `int`.
local t --- @type [int..., string]
local a, b, c, d = t[1]
-- `a`, `b`, `c`, `d` are all `int`.
local e = t[2]
-- `e` is `string`I'd like to fix this.
There are two approaches we could take:
-
disallow variadic expansion in places where it can't be handled.
Specifically, using
T...will be allowed:- in last element of a tuple, i.e.
[int, string...], - in generic arguments, i.e.
Foo<T...>(semantics of this needs revision, but I'll leave it for later), - on top level of function/operator parameters and return values, i.e.
@param ... T....
The rest will be reported as an error.
- in last element of a tuple, i.e.
-
handle variadics everywhere, with default behavior to extract the first value.
This will make variadic expansion a no-op outside of the cases mentioned above.
Specifically,
int...will be treated asint,T...will be treated asT, and so on.
I like option 1. Option 2 is more error prone, and can lead to unexpected behavior. For example, consider this:
--- @generic T
--- @param ... T...
--- @return [T..., table]
function foo(...) end
local x = foo(1, "")What should the type of x be? Is it [integer, string, table], [integer, table], or [integer, string]? Current implementation derives [integer, string], but is it reasonable?