mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 08:24:39 +00:00
Shared type analysis for patterns: clean up switch data structures.
- `CaseHeadInfo` is renamed to `CaseHeadOrDefaultInfo`, to reflect the fact that it is used for both case heads and default clauses. - `CaseHeadOrDefaultInfo.node` is no longer needed; this used to be used for error reporting, but after the refactor of https://dart-review.googlesource.com/c/sdk/+/259021 is was no longer used. - `ExpressionCaseInfo` is renamed to `SwitchExpressionMemberInfo`, consistent with the AST structure `SwitchExpressionMember` in the analyzer. - `SwitchExpressionMemberInfo.body` is renamed to `SwitchExpressionMemberInfo.expression`, consistent with the nomenclature used in the analyzer. - `StatementCaseInfo` is renamed to `SwitchStatementMemberInfo` for consistency with `SwitchExpressionMemberInfo`. Note that the analyzer calls its corresponding AST structure `SwitchMember` rather than `SwitchStatementMember` for legacy reasons. - `SwitchExpressionMemberInfo` no longer extends `CaseHeadOrDefaultInfo`; it contains a pointer to the head or default info. This is more consistent with `SwitchStatementMemberInfo`. Change-Id: I727766a6f0601ec5cd8aff824364319a54446bd2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/259880 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
This commit is contained in:
parent
83ab5d5ca3
commit
84b71e55d4
|
@ -7,15 +7,11 @@ import 'type_analysis_result.dart';
|
|||
import 'type_operations.dart';
|
||||
|
||||
/// Information supplied by the client to [TypeAnalyzer.analyzeSwitchExpression]
|
||||
/// or [TypeAnalyzer.analyzeSwitchStatement] about a single case head.
|
||||
/// or [TypeAnalyzer.analyzeSwitchStatement] about a single case head or
|
||||
/// `default` clause.
|
||||
///
|
||||
/// The client is free to `implement` or `extend` this class.
|
||||
class CaseHeadInfo<Node extends Object, Expression extends Node> {
|
||||
/// The AST node for this `case` or `default` clause. This is used for error
|
||||
/// reporting, in case errors arise from mismatch among the variables bound by
|
||||
/// various cases that share a body.
|
||||
final Node node;
|
||||
|
||||
class CaseHeadOrDefaultInfo<Node extends Object, Expression extends Node> {
|
||||
/// For a `case` clause, the case pattern. For a `default` clause, `null`.
|
||||
final Node? pattern;
|
||||
|
||||
|
@ -23,36 +19,34 @@ class CaseHeadInfo<Node extends Object, Expression extends Node> {
|
|||
/// `when`. Otherwise `null`.
|
||||
final Expression? guard;
|
||||
|
||||
CaseHeadInfo({required this.node, required this.pattern, this.guard});
|
||||
CaseHeadOrDefaultInfo({required this.pattern, this.guard});
|
||||
}
|
||||
|
||||
/// Information supplied by the client to [TypeAnalyzer.analyzeSwitchExpression]
|
||||
/// about an individual `case` or `default` clause.
|
||||
///
|
||||
/// The client is free to `implement` or `extend` this class.
|
||||
class ExpressionCaseInfo<Node extends Object, Expression extends Node>
|
||||
extends CaseHeadInfo<Node, Expression> {
|
||||
/// The body of the `case` or `default` clause.
|
||||
final Expression body;
|
||||
class SwitchExpressionMemberInfo<Node extends Object, Expression extends Node> {
|
||||
/// The [CaseOrDefaultHead] associated with this clause.
|
||||
final CaseHeadOrDefaultInfo<Node, Expression> head;
|
||||
|
||||
ExpressionCaseInfo(
|
||||
{required super.node,
|
||||
required super.pattern,
|
||||
super.guard,
|
||||
required this.body});
|
||||
/// The body of the `case` or `default` clause.
|
||||
final Expression expression;
|
||||
|
||||
SwitchExpressionMemberInfo({required this.head, required this.expression});
|
||||
}
|
||||
|
||||
/// Information supplied by the client to [TypeAnalyzer.analyzeSwitchStatement]
|
||||
/// about an individual `case` or `default` clause.
|
||||
///
|
||||
/// The client is free to `implement` or `extend` this class.
|
||||
class StatementCaseInfo<Node extends Object, Statement extends Node,
|
||||
class SwitchStatementMemberInfo<Node extends Object, Statement extends Node,
|
||||
Expression extends Node> {
|
||||
/// The list of case heads for this case.
|
||||
///
|
||||
/// The reason this is a list rather than a single head is because the front
|
||||
/// end merges together cases that share a body at parse time.
|
||||
final List<CaseHeadInfo<Node, Expression>> heads;
|
||||
final List<CaseHeadOrDefaultInfo<Node, Expression>> heads;
|
||||
|
||||
/// The labels preceding this `case` or `default` clause, if any.
|
||||
final List<Node> labels;
|
||||
|
@ -63,7 +57,7 @@ class StatementCaseInfo<Node extends Object, Statement extends Node,
|
|||
/// that follows.
|
||||
final List<Statement> body;
|
||||
|
||||
StatementCaseInfo(this.heads, this.body, {this.labels = const []});
|
||||
SwitchStatementMemberInfo(this.heads, this.body, {this.labels = const []});
|
||||
}
|
||||
|
||||
/// Type analysis logic to be shared between the analyzer and front end. The
|
||||
|
@ -320,11 +314,11 @@ mixin TypeAnalyzer<Node extends Object, Statement extends Node,
|
|||
Type? lubType;
|
||||
for (int i = 0; i < numCases; i++) {
|
||||
// Stack: (Expression, i * ExpressionCase)
|
||||
ExpressionCaseInfo<Node, Expression> caseInfo =
|
||||
getExpressionCaseInfo(node, i);
|
||||
SwitchExpressionMemberInfo<Node, Expression> memberInfo =
|
||||
getSwitchExpressionMemberInfo(node, i);
|
||||
flow?.switchStatement_beginCase();
|
||||
Map<Variable, VariableTypeInfo<Node, Type>> typeInfos = {};
|
||||
Node? pattern = caseInfo.pattern;
|
||||
Node? pattern = memberInfo.head.pattern;
|
||||
if (pattern != null) {
|
||||
dispatchPattern(pattern).match(
|
||||
expressionType,
|
||||
|
@ -334,7 +328,7 @@ mixin TypeAnalyzer<Node extends Object, Statement extends Node,
|
|||
switchScrutinee: scrutinee,
|
||||
topPattern: pattern));
|
||||
// Stack: (Expression, i * ExpressionCase, Pattern)
|
||||
Expression? guard = caseInfo.guard;
|
||||
Expression? guard = memberInfo.head.guard;
|
||||
bool hasGuard = guard != null;
|
||||
if (hasGuard) {
|
||||
_checkGuardType(guard, analyzeExpression(guard, boolType));
|
||||
|
@ -349,7 +343,7 @@ mixin TypeAnalyzer<Node extends Object, Statement extends Node,
|
|||
handleDefault(node, i);
|
||||
}
|
||||
// Stack: (Expression, i * ExpressionCase, CaseHead)
|
||||
Type type = analyzeExpression(caseInfo.body, context);
|
||||
Type type = analyzeExpression(memberInfo.expression, context);
|
||||
// Stack: (Expression, i * ExpressionCase, CaseHead, Expression)
|
||||
if (lubType == null) {
|
||||
lubType = type;
|
||||
|
@ -391,14 +385,14 @@ mixin TypeAnalyzer<Node extends Object, Statement extends Node,
|
|||
while (i < numCases) {
|
||||
// Stack: (Expression, numExecutionPaths * StatementCase,
|
||||
// numHeads * CaseHead)
|
||||
StatementCaseInfo<Node, Statement, Expression> caseInfo =
|
||||
getStatementCaseInfo(node, i);
|
||||
if (caseInfo.labels.isNotEmpty) {
|
||||
SwitchStatementMemberInfo<Node, Statement, Expression> memberInfo =
|
||||
getSwitchStatementMemberInfo(node, i);
|
||||
if (memberInfo.labels.isNotEmpty) {
|
||||
hasLabels = true;
|
||||
}
|
||||
List<CaseHeadInfo<Node, Expression>> heads = caseInfo.heads;
|
||||
List<CaseHeadOrDefaultInfo<Node, Expression>> heads = memberInfo.heads;
|
||||
for (int j = 0; j < heads.length; j++) {
|
||||
CaseHeadInfo<Node, Expression> head = heads[j];
|
||||
CaseHeadOrDefaultInfo<Node, Expression> head = heads[j];
|
||||
Node? pattern = head.pattern;
|
||||
if (pattern != null) {
|
||||
dispatchPattern(pattern).match(
|
||||
|
@ -429,7 +423,7 @@ mixin TypeAnalyzer<Node extends Object, Statement extends Node,
|
|||
// Stack: (Expression, numExecutionPaths * StatementCase,
|
||||
// numHeads * CaseHead),
|
||||
flow?.switchStatement_endAlternative();
|
||||
body = caseInfo.body;
|
||||
body = memberInfo.body;
|
||||
}
|
||||
i++;
|
||||
if (body.isNotEmpty) break;
|
||||
|
@ -558,7 +552,7 @@ mixin TypeAnalyzer<Node extends Object, Statement extends Node,
|
|||
/// simply return the [index]th `case` or `default` clause.
|
||||
///
|
||||
/// See [analyzeSwitchExpression].
|
||||
ExpressionCaseInfo<Node, Expression> getExpressionCaseInfo(
|
||||
SwitchExpressionMemberInfo<Node, Expression> getSwitchExpressionMemberInfo(
|
||||
Expression node, int index);
|
||||
|
||||
/// Returns a [StatementCaseInfo] object describing the [index]th `case` or
|
||||
|
@ -569,8 +563,8 @@ mixin TypeAnalyzer<Node extends Object, Statement extends Node,
|
|||
/// simply return the [index]th `case` or `default` clause.
|
||||
///
|
||||
/// See [analyzeSwitchStatement].
|
||||
StatementCaseInfo<Node, Statement, Expression> getStatementCaseInfo(
|
||||
Statement node, int caseIndex);
|
||||
SwitchStatementMemberInfo<Node, Statement, Expression>
|
||||
getSwitchStatementMemberInfo(Statement node, int caseIndex);
|
||||
|
||||
/// Called after visiting a merged set of `case` / `default` clauses.
|
||||
///
|
||||
|
|
|
@ -399,7 +399,9 @@ abstract class Expression extends Node {
|
|||
/// Representation of a single case clause in a switch expression. Use
|
||||
/// [caseExpr] to create instances of this class.
|
||||
class ExpressionCase extends Node
|
||||
implements ExpressionCaseInfo<Node, Expression> {
|
||||
implements
|
||||
SwitchExpressionMemberInfo<Node, Expression>,
|
||||
CaseHeadOrDefaultInfo<Node, Expression> {
|
||||
@override
|
||||
final Pattern? pattern;
|
||||
|
||||
|
@ -407,26 +409,26 @@ class ExpressionCase extends Node
|
|||
final Expression? guard;
|
||||
|
||||
@override
|
||||
final Expression body;
|
||||
final Expression expression;
|
||||
|
||||
ExpressionCase._(this.pattern, this.guard, this.body,
|
||||
ExpressionCase._(this.pattern, this.guard, this.expression,
|
||||
{required super.location})
|
||||
: super._();
|
||||
|
||||
@override
|
||||
Node get node => this;
|
||||
CaseHeadOrDefaultInfo<Node, Expression> get head => this;
|
||||
|
||||
String toString() => [
|
||||
pattern == null ? 'default' : 'case $pattern',
|
||||
if (guard != null) ' when $guard',
|
||||
': $body'
|
||||
': $expression'
|
||||
].join('');
|
||||
|
||||
void _preVisit(PreVisitor visitor) {
|
||||
var variableBinder = VariableBinder<Node, Var, Type>(visitor);
|
||||
pattern?.preVisit(visitor, variableBinder);
|
||||
variableBinder.finish();
|
||||
body.preVisit(visitor);
|
||||
expression.preVisit(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2447,18 +2449,19 @@ class _MiniAstTypeAnalyzer
|
|||
}
|
||||
|
||||
@override
|
||||
ExpressionCaseInfo<Node, Expression> getExpressionCaseInfo(
|
||||
SwitchExpressionMemberInfo<Node, Expression> getSwitchExpressionMemberInfo(
|
||||
covariant _SwitchExpression node, int index) =>
|
||||
node.cases[index];
|
||||
|
||||
@override
|
||||
StatementCaseInfo<Node, Statement, Expression> getStatementCaseInfo(
|
||||
covariant _SwitchStatement node, int caseIndex) {
|
||||
SwitchStatementMemberInfo<Node, Statement, Expression>
|
||||
getSwitchStatementMemberInfo(
|
||||
covariant _SwitchStatement node, int caseIndex) {
|
||||
StatementCase case_ = node.cases[caseIndex];
|
||||
return StatementCaseInfo([
|
||||
return SwitchStatementMemberInfo([
|
||||
for (var caseHead in case_._caseHeads._caseHeads)
|
||||
CaseHeadInfo(
|
||||
node: caseHead, pattern: caseHead._pattern, guard: caseHead._guard)
|
||||
CaseHeadOrDefaultInfo(
|
||||
pattern: caseHead._pattern, guard: caseHead._guard)
|
||||
], case_._body.statements, labels: case_._caseHeads._labels);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue