Try interface candidates in reverse order.

R=brianwilkerson@google.com

Change-Id: I616cdc280299da321834140678d39c28e5ecb614
Reviewed-on: https://dart-review.googlesource.com/c/78711
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2018-10-09 20:12:46 +00:00 committed by commit-bot@chromium.org
parent 5561e69f4e
commit 9cde31ba1d
2 changed files with 102 additions and 15 deletions

View file

@ -57,7 +57,7 @@ class InheritanceManager2 {
_interfaces[type] = const Interface._(const {}, const [{}], const []);
Map<Name, FunctionType> map = {};
List<Map<Name, FunctionType>> supers = [];
List<Map<Name, FunctionType>> superImplemented = [];
List<Conflict> conflicts = null;
// If a class declaration has a member declaration, the signature of that
@ -65,6 +65,11 @@ class InheritanceManager2 {
_addTypeMembers(map, type);
Map<Name, List<FunctionType>> namedCandidates = {};
for (var interface in type.interfaces) {
_addCandidates(namedCandidates, interface);
}
if (type.element.isMixin) {
for (var constraint in type.superclassConstraints) {
_addCandidates(namedCandidates, constraint);
@ -74,7 +79,7 @@ class InheritanceManager2 {
// from its superclass constraints, whether it is abstract or concrete.
Map<Name, FunctionType> mixinSuperClass = {};
_findMostSpecificFromNamedCandidates(mixinSuperClass, namedCandidates);
supers.add(mixinSuperClass);
superImplemented.add(mixinSuperClass);
} else {
Map<Name, FunctionType> implemented;
@ -82,7 +87,7 @@ class InheritanceManager2 {
_addCandidates(namedCandidates, type.superclass);
implemented = _getImplemented(type.superclass);
supers.add(implemented);
superImplemented.add(implemented);
}
for (var mixin in type.mixins) {
@ -92,14 +97,10 @@ class InheritanceManager2 {
implemented = <Name, FunctionType>{}
..addAll(implemented)
..addAll(implementedInMixin);
supers.add(implemented);
superImplemented.add(implemented);
}
}
for (var interface in type.interfaces) {
_addCandidates(namedCandidates, interface);
}
// If a class declaration does not have a member declaration with a
// particular name, but some super-interfaces do have a member with that
// name, it's a compile-time error if there is no signature among the
@ -108,7 +109,11 @@ class InheritanceManager2 {
// signature becomes the signature of the class's interface.
conflicts = _findMostSpecificFromNamedCandidates(map, namedCandidates);
var interface = new Interface._(map, supers, conflicts ?? const []);
var interface = new Interface._(
map,
superImplemented,
conflicts ?? const [],
);
_interfaces[type] = interface;
return interface;
}
@ -132,11 +137,11 @@ class InheritanceManager2 {
bool forSuper: false,
}) {
if (forSuper) {
var supers = getInterface(type)._supers;
var superImplemented = getInterface(type)._superImplemented;
if (forMixinIndex >= 0) {
return supers[forMixinIndex][name];
return superImplemented[forMixinIndex][name];
}
return supers.last[name];
return superImplemented.last[name];
}
if (concrete) {
return _getImplemented(type)[name];
@ -247,8 +252,13 @@ class InheritanceManager2 {
conflicts.add(conflict);
}
// Candidates are recorded in forward order, so
// `class X extends S with M1, M2 implements I1, I2 {}` will record
// candidates from [I1, I2, S, M1, M2]. But during method lookup
// candidates should be considered in backward order, i.e. from `M2`,
// then from `M1`, then from `S`.
FunctionType validOverride;
for (var i = 0; i < candidates.length; i++) {
for (var i = candidates.length - 1; i >= 0; i--) {
validOverride = candidates[i];
for (var j = 0; j < candidates.length; j++) {
var candidate = candidates[j];
@ -360,14 +370,14 @@ class Interface {
/// The first item of the list is the nominal superclass, next the nominal
/// superclass plus the first mixin, etc. So, for the class like
/// `class C extends S with M1, M2`, we get `[S, S&M1, S&M1&M2]`.
final List<Map<Name, FunctionType>> _supers;
final List<Map<Name, FunctionType>> _superImplemented;
/// The list of conflicts between superinterfaces - the nominal superclass,
/// mixins, and interfaces. Does not include conflicts with the declared
/// members of the class.
final List<Conflict> conflicts;
const Interface._(this.map, this._supers, this.conflicts);
const Interface._(this.map, this._superImplemented, this.conflicts);
}
/// A public name, or a private name qualified by a library URI.

View file

@ -54,4 +54,81 @@ abstract class C implements I1, I2 {}
DartType parameterType = memberType.parameters[0].type;
expect(parameterType.name, 'Object');
}
test_preferLatest_mixin() async {
addTestFile('''
class A {
void foo() {}
}
mixin M1 {
void foo() {}
}
mixin M2 {
void foo() {}
}
abstract class I {
void foo();
}
class X extends A with M1, M2 implements I {}
''');
await resolveTestFile();
var member = manager.getMember(
findElement.class_('X').type,
new Name(null, 'foo'),
);
expect(member.element, findElement.method('foo', of: 'M2'));
}
test_preferLatest_superclass() async {
addTestFile('''
class A {
void foo() {}
}
class B extends A {
void foo() {}
}
abstract class I {
void foo();
}
class X extends B implements I {}
''');
await resolveTestFile();
var member = manager.getMember(
findElement.class_('X').type,
new Name(null, 'foo'),
);
expect(member.element, findElement.method('foo', of: 'B'));
}
test_preferLatest_this() async {
addTestFile('''
class A {
void foo() {}
}
abstract class I {
void foo();
}
class X extends A implements I {
void foo() {}
}
''');
await resolveTestFile();
var member = manager.getMember(
findElement.class_('X').type,
new Name(null, 'foo'),
);
expect(member.element, findElement.method('foo', of: 'X'));
}
}