mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 12:58:05 +00:00
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:
parent
5561e69f4e
commit
9cde31ba1d
|
@ -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.
|
||||
|
|
|
@ -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'));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue