[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:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
23a289417d
commit
27ece1a4b6
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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; }''',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user