Skip to content

Commit ff8b437

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Move reporting INVALID_ASSIGNMENT for compound assignments into StaticTypeAnalyzer.
[email protected] Change-Id: Ia5355023ff5873c7d10eb60b85c5fd8a41dea417 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/115800 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent cf5e9ca commit ff8b437

File tree

5 files changed

+78
-98
lines changed

5 files changed

+78
-98
lines changed

pkg/analyzer/lib/src/generated/error_verifier.dart

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,6 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
418418
operatorType == TokenType.QUESTION_QUESTION_EQ) {
419419
_checkForInvalidAssignment(lhs, rhs);
420420
} else {
421-
_checkForInvalidCompoundAssignment(node, lhs, rhs);
422421
_checkForArgumentTypeNotAssignableForArgument(rhs);
423422
_checkForNullableDereference(lhs);
424423
}
@@ -3474,27 +3473,6 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
34743473
rhs, leftType, StaticTypeWarningCode.INVALID_ASSIGNMENT);
34753474
}
34763475

3477-
/**
3478-
* Given an [assignment] using a compound assignment operator, this verifies
3479-
* that the given assignment is valid. The [lhs] is the left hand side
3480-
* expression. The [rhs] is the right hand side expression.
3481-
*
3482-
* See [StaticTypeWarningCode.INVALID_ASSIGNMENT].
3483-
*/
3484-
void _checkForInvalidCompoundAssignment(
3485-
AssignmentExpression assignment, Expression lhs, Expression rhs) {
3486-
if (lhs == null) {
3487-
return;
3488-
}
3489-
DartType leftType = getStaticType(lhs);
3490-
DartType rightType = getStaticType(assignment);
3491-
if (!_typeSystem.isAssignableTo(rightType, leftType,
3492-
featureSet: _featureSet)) {
3493-
_errorReporter.reportTypeErrorForNode(
3494-
StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [rightType, leftType]);
3495-
}
3496-
}
3497-
34983476
/**
34993477
* Check the given [initializer] to ensure that the field being initialized is
35003478
* a valid field. The [fieldName] is the field name from the

pkg/analyzer/lib/src/generated/static_type_analyzer.dart

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -322,15 +322,26 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
322322
operator == TokenType.BAR_BAR_EQ) {
323323
_recordStaticType(node, _nonNullable(_typeProvider.boolType));
324324
} else {
325-
ExecutableElement staticMethodElement = node.staticElement;
326-
DartType staticType = _computeStaticReturnType(staticMethodElement);
327-
staticType = _typeSystem.refineBinaryExpressionType(
328-
_getStaticType(node.leftHandSide, read: true),
329-
operator,
330-
node.rightHandSide.staticType,
331-
staticType,
332-
_featureSet);
333-
_recordStaticType(node, staticType);
325+
var operatorElement = node.staticElement;
326+
var type = operatorElement?.returnType ?? _dynamicType;
327+
type = _typeSystem.refineBinaryExpressionType(
328+
_getStaticType(node.leftHandSide, read: true),
329+
operator,
330+
node.rightHandSide.staticType,
331+
type,
332+
_featureSet,
333+
);
334+
_recordStaticType(node, type);
335+
336+
var leftWriteType = _getStaticType(node.leftHandSide);
337+
if (!_typeSystem.isAssignableTo(type, leftWriteType,
338+
featureSet: _featureSet)) {
339+
_resolver.errorReporter.reportTypeErrorForNode(
340+
StaticTypeWarningCode.INVALID_ASSIGNMENT,
341+
node.rightHandSide,
342+
[type, leftWriteType],
343+
);
344+
}
334345
}
335346
_nullShortingTermination(node);
336347
}

pkg/analyzer/test/generated/static_type_analyzer_test.dart

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -428,26 +428,6 @@ class StaticTypeAnalyzerTest extends EngineTestCase with ResourceProviderMixin {
428428
_listener.assertNoErrors();
429429
}
430430

431-
void test_visitAssignmentExpression_compound_II() {
432-
validate(TokenType operator) {
433-
InterfaceType numType = _typeProvider.numType;
434-
InterfaceType intType = _typeProvider.intType;
435-
SimpleIdentifier identifier = _resolvedVariable(intType, "i");
436-
AssignmentExpression node = AstTestFactory.assignmentExpression(
437-
identifier, operator, _resolvedInteger(1));
438-
MethodElement plusMethod = getMethod(numType, "+");
439-
node.staticElement = plusMethod;
440-
expect(_analyze(node), same(intType));
441-
_listener.assertNoErrors();
442-
}
443-
444-
validate(TokenType.MINUS_EQ);
445-
validate(TokenType.PERCENT_EQ);
446-
validate(TokenType.PLUS_EQ);
447-
validate(TokenType.STAR_EQ);
448-
validate(TokenType.TILDE_SLASH_EQ);
449-
}
450-
451431
void test_visitAssignmentExpression_compound_lazy() {
452432
validate(TokenType operator) {
453433
InterfaceType boolType = _typeProvider.boolType;
@@ -462,46 +442,6 @@ class StaticTypeAnalyzerTest extends EngineTestCase with ResourceProviderMixin {
462442
validate(TokenType.BAR_BAR_EQ);
463443
}
464444

465-
void test_visitAssignmentExpression_compound_plusID() {
466-
validate(TokenType operator) {
467-
InterfaceType numType = _typeProvider.numType;
468-
InterfaceType intType = _typeProvider.intType;
469-
InterfaceType doubleType = _typeProvider.doubleType;
470-
SimpleIdentifier identifier = _resolvedVariable(intType, "i");
471-
AssignmentExpression node = AstTestFactory.assignmentExpression(
472-
identifier, operator, _resolvedDouble(1.0));
473-
MethodElement plusMethod = getMethod(numType, "+");
474-
node.staticElement = plusMethod;
475-
expect(_analyze(node), same(doubleType));
476-
_listener.assertNoErrors();
477-
}
478-
479-
validate(TokenType.MINUS_EQ);
480-
validate(TokenType.PERCENT_EQ);
481-
validate(TokenType.PLUS_EQ);
482-
validate(TokenType.STAR_EQ);
483-
}
484-
485-
void test_visitAssignmentExpression_compoundIfNull_differentTypes() {
486-
// double d; d ??= 0
487-
Expression node = AstTestFactory.assignmentExpression(
488-
_resolvedVariable(_typeProvider.doubleType, 'd'),
489-
TokenType.QUESTION_QUESTION_EQ,
490-
_resolvedInteger(0));
491-
expect(_analyze(node), _typeProvider.numType);
492-
_listener.assertNoErrors();
493-
}
494-
495-
void test_visitAssignmentExpression_compoundIfNull_sameTypes() {
496-
// int i; i ??= 0
497-
Expression node = AstTestFactory.assignmentExpression(
498-
_resolvedVariable(_typeProvider.intType, 'i'),
499-
TokenType.QUESTION_QUESTION_EQ,
500-
_resolvedInteger(0));
501-
expect(_analyze(node), same(_typeProvider.intType));
502-
_listener.assertNoErrors();
503-
}
504-
505445
void test_visitAssignmentExpression_simple() {
506446
// i = 0
507447
InterfaceType intType = _typeProvider.intType;

pkg/analyzer/test/src/dart/resolution/assignment_test.dart

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'package:analyzer/dart/ast/ast.dart';
66
import 'package:analyzer/dart/element/element.dart';
7+
import 'package:analyzer/src/error/codes.dart';
78
import 'package:test/test.dart';
89
import 'package:test_reflective_loader/test_reflective_loader.dart';
910

@@ -131,6 +132,63 @@ class C {
131132
assertType(right, 'int');
132133
}
133134

135+
test_compound_refineType_int_double() async {
136+
await assertErrorsInCode(r'''
137+
main(int i) {
138+
i += 1.2;
139+
i -= 1.2;
140+
i *= 1.2;
141+
i %= 1.2;
142+
}
143+
''', [
144+
error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 21, 3),
145+
error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 33, 3),
146+
error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 45, 3),
147+
error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 57, 3),
148+
]);
149+
assertType(findNode.assignment('+='), 'double');
150+
assertType(findNode.assignment('-='), 'double');
151+
assertType(findNode.assignment('*='), 'double');
152+
assertType(findNode.assignment('%='), 'double');
153+
}
154+
155+
test_compound_refineType_int_int() async {
156+
await assertNoErrorsInCode(r'''
157+
main(int i) {
158+
i += 1;
159+
i -= 1;
160+
i *= 1;
161+
i ~/= 1;
162+
i %= 1;
163+
}
164+
''');
165+
assertType(findNode.assignment('+='), 'int');
166+
assertType(findNode.assignment('-='), 'int');
167+
assertType(findNode.assignment('*='), 'int');
168+
assertType(findNode.assignment('~/='), 'int');
169+
assertType(findNode.assignment('%='), 'int');
170+
}
171+
172+
test_compoundIfNull_differentTypes() async {
173+
await assertErrorsInCode(r'''
174+
main(double a, int b) {
175+
a ??= b;
176+
}
177+
''', [
178+
error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 32, 1),
179+
]);
180+
assertType(findNode.assignment('??='), 'num');
181+
}
182+
183+
test_compoundIfNull_sameTypes() async {
184+
await assertNoErrorsInCode(r'''
185+
main(int a) {
186+
a ??= 0;
187+
}
188+
''');
189+
assertType(findNode.assignment('??='), 'int');
190+
}
191+
134192
test_in_const_context() async {
135193
addTestFile('''
136194
void f(num x, int y) {

pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,6 @@ m(B b) {
144144
assertType(assignment2, 'int');
145145
}
146146

147-
@FailingTest(reason: r'''
148-
This test fails because verifier checks that the type of `b.a?.x += 1`, which
149-
is the type of `+` invocation, is assignable to `b.a?.x` type. But with NNBD
150-
it is not. The type of `b.a?.x += 1` is `int?`, because of shortening. But
151-
because of the same shortening the assignment is performed only when `b.a` is
152-
not null, and the type to check should be `int`.
153-
''')
154147
test_assignment_plusEq_propertyAccess3_short1() async {
155148
await assertErrorsInCode(r'''
156149
class A {

0 commit comments

Comments
 (0)