Fix name resolution in typealias with constraint (#144)

The body of a typealias gets inlined into wherever the typealias
is used. This fixes a bug where the references in the typealias body can
resolve to the wrong value.
This commit is contained in:
Kushal Pisavadia
2024-02-15 21:28:10 +00:00
committed by GitHub
parent 1c29287344
commit 3d1db25864
11 changed files with 76 additions and 7 deletions

View File

@@ -82,7 +82,8 @@ public final class TypeAliasNode extends ExpressionNode {
simpleName,
module,
qualifiedName,
typeParameters);
typeParameters,
frame.materialize());
VmUtils.evaluateAnnotations(frame, annotationNodes, annotations);
cachedTypeAlias.initTypeCheckNode(typeAnnotationNode.execute(frame));

View File

@@ -1614,13 +1614,36 @@ public abstract class TypeNode extends PklNode {
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.
*/
public void execute(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()));
aliasedTypeNode.execute(frame, value);
VmUtils.setOwner(frame, prevOwner);
VmUtils.setReceiver(frame, prevReceiver);
}
/** See docstring on {@link TypeAliasTypeNode#execute}. */
@Override
public void executeAndSet(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()));
aliasedTypeNode.executeAndSet(frame, value);
VmUtils.setOwner(frame, prevOwner);
VmUtils.setReceiver(frame, prevReceiver);
}
@Override

View File

@@ -16,6 +16,8 @@
package org.pkl.core.runtime;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.source.SourceSection;
import java.util.ArrayList;
import java.util.List;
@@ -42,6 +44,7 @@ public final class VmTypeAlias extends VmValue {
private final VmTyped module;
private final String qualifiedName;
private final List<TypeParameter> typeParameters;
private final MaterializedFrame enclosingFrame;
@LateInit private TypeNode typeNode;
@@ -66,7 +69,8 @@ public final class VmTypeAlias extends VmValue {
String simpleName,
VmTyped module,
String qualifiedName,
List<TypeParameter> typeParameters) {
List<TypeParameter> typeParameters,
MaterializedFrame enclosingFrame) {
this.sourceSection = sourceSection;
this.headerSection = headerSection;
this.docComment = docComment;
@@ -76,6 +80,7 @@ public final class VmTypeAlias extends VmValue {
this.module = module;
this.qualifiedName = qualifiedName;
this.typeParameters = typeParameters;
this.enclosingFrame = enclosingFrame;
}
public void initTypeCheckNode(TypeNode typeNode) {
@@ -155,6 +160,10 @@ public final class VmTypeAlias extends VmValue {
return typeNode;
}
public Frame getEnclosingFrame() {
return enclosingFrame;
}
@TruffleBoundary
public TypeNode instantiate(TypeNode[] typeArgumentNodes) {
// Cloning the type node means that the entire type check remains within a single root node,

View File

@@ -136,6 +136,10 @@ public final class VmUtils {
return result;
}
public static void setReceiver(Frame frame, Object receiver) {
frame.getArguments()[0] = receiver;
}
public static VmObjectLike getObjectReceiver(Frame frame) {
return (VmObjectLike) getReceiver(frame);
}
@@ -156,6 +160,10 @@ public final class VmUtils {
return result;
}
public static void setOwner(Frame frame, VmObjectLike owner) {
frame.getArguments()[1] = owner;
}
/** Returns a `ObjectMember`'s key while executing the corresponding `MemberNode`. */
public static Object getMemberKey(Frame frame) {
return frame.getArguments()[2];