// Copyright (c) 2019, 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. import 'dart:async'; import 'dart:io'; import 'dart:typed_data'; import 'package:front_end/src/api_unstable/bazel_worker.dart' as fe; import 'package:front_end/src/api_prototype/standard_file_system.dart'; import 'package:kernel/target/targets.dart'; import 'package:kernel/kernel.dart'; import 'package:kernel/verifier.dart'; import 'package:vm/target/vm.dart'; import 'package:vm/kernel_front_end.dart'; main() async { Uri sdkSummary = sdkRootFile(Platform.executable).resolve('vm_platform_strong.dill'); if (!await File.fromUri(sdkSummary).exists()) { // If we run from the /dart-sdk/bin folder, we need to navigate two // levels up. sdkSummary = sdkRootFile(Platform.executable) .resolve('../../vm_platform_strong.dill'); } // Tests are run in the root directory of the sdk checkout. final Uri packagesFile = sdkRootFile('.packages'); final Uri librariesFile = sdkRootFile('sdk/lib/libraries.json'); final vmTarget = VmTarget(TargetFlags()); await withTempDirectory((Uri uri) async { final mixinFilename = uri.resolve('mixin.dart'); final mixinDillFilename = uri.resolve('mixin.dart.dill'); await File.fromUri(mixinFilename).writeAsStringSync(mixinFile); await compileToKernel(vmTarget, librariesFile, sdkSummary, packagesFile, mixinDillFilename, [mixinFilename], []); final mainFilename = uri.resolve('main.dart'); final mainDillFilename = uri.resolve('main.dart.dill'); await File.fromUri(mainFilename).writeAsStringSync(mainFile); await compileToKernel(vmTarget, librariesFile, sdkSummary, packagesFile, mainDillFilename, [mainFilename], [mixinDillFilename]); final bytes = concat( await File.fromUri(sdkSummary).readAsBytes(), concat(await File.fromUri(mixinDillFilename).readAsBytes(), await File.fromUri(mainDillFilename).readAsBytes())); final component = loadComponentFromBytes(bytes); // Verify before running global transformations. verifyComponent(component, isOutline: false, afterConst: true); const useGlobalTypeFlowAnalysis = true; const enableAsserts = false; const useProtobufTreeShakerV2 = false; await runGlobalTransformations( vmTarget, component, useGlobalTypeFlowAnalysis, enableAsserts, useProtobufTreeShakerV2, ErrorDetector()); // Verify after running global transformations. verifyComponent(component, isOutline: false, afterConst: true); // Verify that we can reserialize the component to ensure that all // references are contained within the component. writeComponentToBytes( loadComponentFromBytes(writeComponentToBytes(component))); }); } Future compileToKernel( Target target, Uri librariesFile, Uri sdkSummary, Uri packagesFile, Uri outputFile, List sources, List additionalDills) async { final state = await fe.initializeCompiler( null, sdkSummary, librariesFile, packagesFile, additionalDills, target, StandardFileSystem.instance, const [], const {}); void onDiagnostic(fe.DiagnosticMessage message) { message.plainTextFormatted.forEach(print); } final Component component = await fe.compileComponent(state, sources, onDiagnostic); final Uint8List kernel = fe.serializeComponent(component, filter: (library) => sources.contains(library.importUri)); await File(outputFile.toFilePath()).writeAsBytes(kernel); } Future withTempDirectory(Future func(Uri dirUri)) async { final dir = await Directory.systemTemp.createTemp('modular-compile-test'); try { await func(dir.uri); } finally { await dir.delete(recursive: true); } } Uint8List concat(List a, List b) { final bytes = Uint8List(a.length + b.length); bytes.setRange(0, a.length, a); bytes.setRange(a.length, bytes.length, b); return bytes; } Uri sdkRootFile(name) => Directory.current.uri.resolveUri(Uri.file(name)); const String mainFile = r''' // @dart=2.9 // This library is opt-out to provoke the creation of member signatures in // R that point to members of A2. import 'mixin.dart'; class R extends A2 { void bar() { mixinProperty = ''; mixinProperty.foo(); mixinMethod('').foo(); super.mixinProperty= ''; super.mixinProperty.foo(); super.mixinMethod('').foo(); } } main() { A1(); final a2 = A2(); // The mixin deduplication will remove the anonymous mixin application class // from `A2 & Mixin` and instead use the one from `A1 & Mixin`. a2.mixinProperty= ''; a2.mixinProperty.foo(); a2.mixinMethod('').foo(); R().bar(); B1(); B1.named(); B2(); final b2 = B2.named(); // The mixin deduplication will remove the anonymous mixin application class // from `B2 & Mixin` and instead use the one from `B1 & Mixin`. b2.mixinProperty= ''; b2.mixinProperty.foo(); b2.mixinMethod('').foo(); } '''; const String mixinFile = r''' class Foo { foo() {} } class Mixin { void set mixinProperty(v) {} Foo get mixinProperty => new Foo(); Foo mixinMethod(v) => new Foo(); } class A1 extends Object with Mixin { } class A2 extends Object with Mixin { } class B { B(); B.named(); } class B1 extends B with Mixin { B1() : super(); B1.named() : super.named(); } class B2 extends B with Mixin { B2() : super(); B2.named() : super.named(); } ''';