Skip to content

Commit 85a4505

Browse files
committed
fix some issues with tuples and varargs in type functions
1 parent e2fa77b commit 85a4505

File tree

12 files changed

+164
-25
lines changed

12 files changed

+164
-25
lines changed

nattlua/analyzer/analyzer.lua

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ do
116116
local AnalyzeFunction = require("nattlua.analyzer.expressions.function").AnalyzeFunction
117117
local AnalyzeTable = require("nattlua.analyzer.expressions.table").AnalyzeTable
118118
local AnalyzeAtomicValue = require("nattlua.analyzer.expressions.atomic_value").AnalyzeAtomicValue
119+
local LookupValue = require("nattlua.analyzer.expressions.atomic_value").LookupValue
119120
local AnalyzeLSX = require("nattlua.analyzer.expressions.lsx").AnalyzeLSX
120121
local Union = require("nattlua.types.union").Union
121122
local Tuple = require("nattlua.types.tuple").Tuple
@@ -166,7 +167,11 @@ do
166167
then
167168
return AnalyzeFunction(self, node)
168169
elseif node.kind == "vararg" then
169-
return VarArg(self:AnalyzeExpression(node.value))
170+
if node.value then
171+
return VarArg(self:AnalyzeExpression(node.value))
172+
else
173+
return LookupValue(self, "...")
174+
end
170175
elseif node.kind == "postfix_operator" then
171176
if node.value.value == "++" then
172177
local r = self:AnalyzeExpression(node.left)

nattlua/analyzer/expressions/atomic_value.lua

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ local Boolean = require("nattlua.types.union").Boolean
1313
local table = _G.table
1414
local type_errors = require("nattlua.types.error_messages")
1515

16-
local function lookup_value(self, node)
16+
local function lookup_value(self, ident)
1717
local errors = {}
18-
local key = ConstString(node.value.value)
18+
local key = ConstString(ident)
1919
local obj, err = self:GetLocalOrGlobalValue(key)
2020

2121
if self:IsTypesystem() then
@@ -72,6 +72,7 @@ local function is_primitive(val)
7272
end
7373

7474
return {
75+
LookupValue = lookup_value,
7576
AnalyzeAtomicValue = function(self, node)
7677
local value = node.value.value
7778
local type = runtime_syntax:GetTokenType(node.value)
@@ -85,9 +86,9 @@ return {
8586
return False()
8687
end
8788
elseif node.force_upvalue then
88-
return lookup_value(self, node)
89+
return lookup_value(self, node.value.value)
8990
elseif value == "..." then
90-
return lookup_value(self, node)
91+
return lookup_value(self, node.value.value)
9192
elseif type == "letter" and node.standalone_letter then
9293
-- standalone_letter means it's the first part of something, either >true<, >foo<.bar, >foo<()
9394
if self:IsTypesystem() then
@@ -120,7 +121,7 @@ return {
120121
end
121122
end
122123

123-
return lookup_value(self, node)
124+
return lookup_value(self, node.value.value)
124125
elseif type == "number" then
125126
local num = LNumberFromString(value)
126127

nattlua/analyzer/expressions/postfix_call.lua

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ return {
3838
local arguments
3939

4040
if self:IsTypesystem() then
41-
arguments = Tuple(types)
41+
if #types == 1 and types[1].Type == "tuple" and callable:GetInputSignature():GetTupleLength() == math.huge then
42+
arguments = types[1]
43+
else
44+
arguments = Tuple(types)
45+
end
4246
else
4347
arguments = NormalizeTuples(types)
4448
end

nattlua/analyzer/operators/function_call_body.lua

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,14 @@ return function(self, obj, input)
449449
for i, identifier in ipairs(function_node.identifiers) do
450450
local argi = function_node.self_call and (i + 1) or i
451451

452+
452453
if self:IsTypesystem() then
453-
self:CreateLocalValue(identifier.value.value, self:Assert(input:GetWithoutExpansion(argi)))
454+
if identifier.value.value == "..." then
455+
if input.tr and input.Data[1] and input.Data[1].tr then print(input.Data[1].tr) end
456+
self:CreateLocalValue(identifier.value.value, input:Slice(argi))
457+
else
458+
self:CreateLocalValue(identifier.value.value, self:Assert(input:GetWithoutExpansion(argi)))
459+
end
454460
end
455461

456462
if self:IsRuntime() then
@@ -484,7 +490,6 @@ return function(self, obj, input)
484490
if is_type_function then self:PushAnalyzerEnvironment("typesystem") end
485491

486492
local output = self:AnalyzeStatementsAndCollectOutputSignatures(function_node)
487-
488493
if is_type_function then self:PopAnalyzerEnvironment() end
489494

490495
self:PopGlobalEnvironment(self:GetCurrentAnalyzerEnvironment())

nattlua/analyzer/statements/assignment.lua

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,16 @@ return {
8888
right[index] = obj:GetWithoutExpansion(i)
8989
end
9090
else
91-
-- otherwise plainly assign it
92-
right[right_pos] = obj
91+
if #statement.left > 1 then
92+
-- at runtime unpack the tuple
93+
for i = 1, #statement.left do
94+
local index = right_pos + i - 1
95+
right[index] = obj:GetWithNumber(i)
96+
end
97+
else
98+
-- otherwise plainly assign it
99+
right[right_pos] = obj
100+
end
93101
end
94102
end
95103
elseif obj.Type == "union" then

nattlua/definitions/lua/globals.nlua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,12 @@ type xpcall = ReturnIfNonLiteral<|
396396
|>
397397
type select = ReturnIfNonLiteral<|
398398
analyzer function(index: 1 .. inf | "#", ...: ...any): ...any
399+
local x = ...
400+
401+
if x and x.Type == "tuple" then
402+
return select(index:GetData(), x:Unpack())
403+
end
404+
399405
return select(index:GetData(), ...)
400406
end
401407
|>

nattlua/definitions/lua/io.nlua

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
1+
local function check_read_args<|...: ...$"%**[Lanl].*" | number|>
2+
local out = {}
3+
4+
for i = 1, select<|"#", ...|> do
5+
local v = ...[i]
6+
7+
if v:sub(1, 1) == "n" or v:sub(1, 2) == "*n" then
8+
out[i] = number | nil
9+
else
10+
out[i] = string | nil
11+
end
12+
end
13+
14+
return table.unpack<|out|>
15+
end
16+
117
type io = {
218
write = function=(...string)>(nil),
319
flush = function=()>(boolean | nil, string | nil),
4-
read = function <|s: "*n" | "*a" | "*l" | "n" | "a" | "l" | "L" | number | nil|>
5-
if s == "*n" or s == "n" then return nil | number end
6-
7-
return nil | string
8-
end,
20+
read = check_read_args,
921
lines = function=()>(Function),
1022
setvbuf = function=(mode: "no" | "full" | "line", size: number | nil)>(boolean | nil, string | nil),
1123
seek = function=(mode: "set" | "cur" | "end", offset: number | nil)>(number | nil, string | nil),
@@ -14,10 +26,8 @@ type File = {
1426
close = function=(self)>(boolean | nil, string, number | nil),
1527
write = function=(self, ...(number | string))>(self | nil, string | nil),
1628
flush = function=(self)>(boolean | nil, string | nil),
17-
read = function <|self: File, s: "*n" | "*a" | "*l" | "n" | "a" | "l" | "L" | number | nil|>
18-
if s == "*n" or s == "n" then return nil | number end
19-
20-
return nil | string
29+
read = function <|self: File, ...: ...any|>
30+
return check_read_args<|...|>
2131
end,
2232
lines = function=(self)>(Function),
2333
setvbuf = function=(self, mode: "no" | "full" | "line", size: number | nil)>(boolean | nil, string | nil),

nattlua/emitter/emitter.lua

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,9 @@ end
955955

956956
function META:EmitVararg(node--[[#: Node]])
957957
self:EmitToken(node.tokens["..."])
958-
self:EmitExpression(node.value)
958+
if node.value then
959+
self:EmitExpression(node.value)
960+
end
959961
end
960962

961963
function META:EmitTable(tree--[[#: Node]])

nattlua/parser/expressions.lua

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,15 @@ do -- typesystem
127127
end
128128

129129
function META:ParseValueTypeExpression()
130-
if not (self:IsTokenValue("...") and self:IsTokenType("letter", 1)) then
130+
if not self:IsTokenValue("...") then
131131
return
132132
end
133133

134134
local node = self:StartNode("expression", "vararg")
135135
node.tokens["..."] = self:ExpectTokenValue("...")
136-
node.value = self:ParseTypeExpression(0)
136+
if not self:GetToken().whitespace then
137+
node.value = self:ParseTypeExpression(0)
138+
end
137139
node = self:EndNode(node)
138140
return node
139141
end

nattlua/types/tuple.lua

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,10 @@ end
194194

195195
function META.IsSubsetOfTupleWithoutExpansion(a--[[#: TTuple]], b--[[#: TBaseType]])
196196
for i, a_val in ipairs(a:GetData()) do
197-
local b_val = b:GetWithoutExpansion(i)
197+
local b_val, err = b:GetWithoutExpansion(i)
198+
199+
if not b_val then return b_val, err, a_val, "nil", i end
200+
198201
local ok, err = a_val:IsSubsetOf(b_val)
199202

200203
if not ok then return ok, err, a_val, b_val, i end

0 commit comments

Comments
 (0)