Skip to content

Commit ac26102

Browse files
committed
generic tests
1 parent 265cf48 commit ac26102

1 file changed

Lines changed: 178 additions & 0 deletions

File tree

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
-- Bug #4: Method calls on values returned from generic constructors
2+
-- "type symbol : nil cannot be called"
3+
--
4+
-- When a generic function returns an object with a metatable,
5+
-- calling methods on the result produces "nil cannot be called".
6+
-- ============================================================
7+
-- BASELINE: metatable methods work on non-generic constructor
8+
-- ============================================================
9+
analyze[[
10+
local Foo = {}
11+
Foo.__index = Foo
12+
type Foo.@Name = "Foo"
13+
type Foo.@SelfArgument = {
14+
["value"] = number,
15+
@MetaTable = Foo,
16+
}
17+
18+
function Foo:GetValue(): number
19+
return self.value
20+
end
21+
22+
local function new_foo(): Foo.@SelfArgument
23+
return setmetatable({value = 42} as Foo.@SelfArgument, Foo)
24+
end
25+
26+
local f = new_foo()
27+
local v = f:GetValue()
28+
attest.equal(v, _ as number)
29+
]]
30+
-- ============================================================
31+
-- Test A: generic constructor, method call on local variable
32+
-- ============================================================
33+
analyze[[
34+
local Foo = {}
35+
Foo.__index = Foo
36+
type Foo.@Name = "Foo"
37+
type Foo.@SelfArgument = {
38+
["value"] = number,
39+
@MetaTable = Foo,
40+
}
41+
42+
function Foo:GetValue(): number
43+
return self.value
44+
end
45+
46+
local function new_foo<|T: any|>(): Foo.@SelfArgument
47+
return setmetatable({value = 42} as Foo.@SelfArgument, Foo)
48+
end
49+
50+
local f = new_foo<|string|>()
51+
local v = f:GetValue()
52+
attest.equal(v, _ as number)
53+
]]
54+
-- ============================================================
55+
-- Test B: generic constructor, method call without explicit type args
56+
-- ============================================================
57+
analyze[[
58+
local Foo = {}
59+
Foo.__index = Foo
60+
type Foo.@Name = "Foo"
61+
type Foo.@SelfArgument = {
62+
["value"] = number,
63+
@MetaTable = Foo,
64+
}
65+
66+
function Foo:GetValue(): number
67+
return self.value
68+
end
69+
70+
local function new_foo<|T: any|>(): Foo.@SelfArgument
71+
return setmetatable({value = 42} as Foo.@SelfArgument, Foo)
72+
end
73+
74+
local f = new_foo()
75+
local v = f:GetValue()
76+
attest.equal(v, _ as number)
77+
]]
78+
-- ============================================================
79+
-- Test C: generic constructor, inline method call (no local)
80+
-- ============================================================
81+
analyze[[
82+
local Foo = {}
83+
Foo.__index = Foo
84+
type Foo.@Name = "Foo"
85+
type Foo.@SelfArgument = {
86+
["value"] = number,
87+
@MetaTable = Foo,
88+
}
89+
90+
function Foo:GetValue(): number
91+
return self.value
92+
end
93+
94+
local function new_foo<|T: any|>(): Foo.@SelfArgument
95+
return setmetatable({value = 42} as Foo.@SelfArgument, Foo)
96+
end
97+
98+
local v = new_foo<|string|>():GetValue()
99+
attest.equal(v, _ as number)
100+
]]
101+
-- ============================================================
102+
-- Test D: non-generic constructor, inline method call
103+
-- ============================================================
104+
analyze[[
105+
local Foo = {}
106+
Foo.__index = Foo
107+
type Foo.@Name = "Foo"
108+
type Foo.@SelfArgument = {
109+
["value"] = number,
110+
@MetaTable = Foo,
111+
}
112+
113+
function Foo:GetValue(): number
114+
return self.value
115+
end
116+
117+
local function new_foo(): Foo.@SelfArgument
118+
return setmetatable({value = 42} as Foo.@SelfArgument, Foo)
119+
end
120+
121+
local v = new_foo():GetValue()
122+
attest.equal(v, _ as number)
123+
]]
124+
-- ============================================================
125+
-- Test E: generic constructor using typed local instead of as-cast
126+
-- (the pattern from our reactive project)
127+
-- ============================================================
128+
analyze[[
129+
local Foo = {}
130+
Foo.__index = Foo
131+
type Foo.@Name = "Foo"
132+
type Foo.@SelfArgument = {
133+
["value"] = number,
134+
@MetaTable = Foo,
135+
}
136+
137+
function Foo:GetValue(): number
138+
return self.value
139+
end
140+
141+
local function new_foo<|T: any|>(): Foo.@SelfArgument
142+
local self: Foo.@SelfArgument = {
143+
value = 42,
144+
}
145+
setmetatable(self, Foo)
146+
return self
147+
end
148+
149+
local f = new_foo<|string|>()
150+
local v = f:GetValue()
151+
attest.equal(v, _ as number)
152+
]]
153+
-- ============================================================
154+
-- Test F: exported through module table
155+
-- ============================================================
156+
analyze[[
157+
local Foo = {}
158+
Foo.__index = Foo
159+
type Foo.@Name = "Foo"
160+
type Foo.@SelfArgument = {
161+
["value"] = number,
162+
@MetaTable = Foo,
163+
}
164+
165+
function Foo:GetValue(): number
166+
return self.value
167+
end
168+
169+
local M = {}
170+
local function new_foo<|T: any|>(): Foo.@SelfArgument
171+
return setmetatable({value = 42} as Foo.@SelfArgument, Foo)
172+
end
173+
M.new = new_foo
174+
175+
local f = M.new<|string|>()
176+
local v = f:GetValue()
177+
attest.equal(v, _ as number)
178+
]]

0 commit comments

Comments
 (0)