Revert "Revert "Reject abstract members in non-abstract classes" (#1688)" (#1780)

This reverts commit 1bf00b84ea.

Co-authored-by: Vinayak <vinayak@vama.app>
This commit is contained in:
Jen Basch
2026-07-16 11:34:20 -07:00
committed by GitHub
parent a1421ff667
commit 3d03a47933
11 changed files with 70 additions and 3 deletions
@@ -1476,6 +1476,8 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
var scope = (ModuleScope) symbolTable.getCurrentScope(); var scope = (ModuleScope) symbolTable.getCurrentScope();
scope.setModifiers(modifiers); scope.setModifiers(modifiers);
checkAbstractMembersAllowed(modifiers, mod.getProperties(), mod.getMethods());
// visit imports first so that we already have the object member name available // visit imports first so that we already have the object member name available
var imports = mod.getImports(); var imports = mod.getImports();
var importMembers = new ObjectMember[imports.size()]; var importMembers = new ObjectMember[imports.size()];
@@ -1720,6 +1722,7 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
List<ClassProperty> properties = bodyNode != null ? bodyNode.getProperties() : List.of(); List<ClassProperty> properties = bodyNode != null ? bodyNode.getProperties() : List.of();
List<ClassMethod> methods = bodyNode != null ? bodyNode.getMethods() : List.of(); List<ClassMethod> methods = bodyNode != null ? bodyNode.getMethods() : List.of();
registerClassScopeNames(scope, properties, methods); registerClassScopeNames(scope, properties, methods);
checkAbstractMembersAllowed(modifiers, properties, methods);
var supertypeCtx = clazz.getSuperClass(); var supertypeCtx = clazz.getSuperClass();
@@ -1810,6 +1813,30 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
}; };
} }
private void checkAbstractMembersAllowed(
int enclosingModifiers, List<ClassProperty> properties, List<ClassMethod> methods) {
if (VmModifier.isAbstract(enclosingModifiers)) {
return;
}
for (var property : properties) {
checkMemberNotAbstract(property.getModifiers());
}
for (var method : methods) {
checkMemberNotAbstract(method.getModifiers());
}
}
private void checkMemberNotAbstract(List<Modifier> modifiers) {
for (var modifier : modifiers) {
if (modifier.getValue() == ModifierValue.ABSTRACT) {
throw exceptionBuilder()
.evalError("abstractMemberInNonAbstractClass")
.withSourceSection(createSourceSection(modifier.span()))
.build();
}
}
}
private UnresolvedPropertyNode[] doVisitClassProperties( private UnresolvedPropertyNode[] doVisitClassProperties(
List<ClassProperty> propertyContexts, Set<String> propertyNames) { List<ClassProperty> propertyContexts, Set<String> propertyNames) {
var propertyNodes = new UnresolvedPropertyNode[propertyContexts.size()]; var propertyNodes = new UnresolvedPropertyNode[propertyContexts.size()];
@@ -289,6 +289,11 @@ External members cannot have a body.
abstractMemberCannotHaveBody=\ abstractMemberCannotHaveBody=\
Abstract members cannot have a body. Abstract members cannot have a body.
abstractMemberInNonAbstractClass=\
Cannot define an abstract member in a non-abstract class.\n\
\n\
A member can only be `abstract` if its enclosing class is also `abstract`.
methodNotDefined1=\ methodNotDefined1=\
Method `{0}` is not defined for argument type `{1}`. Method `{0}` is not defined for argument type `{1}`.
@@ -0,0 +1,5 @@
class Foo {
abstract bar: Int
}
res = new Foo { bar = 5 }
@@ -0,0 +1 @@
abstract foo: Int
@@ -0,0 +1,5 @@
class Foo {
abstract function bar(): Int
}
res = new Foo {}
@@ -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`.
@@ -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`.
@@ -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`.
@@ -1,5 +1,5 @@
/// Module methods with different modifiers. /// Module methods with different modifiers.
module com.package1.moduleMethodModifiers abstract module com.package1.moduleMethodModifiers
/// Method with `abstract` modifier. /// Method with `abstract` modifier.
abstract function method1(arg: String): Boolean abstract function method1(arg: String): Boolean
@@ -32,7 +32,7 @@
</ul> </ul>
<div id="_overview" class="anchor"> </div> <div id="_overview" class="anchor"> </div>
<div id="_declaration" class="member"> <div id="_declaration" class="member">
<div class="member-signature">module <span class="name-decl">com.package1.moduleMethodModifiers</span></div> <div class="member-signature">abstract module <span class="name-decl">com.package1.moduleMethodModifiers</span></div>
<div class="doc-comment"><p>Module methods with different modifiers.</p></div> <div class="doc-comment"><p>Module methods with different modifiers.</p></div>
<dl class="member-info"> <dl class="member-info">
<dt class="">Module URI:</dt> <dt class="">Module URI:</dt>
@@ -32,7 +32,7 @@
</ul> </ul>
<div id="_overview" class="anchor"> </div> <div id="_overview" class="anchor"> </div>
<div id="_declaration" class="member"> <div id="_declaration" class="member">
<div class="member-signature">module <span class="name-decl">com.package1.moduleMethodModifiers</span></div> <div class="member-signature">abstract module <span class="name-decl">com.package1.moduleMethodModifiers</span></div>
<div class="doc-comment"><p>Module methods with different modifiers.</p></div> <div class="doc-comment"><p>Module methods with different modifiers.</p></div>
<dl class="member-info"> <dl class="member-info">
<dt class="">Module URI:</dt> <dt class="">Module URI:</dt>