mirror of
https://github.com/apple/pkl.git
synced 2026-01-11 14:20:35 +01:00
Fix super method call inside let expression (#1383)
Fixes #1309 The issue was that super calls were blocked inside let expressions because: 1. The compiler's isClassMemberScope() check didn't skip over lambda scopes created by let expressions 2. The runtime's findSupermethod() didn't traverse past VmFunction owners to find the actual class prototype Changes: - SymbolTable.java: Updated isClassMemberScope() to skip lambda scopes before checking if the parent is a class or module scope - InvokeSuperMethodNode.java: Updated findSupermethod() to skip VmFunction owners when looking for the class prototype Added regression tests covering: - Super method calls inside let expressions - Super property access inside let expressions - Nested let expressions with super calls --------- Co-authored-by: Jen Basch <jbasch@apple.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -327,6 +327,8 @@ public final class SymbolTable {
|
||||
}
|
||||
|
||||
public final boolean isClassMemberScope() {
|
||||
var effectiveScope = skipLambdaScopes();
|
||||
var parent = effectiveScope.parent;
|
||||
if (parent == null) return false;
|
||||
|
||||
return parent.isClassScope()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,6 +25,7 @@ import com.oracle.truffle.api.source.SourceSection;
|
||||
import org.pkl.core.ast.ExpressionNode;
|
||||
import org.pkl.core.ast.member.ClassMethod;
|
||||
import org.pkl.core.runtime.Identifier;
|
||||
import org.pkl.core.runtime.VmFunction;
|
||||
import org.pkl.core.runtime.VmUtils;
|
||||
|
||||
public abstract class InvokeSuperMethodNode extends ExpressionNode {
|
||||
@@ -66,6 +67,10 @@ public abstract class InvokeSuperMethodNode extends ExpressionNode {
|
||||
|
||||
protected ClassMethod findSupermethod(VirtualFrame frame) {
|
||||
var owner = VmUtils.getOwner(frame);
|
||||
while (owner instanceof VmFunction) {
|
||||
owner = owner.getEnclosingOwner();
|
||||
}
|
||||
assert owner != null : "VmFunction always has a parent";
|
||||
assert owner.isPrototype();
|
||||
|
||||
var superclass = owner.getVmClass().getSuperclass();
|
||||
|
||||
44
pkl-core/src/test/files/LanguageSnippetTests/input/classes/supercallsInLet.pkl
vendored
Normal file
44
pkl-core/src/test/files/LanguageSnippetTests/input/classes/supercallsInLet.pkl
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
open class A {
|
||||
function foo() = "a"
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
function foo() =
|
||||
let (bar = "b")
|
||||
super.foo() + bar
|
||||
}
|
||||
|
||||
local b = new B {}
|
||||
|
||||
res1 = b.foo()
|
||||
|
||||
// Also test with property access
|
||||
open class C {
|
||||
value = "c"
|
||||
}
|
||||
|
||||
class D extends C {
|
||||
result =
|
||||
let (x = "d")
|
||||
super.value + x
|
||||
}
|
||||
|
||||
local d = new D {}
|
||||
|
||||
res2 = d.result
|
||||
|
||||
// Test with nested let expressions
|
||||
open class E {
|
||||
function getValue() = "e"
|
||||
}
|
||||
|
||||
class F extends E {
|
||||
function getValue() =
|
||||
let (x = "f")
|
||||
let (y = " and " + x)
|
||||
super.getValue() + y
|
||||
}
|
||||
|
||||
local f = new F {}
|
||||
|
||||
res3 = f.getValue()
|
||||
3
pkl-core/src/test/files/LanguageSnippetTests/output/classes/supercallsInLet.pcf
vendored
Normal file
3
pkl-core/src/test/files/LanguageSnippetTests/output/classes/supercallsInLet.pcf
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
res1 = "ab"
|
||||
res2 = "cd"
|
||||
res3 = "e and f"
|
||||
Reference in New Issue
Block a user