tl
tl copied to clipboard
Integer doesn't behave as a subtype of number when used inside generic signatures - "got integer, expected number"
The integer is usually accepted where number is required (but not vice-versa), the former being a subtype of the latter per the docs:
local f = function(x: number): number
return x
end
local g = function(x: integer): integer
return x
end
local ok = f(g(1)) -- integer correctly accepted as number
local not_ok = g(f(1)) -- number correctly rejected as integer with "got number, expected integer"
But, when used with generics:
local type Identity = record<T>
v: T
end
local add_id = function(x: Identity<number>, y: Identity<number>): number
return x.v + y.v
end
local num1: Identity<integer> = {v=1}
local num2: Identity<integer> = {v=2}
local num_sum = add_id(num1, num2) -- integer rejected as number with "type parameter <number>: got integer, expected number"
(Poking at this through type constraints using function<I is Identity<number>>(x: I, y: I): number, which instead throws given type Identity<integer> does not satisfy Identity<number> constraint in type variable I, and function<N is number>(x: Identity<N>, y: Identity<N>): number throws "expected an interface".)
The problem with allowing it is that one can break the types.
Add a x.v = 2.5 to the add_id function and suddenly the first Identity<integer> you passed to it becomes an actual Identity<number>
passing an integer to a function that expects a number doesn't run into this because the function has no way to overwrite the original value, it only works on a copied version of it after all.
( https://teal-playground.netlify.app/?c=bG9jYWwgdHlwZSBJZGVudGl0eSA9IHJlY29yZDxUPgoJdjogVAplbmQKCmxvY2FsIGFkZF9pZCA9IGZ1bmN0aW9uKHg6IElkZW50aXR5PG51bWJlcj4sIHk6IElkZW50aXR5PG51bWJlcj4pOiBudW1iZXIKCXgudiA9IDIuNQogICAgcmV0dXJuIHgudiArIHkudgplbmQKCmxvY2FsIG51bTE6IElkZW50aXR5PGludGVnZXI%2BID0ge3Y9MX0KbG9jYWwgbnVtMjogSWRlbnRpdHk8aW50ZWdlcj4gPSB7dj0yfQpwcmludChudW0xLnYpCmxvY2FsIG51bV9zdW0gPSBhZGRfaWQobnVtMSBhcyBJZGVudGl0eTxudW1iZXI%2BLCBudW0yIGFzIElkZW50aXR5PG51bWJlcj4pCnByaW50KG51bTEudik%3D )