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
9 changes: 8 additions & 1 deletion pkl-core/src/main/java/org/pkl/core/runtime/VmClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@ public EconomicMap<Object, ObjectMember> getTypedToDynamicMembers() {
if (__typedToDynamicMembers == null) {
__typedToDynamicMembers =
createDelegatingMembers(
false,
(member) ->
new UntypedObjectMemberNode(
null, new FrameDescriptor(), member, new DelegateToExtraStorageObjNode()));
Expand All @@ -512,6 +513,7 @@ public EconomicMap<Object, ObjectMember> getDynamicToTypedMembers() {
if (__dynamicToTypedMembers == null) {
__dynamicToTypedMembers =
createDelegatingMembers(
true,
(member) ->
TypeCheckedPropertyNodeGen.create(
null,
Expand All @@ -530,6 +532,7 @@ public EconomicMap<Object, ObjectMember> getMapToTypedMembers() {
if (__mapToTypedMembers == null) {
__mapToTypedMembers =
createDelegatingMembers(
true,
(member) ->
TypeCheckedPropertyNodeGen.create(
null,
Expand All @@ -542,14 +545,18 @@ public EconomicMap<Object, ObjectMember> getMapToTypedMembers() {
}

private EconomicMap<Object, ObjectMember> createDelegatingMembers(
Function<ObjectMember, MemberNode> memberNodeFactory) {
boolean isConversionToTyped, Function<ObjectMember, MemberNode> memberNodeFactory) {
var result = EconomicMaps.<Object, ObjectMember>create();
for (var cursor = getAllProperties().getEntries(); cursor.advance(); ) {
var property = cursor.getValue();
// Typed->Dynamic conversion: Dynamic objects cannot currently have hidden members.
// Dynamic/Map->Typed conversion: Overall it seems more useful for the typed object
// to inherit its prototype's value for the hidden property (e.g., Module.output).
if (property.isHidden()) continue;
// Dynamic/Map->Typed conversion: a `fixed` or `const` property's value is fixed by its
// declaration, so it must not be overridden by whatever value happens to be in the source
// Dynamic/Map.
if (isConversionToTyped && property.isConstOrFixed()) continue;

var name = cursor.getKey();
var member =
Expand Down
12 changes: 12 additions & 0 deletions pkl-core/src/test/files/LanguageSnippetTests/input/api/dynamic.pkl
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ examples {
module.catch(() -> new Dynamic { name = "Pigeon" }.toTyped(Person).age)
module.catch(() -> obj.toTyped(Pair)) // Pair is not a Typed
module.catch(() -> obj.toTyped(ValueRenderer)) // ValueRenderer is abstract
(new Dynamic { name = "Pigeon"; id = 99 }).toTyped(FixedPerson)
(new Dynamic { name = "Pigeon"; id = 99 }).toTyped(ConstPerson)
}
}

Expand Down Expand Up @@ -89,3 +91,13 @@ local class Person {
name: String = "Default"
age: UInt
}

local class FixedPerson {
name: String = "Default"
fixed id: Int = 1
}

local class ConstPerson {
name: String = "Default"
const id: Int = 1
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,12 @@ examples {
module.catch(() -> Map("name", "Pigeon").toTyped(Person).age)
module.catch(() -> Map().toTyped(Int))
module.catch(() -> Map().toTyped(Abstract))
Map("name", "Pigeon", "id", 99).toTyped(FixedPerson)
Map("name", "Pigeon", "id", 99).toTyped(ConstPerson)
}
}

local class Person { name: String = "Default"; age: Int }
local abstract class Abstract
local class FixedPerson { name: String = "Default"; fixed id: Int = 1 }
local class ConstPerson { name: String = "Default"; const id: Int = 1 }
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,13 @@ examples {
"Tried to read property `age` but its value is undefined."
"Class `Pair` is not a subtype of `Typed`."
"Cannot instantiate abstract class `ValueRenderer`."
new {
name = "Pigeon"
id = 1
}
new {
name = "Pigeon"
id = 1
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,5 +129,13 @@ examples {
"Tried to read property `age` but its value is undefined."
"Class `Int` is not a subtype of `Typed`."
"Cannot instantiate abstract class `map#Abstract`."
new {
name = "Pigeon"
id = 1
}
new {
name = "Pigeon"
id = 1
}
}
}