-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Description
Label Refactoring
This document outlines the refactoring of the Label node and its usages in the Dart analyzer AST. The goal is to replace SimpleIdentifier (which is an Expression) with a simple Token in places where the name is used purely for structural identification and not for evaluation.
1. Current State (Legacy Design)
Currently, a Label (both in declarations and in break/continue statements) uses a SimpleIdentifier to represent the name. Since SimpleIdentifier is a subclass of Expression, this implies that a label name is an expression, which is semantically incorrect. Labels are purely structural markers and do not evaluate to values or have types.
Current Hierarchy and Usage
-
Label(Declaration):abstract final class Label implements AstNode { SimpleIdentifier get label; Token get colon; }
The
declaredFragment(or element) is currently retrieved by looking at theSimpleIdentifier's element. -
BreakStatement&ContinueStatement(Usage):abstract final class BreakStatement implements Statement { Token get breakKeyword; SimpleIdentifier? get label; Token get semicolon; AstNode? get target; }
The reference to the label is also a
SimpleIdentifier. Its resolved label binding is available vianode.label?.element, whiletargetindependently stores the resolved jump destination AST node.
Pain Points
- Semantic Incorrectness:
SimpleIdentifieris anExpression. Using it for labels implies they have expression semantics (types, evaluation), which they do not. - Cluttered Expression Model: Tools that analyze expressions (like searching for references, refactorings, or lints) have to explicitly filter out label identifiers because they appear in the AST as expressions.
2. New Design (Target State)
The new design splits declarations and references:
- A declared
Labelstores its name as a simpleToken. - A
break/continuelabel reference becomes a dedicated wrapper node that stores both theTokenand its resolvedLabelElement.
This keeps label references out of the expression hierarchy without scattering their resolution state across the parent statement nodes.
Detailed Structure
-
Label(Changes):abstract final class Label implements AstNode { Token get name; // Changed from SimpleIdentifier to Token Token get colon; LabelFragment? get declaredFragment; // Moved from SimpleIdentifier to the Label node itself }
-
LabelReference(New):abstract final class LabelReference implements AstNode { Token get name; LabelElement? get element; }
-
BreakStatementandContinueStatement(Changes):abstract final class BreakStatement implements Statement { Token get breakKeyword; LabelReference? get label; // Changed from SimpleIdentifier? Token get semicolon; AstNode? get target; // Preserved: resolved jump destination AST node }
(Same changes apply to
ContinueStatement.)
3. Advantages
- Semantic Accuracy: Labels are no longer treated as expressions. They are accurately modeled as purely syntactic tokens.
- Cleaner Expression Processing: Visitors that process expressions do not see labels, reducing special-casing and potential bugs in lints or refactorings.
- Node-Based Reference Model: A label use remains a first-class AST node, so tooling such as element location, printing, and reference traversal can continue to work naturally on the reference itself.
- Direct Resolution Access: Resolution information for label bindings is stored directly on the reference node, while existing jump-target resolution on
BreakStatement.target/ContinueStatement.targetremains separate.
4. Implementation (In-Place Breaking Change)
As we are not doing incremental migrations for these structural modernizations, this change will be implemented as an in-place breaking change.
Steps
- AST Structure Update: Modify
ast.dartand regenerate code so thatLabelstores aToken name, andBreakStatement/ContinueStatementuseLabelReference? labelinstead ofSimpleIdentifier?. - Parser Adjustment (
AstBuilder): UpdateAstBuilderto createLabelfrom the declaration token and to buildLabelReferencenodes forbreak/continuelabels. - Resolution Visitor Update (
ResolverVisitor):- For
Label, create and attach theLabelElementdirectly to theLabelnode. - For
LabelReference, resolve itsnameto the activeLabelElementand attach it to the reference node. Continue to computetargetas the resolved jump destination AST node, as today.
- For
- Fix Internal Usages: Update internal analyzer visitors (testing, highlights, lints, element location, source printing) to use the new declaration token and
LabelReferencenode.
Content before 2026-03-29 9:20
Label Refactoring
This document outlines the refactoring of the Label node and its usages in the Dart analyzer AST. The goal is to replace SimpleIdentifier (which is an Expression) with a simple Token in places where the name is used purely for structural identification and not for evaluation.
1. Current State (Legacy Design)
Currently, a Label (both in declarations and in break/continue statements) uses a SimpleIdentifier to represent the name. Since SimpleIdentifier is a subclass of Expression, this implies that a label name is an expression, which is semantically incorrect. Labels are purely structural markers and do not evaluate to values or have types.
Current Hierarchy and Usage
-
Label(Declaration):abstract final class Label implements AstNode { SimpleIdentifier get label; Token get colon; }
The
declaredFragment(or element) is currently retrieved by looking at theSimpleIdentifier's element. -
BreakStatement&ContinueStatement(Usage):abstract final class BreakStatement implements Statement { Token get breakKeyword; SimpleIdentifier? get label; Token get semicolon; }
The reference to the label is also a
SimpleIdentifier.
Pain Points
- Semantic Incorrectness:
SimpleIdentifieris anExpression. Using it for labels implies they have expression semantics (types, evaluation), which they do not. - Cluttered Expression Model: Tools that analyze expressions (like searching for references, refactorings, or lints) have to explicitly filter out label identifiers because they appear in the AST as expressions.
2. New Design (Target State)
The new design changes the label representation from a SimpleIdentifier to a simple Token. This applies to both the Label declaration and the label references in BreakStatement and ContinueStatement.
Since the Token itself cannot hold resolution information (like an element or fragment), the resolution state is moved directly onto the containing AST nodes.
Detailed Structure
-
Label(Changes):abstract final class Label implements AstNode { Token get name; // Changed from SimpleIdentifier to Token Token get colon; LabelFragment? get declaredFragment; // Moved from SimpleIdentifier to the Label node itself }
-
BreakStatementandContinueStatement(Changes):abstract final class BreakStatement implements Statement { Token get breakKeyword; Token? get label; // Changed from SimpleIdentifier? to Token? Token get semicolon; LabelElement? get target; // Resolution moved to the statement itself }
(Same changes apply to
ContinueStatement.)
3. Advantages
- Semantic Accuracy: Labels are no longer treated as expressions. They are accurately modeled as purely syntactic tokens.
- Cleaner Expression Processing: Visitors that process expressions do not see labels, reducing special-casing and potential bugs in lints or refactorings.
- Direct Resolution Access: Resolution information (elements) is stored directly on the nodes that define or consume the label, rather than hiding it inside a child identifier.
4. Implementation (In-Place Breaking Change)
As we are not doing incremental migrations for these structural modernizations, this change will be implemented as an in-place breaking change.
Steps
- AST Structure Update: Modify
ast.dartand regenerate code to change thelabelfields fromSimpleIdentifiertoToken. - Parser Adjustment (
AstBuilder): UpdateAstBuilderto create the new nodes using theTokendirectly from the token stream. - Resolution Visitor Update (
ResolverVisitor):- For
Label, create and attach theLabelElementdirectly to theLabelnode. - For
BreakStatement/ContinueStatement, resolve theTokento the activeLabelElementand attach it to the statement'starget.
- For
- Fix Internal Usages: Update all internal analyzer visitors (testing, highlights, lints) to use the new
Tokenand node-level elements.