Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2025 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.
Expand All @@ -19,6 +19,9 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.ast.type.TypeNode.ConstrainedTypeNode;
import org.pkl.core.ast.type.TypeNode.TypeAliasTypeNode;
import org.pkl.core.ast.type.TypeNode.UnionTypeNode;
import org.pkl.core.runtime.Identifier;
import org.pkl.core.runtime.VmUtils;
import org.pkl.core.util.Nullable;
Expand Down Expand Up @@ -50,8 +53,30 @@ public Object executeGeneric(VirtualFrame frame) {
}

CompilerDirectives.transferToInterpreter();

// attempt to give a hint when a union type is missing a default
String aliasName = null;
String unionTypeSource = null;
if (typeNode != null) {
var tn = typeNode.getTypeNode();
while (true) {
if (tn instanceof TypeAliasTypeNode typeAlias) {
aliasName = typeAlias.getVmTypeAlias().getSimpleName();
tn = typeAlias.getVmTypeAlias().getTypeNode();
} else if (tn instanceof ConstrainedTypeNode constrained) {
tn = constrained.getBaseTypeNode();
} else {
break;
}
}
if (tn instanceof UnionTypeNode union && !union.getHasDefaultElement()) {
unionTypeSource = union.getSourceSection().getCharacters().toString();
}
}

throw exceptionBuilder()
.undefinedPropertyValue(propertyName, VmUtils.getReceiver(frame))
.undefinedPropertyValue(
propertyName, VmUtils.getReceiver(frame), unionTypeSource, aliasName)
.build();
}
}
8 changes: 8 additions & 0 deletions pkl-core/src/main/java/org/pkl/core/ast/type/TypeNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,10 @@ public TypeNode[] getElementTypeNodes() {
return elementTypeNodes;
}

public boolean getHasDefaultElement() {
return defaultIndex != -1;
}

@Override
public boolean isNoopTypeCheck() {
return skipElementTypeChecks;
Expand Down Expand Up @@ -2598,6 +2602,10 @@ public Object executeAndSet(VirtualFrame frame, Object value) {
return childNode.createDefaultValue(language, headerSection, qualifiedName);
}

public TypeNode getBaseTypeNode() {
return childNode;
}

public SourceSection getBaseTypeSection() {
return childNode.getSourceSection();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2025 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.
Expand Down Expand Up @@ -124,9 +124,19 @@ public VmExceptionBuilder undefinedValue() {
return withExternalMessage("undefinedValue");
}

public VmExceptionBuilder undefinedPropertyValue(Identifier propertyName, Object receiver) {
public VmExceptionBuilder undefinedPropertyValue(
Identifier propertyName,
Object receiver,
@Nullable String unionTypeSource,
@Nullable String typeAliasName) {
kind = VmException.Kind.UNDEFINED_VALUE;
this.receiver = receiver;
if (unionTypeSource != null && typeAliasName != null) {
return withExternalMessage(
"undefinedPropertyValueUnionAlias", propertyName, unionTypeSource, typeAliasName);
} else if (unionTypeSource != null) {
return withExternalMessage("undefinedPropertyValueUnion", propertyName, unionTypeSource);
}
return withExternalMessage("undefinedPropertyValue", propertyName);
}

Expand Down
10 changes: 10 additions & 0 deletions pkl-core/src/main/resources/org/pkl/core/errorMessages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,16 @@ Undefined value.
undefinedPropertyValue=\
Tried to read property `{0}` but its value is undefined.

undefinedPropertyValueUnion=\
Tried to read property `{0}` but its value is undefined.\n\
Union type `{1}` has no default member denoted by `*`.\n\
Either update the type to specify a default member or explicitly assign a value.

undefinedPropertyValueUnionAlias=\
Tried to read property `{0}` but its value is undefined.\n\
Union type `{1}` (from type alias `{2}`) has no default member denoted by `*`.\n\
Either update the type to specify a default member or explicitly assign a value.

cannotFindModule=\
Cannot find module `{0}`.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
local typealias B = Listing<String> | String

b: B
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
local typealias B = Listing<String> | String
local typealias C = B(true)

c: C
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// should not get "union with no default" diagnostic here (since there is a default)
// and lack of default value is due to String's lack of default value
foo: *String|Listing<String>
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
–– Pkl Error ––
Tried to read property `foo` but its value is undefined.
Union type `Foo|"baz"` has no default member denoted by `*`.
Either update the type to specify a default member or explicitly assign a value.

x | foo: Foo|"baz"
^^^
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
–– Pkl Error ––
Tried to read property `b` but its value is undefined.
Union type `Listing<String> | String` (from type alias `B`) has no default member denoted by `*`.
Either update the type to specify a default member or explicitly assign a value.

x | b: B
^
at noDefault3#b (file:///$snippetsDir/input/errors/noDefault3.pkl)

The above error occurred when rendering path `b` of module `file:///$snippetsDir/input/errors/noDefault3.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)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
–– Pkl Error ––
Tried to read property `c` but its value is undefined.
Union type `Listing<String> | String` (from type alias `B`) has no default member denoted by `*`.
Either update the type to specify a default member or explicitly assign a value.

x | c: C
^
at noDefault4#c (file:///$snippetsDir/input/errors/noDefault4.pkl)

The above error occurred when rendering path `c` of module `file:///$snippetsDir/input/errors/noDefault4.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)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
–– Pkl Error ––
Tried to read property `foo` but its value is undefined.

x | foo: *String|Listing<String>
^^^
at noDefault5#foo (file:///$snippetsDir/input/errors/noDefault5.pkl)

The above error occurred when rendering path `foo` of module `file:///$snippetsDir/input/errors/noDefault5.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)
Loading