Eagerly check function arguments when called from inside iterable (#778)

This mitigates an issue where lazy mappings and listings widen an existing bug.

This is a follow-up to https://github.com/apple/pkl/pull/752.
This commit is contained in:
Daniel Chao
2024-11-05 09:05:09 -08:00
committed by GitHub
parent 6d161ce1d4
commit b402463f3c
22 changed files with 215 additions and 49 deletions

View File

@@ -1986,6 +1986,7 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
visitArgumentList(argCtx),
MemberLookupMode.EXPLICIT_RECEIVER,
needsConst,
symbolTable.getCurrentScope().isVisitingIterable(),
PropagateNullReceiverNodeGen.create(unavailableSourceSection(), receiver),
GetClassNodeGen.create(null)));
}
@@ -1998,6 +1999,7 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
visitArgumentList(argCtx),
MemberLookupMode.EXPLICIT_RECEIVER,
needsConst,
symbolTable.getCurrentScope().isVisitingIterable(),
receiver,
GetClassNodeGen.create(null));
}
@@ -2072,7 +2074,11 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
}
return InvokeSuperMethodNodeGen.create(
sourceSection, memberName, visitArgumentList(argCtx), needsConst);
sourceSection,
memberName,
symbolTable.getCurrentScope().isVisitingIterable(),
visitArgumentList(argCtx),
needsConst);
}
// superproperty call
@@ -2130,7 +2136,8 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
isBaseModule,
scope.isCustomThisScope(),
scope.getConstLevel(),
scope.getConstDepth());
scope.getConstDepth(),
scope.isVisitingIterable());
}
@Override

View File

@@ -71,6 +71,6 @@ public final class LetExprNode extends ExpressionNode {
var value = valueNode.executeGeneric(frame);
return callNode.call(function.getThisValue(), function, value);
return callNode.call(function.getThisValue(), function, false, value);
}
}

View File

@@ -184,7 +184,8 @@ public final class AmendFunctionNode extends PklNode {
var arguments = new Object[frameArguments.length];
arguments[0] = functionToAmend.getThisValue();
arguments[1] = functionToAmend;
System.arraycopy(frameArguments, 2, arguments, 2, frameArguments.length - 2);
arguments[2] = false;
System.arraycopy(frameArguments, 3, arguments, 3, frameArguments.length - 3);
var valueToAmend = callNode.call(functionToAmend.getCallTarget(), arguments);
if (!(valueToAmend instanceof VmFunction newFunctionToAmend)) {

View File

@@ -28,6 +28,7 @@ public final class InvokeMethodDirectNode extends ExpressionNode {
private final VmObjectLike owner;
@Child private ExpressionNode receiverNode;
@Children private final ExpressionNode[] argumentNodes;
private final boolean isInIterable;
@Child private DirectCallNode callNode;
@@ -35,12 +36,14 @@ public final class InvokeMethodDirectNode extends ExpressionNode {
SourceSection sourceSection,
ClassMethod method,
ExpressionNode receiverNode,
ExpressionNode[] argumentNodes) {
ExpressionNode[] argumentNodes,
boolean isInIterable) {
super(sourceSection);
this.owner = method.getOwner();
this.receiverNode = receiverNode;
this.argumentNodes = argumentNodes;
this.isInIterable = isInIterable;
callNode = DirectCallNode.create(method.getCallTarget(sourceSection));
}
@@ -48,11 +51,12 @@ public final class InvokeMethodDirectNode extends ExpressionNode {
@Override
@ExplodeLoop
public Object executeGeneric(VirtualFrame frame) {
var args = new Object[2 + argumentNodes.length];
var args = new Object[3 + argumentNodes.length];
args[0] = receiverNode.executeGeneric(frame);
args[1] = owner;
args[2] = isInIterable;
for (var i = 0; i < argumentNodes.length; i++) {
args[2 + i] = argumentNodes[i].executeGeneric(frame);
args[3 + i] = argumentNodes[i].executeGeneric(frame);
}
return callNode.call(args);

View File

@@ -33,29 +33,33 @@ public final class InvokeMethodLexicalNode extends ExpressionNode {
private final int levelsUp;
@Child private DirectCallNode callNode;
private final boolean isInIterable;
InvokeMethodLexicalNode(
SourceSection sourceSection,
CallTarget callTarget,
int levelsUp,
ExpressionNode[] argumentNodes) {
ExpressionNode[] argumentNodes,
boolean isInIterable) {
super(sourceSection);
this.levelsUp = levelsUp;
this.argumentNodes = argumentNodes;
callNode = DirectCallNode.create(callTarget);
this.isInIterable = isInIterable;
}
@Override
@ExplodeLoop
public Object executeGeneric(VirtualFrame frame) {
var args = new Object[2 + argumentNodes.length];
var args = new Object[3 + argumentNodes.length];
var enclosingFrame = getEnclosingFrame(frame);
args[0] = VmUtils.getReceiver(enclosingFrame);
args[1] = VmUtils.getOwner(enclosingFrame);
args[2] = isInIterable;
for (var i = 0; i < argumentNodes.length; i++) {
args[2 + i] = argumentNodes[i].executeGeneric(frame);
args[3 + i] = argumentNodes[i].executeGeneric(frame);
}
return callNode.call(args);

View File

@@ -36,6 +36,7 @@ import org.pkl.core.runtime.VmClass;
import org.pkl.core.runtime.VmFunction;
/** A virtual method call. */
@SuppressWarnings("DuplicatedCode")
@ImportStatic(Identifier.class)
@NodeChild(value = "receiverNode", type = ExpressionNode.class)
@NodeChild(value = "receiverClassNode", type = GetClassNode.class, executeWith = "receiverNode")
@@ -44,27 +45,31 @@ public abstract class InvokeMethodVirtualNode extends ExpressionNode {
@Children private final ExpressionNode[] argumentNodes;
private final MemberLookupMode lookupMode;
private final boolean needsConst;
private final boolean isInIterable;
protected InvokeMethodVirtualNode(
SourceSection sourceSection,
Identifier methodName,
ExpressionNode[] argumentNodes,
MemberLookupMode lookupMode,
boolean needsConst) {
boolean needsConst,
boolean isInIterable) {
super(sourceSection);
this.methodName = methodName;
this.argumentNodes = argumentNodes;
this.lookupMode = lookupMode;
this.needsConst = needsConst;
this.isInIterable = isInIterable;
}
protected InvokeMethodVirtualNode(
SourceSection sourceSection,
Identifier methodName,
ExpressionNode[] argumentNodes,
MemberLookupMode lookupMode) {
this(sourceSection, methodName, argumentNodes, lookupMode, false);
MemberLookupMode lookupMode,
boolean isInIterable) {
this(sourceSection, methodName, argumentNodes, lookupMode, false, isInIterable);
}
/**
@@ -84,11 +89,12 @@ public abstract class InvokeMethodVirtualNode extends ExpressionNode {
RootCallTarget cachedCallTarget,
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
var args = new Object[2 + argumentNodes.length];
var args = new Object[3 + argumentNodes.length];
args[0] = receiver.getThisValue();
args[1] = receiver;
args[2] = isInIterable;
for (var i = 0; i < argumentNodes.length; i++) {
args[2 + i] = argumentNodes[i].executeGeneric(frame);
args[3 + i] = argumentNodes[i].executeGeneric(frame);
}
return callNode.call(args);
@@ -103,11 +109,12 @@ public abstract class InvokeMethodVirtualNode extends ExpressionNode {
@SuppressWarnings("unused") VmClass receiverClass,
@Exclusive @Cached("create()") IndirectCallNode callNode) {
var args = new Object[2 + argumentNodes.length];
var args = new Object[3 + argumentNodes.length];
args[0] = receiver.getThisValue();
args[1] = receiver;
args[2] = isInIterable;
for (var i = 0; i < argumentNodes.length; i++) {
args[2 + i] = argumentNodes[i].executeGeneric(frame);
args[3 + i] = argumentNodes[i].executeGeneric(frame);
}
return callNode.call(receiver.getCallTarget(), args);
@@ -123,11 +130,12 @@ public abstract class InvokeMethodVirtualNode extends ExpressionNode {
@Cached("resolveMethod(receiverClass)") ClassMethod method,
@Cached("create(method.getCallTarget(sourceSection))") DirectCallNode callNode) {
var args = new Object[2 + argumentNodes.length];
var args = new Object[3 + argumentNodes.length];
args[0] = receiver;
args[1] = method.getOwner();
args[2] = isInIterable;
for (var i = 0; i < argumentNodes.length; i++) {
args[2 + i] = argumentNodes[i].executeGeneric(frame);
args[3 + i] = argumentNodes[i].executeGeneric(frame);
}
return callNode.call(args);
@@ -142,11 +150,12 @@ public abstract class InvokeMethodVirtualNode extends ExpressionNode {
@Exclusive @Cached("create()") IndirectCallNode callNode) {
var method = resolveMethod(receiverClass);
var args = new Object[2 + argumentNodes.length];
var args = new Object[3 + argumentNodes.length];
args[0] = receiver;
args[1] = method.getOwner();
args[2] = isInIterable;
for (var i = 0; i < argumentNodes.length; i++) {
args[2 + i] = argumentNodes[i].executeGeneric(frame);
args[3 + i] = argumentNodes[i].executeGeneric(frame);
}
// Deprecation should not report here (getCallTarget(sourceSection)), as this happens for each

View File

@@ -30,15 +30,18 @@ import org.pkl.core.runtime.VmUtils;
public abstract class InvokeSuperMethodNode extends ExpressionNode {
private final Identifier methodName;
@Children private final ExpressionNode[] argumentNodes;
private final boolean isInIterable;
private final boolean needsConst;
protected InvokeSuperMethodNode(
SourceSection sourceSection,
Identifier methodName,
boolean isInIterable,
ExpressionNode[] argumentNodes,
boolean needsConst) {
super(sourceSection);
this.isInIterable = isInIterable;
this.needsConst = needsConst;
assert !methodName.isLocalMethod();
@@ -54,11 +57,12 @@ public abstract class InvokeSuperMethodNode extends ExpressionNode {
@Cached(value = "findSupermethod(frame)", neverDefault = true) ClassMethod supermethod,
@Cached("create(supermethod.getCallTarget(sourceSection))") DirectCallNode callNode) {
var args = new Object[2 + argumentNodes.length];
var args = new Object[3 + argumentNodes.length];
args[0] = VmUtils.getReceiverOrNull(frame);
args[1] = supermethod.getOwner();
args[2] = isInIterable;
for (int i = 0; i < argumentNodes.length; i++) {
args[2 + i] = argumentNodes[i].executeGeneric(frame);
args[3 + i] = argumentNodes[i].executeGeneric(frame);
}
return callNode.call(args);

View File

@@ -50,6 +50,7 @@ public final class ResolveMethodNode extends ExpressionNode {
private final boolean isCustomThisScope;
private final ConstLevel constLevel;
private final int constDepth;
private final boolean isInIterable;
public ResolveMethodNode(
SourceSection sourceSection,
@@ -58,7 +59,8 @@ public final class ResolveMethodNode extends ExpressionNode {
boolean isBaseModule,
boolean isCustomThisScope,
ConstLevel constLevel,
int constDepth) {
int constDepth,
boolean isInIterable) {
super(sourceSection);
@@ -68,6 +70,7 @@ public final class ResolveMethodNode extends ExpressionNode {
this.isCustomThisScope = isCustomThisScope;
this.constLevel = constLevel;
this.constDepth = constDepth;
this.isInIterable = isInIterable;
}
@Override
@@ -91,7 +94,11 @@ public final class ResolveMethodNode extends ExpressionNode {
assert localMethod.isLocal();
checkConst(currOwner, localMethod, levelsUp);
return new InvokeMethodLexicalNode(
sourceSection, localMethod.getCallTarget(sourceSection), levelsUp, argumentNodes);
sourceSection,
localMethod.getCallTarget(sourceSection),
levelsUp,
argumentNodes,
isInIterable);
}
var method = currOwner.getVmClass().getDeclaredMethod(methodName);
if (method != null) {
@@ -99,7 +106,11 @@ public final class ResolveMethodNode extends ExpressionNode {
checkConst(currOwner, method, levelsUp);
if (method.getDeclaringClass().isClosed()) {
return new InvokeMethodLexicalNode(
sourceSection, method.getCallTarget(sourceSection), levelsUp, argumentNodes);
sourceSection,
method.getCallTarget(sourceSection),
levelsUp,
argumentNodes,
isInIterable);
}
//noinspection ConstantConditions
@@ -108,6 +119,7 @@ public final class ResolveMethodNode extends ExpressionNode {
methodName,
argumentNodes,
MemberLookupMode.IMPLICIT_LEXICAL,
isInIterable,
levelsUp == 0 ? new GetReceiverNode() : new GetEnclosingReceiverNode(levelsUp),
GetClassNodeGen.create(null));
}
@@ -122,7 +134,7 @@ public final class ResolveMethodNode extends ExpressionNode {
(CallTarget) localMethod.getCallTarget().call(currOwner, currOwner);
return new InvokeMethodLexicalNode(
sourceSection, methodCallTarget, levelsUp, argumentNodes);
sourceSection, methodCallTarget, levelsUp, argumentNodes, isInIterable);
}
}
@@ -138,7 +150,7 @@ public final class ResolveMethodNode extends ExpressionNode {
if (method != null) {
assert !method.isLocal();
return new InvokeMethodDirectNode(
sourceSection, method, new ConstantValueNode(baseModule), argumentNodes);
sourceSection, method, new ConstantValueNode(baseModule), argumentNodes, isInIterable);
}
}
@@ -158,6 +170,7 @@ public final class ResolveMethodNode extends ExpressionNode {
argumentNodes,
MemberLookupMode.IMPLICIT_THIS,
needsConst,
isInIterable,
VmUtils.createThisNode(VmUtils.unavailableSourceSection(), isCustomThisScope),
GetClassNodeGen.create(null));
}

View File

@@ -80,6 +80,7 @@ public abstract class ToStringNode extends UnaryExpressionNode {
Identifier.TO_STRING,
new ExpressionNode[] {},
MemberLookupMode.EXPLICIT_RECEIVER,
false,
null,
null);
}

View File

@@ -33,12 +33,12 @@ public abstract class ApplyVmFunction0Node extends PklNode {
RootCallTarget cachedCallTarget,
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
return callNode.call(function.getThisValue(), function);
return callNode.call(function.getThisValue(), function, false);
}
@Specialization(replaces = "evalDirect")
protected Object eval(VmFunction function, @Cached("create()") IndirectCallNode callNode) {
return callNode.call(function.getCallTarget(), function.getThisValue(), function);
return callNode.call(function.getCallTarget(), function.getThisValue(), function, false);
}
}

View File

@@ -77,13 +77,13 @@ public abstract class ApplyVmFunction1Node extends ExpressionNode {
RootCallTarget cachedCallTarget,
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
return callNode.call(function.getThisValue(), function, arg1);
return callNode.call(function.getThisValue(), function, false, arg1);
}
@Specialization(replaces = "evalDirect")
protected Object eval(
VmFunction function, Object arg1, @Cached("create()") IndirectCallNode callNode) {
return callNode.call(function.getCallTarget(), function.getThisValue(), function, arg1);
return callNode.call(function.getCallTarget(), function.getThisValue(), function, false, arg1);
}
}

View File

@@ -76,7 +76,7 @@ public abstract class ApplyVmFunction2Node extends PklNode {
RootCallTarget cachedCallTarget,
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
return callNode.call(function.getThisValue(), function, arg1, arg2);
return callNode.call(function.getThisValue(), function, false, arg1, arg2);
}
@Specialization(replaces = "evalDirect")
@@ -86,6 +86,7 @@ public abstract class ApplyVmFunction2Node extends PklNode {
Object arg2,
@Cached("create()") IndirectCallNode callNode) {
return callNode.call(function.getCallTarget(), function.getThisValue(), function, arg1, arg2);
return callNode.call(
function.getCallTarget(), function.getThisValue(), function, false, arg1, arg2);
}
}

View File

@@ -36,7 +36,7 @@ public abstract class ApplyVmFunction3Node extends PklNode {
RootCallTarget cachedCallTarget,
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
return callNode.call(function.getThisValue(), function, arg1, arg2, arg3);
return callNode.call(function.getThisValue(), function, false, arg1, arg2, arg3);
}
@Specialization(replaces = "evalDirect")
@@ -48,6 +48,6 @@ public abstract class ApplyVmFunction3Node extends PklNode {
@Cached("create()") IndirectCallNode callNode) {
return callNode.call(
function.getCallTarget(), function.getThisValue(), function, arg1, arg2, arg3);
function.getCallTarget(), function.getThisValue(), function, false, arg1, arg2, arg3);
}
}

View File

@@ -38,7 +38,7 @@ public abstract class ApplyVmFunction4Node extends PklNode {
RootCallTarget cachedCallTarget,
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
return callNode.call(function.getThisValue(), function, arg1, arg2, arg3, arg4);
return callNode.call(function.getThisValue(), function, false, arg1, arg2, arg3, arg4);
}
@Specialization(replaces = "evalDirect")
@@ -51,6 +51,6 @@ public abstract class ApplyVmFunction4Node extends PklNode {
@Cached("create()") IndirectCallNode callNode) {
return callNode.call(
function.getCallTarget(), function.getThisValue(), function, arg1, arg2, arg3, arg4);
function.getCallTarget(), function.getThisValue(), function, false, arg1, arg2, arg3, arg4);
}
}

View File

@@ -39,7 +39,7 @@ public abstract class ApplyVmFunction5Node extends PklNode {
RootCallTarget cachedCallTarget,
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
return callNode.call(function.getThisValue(), function, arg1, arg2, arg3, arg4, arg5);
return callNode.call(function.getThisValue(), function, false, arg1, arg2, arg3, arg4, arg5);
}
@Specialization(replaces = "evalDirect")
@@ -53,6 +53,14 @@ public abstract class ApplyVmFunction5Node extends PklNode {
@Cached("create()") IndirectCallNode callNode) {
return callNode.call(
function.getCallTarget(), function.getThisValue(), function, arg1, arg2, arg3, arg4, arg5);
function.getCallTarget(),
function.getThisValue(),
function,
false,
arg1,
arg2,
arg3,
arg4,
arg5);
}
}

View File

@@ -44,7 +44,11 @@ public final class FunctionNode extends RegularMemberNode {
// For VmObject receivers, the owner is the same as or an ancestor of the receiver.
// For other receivers, the owner is the prototype of the receiver's class.
// The chain of enclosing owners forms a function/property's lexical scope.
private static final int IMPLICIT_PARAM_COUNT = 2;
//
// For function calls only, a third implicit argument is passed; whether the call came from within
// an iterable node or not.
// This is a mitigation for an existing bug (https://github.com/apple/pkl/issues/741).
private static final int IMPLICIT_PARAM_COUNT = 3;
private final int paramCount;
private final int totalParamCount;
@@ -109,10 +113,15 @@ public final class FunctionNode extends RegularMemberNode {
throw wrongArgumentCount(totalArgCount - IMPLICIT_PARAM_COUNT);
}
var isInIterable = (boolean) frame.getArguments()[2];
try {
for (var i = 0; i < parameterTypeNodes.length; i++) {
var argument = frame.getArguments()[IMPLICIT_PARAM_COUNT + i];
parameterTypeNodes[i].executeAndSet(frame, argument);
if (isInIterable) {
parameterTypeNodes[i].executeEagerlyAndSet(frame, argument);
} else {
parameterTypeNodes[i].executeAndSet(frame, argument);
}
}
var result = bodyNode.executeGeneric(frame);

View File

@@ -55,16 +55,16 @@ public final class IdentityMixinNode extends PklRootNode {
@Override
public Object execute(VirtualFrame frame) {
var arguments = frame.getArguments();
if (arguments.length != 3) {
if (arguments.length != 4) {
CompilerDirectives.transferToInterpreter();
throw exceptionBuilder()
.evalError("wrongFunctionArgumentCount", 1, arguments.length - 2)
.evalError("wrongFunctionArgumentCount", 1, arguments.length - 3)
.withSourceSection(sourceSection)
.build();
}
try {
var argument = arguments[2];
var argument = arguments[3];
if (argumentTypeNode != null) {
return argumentTypeNode.execute(frame, argument);
}

View File

@@ -94,6 +94,14 @@ public abstract class TypeNode extends PklNode {
return execute(frame, value);
}
/**
* Checks if {@code value} conforms to this type.
*
* <p>If {@code value} is conforming, sets {@code slot} to {@code value}. Otherwise, throws a
* {@link VmTypeMismatchException}.
*/
public abstract Object executeEagerlyAndSet(VirtualFrame frame, Object value);
// method arguments are used when default value contains a root node
public @Nullable Object createDefaultValue(
VmLanguage language,
@@ -213,6 +221,11 @@ public abstract class TypeNode extends PklNode {
frame.setLong(slot, (long) value);
return value;
}
@Override
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
return executeAndSet(frame, value);
}
}
public abstract static class ObjectSlotTypeNode extends FrameSlotTypeNode {
@@ -230,6 +243,13 @@ public abstract class TypeNode extends PklNode {
frame.setObject(slot, result);
return result;
}
@Override
public final Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
var result = executeEagerly(frame, value);
frame.setObject(slot, result);
return result;
}
}
/**
@@ -263,6 +283,13 @@ public abstract class TypeNode extends PklNode {
writeSlotNode.executeWithValue(frame, result);
return result;
}
@Override
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
var result = executeEagerly(frame, value);
writeSlotNode.executeWithValue(frame, result);
return result;
}
}
/** The `unknown` type. */
@@ -328,6 +355,11 @@ public abstract class TypeNode extends PklNode {
throw PklBugException.unreachableCode();
}
@Override
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
return executeAndSet(frame, value);
}
@Override
public FrameSlotKind getFrameSlotKind() {
return FrameSlotKind.Illegal;
@@ -2382,6 +2414,22 @@ public abstract class TypeNode extends PklNode {
}
}
/** See docstring on {@link TypeAliasTypeNode#execute}. */
@Override
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
var prevOwner = VmUtils.getOwner(frame);
var prevReceiver = VmUtils.getReceiver(frame);
VmUtils.setOwner(frame, VmUtils.getOwner(typeAlias.getEnclosingFrame()));
VmUtils.setReceiver(frame, VmUtils.getReceiver(typeAlias.getEnclosingFrame()));
try {
return aliasedTypeNode.executeEagerlyAndSet(frame, value);
} finally {
VmUtils.setOwner(frame, prevOwner);
VmUtils.setReceiver(frame, prevReceiver);
}
}
@Override
@TruffleBoundary
public @Nullable Object createDefaultValue(
@@ -2501,6 +2549,13 @@ public abstract class TypeNode extends PklNode {
return ret;
}
@Override
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
var ret = executeEagerly(frame, value);
childNode.executeEagerlyAndSet(frame, ret);
return ret;
}
@Override
public @Nullable Object createDefaultValue(
VmLanguage language, SourceSection headerSection, String qualifiedName) {
@@ -2648,6 +2703,11 @@ public abstract class TypeNode extends PklNode {
}
}
@Override
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
return executeAndSet(frame, value);
}
@Override
public VmClass getVmClass() {
return BaseModule.getNumberClass();
@@ -2716,6 +2776,11 @@ public abstract class TypeNode extends PklNode {
return value;
}
@Override
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
return executeAndSet(frame, value);
}
@Override
public VmClass getVmClass() {
return BaseModule.getFloatClass();
@@ -2756,6 +2821,11 @@ public abstract class TypeNode extends PklNode {
return value;
}
@Override
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
return executeAndSet(frame, value);
}
@Override
public VmClass getVmClass() {
return BaseModule.getBooleanClass();

View File

@@ -55,7 +55,7 @@ public final class VmFunction extends VmObjectLike {
// if call site is a node, use ApplyVmFunction1Node.execute() or DirectCallNode.call() instead of
// this method
public Object apply(Object arg1) {
return getCallTarget().call(thisValue, this, arg1);
return getCallTarget().call(thisValue, this, false, arg1);
}
public String applyString(Object arg1) {
@@ -69,7 +69,7 @@ public final class VmFunction extends VmObjectLike {
// if call site is a node, use ApplyVmFunction2Node.execute() or DirectCallNode.call() instead of
// this method
public Object apply(Object arg1, Object arg2) {
return getCallTarget().call(thisValue, this, arg1, arg2);
return getCallTarget().call(thisValue, this, false, arg1, arg2);
}
public VmFunction copy(

View File

@@ -31,11 +31,12 @@ public final class FunctionNodes {
protected Object eval(VmFunction self, VmList argList) {
var argCount = argList.getLength();
var args = new Object[2 + argCount];
var args = new Object[3 + argCount];
args[0] = self.getThisValue();
args[1] = self;
args[2] = false;
var i = 2;
var i = 3;
for (var arg : argList) {
args[i++] = arg;
}

View File

@@ -31,3 +31,27 @@ res2 {
}.birds
}
}
res3 {
for (key, _ in Map("hello-there", 5)) {
...myself(new Listing {
new Listing {
key
}
})
}
}
res4 {
for (key, _ in Map("hello-there", 5)) {
...myself2.apply(new Listing {
new Listing {
key
}
})
}
}
function myself(l: Listing<Listing<String>>) = l
local myself2 = (l: Listing<Listing<String>>) -> l

View File

@@ -8,3 +8,13 @@ res2 {
age = 1
}
}
res3 {
new {
"hello-there"
}
}
res4 {
new {
"hello-there"
}
}