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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.pkl.core.ast; package org.pkl.core.ast;
import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.api.source.SourceSection;
import org.pkl.core.ast.member.DefaultPropertyBodyNode; import org.pkl.core.ast.member.DefaultPropertyBodyNode;
import org.pkl.core.runtime.VmExceptionBuilder; import org.pkl.core.runtime.VmExceptionBuilder;
@@ -46,7 +47,8 @@ public abstract class MemberNode extends PklRootNode {
return new VmExceptionBuilder().withSourceSection(getHeaderSection()); return new VmExceptionBuilder().withSourceSection(getHeaderSection());
} }
public boolean isUndefined() { public boolean isUndefined(VirtualFrame frame) {
return bodyNode instanceof DefaultPropertyBodyNode propBodyNode && propBodyNode.isUndefined(); 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -67,7 +67,7 @@ public final class InferParentWithinMethodNode extends ExpressionNode {
var returnTypeDefaultValue = var returnTypeDefaultValue =
returnTypeNode.createDefaultValue( returnTypeNode.createDefaultValue(
language, method.getHeaderSection(), method.getQualifiedName()); frame, language, method.getHeaderSection(), method.getQualifiedName());
if (returnTypeDefaultValue != null) { if (returnTypeDefaultValue != null) {
inferredParent = returnTypeDefaultValue; inferredParent = returnTypeDefaultValue;
ownerNode = null; 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -75,7 +75,7 @@ public final class InferParentWithinObjectMethodNode extends ExpressionNode {
Object defaultReturnTypeValue = Object defaultReturnTypeValue =
returnTypeNode.createDefaultValue( returnTypeNode.createDefaultValue(
language, member.getHeaderSection(), member.getQualifiedName()); frame, language, member.getHeaderSection(), member.getQualifiedName());
if (defaultReturnTypeValue != null) { if (defaultReturnTypeValue != null) {
inferredParent = defaultReturnTypeValue; inferredParent = defaultReturnTypeValue;
ownerNode = null; 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package org.pkl.core.ast.expression.member;
import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.api.source.SourceSection;
import org.pkl.core.ast.ExpressionNode; import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.runtime.*; import org.pkl.core.runtime.*;
@@ -35,9 +36,9 @@ public abstract class InferParentWithinPropertyNode extends ExpressionNode {
} }
@Specialization(guards = "!owner.isPrototype()") @Specialization(guards = "!owner.isPrototype()")
protected Object evalTypedObject(VmTyped owner) { protected Object evalTypedObject(VirtualFrame frame, VmTyped owner) {
if (isLocalProperty) { if (isLocalProperty) {
return getLocalPropertyDefaultValue(owner); return getLocalPropertyDefaultValue(frame, owner);
} }
try { try {
@@ -51,7 +52,7 @@ public abstract class InferParentWithinPropertyNode extends ExpressionNode {
} }
@Specialization(guards = "owner.isPrototype()") @Specialization(guards = "owner.isPrototype()")
protected Object evalPrototype(VmTyped owner) { protected Object evalPrototype(VirtualFrame frame, VmTyped owner) {
var property = var property =
isLocalProperty isLocalProperty
? ?
@@ -66,7 +67,7 @@ public abstract class InferParentWithinPropertyNode extends ExpressionNode {
var typeNode = property.getTypeNode(); var typeNode = property.getTypeNode();
if (typeNode == null || typeNode.isUnknownType()) return VmDynamic.empty(); if (typeNode == null || typeNode.isUnknownType()) return VmDynamic.empty();
var result = typeNode.getDefaultValue(); var result = typeNode.getDefaultValue(frame);
if (result != null) return result; if (result != null) return result;
// no default exists for this property type // no default exists for this property type
@@ -76,18 +77,18 @@ public abstract class InferParentWithinPropertyNode extends ExpressionNode {
} }
@Specialization @Specialization
protected Object eval(@SuppressWarnings("unused") VmDynamic owner) { protected Object eval(VirtualFrame frame, @SuppressWarnings("unused") VmDynamic owner) {
if (isLocalProperty) { if (isLocalProperty) {
return getLocalPropertyDefaultValue(owner); return getLocalPropertyDefaultValue(frame, owner);
} }
return VmDynamic.empty(); return VmDynamic.empty();
} }
@Specialization @Specialization
protected Object eval(@SuppressWarnings("unused") VmListing owner) { protected Object eval(VirtualFrame frame, @SuppressWarnings("unused") VmListing owner) {
if (isLocalProperty) { if (isLocalProperty) {
return getLocalPropertyDefaultValue(owner); return getLocalPropertyDefaultValue(frame, owner);
} }
assert ownPropertyName == Identifier.DEFAULT; assert ownPropertyName == Identifier.DEFAULT;
@@ -96,9 +97,9 @@ public abstract class InferParentWithinPropertyNode extends ExpressionNode {
} }
@Specialization @Specialization
protected Object eval(@SuppressWarnings("unused") VmMapping owner) { protected Object eval(VirtualFrame frame, @SuppressWarnings("unused") VmMapping owner) {
if (isLocalProperty) { if (isLocalProperty) {
return getLocalPropertyDefaultValue(owner); return getLocalPropertyDefaultValue(frame, owner);
} }
assert ownPropertyName == Identifier.DEFAULT; assert ownPropertyName == Identifier.DEFAULT;
@@ -106,13 +107,13 @@ public abstract class InferParentWithinPropertyNode extends ExpressionNode {
return VmUtils.readMember(BaseModule.getMappingClass().getPrototype(), ownPropertyName); return VmUtils.readMember(BaseModule.getMappingClass().getPrototype(), ownPropertyName);
} }
private Object getLocalPropertyDefaultValue(VmObjectLike owner) { private Object getLocalPropertyDefaultValue(VirtualFrame frame, VmObjectLike owner) {
assert isLocalProperty; assert isLocalProperty;
var member = owner.getMember(ownPropertyName); var member = owner.getMember(ownPropertyName);
assert member != null; assert member != null;
var defaultValue = member.getLocalPropertyDefaultValue(); var defaultValue = member.getLocalPropertyDefaultValue(frame);
if (defaultValue != null) return defaultValue; if (defaultValue != null) return defaultValue;
// no default exists for this property type // 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -38,14 +38,14 @@ public final class DefaultPropertyBodyNode extends ExpressionNode {
this.typeNode = typeNode; this.typeNode = typeNode;
} }
public boolean isUndefined() { public boolean isUndefined(VirtualFrame frame) {
return typeNode == null || typeNode.getDefaultValue() == null; return typeNode == null || typeNode.getDefaultValue(frame) == null;
} }
@Override @Override
public Object executeGeneric(VirtualFrame frame) { public Object executeGeneric(VirtualFrame frame) {
if (typeNode != null) { if (typeNode != null) {
var defaultValue = typeNode.getDefaultValue(); var defaultValue = typeNode.getDefaultValue(frame);
if (defaultValue != null) return defaultValue; 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -45,11 +45,11 @@ public final class LocalTypedPropertyNode extends RegularMemberNode {
this.unresolvedTypeNode = unresolvedTypeNode; this.unresolvedTypeNode = unresolvedTypeNode;
} }
public @Nullable Object getDefaultValue() { public @Nullable Object getDefaultValue(VirtualFrame frame) {
if (!defaultValueInitialized) { if (!defaultValueInitialized) {
defaultValue = defaultValue =
typeNode.createDefaultValue( typeNode.createDefaultValue(
language, member.getHeaderSection(), member.getQualifiedName()); frame, language, member.getHeaderSection(), member.getQualifiedName());
defaultValueInitialized = true; defaultValueInitialized = true;
} }
return defaultValue; 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@ package org.pkl.core.ast.member;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.api.source.SourceSection;
import org.pkl.core.ast.ConstantNode; import org.pkl.core.ast.ConstantNode;
import org.pkl.core.ast.MemberNode; import org.pkl.core.ast.MemberNode;
@@ -102,14 +103,14 @@ public final class ObjectMember extends Member {
return callTarget; return callTarget;
} }
public boolean isUndefined() { public boolean isUndefined(VirtualFrame frame) {
return getMemberNode() != null && getMemberNode().isUndefined(); return getMemberNode() != null && getMemberNode().isUndefined(frame);
} }
public @Nullable Object getLocalPropertyDefaultValue() { public @Nullable Object getLocalPropertyDefaultValue(VirtualFrame frame) {
assert isProp() && isLocal(); assert isProp() && isLocal();
return getMemberNode() instanceof LocalTypedPropertyNode propertyNode return getMemberNode() instanceof LocalTypedPropertyNode propertyNode
? propertyNode.getDefaultValue() ? propertyNode.getDefaultValue(frame)
: VmDynamic.empty(); : 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -64,11 +64,11 @@ public final class PropertyTypeNode extends PklRootNode {
return typeNode.execute(frame, frame.getArguments()[2]); return typeNode.execute(frame, frame.getArguments()[2]);
} }
public @Nullable Object getDefaultValue() { public @Nullable Object getDefaultValue(VirtualFrame frame) {
if (!defaultValueInitialized) { if (!defaultValueInitialized) {
defaultValue = defaultValue =
typeNode.createDefaultValue( typeNode.createDefaultValue(
VmLanguage.get(this), getSourceSection(), qualifiedPropertyName); frame, VmLanguage.get(this), getSourceSection(), qualifiedPropertyName);
defaultValueInitialized = true; defaultValueInitialized = true;
} }
return defaultValue; 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@ import org.pkl.core.util.LateInit;
/** Resolves `<type>` to the type's default value in `new <type> { ... }`. */ /** Resolves `<type>` to the type's default value in `new <type> { ... }`. */
public final class GetParentForTypeNode extends ExpressionNode { public final class GetParentForTypeNode extends ExpressionNode {
@Child private UnresolvedTypeNode unresolvedTypeNode; @Child private UnresolvedTypeNode unresolvedTypeNode;
@Child private TypeNode typeNode;
private final String qualifiedName; private final String qualifiedName;
@CompilationFinal @LateInit Object defaultValue; @CompilationFinal @LateInit Object defaultValue;
@@ -37,14 +38,24 @@ public final class GetParentForTypeNode extends ExpressionNode {
this.qualifiedName = qualifiedName; this.qualifiedName = qualifiedName;
} }
private TypeNode getTypeNode(VirtualFrame frame) {
if (typeNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
typeNode = unresolvedTypeNode.execute(frame);
adoptChildren();
}
return typeNode;
}
@Override @Override
public Object executeGeneric(VirtualFrame frame) { public Object executeGeneric(VirtualFrame frame) {
if (defaultValue != null) return defaultValue; if (defaultValue != null) return defaultValue;
CompilerDirectives.transferToInterpreterAndInvalidate(); CompilerDirectives.transferToInterpreterAndInvalidate();
var typeNode = unresolvedTypeNode.execute(frame); var typeNode = getTypeNode(frame);
defaultValue = typeNode.createDefaultValue(VmLanguage.get(this), sourceSection, qualifiedName); defaultValue =
typeNode.createDefaultValue(frame, VmLanguage.get(this), sourceSection, qualifiedName);
if (defaultValue != null) { if (defaultValue != null) {
unresolvedTypeNode = 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -116,6 +116,7 @@ public abstract class TypeNode extends PklNode {
// method arguments are used when default value contains a root node // method arguments are used when default value contains a root node
public @Nullable Object createDefaultValue( public @Nullable Object createDefaultValue(
VirtualFrame frame,
VmLanguage language, VmLanguage language,
// header section of the property or method that carries the type annotation // header section of the property or method that carries the type annotation
SourceSection headerSection, SourceSection headerSection,
@@ -473,6 +474,16 @@ public abstract class TypeNode extends PklNode {
protected boolean acceptTypeNode(TypeNodeConsumer consumer) { protected boolean acceptTypeNode(TypeNodeConsumer consumer) {
return consumer.accept(this); 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 { public static final class StringLiteralTypeNode extends ObjectSlotTypeNode {
@@ -504,7 +515,10 @@ public abstract class TypeNode extends PklNode {
@Override @Override
public Object createDefaultValue( public Object createDefaultValue(
VmLanguage language, SourceSection headerSection, String qualifiedName) { VirtualFrame frame,
VmLanguage language,
SourceSection headerSection,
String qualifiedName) {
return literal; return literal;
} }
@@ -572,7 +586,10 @@ public abstract class TypeNode extends PklNode {
@Override @Override
public Object createDefaultValue( public Object createDefaultValue(
VmLanguage language, SourceSection headerSection, String qualifiedName) { VirtualFrame frame,
VmLanguage language,
SourceSection headerSection,
String qualifiedName) {
return VmDynamic.empty(); return VmDynamic.empty();
} }
@@ -622,7 +639,10 @@ public abstract class TypeNode extends PklNode {
@Override @Override
public @Nullable Object createDefaultValue( public @Nullable Object createDefaultValue(
VmLanguage language, SourceSection headerSection, String qualifiedName) { VirtualFrame frame,
VmLanguage language,
SourceSection headerSection,
String qualifiedName) {
return TypeNode.createDefaultValue(clazz); return TypeNode.createDefaultValue(clazz);
} }
@@ -691,7 +711,10 @@ public abstract class TypeNode extends PklNode {
@Override @Override
public @Nullable Object createDefaultValue( public @Nullable Object createDefaultValue(
VmLanguage language, SourceSection headerSection, String qualifiedName) { VirtualFrame frame,
VmLanguage language,
SourceSection headerSection,
String qualifiedName) {
return TypeNode.createDefaultValue(clazz); return TypeNode.createDefaultValue(clazz);
} }
@@ -734,10 +757,13 @@ public abstract class TypeNode extends PklNode {
@Override @Override
public @Nullable Object createDefaultValue( public @Nullable Object createDefaultValue(
VmLanguage language, SourceSection headerSection, String qualifiedName) { VirtualFrame frame,
VmLanguage language,
SourceSection headerSection,
String qualifiedName) {
return VmNull.withDefault( return VmNull.withDefault(
elementTypeNode.createDefaultValue(language, headerSection, qualifiedName)); elementTypeNode.createDefaultValue(frame, language, headerSection, qualifiedName));
} }
@Override @Override
@@ -817,12 +843,15 @@ public abstract class TypeNode extends PklNode {
@Override @Override
public @Nullable Object createDefaultValue( public @Nullable Object createDefaultValue(
VmLanguage language, SourceSection headerSection, String qualifiedName) { VirtualFrame frame,
VmLanguage language,
SourceSection headerSection,
String qualifiedName) {
return defaultIndex == -1 return defaultIndex == -1
? null ? null
: elementTypeNodes[defaultIndex].createDefaultValue( : elementTypeNodes[defaultIndex].createDefaultValue(
language, headerSection, qualifiedName); frame, language, headerSection, qualifiedName);
} }
@Override @Override
@@ -1021,9 +1050,11 @@ public abstract class TypeNode extends PklNode {
} }
@Override @Override
@TruffleBoundary
public @Nullable Object createDefaultValue( public @Nullable Object createDefaultValue(
VmLanguage language, SourceSection headerSection, String qualifiedName) { VirtualFrame frame,
VmLanguage language,
SourceSection headerSection,
String qualifiedName) {
return unionDefault; return unionDefault;
} }
@@ -1063,7 +1094,10 @@ public abstract class TypeNode extends PklNode {
@Override @Override
public Object createDefaultValue( public Object createDefaultValue(
VmLanguage language, SourceSection headerSection, String qualifiedName) { VirtualFrame frame,
VmLanguage language,
SourceSection headerSection,
String qualifiedName) {
return VmList.EMPTY; return VmList.EMPTY;
} }
@@ -1152,7 +1186,10 @@ public abstract class TypeNode extends PklNode {
@Override @Override
public Object createDefaultValue( public Object createDefaultValue(
VmLanguage language, SourceSection headerSection, String qualifiedName) { VirtualFrame frame,
VmLanguage language,
SourceSection headerSection,
String qualifiedName) {
return VmList.EMPTY; return VmList.EMPTY;
} }
@@ -1240,7 +1277,10 @@ public abstract class TypeNode extends PklNode {
@Override @Override
public final Object createDefaultValue( public final Object createDefaultValue(
VmLanguage language, SourceSection headerSection, String qualifiedName) { VirtualFrame frame,
VmLanguage language,
SourceSection headerSection,
String qualifiedName) {
return VmSet.EMPTY; return VmSet.EMPTY;
} }
@@ -1332,7 +1372,10 @@ public abstract class TypeNode extends PklNode {
@Override @Override
public Object createDefaultValue( public Object createDefaultValue(
VmLanguage language, SourceSection headerSection, String qualifiedName) { VirtualFrame frame,
VmLanguage language,
SourceSection headerSection,
String qualifiedName) {
return VmMap.EMPTY; return VmMap.EMPTY;
} }
@@ -1586,45 +1629,48 @@ public abstract class TypeNode extends PklNode {
return valueTypeCastNode; 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 @TruffleBoundary
public final Object createDefaultValue( private Object newEmptyListingOrMapping() {
VmLanguage language, SourceSection headerSection, String qualifiedName) { if (isListing()) {
return new VmListing(
if (valueTypeNode instanceof UnknownTypeNode) {
if (isListing()) {
return new VmListing(
VmUtils.createEmptyMaterializedFrame(),
BaseModule.getListingClass().getPrototype(),
EconomicMaps.create(),
0);
}
return new VmMapping(
VmUtils.createEmptyMaterializedFrame(), VmUtils.createEmptyMaterializedFrame(),
BaseModule.getMappingClass().getPrototype(), BaseModule.getListingClass().getPrototype(),
EconomicMaps.create()); 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 = var defaultMember =
new ObjectMember( new ObjectMember(
headerSection, headerSection,
headerSection, headerSection,
VmModifier.HIDDEN, VmModifier.HIDDEN,
Identifier.DEFAULT, Identifier.DEFAULT,
qualifiedName + ".default"); VmUtils.concat(qualifiedName, ".default"));
var defaultMemberValue =
valueTypeNode.createDefaultValue(language, headerSection, qualifiedName);
if (defaultMemberValue == null) { if (defaultMemberValue == null) {
defaultMember.initMemberNode( defaultMember.initMemberNode(
new UntypedObjectMemberNode( new UntypedObjectMemberNode(
@@ -1645,23 +1691,38 @@ public abstract class TypeNode extends PklNode {
language, language,
new FrameDescriptor(), new FrameDescriptor(),
headerSection, headerSection,
defaultMember.getQualifiedName() + ".<function>", VmUtils.concat(defaultMember.getQualifiedName(), ".<function>"),
new ConstantValueNode(defaultMemberValue)), new ConstantValueNode(defaultMemberValue)),
null)); null));
} }
return defaultMember;
}
if (isListing()) { // either (if defaultMemberValue != null):
return new VmListing( // x: Listing<Foo> // = new Listing {
VmUtils.createEmptyMaterializedFrame(), // default = name -> new Foo {}
BaseModule.getListingClass().getPrototype(), // }
EconomicMaps.of(Identifier.DEFAULT, defaultMember), // or (if defaultMemberValue == null):
0); // 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( var defaultMemberValue =
VmUtils.createEmptyMaterializedFrame(), valueTypeNode.createDefaultValue(frame, language, headerSection, qualifiedName);
BaseModule.getMappingClass().getPrototype(),
EconomicMaps.of(Identifier.DEFAULT, defaultMember)); var defaultMember = createDefaultMember(headerSection, qualifiedName, defaultMemberValue);
return newEmptyListingOrMapping(defaultMember);
} }
protected void doEagerCheck(VirtualFrame frame, VmObject object) { protected void doEagerCheck(VirtualFrame frame, VmObject object) {
@@ -2030,7 +2091,10 @@ public abstract class TypeNode extends PklNode {
@Override @Override
public @Nullable Object createDefaultValue( public @Nullable Object createDefaultValue(
VmLanguage language, SourceSection headerSection, String qualifiedName) { VirtualFrame frame,
VmLanguage language,
SourceSection headerSection,
String qualifiedName) {
CompilerDirectives.transferToInterpreter(); CompilerDirectives.transferToInterpreter();
throw exceptionBuilder() throw exceptionBuilder()
@@ -2441,34 +2505,41 @@ public abstract class TypeNode extends PklNode {
} }
} }
@Override
@TruffleBoundary @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( public @Nullable Object createDefaultValue(
VmLanguage language, SourceSection headerSection, String qualifiedName) { VirtualFrame frame,
VmLanguage language,
SourceSection headerSection,
String qualifiedName) {
if (typeAlias == BaseModule.getMixinTypeAlias()) { if (typeAlias == BaseModule.getMixinTypeAlias()) {
//noinspection ConstantConditions return newMixin(language, qualifiedName);
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 aliasedTypeNode.createDefaultValue(language, headerSection, qualifiedName); return aliasedTypeNode.createDefaultValue(frame, language, headerSection, qualifiedName);
} }
@Override @Override
@@ -2593,9 +2664,12 @@ public abstract class TypeNode extends PklNode {
@Override @Override
public @Nullable Object createDefaultValue( 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() { 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -184,7 +184,10 @@ public final class MirrorFactories {
property -> property ->
property.getProperty().isAbstract() property.getProperty().isAbstract()
|| property.getProperty().isExternal() || property.getProperty().isExternal()
|| property.getProperty().getInitializer().isUndefined() || property
.getProperty()
.getInitializer()
.isUndefined(VmUtils.createEmptyMaterializedFrame())
? VmNull.withoutDefault() ? VmNull.withoutDefault()
: :
// get default from prototype because it's cached there // 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -909,4 +909,9 @@ public final class VmUtils {
return frame.getArguments().length != 4 return frame.getArguments().length != 4
|| frame.getArguments()[3] != VmUtils.SKIP_TYPECHECK_MARKER; || 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