mirror of
https://github.com/apple/pkl.git
synced 2026-08-06 04:08:41 +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.InferParentWithinObjectMethodNode;
|
||||
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.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.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.ReadQualifiedLocalPropertyNode;
|
||||
import org.pkl.core.ast.expression.member.ReadSuperEntryNode;
|
||||
import org.pkl.core.ast.expression.member.ReadSuperPropertyNode;
|
||||
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.GetOwnerNode;
|
||||
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.ThisNode;
|
||||
import org.pkl.core.ast.expression.ternary.IfElseNode;
|
||||
@@ -526,7 +530,7 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetModuleNode visitModuleExpr(ModuleExpr expr) {
|
||||
public ExpressionNode visitModuleExpr(ModuleExpr expr) {
|
||||
var currentScope = symbolTable.getCurrentScope();
|
||||
// cannot use unqualified `module` in a const context
|
||||
if (currentScope.getConstLevel().isConst() && !(expr.parent() instanceof QualifiedAccessExpr)) {
|
||||
@@ -549,7 +553,9 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
|
||||
.withSourceSection(createSourceSection(expr))
|
||||
.build();
|
||||
}
|
||||
return new GetModuleNode(createSourceSection(expr));
|
||||
return symbolTable.isInTypeAliasScope
|
||||
? new GetTypeAliasModuleNode(createSourceSection(expr))
|
||||
: new GetModuleNode(createSourceSection(expr));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -687,12 +693,30 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
|
||||
case MODULE -> p.isModuleScope();
|
||||
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()) {
|
||||
return new ReadAmbiguousLocalityPropertyNode(
|
||||
sourceSection, org.pkl.core.runtime.Identifier.get(name), p.levelsUp(), needsConst);
|
||||
}
|
||||
if (p.isLocal()) {
|
||||
return new ReadLocalPropertyNode(
|
||||
return new ReadLexicalLocalPropertyNode(
|
||||
sourceSection,
|
||||
org.pkl.core.runtime.Identifier.localProperty(name),
|
||||
p.levelsUp(),
|
||||
@@ -769,11 +793,34 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
|
||||
case MODULE -> method.isModuleScope();
|
||||
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()) {
|
||||
return new InvokeObjectMethodNode(sourceSection, identifier, levelsUp, args, needsConst);
|
||||
return new InvokeLexicalObjectMethodNode(
|
||||
sourceSection, identifier, levelsUp, args, needsConst);
|
||||
}
|
||||
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(
|
||||
sourceSection,
|
||||
|
||||
@@ -47,6 +47,8 @@ import org.pkl.parser.Lexer;
|
||||
public final class SymbolTable {
|
||||
|
||||
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) {
|
||||
currentScope = new ModuleScope(moduleInfo, isBaseModule);
|
||||
@@ -85,14 +87,19 @@ public final class SymbolTable {
|
||||
Identifier name,
|
||||
List<TypeParameter> typeParameters,
|
||||
Function<TypeAliasScope, ObjectMember> nodeFactory) {
|
||||
return doEnter(
|
||||
new TypeAliasScope(
|
||||
currentScope,
|
||||
name,
|
||||
toQualifiedName(name),
|
||||
new FrameDescriptorBuilder(),
|
||||
typeParameters),
|
||||
nodeFactory);
|
||||
try {
|
||||
this.isInTypeAliasScope = true;
|
||||
return doEnter(
|
||||
new TypeAliasScope(
|
||||
currentScope,
|
||||
name,
|
||||
toQualifiedName(name),
|
||||
new FrameDescriptorBuilder(),
|
||||
typeParameters),
|
||||
nodeFactory);
|
||||
} finally {
|
||||
this.isInTypeAliasScope = false;
|
||||
}
|
||||
}
|
||||
|
||||
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.runtime.Identifier;
|
||||
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 int levelsUp;
|
||||
private final boolean needsConst;
|
||||
@Children private ExpressionNode[] argumentNodes;
|
||||
@Child private @Nullable DirectCallNode callNode;
|
||||
@CompilationFinal protected boolean isConstChecked;
|
||||
|
||||
protected AbstractInvokeMethodLexicalNode(
|
||||
protected AbstractInvokeMethodNode(
|
||||
SourceSection sourceSection,
|
||||
Identifier methodName,
|
||||
int levelsUp,
|
||||
ExpressionNode[] argumentNodes,
|
||||
boolean needsConst) {
|
||||
super(sourceSection);
|
||||
this.methodName = methodName;
|
||||
this.levelsUp = levelsUp;
|
||||
this.argumentNodes = argumentNodes;
|
||||
this.needsConst = needsConst;
|
||||
this.isConstChecked = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ExplodeLoop
|
||||
public final Object executeGeneric(VirtualFrame frame) {
|
||||
var args = new Object[2 + argumentNodes.length];
|
||||
var capturedFrame = VmUtils.getFrame(frame, levelsUp);
|
||||
var owner = VmUtils.getOwner(capturedFrame);
|
||||
var receiver = VmUtils.getReceiver(capturedFrame);
|
||||
protected final Object invoke(VirtualFrame frame, VmObjectLike owner, Object receiver) {
|
||||
checkConst(owner);
|
||||
var args = new Object[2 + argumentNodes.length];
|
||||
args[0] = receiver;
|
||||
args[1] = owner;
|
||||
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 final VmObjectLike getOwner(VirtualFrame frame) {
|
||||
return VmUtils.getOwner(frame, levelsUp);
|
||||
}
|
||||
|
||||
protected DirectCallNode getCallNode(VmObjectLike owner) {
|
||||
if (callNode == null) {
|
||||
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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,69 +15,38 @@
|
||||
*/
|
||||
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.CompilationFinal;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.nodes.DirectCallNode;
|
||||
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
||||
import com.oracle.truffle.api.source.SourceSection;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.pkl.core.PklBugException;
|
||||
import org.pkl.core.ast.ExpressionNode;
|
||||
import org.pkl.core.ast.member.ObjectMember;
|
||||
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 ReadLocalPropertyNode extends ExpressionNode {
|
||||
public abstract class AbstractReadLocalPropertyNode extends ExpressionNode {
|
||||
|
||||
private final Identifier name;
|
||||
private final int levelsUp;
|
||||
private final boolean needsConst;
|
||||
@Child private @Nullable DirectCallNode callNode;
|
||||
@CompilationFinal @Nullable private ObjectMember property;
|
||||
|
||||
public ReadLocalPropertyNode(
|
||||
SourceSection sourceSection, Identifier name, int levelsUp, boolean needsConst) {
|
||||
|
||||
public AbstractReadLocalPropertyNode(
|
||||
SourceSection sourceSection, Identifier name, boolean needsConst) {
|
||||
super(sourceSection);
|
||||
CompilerAsserts.neverPartOfCompilation();
|
||||
|
||||
this.name = name;
|
||||
this.levelsUp = levelsUp;
|
||||
this.needsConst = needsConst;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
private ObjectMember getProperty(VmObjectLike owner) {
|
||||
protected ObjectMember getProperty(VmObjectLike owner) {
|
||||
if (property == null) {
|
||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||
property = owner.getMember(name);
|
||||
if (property == null) {
|
||||
// should never happen
|
||||
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()) {
|
||||
throw exceptionBuilder().evalError("propertyMustBeConst", name.toString()).build();
|
||||
@@ -86,7 +55,7 @@ public final class ReadLocalPropertyNode extends ExpressionNode {
|
||||
return property;
|
||||
}
|
||||
|
||||
public DirectCallNode getCallNode(ObjectMember property) {
|
||||
protected DirectCallNode getCallNode(ObjectMember property) {
|
||||
if (callNode == null) {
|
||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||
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
|
||||
* abstract, and is lexically scoped).
|
||||
*
|
||||
* <p>For local methods, use {@link InvokeObjectMethodNode}.
|
||||
*/
|
||||
public final class InvokeClassMethodNode extends AbstractInvokeMethodLexicalNode {
|
||||
public InvokeClassMethodNode(
|
||||
public final class InvokeLexicalClassMethodNode extends AbstractInvokeLexicalMethodNode {
|
||||
public InvokeLexicalClassMethodNode(
|
||||
SourceSection sourceSection,
|
||||
Identifier methodName,
|
||||
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.VmObjectLike;
|
||||
|
||||
/** A non-virtual call of a local method. */
|
||||
public final class InvokeObjectMethodNode extends AbstractInvokeMethodLexicalNode {
|
||||
public InvokeObjectMethodNode(
|
||||
/** A non-virtual call of an object method that is lexically scoped. */
|
||||
public final class InvokeLexicalObjectMethodNode extends AbstractInvokeLexicalMethodNode {
|
||||
public InvokeLexicalObjectMethodNode(
|
||||
SourceSection sourceSection,
|
||||
Identifier methodName,
|
||||
int levelsUp,
|
||||
@@ -33,6 +33,7 @@ public final class InvokeObjectMethodNode extends AbstractInvokeMethodLexicalNod
|
||||
super(sourceSection, methodName, levelsUp, argumentNodes, needsConst);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doCheckConst(VmObjectLike owner) {
|
||||
var member = owner.getMember(methodName);
|
||||
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();
|
||||
readLocalPropertyNode =
|
||||
insert(
|
||||
new ReadLocalPropertyNode(
|
||||
new ReadLexicalLocalPropertyNode(
|
||||
sourceSection, name.toLocalProperty(), levelsUp, needsConst));
|
||||
}
|
||||
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.pkl.core.TypeParameter;
|
||||
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.runtime.VmTypeAlias;
|
||||
import org.pkl.core.runtime.VmTyped;
|
||||
@@ -86,7 +87,15 @@ public final class TypeAliasNode extends ExpressionNode {
|
||||
frame.materialize());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.Fallback;
|
||||
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.FrameSlotKind;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
@@ -2735,56 +2734,18 @@ 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.
|
||||
*/
|
||||
protected Object executeLazily(VirtualFrame frame, Object value) {
|
||||
var prevOwner = VmUtils.getOwner(frame);
|
||||
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);
|
||||
}
|
||||
return aliasedTypeNode.executeLazily(frame, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object executeEagerly(VirtualFrame frame, Object value) {
|
||||
var prevOwner = VmUtils.getOwner(frame);
|
||||
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);
|
||||
}
|
||||
return aliasedTypeNode.executeEagerly(frame, value);
|
||||
}
|
||||
|
||||
/** See docstring on {@link TypeAliasTypeNode#executeLazily}. */
|
||||
@Override
|
||||
public Object executeAndSet(VirtualFrame frame, Object value) {
|
||||
var prevOwner = VmUtils.getOwner(frame);
|
||||
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);
|
||||
}
|
||||
return aliasedTypeNode.executeAndSet(frame, value);
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
@@ -2859,22 +2820,6 @@ public abstract class TypeNode extends PklNode {
|
||||
protected boolean isParametric() {
|
||||
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 {
|
||||
|
||||
@@ -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