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:
Daniel Chao
2026-01-05 11:39:24 -08:00
committed by GitHub
parent 0a4281366f
commit 8f83885c75
14 changed files with 245 additions and 121 deletions

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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() {

View File

@@ -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

View File

@@ -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;
}
}

View 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
}
}
}

View File

@@ -0,0 +1,7 @@
prop = "hi"
myself {
prop = "hi again"
myself = null
prop2 = 15
}
prop2 = 15