| Index: tests/compiler/dart2js/kernel/mixin_test.dart
|
| diff --git a/tests/compiler/dart2js/kernel/mixin_test.dart b/tests/compiler/dart2js/kernel/mixin_test.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ca56dc15300b83860807a2a0e1b099a4c9d2d941
|
| --- /dev/null
|
| +++ b/tests/compiler/dart2js/kernel/mixin_test.dart
|
| @@ -0,0 +1,201 @@
|
| +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +// Test that the optimized algorithm for mixin applications matches the mixins
|
| +// generated by fasta.
|
| +library dart2js.kernel.mixins_test;
|
| +
|
| +import 'package:async_helper/async_helper.dart';
|
| +import 'package:compiler/src/commandline_options.dart';
|
| +import 'package:compiler/src/common_elements.dart';
|
| +import 'package:compiler/src/compiler.dart';
|
| +import 'package:compiler/src/elements/entities.dart';
|
| +import 'package:compiler/src/elements/types.dart';
|
| +import 'package:compiler/src/kernel/kernel_strategy.dart';
|
| +import 'package:compiler/src/resolution/class_hierarchy.dart';
|
| +import 'package:compiler/src/universe/class_set.dart';
|
| +import 'package:compiler/src/world.dart';
|
| +import 'package:expect/expect.dart';
|
| +import '../memory_compiler.dart';
|
| +import '../equivalence/check_helpers.dart';
|
| +import 'test_helpers.dart';
|
| +import 'compiler_helper.dart';
|
| +
|
| +const SOURCE = const {
|
| + 'main.dart': '''
|
| +
|
| +class Super {}
|
| +class Mixin1 {}
|
| +class Mixin2 {}
|
| +class Sub1 extends Super with Mixin1 {}
|
| +class Sub2 extends Super with Mixin1, Mixin2 {}
|
| +class NamedSub1 = Super with Mixin1;
|
| +class NamedSub2 = Super with Mixin1, Mixin2;
|
| +
|
| +
|
| +class GenericSuper<T> {}
|
| +class GenericMixin1<T> {}
|
| +class GenericMixin2<T> {}
|
| +class GenericSub1<T> extends GenericSuper<T> with GenericMixin1<T> {}
|
| +class GenericSub2<T> extends GenericSuper<T>
|
| + with GenericMixin1<T>, GenericMixin2<T> {}
|
| +class GenericNamedSub1<T> = GenericSuper<T> with GenericMixin1<T>;
|
| +class GenericNamedSub2<T> = GenericSuper<T>
|
| + with GenericMixin1<T>, GenericMixin2<T>;
|
| +
|
| +class FixedSub1a extends GenericSuper<int> with GenericMixin1<int> {}
|
| +class FixedSub1b extends GenericSuper<int> with GenericMixin1<double> {}
|
| +class FixedSub2a extends GenericSuper<int>
|
| + with GenericMixin1<int>, GenericMixin2<int> {}
|
| +class FixedSub2b extends GenericSuper<double>
|
| + with GenericMixin1<double>, GenericMixin2<double> {}
|
| +
|
| +
|
| +main() {
|
| + new Super();
|
| + new Mixin1();
|
| + new Mixin2();
|
| + new Sub1();
|
| + new Sub2();
|
| + new NamedSub1();
|
| + new NamedSub2();
|
| +
|
| + new GenericSuper<int>();
|
| + new GenericMixin1<int>();
|
| + new GenericMixin2<int>();
|
| + new GenericSub1<int>();
|
| + new GenericSub2<int>();
|
| + new GenericNamedSub1<int>();
|
| + new GenericNamedSub2<int>();
|
| +
|
| + new FixedSub1a();
|
| + new FixedSub1b();
|
| + new FixedSub2a();
|
| + new FixedSub2b();
|
| +}
|
| +'''
|
| +};
|
| +
|
| +Map<ClassEntity, String> generateClassEnv(
|
| + ElementEnvironment env, DartTypes types) {
|
| + Map<ClassEntity, String> classEnv = <ClassEntity, String>{};
|
| +
|
| + void createEnv(ClassEntity cls) {
|
| + classEnv.putIfAbsent(cls, () {
|
| + InterfaceType thisType = env.getThisType(cls);
|
| + StringBuffer sb = new StringBuffer();
|
| + sb.write('class ');
|
| + sb.write(env.getThisType(cls));
|
| + ClassEntity superclass = env.getSuperClass(cls);
|
| + if (superclass != null) {
|
| + createEnv(superclass);
|
| + sb.write(' extends ');
|
| + sb.write(types.asInstanceOf(thisType, superclass));
|
| + }
|
| + return sb.toString();
|
| + });
|
| + }
|
| +
|
| + env.forEachClass(env.mainLibrary, createEnv);
|
| +
|
| + return classEnv;
|
| +}
|
| +
|
| +main(List<String> args) {
|
| + asyncTest(() async {
|
| + useOptimizedMixins = true;
|
| +
|
| + Uri entryPoint = await createTemp(Uri.parse('memory:main.dart'), SOURCE,
|
| + printSteps: true);
|
| +
|
| + print(
|
| + '---- compiler from ast -----------------------------------------------');
|
| + var result =
|
| + await runCompiler(entryPoint: entryPoint, options: [Flags.analyzeOnly]);
|
| + Compiler compiler1 = result.compiler;
|
| +
|
| + Compiler compiler2 = await compileWithDill(
|
| + entryPoint, {}, [Flags.analyzeOnly],
|
| + printSteps: true);
|
| +
|
| + ElementEnvironment env1 = compiler1.frontendStrategy.elementEnvironment;
|
| + DartTypes types1 = compiler1.frontendStrategy.dartTypes;
|
| + ClosedWorld closedWorld1 = compiler1.resolutionWorldBuilder.closeWorld();
|
| +
|
| + KernelFrontEndStrategy frontendStrategy = compiler2.frontendStrategy;
|
| + ElementEnvironment env2 = frontendStrategy.elementEnvironment;
|
| + DartTypes types2 = frontendStrategy.dartTypes;
|
| + ClosedWorld closedWorld2 = compiler2.resolutionWorldBuilder.closeWorld();
|
| +
|
| + KernelEquivalence equivalence =
|
| + new KernelEquivalence(frontendStrategy.elementMap);
|
| +
|
| + if (args.contains('-v')) {
|
| + Map<ClassEntity, String> classEnv1 = generateClassEnv(env1, types1);
|
| + Map<ClassEntity, String> classEnv2 = generateClassEnv(env2, types2);
|
| +
|
| + print('----');
|
| + classEnv1.forEach((ClassEntity cls, String env) {
|
| + print(env);
|
| + });
|
| + print('----');
|
| + classEnv2.forEach((ClassEntity cls, String env) {
|
| + print(env);
|
| + });
|
| + }
|
| +
|
| + void checkClasses(ClassEntity cls1, ClassEntity cls2) {
|
| + if (cls1 == cls2) return;
|
| + Expect.isNotNull(cls1, 'Missing class ${cls2.name}');
|
| + Expect.isNotNull(cls2, 'Missing class ${cls1.name}');
|
| +
|
| + check(cls1.library, cls2.library, 'class ${cls1.name}', cls1, cls2,
|
| + equivalence.entityEquivalence);
|
| + InterfaceType thisType1 = types1.getThisType(cls1);
|
| + InterfaceType thisType2 = types2.getThisType(cls2);
|
| + check(cls1, cls2, 'thisType', thisType1, thisType2,
|
| + equivalence.typeEquivalence);
|
| + check(cls1, cls2, 'supertype', types1.getSupertype(cls1),
|
| + types2.getSupertype(cls2), equivalence.typeEquivalence);
|
| + checkClasses(env1.getSuperClass(cls1), env2.getSuperClass(cls2));
|
| +
|
| + List<DartType> mixins1 = <DartType>[];
|
| + env1.forEachMixin(cls1, (ClassEntity mixin) {
|
| + mixins1.add(types1.asInstanceOf(thisType1, mixin));
|
| + });
|
| + List<DartType> mixins2 = <DartType>[];
|
| + env2.forEachMixin(cls2, (ClassEntity mixin) {
|
| + mixins2.add(types2.asInstanceOf(thisType2, mixin));
|
| + });
|
| + checkLists(
|
| + mixins1, mixins2, '${cls1.name} mixins', equivalence.typeEquivalence);
|
| +
|
| + checkLists(
|
| + types1.getInterfaces(cls1).toList(),
|
| + types2.getInterfaces(cls2).toList(),
|
| + '${cls1.name} interfaces',
|
| + equivalence.typeEquivalence);
|
| + checkLists(
|
| + types1.getSupertypes(cls1).toList(),
|
| + types2.getSupertypes(cls2).toList(),
|
| + '${cls1.name} supertypes',
|
| + equivalence.typeEquivalence);
|
| +
|
| + if (cls1 == compiler1.frontendStrategy.commonElements.objectClass) return;
|
| +
|
| + ClassHierarchyNode node1 = closedWorld1.getClassHierarchyNode(cls1);
|
| + ClassHierarchyNode node2 = closedWorld2.getClassHierarchyNode(cls2);
|
| + checkSets(
|
| + new Set.from(node1.directSubclasses),
|
| + new Set.from(node2.directSubclasses),
|
| + '${cls1.name} direct subclasses',
|
| + (a, b) => equivalence.entityEquivalence(a.cls, b.cls));
|
| + }
|
| +
|
| + env1.forEachClass(env1.mainLibrary, (ClassEntity cls1) {
|
| + ClassEntity cls2 = env2.lookupClass(env2.mainLibrary, cls1.name);
|
| + checkClasses(cls1, cls2);
|
| + });
|
| + });
|
| +}
|
|
|