Skip to content

Commit c9b05d3

Browse files
Kevin Millikincommit-bot@chromium.org
Kevin Millikin
authored andcommitted
Allow super calls in mixin declarations
Allow super calls to occur in mixin declarations if they target a method from any of the superclass constraint interfaces. Instead of compiling the Dart mixin declaration mixin M on S0, S1 {...} to Kernel: abstract class _M&S0&S1 = S0 with S1; abstract class M extends _M&S0&S1 { ... } we compile it to Kernel: abstract class _M&S0&S1 implements S0, S1 {} abstract class M extends _M&S0&S1 { ... } because the former is not symmetrical with respect to S0 and S1. It will prefer a method from the 'mixin' S1 over one from S0 which can give a compile-time error if the method from S0 is more general. Modify mixin inference to support the new compilation of mixin declarations. It still has to support old-style VM super mixins until support for those is removed from the VM. Change-Id: Ib945aa11cc19c457b07bc802beae10d1663ff6b7 Reviewed-on: https://dart-review.googlesource.com/76141 Reviewed-by: Jenny Messerly <[email protected]> Reviewed-by: Johnni Winther <[email protected]> Reviewed-by: Dmitry Stefantsov <[email protected]> Commit-Queue: Kevin Millikin <[email protected]>
1 parent 225b8d5 commit c9b05d3

File tree

50 files changed

+536
-167
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+536
-167
lines changed

pkg/compiler/lib/src/kernel/element_map_impl.dart

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -289,44 +289,7 @@ abstract class KernelToElementMapBase implements IrToElementMap {
289289
InterfaceType supertype;
290290
LinkBuilder<InterfaceType> linkBuilder =
291291
new LinkBuilder<InterfaceType>();
292-
if (node.isMixinDeclaration) {
293-
// A mixin declaration
294-
//
295-
// mixin M on A, B, C {}
296-
//
297-
// is encoded by CFE as
298-
//
299-
// abstract class M extends A with B, C {}
300-
//
301-
// but we encode it as
302-
//
303-
// abstract class M extends Object implements A, B, C {}
304-
//
305-
// so we need to collect the non-Object superclasses and add them
306-
// to the interfaces of M.
307-
308-
ir.Class superclass = node.superclass;
309-
while (superclass != null) {
310-
if (superclass.isAnonymousMixin) {
311-
// Add second to last mixed in superclasses. `B` and `C` in the
312-
// example above.
313-
ir.DartType mixinType = typeEnvironment.hierarchy
314-
.getTypeAsInstanceOf(node.thisType, superclass.mixedInClass);
315-
linkBuilder.addLast(getDartType(mixinType));
316-
} else {
317-
// Add first mixed in superclass. `A` in the example above.
318-
ir.DartType mixinType = typeEnvironment.hierarchy
319-
.getTypeAsInstanceOf(node.thisType, superclass);
320-
linkBuilder.addLast(getDartType(mixinType));
321-
break;
322-
}
323-
superclass = superclass.superclass;
324-
}
325-
// Set superclass to `Object`.
326-
supertype = _commonElements.objectType;
327-
} else {
328-
supertype = processSupertype(node.supertype);
329-
}
292+
supertype = processSupertype(node.supertype);
330293
if (supertype == _commonElements.objectType) {
331294
ClassEntity defaultSuperclass =
332295
_commonElements.getDefaultSuperclass(cls, nativeBasicData);

pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,8 @@ Class getSuperclassAndMixins(Class c, List<Class> mixins) {
230230

231231
var sc = c.superclass;
232232
for (; sc.isAnonymousMixin; sc = sc.superclass) {
233-
mixins.add(sc.mixedInClass);
233+
mixedInClass = sc.mixedInClass;
234+
if (mixedInClass != null) mixins.add(sc.mixedInClass);
234235
}
235236
return sc;
236237
}

pkg/front_end/lib/src/fasta/kernel/body_builder.dart

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,11 +1494,12 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
14941494
Member target = isSuper
14951495
? hierarchy.getDispatchTarget(cls, name, setter: isSetter)
14961496
: hierarchy.getInterfaceMember(cls, name, setter: isSetter);
1497-
if (isSuper &&
1498-
target == null &&
1499-
library.loader.target.backendTarget.enableSuperMixins &&
1500-
classBuilder.isAbstract) {
1501-
target = hierarchy.getInterfaceMember(cls, name, setter: isSetter);
1497+
if (isSuper && target == null) {
1498+
if (classBuilder.cls.isMixinDeclaration ||
1499+
(library.loader.target.backendTarget.enableSuperMixins &&
1500+
classBuilder.isAbstract)) {
1501+
target = hierarchy.getInterfaceMember(cls, name, setter: isSetter);
1502+
}
15021503
}
15031504
return target;
15041505
}

pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ class KernelLibraryBuilder
231231
modifiers,
232232
className,
233233
typeVariables,
234-
applyMixins(supertype, supertypeOffset, className,
234+
applyMixins(supertype, supertypeOffset, className, isMixinDeclaration,
235235
typeVariables: typeVariables),
236236
interfaces,
237237
classScope,
@@ -307,8 +307,8 @@ class KernelLibraryBuilder
307307
return typeVariablesByName;
308308
}
309309

310-
KernelTypeBuilder applyMixins(
311-
KernelTypeBuilder type, int charOffset, String subclassName,
310+
KernelTypeBuilder applyMixins(KernelTypeBuilder type, int charOffset,
311+
String subclassName, bool isMixinDeclaration,
312312
{String documentationComment,
313313
List<MetadataBuilder> metadata,
314314
String name,
@@ -469,8 +469,10 @@ class KernelLibraryBuilder
469469
: abstractMask,
470470
fullname,
471471
applicationTypeVariables,
472-
supertype,
473-
isNamedMixinApplication ? interfaces : null,
472+
isMixinDeclaration ? null : supertype,
473+
isNamedMixinApplication
474+
? interfaces
475+
: isMixinDeclaration ? [supertype, mixin] : null,
474476
new Scope(<String, MemberBuilder>{}, <String, MemberBuilder>{},
475477
scope.withTypeVariables(typeVariables),
476478
"mixin $fullname ", isModifiable: false),
@@ -481,7 +483,7 @@ class KernelLibraryBuilder
481483
startCharOffset,
482484
charOffset,
483485
TreeNode.noOffset,
484-
mixedInType: mixin);
486+
mixedInType: isMixinDeclaration ? null : mixin);
485487
if (isNamedMixinApplication) {
486488
loader.target.metadataCollector?.setDocumentationComment(
487489
application.target, documentationComment);
@@ -512,7 +514,7 @@ class KernelLibraryBuilder
512514
// Nested declaration began in `OutlineBuilder.beginNamedMixinApplication`.
513515
endNestedDeclaration(name).resolveTypes(typeVariables, this);
514516
KernelNamedTypeBuilder supertype = applyMixins(
515-
mixinApplication, charOffset, name,
517+
mixinApplication, charOffset, name, false,
516518
documentationComment: documentationComment,
517519
metadata: metadata,
518520
name: name,

pkg/front_end/lib/src/fasta/source/source_loader.dart

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ import 'package:kernel/class_hierarchy.dart'
3030

3131
import 'package:kernel/core_types.dart' show CoreTypes;
3232

33-
import 'package:kernel/type_environment.dart' show TypeEnvironment;
34-
3533
import '../../api_prototype/file_system.dart';
3634

3735
import '../../base/instrumentation.dart'
@@ -801,16 +799,9 @@ class SourceLoader<L> extends Loader<L> {
801799
}
802800

803801
void handleAmbiguousSupertypes(Class cls, Supertype a, Supertype b) {
804-
String name = cls.name;
805-
TypeEnvironment env = new TypeEnvironment(coreTypes, hierarchy,
806-
strongMode: target.strongMode);
807-
808-
if (cls.isAnonymousMixin) return;
809-
810-
if (env.isSubtypeOf(a.asInterfaceType, b.asInterfaceType)) return;
811802
addProblem(
812803
templateAmbiguousSupertypes.withArguments(
813-
name, a.asInterfaceType, b.asInterfaceType),
804+
cls.name, a.asInterfaceType, b.asInterfaceType),
814805
cls.fileOffset,
815806
noLength,
816807
cls.fileUri);

pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,26 +1932,38 @@ class StrongModeMixinInferrer implements MixinInferrer {
19321932
if (mixinSupertype.typeArguments.isEmpty) {
19331933
// The supertype constraint isn't generic; it doesn't constrain anything.
19341934
} else if (mixinSupertype.classNode.isAnonymousMixin) {
1935-
// We had a mixin M<X0, ..., Xn> with a superclass constraint of the form
1936-
// S0 with M0 where S0 and M0 each possibly have type arguments. That has
1937-
// been compiled a named mixin application class of the form
1935+
// We have either a mixin declaration `mixin M<X0, ..., Xn> on S0, S1` or
1936+
// a VM-style super mixin `abstract class M<X0, ..., Xn> extends S0 with
1937+
// S1` where S0 and S1 are superclass constraints that possibly have type
1938+
// arguments.
19381939
//
1939-
// class S0&M0<...> = S0 with M0;
1940-
// class M<X0, ..., Xn> extends S0&M0<...>
1940+
// It has been compiled by naming the superclass to either:
19411941
//
1942-
// where the type parameters of S0&M0 are the X0, ..., Xn that occured
1943-
// free in S0 and M0. Treat S0 and M0 as separate supertype constraints
1944-
// by recursively calling this algorithm.
1942+
// abstract class S0&S1<...> extends Object implements S0, S1 {}
1943+
// abstract class M<X0, ..., Xn> extends S0&S1<...> ...
19451944
//
1946-
// In some back ends (e.g., the Dart VM) the mixin application classes
1947-
// themselves are all eliminated by translating them to normal classes.
1948-
// In that case, the mixin appears as the only interface in the
1949-
// introduced class:
1945+
// for a mixin declaration, or else:
19501946
//
1951-
// class S0&M0<...> extends S0 implements M0 {}
1947+
// abstract class S0&S1<...> = S0 with S1;
1948+
// abstract class M<X0, ..., Xn> extends S0&S1<...>
1949+
//
1950+
// for a VM-style super mixin. The type parameters of S0&S1 are the X0,
1951+
// ..., Xn that occured free in S0 and S1. Treat S0 and S1 as separate
1952+
// supertype constraints by recursively calling this algorithm.
1953+
//
1954+
// In the Dart VM the mixin application classes themselves are all
1955+
// eliminated by translating them to normal classes. In that case, the
1956+
// mixin appears as the only interface in the introduced class. We
1957+
// support three forms for the superclass constraints:
1958+
//
1959+
// abstract class S0&S1<...> extends Object implements S0, S1 {}
1960+
// abstract class S0&S1<...> = S0 with S1;
1961+
// abstract class S0&S1<...> extends S0 implements S1 {}
19521962
var mixinSuperclass = mixinSupertype.classNode;
19531963
if (mixinSuperclass.mixedInType == null &&
1954-
mixinSuperclass.implementedTypes.length != 1) {
1964+
mixinSuperclass.implementedTypes.length != 1 &&
1965+
(mixinSuperclass.superclass != coreTypes.objectClass ||
1966+
mixinSuperclass.implementedTypes.length != 2)) {
19551967
unexpected(
19561968
'Compiler-generated mixin applications have a mixin or else '
19571969
'implement exactly one type',
@@ -1961,11 +1973,21 @@ class StrongModeMixinInferrer implements MixinInferrer {
19611973
mixinSuperclass.fileUri);
19621974
}
19631975
var substitution = Substitution.fromSupertype(mixinSupertype);
1964-
var s0 = substitution.substituteSupertype(mixinSuperclass.supertype);
1965-
var m0 = substitution.substituteSupertype(mixinSuperclass.mixedInType ??
1966-
mixinSuperclass.implementedTypes.first);
1976+
Supertype s0, s1;
1977+
if (mixinSuperclass.implementedTypes.length == 2) {
1978+
s0 = mixinSuperclass.implementedTypes[0];
1979+
s1 = mixinSuperclass.implementedTypes[1];
1980+
} else if (mixinSuperclass.implementedTypes.length == 1) {
1981+
s0 = mixinSuperclass.supertype;
1982+
s1 = mixinSuperclass.implementedTypes.first;
1983+
} else {
1984+
s0 = mixinSuperclass.supertype;
1985+
s1 = mixinSuperclass.mixedInType;
1986+
}
1987+
s0 = substitution.substituteSupertype(s0);
1988+
s1 = substitution.substituteSupertype(s1);
19671989
generateConstraints(hierarchy, mixinClass, baseType, s0);
1968-
generateConstraints(hierarchy, mixinClass, baseType, m0);
1990+
generateConstraints(hierarchy, mixinClass, baseType, s1);
19691991
} else {
19701992
// Find the type U0 which is baseType as an instance of mixinSupertype's
19711993
// class.
@@ -2028,11 +2050,10 @@ class StrongModeMixinInferrer implements MixinInferrer {
20282050
return p;
20292051
}
20302052
assert(constraint == null || constraint.upper == constraint.lower);
2053+
bool exact =
2054+
constraint != null && constraint.upper != const UnknownType();
20312055
return new TypeParameter(
2032-
p.name,
2033-
constraint == null || constraint.upper == const UnknownType()
2034-
? p.bound
2035-
: constraint.upper);
2056+
p.name, exact ? constraint.upper : p.bound, p.defaultType);
20362057
}).toList();
20372058
// Bounds might mention the mixin class's type parameters so we have to
20382059
// substitute them before calling instantiate to bounds.

pkg/front_end/testcases/incremental_initialize_from_dill/strongmode_mixins_2.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ invalidate:
1212
sources:
1313
a.dart: |
1414
import 'b.dart';
15-
class A extends Object with B<C>, D<Object> {}
15+
class A extends Object with B<C>, D {}
1616
b.dart: |
17-
abstract class B<ChildType extends Object> extends Object {
17+
mixin B<ChildType extends Object> {
1818
ChildType get child => null;
1919
set child(ChildType value) {}
2020
}
2121
22-
class C extends Object {}
22+
class C {}
2323
24-
abstract class D<T extends Object> extends Object with B<T> {}
24+
mixin D<T extends Object> on B<T> {}

pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart.direct.expect

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
// Formatted problems:
2+
//
3+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart:12:9: Error: '_A&M1&M0' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
4+
// class A extends M1 with M0 {}
5+
// ^
6+
//
7+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart:12:7: Error: 'A' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
8+
// class A extends M1 with M0 {}
9+
// ^
10+
11+
// Unhandled errors:
12+
//
13+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart:12:9: Error: '_A&M1&M0' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
14+
// class A extends M1 with M0 {}
15+
// ^
16+
//
17+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart:12:7: Error: 'A' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
18+
// class A extends M1 with M0 {}
19+
// ^
20+
121
library;
222
import self as self;
323
import "dart:core" as core;

pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart.direct.transformed.expect

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
// Unhandled errors:
2+
//
3+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart:12:9: Error: '_A&M1&M0' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
4+
// class A extends M1 with M0 {}
5+
// ^
6+
//
7+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart:12:7: Error: 'A' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
8+
// class A extends M1 with M0 {}
9+
// ^
10+
111
library;
212
import self as self;
313
import "dart:core" as core;

pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart.outline.expect

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
// Formatted problems:
2+
//
3+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart:12:9: Error: '_A&M1&M0' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
4+
// class A extends M1 with M0 {}
5+
// ^
6+
//
7+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_1.dart:12:7: Error: 'A' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
8+
// class A extends M1 with M0 {}
9+
// ^
10+
111
library;
212
import self as self;
313
import "dart:core" as core;

pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart.direct.expect

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
// Formatted problems:
2+
//
3+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart:12:9: Error: '_A&M1&M0' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
4+
// class A extends M1 with M0 {}
5+
// ^
6+
//
7+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart:12:7: Error: 'A' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
8+
// class A extends M1 with M0 {}
9+
// ^
10+
11+
// Unhandled errors:
12+
//
13+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart:12:9: Error: '_A&M1&M0' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
14+
// class A extends M1 with M0 {}
15+
// ^
16+
//
17+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart:12:7: Error: 'A' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
18+
// class A extends M1 with M0 {}
19+
// ^
20+
121
library;
222
import self as self;
323
import "dart:core" as core;

pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart.direct.transformed.expect

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
// Unhandled errors:
2+
//
3+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart:12:9: Error: '_A&M1&M0' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
4+
// class A extends M1 with M0 {}
5+
// ^
6+
//
7+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart:12:7: Error: 'A' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
8+
// class A extends M1 with M0 {}
9+
// ^
10+
111
library;
212
import self as self;
313
import "dart:core" as core;

pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart.outline.expect

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
// Formatted problems:
2+
//
3+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart:12:9: Error: '_A&M1&M0' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
4+
// class A extends M1 with M0 {}
5+
// ^
6+
//
7+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_2.dart:12:7: Error: 'A' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
8+
// class A extends M1 with M0 {}
9+
// ^
10+
111
library;
212
import self as self;
313
import "dart:core" as core;

pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.direct.expect

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
// Formatted problems:
2+
//
3+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart:13:9: Error: '_A&M1&M0' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
4+
// class A extends M1 with M0 {}
5+
// ^
6+
//
7+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart:13:7: Error: 'A' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
8+
// class A extends M1 with M0 {}
9+
// ^
10+
11+
// Unhandled errors:
12+
//
13+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart:13:9: Error: '_A&M1&M0' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
14+
// class A extends M1 with M0 {}
15+
// ^
16+
//
17+
// pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart:13:7: Error: 'A' can't implement both '#lib1::I<dart.core::int>' and '#lib1::I<dynamic>'
18+
// class A extends M1 with M0 {}
19+
// ^
20+
121
library;
222
import self as self;
323
import "dart:core" as core;

0 commit comments

Comments
 (0)