Revert "Flow analysis changes to fix mixed-mode unsoundness loophole."
This reverts commit d833f2f65c13170c1b330b963fc538d881301115.
Reason for revert: Broke build, e.g. https://ci.chromium.org/p/dart/builders/ci/dart-sdk-mac/12688
Original change's description:
> Flow analysis changes to fix mixed-mode unsoundness loophole.
>
> This is the flow analysis portion of the fix to
> https://github.com/dart-lang/language/issues/1143. Follow-up changes
> will be needed in the CFE and/or backends to ensure that exceptions
> are thrown under appropriate circumstances.
>
> This CL also makes some improvements to flow analysis's reachability
> analysis so that it accounts for nullability of the target when
> analyzing the reachability of `??=` and `?.`. Hopefully these
> improvements should make the fix to
> https://github.com/dart-lang/language/issues/1143 clearer and more
> consistent.
>
> Change-Id: I5fa5c070f13fd57ac4c2fb87f2d67588861594b0
> Bug: https://github.com/dart-lang/language/issues/1143
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/160440
> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
> Reviewed-by: Johnni Winther <johnniwinther@google.com>
> Commit-Queue: Paul Berry <paulberry@google.com>
TBR=paulberry@google.com,scheglov@google.com,johnniwinther@google.com
Change-Id: If1215b19975e0958d612dd69767088095d853879
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: https://github.com/dart-lang/language/issues/1143
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/161580
Reviewed-by: Paul Berry <paulberry@google.com>
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 e6e8921..8c4699a 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
@@ -362,16 +362,7 @@
void doStatement_end(Expression condition);
/// Call this method just after visiting a binary `==` or `!=` expression.
- ///
- /// Return value indicates whether flow analysis believes that a successful
- /// equality check is reachable. If `false` is returned, the client should
- /// ensure that the `==` test behaves like `x == y && throw ...`.
- ///
- /// Note that if `notEqual` is `true`, then the return value describes the
- /// behavior of the underlying `==` test. So if `notEqual` is `true` and
- /// `false` is returned, the client should ensure that the `!=` test behaves
- /// like `!(x == y && throw ...)`.
- bool equalityOp_end(Expression wholeExpression, Expression rightOperand,
+ void equalityOp_end(Expression wholeExpression, Expression rightOperand,
Type rightOperandType,
{bool notEqual = false});
@@ -484,13 +475,7 @@
/// Call this method after visiting the LHS of an if-null expression ("??")
/// or if-null assignment ("??=").
- ///
- /// Return value indicates whether flow analysis believes that the right hand
- /// side is reachable. If `false` is returned, the client should ensure that
- /// `x ?? y` behaves like `x ?? throw ...` (or, correspondingly, that
- /// `x ??= y` behaves like `x ??= throw ...`).
- bool ifNullExpression_rightBegin(
- Expression leftHandSide, Type leftHandSideType);
+ void ifNullExpression_rightBegin(Expression leftHandSide);
/// Call this method after visiting the "then" part of an if statement, and
/// before visiting the "else" part.
@@ -526,16 +511,7 @@
/// be the expression to which the "is" check was applied. [isNot] should be
/// a boolean indicating whether this is an "is" or an "is!" expression.
/// [type] should be the type being checked.
- ///
- /// Return value indicates whether flow analysis believes that a failure of
- /// the `is` test is reachable. If `false` is returned, the client should
- /// ensure that the `is` test behaves like `x is T || throw ...`.
- ///
- /// Note that if `isNot` is `true`, then the return value describes the
- /// behavior of the underlying `if` test. So if `isNot` is `true` and `false`
- /// is returned, the client should ensure that the `is!` test behaves like
- /// `!(x is T || throw ...)`.
- bool isExpression_end(
+ void isExpression_end(
Expression isExpression, Expression subExpression, bool isNot, Type type);
/// Return whether the [variable] is definitely unassigned in the current
@@ -582,22 +558,12 @@
/// [target] should be the expression just before the null-aware operator, or
/// `null` if the null-aware access starts a cascade section.
///
- /// [targetType] should be the type of the expression just before the
- /// null-aware operator, and should be non-null even if the null-aware access
- /// starts a cascade section.
- ///
/// Note that [nullAwareAccess_end] should be called after the conclusion
/// of any null-shorting that is caused by the `?.`. So, for example, if the
/// code being analyzed is `x?.y?.z(x)`, [nullAwareAccess_rightBegin] should
/// be called once upon reaching each `?.`, but [nullAwareAccess_end] should
/// not be called until after processing the method call to `z(x)`.
- ///
- /// Return value indicates whether flow analysis believes that a null target
- /// is reachable. If `false` is returned, the client should ensure that
- /// `x?.y` behaves like `x!.y`. (Note that this is necessary even if `y`
- /// exists on `Object`--see
- /// https://github.com/dart-lang/language/issues/1143#issuecomment-682096575.)
- bool nullAwareAccess_rightBegin(Expression target, Type targetType);
+ void nullAwareAccess_rightBegin(Expression target);
/// Call this method when encountering an expression that is a `null` literal.
void nullLiteral(Expression expression);
@@ -845,17 +811,15 @@
}
@override
- bool equalityOp_end(Expression wholeExpression, Expression rightOperand,
+ void equalityOp_end(Expression wholeExpression, Expression rightOperand,
Type rightOperandType,
{bool notEqual = false}) {
- return _wrap(
+ _wrap(
'equalityOp_end($wholeExpression, $rightOperand, $rightOperandType, '
'notEqual: $notEqual)',
() => _wrapped.equalityOp_end(
wholeExpression, rightOperand, rightOperandType,
- notEqual: notEqual),
- isQuery: true,
- isPure: false);
+ notEqual: notEqual));
}
@override
@@ -938,14 +902,9 @@
}
@override
- bool ifNullExpression_rightBegin(
- Expression leftHandSide, Type leftHandSideType) {
- return _wrap(
- 'ifNullExpression_rightBegin($leftHandSide, $leftHandSideType)',
- () => _wrapped.ifNullExpression_rightBegin(
- leftHandSide, leftHandSideType),
- isQuery: true,
- isPure: false);
+ void ifNullExpression_rightBegin(Expression leftHandSide) {
+ return _wrap('ifNullExpression_rightBegin($leftHandSide)',
+ () => _wrapped.ifNullExpression_rightBegin(leftHandSide));
}
@override
@@ -972,14 +931,12 @@
}
@override
- bool isExpression_end(Expression isExpression, Expression subExpression,
+ void isExpression_end(Expression isExpression, Expression subExpression,
bool isNot, Type type) {
- return _wrap(
+ _wrap(
'isExpression_end($isExpression, $subExpression, $isNot, $type)',
- () =>
- _wrapped.isExpression_end(isExpression, subExpression, isNot, type),
- isQuery: true,
- isPure: false);
+ () => _wrapped.isExpression_end(
+ isExpression, subExpression, isNot, type));
}
@override
@@ -1034,10 +991,9 @@
}
@override
- bool nullAwareAccess_rightBegin(Expression target, Type targetType) {
- return _wrap('nullAwareAccess_rightBegin($target, $targetType)',
- () => _wrapped.nullAwareAccess_rightBegin(target, targetType),
- isQuery: true, isPure: false);
+ void nullAwareAccess_rightBegin(Expression target) {
+ _wrap('nullAwareAccess_rightBegin($target)',
+ () => _wrapped.nullAwareAccess_rightBegin(target));
}
@override
@@ -2500,7 +2456,7 @@
}
@override
- bool equalityOp_end(Expression wholeExpression, Expression rightOperand,
+ void equalityOp_end(Expression wholeExpression, Expression rightOperand,
Type rightOperandType,
{bool notEqual = false}) {
_EqualityOpContext<Variable, Type> context =
@@ -2515,16 +2471,14 @@
typeOperations.classifyType(rightOperandType);
if (leftOperandTypeClassification == TypeClassification.nullOrEquivalent &&
rightOperandTypeClassification == TypeClassification.nullOrEquivalent) {
- booleanLiteral(wholeExpression, !notEqual);
- return true;
+ return booleanLiteral(wholeExpression, !notEqual);
} else if ((leftOperandTypeClassification ==
TypeClassification.nullOrEquivalent &&
rightOperandTypeClassification == TypeClassification.nonNullable) ||
(rightOperandTypeClassification ==
TypeClassification.nullOrEquivalent &&
leftOperandTypeClassification == TypeClassification.nonNullable)) {
- booleanLiteral(wholeExpression, notEqual);
- return false;
+ return booleanLiteral(wholeExpression, notEqual);
} else if (lhsInfo is _NullInfo<Variable, Type> &&
rhsInfo is _VariableReadInfo<Variable, Type>) {
assert(
@@ -2536,11 +2490,10 @@
equalityInfo =
_current.tryMarkNonNullable(typeOperations, lhsInfo._variable);
} else {
- return true;
+ return;
}
_storeExpressionInfo(wholeExpression,
notEqual ? equalityInfo : ExpressionInfo.invert(equalityInfo));
- return equalityInfo.ifFalse.reachable;
}
@override
@@ -2666,8 +2619,7 @@
}
@override
- bool ifNullExpression_rightBegin(
- Expression leftHandSide, Type leftHandSideType) {
+ void ifNullExpression_rightBegin(Expression leftHandSide) {
ExpressionInfo<Variable, Type> lhsInfo = _getExpressionInfo(leftHandSide);
FlowModel<Variable, Type> promoted;
if (lhsInfo is _VariableReadInfo<Variable, Type>) {
@@ -2678,12 +2630,7 @@
} else {
promoted = _current;
}
- if (typeOperations.classifyType(leftHandSideType) ==
- TypeClassification.nonNullable) {
- _current = _current.setReachable(false);
- }
_stack.add(new _SimpleContext<Variable, Type>(promoted));
- return _current.reachable;
}
@override
@@ -2723,7 +2670,7 @@
}
@override
- bool isExpression_end(Expression isExpression, Expression subExpression,
+ void isExpression_end(Expression isExpression, Expression subExpression,
bool isNot, Type type) {
ExpressionInfo<Variable, Type> subExpressionInfo =
_getExpressionInfo(subExpression);
@@ -2731,13 +2678,12 @@
if (subExpressionInfo is _VariableReadInfo<Variable, Type>) {
variable = subExpressionInfo._variable;
} else {
- return true;
+ return;
}
ExpressionInfo<Variable, Type> expressionInfo =
_current.tryPromoteForTypeCheck(typeOperations, variable, type);
_storeExpressionInfo(isExpression,
isNot ? ExpressionInfo.invert(expressionInfo) : expressionInfo);
- return expressionInfo.ifFalse.reachable;
}
@override
@@ -2814,16 +2760,8 @@
}
@override
- bool nullAwareAccess_rightBegin(Expression target, Type targetType) {
- assert(targetType != null);
- bool shortingIsReachable = true;
- FlowModel<Variable, Type> shortingModel = _current;
- if (typeOperations.classifyType(targetType) ==
- TypeClassification.nonNullable) {
- shortingModel = shortingModel.setReachable(false);
- shortingIsReachable = false;
- }
- _stack.add(new _SimpleContext<Variable, Type>(shortingModel));
+ void nullAwareAccess_rightBegin(Expression target) {
+ _stack.add(new _SimpleContext<Variable, Type>(_current));
if (target != null) {
ExpressionInfo<Variable, Type> targetInfo = _getExpressionInfo(target);
if (targetInfo is _VariableReadInfo<Variable, Type>) {
@@ -2832,7 +2770,6 @@
.ifTrue;
}
}
- return shortingIsReachable;
}
@override
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 d512956..09e6023 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
@@ -185,76 +185,15 @@
var nullExpr = _Expression();
flow.nullLiteral(nullExpr);
var expr = _Expression();
- var successIsReachable =
- flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: true);
- expect(successIsReachable, true);
+ flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: true);
flow.ifStatement_thenBegin(expr);
- expect(flow.isReachable, true);
expect(flow.promotedType(x).type, 'int');
flow.ifStatement_elseBegin();
- expect(flow.isReachable, true);
expect(flow.promotedType(x), isNull);
flow.ifStatement_end(true);
});
});
- test('equalityOp(x != null) when x is non-nullable', () {
- var h = _Harness();
- var x = h.addVar('x', 'int');
- h.run((flow) {
- h.declare(x, initialized: true);
- var varExpr = _Expression();
- flow.variableRead(varExpr, x);
- flow.equalityOp_rightBegin(varExpr, _Type('int'));
- var nullExpr = _Expression();
- flow.nullLiteral(nullExpr);
- var expr = _Expression();
- var successIsReachable =
- flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: true);
- expect(successIsReachable, false);
- flow.ifStatement_thenBegin(expr);
- expect(flow.isReachable, true);
- expect(flow.promotedType(x), isNull);
- flow.ifStatement_elseBegin();
- expect(flow.isReachable, false);
- expect(flow.promotedType(x), isNull);
- flow.ifStatement_end(true);
- });
- });
-
- test('equalityOp(<expr> == <expr>) has no special effect', () {
- var h = _Harness();
- h.run((flow) {
- flow.equalityOp_rightBegin(_Expression(), _Type('int?'));
- var expr = _Expression();
- var successIsReachable = flow.equalityOp_end(
- expr, _Expression(), _Type('int?'),
- notEqual: false);
- expect(successIsReachable, true);
- flow.ifStatement_thenBegin(expr);
- expect(flow.isReachable, true);
- flow.ifStatement_elseBegin();
- expect(flow.isReachable, true);
- flow.ifStatement_end(true);
- });
- });
-
- test('equalityOp(<expr> != <expr>) has no special effect', () {
- var h = _Harness();
- h.run((flow) {
- flow.equalityOp_rightBegin(_Expression(), _Type('int?'));
- var expr = _Expression();
- var successIsReachable = flow
- .equalityOp_end(expr, _Expression(), _Type('int?'), notEqual: true);
- expect(successIsReachable, true);
- flow.ifStatement_thenBegin(expr);
- expect(flow.isReachable, true);
- flow.ifStatement_elseBegin();
- expect(flow.isReachable, true);
- flow.ifStatement_end(true);
- });
- });
-
test('equalityOp(x != <null expr>) does not promote', () {
var h = _Harness();
var x = h.addVar('x', 'int?');
@@ -285,43 +224,15 @@
var nullExpr = _Expression();
flow.nullLiteral(nullExpr);
var expr = _Expression();
- var successIsReachable =
- flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: false);
- expect(successIsReachable, true);
+ flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: false);
flow.ifStatement_thenBegin(expr);
- expect(flow.isReachable, true);
expect(flow.promotedType(x), isNull);
flow.ifStatement_elseBegin();
- expect(flow.isReachable, true);
expect(flow.promotedType(x).type, 'int');
flow.ifStatement_end(true);
});
});
- test('equalityOp(x == null) when x is non-nullable', () {
- var h = _Harness();
- var x = h.addVar('x', 'int');
- h.run((flow) {
- h.declare(x, initialized: true);
- var varExpr = _Expression();
- flow.variableRead(varExpr, x);
- flow.equalityOp_rightBegin(varExpr, _Type('int'));
- var nullExpr = _Expression();
- flow.nullLiteral(nullExpr);
- var expr = _Expression();
- var successIsReachable =
- flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: false);
- expect(successIsReachable, false);
- flow.ifStatement_thenBegin(expr);
- expect(flow.isReachable, false);
- expect(flow.promotedType(x), isNull);
- flow.ifStatement_elseBegin();
- expect(flow.isReachable, true);
- expect(flow.promotedType(x), isNull);
- flow.ifStatement_end(true);
- });
- });
-
test('equalityOp(null != x) promotes true branch', () {
var h = _Harness();
var x = h.addVar('x', 'int?');
@@ -388,9 +299,7 @@
flow.equalityOp_rightBegin(null1, _Type('Null'));
var null2 = _Expression();
var expr = _Expression();
- var successIsReachable =
- flow.equalityOp_end(expr, null2, _Type('Null'));
- expect(successIsReachable, true);
+ flow.equalityOp_end(expr, null2, _Type('Null'));
flow.ifStatement_thenBegin(expr);
expect(flow.isReachable, true);
flow.ifStatement_elseBegin();
@@ -406,9 +315,7 @@
flow.equalityOp_rightBegin(null1, _Type('Null'));
var null2 = _Expression();
var expr = _Expression();
- var successIsReachable =
- flow.equalityOp_end(expr, null2, _Type('Null'), notEqual: true);
- expect(successIsReachable, true);
+ flow.equalityOp_end(expr, null2, _Type('Null'), notEqual: true);
flow.ifStatement_thenBegin(expr);
expect(flow.isReachable, false);
flow.ifStatement_elseBegin();
@@ -424,8 +331,7 @@
flow.equalityOp_rightBegin(null1, _Type('Null'));
var null2 = _Expression();
var expr = _Expression();
- var successIsReachable = flow.equalityOp_end(expr, null2, _Type('int'));
- expect(successIsReachable, false);
+ flow.equalityOp_end(expr, null2, _Type('int'));
flow.ifStatement_thenBegin(expr);
expect(flow.isReachable, false);
flow.ifStatement_elseBegin();
@@ -441,9 +347,7 @@
flow.equalityOp_rightBegin(null1, _Type('Null'));
var null2 = _Expression();
var expr = _Expression();
- var successIsReachable =
- flow.equalityOp_end(expr, null2, _Type('int'), notEqual: true);
- expect(successIsReachable, false);
+ flow.equalityOp_end(expr, null2, _Type('int'), notEqual: true);
flow.ifStatement_thenBegin(expr);
expect(flow.isReachable, true);
flow.ifStatement_elseBegin();
@@ -459,9 +363,7 @@
flow.equalityOp_rightBegin(null1, _Type('int'));
var null2 = _Expression();
var expr = _Expression();
- var successIsReachable =
- flow.equalityOp_end(expr, null2, _Type('Null'));
- expect(successIsReachable, false);
+ flow.equalityOp_end(expr, null2, _Type('Null'));
flow.ifStatement_thenBegin(expr);
expect(flow.isReachable, false);
flow.ifStatement_elseBegin();
@@ -477,9 +379,7 @@
flow.equalityOp_rightBegin(null1, _Type('int'));
var null2 = _Expression();
var expr = _Expression();
- var successIsReachable =
- flow.equalityOp_end(expr, null2, _Type('Null'), notEqual: true);
- expect(successIsReachable, false);
+ flow.equalityOp_end(expr, null2, _Type('Null'), notEqual: true);
flow.ifStatement_thenBegin(expr);
expect(flow.isReachable, true);
flow.ifStatement_elseBegin();
@@ -985,14 +885,10 @@
h.assignedVariables((vars) => vars.write(x));
h.run((flow) {
h.declare(x, initialized: true);
- var rhsIsReachable = flow.ifNullExpression_rightBegin(
- h.variableRead(x)(), _Type('int?'));
- expect(rhsIsReachable, true);
- expect(flow.isReachable, true);
+ flow.ifNullExpression_rightBegin(h.variableRead(x)());
flow.write(x, _Type('int'));
expect(flow.promotedType(x).type, 'int');
flow.ifNullExpression_end();
- expect(flow.isReachable, true);
expect(flow.promotedType(x).type, 'int');
});
});
@@ -1002,14 +898,10 @@
var x = h.addVar('x', 'int?');
h.run((flow) {
h.declare(x, initialized: true);
- var rhsIsReachable = flow.ifNullExpression_rightBegin(
- h.variableRead(x)(), _Type('int?'));
- expect(rhsIsReachable, true);
- expect(flow.isReachable, true);
+ flow.ifNullExpression_rightBegin(h.variableRead(x)());
h.promote(x, 'int');
expect(flow.promotedType(x).type, 'int');
flow.ifNullExpression_end();
- expect(flow.isReachable, true);
expect(flow.promotedType(x).type, 'int');
});
});
@@ -1019,43 +911,14 @@
var x = h.addVar('x', 'int?');
h.run((flow) {
h.declare(x, initialized: true);
- var rhsIsReachable =
- flow.ifNullExpression_rightBegin(h.expr(), _Type('int?'));
- expect(rhsIsReachable, true);
- expect(flow.isReachable, true);
+ flow.ifNullExpression_rightBegin(h.expr());
h.promote(x, 'int');
expect(flow.promotedType(x).type, 'int');
flow.ifNullExpression_end();
- expect(flow.isReachable, true);
expect(flow.promotedType(x), null);
});
});
- test('ifNullExpression detects when RHS is unreachable', () {
- var h = _Harness();
- h.run((flow) {
- var rhsIsReachable =
- flow.ifNullExpression_rightBegin(h.expr(), _Type('int'));
- expect(rhsIsReachable, false);
- expect(flow.isReachable, false);
- flow.ifNullExpression_end();
- expect(flow.isReachable, true);
- });
- });
-
- test('ifNullExpression determines reachability correctly for `Null` type',
- () {
- var h = _Harness();
- h.run((flow) {
- var rhsIsReachable =
- flow.ifNullExpression_rightBegin(h.expr(), _Type('Null'));
- expect(rhsIsReachable, true);
- expect(flow.isReachable, true);
- flow.ifNullExpression_end();
- expect(flow.isReachable, true);
- });
- });
-
test('ifStatement_end(false) keeps else branch if then branch exits', () {
var h = _Harness();
var x = h.addVar('x', 'int?');
@@ -1069,12 +932,11 @@
});
void _checkIs(
- String declaredType,
- String tryPromoteType,
- String expectedPromotedTypeThen,
- String expectedPromotedTypeElse,
- bool expectedFailureReachable,
- {bool inverted = false}) {
+ String declaredType,
+ String tryPromoteType,
+ String expectedPromotedTypeThen,
+ String expectedPromotedTypeElse,
+ ) {
var h = _Harness();
var x = h.addVar('x', declaredType);
h.run((flow) {
@@ -1082,18 +944,14 @@
var read = _Expression();
flow.variableRead(read, x);
var expr = _Expression();
- var failureReachable =
- flow.isExpression_end(expr, read, inverted, _Type(tryPromoteType));
- expect(failureReachable, expectedFailureReachable);
+ flow.isExpression_end(expr, read, false, _Type(tryPromoteType));
flow.ifStatement_thenBegin(expr);
- expect(flow.isReachable, inverted ? expectedFailureReachable : true);
if (expectedPromotedTypeThen == null) {
expect(flow.promotedType(x), isNull);
} else {
expect(flow.promotedType(x).type, expectedPromotedTypeThen);
}
flow.ifStatement_elseBegin();
- expect(flow.isReachable, inverted ? true : expectedFailureReachable);
if (expectedPromotedTypeElse == null) {
expect(flow.promotedType(x), isNull);
} else {
@@ -1104,61 +962,15 @@
}
test('isExpression_end promotes to a subtype', () {
- _checkIs('int?', 'int', 'int', 'Never?', true);
- });
-
- test('isExpression_end promotes to a subtype, inverted', () {
- _checkIs('int?', 'int', 'Never?', 'int', true, inverted: true);
+ _checkIs('int?', 'int', 'int', 'Never?');
});
test('isExpression_end does not promote to a supertype', () {
- _checkIs('int', 'int?', null, 'Never', false);
- });
-
- test('isExpression_end does not promote to a supertype, inverted', () {
- _checkIs('int', 'int?', 'Never', null, false, inverted: true);
+ _checkIs('int', 'int?', null, 'Never');
});
test('isExpression_end does not promote to an unrelated type', () {
- _checkIs('int', 'String', null, null, true);
- });
-
- test('isExpression_end does not promote to an unrelated type, inverted',
- () {
- _checkIs('int', 'String', null, null, true, inverted: true);
- });
-
- test('isExpression_end does nothing if applied to a non-variable', () {
- var h = _Harness();
- h.run((flow) {
- var subExpr = _Expression();
- var expr = _Expression();
- var failureReachable =
- flow.isExpression_end(expr, subExpr, false, _Type('int'));
- expect(failureReachable, true);
- flow.ifStatement_thenBegin(expr);
- expect(flow.isReachable, true);
- flow.ifStatement_elseBegin();
- expect(flow.isReachable, true);
- flow.ifStatement_end(true);
- });
- });
-
- test('isExpression_end does nothing if applied to a non-variable, inverted',
- () {
- var h = _Harness();
- h.run((flow) {
- var subExpr = _Expression();
- var expr = _Expression();
- var failureReachable =
- flow.isExpression_end(expr, subExpr, true, _Type('int'));
- expect(failureReachable, true);
- flow.ifStatement_thenBegin(expr);
- expect(flow.isReachable, true);
- flow.ifStatement_elseBegin();
- expect(flow.isReachable, true);
- flow.ifStatement_end(true);
- });
+ _checkIs('int', 'String', null, null);
});
test('isExpression_end() does not promote write-captured vars', () {
@@ -1341,10 +1153,7 @@
h.declare(x, initialized: true);
var varExpr = _Expression();
flow.variableRead(varExpr, x);
- var shortIsReachable =
- flow.nullAwareAccess_rightBegin(varExpr, _Type('int?'));
- expect(shortIsReachable, true);
- expect(flow.isReachable, true);
+ flow.nullAwareAccess_rightBegin(varExpr);
expect(flow.promotedType(x).type, 'int');
flow.nullAwareAccess_end();
expect(flow.promotedType(x), isNull);
@@ -1358,10 +1167,7 @@
h.declare(x, initialized: true);
var varExpr = _Expression();
flow.variableRead(varExpr, x);
- var shortIsReachable =
- flow.nullAwareAccess_rightBegin(null, _Type('int?'));
- expect(shortIsReachable, true);
- expect(flow.isReachable, true);
+ flow.nullAwareAccess_rightBegin(null);
expect(flow.promotedType(x), isNull);
flow.nullAwareAccess_end();
});
@@ -1375,10 +1181,7 @@
h.declare(x, initialized: true);
h.promote(x, 'int');
var lhs = _Expression();
- var shortIsReachable =
- flow.nullAwareAccess_rightBegin(lhs, _Type('int'));
- expect(shortIsReachable, false);
- expect(flow.isReachable, true);
+ flow.nullAwareAccess_rightBegin(lhs);
expect(flow.promotedType(x).type, 'int');
flow.write(x, _Type('int?'));
expect(flow.promotedType(x), isNull);
@@ -1387,24 +1190,6 @@
});
});
- test('nullAwareAccess_end ignores shorting if target is non-nullable', () {
- var h = _Harness();
- var x = h.addVar('x', 'int?');
- h.run((flow) {
- h.declare(x, initialized: true);
- var shortIsReachable =
- flow.nullAwareAccess_rightBegin(_Expression(), _Type('int'));
- expect(shortIsReachable, false);
- expect(flow.isReachable, true);
- h.promote(x, 'int');
- expect(flow.promotedType(x).type, 'int');
- flow.nullAwareAccess_end();
- // `x` should still be promoted because the target was non-nullable, so
- // the null shorting path was unreachable.
- expect(flow.promotedType(x).type, 'int');
- });
- });
-
test('parenthesizedExpression preserves promotion behaviors', () {
var h = _Harness();
var x = h.addVar('x', 'int?');
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/if_null.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/if_null.dart
deleted file mode 100644
index 0cc336e..0000000
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/if_null.dart
+++ /dev/null
@@ -1,331 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-void variable_if_null_reachable(int? i) {
- i ?? 0;
-}
-
-void variable_if_null_assign_reachable(int? i) {
- i ??= 0;
-}
-
-void variable_if_null_unreachable(int i) {
- i ?? /*unreachable*/ 0;
-}
-
-void variable_if_null_assign_unreachable(int i) {
- // Note: CFE reports that the update to `i` is unreachable; analyzer does not.
- // This is ok; what matters is that the RHS is unreachable.
- /*cfe.update: unreachable*/ i ??= /*unreachable*/ 0;
-}
-
-void variable_if_null_assign_unreachable_due_to_promotion(int? i) {
- if (i == null) return;
- // Note: CFE reports that the update to `i` is unreachable; analyzer does not.
- // This is ok; what matters is that the RHS is unreachable.
- /*cfe.update: unreachable*/ i ??= /*unreachable*/ 0;
-}
-
-/*member: topLevelNullable:doesNotComplete*/
-int? get topLevelNullable => 0;
-void set topLevelNullable(int? value) {}
-
-/*member: topLevelNonNullGet:doesNotComplete*/
-int get topLevelNonNullGet => 0;
-void set topLevelNonNullGet(int? value) {}
-
-void top_level_if_null_reachable() {
- topLevelNullable ?? 0;
-}
-
-void top_level_if_null_assign_reachable() {
- topLevelNullable ??= 0;
-}
-
-void top_level_if_null_unreachable() {
- topLevelNonNullGet ?? /*unreachable*/ 0;
-}
-
-void top_level_if_null_assign_unreachable() {
- // Note: CFE reports that the update to `topLevelNonNullGet` is unreachable;
- // analyzer does not. This is ok; what matters is that the RHS is
- // unreachable.
- topLevelNonNullGet /*cfe.update: unreachable*/ ??= /*unreachable*/ 0;
-}
-
-class HasProperty<T> {
- /*member: HasProperty.prop:doesNotComplete*/
- T get prop => throw '';
- set prop(T? value) {}
-}
-
-void property_if_null_reachable(HasProperty<int?> x) {
- x.prop ?? 0;
-}
-
-void property_if_null_assign_reachable(HasProperty<int?> x) {
- x.prop ??= 0;
-}
-
-void property_if_null_unreachable(HasProperty<int> x) {
- x.prop ?? /*unreachable*/ 0;
-}
-
-void property_if_null_assign_unreachable(HasProperty<int> x) {
- x.prop ??= /*unreachable*/ 0;
-}
-
-void null_aware_property_if_null_reachable(HasProperty<int?>? x) {
- x?.prop ?? 0;
-}
-
-void null_aware_property_if_null_assign_reachable(HasProperty<int?>? x) {
- x?.prop ??= 0;
-}
-
-void null_aware_property_if_null_not_shortened(HasProperty<int>? x) {
- // If `??` participated in null-shortening, `0` would be unreachable.
- x?.prop ?? 0;
-}
-
-void null_aware_property_if_null_assign_unreachable(HasProperty<int>? x) {
- x?.prop ??= /*unreachable*/ 0;
-}
-
-class SuperIntQuestionProperty extends HasProperty<int?> {
- void if_null_reachable() {
- super.prop ?? 0;
- }
-
- void if_null_assign_reachable() {
- super.prop ??= 0;
- }
-}
-
-class SuperIntProperty extends HasProperty<int> {
- void if_null_unreachable() {
- super.prop ?? /*unreachable*/ 0;
- }
-
- void if_null_assign_unreachable() {
- super.prop ??= /*unreachable*/ 0;
- }
-}
-
-extension ExtensionProperty<T> on HasProperty<T> {
- /*member: ExtensionProperty|get#extendedProp:doesNotComplete*/
- T get extendedProp => prop;
- set extendedProp(T? value) {
- prop = value;
- }
-}
-
-void extended_property_if_null_reachable(HasProperty<int?> x) {
- x.extendedProp ?? 0;
-}
-
-void extended_property_if_null_assign_reachable(HasProperty<int?> x) {
- x.extendedProp ??= 0;
-}
-
-void extended_property_if_null_unreachable(HasProperty<int> x) {
- x.extendedProp ?? /*unreachable*/ 0;
-}
-
-void extended_property_if_null_assign_unreachable(HasProperty<int> x) {
- x.extendedProp ??= /*unreachable*/ 0;
-}
-
-void null_aware_extended_property_if_null_reachable(HasProperty<int?>? x) {
- x?.extendedProp ?? 0;
-}
-
-void null_aware_extended_property_if_null_assign_reachable(
- HasProperty<int?>? x) {
- x?.extendedProp ??= 0;
-}
-
-void null_aware_extended_property_if_null_not_shortened(HasProperty<int>? x) {
- // If `??` participated in null-shortening, `0` would be unreachable.
- x?.extendedProp ?? 0;
-}
-
-void null_aware_extended_property_if_null_assign_unreachable(
- HasProperty<int>? x) {
- x?.extendedProp ??= /*unreachable*/ 0;
-}
-
-void explicit_extended_property_if_null_reachable(HasProperty<int?> x) {
- ExtensionProperty(x).extendedProp ?? 0;
-}
-
-void explicit_extended_property_if_null_assign_reachable(HasProperty<int?> x) {
- ExtensionProperty(x).extendedProp ??= 0;
-}
-
-void explicit_extended_property_if_null_unreachable(HasProperty<int> x) {
- ExtensionProperty(x).extendedProp ?? /*unreachable*/ 0;
-}
-
-void explicit_extended_property_if_null_assign_unreachable(HasProperty<int> x) {
- ExtensionProperty(x).extendedProp ??= /*unreachable*/ 0;
-}
-
-void null_aware_explicit_extended_property_if_null_reachable(
- HasProperty<int?>? x) {
- ExtensionProperty(x)?.extendedProp ?? 0;
-}
-
-void null_aware_explicit_extended_property_if_null_assign_reachable(
- HasProperty<int?>? x) {
- ExtensionProperty(x)?.extendedProp ??= 0;
-}
-
-void null_aware_explicit_extended_property_if_null_not_shortened(
- HasProperty<int>? x) {
- // If `??` participated in null-shortening, `0` would be unreachable.
- ExtensionProperty(x)?.extendedProp ?? 0;
-}
-
-void null_aware_explicit_extended_property_if_null_assign_unreachable(
- HasProperty<int>? x) {
- ExtensionProperty(x)?.extendedProp ??= /*unreachable*/ 0;
-}
-
-class Indexable<T> {
- /*member: Indexable.[]:doesNotComplete*/
- T operator [](int index) => throw '';
- operator []=(int index, T? value) {}
-}
-
-void index_if_null_reachable(Indexable<int?> x) {
- x[0] ?? 0;
-}
-
-void index_if_null_unreachable(Indexable<int> x) {
- x[0] ?? /*unreachable*/ 0;
-}
-
-void index_if_null_assign_reachable(Indexable<int?> x) {
- x[0] ??= 0;
-}
-
-void index_if_null_assign_unreachable(Indexable<int> x) {
- x[0] ??= /*unreachable*/ 0;
-}
-
-void null_aware_index_if_null_reachable(Indexable<int?>? x) {
- x?[0] ?? 0;
-}
-
-void null_aware_index_if_null_unreachable(Indexable<int>? x) {
- // If `??` participated in null-shortening, `0` would be unreachable.
- x?[0] ?? 0;
-}
-
-void null_aware_index_if_null_assign_reachable(Indexable<int?>? x) {
- x?[0] ??= 0;
-}
-
-void null_aware_index_if_null_assign_unreachable(Indexable<int>? x) {
- x?[0] ??= /*unreachable*/ 0;
-}
-
-class SuperIntQuestionIndex extends Indexable<int?> {
- void if_null_reachable() {
- super[0] ?? 0;
- }
-
- void if_null_assign_reachable() {
- super[0] ??= 0;
- }
-}
-
-class SuperIntIndex extends Indexable<int> {
- void if_null_unreachable() {
- super[0] ?? /*unreachable*/ 0;
- }
-
- void if_null_assign_unreachable() {
- super[0] ??= /*unreachable*/ 0;
- }
-}
-
-extension ExtensionIndex<T> on HasProperty<T> {
- /*member: ExtensionIndex|[]:doesNotComplete*/
- T operator [](int index) => prop;
- operator []=(int index, T? value) {
- prop = value;
- }
-}
-
-void extended_index_if_null_reachable(HasProperty<int?> x) {
- x[0] ?? 0;
-}
-
-void extended_index_if_null_assign_reachable(HasProperty<int?> x) {
- x[0] ??= 0;
-}
-
-void extended_index_if_null_unreachable(HasProperty<int> x) {
- x[0] ?? /*unreachable*/ 0;
-}
-
-void extended_index_if_null_assign_unreachable(HasProperty<int> x) {
- x[0] ??= /*unreachable*/ 0;
-}
-
-void null_aware_extended_index_if_null_reachable(HasProperty<int?>? x) {
- x?[0] ?? 0;
-}
-
-void null_aware_extended_index_if_null_assign_reachable(HasProperty<int?>? x) {
- x?[0] ??= 0;
-}
-
-void null_aware_extended_index_if_null_not_shortened(HasProperty<int>? x) {
- // If `??` participated in null-shortening, `0` would be unreachable.
- x?[0] ?? 0;
-}
-
-void null_aware_extended_index_if_null_assign_unreachable(HasProperty<int>? x) {
- x?[0] ??= /*unreachable*/ 0;
-}
-
-void explicit_extended_index_if_null_reachable(HasProperty<int?> x) {
- ExtensionIndex(x)[0] ?? 0;
-}
-
-void explicit_extended_index_if_null_assign_reachable(HasProperty<int?> x) {
- ExtensionIndex(x)[0] ??= 0;
-}
-
-void explicit_extended_index_if_null_unreachable(HasProperty<int> x) {
- ExtensionIndex(x)[0] ?? /*unreachable*/ 0;
-}
-
-void explicit_extended_index_if_null_assign_unreachable(HasProperty<int> x) {
- ExtensionIndex(x)[0] ??= /*unreachable*/ 0;
-}
-
-void null_aware_explicit_extended_index_if_null_reachable(
- HasProperty<int?>? x) {
- ExtensionIndex(x)?[0] ?? 0;
-}
-
-void null_aware_explicit_extended_index_if_null_assign_reachable(
- HasProperty<int?>? x) {
- ExtensionIndex(x)?[0] ??= 0;
-}
-
-void null_aware_explicit_extended_index_if_null_not_shortened(
- HasProperty<int>? x) {
- // If `??` participated in null-shortening, `0` would be unreachable.
- ExtensionIndex(x)?[0] ?? 0;
-}
-
-void null_aware_explicit_extended_index_if_null_assign_unreachable(
- HasProperty<int>? x) {
- ExtensionIndex(x)?[0] ??= /*unreachable*/ 0;
-}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/null_aware_access.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/null_aware_access.dart
deleted file mode 100644
index a204bf8..0000000
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/null_aware_access.dart
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-void index_reachable(List<int>? f()) {
- f()?[throw ''];
- 0;
-}
-
-/*member: index_unreachable:doesNotComplete*/
-void index_unreachable(List<int> f()) {
- f()?[throw ''];
- /*stmt: unreachable*/ 0;
-}
-
-void cascaded_index_reachable(List<int>? f()) {
- f()?..[throw ''];
- 0;
-}
-
-/*member: cascaded_index_unreachable:doesNotComplete*/
-void cascaded_index_unreachable(List<int> f()) {
- f()?..[throw ''];
- /*stmt: unreachable*/ 0;
-}
-
-void method_invocation_reachable(int? f()) {
- f()?.remainder(throw '');
- 0;
-}
-
-/*member: method_invocation_unreachable:doesNotComplete*/
-void method_invocation_unreachable(int f()) {
- f()?.remainder(throw '');
- /*stmt: unreachable*/ 0;
-}
-
-void cascaded_method_invocation_reachable(int? f()) {
- f()?..remainder(throw '');
- 0;
-}
-
-/*member: cascaded_method_invocation_unreachable:doesNotComplete*/
-void cascaded_method_invocation_unreachable(int f()) {
- f()?..remainder(throw '');
- /*stmt: unreachable*/ 0;
-}
-
-void property_get_reachable(int? f()) {
- f()?.hashCode.remainder(throw '');
- 0;
-}
-
-/*member: property_get_unreachable:doesNotComplete*/
-void property_get_unreachable(int f()) {
- f()?.hashCode.remainder(throw '');
- /*stmt: unreachable*/ 0;
-}
-
-void cascaded_property_get_reachable(int? f()) {
- f()?..hashCode.remainder(throw '');
- 0;
-}
-
-/*member: cascaded_property_get_unreachable:doesNotComplete*/
-void cascaded_property_get_unreachable(int f()) {
- f()?..hashCode.remainder(throw '');
- /*stmt: unreachable*/ 0;
-}
-
-void property_get_invocation_reachable(List<void Function(dynamic)>? f()) {
- // We need a special test case for this because it parses like a method
- // invocation but the analyzer rewrites it as a property access followed by a
- // function expression invocation.
- f()?.first(throw '');
- 0;
-}
-
-/*member: property_get_invocation_unreachable:doesNotComplete*/
-void property_get_invocation_unreachable(List<void Function(dynamic)> f()) {
- // We need a special test case for this because it parses like a method
- // invocation but the analyzer rewrites it as a property access followed by a
- // function expression invocation.
- f()?.first(throw '');
- /*stmt: unreachable*/ 0;
-}
-
-void cascaded_property_get_invocation_reachable(
- List<void Function(dynamic)>? f()) {
- // We need a special test case for this because it parses like a method
- // invocation but the analyzer rewrites it as a property access followed by a
- // function expression invocation.
- f()?..first(throw '');
- 0;
-}
-
-/*member: cascaded_property_get_invocation_unreachable:doesNotComplete*/
-void cascaded_property_get_invocation_unreachable(
- List<void Function(dynamic)> f()) {
- // We need a special test case for this because it parses like a method
- // invocation but the analyzer rewrites it as a property access followed by a
- // function expression invocation.
- f()?..first(throw '');
- /*stmt: unreachable*/ 0;
-}
-
-class C {
- int field = 0;
-}
-
-void property_set_reachable(C? f()) {
- f()?.field = throw '';
- 0;
-}
-
-/*member: property_set_unreachable:doesNotComplete*/
-void property_set_unreachable(C f()) {
- f()?.field = throw '';
- /*stmt: unreachable*/ 0;
-}
-
-void cascaded_property_set_reachable(C? f()) {
- f()?..field = throw '';
- 0;
-}
-
-/*member: cascaded_property_set_unreachable:doesNotComplete*/
-void cascaded_property_set_unreachable(C f()) {
- f()?..field = throw '';
- /*stmt: unreachable*/ 0;
-}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/null_aware_access_static.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/null_aware_access_static.dart
deleted file mode 100644
index 4edebe4..0000000
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/null_aware_access_static.dart
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-class C {
- static void staticMethod(dynamic d) {}
- /*member: C.staticGetter:doesNotComplete*/
- static int get staticGetter => 0;
- /*member: C.staticInvokableGetter:doesNotComplete*/
- static void Function(dynamic d) get staticInvokableGetter => (_) {};
- static void set staticSetter(int value) {}
-}
-
-/*member: method_invocation_unreachable:doesNotComplete*/
-void method_invocation_unreachable() {
- C?.staticMethod(throw '');
- /*stmt: unreachable*/ 0;
-}
-
-/*member: property_get_unreachable:doesNotComplete*/
-void property_get_unreachable() {
- C?.staticGetter.remainder(throw '');
- /*stmt: unreachable*/ 0;
-}
-
-/*member: property_get_invocation_unreachable:doesNotComplete*/
-void property_get_invocation_unreachable() {
- // We need a special test case for this because it parses like a method
- // invocation but the analyzer rewrites it as a property access followed by a
- // function expression invocation.
- C?.staticInvokableGetter(throw '');
- /*stmt: unreachable*/ 0;
-}
-
-/*member: property_set_unreachable:doesNotComplete*/
-void property_set_unreachable() {
- C?.staticSetter = throw '';
- /*stmt: unreachable*/ 0;
-}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart
index 28948d0..32b927a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_if_null_operator_test.dart
@@ -5,7 +5,6 @@
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
-import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -32,10 +31,7 @@
''');
await assertHasFix('''
int f(int a, int b) => a;
-''', errorFilter: (e) {
- // See https://github.com/dart-lang/sdk/issues/43263.
- return e.errorCode != HintCode.DEAD_CODE;
- });
+''');
}
Future<void> test_nestedChild() async {
@@ -44,10 +40,7 @@
''');
await assertHasFix('''
int f(int a, int b) => a;
-''', errorFilter: (e) {
- // See https://github.com/dart-lang/sdk/issues/43263.
- return e.errorCode != HintCode.DEAD_CODE;
- });
+''');
}
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
index c0a9af2..274b4be 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -466,7 +466,7 @@
var flow = _flowAnalysis?.flow;
if (flow != null && operator == TokenType.QUESTION_QUESTION_EQ) {
- flow.ifNullExpression_rightBegin(left, leftType);
+ flow.ifNullExpression_rightBegin(left);
}
right?.accept(_resolver);
diff --git a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
index ddab194..fe41371 100644
--- a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -178,7 +178,7 @@
}
InferenceContext.setType(right, rightContextType);
- flow?.ifNullExpression_rightBegin(left, leftType);
+ flow?.ifNullExpression_rightBegin(left);
right.accept(_resolver);
right = node.rightOperand;
flow?.ifNullExpression_end();
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index 915f509..1c2938f1 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -85,7 +85,7 @@
if (flow == null) return null;
if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
- flow.ifNullExpression_rightBegin(node.leftHandSide, node.readType);
+ flow.ifNullExpression_rightBegin(node.leftHandSide);
}
}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index d1fedd3..0c60e48 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -850,8 +850,7 @@
node.target.accept(this);
if (node.isNullAware && _isNonNullableByDefault) {
- _flowAnalysis.flow.nullAwareAccess_rightBegin(
- node.target, node.target.staticType ?? typeProvider.dynamicType);
+ _flowAnalysis.flow.nullAwareAccess_rightBegin(node.target);
_unfinishedNullShorts.add(node.nullShortingTermination);
}
@@ -1448,8 +1447,7 @@
node.target?.accept(this);
if (_migratableAstInfoProvider.isIndexExpressionNullAware(node) &&
_isNonNullableByDefault) {
- _flowAnalysis.flow.nullAwareAccess_rightBegin(
- node.target, node.realTarget.staticType ?? typeProvider.dynamicType);
+ _flowAnalysis.flow.nullAwareAccess_rightBegin(node.target);
_unfinishedNullShorts.add(node.nullShortingTermination);
}
node.accept(elementResolver);
@@ -1536,18 +1534,12 @@
@override
void visitMethodInvocation(MethodInvocation node) {
- var target = node.target;
- target?.accept(this);
+ node.target?.accept(this);
if (_migratableAstInfoProvider.isMethodInvocationNullAware(node) &&
_isNonNullableByDefault) {
- if (target is SimpleIdentifier && target.staticElement is ClassElement) {
- // `?.` to access static methods is equivalent to `.`, so do nothing.
- } else {
- _flowAnalysis.flow.nullAwareAccess_rightBegin(
- target, node.realTarget.staticType ?? typeProvider.dynamicType);
- _unfinishedNullShorts.add(node.nullShortingTermination);
- }
+ _flowAnalysis.flow.nullAwareAccess_rightBegin(node.target);
+ _unfinishedNullShorts.add(node.nullShortingTermination);
}
node.typeArguments?.accept(this);
@@ -1640,17 +1632,11 @@
// We visit the target, but do not visit the property name because it needs
// to be visited in the context of the property access node.
//
- var target = node.target;
- target?.accept(this);
+ node.target?.accept(this);
if (_migratableAstInfoProvider.isPropertyAccessNullAware(node) &&
_isNonNullableByDefault) {
- if (target is SimpleIdentifier && target.staticElement is ClassElement) {
- // `?.` to access static methods is equivalent to `.`, so do nothing.
- } else {
- _flowAnalysis.flow.nullAwareAccess_rightBegin(
- target, node.realTarget.staticType ?? typeProvider.dynamicType);
- _unfinishedNullShorts.add(node.nullShortingTermination);
- }
+ _flowAnalysis.flow.nullAwareAccess_rightBegin(node.target);
+ _unfinishedNullShorts.add(node.nullShortingTermination);
}
node.accept(elementResolver);
node.accept(typeAnalyzer);
@@ -2020,14 +2006,8 @@
if (function is PropertyAccess &&
_migratableAstInfoProvider.isPropertyAccessNullAware(function) &&
_isNonNullableByDefault) {
- var target = function.target;
- if (target is SimpleIdentifier && target.staticElement is ClassElement) {
- // `?.` to access static methods is equivalent to `.`, so do nothing.
- } else {
- _flowAnalysis.flow.nullAwareAccess_rightBegin(function,
- function.realTarget.staticType ?? typeProvider.dynamicType);
- _unfinishedNullShorts.add(node.nullShortingTermination);
- }
+ _flowAnalysis.flow.nullAwareAccess_rightBegin(function);
+ _unfinishedNullShorts.add(node.nullShortingTermination);
}
_functionExpressionInvocationResolver.resolve(node);
diff --git a/pkg/analyzer/lib/src/util/ast_data_extractor.dart b/pkg/analyzer/lib/src/util/ast_data_extractor.dart
index 2147db8..06fdab9 100644
--- a/pkg/analyzer/lib/src/util/ast_data_extractor.dart
+++ b/pkg/analyzer/lib/src/util/ast_data_extractor.dart
@@ -84,13 +84,6 @@
var memberName = element.name;
var className = element.enclosingElement.name;
return MemberId.internal(memberName, className: className);
- } else if (element.enclosingElement is ExtensionElement) {
- var memberName = element.name;
- var extensionName = element.enclosingElement.name;
- if (element is PropertyAccessorElement) {
- memberName = '${element.isGetter ? 'get' : 'set'}#$memberName';
- }
- return MemberId.internal('$extensionName|$memberName');
}
throw UnimplementedError(
'TODO(paulberry): $element (${element.runtimeType})');
diff --git a/pkg/analyzer/test/src/diagnostics/dead_null_aware_expression_test.dart b/pkg/analyzer/test/src/diagnostics/dead_null_aware_expression_test.dart
index e60e478..c1e4746 100644
--- a/pkg/analyzer/test/src/diagnostics/dead_null_aware_expression_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/dead_null_aware_expression_test.dart
@@ -22,16 +22,13 @@
var x = 0;
''');
- await assertErrorsInCode('''
+ await assertNoErrorsInCode('''
import 'a.dart';
f() {
x ??= 0;
}
-''', [
- // See https://github.com/dart-lang/sdk/issues/43263.
- error(HintCode.DEAD_CODE, 32, 2),
- ]);
+''');
}
test_assignCompound_map() async {
@@ -54,8 +51,6 @@
}
''', [
error(StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION, 19, 1),
- // See https://github.com/dart-lang/sdk/issues/43263.
- error(HintCode.DEAD_CODE, 19, 2),
]);
}
@@ -73,16 +68,13 @@
var x = 0;
''');
- await assertErrorsInCode('''
+ await assertNoErrorsInCode('''
import 'a.dart';
f() {
x ?? 0;
}
-''', [
- // See https://github.com/dart-lang/sdk/issues/43263.
- error(HintCode.DEAD_CODE, 31, 2),
- ]);
+''');
}
test_binary_nonNullable() async {
@@ -92,8 +84,6 @@
}
''', [
error(StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION, 18, 1),
- // See https://github.com/dart-lang/sdk/issues/43263.
- error(HintCode.DEAD_CODE, 18, 2),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/not_assigned_potentially_non_nullable_local_variable_test.dart b/pkg/analyzer/test/src/diagnostics/not_assigned_potentially_non_nullable_local_variable_test.dart
index df5882b..1caa9cc 100644
--- a/pkg/analyzer/test/src/diagnostics/not_assigned_potentially_non_nullable_local_variable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_assigned_potentially_non_nullable_local_variable_test.dart
@@ -84,8 +84,6 @@
}
''', [
_notAssignedError(22, 1),
- // See https://github.com/dart-lang/sdk/issues/43263.
- error(HintCode.DEAD_CODE, 28, 2),
error(StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION, 28, 1),
]);
}
@@ -98,8 +96,6 @@
}
''', [
_notAssignedError(22, 1),
- // See https://github.com/dart-lang/sdk/issues/43263.
- error(HintCode.DEAD_CODE, 28, 2),
error(StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION, 28, 1),
_notAssignedError(28, 1),
]);
@@ -122,11 +118,7 @@
(v = 0) ?? 0;
v;
}
-''', [
- error(StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION, 33, 1),
- // See https://github.com/dart-lang/sdk/issues/43263.
- error(HintCode.DEAD_CODE, 33, 7),
- ]);
+''', [error(StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION, 33, 1)]);
}
test_binaryExpression_ifNull_right() async {
@@ -138,8 +130,6 @@
}
''', [
error(StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION, 32, 7),
- // See https://github.com/dart-lang/sdk/issues/43263.
- error(HintCode.DEAD_CODE, 32, 13),
_notAssignedError(43, 1),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
index a668a46..0552343 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
@@ -409,4 +409,10 @@
int f() => A.x;
''');
}
+
+ @override
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/42957')
+ test_typeLiteral_conditionalAccess() {
+ return super.test_typeLiteral_conditionalAccess();
+ }
}
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 ec7bc61..74b894e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -1159,8 +1159,7 @@
lhsResult.inferredType, equalsName, node.fileOffset)
.member;
- inferrer.flowAnalysis
- .ifNullExpression_rightBegin(node.left, lhsResult.inferredType);
+ inferrer.flowAnalysis.ifNullExpression_rightBegin(node.left);
// - Let J = T0 if K is `?` else K.
// - Infer e1 in context J to get T1
ExpressionInferenceResult rhsResult;
@@ -2671,7 +2670,7 @@
Expression read = readResult.expression;
DartType readType = readResult.inferredType;
- inferrer.flowAnalysis.ifNullExpression_rightBegin(read, readType);
+ inferrer.flowAnalysis.ifNullExpression_rightBegin(read);
ExpressionInferenceResult writeResult = inferrer
.inferExpression(node.write, typeContext, true, isVoidAllowed: true);
inferrer.flowAnalysis.ifNullExpression_end();
@@ -2743,7 +2742,7 @@
read = readResult.expression;
readType = readResult.inferredType;
}
- inferrer.flowAnalysis.ifNullExpression_rightBegin(read, readType);
+ inferrer.flowAnalysis.ifNullExpression_rightBegin(read);
ExpressionInferenceResult writeResult = inferrer
.inferExpression(node.write, typeContext, true, isVoidAllowed: true);
inferrer.flowAnalysis.ifNullExpression_end();
@@ -3099,7 +3098,7 @@
readResult.inferredType, "??=", node.readOffset);
Expression read = readResult.expression;
DartType readType = readResult.inferredType;
- inferrer.flowAnalysis.ifNullExpression_rightBegin(read, readType);
+ inferrer.flowAnalysis.ifNullExpression_rightBegin(read);
Member equalsMember = inferrer
.findInterfaceMember(readType, equalsName, node.testOffset)
@@ -3270,7 +3269,7 @@
..fileOffset = node.readOffset;
}
- inferrer.flowAnalysis.ifNullExpression_rightBegin(read, readType);
+ inferrer.flowAnalysis.ifNullExpression_rightBegin(read);
ExpressionInferenceResult valueResult = inferrer
.inferExpression(node.value, valueType, true, isVoidAllowed: true);
Expression value = inferrer.ensureAssignableResult(valueType, valueResult);
@@ -3424,7 +3423,7 @@
readResult.inferredType, "??=", node.readOffset);
Expression read = readResult.expression;
DartType readType = readResult.inferredType;
- inferrer.flowAnalysis.ifNullExpression_rightBegin(read, readType);
+ inferrer.flowAnalysis.ifNullExpression_rightBegin(read);
Member equalsMember = inferrer
.findInterfaceMember(readType, equalsName, node.testOffset)
@@ -4904,7 +4903,7 @@
isThisReceiver: node.receiver is ThisExpression);
Expression read = readResult.expression;
DartType readType = readResult.inferredType;
- inferrer.flowAnalysis.ifNullExpression_rightBegin(read, readType);
+ inferrer.flowAnalysis.ifNullExpression_rightBegin(read);
Member readEqualsMember = inferrer
.findInterfaceMember(readType, equalsName, node.testOffset)
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 2d855ee8..0603833 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
@@ -3814,15 +3814,14 @@
assert(_inferrer != null) {
// Ensure the initializer of [_nullAwareVariable] is promoted to
// non-nullable.
- _inferrer.flowAnalysis.nullAwareAccess_rightBegin(
- _nullAwareVariable.initializer, _nullAwareVariable.type);
+ _inferrer.flowAnalysis
+ .nullAwareAccess_rightBegin(_nullAwareVariable.initializer);
// Ensure [_nullAwareVariable] is promoted to non-nullable.
// TODO(johnniwinther): Avoid creating a [VariableGet] to promote the
// variable.
VariableGet read = new VariableGet(_nullAwareVariable);
_inferrer.flowAnalysis.variableRead(read, _nullAwareVariable);
- _inferrer.flowAnalysis
- .nullAwareAccess_rightBegin(read, _nullAwareVariable.type);
+ _inferrer.flowAnalysis.nullAwareAccess_rightBegin(read);
}
/// Creates the null-guarded application of [nullAwareAction] with the
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index c9f67ed..81e9982 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -276,7 +276,6 @@
behaviors
behind
being
-believes
belong
belongs
below
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index b59c9c5..c61bc53 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -456,7 +456,7 @@
} else if (operatorType == TokenType.QUESTION_QUESTION) {
DecoratedType expressionType;
var leftType = _dispatch(leftOperand);
- _flowAnalysis.ifNullExpression_rightBegin(node.leftOperand, leftType);
+ _flowAnalysis.ifNullExpression_rightBegin(node.leftOperand);
try {
_guards.add(leftType.node);
DecoratedType rightType;
@@ -2210,8 +2210,8 @@
if (questionAssignNode != null) {
_guards.add(destinationType.node);
- _flowAnalysis.ifNullExpression_rightBegin(
- questionAssignNode.leftHandSide, destinationType);
+ _flowAnalysis
+ .ifNullExpression_rightBegin(questionAssignNode.leftHandSide);
}
DecoratedType sourceType;
try {