Skip to content

Commit b465e0d

Browse files
First-pass fix to Compiler compileExprVarargs
Fixes the simplest case of: --- local function foo(...) print(...) end foo("Hello, World!") --- Does not pass tests/Issue snippet
1 parent 7c5e873 commit b465e0d

File tree

2 files changed

+51
-4
lines changed

2 files changed

+51
-4
lines changed

Compiler/src/Compiler.cpp

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,41 @@ struct Compiler
403403

404404
setDebugLine(expr); // normally compileExpr sets up line info, but compileExprVarargs can be called directly
405405

406-
bytecode.emitABC(LOP_GETVARARGS, target, multRet ? 0 : uint8_t(targetCount + 1), 0);
406+
/*
407+
bool doVararg = true;
408+
if (inlineFrames.size() > 0)
409+
{
410+
bool foundArg = false;
411+
412+
for (AstNode* arg : inlineFrames.back().call->args)
413+
if (arg == expr)
414+
{
415+
foundArg = true;
416+
break;
417+
}
418+
419+
if (!foundArg)
420+
doVararg = false;
421+
}
422+
*/
423+
424+
if (inlineFrames.size() == 0)
425+
bytecode.emitABC(LOP_GETVARARGS, target, multRet ? 0 : uint8_t(targetCount + 1), 0);
426+
else
427+
{
428+
const InlineFrame& frame = inlineFrames.back();
429+
LUAU_ASSERT(frame.call);
430+
431+
// we need to compile the arguments themselves instead of a vararg
432+
433+
for (size_t index = 0; index < frame.call->args.size; index++)
434+
{
435+
AstExpr* arg = frame.call->args.data[index]->asExpr();
436+
LUAU_ASSERT(arg);
437+
438+
compileExpr(arg, target + index);
439+
}
440+
}
407441
}
408442

409443
void compileExprSelectVararg(AstExprCall* expr, uint8_t target, uint8_t targetCount, bool targetTop, bool multRet, uint8_t regs)
@@ -590,12 +624,18 @@ struct Compiler
590624
// - additionally, we can't easily compile multret expressions into designated target as computed call arguments will get clobbered
591625
if (multRet)
592626
{
593-
bytecode.addDebugRemark("inlining failed: can't convert fixed returns to multret");
627+
bytecode.addDebugRemark("inlining failed: can't convert multret to fixed returns");
594628
return false;
595629
}
596630

597631
if (func->vararg)
598632
{
633+
if (func->args.size > expr->args.size)
634+
{
635+
bytecode.addDebugRemark("inlining failed: not enough arguments");
636+
return false;
637+
}
638+
599639
for (AstExpr* arg : expr->args)
600640
{
601641
if (isExprMultRet(arg))
@@ -743,7 +783,7 @@ struct Compiler
743783
}
744784

745785
// the inline frame will be used to compile return statements as well as to reject recursive inlining attempts
746-
inlineFrames.push_back({func, oldLocals, target, targetCount});
786+
inlineFrames.push_back({func, expr, oldLocals, target, targetCount});
747787

748788
// fold constant values updated above into expressions in the function body
749789
foldConstants(constants, variables, locstants, builtinsFold, builtinsFoldLibraryK, options.libraryMemberConstantCb, func->body, names);
@@ -989,7 +1029,7 @@ struct Compiler
9891029
CompileError::raise(expr->func->location, "Exceeded jump distance limit; simplify the code to compile");
9901030
}
9911031

992-
bytecode.emitABC(LOP_CALL, regs, multCall ? 0 : uint8_t(expr->self + expr->args.size + 1), multRet ? 0 : uint8_t(targetCount + 1));
1032+
bytecode.emitABC(LOP_CALL, regs, (multCall && inlineFrames.size() == 0) ? 0 : uint8_t(expr->self + expr->args.size + 1), multRet ? 0 : uint8_t(targetCount + 1));
9931033

9941034
// if we didn't output results directly to target, we need to move them
9951035
if (!targetTop)
@@ -4136,6 +4176,7 @@ struct Compiler
41364176
struct InlineFrame
41374177
{
41384178
AstExprFunction* func;
4179+
AstExprCall* call;
41394180

41404181
size_t localOffset;
41414182

tests/conformance/vararg.luau

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,5 +167,11 @@ f = loadstring[[
167167
assert(f("a", "b", nil, {}, assert))
168168
assert(f())
169169

170+
-- pass to another variadic function
171+
local function passmc(...)
172+
assert(true, ...)
173+
end
174+
passmc(nil)
175+
170176
return('OK')
171177

0 commit comments

Comments
 (0)