diff --git a/pkl-core/src/main/java/org/pkl/core/ast/type/TypeNode.java b/pkl-core/src/main/java/org/pkl/core/ast/type/TypeNode.java index edf41628c..925dc3029 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/type/TypeNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/type/TypeNode.java @@ -849,19 +849,14 @@ public abstract class TypeNode extends PklNode { public static class UnionTypeNode extends WriteFrameSlotTypeNode { @Children final TypeNode[] elementTypeNodes; - private final boolean skipElementTypeChecks; private final int defaultIndex; public UnionTypeNode( - SourceSection sourceSection, - int defaultIndex, - TypeNode[] elementTypeNodes, - boolean skipElementTypeChecks) { + SourceSection sourceSection, int defaultIndex, TypeNode[] elementTypeNodes) { super(sourceSection); assert elementTypeNodes.length > 0; this.elementTypeNodes = elementTypeNodes; this.defaultIndex = defaultIndex; - this.skipElementTypeChecks = skipElementTypeChecks; } @Override @@ -879,7 +874,10 @@ public abstract class TypeNode extends PklNode { @Override public boolean isNoopTypeCheck() { - return skipElementTypeChecks; + for (var element : elementTypeNodes) { + if (!element.isNoopTypeCheck()) return false; + } + return true; } @Override @@ -985,8 +983,6 @@ public abstract class TypeNode extends PklNode { @Fallback @ExplodeLoop protected Object executeLazily(VirtualFrame frame, Object value) { - if (skipElementTypeChecks) return value; - // escape analysis should remove this allocation in compiled code var typeMismatches = new VmTypeMismatchException[elementTypeNodes.length]; @@ -1037,8 +1033,6 @@ public abstract class TypeNode extends PklNode { @Override public Object executeEagerly(VirtualFrame frame, Object value) { - if (skipElementTypeChecks) return value; - // escape analysis should remove this allocation in compiled code var typeMismatches = new VmTypeMismatchException[elementTypeNodes.length]; @@ -1162,7 +1156,6 @@ public abstract class TypeNode extends PklNode { @Child private TypeNode elementTypeNode; public CollectionTypeNode(SourceSection sourceSection, TypeNode elementTypeNode) { - super(sourceSection); this.elementTypeNode = elementTypeNode; } @@ -1272,12 +1265,10 @@ public abstract class TypeNode extends PklNode { public static final class ListTypeNode extends ObjectSlotTypeNode { @Child private TypeNode elementTypeNode; - private final boolean skipElementTypeChecks; public ListTypeNode(SourceSection sourceSection, TypeNode elementTypeNode) { super(sourceSection); this.elementTypeNode = elementTypeNode; - skipElementTypeChecks = elementTypeNode.isNoopTypeCheck(); } @Override @@ -1322,7 +1313,7 @@ public abstract class TypeNode extends PklNode { if (!(value instanceof VmList vmList)) { throw typeMismatch(value, BaseModule.getListClass()); } - if (skipElementTypeChecks) return vmList; + if (elementTypeNode.isNoopTypeCheck()) return vmList; for (var elem : vmList) { elementTypeNode.executeEagerly(frame, elem); @@ -1339,7 +1330,7 @@ public abstract class TypeNode extends PklNode { if (!(value instanceof VmList vmList)) { throw typeMismatch(value, BaseModule.getListClass()); } - if (skipElementTypeChecks) return vmList; + if (elementTypeNode.isNoopTypeCheck()) return vmList; var ret = vmList; var idx = 0; @@ -1371,12 +1362,10 @@ public abstract class TypeNode extends PklNode { public abstract static class SetTypeNode extends ObjectSlotTypeNode { @Child private TypeNode elementTypeNode; - private final boolean skipElementTypeChecks; protected SetTypeNode(SourceSection sourceSection, TypeNode elementTypeNode) { super(sourceSection); this.elementTypeNode = elementTypeNode; - skipElementTypeChecks = elementTypeNode.isNoopTypeCheck(); } @Override @@ -1426,7 +1415,7 @@ public abstract class TypeNode extends PklNode { @Specialization protected Object eval(VirtualFrame frame, VmSet value) { - if (skipElementTypeChecks) return value; + if (elementTypeNode.isNoopTypeCheck()) return value; for (var elem : value) { // no point doing a lazy check because set members have their hash code computed, which // necessarily deep-forces them. @@ -1451,14 +1440,11 @@ public abstract class TypeNode extends PklNode { public static final class MapTypeNode extends ObjectSlotTypeNode { @Child private TypeNode keyTypeNode; @Child private TypeNode valueTypeNode; - private final boolean skipEntryTypeChecks; public MapTypeNode(SourceSection sourceSection, TypeNode keyTypeNode, TypeNode valueTypeNode) { - super(sourceSection); this.keyTypeNode = keyTypeNode; this.valueTypeNode = valueTypeNode; - skipEntryTypeChecks = keyTypeNode.isNoopTypeCheck() && valueTypeNode.isNoopTypeCheck(); } @Override @@ -1531,7 +1517,7 @@ public abstract class TypeNode extends PklNode { } private Object eval(VirtualFrame frame, VmMap value) { - if (skipEntryTypeChecks) return value; + if (keyTypeNode.isNoopTypeCheck() && valueTypeNode.isNoopTypeCheck()) return value; var ret = value; for (var entry : value) { @@ -1548,7 +1534,7 @@ public abstract class TypeNode extends PklNode { } private Object evalEager(VirtualFrame frame, VmMap value) { - if (skipEntryTypeChecks) return value; + if (keyTypeNode.isNoopTypeCheck() && valueTypeNode.isNoopTypeCheck()) return value; for (var entry : value) { keyTypeNode.executeEagerly(frame, VmUtils.getKey(entry)); valueTypeNode.executeEagerly(frame, VmUtils.getValue(entry)); @@ -1712,9 +1698,6 @@ public abstract class TypeNode extends PklNode { @Child protected TypeNode valueTypeNode; @Child @Nullable protected ListingOrMappingTypeCastNode valueTypeCastNode; - private final boolean skipKeyTypeChecks; - private final boolean skipValueTypeChecks; - protected ListingOrMappingTypeNode( SourceSection sourceSection, VmLanguage language, @@ -1725,9 +1708,6 @@ public abstract class TypeNode extends PklNode { this.language = language; this.keyTypeNode = keyTypeNode; this.valueTypeNode = valueTypeNode; - - skipKeyTypeChecks = keyTypeNode == null || keyTypeNode.isNoopTypeCheck(); - skipValueTypeChecks = valueTypeNode.isNoopTypeCheck(); } private boolean isListing() { @@ -1849,7 +1829,11 @@ public abstract class TypeNode extends PklNode { } protected void doEagerCheck(VirtualFrame frame, VmObject object) { - doEagerCheck(frame, object, skipKeyTypeChecks, skipValueTypeChecks); + doEagerCheck( + frame, + object, + keyTypeNode == null || keyTypeNode.isNoopTypeCheck(), + valueTypeNode.isNoopTypeCheck()); } protected void doEagerCheck( @@ -2262,7 +2246,6 @@ public abstract class TypeNode extends PklNode { public PairTypeNode( SourceSection sourceSection, TypeNode firstTypeNode, TypeNode secondTypeNode) { - super(sourceSection); this.firstTypeNode = firstTypeNode; this.secondTypeNode = secondTypeNode; @@ -2773,6 +2756,21 @@ public abstract class TypeNode extends PklNode { } } + @Override + public Object executeEagerly(VirtualFrame frame, Object value) { + var prevOwner = VmUtils.getOwner(frame); + var prevReceiver = VmUtils.getReceiver(frame); + setOwner(frame, VmUtils.getOwner(typeAlias.getEnclosingFrame())); + setReceiver(frame, VmUtils.getReceiver(typeAlias.getEnclosingFrame())); + + try { + return aliasedTypeNode.executeEagerly(frame, value); + } finally { + setOwner(frame, prevOwner); + setReceiver(frame, prevReceiver); + } + } + /** See docstring on {@link TypeAliasTypeNode#executeLazily}. */ @Override public Object executeAndSet(VirtualFrame frame, Object value) { diff --git a/pkl-core/src/main/java/org/pkl/core/ast/type/UnresolvedTypeNode.java b/pkl-core/src/main/java/org/pkl/core/ast/type/UnresolvedTypeNode.java index e5cbd35d2..0d387b91f 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/type/UnresolvedTypeNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/type/UnresolvedTypeNode.java @@ -361,16 +361,13 @@ public abstract class UnresolvedTypeNode extends PklNode { CompilerDirectives.transferToInterpreter(); var elementTypeNodes = new TypeNode[unresolvedElementTypeNodes.length]; - var skipElementTypeChecks = true; for (var i = 0; i < elementTypeNodes.length; i++) { var elementTypeNode = unresolvedElementTypeNodes[i].execute(frame); elementTypeNodes[i] = elementTypeNode; - skipElementTypeChecks &= elementTypeNode.isNoopTypeCheck(); } - return new UnionTypeNode( - sourceSection, defaultIndex, elementTypeNodes, skipElementTypeChecks); + return new UnionTypeNode(sourceSection, defaultIndex, elementTypeNodes); } } diff --git a/pkl-core/src/main/java/org/pkl/core/stdlib/protobuf/RendererNodes.java b/pkl-core/src/main/java/org/pkl/core/stdlib/protobuf/RendererNodes.java index 82c6274a6..5b42525b3 100644 --- a/pkl-core/src/main/java/org/pkl/core/stdlib/protobuf/RendererNodes.java +++ b/pkl-core/src/main/java/org/pkl/core/stdlib/protobuf/RendererNodes.java @@ -645,10 +645,7 @@ public final class RendererNodes { hasString && elements.size() == 1 ? elements.get(0) : new UnionTypeNode( - VmUtils.unavailableSourceSection(), - -1, - elements.toArray(new TypeNode[0]), - false); + VmUtils.unavailableSourceSection(), -1, elements.toArray(new TypeNode[0])); return type; } return type; diff --git a/pkl-core/src/test/files/LanguageSnippetTests/input/types/typeAlias4.pkl b/pkl-core/src/test/files/LanguageSnippetTests/input/types/typeAlias4.pkl new file mode 100644 index 000000000..e3fa0d31c --- /dev/null +++ b/pkl-core/src/test/files/LanguageSnippetTests/input/types/typeAlias4.pkl @@ -0,0 +1,20 @@ +typealias MyList = List +res1 = List(new Dynamic {}) is MyList + +typealias MySet = Set +res2 = Set(new Dynamic {}) is MySet + +typealias MyMap = Map +res3 = Map("foo", new Dynamic {}) is MyMap + +typealias MyListing = Listing +res4 = new Listing { new Dynamic {} } is MyListing + +typealias MyMapping = Mapping +res5 = new Mapping { ["foo"] = new Dynamic {} } is MyMapping + +typealias MyUnion = A | B +res6 = new Dynamic {} is MyUnion + +typealias NestedUnion = (A | A) | (B | B) +res7 = new Dynamic {} is NestedUnion diff --git a/pkl-core/src/test/files/LanguageSnippetTests/output/types/typeAlias4.pcf b/pkl-core/src/test/files/LanguageSnippetTests/output/types/typeAlias4.pcf new file mode 100644 index 000000000..111a6756f --- /dev/null +++ b/pkl-core/src/test/files/LanguageSnippetTests/output/types/typeAlias4.pcf @@ -0,0 +1,7 @@ +res1 = false +res2 = false +res3 = false +res4 = false +res5 = false +res6 = false +res7 = false