[cfe] Introduce InternalSyntheticVariable internal AST node
The new node is generated in for-in loops with synthetic variables. Part of https://github.com/dart-lang/sdk/issues/61572 Change-Id: Icaa63097a145d07cdcfe21edc0487a47f90da8dd Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/487060 Commit-Queue: Chloe Stefantsova <cstefantsova@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
committed by
Commit Queue
parent
39870102e6
commit
ea1f4d474e
@@ -8236,13 +8236,22 @@ class BodyBuilderImpl extends StackListenerImpl
|
||||
lvalue.isConst = false;
|
||||
}
|
||||
} else {
|
||||
VariableDeclaration variable = elements.syntheticVariableDeclaration =
|
||||
forest.createVariableDeclaration(
|
||||
offsetForToken(forToken),
|
||||
null,
|
||||
isFinal: true,
|
||||
isSynthesized: true,
|
||||
);
|
||||
ExpressionVariable astVariable = isClosureContextLoweringEnabled
|
||||
? new SyntheticVariable(type: const DynamicType())
|
||||
: forest.createVariableDeclaration(
|
||||
offsetForToken(forToken),
|
||||
null,
|
||||
isFinal: true,
|
||||
isSynthesized: true,
|
||||
);
|
||||
|
||||
ExpressionVariable variable = elements.syntheticVariableDeclaration =
|
||||
isClosureContextLoweringEnabled
|
||||
? new InternalSyntheticVariable(
|
||||
astVariable: astVariable as SyntheticVariable,
|
||||
isImplicitlyTyped: false,
|
||||
)
|
||||
: astVariable;
|
||||
if (lvalue is Generator) {
|
||||
/// We are in this case, where `lvalue` isn't a [VariableDeclaration]:
|
||||
///
|
||||
@@ -8255,7 +8264,7 @@ class BodyBuilderImpl extends StackListenerImpl
|
||||
/// body;
|
||||
/// }
|
||||
elements.syntheticAssignment = lvalue.buildAssignment(
|
||||
new VariableGet(variable)..fileOffset = inToken.offset,
|
||||
new VariableGet(astVariable)..fileOffset = inToken.offset,
|
||||
voidContext: true,
|
||||
);
|
||||
} else if (lvalue is Pattern) {
|
||||
|
||||
@@ -1334,6 +1334,48 @@ class InternalCatchVariable extends TreeNode
|
||||
String get catchVariableName => astVariable.catchVariableName;
|
||||
}
|
||||
|
||||
class InternalSyntheticVariable extends TreeNode
|
||||
with InternalExpressionVariableMixin, DelegatingVariableMixin
|
||||
implements SyntheticVariable, InternalExpressionVariable {
|
||||
@override
|
||||
SyntheticVariable astVariable;
|
||||
|
||||
@override
|
||||
final bool forSyntheticToken;
|
||||
|
||||
@override
|
||||
final bool isImplicitlyTyped;
|
||||
|
||||
@override
|
||||
final bool isLocalFunction;
|
||||
|
||||
InternalSyntheticVariable({
|
||||
required this.astVariable,
|
||||
required this.isImplicitlyTyped,
|
||||
this.forSyntheticToken = false,
|
||||
this.isLocalFunction = false,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "InternalSyntheticVariable(${toStringInternal()})";
|
||||
}
|
||||
|
||||
@override
|
||||
// Coverage-ignore(suite): Not run.
|
||||
void toTextInternal(AstPrinter printer) {
|
||||
printer.writeExpressionVariable(astVariable);
|
||||
List<String> modifiers = [
|
||||
if (forSyntheticToken) "forSyntheticToken",
|
||||
if (isImplicitlyTyped) "isImplicitlyTyped",
|
||||
if (isLocalFunction) "isLocalFunction",
|
||||
];
|
||||
if (modifiers.isNotEmpty) {
|
||||
printer.write("[${modifiers.join(",")}]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mixin DelegatingVariableMixin on InternalExpressionVariableMixin
|
||||
implements InternalExpressionVariable {
|
||||
@override
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
test(List<String> list) {
|
||||
String s = "";
|
||||
for (s in list) {
|
||||
if (s.isNotEmpty) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method test(positional-parameter list) → dynamic/* scope=[
|
||||
#ctx1: not-captured VariableContext([
|
||||
positional-parameter list;
|
||||
]),
|
||||
] */ {
|
||||
s := "";
|
||||
for (synthetic-variable #t1 in list) {
|
||||
s = #t1;
|
||||
if(s.{core::String::isNotEmpty}{core::bool}) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method test(positional-parameter list) → dynamic/* scope=[
|
||||
#ctx1: not-captured VariableContext([
|
||||
positional-parameter list;
|
||||
]),
|
||||
] */ {
|
||||
s := "";
|
||||
for (synthetic-variable #t1 in list) {
|
||||
s = #t1;
|
||||
if(s.{core::String::isNotEmpty}{core::bool}) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
library;
|
||||
import self as self;
|
||||
|
||||
static method test(positional-parameter list) → dynamic
|
||||
;
|
||||
+1
@@ -0,0 +1 @@
|
||||
test(List<String> list) {}
|
||||
+1
@@ -0,0 +1 @@
|
||||
test(List<String> list) {}
|
||||
@@ -30,3 +30,4 @@ closure_context_lowering/foo48: Crash
|
||||
closure_context_lowering/assert_captured_variables: Crash
|
||||
closure_context_lowering/late_variable_initializers: Crash
|
||||
closure_context_lowering/catch_variables: Crash
|
||||
closure_context_lowering/synthetic_variables: Crash
|
||||
|
||||
@@ -27,3 +27,4 @@ closure_context_lowering/foo45: ExpectationFileMismatchSerialized
|
||||
closure_context_lowering/foo48: ExpectationFileMismatchSerialized
|
||||
closure_context_lowering/assert_captured_variables: ExpectationFileMismatchSerialized
|
||||
closure_context_lowering/late_variable_initializers: ExpectationFileMismatchSerialized
|
||||
closure_context_lowering/synthetic_variables: ExpectationFileMismatchSerialized
|
||||
|
||||
@@ -268,3 +268,4 @@ closure_context_lowering/foo48: Crash
|
||||
closure_context_lowering/assert_captured_variables: Crash
|
||||
closure_context_lowering/late_variable_initializers: Crash
|
||||
closure_context_lowering/catch_variables: Crash
|
||||
closure_context_lowering/synthetic_variables: Crash
|
||||
|
||||
@@ -1543,9 +1543,7 @@ class SyntheticVariable extends ExpressionVariable {
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isSynthesized {
|
||||
throw new UnsupportedError("${this.runtimeType}");
|
||||
}
|
||||
bool get isSynthesized => true;
|
||||
|
||||
@override
|
||||
void set isSynthesized(bool value) {
|
||||
@@ -1553,9 +1551,7 @@ class SyntheticVariable extends ExpressionVariable {
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isConst {
|
||||
throw new UnsupportedError("${this.runtimeType}");
|
||||
}
|
||||
bool get isConst => false;
|
||||
|
||||
@override
|
||||
void set isConst(bool value) {
|
||||
@@ -1624,7 +1620,7 @@ class SyntheticVariable extends ExpressionVariable {
|
||||
bool get hasIsFinal => true;
|
||||
|
||||
@override
|
||||
bool get hasIsConst => false;
|
||||
bool get hasIsConst => true;
|
||||
|
||||
@override
|
||||
bool get hasIsLate => false;
|
||||
@@ -1633,7 +1629,7 @@ class SyntheticVariable extends ExpressionVariable {
|
||||
bool get hasIsInitializingFormal => false;
|
||||
|
||||
@override
|
||||
bool get hasIsSynthesized => false;
|
||||
bool get hasIsSynthesized => true;
|
||||
|
||||
@override
|
||||
bool get hasIsHoisted => true;
|
||||
|
||||
@@ -138,7 +138,7 @@ String componentToString(Component node) {
|
||||
|
||||
class NameSystem {
|
||||
final Namer<ExpressionVariable> variables =
|
||||
new NormalNamer<VariableDeclaration>('#t');
|
||||
new NormalNamer<ExpressionVariable>('#t');
|
||||
final Namer<Reference> libraries = new NormalNamer<Reference>('#lib');
|
||||
final Namer<TypeParameter> typeParameters =
|
||||
new NormalNamer<TypeParameter>('#T');
|
||||
|
||||
Reference in New Issue
Block a user