luau-lang / luau

A fast, small, safe, gradually typed embeddable scripting language derived from Lua
https://luau-lang.org
MIT License
3.8k stars 352 forks source link

Argument count mismatch on call rather than function #1226

Closed User9684 closed 2 months ago

User9684 commented 2 months ago

Hi, I was writing basic typed functions earlier and accidentally came across this, unsure if it's considered a bug or not, but it definitely seemed like a bug to me.

I've made two examples, one that has no issues and another that has a warning.

Example one, everything is typed correctly and there are no warnings as expected.

type Test1 = {
    Test: (self: Test1, requiredArg: string, optionalArg: string?) -> ()
}

local Test1Impl: Test1 = {} :: Test1
function Test1Impl:Test(requiredArg: string, optionalArg: string?) 
    print(self, requiredArg, optionalArg)
end

Test1Impl:Test("test")
Test1Impl:Test("test2", "test3")

Example two, the function is defined with an argument that does not exist on the type, leading to a warning.

type Test2 = {
    Test: (self: Test1, requiredArg: string) -> ()
}

local Test2Impl: Test2 = {} :: Test2
function Test2Impl:Test(requiredArg: string, optionalArg: string?) 
    print(self, requiredArg, optionalArg)
end

Test2Impl:Test("test")
Test2Impl:Test("test2", "test3")

Expected behavior: Warning shows up on the function definition stating that (self, arg1, arg2?) cannot be converted into (self, arg1) Actual behavior: Warning shows up on the second Test call saying that there are three arguments when expected only two.

Fireboltofdeath commented 2 months ago

Assigning (A, B?) -> C to (A) -> C is always valid as all invocations of (A) -> C are also valid invocations of (A, B?) -> C since there is guaranteed not to be a second argument. It is still probably worth having a warning on the function as the number of arguments are known, though.

Since you type casted Test2Impl to a different type, Luau has no idea that your "Test" function technically accepts a second argument, it only knows that Test2.Test does not accept a second argument and so it wouldn't be type safe to pass one.

aatxe commented 2 months ago

Yep, this is not a bug. The type of Test2Impl:Test is compatible with the type you gave it like @Fireboltofdeath explained, and the second call is correctly erroring based on the interface you typed the function at (saying that it does not have an optional argument).