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.
-
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 as int, T... will be treated as T, 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?
Right now, we allow variadic type expansion anywhere in a type expression. This leads to potential unsoundness where
Variadic<T>are not properly unwrapped: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:[int, string...],Foo<T...>(semantics of this needs revision, but I'll leave it for later),@param ... T....The rest will be reported as an error.
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:
What should the type of
xbe? Is it[integer, string, table],[integer, table], or[integer, string]? Current implementation derives[integer, string], but is it reasonable?