Skip to content

Commit 8e1ec50

Browse files
committed
infer by if x and x.y then
1 parent 999c5dd commit 8e1ec50

File tree

2 files changed

+109
-104
lines changed

2 files changed

+109
-104
lines changed

script/vm/runner.lua

Lines changed: 91 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,21 @@ mt.index = 1
2222
---@field node? vm.node
2323
---@field object? parser.object
2424
---@field name? string
25+
---@field tag? string
2526
---@field copy? boolean
2627
---@field ref1? vm.runner.step
2728
---@field ref2? vm.runner.step
2829

29-
---@param filter parser.object
30-
---@param pos integer
31-
function mt:_compileNarrowByFilter(filter, pos)
30+
---@param filter parser.object
31+
---@param outStep vm.runner.step
32+
---@param blockStep vm.runner.step
33+
function mt:_compileNarrowByFilter(filter, outStep, blockStep)
3234
if not filter then
3335
return
3436
end
3537
if filter.type == 'paren' then
3638
if filter.exp then
37-
self:_compileNarrowByFilter(filter.exp, pos)
39+
self:_compileNarrowByFilter(filter.exp, outStep, blockStep)
3840
end
3941
return
4042
end
@@ -48,13 +50,14 @@ function mt:_compileNarrowByFilter(filter, pos)
4850
if exp.type == 'getlocal' and exp.node == self.loc then
4951
self.steps[#self.steps+1] = {
5052
type = 'truly',
51-
pos = pos,
52-
order = 2,
53+
pos = filter.finish,
54+
ref1 = outStep,
5355
}
5456
self.steps[#self.steps+1] = {
5557
type = 'falsy',
56-
pos = pos,
57-
order = 4,
58+
copy = true,
59+
pos = filter.finish,
60+
ref1 = blockStep,
5861
}
5962
end
6063
end
@@ -65,8 +68,8 @@ function mt:_compileNarrowByFilter(filter, pos)
6568
return
6669
end
6770
if filter.op.type == 'and' then
68-
self:_compileNarrowByFilter(filter[1], pos)
69-
self:_compileNarrowByFilter(filter[2], pos)
71+
self:_compileNarrowByFilter(filter[1], outStep, blockStep)
72+
self:_compileNarrowByFilter(filter[2], outStep, blockStep)
7073
end
7174
if filter.op.type == '=='
7275
or filter.op.type == '~=' then
@@ -86,28 +89,30 @@ function mt:_compileNarrowByFilter(filter, pos)
8689
self.steps[#self.steps+1] = {
8790
type = 'remove',
8891
name = exp.type,
89-
pos = pos,
90-
order = 2,
92+
pos = filter.finish,
93+
ref1 = outStep,
9194
}
9295
self.steps[#self.steps+1] = {
9396
type = 'as',
9497
name = exp.type,
95-
pos = pos,
96-
order = 4,
98+
copy = true,
99+
pos = filter.finish,
100+
ref1 = blockStep,
97101
}
98102
end
99103
if filter.op.type == '~=' then
100104
self.steps[#self.steps+1] = {
101105
type = 'as',
102106
name = exp.type,
103-
pos = pos,
104-
order = 2,
107+
pos = filter.finish,
108+
ref1 = outStep,
105109
}
106110
self.steps[#self.steps+1] = {
107111
type = 'remove',
108112
name = exp.type,
109-
pos = pos,
110-
order = 4,
113+
copy = true,
114+
pos = filter.finish,
115+
ref1 = blockStep,
111116
}
112117
end
113118
end
@@ -116,13 +121,14 @@ function mt:_compileNarrowByFilter(filter, pos)
116121
if filter.type == 'getlocal' and filter.node == self.loc then
117122
self.steps[#self.steps+1] = {
118123
type = 'falsy',
119-
pos = pos,
120-
order = 2,
124+
pos = filter.finish,
125+
ref1 = outStep,
121126
}
122127
self.steps[#self.steps+1] = {
123128
type = 'truly',
124-
pos = pos,
125-
order = 4,
129+
copy = true,
130+
pos = filter.finish,
131+
ref1 = blockStep,
126132
}
127133
end
128134
end
@@ -145,80 +151,56 @@ function mt:_compileBlock(block)
145151
---@type vm.runner.step[]
146152
local finals = {}
147153
for _, childBlock in ipairs(block) do
148-
if #childBlock > 0 then
149-
local initState = {
150-
type = 'save',
151-
copy = true,
152-
pos = childBlock.start,
153-
order = 1,
154-
}
155-
local outState = {
156-
type = 'save',
157-
copy = true,
158-
pos = childBlock.start,
159-
order = 2,
160-
}
161-
local filterState = {
162-
type = 'save',
163-
copy = true,
164-
pos = childBlock.start,
165-
order = 3,
166-
}
167-
self.steps[#self.steps+1] = initState
168-
self.steps[#self.steps+1] = outState
169-
self.steps[#self.steps+1] = filterState
170-
self.steps[#self.steps+1] = {
171-
type = 'load',
172-
ref1 = outState,
173-
pos = childBlock[1].start - 1,
174-
order = 1,
175-
}
176-
self.steps[#self.steps+1] = {
177-
type = 'load',
178-
ref1 = initState,
179-
pos = childBlock[1].start - 1,
180-
order = 3,
181-
}
182-
self:_compileNarrowByFilter(childBlock.filter, childBlock[1].start - 1)
183-
if childBlock.returns then
184-
self.steps[#self.steps+1] = {
185-
type = 'load',
186-
ref1 = outState,
187-
pos = childBlock.finish,
188-
order = 1,
189-
}
190-
else
191-
local finalState = {
192-
type = 'save',
193-
pos = childBlock.finish,
194-
order = 1,
195-
}
196-
finals[#finals+1] = finalState
197-
self.steps[#self.steps+1] = finalState
198-
self.steps[#self.steps+1] = {
199-
type = 'load',
200-
ref1 = outState,
201-
pos = childBlock.finish,
202-
order = 2,
203-
}
204-
end
154+
local outStep = {
155+
type = 'save',
156+
tag = 'out',
157+
copy = true,
158+
pos = block.start,
159+
order = 1,
160+
}
161+
self.steps[#self.steps+1] = outStep
162+
local blockStep = {
163+
type = 'load',
164+
tag = 'block',
165+
copy = true,
166+
ref = outStep,
167+
pos = childBlock.start,
168+
order = 2,
169+
}
170+
self.steps[#self.steps+1] = blockStep
171+
self:_compileNarrowByFilter(childBlock.filter, outStep, blockStep)
172+
if not childBlock.returns then
173+
finals[#finals+1] = blockStep
205174
end
175+
self.steps[#self.steps+1] = {
176+
type = 'load',
177+
tag = 'final',
178+
ref1 = outStep,
179+
pos = childBlock.finish,
180+
order = 1,
181+
}
206182
end
207183
for i, final in ipairs(finals) do
208184
self.steps[#self.steps+1] = {
209185
type = 'merge',
210-
ref1 = final,
186+
ref2 = final,
211187
pos = block.finish,
212188
order = i,
213189
}
214190
end
215191
end
216192

217193
if block.type == 'function' then
194+
self.steps[#self.steps+1] = {
195+
type = 'load',
196+
pos = block.start,
197+
order = 1,
198+
}
218199
local savePoint = {
219-
type = 'save',
220-
copy = true,
221-
pos = block.start,
200+
type = 'save',
201+
copy = true,
202+
pos = block.start,
203+
order = 2,
222204
}
223205
self.steps[#self.steps+1] = savePoint
224206
self.steps[#self.steps+1] = {
@@ -286,34 +268,52 @@ end
286268

287269
---@param callback fun(src: parser.object, node: vm.node)
288270
function mt:launch(callback)
289-
local node = vm.getNode(self.loc):copy()
271+
local topNode = vm.getNode(self.loc):copy()
272+
---@type vm.runner.step
273+
local context
290274
for _, step in ipairs(self.steps) do
275+
local node = (step.ref1 and step.ref1.node)
276+
or (context and context.node)
277+
or topNode
291278
if step.copy then
292279
node = node:copy()
280+
if context then
281+
context.node = node
282+
end
293283
end
294284
if step.type == 'truly' then
295285
node:setTruly()
296286
elseif step.type == 'falsy' then
297287
node:setFalsy()
298288
elseif step.type == 'as' then
299-
node = vm.createNode(globalMgr.getGlobal('type', step.name))
289+
topNode = vm.createNode(globalMgr.getGlobal('type', step.name))
290+
if step.ref1 then
291+
step.ref1.node = topNode
292+
elseif context then
293+
context.node = topNode
294+
end
300295
elseif step.type == 'add' then
301296
node:merge(globalMgr.getGlobal('type', step.name))
302297
elseif step.type == 'remove' then
303298
node:remove(step.name)
304299
elseif step.type == 'object' then
305-
node = callback(step.object, node) or node
300+
topNode = callback(step.object, node) or node
306301
if step.object.type == 'getlocal' then
307-
node = checkAssert(step.object, node)
302+
topNode = checkAssert(step.object, node)
303+
end
304+
if step.ref1 then
305+
step.ref1.node = topNode
306+
elseif context then
307+
context.node = topNode
308308
end
309309
elseif step.type == 'save' then
310-
-- nothing to do
310+
step.node = node
311311
elseif step.type == 'load' then
312-
node = step.ref1.node
312+
context = step
313+
context.node = node
313314
elseif step.type == 'merge' then
314-
node:merge(step.ref1.node)
315+
node:merge(step.ref2.node)
315316
end
316-
step.node = node
317317
end
318318
end
319319

test/type_inference/init.lua

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,18 +1744,15 @@ end
17441744
]]
17451745
--[[
17461746
#0 integer?
1747-
save 1 #1 integer? --ifblock --block中的初始状态
1748-
save 2 #2 integer? --ifblock --block外的状态
1749-
save 3 #3 integer? --ifblock --filter的状态
1750-
object get #3 integer? --if x then
1751-
load 2 #2 integer? --ifblock
1752-
falsy 2 #2 ? --ifblock
1753-
load 1 #1 integer? --ifblock
1754-
truly #1 integer --ifblock
1755-
object get #1 integer --print(x)
1756-
save 4 #?(1) integer --block中的最终状态
1757-
load 2 #2 ? --ifblock -- block
1758-
merge 4 #2 --if 最终状态
1747+
save 1 #1 integer? --ifblock --block外的状态
1748+
load 2 #2 integer? --ifblock --block中的初始状态
1749+
object get #2 integer? --if x then
1750+
truly 2 #2 integer --ifblock
1751+
falsy 1 #1 ?
1752+
object get #2 integer --print(x)
1753+
save 3 #?(2) integer --block中的最终状态
1754+
load 1 #2 ? --ifblock -- block
1755+
merge 3 #2 --if 最终状态
17591756
]]
17601757

17611758
TEST 'integer?' [[
@@ -1800,7 +1797,7 @@ end
18001797
print(x)
18011798
]]
18021799

1803-
TEST 'integer?' [[
1800+
TEST 'integer|nil' [[
18041801
---@type integer?
18051802
local x
18061803
@@ -1945,3 +1942,11 @@ assert(x == 1)
19451942
19461943
print(<?x?>)
19471944
]]
1945+
1946+
TEST 'integer' [[
1947+
---@type integer?
1948+
local x
1949+
1950+
if x and <?x?>.y then
1951+
end
1952+
]]

0 commit comments

Comments
 (0)