mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 04:16:51 +00:00
Issue 43200. Report ASSIGNMENT_TO_FINAL when 'final late' has an initializer.
Bug: https://github.com/dart-lang/sdk/issues/43200 Change-Id: Ib79b4e8246f8f67661212c3d107de961d72132b4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/161471 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
ab16d79af9
commit
01024dfa5a
|
@ -265,9 +265,9 @@ class AssignmentExpressionResolver {
|
|||
CompileTimeErrorCode.ASSIGNMENT_TO_CONST,
|
||||
left,
|
||||
);
|
||||
} else if (variable.isFinal && !variable.isLate) {
|
||||
} else if (variable.setter == null) {
|
||||
if (variable is FieldElement) {
|
||||
if (variable.setter == null && variable.isSynthetic) {
|
||||
if (variable.isSynthetic) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER,
|
||||
left,
|
||||
|
|
|
@ -1647,39 +1647,53 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
|
|||
highlightedNode = expression.propertyName;
|
||||
}
|
||||
// check if element is assignable
|
||||
Element toVariable(Element element) {
|
||||
return element is PropertyAccessorElement ? element.variable : element;
|
||||
}
|
||||
|
||||
element = toVariable(element);
|
||||
if (element is VariableElement) {
|
||||
if (element.isConst) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.ASSIGNMENT_TO_CONST, expression);
|
||||
} else if (element.isFinal && !element.isLate) {
|
||||
if (element is FieldElementImpl) {
|
||||
if (element.setter == null && element.isSynthetic) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER,
|
||||
highlightedNode,
|
||||
[element.name, element.enclosingElement.displayName]);
|
||||
} else {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.ASSIGNMENT_TO_FINAL,
|
||||
highlightedNode,
|
||||
[element.name]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (_isNonNullableByDefault && element is PromotableElement) {
|
||||
CompileTimeErrorCode.ASSIGNMENT_TO_CONST,
|
||||
expression,
|
||||
);
|
||||
} else if (element.isFinal) {
|
||||
if (_isNonNullableByDefault) {
|
||||
// Handled during resolution, with flow analysis.
|
||||
} else {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL,
|
||||
highlightedNode,
|
||||
[element.name]);
|
||||
CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL,
|
||||
expression,
|
||||
[element.name],
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (element is PropertyAccessorElement && element.isGetter) {
|
||||
var variable = element.variable;
|
||||
if (variable.isConst) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.ASSIGNMENT_TO_CONST,
|
||||
expression,
|
||||
);
|
||||
} else if (variable.setter == null) {
|
||||
if (variable is FieldElement) {
|
||||
if (variable.isSynthetic) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER,
|
||||
highlightedNode,
|
||||
[variable.name, variable.enclosingElement.displayName],
|
||||
);
|
||||
} else {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.ASSIGNMENT_TO_FINAL,
|
||||
highlightedNode,
|
||||
[variable.name],
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL,
|
||||
highlightedNode,
|
||||
[variable.name],
|
||||
);
|
||||
}
|
||||
} else if (element is FunctionElement) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.ASSIGNMENT_TO_FUNCTION, expression);
|
||||
|
|
|
@ -160,13 +160,15 @@ void f(int value) {
|
|||
}
|
||||
|
||||
test_topLevelVariable_late() async {
|
||||
await assertNoErrorsInCode('''
|
||||
await assertErrorsInCode('''
|
||||
late final int a;
|
||||
late final int b = 0;
|
||||
void f() {
|
||||
a = 1;
|
||||
b = 1;
|
||||
}
|
||||
''');
|
||||
''', [
|
||||
error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 62, 1),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,8 +46,23 @@ f() {
|
|||
@reflectiveTest
|
||||
class AssignmentToFinalWithNullSafetyTest extends AssignmentToFinalTest
|
||||
with WithNullSafetyMixin {
|
||||
test_field_late() async {
|
||||
await assertNoErrorsInCode('''
|
||||
test_field_late_propertyAccess() async {
|
||||
await assertErrorsInCode('''
|
||||
class A {
|
||||
late final int a;
|
||||
late final int b = 0;
|
||||
void m() {
|
||||
this.a = 1;
|
||||
this.b = 1;
|
||||
}
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 92, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_field_late_simpleIdentifier() async {
|
||||
await assertErrorsInCode('''
|
||||
class A {
|
||||
late final int a;
|
||||
late final int b = 0;
|
||||
|
@ -56,11 +71,29 @@ class A {
|
|||
b = 1;
|
||||
}
|
||||
}
|
||||
''');
|
||||
''', [
|
||||
error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 82, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_field_static_late() async {
|
||||
await assertNoErrorsInCode('''
|
||||
test_field_static_final_late_prefixedIdentifier() async {
|
||||
await assertErrorsInCode('''
|
||||
class A {
|
||||
static late final int a;
|
||||
static late final int b = 0;
|
||||
}
|
||||
|
||||
void f() {
|
||||
A.a = 1;
|
||||
A.b = 1;
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 97, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_field_static_final_late_simpleIdentifier() async {
|
||||
await assertErrorsInCode('''
|
||||
class A {
|
||||
static late final int a;
|
||||
static late final int b = 0;
|
||||
|
@ -69,7 +102,9 @@ class A {
|
|||
b = 1;
|
||||
}
|
||||
}
|
||||
''');
|
||||
''', [
|
||||
error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 96, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_set_abstract_field_final_invalid() async {
|
||||
|
|
|
@ -109,7 +109,7 @@ void test1() {
|
|||
|
||||
c1a.m1 = 0;
|
||||
// ^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_LOCAL
|
||||
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_NO_SETTER
|
||||
// [cfe] The setter 'm1' isn't defined for the class 'C1<int>'.
|
||||
|
||||
c1a.m2;
|
||||
|
@ -195,7 +195,7 @@ void test1() {
|
|||
|
||||
c1c.m1 = 0;
|
||||
// ^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_LOCAL
|
||||
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_NO_SETTER
|
||||
// [cfe] The setter 'm1' isn't defined for the class 'C1<Object>'.
|
||||
|
||||
c1c.m2;
|
||||
|
|
|
@ -109,7 +109,7 @@ void test1() {
|
|||
|
||||
c1a.m1 = 0;
|
||||
// ^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_LOCAL
|
||||
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_NO_SETTER
|
||||
// [cfe] The setter 'm1' isn't defined for the class 'C1<int>'.
|
||||
|
||||
c1a.m2;
|
||||
|
|
Loading…
Reference in a new issue