Skip to content

Commit a46162e

Browse files
committed
go back to basics with metatables
get rid of .@self, @self2, @Basetable, potential_self, etc. add SelfArgument which simply specifies what the self argument should be by default when defining functions on a metatable
1 parent 5a4d68f commit a46162e

22 files changed

Lines changed: 1956 additions & 2188 deletions

File tree

nattlua/analyzer/base/base_analyzer.lua

Lines changed: 0 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -98,88 +98,9 @@ return function(META--[[#: any]])
9898
end
9999

100100
do
101-
local function add_potential_self(tup)
102-
local tbl = tup:GetWithNumber(1)
103-
104-
if tbl and tbl.Type == "union" then tbl = tbl:GetType("table") end
105-
106-
if not tbl or tbl.Type ~= "table" then return end
107-
108-
if tbl.Self then
109-
local self = tbl.Self:Copy()
110-
local new_tup = Tuple()
111-
112-
for i, obj in ipairs(tup:GetData()) do
113-
if i == 1 then
114-
new_tup:Set(i, self)
115-
else
116-
new_tup:Set(i, obj)
117-
end
118-
end
119-
120-
return new_tup
121-
elseif tbl.Self2 then
122-
local self = tbl.Self2
123-
local new_tup = Tuple()
124-
125-
for i, obj in ipairs(tup:GetData()) do
126-
if i == 1 then
127-
new_tup:Set(i, self)
128-
else
129-
new_tup:Set(i, obj)
130-
end
131-
end
132-
133-
return new_tup
134-
elseif tbl.potential_self then
135-
local meta = tbl
136-
local self = tbl.potential_self
137-
138-
if self.Type == "union" then
139-
for _, obj in ipairs(self:GetData()) do
140-
obj:SetMetaTable(meta)
141-
end
142-
else
143-
self:SetMetaTable(meta)
144-
end
145-
146-
local new_tup = Tuple()
147-
148-
for i, obj in ipairs(tup:GetData()) do
149-
if i == 1 then
150-
new_tup:Set(i, self)
151-
else
152-
new_tup:Set(i, obj)
153-
end
154-
end
155-
156-
return new_tup
157-
end
158-
end
159-
160101
function META:CrawlFunctionWithoutOrigin(obj)
161102
-- use function's arguments in case they have been maniupulated (ie string.gsub)
162103
local arguments = obj:GetInputSignature():Copy()
163-
164-
if obj:IsExplicitInputSignature() then
165-
local new_arguments = add_potential_self(arguments)
166-
arguments = new_arguments or arguments
167-
168-
for i = 1, arguments:GetSafeLength() do
169-
if new_arguments then i = i + 1 end
170-
171-
arguments:Set(i, Any())
172-
end
173-
else
174-
arguments = add_potential_self(arguments) or arguments
175-
176-
for _, obj in ipairs(arguments:GetData()) do
177-
if obj.Type == "upvalue" or obj.Type == "table" then
178-
obj:ClearMutations()
179-
end
180-
end
181-
end
182-
183104
self:CreateAndPushFunctionScope(obj)
184105
self:PushCurrentStatement(obj:GetFunctionBodyNode())
185106
self:ErrorIfFalse(self:Call(obj, arguments, obj:GetFunctionBodyNode()))

nattlua/analyzer/expressions/function.lua

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,10 @@ local function analyze_arguments(self, node, func)
4141
self:PopAnalyzerEnvironment()
4242

4343
if val then
44-
if val.Self then
45-
args[1] = val.Self
46-
elseif val.Self2 then
47-
args[1] = val.Self2
48-
elseif val:GetContract() then
44+
if val:GetContract() then
4945
args[1] = val
46+
elseif val:GetSelfArgument() then
47+
args[1] = val:GetSelfArgument()
5048
else
5149
args[1] = Union({Any(), val})
5250
end

nattlua/analyzer/operators/newindex.lua

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ return {
4545
local err
4646

4747
if obj == contract then
48-
if obj:GetMetaTable() and obj:GetMetaTable().Self == obj then
48+
if obj:GetMetaTable() then
4949
analyzer:MutateTable(obj, key, val)
5050
return obj:SetExplicit(key, val)
5151
else
@@ -112,42 +112,6 @@ return {
112112
function META:NewIndexOperator(obj, key, val, raw, allow_nil_set)
113113
if obj.Type == "any" then return true end
114114

115-
if val.Type == "function" then
116-
local node = val:GetFunctionBodyNode()
117-
118-
if
119-
node and
120-
(
121-
node.Type == "expression_function" or
122-
node.Type == "expression_type_function" or
123-
node.Type == "expression_analyzer_function" or
124-
node.Type == "statement_function" or
125-
node.Type == "statement_type_function" or
126-
node.Type == "statement_analyzer_function"
127-
)
128-
and
129-
node.self_call
130-
then
131-
local arg = val:GetInputSignature():GetWithNumber(1)
132-
133-
if
134-
arg and
135-
arg.Type == "table" and
136-
not arg:GetContract()
137-
and
138-
not arg.Self and
139-
obj.Self2 ~= arg and
140-
not self:IsTypesystem()
141-
then
142-
val:SetCalled(true)
143-
val = val:Copy()
144-
val:SetCalled(false)
145-
val:GetInputSignature():Set(1, Union({Any(), obj}))
146-
self:AddToUnreachableCodeAnalysis(val)
147-
end
148-
end
149-
end
150-
151115
local ok, err
152116

153117
if obj.Type == "union" then

nattlua/definitions/lua/globals.nlua

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -503,66 +503,7 @@ analyzer function setmetatable(tbl: Table, meta: Table | nil)
503503
end
504504

505505
if meta.Type == "table" then
506-
if meta.NewMetaTable and not meta.Self then
507-
-- @NewMetaTable mode: build an inferred Self from tbl's fields
508-
-- This is informational (no contract enforcement)
509-
local inferred_self = types.Table()
510-
for _, kv in ipairs(tbl:GetData()) do
511-
local key = kv.key
512-
local val = kv.val
513-
-- Widen literal values to their base types for the inferred self
514-
if val:IsLiteral() and val.Type ~= "function" and val.Type ~= "table" and val.Widen then
515-
val = val:Widen()
516-
end
517-
inferred_self:Set(key, val)
518-
end
519-
inferred_self:SetMetaTable(meta)
520-
meta.Self = inferred_self
521-
elseif meta.NewMetaTable and meta.Self then
522-
-- Subsequent setmetatable calls: merge additional fields
523-
for _, kv in ipairs(tbl:GetData()) do
524-
local key = kv.key
525-
local val = kv.val
526-
if val:IsLiteral() and val.Type ~= "function" and val.Type ~= "table" and val.Widen then
527-
val = val:Widen()
528-
end
529-
if not meta.Self:HasKey(key) then
530-
meta.Self:Set(key, val)
531-
end
532-
end
533-
elseif meta.Self then
534-
analyzer:ErrorIfFalse(tbl:FollowsContract(meta.Self))
535-
tbl:CopyLiteralness2(meta.Self)
536-
tbl:SetContract(meta.Self)
537-
-- clear mutations so that when looking up values in the table they won't return their initial value
538-
tbl:ClearMutations()
539-
elseif analyzer:IsRuntime() then
540-
meta.potential_self = meta.potential_self or types.Union()
541-
meta.potential_self:AddType(tbl)
542-
end
543-
544506
tbl:SetMetaTable(meta)
545-
546-
if analyzer:IsTypesystem() then return tbl end
547-
548-
local metatable_functions = analyzer:CallTypesystemUpvalue(types.ConstString("MetaTableFunctions"), tbl)
549-
550-
for _, kv in ipairs(metatable_functions:GetData()) do
551-
local a = kv.val
552-
local b = meta:Get(kv.key)
553-
554-
if b and b.Type == "function" then
555-
local ok = a:IsSubsetOf(b)
556-
557-
if ok then
558-
559-
--TODO: enrich callback types
560-
--b:SetOutputSignature(a:GetOutputSignature())
561-
--b:SetInputSignature(a:GetInputSignature())
562-
--b.arguments_inferred = true
563-
end
564-
end
565-
end
566507
end
567508

568509
return tbl

nattlua/other/class.lua

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,27 @@ function class.CreateTemplate(type_name--[[#: ref string]])--[[#: ref Table]]
66
local META = {}
77
META.Type = type_name
88
META.__index = META
9-
--[[#type META.@Self = {}]]
109

1110
function META.GetSet(META--[[#: ref META]], name--[[#: ref string]], default--[[#: ref any]])
1211
META[name] = default--[[# as NonLiteral<|default|>]]
13-
--[[#type META.@Self[name] = NonLiteral<|default|>]]
14-
META["Set" .. name] = function(self--[[#: ref META.@Self]], val--[[#: NonLiteral<|default|>]])
12+
--[[#type META.@SelfArgument[name] = NonLiteral<|default|>]]
13+
META["Set" .. name] = function(self--[[#: ref META.@SelfArgument]], val--[[#: NonLiteral<|default|>]])
1514
self[name] = val
1615
return self
1716
end
18-
META["Get" .. name] = function(self--[[#: ref META.@Self]])--[[#: NonLiteral<|default|>]]
17+
META["Get" .. name] = function(self--[[#: ref META.@SelfArgument]])--[[#: NonLiteral<|default|>]]
1918
return self[name]
2019
end
2120
end
2221

2322
function META.IsSet(META--[[#: ref META]], name--[[#: ref string]], default--[[#: ref any]])
2423
META[name] = default--[[# as NonLiteral<|default|>]]
25-
--[[#type META.@Self[name] = NonLiteral<|default|>]]
26-
META["Set" .. name] = function(self--[[#: META.@Self]], val--[[#: NonLiteral<|default|>]])
24+
--[[#type META.@SelfArgument[name] = NonLiteral<|default|>]]
25+
META["Set" .. name] = function(self--[[#: META.@SelfArgument]], val--[[#: NonLiteral<|default|>]])
2726
self[name] = val
2827
return self
2928
end
30-
META["Is" .. name] = function(self--[[#: META.@Self]])--[[#: NonLiteral<|default|>]]
29+
META["Is" .. name] = function(self--[[#: META.@SelfArgument]])--[[#: NonLiteral<|default|>]]
3130
return self[name]
3231
end
3332
end
@@ -136,7 +135,7 @@ function class.CreateTemplate(type_name--[[#: ref string]])--[[#: ref Table]]
136135
--[[#func<|res|>]]
137136

138137
for k, v in pairs(res) do
139-
--[[#type META.@Self[k] = v]]
138+
--[[#type META.@SelfArgument[k] = v]]
140139
end
141140
end
142141
end

0 commit comments

Comments
 (0)