Skip to content

Commit f7e8def

Browse files
authored
Add mixins with superclass constraints, to the 'implementers' list. (#3844)
"Implementers" is loose. The list of "implementors" of a class (etc.), _C_, includes classes (etc.) that extend, implement, mix in, or use-as-a-superclass-constraint, _C_. Fixes #3406
1 parent ab8d74c commit f7e8def

File tree

9 files changed

+48
-93
lines changed

9 files changed

+48
-93
lines changed

lib/src/generator/templates.runtime_renderers.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9568,17 +9568,17 @@ class _Renderer_MixedInTypes extends RendererBase<MixedInTypes> {
95689568
self.renderSimpleVariable(c, remainingNames, 'bool'),
95699569
getBool: (CT_ c) => c.hasPublicMixedInTypes,
95709570
),
9571-
'mixedInElements': Property(
9572-
getValue: (CT_ c) => c.mixedInElements,
9571+
'mixedInTypes': Property(
9572+
getValue: (CT_ c) => c.mixedInTypes,
95739573
renderVariable: (CT_ c, Property<CT_> self,
95749574
List<String> remainingNames) =>
95759575
self.renderSimpleVariable(
9576-
c, remainingNames, 'List<InheritingContainer>'),
9576+
c, remainingNames, 'List<DefinedElementType>'),
95779577
renderIterable: (CT_ c, RendererBase<CT_> r,
95789578
List<MustachioNode> ast, StringSink sink) {
9579-
return c.mixedInElements.map((e) =>
9580-
_render_InheritingContainer(e, ast, r.template, sink,
9581-
parent: r));
9579+
return c.mixedInTypes.map((e) => _render_DefinedElementType(
9580+
e, ast, r.template, sink,
9581+
parent: r));
95829582
},
95839583
),
95849584
'publicMixedInTypes': Property(

lib/src/model/class.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class Class extends InheritingContainer with Constructable, MixedInTypes {
3131
this,
3232

3333
// Caching should make this recursion a little less painful.
34-
for (var container in mixedInElements.reversed)
34+
for (var container in mixedInTypes.modelElements.reversed)
3535
...container.inheritanceChain,
3636

3737
for (var container in superChain.modelElements)

lib/src/model/enum.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class Enum extends InheritingContainer with Constructable, MixedInTypes {
2323
@override
2424
late final List<InheritingContainer> inheritanceChain = [
2525
this,
26-
for (var container in mixedInElements.reversed)
26+
for (var container in mixedInTypes.modelElements.reversed)
2727
...container.inheritanceChain,
2828
for (var container in superChain.modelElements)
2929
...container.inheritanceChain,

lib/src/model/inheriting_container.dart

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,8 @@ abstract class InheritingContainer extends Container {
382382

383383
/// All the "immediate" public implementers of this container.
384384
///
385-
/// For a [Mixin], this is actually the mixin applications using the [Mixin].
385+
/// For a [Mixin], this is actually the mixin applications that use the
386+
/// [Mixin].
386387
///
387388
/// If this container has a private implementer, then that is counted as a
388389
/// proxy for any public implementers of that private container.
@@ -580,15 +581,10 @@ abstract class InheritingContainer extends Container {
580581

581582
/// Add the ability to support mixed-in types to an [InheritingContainer].
582583
mixin MixedInTypes on InheritingContainer {
583-
@visibleForTesting
584584
late final List<DefinedElementType> mixedInTypes = element.mixins
585585
.map((f) => getTypeFor(f, library) as DefinedElementType)
586586
.toList(growable: false);
587587

588-
List<InheritingContainer> get mixedInElements => [
589-
for (var t in mixedInTypes) t.modelElement as InheritingContainer,
590-
];
591-
592588
@override
593589
bool get hasModifiers => super.hasModifiers || hasPublicMixedInTypes;
594590

@@ -604,8 +600,8 @@ extension on InterfaceElement {
604600

605601
extension DefinedElementTypeIterableExtension on Iterable<DefinedElementType> {
606602
/// The [ModelElement] for each element.
607-
Iterable<InheritingContainer> get modelElements =>
608-
map((e) => e.modelElement as InheritingContainer);
603+
List<InheritingContainer> get modelElements =>
604+
map((e) => e.modelElement as InheritingContainer).toList();
609605
}
610606

611607
extension InheritingContainerIterableExtension

lib/src/model/package_graph.dart

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -643,14 +643,11 @@ class PackageGraph with CommentReferable, Nameable {
643643
supertype.modelElement as InheritingContainer, container);
644644
}
645645
if (container is Class) {
646-
for (var element in container.mixedInElements) {
646+
for (var element in container.mixedInTypes.modelElements) {
647647
checkAndAddContainer(element, container);
648648
}
649-
for (var element in container.interfaceElements) {
650-
checkAndAddContainer(element, container);
651-
}
652-
} else if (container is ExtensionType) {
653-
for (var element in container.interfaceElements) {
649+
} else if (container is Mixin) {
650+
for (var element in container.superclassConstraints.modelElements) {
654651
checkAndAddContainer(element, container);
655652
}
656653
}

test/end2end/model_test.dart

Lines changed: 4 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,7 +1763,7 @@ void main() async {
17631763

17641764
test('Verify inheritance/mixin structure and type inference', () {
17651765
expect(
1766-
TypeInferenceMixedIn.mixedInElements
1766+
TypeInferenceMixedIn.mixedInTypes
17671767
.map<String>((element) => element.name),
17681768
orderedEquals(['GenericMixin']));
17691769
expect(
@@ -1928,11 +1928,11 @@ void main() async {
19281928
});
19291929

19301930
test('mixins', () {
1931-
expect(Apple.mixedInElements, hasLength(0));
1931+
expect(Apple.mixedInTypes, hasLength(0));
19321932
});
19331933

19341934
test('mixins private', () {
1935-
expect(F.mixedInElements, hasLength(1));
1935+
expect(F.mixedInTypes, hasLength(1));
19361936
});
19371937

19381938
test('interfaces', () {
@@ -4487,30 +4487,6 @@ String? topLevelFunction(int param1, bool param2, Cool coolBeans,
44874487
});
44884488

44894489
group('Implementors', () {
4490-
late final Class apple;
4491-
late final Class b;
4492-
late final List<InheritingContainer> implA, implC;
4493-
4494-
setUpAll(() {
4495-
apple = exLibrary.classes.named('Apple');
4496-
b = exLibrary.classes.named('B');
4497-
implA = apple.publicImplementersSorted;
4498-
implC = exLibrary.classes.named('Cat').publicImplementersSorted;
4499-
});
4500-
4501-
test('private classes do not break the implementor chain', () {
4502-
var Super1 = fakeLibrary.classes.named('Super1');
4503-
var publicImplementors =
4504-
Super1.publicImplementersSorted.map((i) => i.name);
4505-
expect(publicImplementors, hasLength(3));
4506-
// A direct implementor.
4507-
expect(publicImplementors, contains('Super4'));
4508-
// An implementor through _Super2.
4509-
expect(publicImplementors, contains('Super3'));
4510-
// An implementor through _Super5 and _Super2.
4511-
expect(publicImplementors, contains('Super6'));
4512-
});
4513-
45144490
test(
45154491
'private classes in internal libraries do not break the implementor chain',
45164492
() {
@@ -4535,31 +4511,6 @@ String? topLevelFunction(int param1, bool param2, Cool coolBeans,
45354511
expect(publicImplementors, hasLength(1));
45364512
expect(publicImplementors, contains('GenericSuperInt'));
45374513
});
4538-
4539-
test('the first class is Apple', () {
4540-
expect(apple.name, equals('Apple'));
4541-
});
4542-
4543-
test('apple has some implementors', () {
4544-
expect(apple.hasPublicImplementers, isTrue);
4545-
expect(implA, isNotNull);
4546-
expect(implA, hasLength(1));
4547-
expect(implA[0].name, equals('B'));
4548-
});
4549-
4550-
test('Cat has implementors', () {
4551-
expect(implC, hasLength(3));
4552-
var implementors = <String>['B', 'Dog', 'ConstantCat'];
4553-
expect(implementors, contains(implC[0].name));
4554-
expect(implementors, contains(implC[1].name));
4555-
expect(implementors, contains(implC[2].name));
4556-
});
4557-
4558-
test('B does not have implementors', () {
4559-
expect(b, isNotNull);
4560-
expect(b.name, equals('B'));
4561-
expect(b.publicImplementersSorted, hasLength(0));
4562-
});
45634514
});
45644515

45654516
group('Errors and exceptions', () {
@@ -4569,6 +4520,7 @@ String? topLevelFunction(int param1, bool param2, Cool coolBeans,
45694520
'MyErrorImplements',
45704521
'MyExceptionImplements'
45714522
];
4523+
45724524
test('library has the exact errors/exceptions we expect', () {
45734525
expect(exLibrary.exceptions.map((e) => e.name),
45744526
unorderedEquals(expectedNames));

test/enums_test.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,11 @@ enum E<T> with M<T>, N { one, two, three; }
214214
''');
215215
var eEnum = library.enums.named('E');
216216

217-
expect(eEnum.mixedInElements, hasLength(2));
218-
expect(eEnum.mixedInElements.map((e) => e.name), equals(['M', 'N']));
217+
expect(eEnum.mixedInTypes.modelElements, hasLength(2));
218+
expect(
219+
eEnum.mixedInTypes.modelElements.map((e) => e.name),
220+
equals(['M', 'N']),
221+
);
219222
}
220223

221224
void test_operatorsAreDocumented() async {

test/templates/class_test.dart

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ class ClassTest extends TemplateTestBase {
2525
void test_implementers_class_extends() async {
2626
await createPackageWithLibrary('''
2727
class Base {}
28-
class Foo extends Base {}
28+
class _Foo extends Base {}
29+
class Foo extends _Foo {}
2930
''');
3031
var baseLines = readLines(['lib', 'Base-class.html']);
3132

@@ -40,7 +41,8 @@ class Foo extends Base {}
4041
void test_implementers_class_implements() async {
4142
await createPackageWithLibrary('''
4243
class Base {}
43-
class Foo implements Base {}
44+
class _Foo implements Base {}
45+
class Foo implements _Foo {}
4446
''');
4547
var baseLines = readLines(['lib', 'Base-class.html']);
4648

@@ -82,6 +84,22 @@ class Foo implements Base<int> {}
8284
]);
8385
}
8486

87+
void test_implementers_class_mixesIn() async {
88+
await createPackageWithLibrary('''
89+
class Base {}
90+
class _Foo with Base {}
91+
class Foo with _Foo {}
92+
''');
93+
var baseLines = readLines(['lib', 'Base-class.html']);
94+
95+
baseLines.expectMainContentContainsAllInOrder([
96+
matches('<dt>Implementers</dt>'),
97+
matches('<dd><ul class="comma-separated clazz-relationships">'),
98+
matches('<li><a href="../lib/Foo-class.html">Foo</a></li>'),
99+
matches('</ul></dd>'),
100+
]);
101+
}
102+
85103
void test_implementers_extensionType_implements() async {
86104
await createPackageWithLibrary('''
87105
class Base1 {}
@@ -102,7 +120,8 @@ extension type ET(Base2 base) implements Base1 {}
102120
void test_implementers_mixin_implements() async {
103121
await createPackageWithLibrary('''
104122
class Base {}
105-
mixin M implements Base {}
123+
mixin _M implements Base {}
124+
mixin M implements _M {}
106125
''');
107126
var baseLines = readLines(['lib', 'Base-class.html']);
108127

@@ -114,11 +133,11 @@ mixin M implements Base {}
114133
]);
115134
}
116135

117-
@FailingTest(reason: 'Not implemented yet; should be?')
118136
void test_implementers_mixin_superclassConstraint() async {
119137
await createPackageWithLibrary('''
120138
class Base {}
121-
mixin M on Base {}
139+
mixin _M on Base {}
140+
mixin M on _M {}
122141
''');
123142
var baseLines = readLines(['lib', 'Base-class.html']);
124143

testing/test_package/lib/fake.dart

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,18 +1214,6 @@ extension ExtensionOnTypeParameter<T> on T {
12141214
T aFunctionReturningT(T other) => other;
12151215
}
12161216

1217-
class Super1 {}
1218-
1219-
class _Super2 implements Super1 {}
1220-
1221-
class Super3 implements _Super2 {}
1222-
1223-
class Super4 implements Super1 {}
1224-
1225-
class _Super5 implements _Super2 {}
1226-
1227-
class Super6 implements _Super5 {}
1228-
12291217
abstract class IntermediateAbstract extends Object {
12301218
/// This is an override.
12311219
@override

0 commit comments

Comments
 (0)