diff --git a/pkl-core/src/main/java/org/pkl/core/ast/expression/generator/GeneratorObjectLiteralNode.java b/pkl-core/src/main/java/org/pkl/core/ast/expression/generator/GeneratorObjectLiteralNode.java index 75897d0c..1b9d237d 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/expression/generator/GeneratorObjectLiteralNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/expression/generator/GeneratorObjectLiteralNode.java @@ -73,6 +73,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode { @Specialization(guards = "checkObjectCannotHaveParameters()") protected VmDynamic evalDynamic(VirtualFrame frame, VmDynamic parent) { var data = executeChildren(frame, parent, parent.getLength()); + if (data.hasNoMembers()) { + return parent; + } var result = new VmDynamic(frame.materialize(), parent, data.members(), data.length()); return data.storeGeneratorFrames(result); } @@ -81,6 +84,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode { protected VmTyped evalTyped(VirtualFrame frame, VmTyped parent) { VmUtils.checkIsInstantiable(parent.getVmClass(), getParentNode()); var data = executeChildren(frame, parent, 0); + if (data.hasNoMembers()) { + return parent; + } assert data.hasNoGeneratorFrames(); return new VmTyped(frame.materialize(), parent, parent.getVmClass(), data.members()); } @@ -88,6 +94,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode { @Specialization(guards = "checkListingCannotHaveParameters()") protected VmListing evalListing(VirtualFrame frame, VmListing parent) { var data = executeChildren(frame, parent, parent.getLength()); + if (data.hasNoMembers()) { + return parent; + } var result = new VmListing(frame.materialize(), parent, data.members(), data.length()); return data.storeGeneratorFrames(result); } @@ -95,6 +104,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode { @Specialization(guards = "checkMappingCannotHaveParameters()") protected VmMapping evalMapping(VirtualFrame frame, VmMapping parent) { var data = executeChildren(frame, parent, 0); + if (data.hasNoMembers()) { + return parent; + } var result = new VmMapping(frame.materialize(), parent, data.members()); return data.storeGeneratorFrames(result); } @@ -118,6 +130,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode { @Specialization(guards = {"parent == getDynamicClass()", "checkObjectCannotHaveParameters()"}) protected VmDynamic evalDynamicClass(VirtualFrame frame, VmClass parent) { var data = executeChildren(frame, parent, 0); + if (data.hasNoMembers()) { + return VmDynamic.empty(); + } var result = new VmDynamic(frame.materialize(), parent.getPrototype(), data.members(), data.length()); return data.storeGeneratorFrames(result); @@ -126,6 +141,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode { @Specialization(guards = {"parent == getMappingClass()", "checkMappingCannotHaveParameters()"}) protected VmMapping evalMappingClass(VirtualFrame frame, VmClass parent) { var data = executeChildren(frame, parent, 0); + if (data.hasNoMembers()) { + return VmMapping.empty(); + } var result = new VmMapping(frame.materialize(), parent.getPrototype(), data.members()); return data.storeGeneratorFrames(result); } @@ -133,6 +151,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode { @Specialization(guards = {"parent == getListingClass()", "checkListingCannotHaveParameters()"}) protected VmListing evalListingClass(VirtualFrame frame, VmClass parent) { var data = executeChildren(frame, parent, 0); + if (data.hasNoMembers()) { + return VmListing.empty(); + } var result = new VmListing(frame.materialize(), parent.getPrototype(), data.members(), data.length()); return data.storeGeneratorFrames(result); @@ -142,6 +163,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode { protected VmTyped evalTypedObjectClass(VirtualFrame frame, VmClass parent) { VmUtils.checkIsInstantiable(parent, getParentNode()); var data = executeChildren(frame, parent, 0); + if (data.hasNoMembers()) { + return parent.getPrototype(); + } assert data.hasNoGeneratorFrames(); return new VmTyped(frame.materialize(), parent.getPrototype(), parent, data.members()); } diff --git a/pkl-core/src/main/java/org/pkl/core/ast/expression/generator/ObjectData.java b/pkl-core/src/main/java/org/pkl/core/ast/expression/generator/ObjectData.java index f7e21186..c418482e 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/expression/generator/ObjectData.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/expression/generator/ObjectData.java @@ -55,6 +55,10 @@ public final class ObjectData { return length; } + boolean hasNoMembers() { + return members.isEmpty(); + } + boolean hasNoGeneratorFrames() { return generatorFrames.isEmpty(); } diff --git a/pkl-core/src/test/files/LanguageSnippetTests/input/generators/generatorNoMembers.pkl b/pkl-core/src/test/files/LanguageSnippetTests/input/generators/generatorNoMembers.pkl new file mode 100644 index 00000000..2eb976c1 --- /dev/null +++ b/pkl-core/src/test/files/LanguageSnippetTests/input/generators/generatorNoMembers.pkl @@ -0,0 +1,46 @@ +// should only result in one trace in the output; generator object literals that don't add any +// members should be optimized away. +res1 { + prop = trace("hello") +} + +res2 = (res1) { + when (false) { + prop2 = 2 + } +} + +res3 = (res1) { + for (_ in List()) { + "hello" + } +} + +res4 = (res1) { + ...List() +} + +res5 = (res1) { + when (true) { + } else { + prop3 = 3 + } +} + +res6 = (Dynamic) { + when (true) {} +} + +res7 = (Mapping) { + when (true) {} +} + +class Person {} + +res8 = (Person) { + when (true) {} +} + +res9 = (Listing) { + when (true) {} +} diff --git a/pkl-core/src/test/files/LanguageSnippetTests/output/generators/generatorNoMembers.err b/pkl-core/src/test/files/LanguageSnippetTests/output/generators/generatorNoMembers.err new file mode 100644 index 00000000..7f436c14 --- /dev/null +++ b/pkl-core/src/test/files/LanguageSnippetTests/output/generators/generatorNoMembers.err @@ -0,0 +1,20 @@ +res1 { + prop = "hello" +} +res2 { + prop = "hello" +} +res3 { + prop = "hello" +} +res4 { + prop = "hello" +} +res5 { + prop = "hello" +} +res6 {} +res7 {} +res8 {} +res9 {} +pkl: TRACE: "hello" = "hello" (file:///$snippetsDir/input/generators/generatorNoMembers.pkl)