Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metamethod type not checked in metatable definition #633

Open
bjornbm opened this issue Feb 19, 2023 · 3 comments
Open

Metamethod type not checked in metatable definition #633

bjornbm opened this issue Feb 19, 2023 · 3 comments
Labels
bug Something isn't working

Comments

@bjornbm
Copy link

bjornbm commented Feb 19, 2023

Hi, is the below code supposed to pass the typechecker? (The type of __add in rec_mt does not have the correct type for metamethod __add in Rec.)

local type Rec = record
   metamethod __add: function(Rec, Rec): Rec
end

local rec_mt: metatable<Rec>
rec_mt = {
   __add = function(_a: Rec, _b: number): number  -- Type error??
      return 1
   end,
}

local r: Rec = setmetatable({ }, rec_mt)
print(r + r)      -- prints 1

What about this one? (__add is not defined in rec_mt)

local type Rec = record
   metamethod __add: function(Rec, Rec): Rec
end

local rec_mt: metatable<Rec> = {}  -- __add is not defined

local r: Rec = setmetatable({ }, rec_mt)
@hishamhm hishamhm added the bug Something isn't working label Feb 27, 2023
@hishamhm
Copy link
Member

hishamhm commented Feb 27, 2023

The second case (__add is not defined in rec_mt) is unlikely to be supported soon (the compiler currently does not do nil checks in general), but the first one sounds like it should have been checked — (note to self: this may require some adding custom code for checking setmetatable arguments, similarly to how we handle pcall, etc.).

@bjornbm
Copy link
Author

bjornbm commented Mar 1, 2023

OK, so my understanding for the second case: the record definition defines what keys/values are valid, but not that they are defined (or more generally perhaps the values may be nil, since nil is a valid value of every type). What is checked is that values for the defined keys have the right type, and that no other keys are added to the record.

@bjornbm
Copy link
Author

bjornbm commented Mar 1, 2023

For the first case, I guess the safest place to check is at setmetatable.

local r: Rec = setmetatable({ }, rec_mt)

I assume the inferred type of { } here is Rec, thanks to the assignment to r: Rec? And thus rec_mt must be metatable<Rec>, which in turn should satisfy the metamethods of Rec?

You could (should?) also check at the assignment to rec_mt that it satisfies the metamethods of Rec, since rec_mt is declared as a metatable<Rec>.

Currently it seems the metatable<Rec> type does nothing at all:

  1. The contents of rec_mt are not checked versus Recs metamethods.
  2. setmetatable does not check that rec_mt is a metatable<Rec> (it will accept any table, including of type metatable<SomeOtherType>).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants