mirror of
https://github.com/apple/pkl.git
synced 2026-07-02 03:01:45 +02:00
Reject abstract members in non-abstract classes (#1647)
Fixes #1614. ## Context A non-abstract `class` (or `module`) was allowed to declare `abstract` properties and methods. Because such an enclosing type is instantiable, an `abstract` member there can never be guaranteed an implementation — so the contradiction surfaced only as a runtime error when the member was accessed (`Cannot invoke abstract method`), or not at all. This makes it a compile-time error to declare an `abstract` member unless its enclosing class or module is also `abstract`. This is consistent with how Pkl already rejects instantiating an abstract class, and mirrors how Java and Kotlin treat abstract members. ## Before ```pkl class Foo { abstract bar: Int } res = new Foo { bar = 5 } // evaluated successfully (should fail) ``` ```pkl class Foo { abstract function bar(): Int } res = new Foo {} // evaluated successfully; res.bar() failed only at runtime ``` ## After ``` –– Pkl Error –– Cannot define an abstract member in a non-abstract class. 2 | abstract bar: Int ^^^^^^^^ at Foo A member can only be `abstract` if its enclosing class is also `abstract`. ``` ## Implementation - `AstBuilder` now validates, while building the AST, that a non-abstract class/module declares no `abstract` members. The check runs in both `visitClass` and `visitModule`, and the error points at the `abstract` keyword. - Adds the `abstractMemberInNonAbstractClass` error message. ## Scope: classes and modules The issue describes classes; I applied the same rule to modules as well, since a module is a class in Pkl and a non-abstract module is likewise directly evaluatable. Happy to narrow this to classes only if you'd prefer — it's a one-line change either way. The `moduleMethodModifiers` pkl-doc test fixture declared an abstract method at non-abstract module level (relying on the old behavior); it's updated to an `abstract module`, and its expected documentation output is regenerated. ## Tests - New `LanguageSnippetTests` error cases: abstract property in a class, abstract method in a class, and abstract member in a module. - `./gradlew build` passes (`pkl-core` and `pkl-doc` included). --------- Co-authored-by: Vinayak <vinayak@vama.app> Co-authored-by: Daniel Chao <daniel.h.chao@gmail.com>
This commit is contained in:
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
class Foo {
|
||||
abstract bar: Int
|
||||
}
|
||||
|
||||
res = new Foo { bar = 5 }
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
abstract foo: Int
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
class Foo {
|
||||
abstract function bar(): Int
|
||||
}
|
||||
|
||||
res = new Foo {}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
–– Pkl Error ––
|
||||
Cannot define an abstract member in a non-abstract class.
|
||||
|
||||
x | abstract bar: Int
|
||||
^^^^^^^^
|
||||
at abstractMemberInNonAbstractClass#Foo (file:///$snippetsDir/input/errors/abstractMemberInNonAbstractClass.pkl)
|
||||
|
||||
A member can only be `abstract` if its enclosing class is also `abstract`.
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
–– Pkl Error ––
|
||||
Cannot define an abstract member in a non-abstract class.
|
||||
|
||||
x | abstract foo: Int
|
||||
^^^^^^^^
|
||||
at abstractMemberInNonAbstractModule (file:///$snippetsDir/input/errors/abstractMemberInNonAbstractModule.pkl)
|
||||
|
||||
A member can only be `abstract` if its enclosing class is also `abstract`.
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
–– Pkl Error ––
|
||||
Cannot define an abstract member in a non-abstract class.
|
||||
|
||||
x | abstract function bar(): Int
|
||||
^^^^^^^^
|
||||
at abstractMethodInNonAbstractClass#Foo (file:///$snippetsDir/input/errors/abstractMethodInNonAbstractClass.pkl)
|
||||
|
||||
A member can only be `abstract` if its enclosing class is also `abstract`.
|
||||
Reference in New Issue
Block a user