Skip to content

syntax: replace impl blocks with named extension declarations #4

Description

@Gray-SS

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions