Version 2.10.0-33.0.dev
Merge commit '87027c97a12a9926c2af8770a3d2a5cebc1767f3' into 'dev'
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 e558b4d..dcfb6a0 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -18,6 +18,7 @@
import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/error/nullable_dereference_verifier.dart';
+import 'package:analyzer/src/generated/migration.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/task/strong/checker.dart';
import 'package:meta/meta.dart';
@@ -46,6 +47,10 @@
bool get _isNonNullableByDefault => _typeSystem.isNonNullableByDefault;
+ MigrationResolutionHooks get _migrationResolutionHooks {
+ return _resolver.migrationResolutionHooks;
+ }
+
NullableDereferenceVerifier get _nullableDereferenceVerifier =>
_resolver.nullableDereferenceVerifier;
@@ -57,10 +62,22 @@
var left = node.leftHandSide;
var right = node.rightHandSide;
+ // Case `id = e`.
+ // Consider an assignment of the form `id = e`, where `id` is an identifier.
+ if (left is SimpleIdentifier) {
+ var leftLookup = _resolver.nameScope.lookup2(left.name);
+ // When the lexical lookup yields a local variable `v`.
+ var leftGetter = leftLookup.getter;
+ if (leftGetter is VariableElement) {
+ _resolve_SimpleIdentifier_LocalVariable(node, left, leftGetter, right);
+ return;
+ }
+ }
+
left?.accept(_resolver);
left = node.leftHandSide;
- var leftLocalVariable = _flowAnalysis?.assignmentExpression(node);
+ _flowAnalysis?.assignmentExpression(node);
TokenType operator = node.operator.type;
if (operator == TokenType.EQ ||
@@ -76,12 +93,7 @@
_resolve1(node);
_resolve2(node);
- _flowAnalysis?.assignmentExpression_afterRight(
- node,
- leftLocalVariable,
- operator == TokenType.QUESTION_QUESTION_EQ
- ? node.rightHandSide.staticType
- : node.staticType);
+ _flowAnalysis?.assignmentExpression_afterRight(node);
}
/// Set the static type of [node] to be the least upper bound of the static
@@ -180,6 +192,32 @@
return type;
}
+ /// Record that the static type of the given node is the given type.
+ ///
+ /// @param expression the node whose type is to be recorded
+ /// @param type the static type of the node
+ ///
+ /// TODO(scheglov) this is duplication
+ void _recordStaticType(Expression expression, DartType type) {
+ if (_resolver.migrationResolutionHooks != null) {
+ // TODO(scheglov) type cannot be null
+ type = _migrationResolutionHooks.modifyExpressionType(
+ expression,
+ type ?? DynamicTypeImpl.instance,
+ );
+ }
+
+ // TODO(scheglov) type cannot be null
+ if (type == null) {
+ expression.staticType = DynamicTypeImpl.instance;
+ } else {
+ expression.staticType = type;
+ if (_typeSystem.isBottom(type)) {
+ _flowAnalysis?.flow?.handleExit();
+ }
+ }
+ }
+
void _resolve1(AssignmentExpressionImpl node) {
Token operator = node.operator;
TokenType operatorType = operator.type;
@@ -290,6 +328,47 @@
_resolver.nullShortingTermination(node);
}
+ void _resolve_SimpleIdentifier_LocalVariable(
+ AssignmentExpressionImpl node,
+ SimpleIdentifier left,
+ VariableElement leftElement,
+ Expression right,
+ ) {
+ left.staticElement = leftElement;
+
+ var leftType = _resolver.localVariableTypeProvider.getType(left);
+ // TODO(scheglov) Set the type only when `operator != TokenType.EQ`.
+ _recordStaticType(left, leftType);
+
+ var operator = node.operator.type;
+ if (operator != TokenType.EQ) {
+ _resolver.checkReadOfNotAssignedLocalVariable(left);
+ }
+
+ if (operator == TokenType.EQ ||
+ operator == TokenType.QUESTION_QUESTION_EQ) {
+ InferenceContext.setType(right, leftType);
+ }
+
+ var flow = _flowAnalysis?.flow;
+ if (flow != null && operator == TokenType.QUESTION_QUESTION_EQ) {
+ flow.ifNullExpression_rightBegin(left);
+ }
+
+ right?.accept(_resolver);
+ right = node.rightHandSide;
+
+ _resolve1(node);
+ _resolve2(node);
+
+ if (flow != null) {
+ flow.write(leftElement, node.staticType);
+ if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
+ flow.ifNullExpression_end();
+ }
+ }
+ }
+
/// If the given [type] is a type parameter, resolve it to the type that
/// should be used when looking up members. Otherwise, return the original
/// type.
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 f6fe441..96dff00 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -77,30 +77,16 @@
flow.asExpression_end(expression, typeAnnotation.type);
}
- VariableElement assignmentExpression(AssignmentExpression node) {
+ void assignmentExpression(AssignmentExpression node) {
if (flow == null) return null;
if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
flow.ifNullExpression_rightBegin(node.leftHandSide);
}
-
- var left = node.leftHandSide;
-
- if (left is SimpleIdentifier) {
- var element = left.staticElement;
- if (element is VariableElement) {
- return element;
- }
- }
-
- return null;
}
- void assignmentExpression_afterRight(AssignmentExpression node,
- VariableElement localElement, DartType writtenType) {
- if (localElement != null) {
- flow.write(localElement, writtenType);
- }
+ void assignmentExpression_afterRight(AssignmentExpression node) {
+ if (flow == null) return null;
if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
flow.ifNullExpression_end();
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 8bba9a1..add5879 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -153,6 +153,8 @@
final MigratableAstInfoProvider _migratableAstInfoProvider;
+ final MigrationResolutionHooks migrationResolutionHooks;
+
/// Helper for checking expression that should have the `bool` type.
BoolExpressionVerifier boolExpressionVerifier;
@@ -290,6 +292,7 @@
this._migratableAstInfoProvider,
MigrationResolutionHooks migrationResolutionHooks)
: _featureSet = featureSet,
+ migrationResolutionHooks = migrationResolutionHooks,
super(definingLibrary, source, typeProvider, errorListener,
nameScope: nameScope) {
_promoteManager = TypePromotionManager(typeSystem);
@@ -429,6 +432,26 @@
}
}
+ void checkReadOfNotAssignedLocalVariable(SimpleIdentifier node) {
+ if (_flowAnalysis != null) {
+ if (_flowAnalysis.isPotentiallyNonNullableLocalReadBeforeWrite(node)) {
+ errorReporter.reportErrorForNode(
+ CompileTimeErrorCode
+ .NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE,
+ node,
+ [node.name],
+ );
+ }
+ if (_flowAnalysis.isReadOfDefinitelyUnassignedLateLocal(node)) {
+ errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE,
+ node,
+ [node.name],
+ );
+ }
+ }
+ }
+
void checkUnreachableNode(AstNode node) {
nullSafetyDeadCodeVerifier.visitNode(node);
}
@@ -1533,23 +1556,7 @@
return;
}
- if (_flowAnalysis != null) {
- if (_flowAnalysis.isPotentiallyNonNullableLocalReadBeforeWrite(node)) {
- errorReporter.reportErrorForNode(
- CompileTimeErrorCode
- .NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE,
- node,
- [node.name],
- );
- }
- if (_flowAnalysis.isReadOfDefinitelyUnassignedLateLocal(node)) {
- errorReporter.reportErrorForNode(
- CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE,
- node,
- [node.name],
- );
- }
- }
+ checkReadOfNotAssignedLocalVariable(node);
super.visitSimpleIdentifier(node);
}
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 4c605a3..2ccef51 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -102,14 +102,20 @@
///
/// @param expression the node whose type is to be recorded
/// @param type the static type of the node
+ ///
+ /// TODO(scheglov) this is duplication
void recordStaticType(Expression expression, DartType type) {
if (_migrationResolutionHooks != null) {
+ // TODO(scheglov) type cannot be null
type = _migrationResolutionHooks.modifyExpressionType(
- expression, type ?? _dynamicType);
+ expression,
+ type ?? DynamicTypeImpl.instance,
+ );
}
+ // TODO(scheglov) type cannot be null
if (type == null) {
- expression.staticType = _dynamicType;
+ expression.staticType = DynamicTypeImpl.instance;
} else {
expression.staticType = type;
if (_typeSystem.isBottom(type)) {
diff --git a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
index 2761663..7ce888a 100644
--- a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -50,34 +50,6 @@
assertType(right, 'int');
}
- test_compound_local() async {
- await resolveTestCode(r'''
-main() {
- num v = 0;
- v += 3;
-}
-''');
- var assignment = findNode.assignment('v += 3');
- assertElement(
- assignment,
- elementMatcher(
- numElement.getMethod('+'),
- isLegacy: isNullSafetySdkAndLegacyLibrary,
- ),
- );
- assertType(assignment, 'num'); // num + int = num
-
- assertSimpleIdentifier(
- assignment.leftHandSide,
- readElement: findElement.localVar('v'),
- writeElement: findElement.localVar('v'),
- type: 'num',
- );
-
- Expression right = assignment.rightHandSide;
- assertType(right, 'int');
- }
-
test_compound_prefixedIdentifier() async {
await resolveTestCode(r'''
main() {
@@ -147,80 +119,6 @@
assertType(right, 'int');
}
- test_compound_refineType_int_double() async {
- await assertErrorsInCode(r'''
-main(int i) {
- i += 1.2;
- i -= 1.2;
- i *= 1.2;
- i %= 1.2;
-}
-''', [
- error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 21, 3),
- error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 33, 3),
- error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 45, 3),
- error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 57, 3),
- ]);
- assertType(findNode.assignment('+='), 'double');
- assertType(findNode.assignment('-='), 'double');
- assertType(findNode.assignment('*='), 'double');
- assertType(findNode.assignment('%='), 'double');
- }
-
- test_compound_refineType_int_int() async {
- await assertNoErrorsInCode(r'''
-main(int i) {
- i += 1;
- i -= 1;
- i *= 1;
- i ~/= 1;
- i %= 1;
-}
-''');
- assertType(findNode.assignment('+='), 'int');
- assertType(findNode.assignment('-='), 'int');
- assertType(findNode.assignment('*='), 'int');
- assertType(findNode.assignment('~/='), 'int');
- assertType(findNode.assignment('%='), 'int');
- }
-
- test_compoundIfNull_differentTypes() async {
- await assertErrorsInCode(r'''
-main(double a, int b) {
- a ??= b;
-}
-''', [
- error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 32, 1),
- ]);
- assertType(findNode.assignment('??='), 'num');
- }
-
- test_compoundIfNull_sameTypes() async {
- await assertNoErrorsInCode(r'''
-main(int a) {
- a ??= 0;
-}
-''');
- assertType(findNode.assignment('??='), 'int');
- }
-
- test_in_const_context() async {
- await resolveTestCode('''
-void f(num x, int y) {
- const [x = y];
-}
-''');
- expect(result.errors, isNotEmpty);
-
- var xRef = findNode.simple('x =');
- assertElement(xRef, findElement.parameter('x'));
- assertType(xRef, 'num');
-
- var yRef = findNode.simple('y]');
- assertElement(yRef, findElement.parameter('y'));
- assertType(yRef, 'int');
- }
-
test_indexExpression_cascade() async {
await resolveTestCode(r'''
main() {
@@ -270,25 +168,6 @@
assertType(assignment, 'double');
}
- test_nullAware_local() async {
- await resolveTestCode(r'''
-main() {
- String v;
- v ??= 'test';
-}
-''');
- var assignment = findNode.assignment('v ??=');
- assertElementNull(assignment);
- assertType(assignment, 'String');
-
- SimpleIdentifier left = assignment.leftHandSide;
- assertElement(left, findElement.localVar('v'));
- assertType(left, 'String');
-
- Expression right = assignment.rightHandSide;
- assertType(right, 'String');
- }
-
test_propertyAccess_forwardingStub() async {
await resolveTestCode(r'''
class A {
@@ -347,49 +226,6 @@
assertType(right, 'int');
}
- test_simple_instanceField_unqualified() async {
- await resolveTestCode(r'''
-class C {
- num f = 0;
- foo() {
- f = 2;
- }
-}
-''');
- var assignment = findNode.assignment('f = 2;');
- assertElementNull(assignment);
- assertType(assignment, 'int');
-
- SimpleIdentifier left = assignment.leftHandSide;
- assertElement(left, findElement.setter('f'));
- assertType(left, 'num');
-
- Expression right = assignment.rightHandSide;
- assertType(right, 'int');
- }
-
- test_simple_local() async {
- await resolveTestCode(r'''
-main() {
- num v = 0;
- v = 2;
-}
-''');
- var assignment = findNode.assignment('v = 2;');
- assertElementNull(assignment);
- assertType(assignment, 'int');
-
- assertSimpleIdentifier(
- assignment.leftHandSide,
- readElement: null,
- writeElement: findElement.localVar('v'),
- type: 'num',
- );
-
- Expression right = assignment.rightHandSide;
- assertType(right, 'int');
- }
-
test_simple_prefixedIdentifier() async {
await resolveTestCode(r'''
main() {
@@ -543,68 +379,628 @@
assertType(right, 'int');
}
- test_simple_staticField_unqualified() async {
- await resolveTestCode(r'''
-class C {
- static num f = 0;
- foo() {
- f = 2;
- }
-}
-''');
- var assignment = findNode.assignment('f = 2');
- assertElementNull(assignment);
- assertType(assignment, 'int');
-
- assertSimpleIdentifier(
- assignment.leftHandSide,
- readElement: null,
- writeElement: findElement.setter('f'),
- type: 'num',
- );
-
- var right = assignment.rightHandSide;
- assertType(right, 'int');
- }
-
- test_simple_topLevelVariable() async {
- await resolveTestCode(r'''
-main() {
- v = 2;
-}
-num v = 0;
-''');
- var assignment = findNode.assignment('v = 2');
- assertElementNull(assignment);
- assertType(assignment, 'int');
-
- assertSimpleIdentifier(
- assignment.leftHandSide,
- readElement: null,
- writeElement: findElement.topSet('v'),
- type: 'num',
- );
-
- var right = assignment.rightHandSide;
- assertType(right, 'int');
- }
-
- test_to_class() async {
- await resolveTestCode('''
+ test_simpleIdentifier_class_simple() async {
+ await assertErrorsInCode('''
class C {}
-void f(int x) {
- C = x;
+
+void f() {
+ C = 0;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_TYPE, 25, 1),
+ error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 29, 1),
+ ]);
+
+ var assignment = findNode.assignment('C = 0');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.class_('C'),
+ type: null,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_fieldInstance_simple() async {
+ await assertNoErrorsInCode(r'''
+class C {
+ num x = 0;
+
+ void f() {
+ x = 2;
+ }
}
''');
- expect(result.errors, isNotEmpty);
- var cRef = findNode.simple('C =');
- assertElement(cRef, findElement.class_('C'));
- assertType(cRef, 'Type');
+ var assignment = findNode.assignment('x = 2');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
- var xRef = findNode.simple('x;');
- assertElement(xRef, findElement.parameter('x'));
- assertType(xRef, 'int');
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.setter('x'),
+ type: null,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_fieldStatic_simple() async {
+ await assertNoErrorsInCode(r'''
+class C {
+ static num x = 0;
+
+ void f() {
+ x = 2;
+ }
+}
+''');
+
+ var assignment = findNode.assignment('x = 2');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.setter('x'),
+ type: null,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_getterInstance_simple() async {
+ await assertErrorsInCode('''
+class C {
+ num get x => 0;
+
+ void f() {
+ x = 2;
+ }
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 46, 1),
+ ]);
+
+ var assignment = findNode.assignment('x = 2');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.getter('x'),
+ type: null,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_getterStatic_simple() async {
+ await assertErrorsInCode('''
+class C {
+ static num get x => 0;
+
+ void f() {
+ x = 2;
+ }
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 53, 1),
+ ]);
+
+ var assignment = findNode.assignment('x = 2');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.getter('x'),
+ type: null,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_getterTopLevel_simple() async {
+ await assertErrorsInCode('''
+int get x => 0;
+
+void f() {
+ x = 2;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 30, 1),
+ ]);
+
+ var assignment = findNode.assignment('x = 2');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.topGet('x'),
+ type: null,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_importPrefix_simple() async {
+ await assertErrorsInCode('''
+import 'dart:math' as x;
+
+main() {
+ x = 2;
+}
+''', [
+ error(CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT, 37, 1),
+ ]);
+
+ var assignment = findNode.assignment('x = 2');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.prefix('x'),
+ type: null,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_localVariable_compound() async {
+ await assertNoErrorsInCode(r'''
+void f() {
+ // ignore:unused_local_variable
+ num x = 0;
+ x += 3;
+}
+''');
+
+ var assignment = findNode.assignment('x += 3');
+ assertAssignment(
+ assignment,
+ operatorElement: elementMatcher(
+ numElement.getMethod('+'),
+ isLegacy: isNullSafetySdkAndLegacyLibrary,
+ ),
+ type: 'num', // num + int = num
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: findElement.localVar('x'),
+ writeElement: findElement.localVar('x'),
+ type: 'num',
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_localVariable_simple() async {
+ await assertNoErrorsInCode(r'''
+void f() {
+ // ignore:unused_local_variable
+ num x = 0;
+ x = 2;
+}
+''');
+
+ var assignment = findNode.assignment('x = 2');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.localVar('x'),
+ type: 'num',
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_localVariableConst_simple() async {
+ await assertErrorsInCode('''
+void f() {
+ // ignore:unused_local_variable
+ const num x = 1;
+ x = 2;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_CONST, 66, 1),
+ ]);
+
+ var assignment = findNode.assignment('x = 2');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.localVar('x'),
+ type: null,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_localVariableFinal_simple() async {
+ await assertErrorsInCode('''
+void f() {
+ // ignore:unused_local_variable
+ final num x = 1;
+ x = 2;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 66, 1),
+ ]);
+
+ var assignment = findNode.assignment('x = 2');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.localVar('x'),
+ type: null,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_parameter_compound_ifNull() async {
+ await assertNoErrorsInCode(r'''
+void f(num x) {
+ x ??= 0;
+}
+''');
+
+ var assignment = findNode.assignment('x ??=');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'num',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: findElement.parameter('x'),
+ writeElement: findElement.parameter('x'),
+ type: 'num',
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_parameter_compound_ifNull_notAssignableType() async {
+ await assertErrorsInCode(r'''
+void f(double a, int b) {
+ a ??= b;
+}
+''', [
+ error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 34, 1),
+ ]);
+
+ var assignment = findNode.assignment('a ??=');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'num',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: findElement.parameter('a'),
+ writeElement: findElement.parameter('a'),
+ type: 'double',
+ );
+
+ assertSimpleIdentifier(
+ assignment.rightHandSide,
+ readElement: findElement.parameter('b'),
+ writeElement: null,
+ type: 'int',
+ );
+ }
+
+ test_simpleIdentifier_parameter_compound_refineType_int_double() async {
+ await assertErrorsInCode(r'''
+void f(int x) {
+ x += 1.2;
+ x -= 1.2;
+ x *= 1.2;
+ x %= 1.2;
+}
+''', [
+ error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 23, 3),
+ error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 35, 3),
+ error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 47, 3),
+ error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 59, 3),
+ ]);
+ assertType(findNode.assignment('+='), 'double');
+ assertType(findNode.assignment('-='), 'double');
+ assertType(findNode.assignment('*='), 'double');
+ assertType(findNode.assignment('%='), 'double');
+ }
+
+ test_simpleIdentifier_parameter_compound_refineType_int_int() async {
+ await assertNoErrorsInCode(r'''
+main(int x) {
+ x += 1;
+ x -= 1;
+ x *= 1;
+ x ~/= 1;
+ x %= 1;
+}
+''');
+ assertType(findNode.assignment('+='), 'int');
+ assertType(findNode.assignment('-='), 'int');
+ assertType(findNode.assignment('*='), 'int');
+ assertType(findNode.assignment('~/='), 'int');
+ assertType(findNode.assignment('%='), 'int');
+ }
+
+ test_simpleIdentifier_parameter_simple() async {
+ await assertNoErrorsInCode(r'''
+void f(num x) {
+ x = 2;
+}
+''');
+
+ var assignment = findNode.assignment('x = 2');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.parameter('x'),
+ type: null,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_parameter_simple_notAssignableType() async {
+ await assertErrorsInCode(r'''
+void f(int x) {
+ x = true;
+}
+''', [
+ error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 22, 4),
+ ]);
+
+ var assignment = findNode.assignment('x = true');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'bool',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.parameter('x'),
+ type: null,
+ );
+
+ assertType(assignment.rightHandSide, 'bool');
+ }
+
+ test_simpleIdentifier_parameterFinal_simple() async {
+ await assertErrorsInCode('''
+void f(final int x) {
+ x = 2;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 24, 1),
+ ]);
+
+ var assignment = findNode.assignment('x = 2');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.parameter('x'),
+ type: null,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_synthetic_simple() async {
+ await assertErrorsInCode('''
+void f(int y) {
+ = y;
+}
+''', [
+ error(ParserErrorCode.MISSING_IDENTIFIER, 18, 1),
+ ]);
+
+ var assignment = findNode.assignment('= y');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: null,
+ type: 'dynamic',
+ );
+
+ assertSimpleIdentifier(
+ assignment.rightHandSide,
+ readElement: findElement.parameter('y'),
+ writeElement: null,
+ type: 'int',
+ );
+ }
+
+ test_simpleIdentifier_topLevelVariable_simple() async {
+ await assertNoErrorsInCode(r'''
+num x = 0;
+
+void f() {
+ x = 2;
+}
+''');
+
+ var assignment = findNode.assignment('x = 2');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.topSet('x'),
+ type: null,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_topLevelVariable_simple_notAssignableType() async {
+ await assertErrorsInCode(r'''
+int x = 0;
+
+void f() {
+ x = true;
+}
+''', [
+ error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 29, 4),
+ ]);
+
+ var assignment = findNode.assignment('x = true');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'bool',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.topSet('x'),
+ type: null,
+ );
+
+ assertType(assignment.rightHandSide, 'bool');
+ }
+
+ test_simpleIdentifier_topLevelVariableFinal_simple() async {
+ await assertErrorsInCode(r'''
+final num x = 0;
+
+void f() {
+ x = 2;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 31, 1),
+ ]);
+
+ var assignment = findNode.assignment('x = 2');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: findElement.topGet('x'),
+ type: null,
+ );
+
+ assertType(assignment.rightHandSide, 'int');
+ }
+
+ test_simpleIdentifier_unresolved_simple() async {
+ await assertErrorsInCode(r'''
+void f(int a) {
+ x = a;
+}
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 18, 1),
+ ]);
+
+ var assignment = findNode.assignment('x = a');
+ assertAssignment(
+ assignment,
+ operatorElement: null,
+ type: 'int',
+ );
+
+ assertSimpleIdentifier(
+ assignment.leftHandSide,
+ readElement: null,
+ writeElement: null,
+ type: null,
+ );
+
+ assertSimpleIdentifier(
+ assignment.rightHandSide,
+ readElement: findElement.parameter('a'),
+ writeElement: null,
+ type: 'int',
+ );
}
test_to_class_ambiguous() async {
@@ -624,33 +1020,6 @@
assertType(xRef, 'int');
}
- test_to_final_parameter() async {
- await resolveTestCode('''
-f(final int x) {
- x += 2;
-}
-''');
- expect(result.errors, isNotEmpty);
-
- var xRef = findNode.simple('x +=');
- assertElement(xRef, findElement.parameter('x'));
- assertType(xRef, 'int');
- }
-
- test_to_final_variable_local() async {
- await resolveTestCode('''
-main() {
- final x = 1;
- x += 2;
-}
-''');
- expect(result.errors, isNotEmpty);
-
- var xRef = findNode.simple('x +=');
- assertElement(xRef, findElement.localVar('x'));
- assertType(xRef, 'int');
- }
-
test_to_getter_instance_direct() async {
await resolveTestCode('''
class C {
@@ -667,22 +1036,6 @@
assertType(xRef, 'int');
}
- test_to_getter_instance_via_implicit_this() async {
- await resolveTestCode('''
-class C {
- int get x => 0;
- f() {
- x += 2;
- }
-}
-''');
- expect(result.errors, isNotEmpty);
-
- var xRef = findNode.simple('x +=');
- assertElement(xRef, findElement.getter('x'));
- assertType(xRef, 'int');
- }
-
test_to_getter_static_direct() async {
await resolveTestCode('''
class C {
@@ -699,36 +1052,6 @@
assertType(xRef, 'int');
}
- test_to_getter_static_via_scope() async {
- await resolveTestCode('''
-class C {
- static int get x => 0;
- f() {
- x += 2;
- }
-}
-''');
- expect(result.errors, isNotEmpty);
-
- var xRef = findNode.simple('x +=');
- assertElement(xRef, findElement.getter('x'));
- assertType(xRef, 'int');
- }
-
- test_to_getter_top_level() async {
- await resolveTestCode('''
-int get x => 0;
-main() {
- x += 2;
-}
-''');
- expect(result.errors, isNotEmpty);
-
- var xRef = findNode.simple('x +=');
- assertElement(xRef, findElement.topGet('x'));
- assertType(xRef, 'int');
- }
-
test_to_non_lvalue() async {
await resolveTestCode('''
void f(int x, double y, String z) {
@@ -801,23 +1124,6 @@
assertType(yRef, 'int');
}
- test_to_prefix() async {
- newFile('/test/lib/a.dart', content: '''
-var x = 0;
-''');
- await resolveTestCode('''
-import 'a.dart' as p;
-main() {
- p += 2;
-}
-''');
- expect(result.errors, isNotEmpty);
-
- var pRef = findNode.simple('p +=');
- assertElement(pRef, findElement.prefix('p'));
- assertTypeDynamic(pRef);
- }
-
test_to_prefix_increment() async {
await resolveTestCode('''
void f(num x, int y) {
@@ -869,60 +1175,6 @@
assertType(yRef, 'int');
}
- test_types_local() async {
- await resolveTestCode(r'''
-int a;
-bool b;
-main() {
- a = b;
-}
-''');
- expect(result.errors, isNotEmpty);
-
- var assignment = findNode.assignment('a = b');
- assertElementNull(assignment);
- assertType(assignment, 'bool');
-
- assertIdentifierTopSetRef(assignment.leftHandSide, 'a');
- assertIdentifierTopGetRef(assignment.rightHandSide, 'b');
- }
-
- test_types_top() async {
- await resolveTestCode(r'''
-int a = 0;
-bool b = a;
-''');
- expect(result.errors, isNotEmpty);
-
- var bDeclaration = findNode.variableDeclaration('b =');
- TopLevelVariableElement bElement = bDeclaration.declaredElement;
- assertElement(bDeclaration.name, findElement.topVar('b'));
- assertTypeNull(bDeclaration.name);
- assertType(bElement.type, 'bool');
-
- SimpleIdentifier aRef = bDeclaration.initializer;
- assertElement(aRef, findElement.topGet('a'));
- assertType(aRef, 'int');
- }
-
- test_types_top_const() async {
- await resolveTestCode(r'''
-const int a = 0;
-const bool b = a;
-''');
- expect(result.errors, isNotEmpty);
-
- var bDeclaration = findNode.variableDeclaration('b =');
- TopLevelVariableElement bElement = bDeclaration.declaredElement;
- assertElement(bDeclaration.name, bElement);
- assertTypeNull(bDeclaration.name);
- assertType(bElement.type, 'bool');
-
- SimpleIdentifier aRef = bDeclaration.initializer;
- assertElement(aRef, findElement.topGet('a'));
- assertType(aRef, 'int');
- }
-
test_unresolved_left_identifier_compound() async {
await resolveTestCode(r'''
int b;
@@ -943,26 +1195,6 @@
assertType(assignment.rightHandSide, 'int');
}
- test_unresolved_left_identifier_simple() async {
- await resolveTestCode(r'''
-int b;
-main() {
- a = b;
-}
-''');
- expect(result.errors, isNotEmpty);
-
- var assignment = findNode.assignment('a = b');
- assertElementNull(assignment);
- assertType(assignment, 'int');
-
- assertElementNull(assignment.leftHandSide);
- assertTypeDynamic(assignment.leftHandSide);
-
- assertElement(assignment.rightHandSide, findElement.topGet('b'));
- assertType(assignment.rightHandSide, 'int');
- }
-
test_unresolved_left_indexed1_simple() async {
await resolveTestCode(r'''
int c;
@@ -1238,32 +1470,4 @@
assertElement(assignment.rightHandSide, findElement.topGet('d'));
assertType(assignment.rightHandSide, 'int');
}
-
- test_with_synthetic_lhs() async {
- await resolveTestCode('''
-void f(int x) {
- = x;
-}
-''');
- expect(result.errors, isNotEmpty);
-
- var xRef = findNode.simple('x;');
- assertElement(xRef, findElement.parameter('x'));
- assertType(xRef, 'int');
- }
-
- test_with_synthetic_lhs_in_method() async {
- await resolveTestCode('''
-class C {
- void f(int x) {
- = x;
- }
-}
-''');
- expect(result.errors, isNotEmpty);
-
- var xRef = findNode.simple('x;');
- assertElement(xRef, findElement.parameter('x'));
- assertType(xRef, 'int');
- }
}
diff --git a/tools/VERSION b/tools/VERSION
index 27730e4..ce12337 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 10
PATCH 0
-PRERELEASE 32
+PRERELEASE 33
PRERELEASE_PATCH 0
\ No newline at end of file