From f284a0560a397e478147b26f23fd6efe117da6f1 Mon Sep 17 00:00:00 2001 From: Jen Basch Date: Thu, 3 Sep 2026 16:03:34 -0700 Subject: [PATCH] Error when inferring a self type in a method argument (#1847) --- .../expression/member/AbstractInferParentNode.java | 2 +- .../InferParentWithinMethodArgumentNode.java | 14 ++++++++++++++ .../main/java/org/pkl/core/ast/type/TypeNode.java | 14 ++++++++++++++ .../input/methods/inferParameterType.pkl | 8 ++++++++ .../output/methods/inferParameterType.pcf | 3 +++ 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/pkl-core/src/main/java/org/pkl/core/ast/expression/member/AbstractInferParentNode.java b/pkl-core/src/main/java/org/pkl/core/ast/expression/member/AbstractInferParentNode.java index bf16fd239..23076fb66 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/expression/member/AbstractInferParentNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/expression/member/AbstractInferParentNode.java @@ -36,7 +36,7 @@ public abstract class AbstractInferParentNode extends ExpressionNode { this.language = language; } - protected final Object getDefaultValue( + protected Object getDefaultValue( VirtualFrame frame, @Nullable TypeNode typeNode, SourceSection headerSection, diff --git a/pkl-core/src/main/java/org/pkl/core/ast/expression/member/InferParentWithinMethodArgumentNode.java b/pkl-core/src/main/java/org/pkl/core/ast/expression/member/InferParentWithinMethodArgumentNode.java index 8b3469106..9d2989aa8 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/expression/member/InferParentWithinMethodArgumentNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/expression/member/InferParentWithinMethodArgumentNode.java @@ -85,4 +85,18 @@ public abstract class InferParentWithinMethodArgumentNode var typeNode = getTypeNode(frame, method); return getDefaultValue(frame, typeNode, method.getHeaderSection(), method.getQualifiedName()); } + + @Override + protected Object getDefaultValue( + VirtualFrame frame, + @Nullable TypeNode typeNode, + SourceSection headerSection, + String qualifiedName) { + if (typeNode != null && typeNode.isSelfType()) { + CompilerDirectives.transferToInterpreter(); + throw exceptionBuilder().evalError("cannotInferParent").build(); + } + + return super.getDefaultValue(frame, typeNode, headerSection, qualifiedName); + } } 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 7c9859fc9..951cc343c 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 @@ -155,6 +155,20 @@ public abstract class TypeNode extends PklNode { return ret.get(); } + public final boolean isSelfType() { + var ret = new MutableBoolean(false); + acceptTypeNode( + true, + typeNode -> { + if (typeNode instanceof NonFinalSelfTypeNode || typeNode instanceof FinalSelfTypeNode) { + ret.set(true); + return false; + } + return true; + }); + return ret.get(); + } + /** Visit child type nodes of this type. */ protected abstract boolean acceptTypeNode(boolean visitTypeArguments, TypeNodeConsumer consumer); diff --git a/pkl-core/src/test/files/LanguageSnippetTests/input/methods/inferParameterType.pkl b/pkl-core/src/test/files/LanguageSnippetTests/input/methods/inferParameterType.pkl index 3e059dd1d..8356412f7 100644 --- a/pkl-core/src/test/files/LanguageSnippetTests/input/methods/inferParameterType.pkl +++ b/pkl-core/src/test/files/LanguageSnippetTests/input/methods/inferParameterType.pkl @@ -16,7 +16,12 @@ class Qux extends Foo { function bar(baz: Foo): Int = thisBar(new { x = baz.x }) } +class Quux { + function selfType(arg: this): String = arg.getClass().toString() +} + function bar(baz: Foo): Int = baz.x +function selfType(arg: this): String = arg.getClass().toString() const function outerMethod(a: Int, b: Qux) = a + b.x * 2 @@ -41,6 +46,9 @@ intrinsicConstructor = test.catch(() -> List(new {})) genericMethod = test.catch(() -> Pair(new {}, new {})) fnApply = test.catch(() -> quux.apply(new {})) tooManyParams = test.catch(() -> bar(new {}, new {})) +finalSelfType = test.catch(() -> new Quux {}.selfType(new {})) +nonFinalSelfType1 = test.catch(() -> selfType(new {})) +nonFinalSelfType2 = test.catch(() -> new Qux {}.selfType(new {})) class Bar1 { x: Int = 1 } class Bar2 { x: Int = 2 } diff --git a/pkl-core/src/test/files/LanguageSnippetTests/output/methods/inferParameterType.pcf b/pkl-core/src/test/files/LanguageSnippetTests/output/methods/inferParameterType.pcf index ff693a58b..272c5447b 100644 --- a/pkl-core/src/test/files/LanguageSnippetTests/output/methods/inferParameterType.pcf +++ b/pkl-core/src/test/files/LanguageSnippetTests/output/methods/inferParameterType.pcf @@ -14,5 +14,8 @@ intrinsicConstructor = "Cannot tell which parent to amend." genericMethod = "Cannot tell which parent to amend." fnApply = "Cannot tell which parent to amend." tooManyParams = "Expected 1 function argument but got 2." +finalSelfType = "Cannot tell which parent to amend." +nonFinalSelfType1 = "Cannot tell which parent to amend." +nonFinalSelfType2 = "Cannot tell which parent to amend." polyCall1 = 1 polyCall2 = 20