Add non-final fields to setters
Change-Id: Ib42064cf762dae6eb0ff5bda4459ce69a9f78b26
Reviewed-on: https://dart-review.googlesource.com/c/88717
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
index 772178d..a6074c2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
@@ -17,6 +17,8 @@
messageInheritedMembersConflict,
messageInheritedMembersConflictCause1,
messageInheritedMembersConflictCause2,
+ templateDuplicatedDeclaration,
+ templateDuplicatedDeclarationCause,
templateMissingImplementationCause,
templateMissingImplementationNotAbstract;
@@ -57,6 +59,10 @@
return memberKind(a.target) != memberKind(b.target);
}
+bool impliesSetter(Declaration declaration) {
+ return declaration.isField && !(declaration.isFinal || declaration.isConst);
+}
+
class ClassHierarchyBuilder {
final Map<KernelClassBuilder, ClassHierarchyNode> nodes =
<KernelClassBuilder, ClassHierarchyNode>{};
@@ -203,6 +209,7 @@
List<Declaration> localSetters =
new List<Declaration>.from(scope.setters.values)
..sort(compareDeclarations);
+ localSetters = mergeAccessors(cls, localMembers, localSetters);
List<Declaration> classMembers;
List<Declaration> classSetters;
List<Declaration> interfaceMembers;
@@ -236,7 +243,6 @@
}
nodes[cls] = new ClassHierarchyNode(cls, scope, classMembers, classSetters,
interfaceMembers, interfaceSetters);
- mergeAccessors(cls, classMembers, classSetters);
if (abstractMemberCount != 0 && !cls.isAbstract) {
if (!hasNoSuchMethod) {
@@ -298,71 +304,66 @@
return input.single;
}
- /// Merge [and check] accessors. This entails removing setters corresponding
- /// to fields, and checking that setters don't override regular methods.
- void mergeAccessors(KernelClassBuilder cls, List<Declaration> members,
- List<Declaration> setters) {
- List<Declaration> overriddenSetters;
+ /// Merge [and check] accessors. This entails copying mutable fields to
+ /// setters to simulate implied setters, and checking that setters don't
+ /// override regular methods.
+ List<Declaration> mergeAccessors(KernelClassBuilder cls,
+ List<Declaration> members, List<Declaration> setters) {
+ final List<Declaration> mergedSetters = new List<Declaration>.filled(
+ members.length + setters.length, null,
+ growable: true);
+ int storeIndex = 0;
int i = 0;
int j = 0;
while (i < members.length && j < setters.length) {
- Declaration member = members[i];
- Declaration setter = setters[j];
+ final Declaration member = members[i];
+ final Declaration setter = setters[j];
final int compare = compareDeclarations(member, setter);
if (compare == 0) {
- if (member.isField) {
- // TODO(ahe): What happens if we have both a field and a setter
- // declared in the same class?
- if (!member.isFinal && !member.isConst) {
- // The field overrides the setter.
- (overriddenSetters ??= <Declaration>[]).add(setter);
- Member target = setter.target;
- if (target.isAbstract) {
- abstractMemberCount--;
- }
- }
- } else if (!member.isGetter) {
- String name = member.fullNameForErrors;
+ if (member.isField ? impliesSetter(member) : !member.isGetter) {
+ // [member] conflicts with [setter].
+ final String name = member.fullNameForErrors;
cls.library.addProblem(
- messageDeclaredMemberConflictsWithInheritedMember,
- member.charOffset,
+ templateDuplicatedDeclaration.withArguments(name),
+ setter.charOffset,
name.length,
- member.fileUri,
+ setter.fileUri,
context: <LocatedMessage>[
- messageDeclaredMemberConflictsWithInheritedMemberCause
+ templateDuplicatedDeclarationCause
+ .withArguments(name)
.withLocation(
- setter.fileUri, setter.charOffset, name.length)
+ member.fileUri, member.charOffset, name.length)
]);
}
+ mergedSetters[storeIndex++] = setter;
i++;
j++;
} else if (compare < 0) {
+ if (impliesSetter(member)) {
+ mergedSetters[storeIndex++] = member;
+ }
i++;
} else {
+ mergedSetters[storeIndex++] = setters[j];
j++;
}
}
- // One of of the two lists is now exhausted. What remains in the other list
- // cannot be a conflict.
+ while (i < members.length) {
+ final Declaration member = members[i];
+ if (impliesSetter(member)) {
+ mergedSetters[storeIndex++] = member;
+ }
+ i++;
+ }
+ while (j < setters.length) {
+ mergedSetters[storeIndex++] = setters[j];
+ j++;
+ }
- if (overriddenSetters != null) {
- // Remove [overriddenSetters] from [setters] by copying [setters]
- // to itself.
- int i = 0;
- int j = 0;
- int storeIndex = 0;
- while (i < setters.length && j < overriddenSetters.length) {
- if (setters[i] == overriddenSetters[j]) {
- i++;
- j++;
- } else {
- setters[storeIndex++] = setters[i++];
- }
- }
- while (i < setters.length) {
- setters[storeIndex++] = setters[i++];
- }
- setters.length = storeIndex;
+ if (storeIndex == j) {
+ return setters;
+ } else {
+ return mergedSetters..length = storeIndex;
}
}
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.expect b/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.expect
index af73d67..6742c9b 100644
--- a/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.expect
+++ b/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.expect
@@ -1,17 +1,17 @@
// Formatted problems:
//
-// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:10:8: Error: Can't declare a member that conflicts with an inherited one.
-// void foo(int x) {}
-// ^^^
-// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:12:12: Context: This is the inherited member.
+// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:12:12: Error: 'foo' is already declared in this scope.
// void set foo(int x);
// ^^^
+// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:10:8: Context: Previous declaration of 'foo'.
+// void foo(int x) {}
+// ^^^
// Unhandled errors:
//
-// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:10:8: Error: Can't declare a member that conflicts with an inherited one.
-// void foo(int x) {}
-// ^^^
+// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:12:12: Error: 'foo' is already declared in this scope.
+// void set foo(int x);
+// ^^^
library;
import self as self;
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.transformed.expect b/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.transformed.expect
index 37f1f55..e9e7677 100644
--- a/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.transformed.expect
+++ b/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.legacy.transformed.expect
@@ -1,8 +1,8 @@
// Unhandled errors:
//
-// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:10:8: Error: Can't declare a member that conflicts with an inherited one.
-// void foo(int x) {}
-// ^^^
+// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:12:12: Error: 'foo' is already declared in this scope.
+// void set foo(int x);
+// ^^^
library;
import self as self;
diff --git a/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.outline.expect b/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.outline.expect
index 51ebf0c..d8c8b38 100644
--- a/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.outline.expect
+++ b/pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart.outline.expect
@@ -1,11 +1,11 @@
// Formatted problems:
//
-// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:10:8: Error: Can't declare a member that conflicts with an inherited one.
-// void foo(int x) {}
-// ^^^
-// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:12:12: Context: This is the inherited member.
+// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:12:12: Error: 'foo' is already declared in this scope.
// void set foo(int x);
// ^^^
+// pkg/front_end/testcases/no_such_method_forwarders/setter_not_shadowed_by_method.dart:10:8: Context: Previous declaration of 'foo'.
+// void foo(int x) {}
+// ^^^
library;
import self as self;
diff --git a/pkg/front_end/testcases/rasta/super.dart.legacy.expect b/pkg/front_end/testcases/rasta/super.dart.legacy.expect
index ffacfe6..473cece 100644
--- a/pkg/front_end/testcases/rasta/super.dart.legacy.expect
+++ b/pkg/front_end/testcases/rasta/super.dart.legacy.expect
@@ -1,11 +1,11 @@
// Formatted problems:
//
-// pkg/front_end/testcases/rasta/super.dart:26:8: Error: Can't declare a member that conflicts with an inherited one.
-// void n() {}
-// ^
-// pkg/front_end/testcases/rasta/super.dart:27:7: Context: This is the inherited member.
+// pkg/front_end/testcases/rasta/super.dart:27:7: Error: 'n' is already declared in this scope.
// set n(_) {}
// ^
+// pkg/front_end/testcases/rasta/super.dart:26:8: Context: Previous declaration of 'n'.
+// void n() {}
+// ^
//
// pkg/front_end/testcases/rasta/super.dart:43:5: Error: '+' is not a prefix operator.
// Try removing '+'.
@@ -239,9 +239,9 @@
// Unhandled errors:
//
-// pkg/front_end/testcases/rasta/super.dart:26:8: Error: Can't declare a member that conflicts with an inherited one.
-// void n() {}
-// ^
+// pkg/front_end/testcases/rasta/super.dart:27:7: Error: 'n' is already declared in this scope.
+// set n(_) {}
+// ^
//
// pkg/front_end/testcases/rasta/super.dart:43:5: Error: '+' is not a prefix operator.
// Try removing '+'.
diff --git a/pkg/front_end/testcases/rasta/super.dart.legacy.transformed.expect b/pkg/front_end/testcases/rasta/super.dart.legacy.transformed.expect
index 3a83d7b..f92047d 100644
--- a/pkg/front_end/testcases/rasta/super.dart.legacy.transformed.expect
+++ b/pkg/front_end/testcases/rasta/super.dart.legacy.transformed.expect
@@ -1,8 +1,8 @@
// Unhandled errors:
//
-// pkg/front_end/testcases/rasta/super.dart:26:8: Error: Can't declare a member that conflicts with an inherited one.
-// void n() {}
-// ^
+// pkg/front_end/testcases/rasta/super.dart:27:7: Error: 'n' is already declared in this scope.
+// set n(_) {}
+// ^
//
// pkg/front_end/testcases/rasta/super.dart:43:5: Error: '+' is not a prefix operator.
// Try removing '+'.
diff --git a/pkg/front_end/testcases/rasta/super.dart.outline.expect b/pkg/front_end/testcases/rasta/super.dart.outline.expect
index 8798c49..c3496aa 100644
--- a/pkg/front_end/testcases/rasta/super.dart.outline.expect
+++ b/pkg/front_end/testcases/rasta/super.dart.outline.expect
@@ -1,11 +1,11 @@
// Formatted problems:
//
-// pkg/front_end/testcases/rasta/super.dart:26:8: Error: Can't declare a member that conflicts with an inherited one.
-// void n() {}
-// ^
-// pkg/front_end/testcases/rasta/super.dart:27:7: Context: This is the inherited member.
+// pkg/front_end/testcases/rasta/super.dart:27:7: Error: 'n' is already declared in this scope.
// set n(_) {}
// ^
+// pkg/front_end/testcases/rasta/super.dart:26:8: Context: Previous declaration of 'n'.
+// void n() {}
+// ^
library;
import self as self;