Summary
Replace anonymous impl Foo { } blocks with named extension declarations (extension FooExtensions for Foo { }) that are first-class syntax nodes, have an explicit name, and can contain the same members as a class body except fields.
Motivation
The current impl blocks are semantically anonymous — multiple impl blocks for the same type are merged silently, and there is no way to refer to a specific extension as a unit. Named extensions make the grouping explicit, match how the type system already models them internally, and enable future features (conditional extensions, visibility on the extension itself, etc.).
Changes
Before:
impl Vector2 {
def length(self): float { ... }
}
After:
extension Vector2Extensions for Vector2 {
def length(self): float { ... }
# Extensions also support associated let/const (no fields):
let UNIT_X: Vector2 = Vector2(1.0, 0.0);
const MAX_COMPONENTS: int = 2;
}
Extension members are accessible via the extended type (Vector2.UNIT_X, v.length()), not via the extension name.
Affected components
TokenKind.java — add ExtensionKeyword; remove ImplKeyword
SyntaxFacts.java — add ExtensionKeyword to keyword map
ImplBlockSyntax.java — rename/replace with ExtensionDeclarationSyntax; add extensionName: SimpleIdentifierSyntax and targetType: TypeSyntax fields; keep members: SyntaxList<MemberSyntax>
Parser.java — replace parseImplBlock() with parseExtensionDecl(): consume extension, parse name identifier, consume for, parse target type, parse member block; update isMemberStart() and parseMember() to use ExtensionKeyword
SyntaxVisitor.java, SyntaxWalker.java — rename visitImplDecl → visitExtensionDecl
MemberBinder.java / GlobalBinder.java — update all call sites that handle ImplBlockSyntax
TestParser.java, TestTypeChecker.java — update all impl fixtures
Notes
for in extension X for Y does not conflict with the loop ForKeyword because the parser only enters parseExtensionDecl() after matching ExtensionKeyword. Inside that production for is consumed as a separator token rather than a statement keyword.
- Extensions cannot declare fields; attempting to do so is a semantic error (reported by the binder, not the parser, to keep the grammar simple).
- The extension name (
FooExtensions) is currently unused at runtime but is preserved in the AST for tooling and future use.
Summary
Replace anonymous
impl Foo { }blocks with named extension declarations (extension FooExtensions for Foo { }) that are first-class syntax nodes, have an explicit name, and can contain the same members as a class body except fields.Motivation
The current
implblocks are semantically anonymous — multipleimplblocks for the same type are merged silently, and there is no way to refer to a specific extension as a unit. Named extensions make the grouping explicit, match how the type system already models them internally, and enable future features (conditional extensions, visibility on the extension itself, etc.).Changes
Before:
After:
Extension members are accessible via the extended type (
Vector2.UNIT_X,v.length()), not via the extension name.Affected components
TokenKind.java— addExtensionKeyword; removeImplKeywordSyntaxFacts.java— addExtensionKeywordto keyword mapImplBlockSyntax.java— rename/replace withExtensionDeclarationSyntax; addextensionName: SimpleIdentifierSyntaxandtargetType: TypeSyntaxfields; keepmembers: SyntaxList<MemberSyntax>Parser.java— replaceparseImplBlock()withparseExtensionDecl(): consumeextension, parse name identifier, consumefor, parse target type, parse member block; updateisMemberStart()andparseMember()to useExtensionKeywordSyntaxVisitor.java,SyntaxWalker.java— renamevisitImplDecl→visitExtensionDeclMemberBinder.java/GlobalBinder.java— update all call sites that handleImplBlockSyntaxTestParser.java,TestTypeChecker.java— update all impl fixturesNotes
forinextension X for Ydoes not conflict with the loopForKeywordbecause the parser only entersparseExtensionDecl()after matchingExtensionKeyword. Inside that productionforis consumed as a separator token rather than a statement keyword.FooExtensions) is currently unused at runtime but is preserved in the AST for tooling and future use.