Skip to content

Commit 8dd48aa

Browse files
committed
experimental optimization 2
1 parent 8d37877 commit 8dd48aa

5 files changed

Lines changed: 81 additions & 22 deletions

File tree

nattlua/analyzer/operators/function_call_body.lua

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,44 @@ local function restore_mutated_types(self)
3232
table_clear(env.mutated_types)
3333
end
3434

35+
local function can_wrap_table_argument(contract)
36+
if contract.Type == "table" then return true end
37+
38+
if contract.Type ~= "union" then return false end
39+
40+
for _, obj in ipairs(contract:GetData()) do
41+
if obj.Type ~= "table" and (obj.Type ~= "symbol" or not obj:IsNil()) then
42+
return false
43+
end
44+
end
45+
46+
return true
47+
end
48+
49+
local function get_argument_value(arg, contract)
50+
if
51+
arg and
52+
arg.Type == "table" and
53+
can_wrap_table_argument(contract) and
54+
not arg:GetMetaTable()
55+
and
56+
not arg:GetTypeOverride()
57+
and
58+
not arg:GetName()
59+
and
60+
not arg:IsUnique()
61+
then
62+
local tbl = Table()
63+
tbl:SetContract(contract)
64+
tbl:SetAnalyzerEnvironment(arg:GetAnalyzerEnvironment())
65+
return tbl
66+
end
67+
68+
local val = contract:GetFirstValue():Copy(nil, true)
69+
val:SetContract(contract)
70+
return val
71+
end
72+
3573
local function shrink_union_to_function_signature(obj)
3674
local arg = Tuple()
3775
local ret = Tuple()
@@ -314,9 +352,7 @@ return function(self, obj, input)
314352
test<|number|>(1)
315353
]]
316354
-- if it's a ref argument we pass the incoming value
317-
local t = contract:GetFirstValue():Copy(nil, true)
318-
t:SetContract(contract)
319-
input:Set(i, t)
355+
input:Set(i, get_argument_value(arg, contract))
320356
end
321357
elseif
322358
arg and
@@ -337,15 +373,11 @@ return function(self, obj, input)
337373

338374
if doit then
339375
-- if it's not a ref argument we pass the incoming value
340-
local t = contract:GetFirstValue():Copy(nil, true)
341-
t:SetContract(contract)
342-
input:Set(i, t)
376+
input:Set(i, get_argument_value(arg, contract))
343377
end
344378
else
345379
if arg.Type == "any" and arg.Type ~= contract.Type then
346-
local t = contract:GetFirstValue():Copy(nil, true)
347-
t:SetContract(contract)
348-
input:Set(i, t)
380+
input:Set(i, get_argument_value(arg, contract))
349381
end
350382
end
351383
end

nattlua/types/shared.lua

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,18 @@ function shared.IsSubsetOf(
308308

309309
if b.Type == "any" then return true, "b is any" end
310310

311+
do
312+
local contract = a:GetContract()
313+
314+
if contract and contract ~= a then
315+
if contract == b then return true, "same contract" end
316+
317+
local ok, err = shared.IsSubsetOf(contract, b, visited, max_length)
318+
319+
if ok then return true, "contract is subset" end
320+
end
321+
end
322+
311323
if b.Type == "table" then
312324
if a == b then return true, "same type" end
313325

nattlua/types/union.lua

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,6 @@ end
466466

467467
function META:Copy(map--[[#: Map<|any, any|> | nil]], copy_tables--[[#: nil | boolean]])--[[#: TUnion]]
468468
map = map or {}
469-
470469
local existing = map[self]
471470

472471
if existing then return existing--[[# as TUnion]] end -- TODO map[self] doesn't make return map[self] not nil
@@ -483,7 +482,8 @@ function META:Copy(map--[[#: Map<|any, any|> | nil]], copy_tables--[[#: nil | bo
483482
if mapped then
484483
obj = mapped
485484
elseif obj.Type == "table" and not copy_tables then
486-
-- keep shared table references when the caller explicitly asked for it
485+
486+
-- keep shared table references when the caller explicitly asked for it
487487
else
488488
map[obj] = obj:Copy(map, copy_tables)
489489
obj = map[obj]
@@ -502,10 +502,10 @@ end
502502

503503
function META:CopyForReturn(map--[[#: Map<|any, any|> | nil]])--[[#: TUnion]]
504504
map = map or {}
505-
506505
local existing = map[self]
507506

508507
if existing then return existing--[[# as TUnion]] end
508+
509509
local copy = META.New()
510510
map[self] = copy
511511
local data = copy.Data
@@ -524,11 +524,7 @@ function META:CopyForReturn(map--[[#: Map<|any, any|> | nil]])--[[#: TUnion]]
524524
then
525525
local mapped = map[obj]
526526

527-
if mapped then
528-
obj = mapped
529-
else
530-
obj = obj:CopyForReturn(map)
531-
end
527+
if mapped then obj = mapped else obj = obj:CopyForReturn(map) end
532528
end
533529

534530
local s = hash(obj)
@@ -630,6 +626,25 @@ function META:IsNumeric()
630626
return true
631627
end
632628

629+
function META:Get(key)
630+
local union = META.New()
631+
local errors = {}
632+
633+
for _, obj in ipairs(self.Data) do
634+
if obj.Type == "table" and obj:IsEmpty() then
635+
636+
else
637+
local val, err = obj:Get(key)
638+
639+
if val then union:AddType(val) else table.insert(errors, err) end
640+
end
641+
end
642+
643+
if union:GetCardinality() == 0 then return false, errors end
644+
645+
return union:Simplify()
646+
end
647+
633648
return {
634649
TUnion = TUnion,
635650
Union = META.New,

test/tests/nattlua/analyzer/function.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1021,7 +1021,7 @@ local x = {1, 2}
10211021
local type AnyTable = {[any] = any} | {}
10221022
10231023
local function foo(x: AnyTable)
1024-
attest.strict_equal(x, _ as {[any] = any} | {})
1024+
attest.equal(x[1], _ as any)
10251025
x[1]= 1
10261026
end
10271027

test/tests/nattlua/analyzer/generics.lua

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,24 +104,24 @@ analyze[[
104104
local function Array<|T: any, Size: number|>(init: nil | {[Size] = T})
105105
attest.equal<|T, string|>
106106
attest.equal<|Size, 1..10|>
107-
attest.equal(init, _ as nil | {[Size] = T})
107+
attest.subset_of(init, _ as nil | {[Size] = T})
108108
return init
109109
end
110110
111111
local arr = Array<|string, 1..10|>({"hello", "world"})
112-
attest.equal(arr, _ as nil | {[1..10] = string})
112+
attest.subset_of(arr, _ as nil | {[1..10] = string})
113113
]]
114114
analyze[[
115115
local function Array<|T: any, Size: number|>(init: nil | {[Size] = T})
116116
attest.equal<|T, string|>
117117
attest.equal<|Size, 1..10|>
118-
attest.equal(init, _ as nil | {[Size] = T})
118+
attest.subset_of(init, _ as nil | {[Size] = T})
119119
return init
120120
end
121121
122122
do
123123
local arr = Array<|string, 1..10|>({"hello", "world"})
124-
attest.equal(arr, _ as nil | {[1..10] = string})
124+
attest.subset_of(arr, _ as nil | {[1..10] = string})
125125
end
126126
]]
127127
analyze[[

0 commit comments

Comments
 (0)