Version 2.13.0-197.0.dev
Merge commit '778c2361c38ddbbfd787ad9619f1380b18c5fe29' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index 9bae526..e4c7261 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -300,16 +300,16 @@
/// Non-promotion reason describing the situation where a variable was not
/// promoted due to an explicit write to the variable appearing somewhere in the
/// source code.
-class DemoteViaExplicitWrite<Variable extends Object, Expression extends Object>
+class DemoteViaExplicitWrite<Variable extends Object>
extends NonPromotionReason {
/// The local variable that was not promoted.
final Variable variable;
- /// The expression that wrote to the variable; this corresponds to an
- /// expression that was passed to [FlowAnalysis.write].
- final Expression writeExpression;
+ /// The node that wrote to the variable; this corresponds to a node that was
+ /// passed to [FlowAnalysis.write].
+ final Object node;
- DemoteViaExplicitWrite(this.variable, this.writeExpression);
+ DemoteViaExplicitWrite(this.variable, this.node);
@override
String get documentationLink => 'http://dart.dev/go/non-promo-write';
@@ -318,46 +318,14 @@
String get shortName => 'explicitWrite';
@override
- R accept<R, Node extends Object, Expression extends Object,
- Variable extends Object, Type extends Object>(
- NonPromotionReasonVisitor<R, Node, Expression, Variable, Type>
- visitor) =>
+ R accept<R, Node extends Object, Variable extends Object,
+ Type extends Object>(
+ NonPromotionReasonVisitor<R, Node, Variable, Type> visitor) =>
visitor.visitDemoteViaExplicitWrite(
- this as DemoteViaExplicitWrite<Variable, Expression>);
+ this as DemoteViaExplicitWrite<Variable>);
@override
- String toString() => 'DemoteViaExplicitWrite($writeExpression)';
-}
-
-/// Non-promotion reason describing the situation where a variable was not
-/// promoted due to the variable appearing before the word `in` in a "for each"
-/// statement or a "for each" collection element.
-class DemoteViaForEachVariableWrite<Variable extends Object,
- Node extends Object> extends NonPromotionReason {
- /// The local variable that was not promoted.
- final Variable variable;
-
- /// The "for each" statement or collection element that wrote to the variable.
- final Node node;
-
- DemoteViaForEachVariableWrite(this.variable, this.node);
-
- @override
- String get documentationLink => 'http://dart.dev/go/non-promo-write';
-
- @override
- String get shortName => 'explicitWrite';
-
- @override
- R accept<R, Node extends Object, Expression extends Object,
- Variable extends Object, Type extends Object>(
- NonPromotionReasonVisitor<R, Node, Expression, Variable, Type>
- visitor) =>
- visitor.visitDemoteViaForEachVariableWrite(
- this as DemoteViaForEachVariableWrite<Variable, Node>);
-
- @override
- String toString() => 'DemoteViaForEachVariableWrite($node)';
+ String toString() => 'DemoteViaExplicitWrite($node)';
}
/// A collection of flow models representing the possible outcomes of evaluating
@@ -565,11 +533,8 @@
/// - Call [forEach_end].
///
/// [node] should be the same node that was passed to
- /// [AssignedVariables.endNode] for the for statement. [loopVariable] should
- /// be the variable assigned to by the loop (if it is promotable, otherwise
- /// null). [writtenType] should be the type written to that variable (i.e.
- /// if the loop iterates over `List<Foo>`, it should be `Foo`).
- void forEach_bodyBegin(Node node, Variable? loopVariable, Type writtenType);
+ /// [AssignedVariables.endNode] for the for statement.
+ void forEach_bodyBegin(Node node);
/// Call this method just before visiting the body of a "for-in" statement or
/// collection element. See [forEach_bodyBegin] for details.
@@ -982,7 +947,7 @@
/// Register write of the given [variable] in the current state.
/// [writtenType] should be the type of the value that was written.
- /// [expression] should be the whole expression performing the write.
+ /// [node] should be the syntactic construct performing the write.
/// [writtenExpression] should be the expression that was written, or `null`
/// if the expression that was written is not directly represented in the
/// source code (this happens, for example, with compound assignments and with
@@ -991,7 +956,7 @@
/// This should also be used for the implicit write to a non-final variable in
/// its initializer, to ensure that the type is promoted to non-nullable if
/// necessary; in this case, [viaInitializer] should be `true`.
- void write(Expression expression, Variable variable, Type writtenType,
+ void write(Node node, Variable variable, Type writtenType,
Expression? writtenExpression);
/// Prints out a summary of the current state of flow analysis, intended for
@@ -1162,9 +1127,9 @@
}
@override
- void forEach_bodyBegin(Node node, Variable? loopVariable, Type writtenType) {
- return _wrap('forEach_bodyBegin($node, $loopVariable, $writtenType)',
- () => _wrapped.forEach_bodyBegin(node, loopVariable, writtenType));
+ void forEach_bodyBegin(Node node) {
+ return _wrap(
+ 'forEach_bodyBegin($node)', () => _wrapped.forEach_bodyBegin(node));
}
@override
@@ -1513,12 +1478,10 @@
}
@override
- void write(Expression expression, Variable variable, Type writtenType,
+ void write(Node node, Variable variable, Type writtenType,
Expression? writtenExpression) {
- _wrap(
- 'write($expression, $variable, $writtenType, $writtenExpression)',
- () => _wrapped.write(
- expression, variable, writtenType, writtenExpression));
+ _wrap('write($node, $variable, $writtenType, $writtenExpression)',
+ () => _wrapped.write(node, variable, writtenType, writtenExpression));
}
@override
@@ -2348,21 +2311,17 @@
String get shortName;
/// Implementation of the visitor pattern for non-promotion reasons.
- R accept<R, Node extends Object, Expression extends Object,
- Variable extends Object, Type extends Object>(
- NonPromotionReasonVisitor<R, Node, Expression, Variable, Type> visitor);
+ R accept<R, Node extends Object, Variable extends Object,
+ Type extends Object>(
+ NonPromotionReasonVisitor<R, Node, Variable, Type> visitor);
}
/// Implementation of the visitor pattern for non-promotion reasons.
abstract class NonPromotionReasonVisitor<R, Node extends Object,
- Expression extends Object, Variable extends Object, Type extends Object> {
+ Variable extends Object, Type extends Object> {
NonPromotionReasonVisitor._() : assert(false, 'Do not extend this class');
- R visitDemoteViaExplicitWrite(
- DemoteViaExplicitWrite<Variable, Expression> reason);
-
- R visitDemoteViaForEachVariableWrite(
- DemoteViaForEachVariableWrite<Variable, Node> reason);
+ R visitDemoteViaExplicitWrite(DemoteViaExplicitWrite<Variable> reason);
R visitPropertyNotPromoted(PropertyNotPromoted<Type> reason);
@@ -2389,10 +2348,9 @@
String get shortName => 'propertyNotPromoted';
@override
- R accept<R, Node extends Object, Expression extends Object,
- Variable extends Object, Type extends Object>(
- NonPromotionReasonVisitor<R, Node, Expression, Variable, Type>
- visitor) =>
+ R accept<R, Node extends Object, Variable extends Object,
+ Type extends Object>(
+ NonPromotionReasonVisitor<R, Node, Variable, Type> visitor) =>
visitor.visitPropertyNotPromoted(this as PropertyNotPromoted<Type>);
}
@@ -2627,10 +2585,9 @@
String get shortName => 'thisNotPromoted';
@override
- R accept<R, Node extends Object, Expression extends Object,
- Variable extends Object, Type extends Object>(
- NonPromotionReasonVisitor<R, Node, Expression, Variable, Type>
- visitor) =>
+ R accept<R, Node extends Object, Variable extends Object,
+ Type extends Object>(
+ NonPromotionReasonVisitor<R, Node, Variable, Type> visitor) =>
visitor.visitThisNotPromoted(this);
}
@@ -3680,7 +3637,7 @@
}
@override
- void forEach_bodyBegin(Node node, Variable? loopVariable, Type writtenType) {
+ void forEach_bodyBegin(Node node) {
AssignedVariablesNodeInfo<Variable> info =
_assignedVariables._getInfoForNode(node);
_current = _current.conservativeJoin(info._written, info._captured).split();
@@ -3688,14 +3645,6 @@
new _SimpleStatementContext<Variable, Type>(
_current.reachable.parent!, _current);
_stack.add(context);
- if (loopVariable != null) {
- _current = _current.write(
- new DemoteViaForEachVariableWrite<Variable, Node>(loopVariable, node),
- loopVariable,
- writtenType,
- new SsaNode<Variable, Type>(null),
- typeOperations);
- }
}
@override
@@ -4220,7 +4169,7 @@
}
@override
- void write(Expression expression, Variable variable, Type writtenType,
+ void write(Node node, Variable variable, Type writtenType,
Expression? writtenExpression) {
ExpressionInfo<Variable, Type>? expressionInfo = writtenExpression == null
? null
@@ -4228,7 +4177,7 @@
SsaNode<Variable, Type> newSsaNode = new SsaNode<Variable, Type>(
expressionInfo is _TrivialExpressionInfo ? null : expressionInfo);
_current = _current.write(
- new DemoteViaExplicitWrite<Variable, Expression>(variable, expression),
+ new DemoteViaExplicitWrite<Variable>(variable, node),
variable,
writtenType,
newSsaNode,
@@ -4509,8 +4458,7 @@
void for_updaterBegin() {}
@override
- void forEach_bodyBegin(
- Node node, Variable? loopVariable, Type? writtenType) {}
+ void forEach_bodyBegin(Node node) {}
@override
void forEach_end() {}
@@ -4815,7 +4763,7 @@
}
@override
- void write(Expression expression, Variable variable, Type writtenType,
+ void write(Node node, Variable variable, Type writtenType,
Expression? writtenExpression) {
assert(
_assignedVariables._anywhere._written.contains(variable),
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
index c48efaf..4e018e2 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
@@ -5500,8 +5500,8 @@
x.expr.whyNotPromoted((reasons) {
expect(reasons.keys, unorderedEquals([Type('int')]));
var nonPromotionReason =
- reasons.values.single as DemoteViaExplicitWrite<Var, Expression>;
- expect(nonPromotionReason.writeExpression, same(writeExpression));
+ reasons.values.single as DemoteViaExplicitWrite<Var>;
+ expect(nonPromotionReason.node, same(writeExpression));
}).stmt,
]);
});
@@ -5523,13 +5523,9 @@
checkNotPromoted(x),
x.expr.whyNotPromoted((reasons) {
expect(reasons.keys, unorderedEquals([Type('int'), Type('int?')]));
- expect(
- (reasons[Type('int')] as DemoteViaExplicitWrite<Var, Expression>)
- .writeExpression,
+ expect((reasons[Type('int')] as DemoteViaExplicitWrite<Var>).node,
same(writeExpression));
- expect(
- (reasons[Type('int?')] as DemoteViaExplicitWrite<Var, Expression>)
- .writeExpression,
+ expect((reasons[Type('int?')] as DemoteViaExplicitWrite<Var>).node,
same(writeExpression));
}).stmt,
]);
@@ -5553,8 +5549,8 @@
x.expr.whyNotPromoted((reasons) {
expect(reasons.keys, unorderedEquals([Type('int')]));
var nonPromotionReason =
- reasons.values.single as DemoteViaExplicitWrite<Var, Expression>;
- expect(nonPromotionReason.writeExpression, same(writeExpression));
+ reasons.values.single as DemoteViaExplicitWrite<Var>;
+ expect(nonPromotionReason.node, same(writeExpression));
}).stmt,
]);
});
@@ -5577,8 +5573,8 @@
checkPromoted(x, 'num'),
x.expr.whyNotPromoted((reasons) {
var nonPromotionReason =
- reasons[Type('int')] as DemoteViaExplicitWrite;
- expect(nonPromotionReason.writeExpression, same(writeExpression));
+ reasons[Type('int')] as DemoteViaExplicitWrite<Var>;
+ expect(nonPromotionReason.node, same(writeExpression));
}).stmt,
]);
});
@@ -5759,10 +5755,9 @@
String get shortName => fail('Unexpected call to shortName');
- R accept<R, Node extends Object, Expression extends Object,
- Variable extends Object, Type extends Object>(
- NonPromotionReasonVisitor<R, Node, Expression, Variable, Type>
- visitor) =>
+ R accept<R, Node extends Object, Variable extends Object,
+ Type extends Object>(
+ NonPromotionReasonVisitor<R, Node, Variable, Type> visitor) =>
fail('Unexpected call to accept');
}
diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
index fb2769a..9e1ca0a 100644
--- a/pkg/_fe_analyzer_shared/test/mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -37,7 +37,7 @@
new _Break(branchTargetPlaceholder);
SwitchCase case_(List<Statement> body, {bool hasLabel = false}) =>
- SwitchCase._(hasLabel, body);
+ SwitchCase._(hasLabel, new _Block(body));
/// Creates a pseudo-statement whose function is to verify that flow analysis
/// considers [variable]'s assigned state to be [expectedAssignedState].
@@ -79,7 +79,7 @@
new _Declare(variable, initializer, isFinal, isLate);
Statement do_(List<Statement> body, Expression condition) =>
- _Do(body, condition);
+ _Do(block(body), condition);
/// Creates a pseudo-expression having type [typeStr] that otherwise has no
/// effect on flow analysis.
@@ -92,7 +92,7 @@
Statement for_(Statement? initializer, Expression? condition,
Expression? updater, List<Statement> body,
{bool forCollection = false}) =>
- new _For(initializer, condition, updater, body, forCollection);
+ new _For(initializer, condition, updater, block(body), forCollection);
/// Creates a "for each" statement where the identifier being assigned to by the
/// iteration is not a local variable.
@@ -103,7 +103,7 @@
/// for (x in iterable) { ... }
/// }
Statement forEachWithNonVariable(Expression iterable, List<Statement> body) =>
- new _ForEach(null, iterable, body, false);
+ new _ForEach(null, iterable, block(body), false);
/// Creates a "for each" statement where the identifier being assigned to by the
/// iteration is a variable that is being declared by the "for each" statement.
@@ -116,7 +116,7 @@
Var variable, Expression iterable, List<Statement> body) {
// ignore: unnecessary_null_comparison
assert(variable != null);
- return new _ForEach(variable, iterable, body, true);
+ return new _ForEach(variable, iterable, block(body), true);
}
/// Creates a "for each" statement where the identifier being assigned to by the
@@ -131,7 +131,7 @@
Var variable, Expression iterable, List<Statement> body) {
// ignore: unnecessary_null_comparison
assert(variable != null);
- return new _ForEach(variable, iterable, body, false);
+ return new _ForEach(variable, iterable, block(body), false);
}
/// Creates a [Statement] that, when analyzed, will cause [callback] to be
@@ -142,7 +142,7 @@
Statement if_(Expression condition, List<Statement> ifTrue,
[List<Statement>? ifFalse]) =>
- new _If(condition, ifTrue, ifFalse);
+ new _If(condition, block(ifTrue), ifFalse == null ? null : block(ifFalse));
Statement implicitThis_whyNotPromoted(String staticType,
void Function(Map<Type, NonPromotionReason>) callback) =>
@@ -150,7 +150,7 @@
Statement labeled(Statement body) => new _LabeledStatement(body);
-Statement localFunction(List<Statement> body) => _LocalFunction(body);
+Statement localFunction(List<Statement> body) => _LocalFunction(block(body));
Statement return_() => new _Return();
@@ -163,10 +163,11 @@
Expression throw_(Expression operand) => new _Throw(operand);
-TryBuilder try_(List<Statement> body) => new _TryStatement(body, [], null);
+TryBuilder try_(List<Statement> body) =>
+ new _TryStatement(block(body), [], null);
Statement while_(Expression condition, List<Statement> body) =>
- new _While(condition, body);
+ new _While(condition, block(body));
/// Placeholder used by [branchTarget] to tie `break` and `continue` statements
/// to their branch targets.
@@ -481,13 +482,14 @@
/// they contain.
void run(List<Statement> statements) {
var assignedVariables = AssignedVariables<Node, Var>();
- statements._preVisit(assignedVariables);
+ var b = block(statements);
+ b._preVisit(assignedVariables);
var flow = legacy
? FlowAnalysis<Node, Statement, Expression, Var, Type>.legacy(
this, assignedVariables)
: FlowAnalysis<Node, Statement, Expression, Var, Type>(
this, assignedVariables);
- statements._visit(this, flow);
+ b._visit(this, flow);
flow.finish();
}
@@ -601,12 +603,15 @@
/// to create instances of this class.
class SwitchCase implements _Visitable<void> {
final bool _hasLabel;
- final List<Statement> _body;
+ final _Block _body;
SwitchCase._(this._hasLabel, this._body);
- String toString() =>
- [if (_hasLabel) '<label>:', 'case <value>:', ..._body].join(' ');
+ String toString() => [
+ if (_hasLabel) '<label>:',
+ 'case <value>:',
+ ..._body.statements
+ ].join(' ');
void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
_body._preVisit(assignedVariables);
@@ -713,13 +718,17 @@
@override
void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
- statements._preVisit(assignedVariables);
+ for (var statement in statements) {
+ statement._preVisit(assignedVariables);
+ }
}
@override
void _visit(
Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
- statements._visit(h, flow);
+ for (var statement in statements) {
+ statement._visit(h, flow);
+ }
}
}
@@ -765,7 +774,7 @@
/// Representation of a single catch clause in a try/catch statement. Use
/// [catch_] to create instances of this class.
class _CatchClause implements _Visitable<void> {
- final List<Statement> _body;
+ final Statement _body;
final Var? _exception;
final Var? _stackTrace;
@@ -780,7 +789,7 @@
} else {
initialPart = 'on ...';
}
- return '$initialPart ${block(_body)}';
+ return '$initialPart $_body';
}
void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
@@ -973,13 +982,13 @@
}
class _Do extends Statement {
- final List<Statement> body;
+ final Statement body;
final Expression condition;
_Do(this.body, this.condition) : super._();
@override
- String toString() => 'do ${block(body)} while ($condition);';
+ String toString() => 'do $body while ($condition);';
@override
void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
@@ -1051,7 +1060,7 @@
final Statement? initializer;
final Expression? condition;
final Expression? updater;
- final List<Statement> body;
+ final Statement body;
final bool forCollection;
_For(this.initializer, this.condition, this.updater, this.body,
@@ -1074,7 +1083,7 @@
if (updater != null) {
buffer.write(' $updater');
}
- buffer.write(') ${block(body)}');
+ buffer.write(') $body');
return buffer.toString();
}
@@ -1105,7 +1114,7 @@
class _ForEach extends Statement {
final Var? variable;
final Expression iterable;
- final List<Statement> body;
+ final Statement body;
final bool declaresVariable;
_ForEach(this.variable, this.iterable, this.body, this.declaresVariable)
@@ -1121,7 +1130,7 @@
} else {
declarationPart = variable!.name;
}
- return 'for ($declarationPart in $iterable) ${block(body)}';
+ return 'for ($declarationPart in $iterable) $body';
}
@override
@@ -1143,7 +1152,11 @@
void _visit(
Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
var iteratedType = h._getIteratedType(iterable._visit(h, flow));
- flow.forEach_bodyBegin(this, variable, iteratedType);
+ flow.forEach_bodyBegin(this);
+ var variable = this.variable;
+ if (variable != null && !declaresVariable) {
+ flow.write(this, variable, iteratedType, null);
+ }
body._visit(h, flow);
flow.forEach_end();
}
@@ -1188,15 +1201,14 @@
class _If extends Statement {
final Expression condition;
- final List<Statement> ifTrue;
- final List<Statement>? ifFalse;
+ final Statement ifTrue;
+ final Statement? ifFalse;
_If(this.condition, this.ifTrue, this.ifFalse) : super._();
@override
String toString() =>
- 'if ($condition) ${block(ifTrue)}' +
- (ifFalse == null ? '' : 'else ${block(ifFalse!)}');
+ 'if ($condition) $ifTrue' + (ifFalse == null ? '' : 'else $ifFalse');
@override
void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
@@ -1295,12 +1307,12 @@
}
class _LocalFunction extends Statement {
- final List<Statement> body;
+ final Statement body;
_LocalFunction(this.body) : super._();
@override
- String toString() => '() ${block(body)}';
+ String toString() => '() $body';
@override
void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
@@ -1557,7 +1569,9 @@
void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
expression._preVisit(assignedVariables);
assignedVariables.beginNode();
- cases._preVisit(assignedVariables);
+ for (var case_ in cases) {
+ case_._preVisit(assignedVariables);
+ }
assignedVariables.endNode(this);
}
@@ -1568,7 +1582,9 @@
flow.switchStatement_expressionEnd(this);
var oldSwitch = h._currentSwitch;
h._currentSwitch = this;
- cases._visit(h, flow);
+ for (var case_ in cases) {
+ case_._visit(h, flow);
+ }
h._currentSwitch = oldSwitch;
flow.switchStatement_end(isExhaustive);
}
@@ -1631,9 +1647,9 @@
}
class _TryStatement extends TryStatement {
- final List<Statement> _body;
+ final Statement _body;
final List<_CatchClause> _catches;
- final List<Statement>? _finally;
+ final Statement? _finally;
final _bodyNode = Node._();
_TryStatement(this._body, this._catches, this._finally) : super._();
@@ -1642,14 +1658,14 @@
TryStatement catch_(
{Var? exception, Var? stackTrace, required List<Statement> body}) {
assert(_finally == null, 'catch after finally');
- return _TryStatement(
- _body, [..._catches, _CatchClause(body, exception, stackTrace)], null);
+ return _TryStatement(_body,
+ [..._catches, _CatchClause(block(body), exception, stackTrace)], null);
}
@override
Statement finally_(List<Statement> statements) {
assert(_finally == null, 'multiple finally clauses');
- return _TryStatement(_body, _catches, statements);
+ return _TryStatement(_body, _catches, block(statements));
}
@override
@@ -1662,7 +1678,9 @@
}
_body._preVisit(assignedVariables);
assignedVariables.endNode(_bodyNode);
- _catches._preVisit(assignedVariables);
+ for (var catch_ in _catches) {
+ catch_._preVisit(assignedVariables);
+ }
if (_finally != null) {
if (_catches.isNotEmpty) {
assignedVariables.endNode(this);
@@ -1683,7 +1701,9 @@
_body._visit(h, flow);
if (_catches.isNotEmpty) {
flow.tryCatchStatement_bodyEnd(_bodyNode);
- _catches._visit(h, flow);
+ for (var catch_ in _catches) {
+ catch_._visit(h, flow);
+ }
flow.tryCatchStatement_end();
}
if (_finally != null) {
@@ -1740,12 +1760,12 @@
class _While extends Statement {
final Expression condition;
- final List<Statement> body;
+ final Statement body;
_While(this.condition, this.body) : super._();
@override
- String toString() => 'while ($condition) ${block(body)}';
+ String toString() => 'while ($condition) $body';
@override
void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
@@ -1888,18 +1908,3 @@
return type;
}
}
-
-extension on List<_Visitable<void>> {
- void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
- for (var element in this) {
- element._preVisit(assignedVariables);
- }
- }
-
- void _visit(
- Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
- for (var element in this) {
- element._visit(h, flow);
- }
- }
-}
diff --git a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
index c82e332..efa3e86c 100644
--- a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
@@ -14,6 +14,7 @@
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_algebra.dart';
import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/resolver.dart';
@@ -65,6 +66,7 @@
_constructorInvocation(
node,
+ classElement.name,
constructorName,
classElement.typeParameters,
constructorElement,
@@ -113,6 +115,7 @@
void _constructorInvocation(
AnnotationImpl node,
+ String typeDisplayName,
SimpleIdentifierImpl? constructorName,
List<TypeParameterElement> typeParameters,
ConstructorElement? constructorElement,
@@ -136,6 +139,18 @@
// If no type parameters, the elements are correct.
if (typeParameters.isEmpty) {
+ var typeArgumentList = node.typeArguments;
+ if (typeArgumentList != null) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
+ typeArgumentList,
+ [
+ typeDisplayName,
+ typeParameters.length,
+ typeArgumentList.arguments.length,
+ ],
+ );
+ }
_resolveConstructorInvocationArguments(node);
InferenceContext.setType(argumentList, constructorElement.type);
_resolver.visitArgumentList(argumentList,
@@ -174,7 +189,35 @@
typeArguments = typeArgumentList.arguments
.map((element) => element.typeOrThrow)
.toList();
+ var substitution = Substitution.fromPairs(
+ typeParameters,
+ typeArguments,
+ );
+ for (var i = 0; i < typeParameters.length; i++) {
+ var typeParameter = typeParameters[i];
+ var bound = typeParameter.bound;
+ if (bound != null) {
+ bound = substitution.substituteType(bound);
+ var typeArgument = typeArguments[i];
+ if (!_resolver.typeSystem.isSubtypeOf(typeArgument, bound)) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS,
+ typeArgumentList.arguments[i],
+ [typeArgument, typeParameter.name, bound],
+ );
+ }
+ }
+ }
} else {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
+ typeArgumentList,
+ [
+ typeDisplayName,
+ typeParameters.length,
+ typeArgumentList.arguments.length,
+ ],
+ );
typeArguments = List.filled(
typeParameters.length,
DynamicTypeImpl.instance,
@@ -458,6 +501,7 @@
_constructorInvocation(
node,
+ typeAliasElement.name,
constructorName,
typeAliasElement.typeParameters,
constructorElement,
diff --git a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
index 3c44519..1797cfc 100644
--- a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
@@ -132,13 +132,12 @@
?.declare(loopVariable.declaredElement!, true);
}
- _resolver.flowAnalysis?.flow?.forEach_bodyBegin(
- node,
- identifierElement is PromotableElement
- ? identifierElement
- : loopVariable?.declaredElement,
- elementType ?? DynamicTypeImpl.instance,
- );
+ _resolver.flowAnalysis?.flow?.forEach_bodyBegin(node);
+ if (identifierElement is PromotableElement &&
+ forEachParts is ForEachPartsWithIdentifier) {
+ _resolver.flowAnalysis?.flow?.write(forEachParts, identifierElement,
+ elementType ?? DynamicTypeImpl.instance, null);
+ }
_resolveBody(body);
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index bb494fd..1a1918d 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -3443,7 +3443,7 @@
class _WhyNotPromotedVisitor
implements
- NonPromotionReasonVisitor<DiagnosticMessage?, AstNode, Expression,
+ NonPromotionReasonVisitor<DiagnosticMessage?, AstNode,
PromotableElement, DartType> {
final Source source;
@@ -3464,43 +3464,17 @@
@override
DiagnosticMessage? visitDemoteViaExplicitWrite(
- DemoteViaExplicitWrite<PromotableElement, Expression> reason) {
- var writeExpression = reason.writeExpression;
+ DemoteViaExplicitWrite<PromotableElement> reason) {
+ var node = reason.node as AstNode;
+ if (node is ForEachPartsWithIdentifier) {
+ node = node.identifier;
+ }
if (_dataForTesting != null) {
- _dataForTesting!.nonPromotionReasonTargets[writeExpression] =
- reason.shortName;
+ _dataForTesting!.nonPromotionReasonTargets[node] = reason.shortName;
}
var variableName = reason.variable.name;
if (variableName == null) return null;
- return _contextMessageForWrite(variableName, writeExpression, reason);
- }
-
- @override
- DiagnosticMessage? visitDemoteViaForEachVariableWrite(
- DemoteViaForEachVariableWrite<PromotableElement, AstNode> reason) {
- var node = reason.node;
- var variableName = reason.variable.name;
- if (variableName == null) return null;
- ForLoopParts parts;
- if (node is ForStatement) {
- parts = node.forLoopParts;
- } else if (node is ForElement) {
- parts = node.forLoopParts;
- } else {
- assert(false, 'Unexpected node type');
- return null;
- }
- if (parts is ForEachPartsWithIdentifier) {
- var identifier = parts.identifier;
- if (_dataForTesting != null) {
- _dataForTesting!.nonPromotionReasonTargets[identifier] =
- reason.shortName;
- }
- return _contextMessageForWrite(variableName, identifier, reason);
- } else {
- assert(false, 'Unexpected parts type');
- return null;
- }
+ return _contextMessageForWrite(variableName, node, reason);
}
@override
@@ -3551,13 +3525,13 @@
length: property.nameLength);
}
- DiagnosticMessageImpl _contextMessageForWrite(String variableName,
- Expression writeExpression, NonPromotionReason reason) {
+ DiagnosticMessageImpl _contextMessageForWrite(
+ String variableName, AstNode node, NonPromotionReason reason) {
return DiagnosticMessageImpl(
filePath: source.fullName,
message: "Variable '$variableName' could not be promoted due to an "
"assignment. See ${reason.documentationLink}",
- offset: writeExpression.offset,
- length: writeExpression.length);
+ offset: node.offset,
+ length: node.length);
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart b/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
index 9d407aa..25184c2 100644
--- a/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
@@ -471,6 +471,45 @@
''');
}
+ test_metadata_matching() async {
+ await assertNoErrorsInCode(r'''
+class A<T extends num> {
+ const A();
+}
+
+@A<int>()
+void f() {}
+''');
+ }
+
+ test_metadata_notMatching() async {
+ await assertErrorsInCode(r'''
+class A<T extends num> {
+ const A();
+}
+
+@A<String>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 44, 6),
+ ]);
+ }
+
+ test_metadata_notMatching_viaTypeAlias() async {
+ await assertErrorsInCode(r'''
+class A<T> {
+ const A();
+}
+
+typedef B<T extends num> = A<T>;
+
+@B<String>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 66, 6),
+ ]);
+ }
+
test_methodInvocation_genericFunctionTypeArgument_match() async {
await assertNoErrorsInCode(r'''
typedef F = void Function<T extends num>();
diff --git a/pkg/analyzer/test/src/diagnostics/wrong_number_of_type_arguments_test.dart b/pkg/analyzer/test/src/diagnostics/wrong_number_of_type_arguments_test.dart
index 29e3eee..6754881 100644
--- a/pkg/analyzer/test/src/diagnostics/wrong_number_of_type_arguments_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/wrong_number_of_type_arguments_test.dart
@@ -93,6 +93,90 @@
]);
}
+ test_metadata_1of0() async {
+ await assertErrorsInCode(r'''
+class A {
+ const A();
+}
+
+@A<int>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, 28, 5),
+ ]);
+ }
+
+ test_metadata_1of0_viaTypeAlias() async {
+ await assertErrorsInCode(r'''
+class A {
+ const A();
+}
+
+typedef B = A;
+
+@B<int>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, 44, 5),
+ ]);
+ }
+
+ test_metadata_1of2() async {
+ await assertErrorsInCode(r'''
+class A<T, U> {
+ const A();
+}
+
+@A<int>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, 34, 5),
+ ]);
+ }
+
+ test_metadata_1of2_viaTypeAlias() async {
+ await assertErrorsInCode(r'''
+class A {
+ const A();
+}
+
+typedef B<T, U> = A;
+
+@B<int>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, 50, 5),
+ ]);
+ }
+
+ test_metadata_2of1() async {
+ await assertErrorsInCode(r'''
+class A<T> {
+ const A();
+}
+
+@A<int, String>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, 31, 13),
+ ]);
+ }
+
+ test_metadata_2of1_viaTypeAlias() async {
+ await assertErrorsInCode(r'''
+class A {
+ const A();
+}
+
+typedef B<T> = A;
+
+@B<int, String>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, 47, 13),
+ ]);
+ }
+
test_new_nonGeneric() async {
await assertErrorsInCode('''
class C {}
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index 13c72b9..89fdd5e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -901,7 +901,7 @@
// This is matched by the call to [forEach_end] in
// [inferElement], [inferMapEntry] or [inferForInStatement].
inferrer.flowAnalysis.declare(variable, true);
- inferrer.flowAnalysis.forEach_bodyBegin(node, variable, variable.type);
+ inferrer.flowAnalysis.forEach_bodyBegin(node);
VariableDeclaration tempVariable =
new VariableDeclaration(null, type: inferredType, isFinal: true);
@@ -1022,8 +1022,11 @@
}
// This is matched by the call to [forEach_end] in
// [inferElement], [inferMapEntry] or [inferForInStatement].
- inferrer.flowAnalysis.forEach_bodyBegin(node, variable, inferredType);
+ inferrer.flowAnalysis.forEach_bodyBegin(node);
syntheticAssignment = forInVariable.inferAssignment(inferrer, inferredType);
+ if (syntheticAssignment is VariableSet) {
+ inferrer.flowAnalysis.write(node, variable, inferredType, null);
+ }
if (expressionEffects != null) {
StatementInferenceResult result =
inferrer.inferStatement(expressionEffects);
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index ff29dc3..15606b8 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -5130,8 +5130,8 @@
class _WhyNotPromotedVisitor
implements
- NonPromotionReasonVisitor<LocatedMessage, Node, Expression,
- VariableDeclaration, DartType> {
+ NonPromotionReasonVisitor<LocatedMessage, Node, VariableDeclaration,
+ DartType> {
final TypeInferrerImpl inferrer;
final Expression receiver;
@@ -5144,21 +5144,13 @@
@override
LocatedMessage visitDemoteViaExplicitWrite(
- DemoteViaExplicitWrite<VariableDeclaration, Expression> reason) {
+ DemoteViaExplicitWrite<VariableDeclaration> reason) {
+ TreeNode node = reason.node as TreeNode;
if (inferrer.dataForTesting != null) {
inferrer.dataForTesting.flowAnalysisResult
- .nonPromotionReasonTargets[reason.writeExpression] = reason.shortName;
+ .nonPromotionReasonTargets[node] = reason.shortName;
}
- int offset = reason.writeExpression.fileOffset;
- return templateVariableCouldBeNullDueToWrite
- .withArguments(reason.variable.name, reason.documentationLink)
- .withLocation(inferrer.helper.uri, offset, noLength);
- }
-
- @override
- LocatedMessage visitDemoteViaForEachVariableWrite(
- DemoteViaForEachVariableWrite<VariableDeclaration, Node> reason) {
- int offset = (reason.node as TreeNode).fileOffset;
+ int offset = node.fileOffset;
return templateVariableCouldBeNullDueToWrite
.withArguments(reason.variable.name, reason.documentationLink)
.withLocation(inferrer.helper.uri, offset, noLength);
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 5b97ce5..26ad6fe 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -2762,10 +2762,11 @@
source: elementType, destination: lhsType, hard: false);
}
}
- _flowAnalysis.forEach_bodyBegin(
- node,
- lhsElement is PromotableElement ? lhsElement : null,
- elementType ?? _makeNullableDynamicType(node));
+ _flowAnalysis.forEach_bodyBegin(node);
+ if (lhsElement is PromotableElement) {
+ _flowAnalysis.write(node, lhsElement,
+ elementType ?? _makeNullableDynamicType(node), null);
+ }
}
// The condition may fail/iterable may be empty, so the body gets a new
diff --git a/tools/VERSION b/tools/VERSION
index b182322..275cd60 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 196
+PRERELEASE 197
PRERELEASE_PATCH 0
\ No newline at end of file