[cfe][Contexts] Split VariableDeclaration and VariableStatement

This separates VariableDeclaration from Statement. VariableDeclaration no longer implements Statement and variable declared in a block or in a for-statement are now wrapped by a VariableStatement.

Currently there are two VariableStatement implementations; LegacyVariableStatement for variables in the current model, called LegacyVariable, and VariableInitialization for variables used in the new, still experimental, encoding that supports scope computation.

This CL is a step towards realigning the AST nodes to the new model in which each kind of variable has its own distinct subclass. (LocalVariable, PositionalParameter, NamedParameter, SyntheticVariable, etc.)

Note that it is not the intent to use VariableStatement in ForStatement going forward but that will be handled in a follow-up.

TEST=existing.

Change-Id: I5b309cd62c9b138f95b74fb054686edffa49a393
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/502681
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Nicholas Shahan <nshahan@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Johnni Winther
2026-05-18 05:49:28 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 046d473d5e
commit e30cd0322c
78 changed files with 1341 additions and 1132 deletions
+27 -20
View File
@@ -4861,10 +4861,10 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
@override
js_ast.Statement visitForStatement(ForStatement node) {
return _translateLoop(node, () {
js_ast.VariableInitialization emitForInitializer(VariableDeclaration v) =>
js_ast.VariableInitialization emitForInitializer(VariableStatement s) =>
js_ast.VariableInitialization(
_emitVariableDef(v),
_visitInitializer(v.initializer, v.annotations),
_emitVariableDef(s.variable),
_visitInitializer(s.variable.initializer, s.variable.annotations),
);
if (node.variables.any(containsFunctionExpression)) {
@@ -4934,30 +4934,34 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
js_ast.Statement _rewriteAsWhile(ForStatement node) {
var initFlagTempId = _emitScopedId('t#_init');
var loopVariableIds = {
for (var variable in node.variables) variable: _emitVariableDef(variable),
for (var stmt in node.variables)
stmt.variable: _emitVariableDef(stmt.variable),
};
var prevVariableTempIds = {
for (var variable in node.variables)
variable: _emitScopedId('t#_prev_${variable.name!}'),
for (var stmt in node.variables)
stmt.variable: _emitScopedId('t#_prev_${stmt.variable.name!}'),
};
var inits = js_ast.Block([
// Set init flag to false so the initialization only happens on the first
// iteration of the while loop.
js.statement('# = false;', [initFlagTempId]),
// Initialize fresh loop variables to initial values.
for (var variable in node.variables)
for (var stmt in node.variables)
js.statement('# = #;', [
loopVariableIds[variable]!,
_visitInitializer(variable.initializer, variable.annotations),
loopVariableIds[stmt.variable]!,
_visitInitializer(
stmt.variable.initializer,
stmt.variable.annotations,
),
]),
]);
var prevInits = js_ast.Block([
// Initialize fresh loop variables with the value from the previous
// iteration.
for (var variable in node.variables)
for (var stmt in node.variables)
js.statement('# = #;', [
loopVariableIds[variable],
prevVariableTempIds[variable],
loopVariableIds[stmt.variable],
prevVariableTempIds[stmt.variable],
]),
// Original update expressions.
for (var update in node.updates) _visitExpression(update).toStatement(),
@@ -4970,8 +4974,11 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
initFlagTempId,
js_ast.LiteralBool(true),
),
for (var variable in node.variables)
js_ast.VariableInitialization(prevVariableTempIds[variable]!, null),
for (var stmt in node.variables)
js_ast.VariableInitialization(
prevVariableTempIds[stmt.variable]!,
null,
),
]).toStatement(),
// The for loop transformed into a while loop.
js_ast.While(
@@ -4980,9 +4987,9 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
// Create fresh loop variables every iteration.
if (node.variables.isNotEmpty)
js_ast.VariableDeclarationList('let', [
for (var variable in node.variables)
for (var stmt in node.variables)
js_ast.VariableInitialization(
loopVariableIds[variable]!,
loopVariableIds[stmt.variable]!,
null,
),
]).toStatement(),
@@ -4995,15 +5002,15 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
// Original loop body.
_visitScope(_effectiveBodyOf(node, node.body)),
// Save previous loop variables
for (var variable in node.variables)
for (var stmt in node.variables)
js.statement('# = #;', [
prevVariableTempIds[variable]!,
_emitVariableRef(variable),
prevVariableTempIds[stmt.variable]!,
_emitVariableRef(stmt.variable),
])
// Map these locations to the variable declaration so stepping
// in the Dart debugger doesn't jump to the previous line when
// stepping.
..sourceInformation = _nodeStart(variable),
..sourceInformation = _nodeStart(stmt.variable),
]),
)
// The while loop gets mapped to the original for loop location.
@@ -5475,10 +5475,10 @@ class LibraryCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
@override
js_ast.Statement visitForStatement(ForStatement node) {
return _translateLoop(node, () {
js_ast.VariableInitialization emitForInitializer(VariableDeclaration v) =>
js_ast.VariableInitialization emitForInitializer(VariableStatement s) =>
js_ast.VariableInitialization(
_emitVariableDef(v),
_visitInitializer(v.initializer, v.annotations),
_emitVariableDef(s.variable),
_visitInitializer(s.variable.initializer, s.variable.annotations),
);
if (node.variables.any(containsFunctionExpression)) {
@@ -5548,30 +5548,34 @@ class LibraryCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
js_ast.Statement _rewriteAsWhile(ForStatement node) {
var initFlagTempId = _emitScopedId('t#_init');
var loopVariableIds = {
for (var variable in node.variables) variable: _emitVariableDef(variable),
for (var stmt in node.variables)
stmt.variable: _emitVariableDef(stmt.variable),
};
var prevVariableTempIds = {
for (var variable in node.variables)
variable: _emitScopedId('t#_prev_${variable.name!}'),
for (var stmt in node.variables)
stmt.variable: _emitScopedId('t#_prev_${stmt.variable.name!}'),
};
var inits = js_ast.Block([
// Set init flag to false so the initialization only happens on the first
// iteration of the while loop.
js.statement('# = false;', [initFlagTempId]),
// Initialize fresh loop variables to initial values.
for (var variable in node.variables)
for (var stmt in node.variables)
js.statement('# = #;', [
loopVariableIds[variable]!,
_visitInitializer(variable.initializer, variable.annotations),
loopVariableIds[stmt.variable]!,
_visitInitializer(
stmt.variable.initializer,
stmt.variable.annotations,
),
]),
]);
var prevInits = js_ast.Block([
// Intialize fresh loop variables with the value from the previous
// iteration.
for (var variable in node.variables)
for (var stmt in node.variables)
js.statement('# = #;', [
loopVariableIds[variable],
prevVariableTempIds[variable],
loopVariableIds[stmt.variable],
prevVariableTempIds[stmt.variable],
]),
// Original update expressions.
for (var update in node.updates) _visitExpression(update).toStatement(),
@@ -5584,8 +5588,11 @@ class LibraryCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
initFlagTempId,
js_ast.LiteralBool(true),
),
for (var variable in node.variables)
js_ast.VariableInitialization(prevVariableTempIds[variable]!, null),
for (var stmt in node.variables)
js_ast.VariableInitialization(
prevVariableTempIds[stmt.variable]!,
null,
),
]).toStatement(),
// The for loop transformed into a while loop.
js_ast.While(
@@ -5594,9 +5601,9 @@ class LibraryCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
// Create fresh loop variables every iteration.
if (node.variables.isNotEmpty)
js_ast.VariableDeclarationList('let', [
for (var variable in node.variables)
for (var stmt in node.variables)
js_ast.VariableInitialization(
loopVariableIds[variable]!,
loopVariableIds[stmt.variable]!,
null,
),
]).toStatement(),
@@ -5609,15 +5616,15 @@ class LibraryCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
// Original loop body.
_visitScope(_effectiveBodyOf(node, node.body)),
// Save previous loop variables
for (var variable in node.variables)
for (var stmt in node.variables)
js.statement('# = #;', [
prevVariableTempIds[variable]!,
_emitVariableRef(variable),
prevVariableTempIds[stmt.variable]!,
_emitVariableRef(stmt.variable),
])
// Map these locations to the variable declaration so stepping
// in the Dart debugger doesn't jump to the previous line when
// stepping.
..sourceInformation = _nodeStart(variable),
..sourceInformation = _nodeStart(stmt.variable),
]),
)
// The while loop gets mapped to the original for loop location.
@@ -187,7 +187,7 @@ class ModuleSymbolsCollector extends RecursiveVisitor {
}
@override
void visitVariableDeclaration(VariableDeclaration node) {
void defaultVariableDeclaration(VariableDeclaration node) {
var kind = node.isInitializingFormal
? VariableSymbolKind.formal
: VariableSymbolKind.local;
@@ -417,7 +417,7 @@ class _NullableVariableInference extends RecursiveVisitor {
}
@override
void visitVariableDeclaration(VariableDeclaration node) {
void defaultVariableDeclaration(VariableDeclaration node) {
if (_nullInference.allowNotNullDeclarations) {
var annotations = node.annotations;
if (annotations.isNotEmpty &&