mirror of
https://github.com/apple/pkl.git
synced 2026-01-11 22:30:54 +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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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() {
|
public final boolean isClassMemberScope() {
|
||||||
|
var effectiveScope = skipLambdaScopes();
|
||||||
|
var parent = effectiveScope.parent;
|
||||||
if (parent == null) return false;
|
if (parent == null) return false;
|
||||||
|
|
||||||
return parent.isClassScope()
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.ExpressionNode;
|
||||||
import org.pkl.core.ast.member.ClassMethod;
|
import org.pkl.core.ast.member.ClassMethod;
|
||||||
import org.pkl.core.runtime.Identifier;
|
import org.pkl.core.runtime.Identifier;
|
||||||
|
import org.pkl.core.runtime.VmFunction;
|
||||||
import org.pkl.core.runtime.VmUtils;
|
import org.pkl.core.runtime.VmUtils;
|
||||||
|
|
||||||
public abstract class InvokeSuperMethodNode extends ExpressionNode {
|
public abstract class InvokeSuperMethodNode extends ExpressionNode {
|
||||||
@@ -66,6 +67,10 @@ public abstract class InvokeSuperMethodNode extends ExpressionNode {
|
|||||||
|
|
||||||
protected ClassMethod findSupermethod(VirtualFrame frame) {
|
protected ClassMethod findSupermethod(VirtualFrame frame) {
|
||||||
var owner = VmUtils.getOwner(frame);
|
var owner = VmUtils.getOwner(frame);
|
||||||
|
while (owner instanceof VmFunction) {
|
||||||
|
owner = owner.getEnclosingOwner();
|
||||||
|
}
|
||||||
|
assert owner != null : "VmFunction always has a parent";
|
||||||
assert owner.isPrototype();
|
assert owner.isPrototype();
|
||||||
|
|
||||||
var superclass = owner.getVmClass().getSuperclass();
|
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