mirror of
https://github.com/apple/pkl.git
synced 2026-08-26 21:54:03 +02:00
Improve evaluation of typealiases (#1796)
This simplifies the resolution of names in typealias constraints. This removes the existing logic around swapping out the frame's owner/receiver, and instead favors resolving the variable at parse time. * During variable resolution, create read variable nodes that read off of a receiver node * Introduce `GetTypeAliasModuleNode` that provides the typealias's enclosing module * Inject the enclosing module during typealias instantiation
This commit is contained in:
@@ -112,14 +112,17 @@ import org.pkl.core.ast.expression.literal.TrueLiteralNode;
|
|||||||
import org.pkl.core.ast.expression.member.InferParentWithinMethodNode;
|
import org.pkl.core.ast.expression.member.InferParentWithinMethodNode;
|
||||||
import org.pkl.core.ast.expression.member.InferParentWithinObjectMethodNode;
|
import org.pkl.core.ast.expression.member.InferParentWithinObjectMethodNode;
|
||||||
import org.pkl.core.ast.expression.member.InferParentWithinPropertyNodeGen;
|
import org.pkl.core.ast.expression.member.InferParentWithinPropertyNodeGen;
|
||||||
import org.pkl.core.ast.expression.member.InvokeClassMethodNode;
|
import org.pkl.core.ast.expression.member.InvokeLexicalClassMethodNode;
|
||||||
|
import org.pkl.core.ast.expression.member.InvokeLexicalObjectMethodNode;
|
||||||
import org.pkl.core.ast.expression.member.InvokeMethodDirectNode;
|
import org.pkl.core.ast.expression.member.InvokeMethodDirectNode;
|
||||||
import org.pkl.core.ast.expression.member.InvokeMethodVirtualNodeGen;
|
import org.pkl.core.ast.expression.member.InvokeMethodVirtualNodeGen;
|
||||||
import org.pkl.core.ast.expression.member.InvokeObjectMethodNode;
|
import org.pkl.core.ast.expression.member.InvokeQualifiedClassMethodNode;
|
||||||
|
import org.pkl.core.ast.expression.member.InvokeQualifiedObjectMethodNode;
|
||||||
import org.pkl.core.ast.expression.member.InvokeSuperMethodNodeGen;
|
import org.pkl.core.ast.expression.member.InvokeSuperMethodNodeGen;
|
||||||
import org.pkl.core.ast.expression.member.ReadAmbiguousLocalityPropertyNode;
|
import org.pkl.core.ast.expression.member.ReadAmbiguousLocalityPropertyNode;
|
||||||
import org.pkl.core.ast.expression.member.ReadLocalPropertyNode;
|
import org.pkl.core.ast.expression.member.ReadLexicalLocalPropertyNode;
|
||||||
import org.pkl.core.ast.expression.member.ReadPropertyNodeGen;
|
import org.pkl.core.ast.expression.member.ReadPropertyNodeGen;
|
||||||
|
import org.pkl.core.ast.expression.member.ReadQualifiedLocalPropertyNode;
|
||||||
import org.pkl.core.ast.expression.member.ReadSuperEntryNode;
|
import org.pkl.core.ast.expression.member.ReadSuperEntryNode;
|
||||||
import org.pkl.core.ast.expression.member.ReadSuperPropertyNode;
|
import org.pkl.core.ast.expression.member.ReadSuperPropertyNode;
|
||||||
import org.pkl.core.ast.expression.primary.ExecuteCustomThisWithRootNode;
|
import org.pkl.core.ast.expression.primary.ExecuteCustomThisWithRootNode;
|
||||||
@@ -128,6 +131,7 @@ import org.pkl.core.ast.expression.primary.GetMemberKeyNode;
|
|||||||
import org.pkl.core.ast.expression.primary.GetModuleNode;
|
import org.pkl.core.ast.expression.primary.GetModuleNode;
|
||||||
import org.pkl.core.ast.expression.primary.GetOwnerNode;
|
import org.pkl.core.ast.expression.primary.GetOwnerNode;
|
||||||
import org.pkl.core.ast.expression.primary.GetReceiverNode;
|
import org.pkl.core.ast.expression.primary.GetReceiverNode;
|
||||||
|
import org.pkl.core.ast.expression.primary.GetTypeAliasModuleNode;
|
||||||
import org.pkl.core.ast.expression.primary.OuterNode;
|
import org.pkl.core.ast.expression.primary.OuterNode;
|
||||||
import org.pkl.core.ast.expression.primary.ThisNode;
|
import org.pkl.core.ast.expression.primary.ThisNode;
|
||||||
import org.pkl.core.ast.expression.ternary.IfElseNode;
|
import org.pkl.core.ast.expression.ternary.IfElseNode;
|
||||||
@@ -526,7 +530,7 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GetModuleNode visitModuleExpr(ModuleExpr expr) {
|
public ExpressionNode visitModuleExpr(ModuleExpr expr) {
|
||||||
var currentScope = symbolTable.getCurrentScope();
|
var currentScope = symbolTable.getCurrentScope();
|
||||||
// cannot use unqualified `module` in a const context
|
// cannot use unqualified `module` in a const context
|
||||||
if (currentScope.getConstLevel().isConst() && !(expr.parent() instanceof QualifiedAccessExpr)) {
|
if (currentScope.getConstLevel().isConst() && !(expr.parent() instanceof QualifiedAccessExpr)) {
|
||||||
@@ -549,7 +553,9 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
.withSourceSection(createSourceSection(expr))
|
.withSourceSection(createSourceSection(expr))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
return new GetModuleNode(createSourceSection(expr));
|
return symbolTable.isInTypeAliasScope
|
||||||
|
? new GetTypeAliasModuleNode(createSourceSection(expr))
|
||||||
|
: new GetModuleNode(createSourceSection(expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -687,12 +693,30 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
case MODULE -> p.isModuleScope();
|
case MODULE -> p.isModuleScope();
|
||||||
case ALL -> p.levelsUp() > constDepth;
|
case ALL -> p.levelsUp() > constDepth;
|
||||||
};
|
};
|
||||||
|
// Assumption: typealiases can only be declared on the module.
|
||||||
|
// If we ever allow typealiases in classes, this code needs to change.
|
||||||
|
if (symbolTable.isInTypeAliasScope && p.isModuleScope()) {
|
||||||
|
var getModuleNode = new GetTypeAliasModuleNode(sourceSection);
|
||||||
|
if (p.isLocal()) {
|
||||||
|
return new ReadQualifiedLocalPropertyNode(
|
||||||
|
sourceSection,
|
||||||
|
org.pkl.core.runtime.Identifier.localProperty(name),
|
||||||
|
needsConst,
|
||||||
|
getModuleNode);
|
||||||
|
}
|
||||||
|
return ReadPropertyNodeGen.create(
|
||||||
|
sourceSection,
|
||||||
|
org.pkl.core.runtime.Identifier.get(name),
|
||||||
|
MemberLookupMode.IMPLICIT_LEXICAL,
|
||||||
|
needsConst,
|
||||||
|
getModuleNode);
|
||||||
|
}
|
||||||
if (p.isAmbiguousLocality()) {
|
if (p.isAmbiguousLocality()) {
|
||||||
return new ReadAmbiguousLocalityPropertyNode(
|
return new ReadAmbiguousLocalityPropertyNode(
|
||||||
sourceSection, org.pkl.core.runtime.Identifier.get(name), p.levelsUp(), needsConst);
|
sourceSection, org.pkl.core.runtime.Identifier.get(name), p.levelsUp(), needsConst);
|
||||||
}
|
}
|
||||||
if (p.isLocal()) {
|
if (p.isLocal()) {
|
||||||
return new ReadLocalPropertyNode(
|
return new ReadLexicalLocalPropertyNode(
|
||||||
sourceSection,
|
sourceSection,
|
||||||
org.pkl.core.runtime.Identifier.localProperty(name),
|
org.pkl.core.runtime.Identifier.localProperty(name),
|
||||||
p.levelsUp(),
|
p.levelsUp(),
|
||||||
@@ -769,11 +793,34 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
case MODULE -> method.isModuleScope();
|
case MODULE -> method.isModuleScope();
|
||||||
case ALL -> method.levelsUp() > constDepth;
|
case ALL -> method.levelsUp() > constDepth;
|
||||||
};
|
};
|
||||||
|
// Assumption: typealiases can only be declared on the module.
|
||||||
|
// If we ever allow typealiases in classes, this code needs to change.
|
||||||
|
if (symbolTable.isInTypeAliasScope && method.isModuleScope()) {
|
||||||
|
var getModuleNode = new GetTypeAliasModuleNode(sourceSection);
|
||||||
|
if (method.isObjectMethod()) {
|
||||||
|
return new InvokeQualifiedObjectMethodNode(
|
||||||
|
sourceSection, identifier, args, needsConst, getModuleNode);
|
||||||
|
}
|
||||||
|
if (method.isOnClosedClass() || method.isLocal() || method.isExternal()) {
|
||||||
|
return new InvokeQualifiedClassMethodNode(
|
||||||
|
sourceSection, identifier, args, needsConst, getModuleNode);
|
||||||
|
}
|
||||||
|
return InvokeMethodVirtualNodeGen.create(
|
||||||
|
sourceSection,
|
||||||
|
identifier,
|
||||||
|
args,
|
||||||
|
MemberLookupMode.IMPLICIT_LEXICAL,
|
||||||
|
needsConst,
|
||||||
|
getModuleNode,
|
||||||
|
GetClassNodeGen.create(null));
|
||||||
|
}
|
||||||
if (method.isObjectMethod()) {
|
if (method.isObjectMethod()) {
|
||||||
return new InvokeObjectMethodNode(sourceSection, identifier, levelsUp, args, needsConst);
|
return new InvokeLexicalObjectMethodNode(
|
||||||
|
sourceSection, identifier, levelsUp, args, needsConst);
|
||||||
}
|
}
|
||||||
if (method.isOnClosedClass() || method.isLocal() || method.isExternal()) {
|
if (method.isOnClosedClass() || method.isLocal() || method.isExternal()) {
|
||||||
return new InvokeClassMethodNode(sourceSection, identifier, levelsUp, args, needsConst);
|
return new InvokeLexicalClassMethodNode(
|
||||||
|
sourceSection, identifier, levelsUp, args, needsConst);
|
||||||
}
|
}
|
||||||
return InvokeMethodVirtualNodeGen.create(
|
return InvokeMethodVirtualNodeGen.create(
|
||||||
sourceSection,
|
sourceSection,
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ import org.pkl.parser.Lexer;
|
|||||||
public final class SymbolTable {
|
public final class SymbolTable {
|
||||||
|
|
||||||
private Scope currentScope;
|
private Scope currentScope;
|
||||||
|
// consider having each scope keep track of this individually rather than set on SymbolTable.
|
||||||
|
public boolean isInTypeAliasScope;
|
||||||
|
|
||||||
public SymbolTable(ModuleInfo moduleInfo, boolean isBaseModule) {
|
public SymbolTable(ModuleInfo moduleInfo, boolean isBaseModule) {
|
||||||
currentScope = new ModuleScope(moduleInfo, isBaseModule);
|
currentScope = new ModuleScope(moduleInfo, isBaseModule);
|
||||||
@@ -85,14 +87,19 @@ public final class SymbolTable {
|
|||||||
Identifier name,
|
Identifier name,
|
||||||
List<TypeParameter> typeParameters,
|
List<TypeParameter> typeParameters,
|
||||||
Function<TypeAliasScope, ObjectMember> nodeFactory) {
|
Function<TypeAliasScope, ObjectMember> nodeFactory) {
|
||||||
return doEnter(
|
try {
|
||||||
new TypeAliasScope(
|
this.isInTypeAliasScope = true;
|
||||||
currentScope,
|
return doEnter(
|
||||||
name,
|
new TypeAliasScope(
|
||||||
toQualifiedName(name),
|
currentScope,
|
||||||
new FrameDescriptorBuilder(),
|
name,
|
||||||
typeParameters),
|
toQualifiedName(name),
|
||||||
nodeFactory);
|
new FrameDescriptorBuilder(),
|
||||||
|
typeParameters),
|
||||||
|
nodeFactory);
|
||||||
|
} finally {
|
||||||
|
this.isInTypeAliasScope = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T enterMethod(
|
public <T> T enterMethod(
|
||||||
|
|||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pkl.core.ast.expression.member;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
|
import org.pkl.core.runtime.Identifier;
|
||||||
|
import org.pkl.core.runtime.VmUtils;
|
||||||
|
|
||||||
|
public abstract sealed class AbstractInvokeLexicalMethodNode extends AbstractInvokeMethodNode
|
||||||
|
permits InvokeLexicalClassMethodNode, InvokeLexicalObjectMethodNode {
|
||||||
|
private final int levelsUp;
|
||||||
|
|
||||||
|
public AbstractInvokeLexicalMethodNode(
|
||||||
|
SourceSection sourceSection,
|
||||||
|
Identifier methodName,
|
||||||
|
int levelsUp,
|
||||||
|
ExpressionNode[] argumentNodes,
|
||||||
|
boolean needsConst) {
|
||||||
|
super(sourceSection, methodName, argumentNodes, needsConst);
|
||||||
|
this.levelsUp = levelsUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Object executeGeneric(VirtualFrame frame) {
|
||||||
|
var capturedFrame = VmUtils.getFrame(frame, levelsUp);
|
||||||
|
var owner = VmUtils.getOwner(capturedFrame);
|
||||||
|
var receiver = VmUtils.getReceiver(capturedFrame);
|
||||||
|
return invoke(frame, owner, receiver);
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
-17
@@ -26,40 +26,40 @@ import org.jspecify.annotations.Nullable;
|
|||||||
import org.pkl.core.ast.ExpressionNode;
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
import org.pkl.core.runtime.Identifier;
|
import org.pkl.core.runtime.Identifier;
|
||||||
import org.pkl.core.runtime.VmObjectLike;
|
import org.pkl.core.runtime.VmObjectLike;
|
||||||
import org.pkl.core.runtime.VmUtils;
|
|
||||||
|
|
||||||
public abstract sealed class AbstractInvokeMethodLexicalNode extends ExpressionNode
|
/**
|
||||||
permits InvokeObjectMethodNode, InvokeClassMethodNode {
|
* A non-virtual (statically dispatched) method call.
|
||||||
|
*
|
||||||
|
* <p>Subclasses differ only in how they obtain the {@code owner}/{@code receiver} that the method
|
||||||
|
* is invoked on: either by walking the frame chain ({@link InvokeLexicalClassMethodNode}, {@link
|
||||||
|
* InvokeLexicalObjectMethodNode}), or off of an explicit receiver expression ({@link
|
||||||
|
* InvokeQualifiedClassMethodNode}, {@link InvokeQualifiedObjectMethodNode}).
|
||||||
|
*/
|
||||||
|
public abstract sealed class AbstractInvokeMethodNode extends ExpressionNode
|
||||||
|
permits AbstractInvokeQualifiedMethodNode, AbstractInvokeLexicalMethodNode {
|
||||||
|
|
||||||
protected final Identifier methodName;
|
protected final Identifier methodName;
|
||||||
protected final int levelsUp;
|
|
||||||
private final boolean needsConst;
|
private final boolean needsConst;
|
||||||
@Children private ExpressionNode[] argumentNodes;
|
@Children private ExpressionNode[] argumentNodes;
|
||||||
@Child private @Nullable DirectCallNode callNode;
|
@Child private @Nullable DirectCallNode callNode;
|
||||||
@CompilationFinal protected boolean isConstChecked;
|
@CompilationFinal protected boolean isConstChecked;
|
||||||
|
|
||||||
protected AbstractInvokeMethodLexicalNode(
|
protected AbstractInvokeMethodNode(
|
||||||
SourceSection sourceSection,
|
SourceSection sourceSection,
|
||||||
Identifier methodName,
|
Identifier methodName,
|
||||||
int levelsUp,
|
|
||||||
ExpressionNode[] argumentNodes,
|
ExpressionNode[] argumentNodes,
|
||||||
boolean needsConst) {
|
boolean needsConst) {
|
||||||
super(sourceSection);
|
super(sourceSection);
|
||||||
this.methodName = methodName;
|
this.methodName = methodName;
|
||||||
this.levelsUp = levelsUp;
|
|
||||||
this.argumentNodes = argumentNodes;
|
this.argumentNodes = argumentNodes;
|
||||||
this.needsConst = needsConst;
|
this.needsConst = needsConst;
|
||||||
this.isConstChecked = false;
|
this.isConstChecked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@ExplodeLoop
|
@ExplodeLoop
|
||||||
public final Object executeGeneric(VirtualFrame frame) {
|
protected final Object invoke(VirtualFrame frame, VmObjectLike owner, Object receiver) {
|
||||||
var args = new Object[2 + argumentNodes.length];
|
|
||||||
var capturedFrame = VmUtils.getFrame(frame, levelsUp);
|
|
||||||
var owner = VmUtils.getOwner(capturedFrame);
|
|
||||||
var receiver = VmUtils.getReceiver(capturedFrame);
|
|
||||||
checkConst(owner);
|
checkConst(owner);
|
||||||
|
var args = new Object[2 + argumentNodes.length];
|
||||||
args[0] = receiver;
|
args[0] = receiver;
|
||||||
args[1] = owner;
|
args[1] = owner;
|
||||||
for (var i = 0; i < argumentNodes.length; i++) {
|
for (var i = 0; i < argumentNodes.length; i++) {
|
||||||
@@ -81,10 +81,6 @@ public abstract sealed class AbstractInvokeMethodLexicalNode extends ExpressionN
|
|||||||
|
|
||||||
protected abstract void doCheckConst(VmObjectLike owner);
|
protected abstract void doCheckConst(VmObjectLike owner);
|
||||||
|
|
||||||
protected final VmObjectLike getOwner(VirtualFrame frame) {
|
|
||||||
return VmUtils.getOwner(frame, levelsUp);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected DirectCallNode getCallNode(VmObjectLike owner) {
|
protected DirectCallNode getCallNode(VmObjectLike owner) {
|
||||||
if (callNode == null) {
|
if (callNode == null) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pkl.core.ast.expression.member;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
|
import org.pkl.core.runtime.Identifier;
|
||||||
|
import org.pkl.core.runtime.VmTyped;
|
||||||
|
|
||||||
|
public abstract sealed class AbstractInvokeQualifiedMethodNode extends AbstractInvokeMethodNode
|
||||||
|
permits InvokeQualifiedClassMethodNode, InvokeQualifiedObjectMethodNode {
|
||||||
|
@Child private ExpressionNode getReceiverNode;
|
||||||
|
|
||||||
|
protected AbstractInvokeQualifiedMethodNode(
|
||||||
|
SourceSection sourceSection,
|
||||||
|
Identifier methodName,
|
||||||
|
ExpressionNode[] argumentNodes,
|
||||||
|
boolean needsConst,
|
||||||
|
ExpressionNode getReceiverNode) {
|
||||||
|
super(sourceSection, methodName, argumentNodes, needsConst);
|
||||||
|
this.getReceiverNode = getReceiverNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Object executeGeneric(VirtualFrame frame) {
|
||||||
|
var receiver = (VmTyped) getReceiverNode.executeGeneric(frame);
|
||||||
|
return invoke(frame, receiver, receiver);
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-39
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,69 +15,38 @@
|
|||||||
*/
|
*/
|
||||||
package org.pkl.core.ast.expression.member;
|
package org.pkl.core.ast.expression.member;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerAsserts;
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
|
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
|
||||||
import com.oracle.truffle.api.nodes.DirectCallNode;
|
import com.oracle.truffle.api.nodes.DirectCallNode;
|
||||||
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
import org.pkl.core.PklBugException;
|
|
||||||
import org.pkl.core.ast.ExpressionNode;
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
import org.pkl.core.ast.member.ObjectMember;
|
import org.pkl.core.ast.member.ObjectMember;
|
||||||
import org.pkl.core.runtime.Identifier;
|
import org.pkl.core.runtime.Identifier;
|
||||||
import org.pkl.core.runtime.VmObjectLike;
|
import org.pkl.core.runtime.VmObjectLike;
|
||||||
import org.pkl.core.runtime.VmUtils;
|
|
||||||
|
|
||||||
/** Reads a local non-constant property that is known to exist in the lexical scope of this node. */
|
public abstract class AbstractReadLocalPropertyNode extends ExpressionNode {
|
||||||
public final class ReadLocalPropertyNode extends ExpressionNode {
|
|
||||||
private final Identifier name;
|
private final Identifier name;
|
||||||
private final int levelsUp;
|
|
||||||
private final boolean needsConst;
|
private final boolean needsConst;
|
||||||
@Child private @Nullable DirectCallNode callNode;
|
@Child private @Nullable DirectCallNode callNode;
|
||||||
@CompilationFinal @Nullable private ObjectMember property;
|
@CompilationFinal @Nullable private ObjectMember property;
|
||||||
|
|
||||||
public ReadLocalPropertyNode(
|
public AbstractReadLocalPropertyNode(
|
||||||
SourceSection sourceSection, Identifier name, int levelsUp, boolean needsConst) {
|
SourceSection sourceSection, Identifier name, boolean needsConst) {
|
||||||
|
|
||||||
super(sourceSection);
|
super(sourceSection);
|
||||||
CompilerAsserts.neverPartOfCompilation();
|
|
||||||
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.levelsUp = levelsUp;
|
|
||||||
this.needsConst = needsConst;
|
this.needsConst = needsConst;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected ObjectMember getProperty(VmObjectLike owner) {
|
||||||
@ExplodeLoop
|
|
||||||
public Object executeGeneric(VirtualFrame frame) {
|
|
||||||
var owner = VmUtils.getOwner(frame, levelsUp);
|
|
||||||
var property = getProperty(owner);
|
|
||||||
var constantValue = property.getConstantValue();
|
|
||||||
if (constantValue != null) {
|
|
||||||
return constantValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var receiver = (VmObjectLike) VmUtils.getReceiver(frame, levelsUp);
|
|
||||||
var result = receiver.getCachedValue(property);
|
|
||||||
|
|
||||||
if (result == null) {
|
|
||||||
result = getCallNode(property).call(receiver, owner, property.getName());
|
|
||||||
receiver.setCachedValue(property, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ObjectMember getProperty(VmObjectLike owner) {
|
|
||||||
if (property == null) {
|
if (property == null) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
property = owner.getMember(name);
|
property = owner.getMember(name);
|
||||||
if (property == null) {
|
if (property == null) {
|
||||||
// should never happen
|
// should never happen
|
||||||
CompilerDirectives.transferToInterpreter();
|
CompilerDirectives.transferToInterpreter();
|
||||||
throw new PklBugException("Couldn't find local variable `" + name + "`.");
|
throw exceptionBuilder().bug("Couldn't find local variable `" + name + "`.").build();
|
||||||
}
|
}
|
||||||
if (needsConst && !property.isConst()) {
|
if (needsConst && !property.isConst()) {
|
||||||
throw exceptionBuilder().evalError("propertyMustBeConst", name.toString()).build();
|
throw exceptionBuilder().evalError("propertyMustBeConst", name.toString()).build();
|
||||||
@@ -86,7 +55,7 @@ public final class ReadLocalPropertyNode extends ExpressionNode {
|
|||||||
return property;
|
return property;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DirectCallNode getCallNode(ObjectMember property) {
|
protected DirectCallNode getCallNode(ObjectMember property) {
|
||||||
if (callNode == null) {
|
if (callNode == null) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
callNode = DirectCallNode.create(property.getCallTarget());
|
callNode = DirectCallNode.create(property.getCallTarget());
|
||||||
+2
-4
@@ -24,11 +24,9 @@ import org.pkl.core.runtime.VmObjectLike;
|
|||||||
/**
|
/**
|
||||||
* A non-virtual call of closed methods (methods whose enclosing class/module is not open nor
|
* A non-virtual call of closed methods (methods whose enclosing class/module is not open nor
|
||||||
* abstract, and is lexically scoped).
|
* abstract, and is lexically scoped).
|
||||||
*
|
|
||||||
* <p>For local methods, use {@link InvokeObjectMethodNode}.
|
|
||||||
*/
|
*/
|
||||||
public final class InvokeClassMethodNode extends AbstractInvokeMethodLexicalNode {
|
public final class InvokeLexicalClassMethodNode extends AbstractInvokeLexicalMethodNode {
|
||||||
public InvokeClassMethodNode(
|
public InvokeLexicalClassMethodNode(
|
||||||
SourceSection sourceSection,
|
SourceSection sourceSection,
|
||||||
Identifier methodName,
|
Identifier methodName,
|
||||||
int levelsUp,
|
int levelsUp,
|
||||||
+4
-3
@@ -22,9 +22,9 @@ import org.pkl.core.ast.VmModifier;
|
|||||||
import org.pkl.core.runtime.Identifier;
|
import org.pkl.core.runtime.Identifier;
|
||||||
import org.pkl.core.runtime.VmObjectLike;
|
import org.pkl.core.runtime.VmObjectLike;
|
||||||
|
|
||||||
/** A non-virtual call of a local method. */
|
/** A non-virtual call of an object method that is lexically scoped. */
|
||||||
public final class InvokeObjectMethodNode extends AbstractInvokeMethodLexicalNode {
|
public final class InvokeLexicalObjectMethodNode extends AbstractInvokeLexicalMethodNode {
|
||||||
public InvokeObjectMethodNode(
|
public InvokeLexicalObjectMethodNode(
|
||||||
SourceSection sourceSection,
|
SourceSection sourceSection,
|
||||||
Identifier methodName,
|
Identifier methodName,
|
||||||
int levelsUp,
|
int levelsUp,
|
||||||
@@ -33,6 +33,7 @@ public final class InvokeObjectMethodNode extends AbstractInvokeMethodLexicalNod
|
|||||||
super(sourceSection, methodName, levelsUp, argumentNodes, needsConst);
|
super(sourceSection, methodName, levelsUp, argumentNodes, needsConst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected void doCheckConst(VmObjectLike owner) {
|
protected void doCheckConst(VmObjectLike owner) {
|
||||||
var member = owner.getMember(methodName);
|
var member = owner.getMember(methodName);
|
||||||
assert member != null;
|
assert member != null;
|
||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pkl.core.ast.expression.member;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CallTarget;
|
||||||
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
|
import org.pkl.core.runtime.Identifier;
|
||||||
|
import org.pkl.core.runtime.VmObjectLike;
|
||||||
|
|
||||||
|
/** A non-virtual call of a closed class method, invoked off of an explicit receiver. */
|
||||||
|
public final class InvokeQualifiedClassMethodNode extends AbstractInvokeQualifiedMethodNode {
|
||||||
|
public InvokeQualifiedClassMethodNode(
|
||||||
|
SourceSection sourceSection,
|
||||||
|
Identifier methodName,
|
||||||
|
ExpressionNode[] argumentNodes,
|
||||||
|
boolean needsConst,
|
||||||
|
ExpressionNode getReceiverNode) {
|
||||||
|
super(sourceSection, methodName, argumentNodes, needsConst, getReceiverNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doCheckConst(VmObjectLike owner) {
|
||||||
|
var method = owner.getVmClass().getDeclaredMethod(methodName);
|
||||||
|
assert method != null;
|
||||||
|
if (!method.isConst()) {
|
||||||
|
throw exceptionBuilder().evalError("methodMustBeConst", methodName).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CallTarget getCallTarget(VmObjectLike owner) {
|
||||||
|
var method = owner.getVmClass().getDeclaredMethod(methodName);
|
||||||
|
assert method != null;
|
||||||
|
return method.getCallTarget(getSourceSection());
|
||||||
|
}
|
||||||
|
}
|
||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pkl.core.ast.expression.member;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CallTarget;
|
||||||
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
|
import org.pkl.core.ast.VmModifier;
|
||||||
|
import org.pkl.core.runtime.Identifier;
|
||||||
|
import org.pkl.core.runtime.VmObjectLike;
|
||||||
|
|
||||||
|
/** A non-virtual call of an object method, invoked off of an explicit receiver. */
|
||||||
|
public final class InvokeQualifiedObjectMethodNode extends AbstractInvokeQualifiedMethodNode {
|
||||||
|
public InvokeQualifiedObjectMethodNode(
|
||||||
|
SourceSection sourceSection,
|
||||||
|
Identifier methodName,
|
||||||
|
ExpressionNode[] argumentNodes,
|
||||||
|
boolean needsConst,
|
||||||
|
ExpressionNode getReceiverNode) {
|
||||||
|
super(sourceSection, methodName, argumentNodes, needsConst, getReceiverNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doCheckConst(VmObjectLike owner) {
|
||||||
|
var member = owner.getMember(methodName);
|
||||||
|
assert member != null;
|
||||||
|
if (!VmModifier.isConst(member.getModifiers())) {
|
||||||
|
throw exceptionBuilder().evalError("methodMustBeConst", methodName).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CallTarget getCallTarget(VmObjectLike owner) {
|
||||||
|
var method = owner.getMember(methodName);
|
||||||
|
assert method != null && method.isLocal();
|
||||||
|
return (CallTarget) method.getCallTarget().call(owner, owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -67,7 +67,7 @@ public final class ReadAmbiguousLocalityPropertyNode extends ExpressionNode {
|
|||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
readLocalPropertyNode =
|
readLocalPropertyNode =
|
||||||
insert(
|
insert(
|
||||||
new ReadLocalPropertyNode(
|
new ReadLexicalLocalPropertyNode(
|
||||||
sourceSection, name.toLocalProperty(), levelsUp, needsConst));
|
sourceSection, name.toLocalProperty(), levelsUp, needsConst));
|
||||||
}
|
}
|
||||||
return readLocalPropertyNode;
|
return readLocalPropertyNode;
|
||||||
|
|||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pkl.core.ast.expression.member;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CompilerAsserts;
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
|
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
||||||
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
|
import org.pkl.core.runtime.Identifier;
|
||||||
|
import org.pkl.core.runtime.VmObjectLike;
|
||||||
|
import org.pkl.core.runtime.VmUtils;
|
||||||
|
|
||||||
|
/** Reads a local non-constant property that is known to exist in the lexical scope of this node. */
|
||||||
|
public final class ReadLexicalLocalPropertyNode extends AbstractReadLocalPropertyNode {
|
||||||
|
private final int levelsUp;
|
||||||
|
|
||||||
|
public ReadLexicalLocalPropertyNode(
|
||||||
|
SourceSection sourceSection, Identifier name, int levelsUp, boolean needsConst) {
|
||||||
|
super(sourceSection, name, needsConst);
|
||||||
|
CompilerAsserts.neverPartOfCompilation();
|
||||||
|
this.levelsUp = levelsUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@ExplodeLoop
|
||||||
|
public Object executeGeneric(VirtualFrame frame) {
|
||||||
|
var owner = VmUtils.getOwner(frame, levelsUp);
|
||||||
|
var property = getProperty(owner);
|
||||||
|
var constantValue = property.getConstantValue();
|
||||||
|
if (constantValue != null) {
|
||||||
|
return constantValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var receiver = (VmObjectLike) VmUtils.getReceiver(frame, levelsUp);
|
||||||
|
var result = receiver.getCachedValue(property);
|
||||||
|
if (result == null) {
|
||||||
|
result = getCallNode(property).call(receiver, owner, property.getName());
|
||||||
|
receiver.setCachedValue(property, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pkl.core.ast.expression.member;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
|
import org.pkl.core.runtime.Identifier;
|
||||||
|
import org.pkl.core.runtime.VmTyped;
|
||||||
|
|
||||||
|
/** Reads a local property off of the receiver node. */
|
||||||
|
public final class ReadQualifiedLocalPropertyNode extends AbstractReadLocalPropertyNode {
|
||||||
|
@Child private ExpressionNode getReceiverNode;
|
||||||
|
|
||||||
|
public ReadQualifiedLocalPropertyNode(
|
||||||
|
SourceSection sourceSection,
|
||||||
|
Identifier identifier,
|
||||||
|
boolean needsConst,
|
||||||
|
ExpressionNode getReceiverNode) {
|
||||||
|
super(sourceSection, identifier, needsConst);
|
||||||
|
this.getReceiverNode = getReceiverNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object executeGeneric(VirtualFrame frame) {
|
||||||
|
var receiver = (VmTyped) getReceiverNode.executeGeneric(frame);
|
||||||
|
var property = getProperty(receiver);
|
||||||
|
var constantValue = property.getConstantValue();
|
||||||
|
if (constantValue != null) {
|
||||||
|
return constantValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = receiver.getCachedValue(property);
|
||||||
|
if (result == null) {
|
||||||
|
result = getCallNode(property).call(receiver, receiver, property.getName());
|
||||||
|
receiver.setCachedValue(property, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pkl.core.ast.expression.primary;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
|
import org.pkl.core.runtime.VmTyped;
|
||||||
|
|
||||||
|
public final class GetTypeAliasModuleNode extends ExpressionNode {
|
||||||
|
|
||||||
|
@CompilationFinal private @Nullable VmTyped module;
|
||||||
|
|
||||||
|
public GetTypeAliasModuleNode(SourceSection sourceSection) {
|
||||||
|
super(sourceSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInstrumentable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void lateInitModule(VmTyped module) {
|
||||||
|
// must only set this once; the first typealias initialization wins.
|
||||||
|
// guards against nested typealiases; e.g. `typealias A = module; typealias B = A`
|
||||||
|
if (this.module != null) return;
|
||||||
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
|
this.module = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object executeGeneric(VirtualFrame frame) {
|
||||||
|
assert module != null;
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ import java.util.List;
|
|||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
import org.pkl.core.TypeParameter;
|
import org.pkl.core.TypeParameter;
|
||||||
import org.pkl.core.ast.ExpressionNode;
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
|
import org.pkl.core.ast.expression.primary.GetTypeAliasModuleNode;
|
||||||
import org.pkl.core.ast.type.UnresolvedTypeNode;
|
import org.pkl.core.ast.type.UnresolvedTypeNode;
|
||||||
import org.pkl.core.runtime.VmTypeAlias;
|
import org.pkl.core.runtime.VmTypeAlias;
|
||||||
import org.pkl.core.runtime.VmTyped;
|
import org.pkl.core.runtime.VmTyped;
|
||||||
@@ -86,7 +87,15 @@ public final class TypeAliasNode extends ExpressionNode {
|
|||||||
frame.materialize());
|
frame.materialize());
|
||||||
|
|
||||||
VmUtils.evaluateAnnotations(frame, annotationNodes, annotations);
|
VmUtils.evaluateAnnotations(frame, annotationNodes, annotations);
|
||||||
cachedTypeAlias.initTypeCheckNode(typeAnnotationNode.execute(frame));
|
var bodyTypeNode = typeAnnotationNode.execute(frame);
|
||||||
|
bodyTypeNode.accept(
|
||||||
|
node -> {
|
||||||
|
if (node instanceof GetTypeAliasModuleNode getTypeAliasModuleNode) {
|
||||||
|
getTypeAliasModuleNode.lateInitModule(module);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
cachedTypeAlias.initTypeCheckNode(bodyTypeNode);
|
||||||
|
|
||||||
return cachedTypeAlias;
|
return cachedTypeAlias;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
|||||||
import com.oracle.truffle.api.dsl.Cached;
|
import com.oracle.truffle.api.dsl.Cached;
|
||||||
import com.oracle.truffle.api.dsl.Fallback;
|
import com.oracle.truffle.api.dsl.Fallback;
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
import com.oracle.truffle.api.frame.Frame;
|
|
||||||
import com.oracle.truffle.api.frame.FrameDescriptor;
|
import com.oracle.truffle.api.frame.FrameDescriptor;
|
||||||
import com.oracle.truffle.api.frame.FrameSlotKind;
|
import com.oracle.truffle.api.frame.FrameSlotKind;
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
@@ -2735,56 +2734,18 @@ public abstract class TypeNode extends PklNode {
|
|||||||
return getMirrors(typeArgumentNodes);
|
return getMirrors(typeArgumentNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A typealias body is effectively inlined into the type node, and not executed in its own
|
|
||||||
* frame.
|
|
||||||
*
|
|
||||||
* <p>Before executing the typealias body, use the owner and receiver of the original frame
|
|
||||||
* where the typealias was declared, so that we preserve its original scope.
|
|
||||||
*/
|
|
||||||
protected Object executeLazily(VirtualFrame frame, Object value) {
|
protected Object executeLazily(VirtualFrame frame, Object value) {
|
||||||
var prevOwner = VmUtils.getOwner(frame);
|
return aliasedTypeNode.executeLazily(frame, value);
|
||||||
var prevReceiver = VmUtils.getReceiver(frame);
|
|
||||||
setOwner(frame, VmUtils.getOwner(typeAlias.getEnclosingFrame()));
|
|
||||||
setReceiver(frame, VmUtils.getReceiver(typeAlias.getEnclosingFrame()));
|
|
||||||
|
|
||||||
try {
|
|
||||||
return aliasedTypeNode.executeLazily(frame, value);
|
|
||||||
} finally {
|
|
||||||
setOwner(frame, prevOwner);
|
|
||||||
setReceiver(frame, prevReceiver);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object executeEagerly(VirtualFrame frame, Object value) {
|
public Object executeEagerly(VirtualFrame frame, Object value) {
|
||||||
var prevOwner = VmUtils.getOwner(frame);
|
return aliasedTypeNode.executeEagerly(frame, value);
|
||||||
var prevReceiver = VmUtils.getReceiver(frame);
|
|
||||||
setOwner(frame, VmUtils.getOwner(typeAlias.getEnclosingFrame()));
|
|
||||||
setReceiver(frame, VmUtils.getReceiver(typeAlias.getEnclosingFrame()));
|
|
||||||
|
|
||||||
try {
|
|
||||||
return aliasedTypeNode.executeEagerly(frame, value);
|
|
||||||
} finally {
|
|
||||||
setOwner(frame, prevOwner);
|
|
||||||
setReceiver(frame, prevReceiver);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** See docstring on {@link TypeAliasTypeNode#executeLazily}. */
|
|
||||||
@Override
|
@Override
|
||||||
public Object executeAndSet(VirtualFrame frame, Object value) {
|
public Object executeAndSet(VirtualFrame frame, Object value) {
|
||||||
var prevOwner = VmUtils.getOwner(frame);
|
return aliasedTypeNode.executeAndSet(frame, value);
|
||||||
var prevReceiver = VmUtils.getReceiver(frame);
|
|
||||||
setOwner(frame, VmUtils.getOwner(typeAlias.getEnclosingFrame()));
|
|
||||||
setReceiver(frame, VmUtils.getReceiver(typeAlias.getEnclosingFrame()));
|
|
||||||
|
|
||||||
try {
|
|
||||||
return aliasedTypeNode.executeAndSet(frame, value);
|
|
||||||
} finally {
|
|
||||||
setOwner(frame, prevOwner);
|
|
||||||
setReceiver(frame, prevReceiver);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
@@ -2859,22 +2820,6 @@ public abstract class TypeNode extends PklNode {
|
|||||||
protected boolean isParametric() {
|
protected boolean isParametric() {
|
||||||
return typeArgumentNodes.length > 0;
|
return typeArgumentNodes.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that mutating a frame's receiver and owner argument is very risky
|
|
||||||
// because any VmObject instantiated within the same root node execution
|
|
||||||
// holds a reference to (not immutable snapshot of) the frame
|
|
||||||
// via VmObjectLike.enclosingFrame.
|
|
||||||
// *Maybe* this works out for TypeAliasTypeNode because an object instantiated
|
|
||||||
// within a type constraint doesn't escape the constraint expression.
|
|
||||||
// If mutating receiver and owner can't be avoided, it would be safer
|
|
||||||
// to have VmObjectLike store them directly instead of storing enclosingFrame.
|
|
||||||
private static void setReceiver(Frame frame, Object receiver) {
|
|
||||||
frame.getArguments()[0] = receiver;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void setOwner(Frame frame, VmObjectLike owner) {
|
|
||||||
frame.getArguments()[1] = owner;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class ConstrainedTypeNode extends TypeNode {
|
public static final class ConstrainedTypeNode extends TypeNode {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
typealias Id<T> = T
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
name: String = "base"
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
amends "typeAliasAmendBase.pkl"
|
||||||
|
|
||||||
|
local const function isValid(s: String): Boolean = s.startsWith("Bob")
|
||||||
|
|
||||||
|
local typealias ValidString4 = String(isValid(this))
|
||||||
|
|
||||||
|
local myProp: ValidString4 = "Bob Marley"
|
||||||
|
|
||||||
|
name = myProp
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
const function isValid(s: String): Boolean = s.startsWith("Bob")
|
||||||
|
|
||||||
|
typealias ValidString2 = String(isValid(this))
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
local const function isValid(s: String): Boolean = s.startsWith("Bob")
|
||||||
|
|
||||||
|
typealias ValidString3 = String(isValid(this))
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
typealias MyModule = module
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
open module typeAliasOpenModule
|
||||||
|
|
||||||
|
const function isValid(s: String): Boolean = s.startsWith("Bob")
|
||||||
|
|
||||||
|
typealias ValidString = String(isValid(this))
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
const name = "Bob"
|
||||||
|
|
||||||
|
typealias Inner = String(startsWith(name))
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
import "typealias1.pkl"
|
||||||
|
|
||||||
|
const name = "Alice"
|
||||||
|
|
||||||
|
typealias Outer = typealias1.Inner
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import "../../input-helper/types/idType.pkl"
|
||||||
|
|
||||||
|
hidden modules: Listing<idType.Id<module>> = new {
|
||||||
|
new module {}
|
||||||
|
new module {}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = modules.length
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import "../../input-helper/types/typeAliasModule.pkl"
|
||||||
|
|
||||||
|
res: typeAliasModule = module
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
import "../../input-helper/types/typealias2.pkl"
|
||||||
|
|
||||||
|
myProp: typealias2.Outer = "Alice Jenkins"
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
import "../../input-helper/types/typeAliasOpenModule.pkl"
|
||||||
|
|
||||||
|
const function isValid(s: String): Boolean = s.startsWith("Alice")
|
||||||
|
|
||||||
|
myProp: typeAliasOpenModule.ValidString = "Alice Jenkins"
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
import "../../input-helper/types/typeAliasClosedModule.pkl"
|
||||||
|
|
||||||
|
const function isValid(s: String): Boolean = s.startsWith("Alice")
|
||||||
|
|
||||||
|
myProp: typeAliasClosedModule.ValidString2 = "Alice Jenkins"
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
import "../../input-helper/types/typeAliasLocalMethod.pkl"
|
||||||
|
|
||||||
|
local const function isValid(s: String): Boolean = s.startsWith("Alice")
|
||||||
|
|
||||||
|
myProp: typeAliasLocalMethod.ValidString3 = "Alice Jenkins"
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
import "../../input-helper/types/typeAliasAmendModule.pkl"
|
||||||
|
|
||||||
|
local const function isValid(s: String): Boolean = s.startsWith("Alice")
|
||||||
|
|
||||||
|
res = typeAliasAmendModule.name
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
res = 2
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Expected value of type `typeAliasModule`, but got type `typeAlias6`.
|
||||||
|
Value: new ModuleClass { res = ? }
|
||||||
|
|
||||||
|
x | res: typeAliasModule = module
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
at typeAlias6#res (file:///$snippetsDir/input/types/typeAlias6.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Type constraint `startsWith(name)` violated.
|
||||||
|
Value: "Alice Jenkins"
|
||||||
|
|
||||||
|
startsWith(name)
|
||||||
|
│ │
|
||||||
|
false "Bob"
|
||||||
|
|
||||||
|
x | typealias Inner = String(startsWith(name))
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
at typeAliasConstraint4#myProp (file:///$snippetsDir/input-helper/types/typealias1.pkl)
|
||||||
|
|
||||||
|
x | myProp: typealias2.Outer = "Alice Jenkins"
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
at typeAliasConstraint4#myProp (file:///$snippetsDir/input/types/typeAliasConstraint4.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Type constraint `isValid(this)` violated.
|
||||||
|
Value: "Alice Jenkins"
|
||||||
|
|
||||||
|
isValid(this)
|
||||||
|
│ │
|
||||||
|
false "Alice Jenkins"
|
||||||
|
|
||||||
|
x | typealias ValidString = String(isValid(this))
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
at typeAliasConstraint5#myProp (file:///$snippetsDir/input-helper/types/typeAliasOpenModule.pkl)
|
||||||
|
|
||||||
|
x | myProp: typeAliasOpenModule.ValidString = "Alice Jenkins"
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
at typeAliasConstraint5#myProp (file:///$snippetsDir/input/types/typeAliasConstraint5.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Type constraint `isValid(this)` violated.
|
||||||
|
Value: "Alice Jenkins"
|
||||||
|
|
||||||
|
isValid(this)
|
||||||
|
│ │
|
||||||
|
false "Alice Jenkins"
|
||||||
|
|
||||||
|
x | typealias ValidString2 = String(isValid(this))
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
at typeAliasConstraint6#myProp (file:///$snippetsDir/input-helper/types/typeAliasClosedModule.pkl)
|
||||||
|
|
||||||
|
x | myProp: typeAliasClosedModule.ValidString2 = "Alice Jenkins"
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
at typeAliasConstraint6#myProp (file:///$snippetsDir/input/types/typeAliasConstraint6.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Type constraint `isValid(this)` violated.
|
||||||
|
Value: "Alice Jenkins"
|
||||||
|
|
||||||
|
isValid(this)
|
||||||
|
│ │
|
||||||
|
false "Alice Jenkins"
|
||||||
|
|
||||||
|
x | typealias ValidString3 = String(isValid(this))
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
at typeAliasConstraint7#myProp (file:///$snippetsDir/input-helper/types/typeAliasLocalMethod.pkl)
|
||||||
|
|
||||||
|
x | myProp: typeAliasLocalMethod.ValidString3 = "Alice Jenkins"
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
at typeAliasConstraint7#myProp (file:///$snippetsDir/input/types/typeAliasConstraint7.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
res = "Bob Marley"
|
||||||
Reference in New Issue
Block a user