Skip to content

Commit 8d37877

Browse files
committed
experimental optimization
1 parent 886765a commit 8d37877

12 files changed

Lines changed: 450 additions & 71 deletions

nattlua/analyzer/control_flow.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ return function(META--[[#: any]])
426426

427427
if obj:IsExplicitOutputSignature() then
428428
-- so if we have explicit return types, just return those
429-
self.recursively_called[obj] = obj:GetOutputSignature():Copy()
429+
self.recursively_called[obj] = obj:GetOutputSignature():CopyForReturn()
430430
return self.recursively_called[obj]
431431
end
432432

nattlua/analyzer/expressions/postfix_call.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ local function postfix_call(self, self_arg, node, callable)
8282
self:Error(err)
8383

8484
if callable.Type == "function" and callable:IsExplicitOutputSignature() then
85-
return callable:GetOutputSignature():Copy()
85+
return callable:GetOutputSignature():CopyForReturn()
8686
end
8787
end
8888

nattlua/analyzer/operators/call.lua

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,27 @@ local ipairs = _G.ipairs
88
local table_insert = _G.table.insert
99
local math_huge = _G.math.huge
1010

11+
local function needs_input_copy(obj)
12+
if obj.Type == "any" then return true end
13+
14+
if obj.Type == "function" then return obj:GetFunctionBodyNode() ~= nil end
15+
16+
if obj.Type == "tuple" then
17+
obj = obj:GetFirstValue()
18+
return obj and needs_input_copy(obj) or false
19+
end
20+
21+
if obj.Type == "union" then
22+
for _, val in ipairs(obj:GetData()) do
23+
if needs_input_copy(val) then return true end
24+
end
25+
26+
return false
27+
end
28+
29+
return false
30+
end
31+
1132
local function union_call(self, analyzer, input, call_node)
1233
if false--[[# as true]] then return end
1334

@@ -66,7 +87,8 @@ local function union_call(self, analyzer, input, call_node)
6687
)
6788
else
6889
if input:IsSubsetOfTuple(obj:GetInputSignature()) then
69-
local res, reason = analyzer:Call(obj, input:Copy(), call_node, true)
90+
local arguments = needs_input_copy(obj) and input:Copy() or input
91+
local res, reason = analyzer:Call(obj, arguments, call_node, true)
7092

7193
if res then return res end
7294

@@ -87,7 +109,8 @@ local function union_call(self, analyzer, input, call_node)
87109
if recursively_called then return recursively_called end
88110
end
89111

90-
local val, err = analyzer:Call(obj, input:Copy(), call_node, true)
112+
local arguments = needs_input_copy(obj) and input:Copy() or input
113+
local val, err = analyzer:Call(obj, arguments, call_node, true)
91114

92115
if not val then
93116
analyzer:Error(err)
@@ -215,7 +238,7 @@ do
215238
analyzer:GetScope():CertainReturn()
216239
end
217240

218-
return self:GetOutputSignature():Copy()
241+
return self:GetOutputSignature():CopyForReturn()
219242
end
220243

221244
if
@@ -234,7 +257,7 @@ do
234257
analyzer:GetScope():CertainReturn()
235258
end
236259

237-
return self:GetOutputSignature():Copy()
260+
return self:GetOutputSignature():CopyForReturn()
238261
end
239262

240263
local recursively_called = analyzer:PushCallFrame(self, call_node, not_recursive_call)

nattlua/analyzer/operators/function_call_analyzer.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ return function(analyzer, obj, input)
185185
if obj:IsLiteralFunction() then
186186
for _, v in ipairs(input:GetData()) do
187187
if v.Type ~= "function" and not v:IsLiteral() then
188-
return output_signature:Copy()
188+
return output_signature:CopyForReturn()
189189
end
190190
end
191191
end
@@ -213,7 +213,7 @@ return function(analyzer, obj, input)
213213

214214
if not combinations then
215215
analyzer:Error(error_msg)
216-
return output_signature:Copy()
216+
return output_signature:CopyForReturn()
217217
end
218218

219219
for _, arguments in ipairs(combinations) do

nattlua/analyzer/operators/function_call_body.lua

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -672,11 +672,7 @@ return function(self, obj, input)
672672

673673
if function_node.environment == "typesystem" then return output end
674674

675-
local contract = output_signature:Copy()
676-
677-
for _, v in ipairs(contract:GetData()) do
678-
if v.Type == "table" then v:SetReferenceId(false) end
679-
end
675+
local contract = output_signature:CopyForReturn()
680676

681677
-- if a return type is marked with ref, it will pass the ref value back to the caller
682678
-- a bit like generics

nattlua/analyzer/operators/function_call_function_signature.lua

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,7 @@ return function(analyzer, obj, input)
2323
end
2424
end
2525

26-
local ret = obj:GetOutputSignature():Copy()
27-
28-
-- clear any reference id from the returned arguments
29-
for _, v in ipairs(ret:GetData()) do
30-
if v.Type == "table" then v:SetReferenceId(false) end
31-
end
26+
local ret = obj:GetOutputSignature():CopyForReturn()
3227

3328
return ret
3429
end

nattlua/types/base.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ return function()
5858
return self
5959
end
6060

61+
function META:CopyForReturn()
62+
return self
63+
end
64+
6165
function META:CopyInternalsFrom(obj--[[#: TBaseType]])
6266
self:SetContract(obj:GetContract())
6367
end

nattlua/types/function.lua

Lines changed: 112 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -133,27 +133,122 @@ end
133133
function META:Copy(map--[[#: Map<|any, any|> | nil]], copy_tables)
134134
map = map or {}
135135

136-
if map[self] then return map[self] end
136+
local existing = map[self]
137+
138+
if existing then return existing end
137139

138140
local copy = META.New()
139141
map[self] = copy
140-
copy:SetInputSignature(copy_val(self.InputSignature, map, copy_tables)--[[# as TTuple | false]])
141-
copy:SetOutputSignature(copy_val(self.OutputSignature, map, copy_tables)--[[# as TTuple | false]])
142-
copy:SetUpvaluePosition(self:GetUpvaluePosition())
143-
copy:SetAnalyzerFunction(self:GetAnalyzerFunction())
144-
copy:SetScope(self:GetScope())
142+
143+
do
144+
local input = self.InputSignature
145+
146+
if input then
147+
local mapped = map[input]
148+
149+
if mapped then
150+
copy.InputSignature = mapped
151+
else
152+
map[input] = input:Copy(map, copy_tables)
153+
copy.InputSignature = map[input]
154+
end
155+
else
156+
copy.InputSignature = false
157+
end
158+
end
159+
160+
do
161+
local output = self.OutputSignature
162+
163+
if output then
164+
local mapped = map[output]
165+
166+
if mapped then
167+
copy.OutputSignature = mapped
168+
else
169+
map[output] = output:Copy(map, copy_tables)
170+
copy.OutputSignature = map[output]
171+
end
172+
else
173+
copy.OutputSignature = false
174+
end
175+
end
176+
177+
copy.UpvaluePosition = self.UpvaluePosition
178+
copy.AnalyzerFunction = self.AnalyzerFunction
179+
copy.Scope = self.Scope
180+
copy:CopyInternalsFrom(self)
181+
copy.FunctionBodyNode = self.FunctionBodyNode
182+
copy.InputIdentifiers = self.InputIdentifiers
183+
copy.Called = self.Called
184+
copy.ExplicitInputSignature = self.ExplicitInputSignature
185+
copy.ExplicitOutputSignature = self.ExplicitOutputSignature
186+
copy.ArgumentsInferred = self.ArgumentsInferred
187+
copy.PreventInputArgumentExpansion = self.PreventInputArgumentExpansion
188+
copy.LiteralFunction = self.LiteralFunction
189+
copy.InputArgumentsInferred = self.InputArgumentsInferred
190+
copy.InputModifiers = self.InputModifiers
191+
copy.OutputModifiers = self.OutputModifiers
192+
return copy
193+
end
194+
195+
function META:CopyForReturn(map--[[#: Map<|any, any|> | nil]])
196+
map = map or {}
197+
198+
local existing = map[self]
199+
200+
if existing then return existing end
201+
202+
local copy = META.New()
203+
map[self] = copy
204+
205+
do
206+
local input = self.InputSignature
207+
208+
if input then
209+
local mapped = map[input]
210+
211+
if mapped then
212+
copy.InputSignature = mapped
213+
else
214+
copy.InputSignature = input:CopyForReturn(map)
215+
end
216+
else
217+
copy.InputSignature = false
218+
end
219+
end
220+
221+
do
222+
local output = self.OutputSignature
223+
224+
if output then
225+
local mapped = map[output]
226+
227+
if mapped then
228+
copy.OutputSignature = mapped
229+
else
230+
copy.OutputSignature = output:CopyForReturn(map)
231+
end
232+
else
233+
copy.OutputSignature = false
234+
end
235+
end
236+
237+
copy.UpvaluePosition = self.UpvaluePosition
238+
copy.AnalyzerFunction = self.AnalyzerFunction
239+
copy.Scope = self.Scope
145240
copy:CopyInternalsFrom(self)
146-
copy:SetFunctionBodyNode(self:GetFunctionBodyNode())
147-
copy:SetInputIdentifiers(self:GetInputIdentifiers())
148-
copy:SetCalled(self:IsCalled())
149-
copy:SetExplicitInputSignature(self:IsExplicitInputSignature())
150-
copy:SetExplicitOutputSignature(self:IsExplicitOutputSignature())
151-
copy:SetArgumentsInferred(self:IsArgumentsInferred())
152-
copy:SetPreventInputArgumentExpansion(self:GetPreventInputArgumentExpansion())
153-
copy:SetLiteralFunction(self:IsLiteralFunction())
154-
copy:SetInputArgumentsInferred(self:IsInputArgumentsInferred())
155-
copy:SetInputModifiers(self.InputModifiers)
156-
copy:SetOutputModifiers(self.OutputModifiers)
241+
copy.FunctionBodyNode = self.FunctionBodyNode
242+
copy.InputIdentifiers = self.InputIdentifiers
243+
copy.Called = self.Called
244+
copy.ExplicitInputSignature = self.ExplicitInputSignature
245+
copy.ExplicitOutputSignature = self.ExplicitOutputSignature
246+
copy.ArgumentsInferred = self.ArgumentsInferred
247+
copy.PreventInputArgumentExpansion = self.PreventInputArgumentExpansion
248+
copy.LiteralFunction = self.LiteralFunction
249+
copy.InputArgumentsInferred = self.InputArgumentsInferred
250+
copy.InputModifiers = self.InputModifiers
251+
copy.OutputModifiers = self.OutputModifiers
157252
return copy
158253
end
159254

nattlua/types/string.lua

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,7 @@ META:GetSet("Data", false--[[# as string | false]])
1717
META:GetSet("Hash", false--[[# as string]])
1818
META:GetSet("PatternContract", false--[[# as false | string]])
1919
local STRING_ID = "string"
20-
21-
local function compute_hash(data--[[#: nil | string]], pattern--[[#: nil | string]])--[[#: string]]
22-
if pattern then return pattern elseif data then return data end
23-
24-
return STRING_ID
25-
end
20+
local new
2621

2722
function META:GetHashForMutationTracking()
2823
if self.Data then return self.Hash end
@@ -35,11 +30,9 @@ function META:GetHashForMutationTracking()
3530
end
3631

3732
function META:Copy()
38-
local copy = self.New(self.Data)
39-
copy:SetPatternContract(self:GetPatternContract())
40-
copy:SetMetaTable(self:GetMetaTable())
33+
local copy = new(self.Data or nil, self.PatternContract or nil)
34+
copy.MetaTable = self:GetMetaTable()
4135
copy:CopyInternalsFrom(self)
42-
copy.Hash = compute_hash(copy.Data, copy.PatternContract)
4336
copy.lua_compiler = self.lua_compiler
4437
return copy
4538
end
@@ -56,7 +49,7 @@ function META:Get()
5649
return false, error_messages.index_string_attempt()
5750
end
5851

59-
local function new(data--[[#: string | nil]], pattern--[[#: string | nil]])
52+
function new(data--[[#: string | nil]], pattern--[[#: string | nil]])
6053
return META.NewObject{
6154
Type = "string",
6255
Data = data or false,
@@ -65,7 +58,7 @@ local function new(data--[[#: string | nil]], pattern--[[#: string | nil]])
6558
Upvalue = false,
6659
Contract = false,
6760
MetaTable = false,
68-
Hash = compute_hash(data, pattern),
61+
Hash = pattern or data or STRING_ID,
6962
lua_compiler = false,
7063
}
7164
end
@@ -88,7 +81,13 @@ function META.New(data--[[#: string | nil]], pattern--[[#: string | nil]])
8881
local analyzer = context:GetCurrentAnalyzer()
8982

9083
if analyzer then
91-
self:SetMetaTable(analyzer:GetDefaultEnvironment("typesystem").string_metatable)
84+
local default_environment = analyzer.default_environment
85+
86+
if default_environment then
87+
self.MetaTable = default_environment.typesystem.string_metatable
88+
else
89+
self:SetMetaTable(analyzer:GetDefaultEnvironment("typesystem").string_metatable)
90+
end
9291
end
9392

9493
return self
@@ -118,7 +117,7 @@ function META:CopyLiteralness(obj--[[#: TBaseType]])
118117

119118
if not obj:IsLiteral() then
120119
self.Data = false
121-
self.Hash = compute_hash(self.Data, self.PatternContract)
120+
self.Hash = self.PatternContract or STRING_ID
122121
end
123122
end
124123

0 commit comments

Comments
 (0)