mirror of
https://github.com/apple/pkl.git
synced 2026-01-11 14:20:35 +01:00
Fix default value for non-final module type (#1392)
This fixes an issue where the `module` type produces the wrong default value. Closes #1391
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* 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.
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.pkl.core.ast;
|
||||
|
||||
import com.oracle.truffle.api.frame.FrameDescriptor;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.source.SourceSection;
|
||||
import org.pkl.core.ast.member.DefaultPropertyBodyNode;
|
||||
import org.pkl.core.runtime.VmExceptionBuilder;
|
||||
@@ -46,7 +47,8 @@ public abstract class MemberNode extends PklRootNode {
|
||||
return new VmExceptionBuilder().withSourceSection(getHeaderSection());
|
||||
}
|
||||
|
||||
public boolean isUndefined() {
|
||||
return bodyNode instanceof DefaultPropertyBodyNode propBodyNode && propBodyNode.isUndefined();
|
||||
public boolean isUndefined(VirtualFrame frame) {
|
||||
return bodyNode instanceof DefaultPropertyBodyNode propBodyNode
|
||||
&& propBodyNode.isUndefined(frame);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* 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.
|
||||
@@ -67,7 +67,7 @@ public final class InferParentWithinMethodNode extends ExpressionNode {
|
||||
|
||||
var returnTypeDefaultValue =
|
||||
returnTypeNode.createDefaultValue(
|
||||
language, method.getHeaderSection(), method.getQualifiedName());
|
||||
frame, language, method.getHeaderSection(), method.getQualifiedName());
|
||||
if (returnTypeDefaultValue != null) {
|
||||
inferredParent = returnTypeDefaultValue;
|
||||
ownerNode = null;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* 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.
|
||||
@@ -75,7 +75,7 @@ public final class InferParentWithinObjectMethodNode extends ExpressionNode {
|
||||
|
||||
Object defaultReturnTypeValue =
|
||||
returnTypeNode.createDefaultValue(
|
||||
language, member.getHeaderSection(), member.getQualifiedName());
|
||||
frame, language, member.getHeaderSection(), member.getQualifiedName());
|
||||
if (defaultReturnTypeValue != null) {
|
||||
inferredParent = defaultReturnTypeValue;
|
||||
ownerNode = null;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* 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.
|
||||
@@ -18,6 +18,7 @@ package org.pkl.core.ast.expression.member;
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.NodeChild;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
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.*;
|
||||
@@ -35,9 +36,9 @@ public abstract class InferParentWithinPropertyNode extends ExpressionNode {
|
||||
}
|
||||
|
||||
@Specialization(guards = "!owner.isPrototype()")
|
||||
protected Object evalTypedObject(VmTyped owner) {
|
||||
protected Object evalTypedObject(VirtualFrame frame, VmTyped owner) {
|
||||
if (isLocalProperty) {
|
||||
return getLocalPropertyDefaultValue(owner);
|
||||
return getLocalPropertyDefaultValue(frame, owner);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -51,7 +52,7 @@ public abstract class InferParentWithinPropertyNode extends ExpressionNode {
|
||||
}
|
||||
|
||||
@Specialization(guards = "owner.isPrototype()")
|
||||
protected Object evalPrototype(VmTyped owner) {
|
||||
protected Object evalPrototype(VirtualFrame frame, VmTyped owner) {
|
||||
var property =
|
||||
isLocalProperty
|
||||
?
|
||||
@@ -66,7 +67,7 @@ public abstract class InferParentWithinPropertyNode extends ExpressionNode {
|
||||
var typeNode = property.getTypeNode();
|
||||
if (typeNode == null || typeNode.isUnknownType()) return VmDynamic.empty();
|
||||
|
||||
var result = typeNode.getDefaultValue();
|
||||
var result = typeNode.getDefaultValue(frame);
|
||||
if (result != null) return result;
|
||||
|
||||
// no default exists for this property type
|
||||
@@ -76,18 +77,18 @@ public abstract class InferParentWithinPropertyNode extends ExpressionNode {
|
||||
}
|
||||
|
||||
@Specialization
|
||||
protected Object eval(@SuppressWarnings("unused") VmDynamic owner) {
|
||||
protected Object eval(VirtualFrame frame, @SuppressWarnings("unused") VmDynamic owner) {
|
||||
if (isLocalProperty) {
|
||||
return getLocalPropertyDefaultValue(owner);
|
||||
return getLocalPropertyDefaultValue(frame, owner);
|
||||
}
|
||||
|
||||
return VmDynamic.empty();
|
||||
}
|
||||
|
||||
@Specialization
|
||||
protected Object eval(@SuppressWarnings("unused") VmListing owner) {
|
||||
protected Object eval(VirtualFrame frame, @SuppressWarnings("unused") VmListing owner) {
|
||||
if (isLocalProperty) {
|
||||
return getLocalPropertyDefaultValue(owner);
|
||||
return getLocalPropertyDefaultValue(frame, owner);
|
||||
}
|
||||
|
||||
assert ownPropertyName == Identifier.DEFAULT;
|
||||
@@ -96,9 +97,9 @@ public abstract class InferParentWithinPropertyNode extends ExpressionNode {
|
||||
}
|
||||
|
||||
@Specialization
|
||||
protected Object eval(@SuppressWarnings("unused") VmMapping owner) {
|
||||
protected Object eval(VirtualFrame frame, @SuppressWarnings("unused") VmMapping owner) {
|
||||
if (isLocalProperty) {
|
||||
return getLocalPropertyDefaultValue(owner);
|
||||
return getLocalPropertyDefaultValue(frame, owner);
|
||||
}
|
||||
|
||||
assert ownPropertyName == Identifier.DEFAULT;
|
||||
@@ -106,13 +107,13 @@ public abstract class InferParentWithinPropertyNode extends ExpressionNode {
|
||||
return VmUtils.readMember(BaseModule.getMappingClass().getPrototype(), ownPropertyName);
|
||||
}
|
||||
|
||||
private Object getLocalPropertyDefaultValue(VmObjectLike owner) {
|
||||
private Object getLocalPropertyDefaultValue(VirtualFrame frame, VmObjectLike owner) {
|
||||
assert isLocalProperty;
|
||||
|
||||
var member = owner.getMember(ownPropertyName);
|
||||
assert member != null;
|
||||
|
||||
var defaultValue = member.getLocalPropertyDefaultValue();
|
||||
var defaultValue = member.getLocalPropertyDefaultValue(frame);
|
||||
if (defaultValue != null) return defaultValue;
|
||||
|
||||
// no default exists for this property type
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* 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.
|
||||
@@ -38,14 +38,14 @@ public final class DefaultPropertyBodyNode extends ExpressionNode {
|
||||
this.typeNode = typeNode;
|
||||
}
|
||||
|
||||
public boolean isUndefined() {
|
||||
return typeNode == null || typeNode.getDefaultValue() == null;
|
||||
public boolean isUndefined(VirtualFrame frame) {
|
||||
return typeNode == null || typeNode.getDefaultValue(frame) == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object executeGeneric(VirtualFrame frame) {
|
||||
if (typeNode != null) {
|
||||
var defaultValue = typeNode.getDefaultValue();
|
||||
var defaultValue = typeNode.getDefaultValue(frame);
|
||||
if (defaultValue != null) return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* 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.
|
||||
@@ -45,11 +45,11 @@ public final class LocalTypedPropertyNode extends RegularMemberNode {
|
||||
this.unresolvedTypeNode = unresolvedTypeNode;
|
||||
}
|
||||
|
||||
public @Nullable Object getDefaultValue() {
|
||||
public @Nullable Object getDefaultValue(VirtualFrame frame) {
|
||||
if (!defaultValueInitialized) {
|
||||
defaultValue =
|
||||
typeNode.createDefaultValue(
|
||||
language, member.getHeaderSection(), member.getQualifiedName());
|
||||
frame, language, member.getHeaderSection(), member.getQualifiedName());
|
||||
defaultValueInitialized = true;
|
||||
}
|
||||
return defaultValue;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* 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.
|
||||
@@ -17,6 +17,7 @@ package org.pkl.core.ast.member;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
|
||||
import com.oracle.truffle.api.RootCallTarget;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.source.SourceSection;
|
||||
import org.pkl.core.ast.ConstantNode;
|
||||
import org.pkl.core.ast.MemberNode;
|
||||
@@ -102,14 +103,14 @@ public final class ObjectMember extends Member {
|
||||
return callTarget;
|
||||
}
|
||||
|
||||
public boolean isUndefined() {
|
||||
return getMemberNode() != null && getMemberNode().isUndefined();
|
||||
public boolean isUndefined(VirtualFrame frame) {
|
||||
return getMemberNode() != null && getMemberNode().isUndefined(frame);
|
||||
}
|
||||
|
||||
public @Nullable Object getLocalPropertyDefaultValue() {
|
||||
public @Nullable Object getLocalPropertyDefaultValue(VirtualFrame frame) {
|
||||
assert isProp() && isLocal();
|
||||
return getMemberNode() instanceof LocalTypedPropertyNode propertyNode
|
||||
? propertyNode.getDefaultValue()
|
||||
? propertyNode.getDefaultValue(frame)
|
||||
: VmDynamic.empty();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* 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.
|
||||
@@ -64,11 +64,11 @@ public final class PropertyTypeNode extends PklRootNode {
|
||||
return typeNode.execute(frame, frame.getArguments()[2]);
|
||||
}
|
||||
|
||||
public @Nullable Object getDefaultValue() {
|
||||
public @Nullable Object getDefaultValue(VirtualFrame frame) {
|
||||
if (!defaultValueInitialized) {
|
||||
defaultValue =
|
||||
typeNode.createDefaultValue(
|
||||
VmLanguage.get(this), getSourceSection(), qualifiedPropertyName);
|
||||
frame, VmLanguage.get(this), getSourceSection(), qualifiedPropertyName);
|
||||
defaultValueInitialized = true;
|
||||
}
|
||||
return defaultValue;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* 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.
|
||||
@@ -26,6 +26,7 @@ import org.pkl.core.util.LateInit;
|
||||
/** Resolves `<type>` to the type's default value in `new <type> { ... }`. */
|
||||
public final class GetParentForTypeNode extends ExpressionNode {
|
||||
@Child private UnresolvedTypeNode unresolvedTypeNode;
|
||||
@Child private TypeNode typeNode;
|
||||
private final String qualifiedName;
|
||||
|
||||
@CompilationFinal @LateInit Object defaultValue;
|
||||
@@ -37,14 +38,24 @@ public final class GetParentForTypeNode extends ExpressionNode {
|
||||
this.qualifiedName = qualifiedName;
|
||||
}
|
||||
|
||||
private TypeNode getTypeNode(VirtualFrame frame) {
|
||||
if (typeNode == null) {
|
||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||
typeNode = unresolvedTypeNode.execute(frame);
|
||||
adoptChildren();
|
||||
}
|
||||
return typeNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object executeGeneric(VirtualFrame frame) {
|
||||
if (defaultValue != null) return defaultValue;
|
||||
|
||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||
|
||||
var typeNode = unresolvedTypeNode.execute(frame);
|
||||
defaultValue = typeNode.createDefaultValue(VmLanguage.get(this), sourceSection, qualifiedName);
|
||||
var typeNode = getTypeNode(frame);
|
||||
defaultValue =
|
||||
typeNode.createDefaultValue(frame, VmLanguage.get(this), sourceSection, qualifiedName);
|
||||
|
||||
if (defaultValue != null) {
|
||||
unresolvedTypeNode = null;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* 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.
|
||||
@@ -116,6 +116,7 @@ public abstract class TypeNode extends PklNode {
|
||||
|
||||
// method arguments are used when default value contains a root node
|
||||
public @Nullable Object createDefaultValue(
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
// header section of the property or method that carries the type annotation
|
||||
SourceSection headerSection,
|
||||
@@ -473,6 +474,16 @@ public abstract class TypeNode extends PklNode {
|
||||
protected boolean acceptTypeNode(TypeNodeConsumer consumer) {
|
||||
return consumer.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object createDefaultValue(
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
var moduleClass = ((VmTyped) getModuleNode.executeGeneric(frame)).getVmClass();
|
||||
return TypeNode.createDefaultValue(moduleClass);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class StringLiteralTypeNode extends ObjectSlotTypeNode {
|
||||
@@ -504,7 +515,10 @@ public abstract class TypeNode extends PklNode {
|
||||
|
||||
@Override
|
||||
public Object createDefaultValue(
|
||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
|
||||
return literal;
|
||||
}
|
||||
@@ -572,7 +586,10 @@ public abstract class TypeNode extends PklNode {
|
||||
|
||||
@Override
|
||||
public Object createDefaultValue(
|
||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
|
||||
return VmDynamic.empty();
|
||||
}
|
||||
@@ -622,7 +639,10 @@ public abstract class TypeNode extends PklNode {
|
||||
|
||||
@Override
|
||||
public @Nullable Object createDefaultValue(
|
||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
|
||||
return TypeNode.createDefaultValue(clazz);
|
||||
}
|
||||
@@ -691,7 +711,10 @@ public abstract class TypeNode extends PklNode {
|
||||
|
||||
@Override
|
||||
public @Nullable Object createDefaultValue(
|
||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
|
||||
return TypeNode.createDefaultValue(clazz);
|
||||
}
|
||||
@@ -734,10 +757,13 @@ public abstract class TypeNode extends PklNode {
|
||||
|
||||
@Override
|
||||
public @Nullable Object createDefaultValue(
|
||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
|
||||
return VmNull.withDefault(
|
||||
elementTypeNode.createDefaultValue(language, headerSection, qualifiedName));
|
||||
elementTypeNode.createDefaultValue(frame, language, headerSection, qualifiedName));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -817,12 +843,15 @@ public abstract class TypeNode extends PklNode {
|
||||
|
||||
@Override
|
||||
public @Nullable Object createDefaultValue(
|
||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
|
||||
return defaultIndex == -1
|
||||
? null
|
||||
: elementTypeNodes[defaultIndex].createDefaultValue(
|
||||
language, headerSection, qualifiedName);
|
||||
frame, language, headerSection, qualifiedName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1021,9 +1050,11 @@ public abstract class TypeNode extends PklNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
@TruffleBoundary
|
||||
public @Nullable Object createDefaultValue(
|
||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
|
||||
return unionDefault;
|
||||
}
|
||||
@@ -1063,7 +1094,10 @@ public abstract class TypeNode extends PklNode {
|
||||
|
||||
@Override
|
||||
public Object createDefaultValue(
|
||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
|
||||
return VmList.EMPTY;
|
||||
}
|
||||
@@ -1152,7 +1186,10 @@ public abstract class TypeNode extends PklNode {
|
||||
|
||||
@Override
|
||||
public Object createDefaultValue(
|
||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
|
||||
return VmList.EMPTY;
|
||||
}
|
||||
@@ -1240,7 +1277,10 @@ public abstract class TypeNode extends PklNode {
|
||||
|
||||
@Override
|
||||
public final Object createDefaultValue(
|
||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
|
||||
return VmSet.EMPTY;
|
||||
}
|
||||
@@ -1332,7 +1372,10 @@ public abstract class TypeNode extends PklNode {
|
||||
|
||||
@Override
|
||||
public Object createDefaultValue(
|
||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
|
||||
return VmMap.EMPTY;
|
||||
}
|
||||
@@ -1586,45 +1629,48 @@ public abstract class TypeNode extends PklNode {
|
||||
return valueTypeCastNode;
|
||||
}
|
||||
|
||||
// either (if defaultMemberValue != null):
|
||||
// x: Listing<Foo> // = new Listing {
|
||||
// default = name -> new Foo {}
|
||||
// }
|
||||
// or (if defaultMemberValue == null):
|
||||
// x: Listing<Int> // = new Listing {
|
||||
// default = Undefined()
|
||||
// }
|
||||
@Override
|
||||
@TruffleBoundary
|
||||
public final Object createDefaultValue(
|
||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||
|
||||
if (valueTypeNode instanceof UnknownTypeNode) {
|
||||
if (isListing()) {
|
||||
return new VmListing(
|
||||
VmUtils.createEmptyMaterializedFrame(),
|
||||
BaseModule.getListingClass().getPrototype(),
|
||||
EconomicMaps.create(),
|
||||
0);
|
||||
}
|
||||
|
||||
return new VmMapping(
|
||||
private Object newEmptyListingOrMapping() {
|
||||
if (isListing()) {
|
||||
return new VmListing(
|
||||
VmUtils.createEmptyMaterializedFrame(),
|
||||
BaseModule.getMappingClass().getPrototype(),
|
||||
EconomicMaps.create());
|
||||
BaseModule.getListingClass().getPrototype(),
|
||||
EconomicMaps.create(),
|
||||
0);
|
||||
}
|
||||
|
||||
return new VmMapping(
|
||||
VmUtils.createEmptyMaterializedFrame(),
|
||||
BaseModule.getMappingClass().getPrototype(),
|
||||
EconomicMaps.create());
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
private Object newEmptyListingOrMapping(ObjectMember defaultMember) {
|
||||
if (isListing()) {
|
||||
return new VmListing(
|
||||
VmUtils.createEmptyMaterializedFrame(),
|
||||
BaseModule.getListingClass().getPrototype(),
|
||||
EconomicMaps.of(Identifier.DEFAULT, defaultMember),
|
||||
0);
|
||||
}
|
||||
|
||||
return new VmMapping(
|
||||
VmUtils.createEmptyMaterializedFrame(),
|
||||
BaseModule.getMappingClass().getPrototype(),
|
||||
EconomicMaps.of(Identifier.DEFAULT, defaultMember));
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
private ObjectMember createDefaultMember(
|
||||
SourceSection headerSection, String qualifiedName, @Nullable Object defaultMemberValue) {
|
||||
var defaultMember =
|
||||
new ObjectMember(
|
||||
headerSection,
|
||||
headerSection,
|
||||
VmModifier.HIDDEN,
|
||||
Identifier.DEFAULT,
|
||||
qualifiedName + ".default");
|
||||
|
||||
var defaultMemberValue =
|
||||
valueTypeNode.createDefaultValue(language, headerSection, qualifiedName);
|
||||
|
||||
VmUtils.concat(qualifiedName, ".default"));
|
||||
if (defaultMemberValue == null) {
|
||||
defaultMember.initMemberNode(
|
||||
new UntypedObjectMemberNode(
|
||||
@@ -1645,23 +1691,38 @@ public abstract class TypeNode extends PklNode {
|
||||
language,
|
||||
new FrameDescriptor(),
|
||||
headerSection,
|
||||
defaultMember.getQualifiedName() + ".<function>",
|
||||
VmUtils.concat(defaultMember.getQualifiedName(), ".<function>"),
|
||||
new ConstantValueNode(defaultMemberValue)),
|
||||
null));
|
||||
}
|
||||
return defaultMember;
|
||||
}
|
||||
|
||||
if (isListing()) {
|
||||
return new VmListing(
|
||||
VmUtils.createEmptyMaterializedFrame(),
|
||||
BaseModule.getListingClass().getPrototype(),
|
||||
EconomicMaps.of(Identifier.DEFAULT, defaultMember),
|
||||
0);
|
||||
// either (if defaultMemberValue != null):
|
||||
// x: Listing<Foo> // = new Listing {
|
||||
// default = name -> new Foo {}
|
||||
// }
|
||||
// or (if defaultMemberValue == null):
|
||||
// x: Listing<Int> // = new Listing {
|
||||
// default = Undefined()
|
||||
// }
|
||||
@Override
|
||||
public final Object createDefaultValue(
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
|
||||
if (valueTypeNode instanceof UnknownTypeNode) {
|
||||
return newEmptyListingOrMapping();
|
||||
}
|
||||
|
||||
return new VmMapping(
|
||||
VmUtils.createEmptyMaterializedFrame(),
|
||||
BaseModule.getMappingClass().getPrototype(),
|
||||
EconomicMaps.of(Identifier.DEFAULT, defaultMember));
|
||||
var defaultMemberValue =
|
||||
valueTypeNode.createDefaultValue(frame, language, headerSection, qualifiedName);
|
||||
|
||||
var defaultMember = createDefaultMember(headerSection, qualifiedName, defaultMemberValue);
|
||||
|
||||
return newEmptyListingOrMapping(defaultMember);
|
||||
}
|
||||
|
||||
protected void doEagerCheck(VirtualFrame frame, VmObject object) {
|
||||
@@ -2030,7 +2091,10 @@ public abstract class TypeNode extends PklNode {
|
||||
|
||||
@Override
|
||||
public @Nullable Object createDefaultValue(
|
||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
|
||||
CompilerDirectives.transferToInterpreter();
|
||||
throw exceptionBuilder()
|
||||
@@ -2441,34 +2505,41 @@ public abstract class TypeNode extends PklNode {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@TruffleBoundary
|
||||
private VmFunction newMixin(VmLanguage language, String qualifiedName) {
|
||||
//noinspection ConstantConditions
|
||||
return new VmFunction(
|
||||
VmUtils.createEmptyMaterializedFrame(),
|
||||
// Assumption: don't need to set the correct `thisValue`
|
||||
// because it is guaranteed to be never accessed.
|
||||
null,
|
||||
1,
|
||||
new IdentityMixinNode(
|
||||
language,
|
||||
new FrameDescriptor(),
|
||||
getSourceSection(),
|
||||
qualifiedName,
|
||||
typeArgumentNodes.length == 1
|
||||
?
|
||||
// shouldn't need to deepCopy() this node because it isn't used as @Child
|
||||
// anywhere else
|
||||
typeArgumentNodes[0]
|
||||
: null),
|
||||
null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object createDefaultValue(
|
||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
|
||||
if (typeAlias == BaseModule.getMixinTypeAlias()) {
|
||||
//noinspection ConstantConditions
|
||||
return new VmFunction(
|
||||
VmUtils.createEmptyMaterializedFrame(),
|
||||
// Assumption: don't need to set the correct `thisValue`
|
||||
// because it is guaranteed to be never accessed.
|
||||
null,
|
||||
1,
|
||||
new IdentityMixinNode(
|
||||
language,
|
||||
new FrameDescriptor(),
|
||||
getSourceSection(),
|
||||
qualifiedName,
|
||||
typeArgumentNodes.length == 1
|
||||
?
|
||||
// shouldn't need to deepCopy() this node because it isn't used as @Child
|
||||
// anywhere else
|
||||
typeArgumentNodes[0]
|
||||
: null),
|
||||
null);
|
||||
return newMixin(language, qualifiedName);
|
||||
}
|
||||
|
||||
return aliasedTypeNode.createDefaultValue(language, headerSection, qualifiedName);
|
||||
return aliasedTypeNode.createDefaultValue(frame, language, headerSection, qualifiedName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2593,9 +2664,12 @@ public abstract class TypeNode extends PklNode {
|
||||
|
||||
@Override
|
||||
public @Nullable Object createDefaultValue(
|
||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||
VirtualFrame frame,
|
||||
VmLanguage language,
|
||||
SourceSection headerSection,
|
||||
String qualifiedName) {
|
||||
|
||||
return childNode.createDefaultValue(language, headerSection, qualifiedName);
|
||||
return childNode.createDefaultValue(frame, language, headerSection, qualifiedName);
|
||||
}
|
||||
|
||||
public SourceSection getBaseTypeSection() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* 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.
|
||||
@@ -184,7 +184,10 @@ public final class MirrorFactories {
|
||||
property ->
|
||||
property.getProperty().isAbstract()
|
||||
|| property.getProperty().isExternal()
|
||||
|| property.getProperty().getInitializer().isUndefined()
|
||||
|| property
|
||||
.getProperty()
|
||||
.getInitializer()
|
||||
.isUndefined(VmUtils.createEmptyMaterializedFrame())
|
||||
? VmNull.withoutDefault()
|
||||
:
|
||||
// get default from prototype because it's cached there
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* 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.
|
||||
@@ -909,4 +909,9 @@ public final class VmUtils {
|
||||
return frame.getArguments().length != 4
|
||||
|| frame.getArguments()[3] != VmUtils.SKIP_TYPECHECK_MARKER;
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
public static String concat(String str1, String str2) {
|
||||
return str1 + str2;
|
||||
}
|
||||
}
|
||||
|
||||
20
pkl-core/src/test/files/LanguageSnippetTests/input/types/moduleType2.pkl
vendored
Normal file
20
pkl-core/src/test/files/LanguageSnippetTests/input/types/moduleType2.pkl
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
open module Foo
|
||||
|
||||
prop: String
|
||||
|
||||
myself: module?
|
||||
|
||||
class Bar extends module {
|
||||
prop2: Int
|
||||
}
|
||||
|
||||
output {
|
||||
value = new Bar {
|
||||
prop = "hi"
|
||||
prop2 = 15
|
||||
myself {
|
||||
prop = "hi again"
|
||||
prop2 = 15
|
||||
}
|
||||
}
|
||||
}
|
||||
7
pkl-core/src/test/files/LanguageSnippetTests/output/types/moduleType2.pcf
vendored
Normal file
7
pkl-core/src/test/files/LanguageSnippetTests/output/types/moduleType2.pcf
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
prop = "hi"
|
||||
myself {
|
||||
prop = "hi again"
|
||||
myself = null
|
||||
prop2 = 15
|
||||
}
|
||||
prop2 = 15
|
||||
Reference in New Issue
Block a user