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 0d387b91f..22544d37b 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 @@ -39,7 +39,7 @@ public abstract class UnresolvedTypeNode extends PklNode { private final VmLanguage language; @Child UnresolvedTypeNode childNode; - TypeConstraintNode[] constraintCheckNodes; + @Children TypeConstraintNode[] constraintCheckNodes; public Constrained( SourceSection sourceSection, diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/VmTypeAlias.java b/pkl-core/src/main/java/org/pkl/core/runtime/VmTypeAlias.java index b0f82a931..4f4feea84 100644 --- a/pkl-core/src/main/java/org/pkl/core/runtime/VmTypeAlias.java +++ b/pkl-core/src/main/java/org/pkl/core/runtime/VmTypeAlias.java @@ -184,7 +184,7 @@ public final class VmTypeAlias extends VmValue { // * Fewer root nodes to call // * ControlFlowException used to implement union types doesn't escape root node - if (typeParameters.isEmpty()) return (TypeNode) typeNode.deepCopy(); + if (typeParameters.isEmpty()) return deepCopy(typeNode); // handle if alias root is itself a type variable (https://github.com/apple/pkl/issues/1711) if (typeNode instanceof TypeVariableNode typeVarNode) { @@ -198,13 +198,11 @@ public final class VmTypeAlias extends VmValue { clone.accept( node -> { if (node instanceof TypeVariableNode typeVarNode) { - int index = typeVarNode.getTypeParameterIndex(); - // should not need to clone type argument node because it is not used by its original - // root node + var index = typeVarNode.getTypeParameterIndex(); node.replace( typeArgumentNodes.length == 0 ? new UnknownTypeNode(sourceSection) - : typeArgumentNodes[index]); + : deepCopy(typeArgumentNodes[index])); } else if (node instanceof UnresolvedTypeNode.TypeVariable unresolvedTypeVar) { // Type variables inside constraint expressions (e.g. `every((it) -> it is T)`) // are still unresolved at instantiation time. Replace them with a resolved @@ -213,7 +211,8 @@ public final class VmTypeAlias extends VmValue { node.replace( typeArgumentNodes.length == 0 ? new UnresolvedTypeNode.Unknown(sourceSection) - : new UnresolvedTypeNode.Resolved(sourceSection, typeArgumentNodes[index])); + : new UnresolvedTypeNode.Resolved( + sourceSection, deepCopy(typeArgumentNodes[index]))); } return true; }); @@ -311,4 +310,8 @@ public final class VmTypeAlias extends VmValue { public String toString() { return qualifiedName.startsWith("pkl.base#") ? simpleName : qualifiedName; } + + private static TypeNode deepCopy(TypeNode typeArgumentNode) { + return (TypeNode) typeArgumentNode.deepCopy(); + } } diff --git a/pkl-core/src/test/files/LanguageSnippetTests/input/types/typeAliasConstraint3.pkl b/pkl-core/src/test/files/LanguageSnippetTests/input/types/typeAliasConstraint3.pkl index 5f5a16741..de03ed6e5 100644 --- a/pkl-core/src/test/files/LanguageSnippetTests/input/types/typeAliasConstraint3.pkl +++ b/pkl-core/src/test/files/LanguageSnippetTests/input/types/typeAliasConstraint3.pkl @@ -1,3 +1,17 @@ -typealias MyList = List(this[0] is T) +import "pkl:test" -foo: MyList = List("uh oh") +typealias MyList = List(this[0] is T) +typealias MyList2 = List((this[0] as T) != null) +typealias MyList3 = List((this[0] is Any(this is T))) +typealias MyList4 = List((this[0] is T(!(this is T)))) +typealias MyList5 = List((this[0] is T(true))) +typealias MyList6 = List(this[0] is T?) + +local foo = List("uh oh") + +res = test.catch(() -> foo as MyList) +res2 = test.catch(() -> foo as MyList2) +res3 = test.catch(() -> foo as MyList3) +res4 = test.catch(() -> foo as MyList4) +res5 = test.catch(() -> foo as MyList5) +res6 = test.catch(() -> foo as MyList6) diff --git a/pkl-core/src/test/files/LanguageSnippetTests/output/types/typeAliasConstraint3.err b/pkl-core/src/test/files/LanguageSnippetTests/output/types/typeAliasConstraint3.err deleted file mode 100644 index aafc48d7d..000000000 --- a/pkl-core/src/test/files/LanguageSnippetTests/output/types/typeAliasConstraint3.err +++ /dev/null @@ -1,25 +0,0 @@ -–– Pkl Error –– -Type constraint `this[0] is T` violated. -Value: List("uh oh") - - this[0] is T - │ │ │ - │ │ false - │ "uh oh" - List("uh oh") - -x | typealias MyList = List(this[0] is T) - ^^^^^^^^^^^^ -at typeAliasConstraint3#foo (file:///$snippetsDir/input/types/typeAliasConstraint3.pkl) - -x | foo: MyList = List("uh oh") - ^^^^^^^^^^^^^ -at typeAliasConstraint3#foo (file:///$snippetsDir/input/types/typeAliasConstraint3.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) diff --git a/pkl-core/src/test/files/LanguageSnippetTests/output/types/typeAliasConstraint3.pcf b/pkl-core/src/test/files/LanguageSnippetTests/output/types/typeAliasConstraint3.pcf new file mode 100644 index 000000000..fbcf432c9 --- /dev/null +++ b/pkl-core/src/test/files/LanguageSnippetTests/output/types/typeAliasConstraint3.pcf @@ -0,0 +1,6 @@ +res = "Type constraint `this[0] is T` violated. Value: List(\"uh oh\")" +res2 = "Expected value of type `Int`, but got type `String`. Value: \"uh oh\"" +res3 = "Type constraint `this[0] is Any(this is T)` violated. Value: \"u\"" +res4 = "Type constraint `this[0] is T(!(this is T))` violated. Value: \"u\"" +res5 = "Type constraint `this[0] is T(true)` violated. Value: List(\"uh oh\")" +res6 = "Type constraint `this[0] is T?` violated. Value: List(\"uh oh\")"