[cfe][InternalNodes] Add internal nodes for pattern related statements and expressions

This add internal nodes for nodes related to patterns. This prepares for splitting Variable and InternalVariable.

Change-Id: Idd7f2ced9405491fc9690114494e230a9e88e9b2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/509320
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
Johnni Winther
2026-06-08 02:24:59 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 23a289417d
commit 27ece1a4b6
12 changed files with 1642 additions and 666 deletions
+84 -101
View File
@@ -1403,7 +1403,7 @@ class BodyBuilderImpl extends StackListenerImpl
case_.charOffset,
case_.charCount,
);
Pattern pattern = toPattern(pop());
InternalPattern pattern = toPattern(pop());
Expression expression = popForValue();
push(
new Condition(
@@ -1692,7 +1692,7 @@ class BodyBuilderImpl extends StackListenerImpl
"Expected to have scope kind ${LocalScopeKind.switchBlock}, "
"but got ${_localScopes.previous.kind}.",
);
if (value is Pattern) {
if (value is InternalPattern) {
super.push(
new ExpressionOrPatternGuardCase.patternGuard(
caseKeyword.charOffset,
@@ -3221,7 +3221,7 @@ class BodyBuilderImpl extends StackListenerImpl
// [endThenStatement].
assignedVariables.beginNode();
Condition condition = pop() as Condition;
PatternGuard? patternGuard = condition.patternGuard;
InternalPatternGuard? patternGuard = condition.patternGuard;
if (patternGuard != null && patternGuard.guard != null) {
LocalScope thenScope = _localScope.createNestedScope(
kind: LocalScopeKind.statementLocalScope,
@@ -3235,7 +3235,7 @@ class BodyBuilderImpl extends StackListenerImpl
// to enter the scope and declare all of the pattern variables.
if (patternGuard != null) {
createAndEnterLocalScope(kind: LocalScopeKind.ifCaseHead);
InternalPattern pattern = patternGuard.pattern as InternalPattern;
InternalPattern pattern = patternGuard.pattern;
for (InternalVariable variable in pattern.internalDeclaredVariables) {
declareVariable(variable, _localScope);
}
@@ -3281,7 +3281,7 @@ class BodyBuilderImpl extends StackListenerImpl
pop() as AssignedVariablesNodeInfo;
Statement thenPart = popStatement(ifToken);
Condition condition = pop() as Condition;
PatternGuard? patternGuard = condition.patternGuard;
InternalPatternGuard? patternGuard = condition.patternGuard;
Expression expression = condition.expression;
Statement node;
if (patternGuard != null) {
@@ -3753,7 +3753,7 @@ class BodyBuilderImpl extends StackListenerImpl
variables.addAll(_buildForLoopVariableDeclarations(v)!);
}
return variables;
} else if (variableOrExpression is PatternVariableDeclaration) {
} else if (variableOrExpression is InternalPatternVariableDeclaration) {
// Coverage-ignore-block(suite): Not run.
return [];
} else if (variableOrExpression is ParserRecovery) {
@@ -3971,7 +3971,7 @@ class BodyBuilderImpl extends StackListenerImpl
Object? variableOrExpression = pop();
List<VariableDeclaration>? variables;
List<VariableDeclaration>? intermediateVariables;
if (variableOrExpression is PatternVariableDeclaration) {
if (variableOrExpression is InternalPatternVariableDeclaration) {
variables = (pop() as List<InternalVariable>)
.map(intern.createVariableDeclaration)
.toList(); // Internal variables.
@@ -3992,7 +3992,7 @@ class BodyBuilderImpl extends StackListenerImpl
}
if (entry is MapLiteralEntry) {
TreeNode result;
if (variableOrExpression is PatternVariableDeclaration) {
if (variableOrExpression is InternalPatternVariableDeclaration) {
result = intern.createPatternForMapEntry(
offsetForToken(forToken),
patternVariableDeclaration: variableOrExpression,
@@ -4015,7 +4015,7 @@ class BodyBuilderImpl extends StackListenerImpl
push(result);
} else {
TreeNode result;
if (variableOrExpression is PatternVariableDeclaration) {
if (variableOrExpression is InternalPatternVariableDeclaration) {
result = intern.createPatternForElement(
offsetForToken(forToken),
patternVariableDeclaration: variableOrExpression,
@@ -4094,7 +4094,7 @@ class BodyBuilderImpl extends StackListenerImpl
Object? variableOrExpression = pop();
List<VariableDeclaration>? variables;
List<VariableDeclaration>? intermediateVariables;
if (variableOrExpression is PatternVariableDeclaration) {
if (variableOrExpression is InternalPatternVariableDeclaration) {
variables = (pop() as List<InternalVariable>)
.map(intern.createVariableDeclaration)
.toList(); // Internal variables.
@@ -4138,7 +4138,7 @@ class BodyBuilderImpl extends StackListenerImpl
breakTarget.resolveBreaks(labeledStatement, forStatement);
result = labeledStatement;
}
if (variableOrExpression is PatternVariableDeclaration) {
if (variableOrExpression is InternalPatternVariableDeclaration) {
result = intern.createBlock(
fileOffset: result.fileOffset,
fileEndOffset: result.fileOffset,
@@ -7252,7 +7252,7 @@ class BodyBuilderImpl extends StackListenerImpl
assignedVariables.beginNode();
Condition condition = pop() as Condition;
PatternGuard? patternGuard = condition.patternGuard;
InternalPatternGuard? patternGuard = condition.patternGuard;
if (patternGuard != null) {
if (patternGuard.guard != null) {
LocalScope thenScope = _localScope.createNestedScope(
@@ -7262,7 +7262,7 @@ class BodyBuilderImpl extends StackListenerImpl
enterLocalScope(thenScope);
} else {
createAndEnterLocalScope(kind: LocalScopeKind.ifCaseHead);
InternalPattern pattern = patternGuard.pattern as InternalPattern;
InternalPattern pattern = patternGuard.pattern;
for (InternalVariable variable in pattern.internalDeclaredVariables) {
declareVariable(variable, _localScope);
}
@@ -7328,7 +7328,7 @@ class BodyBuilderImpl extends StackListenerImpl
exitLocalScope(expectedScopeKinds: const [LocalScopeKind.ifElement]);
Token ifToken = pop() as Token;
PatternGuard? patternGuard = condition.patternGuard;
InternalPatternGuard? patternGuard = condition.patternGuard;
TreeNode node;
if (entry is MapLiteralEntry) {
if (patternGuard == null) {
@@ -7397,7 +7397,7 @@ class BodyBuilderImpl extends StackListenerImpl
Condition condition = pop() as Condition; // parenthesized expression
Token ifToken = pop() as Token;
PatternGuard? patternGuard = condition.patternGuard;
InternalPatternGuard? patternGuard = condition.patternGuard;
TreeNode node;
if (thenEntry is MapLiteralEntry) {
if (elseEntry is MapLiteralEntry) {
@@ -8961,9 +8961,9 @@ class BodyBuilderImpl extends StackListenerImpl
for (int i = 0; i < expressionOrPatterns.length; i++) {
ExpressionOrPatternGuardCase expressionOrPattern =
expressionOrPatterns[i];
PatternGuard? patternGuard = expressionOrPattern.patternGuard;
InternalPatternGuard? patternGuard = expressionOrPattern.patternGuard;
if (patternGuard != null) {
InternalPattern pattern = patternGuard.pattern as InternalPattern;
InternalPattern pattern = patternGuard.pattern;
if (jointPatternVariables == null) {
jointPatternVariables = [
for (InternalVariable variable
@@ -9257,10 +9257,10 @@ class BodyBuilderImpl extends StackListenerImpl
containsPatterns &&
hasDefaultOrLabels &&
usedNamesOffsets != null) {
PatternGuard? patternGuard =
InternalPatternGuard? patternGuard =
expressionsOrPatternGuards.first.patternGuard;
if (patternGuard != null) {
InternalPattern pattern = patternGuard.pattern as InternalPattern;
InternalPattern pattern = patternGuard.pattern;
for (InternalVariable variable in pattern.internalDeclaredVariables) {
String variableName = variable.cosmeticName!;
if (usedNamesOffsets[variableName] case [int offset, ...]) {
@@ -9280,7 +9280,7 @@ class BodyBuilderImpl extends StackListenerImpl
// Otherwise, we use pattern switch encoding to handle the erroneous case
// of an unsupported use of patterns.
List<int> caseOffsets = [];
List<PatternGuard> patternGuards = <PatternGuard>[];
List<InternalPatternGuard> patternGuards = [];
for (ExpressionOrPatternGuardCase expressionOrPatternGuard
in expressionsOrPatternGuards) {
caseOffsets.add(expressionOrPatternGuard.caseOffset);
@@ -9302,14 +9302,8 @@ class BodyBuilderImpl extends StackListenerImpl
patternGuards,
block,
isDefault: defaultKeyword != null,
hasLabel: labels != null,
jointVariables: [
if (usedJointPatternVariables != null)
// TODO(johnniwinther): Pass the variables directly when we have
// an internal node for pattern switch cases.
for (InternalVariable variable in usedJointPatternVariables)
variable.asVariableDeclaration,
],
labels: labels,
jointVariables: usedJointPatternVariables,
jointVariableFirstUseOffsets: jointVariableFirstUseOffsets,
),
);
@@ -9325,14 +9319,15 @@ class BodyBuilderImpl extends StackListenerImpl
expressionOffsets.add(expression.fileOffset);
}
push(
new SwitchCaseImpl(
caseOffsets,
expressions,
expressionOffsets,
block,
intern.createSwitchStatementCase(
caseOffsets: caseOffsets,
expressions: expressions,
expressionOffsets: expressionOffsets,
body: block,
isDefault: defaultKeyword != null,
hasLabel: labels != null,
)..fileOffset = beginToken.charOffset,
labels: labels,
fileOffset: beginToken.charOffset,
),
);
}
push(labels ?? NullValues.Labels);
@@ -9350,15 +9345,13 @@ class BodyBuilderImpl extends StackListenerImpl
debugEvent("SwitchStatement");
assert(
checkState(switchKeyword, [
/* labelUsers = */ ValueKinds.StatementListOrNullList,
/* cases = */ ValueKinds.SwitchCaseList,
/* containsPatterns */ ValueKinds.Bool,
/* break target = */ ValueKinds.BreakTarget,
/* expression = */ ValueKinds.Condition,
]),
);
List<List<Statement>?> labelUsers = pop() as List<List<Statement>?>;
List<SwitchCase> cases = pop() as List<SwitchCase>;
List<InternalSwitchCase> cases = pop() as List<InternalSwitchCase>;
bool containsPatterns = pop() as bool;
JumpTarget target = exitBreakTarget()!;
exitSwitchScope();
@@ -9374,38 +9367,40 @@ class BodyBuilderImpl extends StackListenerImpl
// If patterns are enabled, we always use the pattern switch encoding.
// Otherwise, we use pattern switch encoding to handle the erroneous case
// of an unsupported use of patterns.
List<PatternSwitchCase> patternSwitchCases =
new List<PatternSwitchCase>.generate(cases.length, (int index) {
SwitchCase switchCase = cases[index];
PatternSwitchCase patternSwitchCase;
if (switchCase is PatternSwitchCase) {
patternSwitchCase = switchCase;
} else {
// Coverage-ignore-block(suite): Not run.
List<PatternGuard> patterns = new List<PatternGuard>.generate(
switchCase.expressions.length,
(int index) {
return intern.createPatternGuard(
switchCase.expressions[index].fileOffset,
intern.createConstantPattern(switchCase.expressions[index]),
);
},
);
patternSwitchCase = intern.createPatternSwitchCase(
switchCase.fileOffset,
(switchCase as SwitchCaseImpl).caseOffsets,
patterns,
switchCase.body,
isDefault: switchCase.isDefault,
hasLabel: switchCase.hasLabel,
jointVariables: [],
jointVariableFirstUseOffsets: null,
);
}
List<Statement>? users = labelUsers[index];
if (users != null) {
patternSwitchCase.labelUsers.addAll(users);
List<InternalPatternSwitchCase> patternSwitchCases =
new List<InternalPatternSwitchCase>.generate(cases.length, (
int index,
) {
InternalSwitchCase switchCase = cases[index];
InternalPatternSwitchCase patternSwitchCase;
switch (switchCase) {
case InternalPatternSwitchCase():
patternSwitchCase = switchCase;
// Coverage-ignore(suite): Not run.
case InternalSwitchStatementCase():
List<InternalPatternGuard> patterns = new List.generate(
switchCase.expressions.length,
(int index) {
return intern.createPatternGuard(
switchCase.expressions[index].fileOffset,
intern.createConstantPattern(
switchCase.expressions[index],
),
);
},
);
patternSwitchCase = intern.createPatternSwitchCase(
switchCase.fileOffset,
switchCase.caseOffsets,
patterns,
switchCase.body,
isDefault: switchCase.isDefault,
labels: switchCase.labels,
jointVariables: [],
jointVariableFirstUseOffsets: null,
);
}
return patternSwitchCase;
});
switchStatement = intern.createPatternSwitchStatement(
@@ -9414,11 +9409,10 @@ class BodyBuilderImpl extends StackListenerImpl
patternSwitchCases,
);
} else {
switchStatement = intern.createSwitchStatement(
expression,
cases,
fileOffset: switchKeyword.charOffset,
);
switchStatement = intern.createSwitchStatement(expression, [
for (InternalSwitchCase case_ in cases)
case_ as InternalSwitchStatementCase,
], fileOffset: switchKeyword.charOffset);
}
Statement result = switchStatement;
// We create a labeled statement enclosing the switch statement if it has
@@ -9486,7 +9480,7 @@ class BodyBuilderImpl extends StackListenerImpl
}
Object? value = pop();
exitLocalScope();
PatternGuard patternGuard = intern.createPatternGuard(
InternalPatternGuard patternGuard = intern.createPatternGuard(
arrow.charOffset,
toPattern(value),
guard,
@@ -9514,12 +9508,12 @@ class BodyBuilderImpl extends StackListenerImpl
repeatedKind(ValueKinds.SwitchExpressionCase, caseCount),
),
);
List<SwitchExpressionCase> cases = new List<SwitchExpressionCase>.filled(
List<InternalSwitchExpressionCase> cases = new List.filled(
caseCount,
dummySwitchExpressionCase,
dummyInternalSwitchExpressionCase,
);
for (int i = caseCount - 1; i >= 0; i--) {
cases[i] = pop() as SwitchExpressionCase;
cases[i] = pop() as InternalSwitchExpressionCase;
}
push(cases);
}
@@ -9534,7 +9528,8 @@ class BodyBuilderImpl extends StackListenerImpl
]),
);
List<SwitchExpressionCase> cases = pop() as List<SwitchExpressionCase>;
List<InternalSwitchExpressionCase> cases =
pop() as List<InternalSwitchExpressionCase>;
Condition condition = pop() as Condition;
assert(
condition.patternGuard == null,
@@ -9568,34 +9563,28 @@ class BodyBuilderImpl extends StackListenerImpl
); // Exit the sentinel scope.
bool containsPatterns = false;
List<SwitchCase> cases = new List<SwitchCase>.filled(
List<InternalSwitchCase> cases = new List.filled(
caseCount,
dummySwitchCase,
growable: true,
);
List<List<Statement>?> caseLabelUsers = new List<List<Statement>?>.filled(
caseCount,
null,
dummyInternalSwitchCase,
growable: true,
);
for (int i = caseCount - 1; i >= 0; i--) {
List<Label>? labels = pop() as List<Label>?;
SwitchCase current = cases[i] = pop() as SwitchCase;
InternalSwitchCase current = cases[i] = pop() as InternalSwitchCase;
if (labels != null) {
for (Label label in labels) {
JumpTarget? target = _switchScope!.lookupLabel(label.name);
if (target != null) {
(caseLabelUsers[i] ??= <Statement>[]).addAll(target.users);
target.resolveGotos(current);
}
}
}
if (current is PatternSwitchCase) {
if (current is InternalPatternSwitchCase) {
containsPatterns = true;
}
}
for (int i = 0; i < caseCount - 1; i++) {
SwitchCase current = cases[i];
InternalSwitchCase current = cases[i];
Block block = current.body as Block;
// [block] is a synthetic block that is added to handle variable
// declarations in the switch case.
@@ -9615,13 +9604,8 @@ class BodyBuilderImpl extends StackListenerImpl
push(containsPatterns);
push(cases);
push(caseLabelUsers);
assert(
checkState(beginToken, [
ValueKinds.StatementListOrNullList,
ValueKinds.SwitchCaseList,
ValueKinds.Bool,
]),
checkState(beginToken, [ValueKinds.SwitchCaseList, ValueKinds.Bool]),
);
}
@@ -9728,10 +9712,9 @@ class BodyBuilderImpl extends StackListenerImpl
}
if (target.isGotoTarget &&
target.functionNestingLevel == functionNestingLevel) {
ContinueSwitchStatement statement = intern
.createContinueSwitchStatement(
fileOffset: continueKeyword.charOffset,
);
Statement statement = intern.createContinueSwitchStatement(
fileOffset: continueKeyword.charOffset,
);
target.addGoto(statement);
push(statement);
return;
@@ -11251,7 +11234,7 @@ class BodyBuilderImpl extends StackListenerImpl
]),
);
Expression expression = popForValue();
Pattern pattern = toPattern(pop());
InternalPattern pattern = toPattern(pop());
push(
intern.createPatternAssignment(equals.charOffset, pattern, expression),
);
@@ -84,11 +84,11 @@ class JumpTarget {
return statements;
}
void resolveGotos(SwitchCase target) {
void resolveGotos(InternalSwitchCase target) {
assert(isGotoTarget);
for (Statement user in users) {
ContinueSwitchStatement continueSwitchStatement =
user as ContinueSwitchStatement;
InternalContinueSwitchStatement continueSwitchStatement =
user as InternalContinueSwitchStatement;
continueSwitchStatement.target = target;
}
users.clear();
@@ -174,7 +174,7 @@ class LabelTarget implements JumpTarget {
@override
// Coverage-ignore(suite): Not run.
void resolveGotos(SwitchCase target) {
void resolveGotos(InternalSwitchCase target) {
unsupported("resolveGotos", charOffset, fileUri);
}
}
@@ -384,7 +384,7 @@ class Label {
class Condition {
final Expression expression;
final PatternGuard? patternGuard;
final InternalPatternGuard? patternGuard;
new(this.expression, [this.patternGuard]);
@@ -403,12 +403,12 @@ final ExpressionOrPatternGuardCase dummyExpressionOrPatternGuardCase =
class ExpressionOrPatternGuardCase {
final int caseOffset;
final Expression? expression;
final PatternGuard? patternGuard;
final InternalPatternGuard? patternGuard;
new expression(this.caseOffset, Expression this.expression)
: patternGuard = null;
new patternGuard(this.caseOffset, PatternGuard this.patternGuard)
new patternGuard(this.caseOffset, InternalPatternGuard this.patternGuard)
: expression = null;
}
+32 -17
View File
@@ -365,7 +365,7 @@ class ForInElement extends ControlFlowElement
class IfCaseElement extends ControlFlowElementImpl
with ControlFlowElementMixin {
Expression expression;
PatternGuard patternGuard;
InternalPatternGuard internalPatternGuard;
Expression then;
Expression? otherwise;
List<Statement> prelude;
@@ -375,16 +375,19 @@ class IfCaseElement extends ControlFlowElementImpl
/// This is set during inference.
DartType? matchedValueType;
/// [PatternGuard] computed after inference of [internalPatternGuard].
late PatternGuard patternGuard;
new({
required this.prelude,
required this.expression,
required this.patternGuard,
required this.internalPatternGuard,
required this.then,
this.otherwise,
}) {
setParents(prelude, this);
expression.parent = this;
patternGuard.parent = this;
internalPatternGuard.parent = this;
then.parent = this;
otherwise?.parent = this;
}
@@ -403,7 +406,7 @@ class IfCaseElement extends ControlFlowElementImpl
printer.write('if (');
printer.writeExpression(expression);
printer.write(' case ');
patternGuard.toTextInternal(printer);
internalPatternGuard.toTextInternal(printer);
printer.write(') ');
printer.writeExpression(then);
if (otherwise != null) {
@@ -437,7 +440,7 @@ class IfCaseElement extends ControlFlowElementImpl
new IfCaseMapEntry(
prelude: prelude,
expression: expression,
patternGuard: patternGuard,
internalPatternGuard: internalPatternGuard,
then: thenEntry,
otherwise: otherwiseEntry,
)
@@ -466,7 +469,7 @@ abstract interface class ForElementBase implements AuxiliaryExpression {
class PatternForElement extends ControlFlowElementImpl
with ControlFlowElementMixin
implements ForElementBase {
PatternVariableDeclaration patternVariableDeclaration;
InternalPatternVariableDeclaration internalPatternVariableDeclaration;
List<VariableDeclaration> intermediateVariables;
// May be empty, but not null.
@@ -482,8 +485,12 @@ class PatternForElement extends ControlFlowElementImpl
@override
Expression body;
/// [PatternVariableDeclaration] computed after inference of
/// [internalPatternVariableDeclaration].
late PatternVariableDeclaration patternVariableDeclaration;
new({
required this.patternVariableDeclaration,
required this.internalPatternVariableDeclaration,
required this.intermediateVariables,
required this.variables,
required this.condition,
@@ -502,7 +509,7 @@ class PatternForElement extends ControlFlowElementImpl
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
patternVariableDeclaration.toTextInternal(printer);
internalPatternVariableDeclaration.toTextInternal(printer);
printer.write('for (');
for (int index = 0; index < variables.length; index++) {
if (index > 0) {
@@ -741,7 +748,7 @@ class ForMapEntry extends TreeNode
class PatternForMapEntry extends TreeNode
with InternalTreeNode, ControlFlowMapEntryMixin
implements ForMapEntryBase, ControlFlowMapEntry {
PatternVariableDeclaration patternVariableDeclaration;
InternalPatternVariableDeclaration internalPatternVariableDeclaration;
List<VariableDeclaration> intermediateVariables;
@override
@@ -756,8 +763,12 @@ class PatternForMapEntry extends TreeNode
@override
MapLiteralEntry body;
/// [PatternVariableDeclaration] computed after inference of
/// [internalPatternVariableDeclaration].
late PatternVariableDeclaration patternVariableDeclaration;
new({
required this.patternVariableDeclaration,
required this.internalPatternVariableDeclaration,
required this.intermediateVariables,
required this.variables,
required this.condition,
@@ -768,7 +779,7 @@ class PatternForMapEntry extends TreeNode
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
patternVariableDeclaration.toTextInternal(printer);
internalPatternVariableDeclaration.toTextInternal(printer);
printer.write('for (');
for (int index = 0; index < variables.length; index++) {
if (index > 0) {
@@ -848,7 +859,7 @@ class IfCaseMapEntry extends TreeNode
with InternalTreeNode, ControlFlowMapEntryMixin
implements ControlFlowMapEntry {
Expression expression;
PatternGuard patternGuard;
InternalPatternGuard internalPatternGuard;
MapLiteralEntry then;
MapLiteralEntry? otherwise;
List<Statement> prelude;
@@ -858,15 +869,18 @@ class IfCaseMapEntry extends TreeNode
/// This is set during inference.
DartType? matchedValueType;
/// [PatternGuard] computed after inference of [internalPatternGuard].
late PatternGuard patternGuard;
new({
required this.prelude,
required this.expression,
required this.patternGuard,
required this.internalPatternGuard,
required this.then,
this.otherwise,
}) {
expression.parent = this;
patternGuard.parent = this;
internalPatternGuard.parent = this;
then.parent = this;
otherwise?.parent = this;
}
@@ -877,7 +891,7 @@ class IfCaseMapEntry extends TreeNode
printer.write('if (');
expression.toTextInternal(printer);
printer.write(' case ');
patternGuard.toTextInternal(printer);
internalPatternGuard.toTextInternal(printer);
printer.write(') ');
then.toTextInternal(printer);
if (otherwise != null) {
@@ -978,7 +992,7 @@ MapLiteralEntry convertToMapEntry(
new IfCaseMapEntry(
prelude: [],
expression: element.expression,
patternGuard: element.patternGuard,
internalPatternGuard: element.internalPatternGuard,
then: convertToMapEntry(
element.then,
problemReporting,
@@ -1003,7 +1017,8 @@ MapLiteralEntry convertToMapEntry(
case PatternForElement():
PatternForMapEntry result = new PatternForMapEntry(
patternVariableDeclaration: element.patternVariableDeclaration,
internalPatternVariableDeclaration:
element.internalPatternVariableDeclaration,
intermediateVariables: element.intermediateVariables,
variables: element.variables,
condition: element.condition,
@@ -998,9 +998,9 @@ class ConstantsTransformer extends RemovingTransformer {
);
}
SwitchCase switchCase = extern.createSwitchCase(
expressions,
expressionOffsets,
patternSwitchCase.body,
expressions: expressions,
expressionOffsets: expressionOffsets,
body: patternSwitchCase.body,
isDefault: patternSwitchCase.isDefault,
fileOffset: patternSwitchCase.fileOffset,
);
@@ -1011,8 +1011,8 @@ class ConstantsTransformer extends RemovingTransformer {
}
replacement = extern.createSwitchStatement(
node.expression,
switchCases,
expression: node.expression,
cases: switchCases,
isExplicitlyExhaustive: !hasDefault && isAlwaysExhaustiveType,
expressionType: scrutineeType,
fileOffset: node.fileOffset,
@@ -1274,15 +1274,15 @@ class ConstantsTransformer extends RemovingTransformer {
], fileOffset: switchCase.fileOffset);
SwitchCase replacementCase = extern.createSwitchCase(
[
expressions: [
extern.createIntLiteral(
typeEnvironment.coreTypes,
continueTargetIndex,
fileOffset: node.fileOffset,
),
],
[node.fileOffset],
extern.createBlock([
expressionOffsets: [node.fileOffset],
body: extern.createBlock([
for (Variable jointVariable in switchCase.jointVariables)
extern.createVariableStatement(
extern.createVariableDeclaration(jointVariable),
@@ -1408,8 +1408,10 @@ class ConstantsTransformer extends RemovingTransformer {
extern.createVariableStatement(declaredVariableHelper),
innerLabeledStatement,
extern.createSwitchStatement(
extern.createVariableGet(matchResultVariableDeclaration.variable),
replacementCases,
expression: extern.createVariableGet(
matchResultVariableDeclaration.variable,
),
cases: replacementCases,
isExplicitlyExhaustive: false,
expressionType: scrutineeType,
fileOffset: node.fileOffset,
@@ -2047,9 +2049,9 @@ class ConstantsTransformer extends RemovingTransformer {
);
SwitchCase switchCase = extern.createSwitchCase(
expressions,
expressionOffsets,
extern.createBlock([
expressions: expressions,
expressionOffsets: expressionOffsets,
body: extern.createBlock([
extern.createExpressionStatement(
extern.createVariableSet(
valueVariableDeclaration.variable,
@@ -2069,8 +2071,8 @@ class ConstantsTransformer extends RemovingTransformer {
}
labeledStatement.body = extern.createSwitchStatement(
node.expression,
switchCases,
expression: node.expression,
cases: switchCases,
isExplicitlyExhaustive: true,
expressionType: scrutineeType,
fileOffset: node.fileOffset,
@@ -379,6 +379,19 @@ FunctionNode createFunctionNode(
..fileEndOffset = fileEndOffset ?? fileOffset;
}
IfCaseStatement createIfCaseStatement({
required Expression expression,
required PatternGuard patternGuard,
required Statement then,
required Statement? otherwise,
required DartType matchedValueType,
required int fileOffset,
}) {
return new IfCaseStatement(expression, patternGuard, then, otherwise)
..matchedValueType = matchedValueType
..fileOffset = fileOffset;
}
/// Creates an if statement with the [condition], [then] branch and [otherwise]
/// as the optional else branch.
IfStatement createIfStatement(
@@ -883,6 +896,77 @@ Variable createParameterVariable(
..isCovariantByClass = isCovariantByClass;
}
PatternAssignment createPatternAssignment({
required Pattern pattern,
required Expression expression,
required DartType matchedValueType,
required int fileOffset,
}) {
return new PatternAssignment(pattern, expression)
..matchedValueType = matchedValueType
..fileOffset = fileOffset;
}
PatternGuard createPatternGuard({
required Pattern pattern,
required Expression? guard,
required int fileOffset,
}) {
return new PatternGuard(pattern, guard)..fileOffset = fileOffset;
}
ContinueSwitchStatement createContinueSwitchStatement({
required int fileOffset,
}) {
return new ContinueSwitchStatement(dummySwitchCase)..fileOffset = fileOffset;
}
PatternSwitchCase createPatternSwitchCase({
required List<int> caseOffsets,
required List<PatternGuard> patternGuards,
required Statement body,
required bool isDefault,
required bool hasLabel,
required List<Variable> jointVariables,
required List<int>? jointVariableFirstUseOffsets,
required int fileOffset,
}) {
return new PatternSwitchCase(
caseOffsets,
patternGuards,
body,
isDefault: isDefault,
hasLabel: hasLabel,
jointVariables: jointVariables,
jointVariableFirstUseOffsets: jointVariableFirstUseOffsets,
)..fileOffset = fileOffset;
}
PatternSwitchStatement createPatternSwitchStatement({
required Expression expression,
required List<PatternSwitchCase> cases,
required DartType expressionType,
required bool lastCaseTerminates,
required int fileOffset,
}) {
return new PatternSwitchStatement(expression, cases)
..expressionType = expressionType
..lastCaseTerminates = lastCaseTerminates
..fileOffset = fileOffset;
}
PatternVariableDeclaration createPatternVariableDeclaration({
required Pattern pattern,
required Expression initializer,
required bool isFinal,
required DartType matchedValueType,
required int fileOffset,
}) {
return new PatternVariableDeclaration(pattern, initializer, isFinal: isFinal)
..matchedValueType = matchedValueType
..fileOffset = fileOffset;
}
PositionalParameter createPositionalParameter({
String? cosmeticName,
required DartType type,
@@ -1075,10 +1159,10 @@ SuperPropertySet createSuperPropertySet(
/// Creates a switch case for the case [expressions] and their corresponding
/// file offsets in [expressionOffsets] with the given [body].
SwitchCase createSwitchCase(
List<Expression> expressions,
List<int> expressionOffsets,
Statement body, {
SwitchCase createSwitchCase({
required List<Expression> expressions,
required List<int> expressionOffsets,
required Statement body,
required bool isDefault,
required int fileOffset,
}) {
@@ -1090,17 +1174,39 @@ SwitchCase createSwitchCase(
)..fileOffset = fileOffset;
}
SwitchExpression createSwitchExpression({
required Expression expression,
required List<SwitchExpressionCase> cases,
required DartType expressionType,
required DartType staticType,
required int fileOffset,
}) {
return new SwitchExpression(expression, cases)
..expressionType = expressionType
..staticType = staticType
..fileOffset = fileOffset;
}
SwitchExpressionCase createSwitchExpressionCase({
required PatternGuard patternGuard,
required Expression expression,
required int fileOffset,
}) {
return new SwitchExpressionCase(patternGuard, expression)
..fileOffset = fileOffset;
}
/// Create a switch statement on the [expression] with the given [cases]. If
/// the switch is known to be exhaustive and without a default case,
/// [isExplicitlyExhaustive] should be set to `true`.
///
/// The [expressionType] is the static type of the switch expression.
SwitchStatement createSwitchStatement(
Expression expression,
List<SwitchCase> cases, {
SwitchStatement createSwitchStatement({
required Expression expression,
required List<SwitchCase> cases,
required bool isExplicitlyExhaustive,
required int fileOffset,
required DartType expressionType,
required int fileOffset,
}) {
return new SwitchStatement(
expression,
+627 -17
View File
@@ -35,6 +35,7 @@ import '../type_inference/inference_results.dart';
import '../type_inference/inference_visitor.dart';
import '../type_inference/inference_visitor_base.dart';
import '../type_inference/type_schema.dart';
import 'body_builder.dart';
import 'external_ast_helper.dart' as extern;
/// @docImport 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
@@ -142,22 +143,182 @@ class TryStatement extends InternalStatement {
}
}
class SwitchCaseImpl extends SwitchCase {
final List<int> caseOffsets;
final bool hasLabel;
sealed class InternalSwitchCase extends TreeNode with InternalTreeNode {
List<Label>? get labels;
Statement get body;
new(
this.caseOffsets,
List<Expression> expressions,
List<int> expressionOffsets,
Statement body, {
bool isDefault = false,
required this.hasLabel,
}) : super(expressions, expressionOffsets, body, isDefault: isDefault);
bool get hasLabel => labels != null;
List<ContinueSwitchStatement>? _continueStatements;
SwitchCase? _node;
void _connectContinueToCase(
ContinueSwitchStatement continueStatement,
SwitchCase switchCase,
) {
continueStatement.target = switchCase;
if (switchCase is PatternSwitchCase) {
switchCase.labelUsers.add(continueStatement);
}
}
/// Registers that [statement] targets this switch case.
///
/// The ensures that continue statements and switch cases are connected
/// correctly in the external AST.
void registerContinueSwitchStatement(ContinueSwitchStatement statement) {
(_continueStatements ??= [])..add(statement);
SwitchCase? node = _node;
if (node != null) {
_connectContinueToCase(statement, node);
}
}
/// Registers that [node] corresponds to this switch case.
///
/// The ensures that continue statements and switch cases are connected
/// correctly in the external AST.
void registerSwitchCase(SwitchCase node) {
assert(_node == null, "SwitchCase already created for $this.");
_node = node;
List<ContinueSwitchStatement>? continueStatements = _continueStatements;
if (continueStatements != null) {
for (ContinueSwitchStatement continueStatement in continueStatements) {
_connectContinueToCase(continueStatement, node);
}
}
}
}
class InternalSwitchStatementCase extends InternalSwitchCase {
final List<Expression> expressions;
final List<int> expressionOffsets;
@override
final Statement body;
final bool isDefault;
final List<int> caseOffsets;
@override
final List<Label>? labels;
new({
required this.caseOffsets,
required this.expressions,
required this.expressionOffsets,
required this.body,
required this.isDefault,
required this.labels,
required int fileOffset,
}) {
setParents(expressions, this);
body.parent = this;
this.fileOffset = fileOffset;
}
int get caseHeadCount => expressions.length;
@override
// Coverage-ignore(suite): Not run.
R accept<R>(TreeVisitor<R> v) {
unsupported("${runtimeType}.accept on ${v.runtimeType}", -1, null);
}
@override
// Coverage-ignore(suite): Not run.
R accept1<R, A>(TreeVisitor1<R, A> v, A arg) {
unsupported("${runtimeType}.accept1 on ${v.runtimeType}", -1, null);
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
bool needsNewLine = false;
if (labels != null) {
for (Label label in labels!) {
if (needsNewLine) {
printer.newLine();
}
printer.write(label.name);
printer.write(':');
needsNewLine = true;
}
}
for (Expression expression in expressions) {
if (needsNewLine) {
printer.newLine();
}
printer.write('case ');
printer.writeExpression(expression);
printer.write(':');
needsNewLine = true;
}
if (isDefault) {
if (needsNewLine) {
printer.newLine();
}
printer.write('default:');
}
printer.incIndentation();
Statement? block = body;
if (block is Block) {
for (Statement statement in block.statements) {
printer.newLine();
printer.writeStatement(statement);
}
} else {
printer.write(' ');
printer.writeStatement(body);
}
printer.decIndentation();
}
@override
String toString() {
return "SwitchCaseImpl(${toStringInternal()})";
return "$runtimeType(${toStringInternal()})";
}
}
class InternalRegularSwitchStatement extends InternalStatement
implements InternalSwitchStatement {
final Expression expression;
@override
final List<InternalSwitchStatementCase> cases;
new({
required this.expression,
required this.cases,
required int fileOffset,
}) {
expression.parent = this;
setParents(cases, this);
this.fileOffset = fileOffset;
}
@override
StatementInferenceResult acceptInference(InferenceVisitorImpl visitor) {
return visitor.visitInternalRegularSwitchStatement(this);
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('switch (');
printer.writeExpression(expression);
printer.write(') {');
printer.incIndentation();
for (InternalSwitchStatementCase switchCase in cases) {
printer.newLine();
switchCase.toTextInternal(printer);
}
printer.decIndentation();
printer.newLine();
printer.write('}');
}
@override
String toString() {
return "$runtimeType(${toStringInternal()})";
}
}
@@ -7129,11 +7290,6 @@ class InternalListPattern extends InternalPattern {
}
}
final InternalPattern dummyInternalPattern = new InternalConstantPattern(
expression: dummyExpression,
fileOffset: TreeNode.noOffset,
);
class InternalMapPattern extends InternalPattern {
/// The key type arguments as specific in the map pattern syntax.
DartType? keyType;
@@ -7642,3 +7798,457 @@ class InternalWildcardPattern extends InternalPattern {
return "$runtimeType(${toStringInternal()})";
}
}
/// A [InternalPattern] with an optional guard [Expression].
class InternalPatternGuard extends TreeNode with InternalTreeNode {
final InternalPattern pattern;
final Expression? guard;
new({required this.pattern, required this.guard, required int fileOffset}) {
pattern.parent = this;
guard?.parent = this;
this.fileOffset = fileOffset;
}
@override
// Coverage-ignore(suite): Not run.
R accept<R>(TreeVisitor<R> v) {
unsupported("${runtimeType}.accept on ${v.runtimeType}", -1, null);
}
@override
// Coverage-ignore(suite): Not run.
R accept1<R, A>(TreeVisitor1<R, A> v, A arg) {
unsupported("${runtimeType}.accept on ${v.runtimeType}", -1, null);
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
pattern.toTextInternal(printer);
if (guard != null) {
printer.write(' when ');
printer.writeExpression(guard!);
}
}
@override
String toString() => '$runtimeType(${toStringInternal()})';
}
class InternalPatternSwitchCase extends InternalSwitchCase {
final List<int> caseOffsets;
final List<InternalPatternGuard> patternGuards;
@override
final Statement body;
final bool isDefault;
@override
final List<Label>? labels;
final List<InternalVariable> jointVariables;
final List<int>? jointVariableFirstUseOffsets;
new({
required this.caseOffsets,
required this.patternGuards,
required this.body,
required this.isDefault,
required this.labels,
required this.jointVariables,
required this.jointVariableFirstUseOffsets,
required int fileOffset,
}) {
setParents(patternGuards, this);
setParents(jointVariables, this);
body.parent = this;
this.fileOffset = fileOffset;
}
int get caseHeadCount => patternGuards.length;
@override
// Coverage-ignore(suite): Not run.
R accept<R>(TreeVisitor<R> v) {
unsupported("${runtimeType}.accept on ${v.runtimeType}", -1, null);
}
@override
// Coverage-ignore(suite): Not run.
R accept1<R, A>(TreeVisitor1<R, A> v, A arg) {
unsupported("${runtimeType}.accept on ${v.runtimeType}", -1, null);
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
bool needsNewLine = false;
if (labels != null) {
for (Label label in labels!) {
if (needsNewLine) {
printer.newLine();
}
printer.write(label.name);
printer.write(':');
needsNewLine = true;
}
}
for (InternalPatternGuard patternGuard in patternGuards) {
if (needsNewLine) {
printer.newLine();
}
printer.write('case ');
patternGuard.toTextInternal(printer);
printer.write(':');
needsNewLine = true;
}
if (isDefault) {
if (needsNewLine) {
printer.newLine();
}
printer.write('default:');
}
printer.incIndentation();
Statement? block = body;
if (block is Block) {
for (Statement statement in block.statements) {
printer.newLine();
printer.writeStatement(statement);
}
} else {
printer.write(' ');
printer.writeStatement(body);
}
printer.decIndentation();
}
@override
String toString() {
return "$runtimeType(${toStringInternal()})";
}
}
class InternalPatternSwitchStatement extends InternalStatement
implements InternalSwitchStatement {
final Expression expression;
@override
final List<InternalPatternSwitchCase> cases;
new({
required this.expression,
required this.cases,
required int fileOffset,
}) {
expression.parent = this;
setParents(cases, this);
this.fileOffset = fileOffset;
}
@override
StatementInferenceResult acceptInference(InferenceVisitorImpl visitor) {
return visitor.visitInternalPatternSwitchStatement(this);
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('switch (');
printer.writeExpression(expression);
printer.write(') {');
printer.incIndentation();
for (InternalPatternSwitchCase switchCase in cases) {
printer.newLine();
switchCase.toTextInternal(printer);
}
printer.decIndentation();
printer.newLine();
printer.write('}');
}
@override
String toString() {
return "$runtimeType(${toStringInternal()})";
}
}
sealed class InternalSwitch implements TreeNode {}
sealed class InternalSwitchStatement
implements InternalSwitch, InternalStatement {
List<InternalSwitchCase> get cases;
}
class InternalSwitchExpressionCase extends TreeNode with InternalTreeNode {
final InternalPatternGuard patternGuard;
final Expression expression;
new({
required this.patternGuard,
required this.expression,
required int fileOffset,
}) {
patternGuard.parent = this;
expression.parent = this;
this.fileOffset = fileOffset;
}
@override
// Coverage-ignore(suite): Not run.
R accept<R>(TreeVisitor<R> v) {
unsupported("${runtimeType}.accept on ${v.runtimeType}", -1, null);
}
@override
// Coverage-ignore(suite): Not run.
R accept1<R, A>(TreeVisitor1<R, A> v, A arg) {
unsupported("${runtimeType}.accept on ${v.runtimeType}", -1, null);
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('case ');
patternGuard.toTextInternal(printer);
printer.write(' => ');
printer.writeExpression(expression);
}
@override
String toString() {
return '$runtimeType(${toStringInternal()})';
}
}
class InternalSwitchExpression extends InternalExpression
implements InternalSwitch {
final Expression expression;
final List<InternalSwitchExpressionCase> cases;
new({
required this.expression,
required this.cases,
required int fileOffset,
}) {
expression.parent = this;
setParents(cases, this);
this.fileOffset = fileOffset;
}
@override
ExpressionInferenceResult acceptInference(
InferenceVisitorImpl visitor,
DartType typeContext,
) {
return visitor.visitInternalSwitchExpression(this, typeContext);
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('switch (');
printer.writeExpression(expression);
printer.write(') {');
String comma = ' ';
for (InternalSwitchExpressionCase switchCase in cases) {
printer.write(comma);
switchCase.toTextInternal(printer);
comma = ', ';
}
printer.write(' }');
}
@override
String toString() => '$runtimeType(${toStringInternal()})';
}
class InternalPatternVariableDeclaration extends InternalStatement {
final InternalPattern pattern;
final Expression initializer;
final bool isFinal;
new({
required this.pattern,
required this.initializer,
required this.isFinal,
required int fileOffset,
}) {
pattern.parent = this;
initializer.parent = this;
this.fileOffset = fileOffset;
}
@override
StatementInferenceResult acceptInference(InferenceVisitorImpl visitor) {
return visitor.visitInternalPatternVariableDeclaration(this);
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
if (isFinal) {
printer.write('final ');
} else {
printer.write('var ');
}
pattern.toTextInternal(printer);
printer.write(" = ");
printer.writeExpression(initializer);
printer.write(';');
}
@override
String toString() {
return "$runtimeType(${toStringInternal()})";
}
}
class InternalPatternAssignment extends InternalExpression {
final InternalPattern pattern;
final Expression expression;
new({
required this.pattern,
required this.expression,
required int fileOffset,
}) {
pattern.parent = this;
expression.parent = this;
this.fileOffset = fileOffset;
}
@override
ExpressionInferenceResult acceptInference(
InferenceVisitorImpl visitor,
DartType typeContext,
) {
return visitor.visitInternalPatternAssignment(this, typeContext);
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
pattern.toTextInternal(printer);
printer.write(' = ');
printer.writeExpression(expression);
}
@override
String toString() {
return "$runtimeType(${toStringInternal()})";
}
}
/// Statement for a if-case statements:
///
/// if (expression case pattern) then
/// if (expression case pattern) then else otherwise
/// if (expression case pattern when guard) then
/// if (expression case pattern when guard) then else otherwise
///
class InternalIfCaseStatement extends InternalStatement {
final Expression expression;
final InternalPatternGuard patternGuard;
final Statement then;
final Statement? otherwise;
new({
required this.expression,
required this.patternGuard,
required this.then,
required this.otherwise,
required int fileOffset,
}) {
expression.parent = this;
patternGuard.parent = this;
then.parent = this;
otherwise?.parent = this;
this.fileOffset = fileOffset;
}
@override
StatementInferenceResult acceptInference(InferenceVisitorImpl visitor) {
return visitor.visitInternalIfCaseStatement(this);
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('if (');
printer.writeExpression(expression);
printer.write(' case ');
patternGuard.toTextInternal(printer);
printer.write(') ');
printer.writeStatement(then);
if (otherwise != null) {
printer.write(' else ');
printer.writeStatement(otherwise!);
}
}
@override
String toString() {
return "$runtimeType(${toStringInternal()})";
}
}
class InternalContinueSwitchStatement extends InternalStatement {
late InternalSwitchCase target;
new({required int fileOffset}) {
this.fileOffset = fileOffset;
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('continue');
if (target.labels != null) {
printer.write(' ');
printer.write(target.labels!.first.name);
}
printer.write(';');
}
@override
String toString() {
return "$runtimeType(${toStringInternal()})";
}
@override
StatementInferenceResult acceptInference(InferenceVisitorImpl visitor) {
return visitor.visitInternalContinueSwitchStatement(this);
}
}
final InternalPattern dummyInternalPattern = new InternalConstantPattern(
expression: dummyExpression,
fileOffset: TreeNode.noOffset,
);
final InternalPatternGuard dummyInternalPatternGuard = new InternalPatternGuard(
pattern: dummyInternalPattern,
guard: null,
fileOffset: TreeNode.noOffset,
);
final InternalSwitchExpressionCase dummyInternalSwitchExpressionCase =
new InternalSwitchExpressionCase(
patternGuard: dummyInternalPatternGuard,
expression: dummyExpression,
fileOffset: TreeNode.noOffset,
);
final InternalSwitchCase dummyInternalSwitchCase =
new InternalSwitchStatementCase(
caseOffsets: [],
expressions: [],
expressionOffsets: [],
body: dummyStatement,
isDefault: false,
labels: null,
fileOffset: TreeNode.noOffset,
);
@@ -8,6 +8,7 @@ import 'package:kernel/src/printer.dart';
import '../base/problems.dart' show unsupported;
import '../type_inference/type_schema.dart';
import 'body_builder.dart';
import 'collections.dart'
show
ForElement,
@@ -259,10 +260,8 @@ Statement createContinueStatement(int fileOffset, Object? label) {
return new BreakStatementImpl(isContinue: true)..fileOffset = fileOffset;
}
ContinueSwitchStatement createContinueSwitchStatement({
required int fileOffset,
}) {
return new ContinueSwitchStatement(dummySwitchCase)..fileOffset = fileOffset;
Statement createContinueSwitchStatement({required int fileOffset}) {
return new InternalContinueSwitchStatement(fileOffset: fileOffset);
}
/// Return a representation of a do statement.
@@ -484,14 +483,14 @@ Expression createIfCaseElement(
int fileOffset, {
required List<Statement> prelude,
required Expression expression,
required PatternGuard patternGuard,
required InternalPatternGuard patternGuard,
required Expression then,
Expression? otherwise,
}) {
return new IfCaseElement(
prelude: prelude,
expression: expression,
patternGuard: patternGuard,
internalPatternGuard: patternGuard,
then: then,
otherwise: otherwise,
)..fileOffset = fileOffset;
@@ -501,28 +500,33 @@ MapLiteralEntry createIfCaseMapEntry(
int fileOffset, {
required List<Statement> prelude,
required Expression expression,
required PatternGuard patternGuard,
required InternalPatternGuard patternGuard,
required MapLiteralEntry then,
MapLiteralEntry? otherwise,
}) {
return new IfCaseMapEntry(
prelude: prelude,
expression: expression,
patternGuard: patternGuard,
internalPatternGuard: patternGuard,
then: then,
otherwise: otherwise,
)..fileOffset = fileOffset;
}
IfCaseStatement createIfCaseStatement(
Statement createIfCaseStatement(
int fileOffset,
Expression expression,
PatternGuard patternGuard,
InternalPatternGuard patternGuard,
Statement then,
Statement? otherwise,
) {
return new IfCaseStatement(expression, patternGuard, then, otherwise)
..fileOffset = fileOffset;
return new InternalIfCaseStatement(
expression: expression,
patternGuard: patternGuard,
then: then,
otherwise: otherwise,
fileOffset: fileOffset,
);
}
Expression createIfElement(
@@ -1073,17 +1077,21 @@ ParenthesizedExpression createParenthesized(
return new ParenthesizedExpression(expression)..fileOffset = fileOffset;
}
PatternAssignment createPatternAssignment(
Expression createPatternAssignment(
int fileOffset,
Pattern pattern,
InternalPattern pattern,
Expression expression,
) {
return new PatternAssignment(pattern, expression)..fileOffset = fileOffset;
return new InternalPatternAssignment(
pattern: pattern,
expression: expression,
fileOffset: fileOffset,
);
}
PatternForElement createPatternForElement(
int fileOffset, {
required PatternVariableDeclaration patternVariableDeclaration,
required InternalPatternVariableDeclaration patternVariableDeclaration,
required List<VariableDeclaration> intermediateVariables,
required List<VariableDeclaration> variables,
required Expression? condition,
@@ -1091,7 +1099,7 @@ PatternForElement createPatternForElement(
required Expression body,
}) {
return new PatternForElement(
patternVariableDeclaration: patternVariableDeclaration,
internalPatternVariableDeclaration: patternVariableDeclaration,
intermediateVariables: intermediateVariables,
variables: variables,
condition: condition,
@@ -1102,7 +1110,7 @@ PatternForElement createPatternForElement(
PatternForMapEntry createPatternForMapEntry(
int fileOffset, {
required PatternVariableDeclaration patternVariableDeclaration,
required InternalPatternVariableDeclaration patternVariableDeclaration,
required List<VariableDeclaration> intermediateVariables,
required List<VariableDeclaration> variableInitializations,
required Expression? condition,
@@ -1110,7 +1118,7 @@ PatternForMapEntry createPatternForMapEntry(
required MapLiteralEntry body,
}) {
return new PatternForMapEntry(
patternVariableDeclaration: patternVariableDeclaration,
internalPatternVariableDeclaration: patternVariableDeclaration,
intermediateVariables: intermediateVariables,
variables: variableInitializations,
condition: condition,
@@ -1119,51 +1127,64 @@ PatternForMapEntry createPatternForMapEntry(
)..fileOffset = fileOffset;
}
PatternGuard createPatternGuard(
InternalPatternGuard createPatternGuard(
int fileOffset,
Pattern pattern, [
InternalPattern pattern, [
Expression? guard,
]) {
return new PatternGuard(pattern, guard)..fileOffset = fileOffset;
return new InternalPatternGuard(
pattern: pattern,
guard: guard,
fileOffset: fileOffset,
);
}
PatternSwitchCase createPatternSwitchCase(
InternalPatternSwitchCase createPatternSwitchCase(
int fileOffset,
List<int> caseOffsets,
List<PatternGuard> patternGuards,
List<InternalPatternGuard> patternGuards,
Statement body, {
required bool isDefault,
required bool hasLabel,
required List<Variable> jointVariables,
required List<Label>? labels,
required List<InternalVariable>? jointVariables,
required List<int>? jointVariableFirstUseOffsets,
}) {
return new PatternSwitchCase(
caseOffsets,
patternGuards,
body,
return new InternalPatternSwitchCase(
caseOffsets: caseOffsets,
patternGuards: patternGuards,
body: body,
isDefault: isDefault,
hasLabel: hasLabel,
jointVariables: jointVariables,
labels: labels,
jointVariables: jointVariables ?? [],
jointVariableFirstUseOffsets: jointVariableFirstUseOffsets,
)..fileOffset = fileOffset;
fileOffset: fileOffset,
);
}
PatternSwitchStatement createPatternSwitchStatement(
Statement createPatternSwitchStatement(
int fileOffset,
Expression expression,
List<PatternSwitchCase> cases,
List<InternalPatternSwitchCase> cases,
) {
return new PatternSwitchStatement(expression, cases)..fileOffset = fileOffset;
return new InternalPatternSwitchStatement(
expression: expression,
cases: cases,
fileOffset: fileOffset,
);
}
PatternVariableDeclaration createPatternVariableDeclaration(
Statement createPatternVariableDeclaration(
int fileOffset,
Pattern pattern,
InternalPattern pattern,
Expression initializer, {
required bool isFinal,
}) {
return new PatternVariableDeclaration(pattern, initializer, isFinal: isFinal)
..fileOffset = fileOffset;
return new InternalPatternVariableDeclaration(
pattern: pattern,
initializer: initializer,
isFinal: isFinal,
fileOffset: fileOffset,
);
}
InternalVariable createPositionalParameter({
@@ -1409,29 +1430,60 @@ SuperPropertySet createSuperPropertySet(
..fileOffset = fileOffset;
}
SwitchExpression createSwitchExpression(
Expression createSwitchExpression(
int fileOffset,
Expression expression,
List<SwitchExpressionCase> cases,
List<InternalSwitchExpressionCase> cases,
) {
return new SwitchExpression(expression, cases)..fileOffset = fileOffset;
return new InternalSwitchExpression(
expression: expression,
cases: cases,
fileOffset: fileOffset,
);
}
SwitchExpressionCase createSwitchExpressionCase(
InternalSwitchExpressionCase createSwitchExpressionCase(
int fileOffset,
PatternGuard patternGuard,
InternalPatternGuard patternGuard,
Expression expression,
) {
return new SwitchExpressionCase(patternGuard, expression)
..fileOffset = fileOffset;
return new InternalSwitchExpressionCase(
patternGuard: patternGuard,
expression: expression,
fileOffset: fileOffset,
);
}
SwitchStatement createSwitchStatement(
Statement createSwitchStatement(
Expression expression,
List<SwitchCase> cases, {
List<InternalSwitchStatementCase> cases, {
required int fileOffset,
}) {
return new SwitchStatement(expression, cases)..fileOffset = fileOffset;
return new InternalRegularSwitchStatement(
expression: expression,
cases: cases,
fileOffset: fileOffset,
);
}
InternalSwitchStatementCase createSwitchStatementCase({
required List<Expression> expressions,
required List<int> expressionOffsets,
required Statement body,
required bool isDefault,
required List<int> caseOffsets,
required List<Label>? labels,
required int fileOffset,
}) {
return new InternalSwitchStatementCase(
caseOffsets: caseOffsets,
expressions: expressions,
expressionOffsets: expressionOffsets,
body: body,
isDefault: isDefault,
labels: labels,
fileOffset: fileOffset,
);
}
/// Return a representation of a symbol literal defined by [value] at the
@@ -201,13 +201,14 @@ class ValueKinds {
NullValues.RecordTypeFieldList,
);
static const ValueKind Selector = const SingleValueKind<type.Selector>();
static const ValueKind SwitchCase = const SingleValueKind<type.SwitchCase>();
static const ValueKind SwitchCase =
const SingleValueKind<type.InternalSwitchCase>();
static const ValueKind SwitchCaseList =
const SingleValueKind<List<type.SwitchCase>>();
const SingleValueKind<List<type.InternalSwitchCase>>();
static const ValueKind SwitchExpressionCase =
const SingleValueKind<type.SwitchExpressionCase>();
const SingleValueKind<type.InternalSwitchExpressionCase>();
static const ValueKind SwitchExpressionCaseList =
const SingleValueKind<List<type.SwitchExpressionCase>>();
const SingleValueKind<List<type.InternalSwitchExpressionCase>>();
static const ValueKind Statement = const SingleValueKind<type.Statement>();
static const ValueKind StatementOrNull =
const SingleValueKind<type.Statement>(NullValues.Block);
File diff suppressed because it is too large Load Diff
@@ -299,7 +299,7 @@ class SharedTypeAnalyzerErrors
@override
InvalidExpression switchCaseCompletesNormally({
required covariant SwitchStatement node,
required covariant InternalSwitchStatement node,
required int caseIndex,
}) {
return problemReporting.buildProblem(
@@ -30,10 +30,16 @@ class ValueKinds {
const SingleValueKind<type.Pattern>();
static const SingleValueKind<type.Pattern> PatternOrNull =
const SingleValueKind<type.Pattern>(NullValues.Pattern);
static const SingleValueKind<type.PatternGuard> PatternGuard =
const SingleValueKind<type.PatternGuard>();
static const SingleValueKind<type.PatternSwitchCase> PatternSwitchCase =
const SingleValueKind<type.PatternSwitchCase>();
static const SingleValueKind<type.Statement> Statement =
const SingleValueKind<type.Statement>();
static const SingleValueKind<type.Statement> StatementOrNull =
const SingleValueKind<type.Statement>(NullValues.Statement);
static const SingleValueKind<type.SwitchCase> SwitchCase =
const SingleValueKind<type.SwitchCase>();
static const SingleValueKind<type.SwitchExpressionCase> SwitchExpressionCase =
const SingleValueKind<type.SwitchExpressionCase>();
}
@@ -13,6 +13,7 @@ import 'package:front_end/src/dill/dill_library_builder.dart';
import 'package:front_end/src/dill/dill_loader.dart';
import 'package:front_end/src/dill/dill_target.dart';
import 'package:front_end/src/dill/dill_type_alias_builder.dart';
import 'package:front_end/src/kernel/body_builder.dart';
import 'package:front_end/src/kernel/collections.dart';
import 'package:front_end/src/kernel/internal_ast.dart';
import 'package:front_end/src/kernel/internal_ast_helper.dart' as forest;
@@ -600,9 +601,21 @@ void _testSwitchCaseImpl() {
Block returnBlock2 = new Block([new ReturnStatement()]);
testStatement(
new SwitchStatement(expression, [
new SwitchCaseImpl([0], [case0], [0], emptyBlock, hasLabel: false),
]),
new InternalRegularSwitchStatement(
expression: expression,
cases: [
new InternalSwitchStatementCase(
caseOffsets: [0],
expressions: [case0],
expressionOffsets: [0],
body: emptyBlock,
isDefault: false,
labels: null,
fileOffset: TreeNode.noOffset,
),
],
fileOffset: TreeNode.noOffset,
),
'''
switch (null) {
case 0:
@@ -612,16 +625,21 @@ switch (null) { case 0: }''',
);
testStatement(
new SwitchStatement(expression, [
new SwitchCaseImpl(
[],
[],
[0],
emptyBlock,
hasLabel: false,
isDefault: true,
),
]),
new InternalRegularSwitchStatement(
expression: expression,
cases: [
new InternalSwitchStatementCase(
caseOffsets: [],
expressions: [],
expressionOffsets: [0],
body: emptyBlock,
labels: null,
isDefault: true,
fileOffset: TreeNode.noOffset,
),
],
fileOffset: TreeNode.noOffset,
),
'''
switch (null) {
default:
@@ -631,34 +649,42 @@ switch (null) { default: }''',
);
testStatement(
new SwitchStatement(expression, [
new SwitchCaseImpl(
[0, 1],
[case0, case1],
[0, 1],
returnBlock1,
hasLabel: false,
),
new SwitchCaseImpl(
[0],
[case2],
[0],
returnBlock2,
hasLabel: true,
isDefault: true,
),
]),
new InternalRegularSwitchStatement(
expression: expression,
cases: [
new InternalSwitchStatementCase(
caseOffsets: [0, 1],
expressions: [case0, case1],
expressionOffsets: [0, 1],
body: returnBlock1,
isDefault: false,
labels: null,
fileOffset: TreeNode.noOffset,
),
new InternalSwitchStatementCase(
caseOffsets: [0],
expressions: [case2],
expressionOffsets: [0],
body: returnBlock2,
isDefault: true,
labels: [new Label('foo', TreeNode.noOffset)],
fileOffset: TreeNode.noOffset,
),
],
fileOffset: TreeNode.noOffset,
),
'''
switch (null) {
case 0:
case 1:
return;
foo:
case 2:
default:
return;
}''',
limited: '''
switch (null) { case 0: case 1: return; case 2: default: return; }''',
switch (null) { case 0: case 1: return; foo: case 2: default: return; }''',
);
}