2cc4d7ca2f
Validates that the .dill files provided for dependencies and the SDK support sound null safety when compiling for strong mode. Change-Id: Id1f7547a6bc473b901bfce62145cc918353c8ea4 Issue: https://github.com/dart-lang/sdk/issues/41694 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/149080 Reviewed-by: Jens Johansen <jensj@google.com> Commit-Queue: Nicholas Shahan <nshahan@google.com>
236 lines
8.6 KiB
Dart
236 lines
8.6 KiB
Dart
// 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.
|
|
|
|
/// Defines the front-end API for converting source code to Dart Kernel objects.
|
|
library front_end.kernel_generator_impl;
|
|
|
|
import 'dart:async' show Future;
|
|
|
|
import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
|
|
|
|
import 'package:kernel/kernel.dart'
|
|
show CanonicalName, Component, NonNullableByDefaultCompiledMode;
|
|
|
|
import 'base/nnbd_mode.dart';
|
|
|
|
import 'base/processed_options.dart' show ProcessedOptions;
|
|
|
|
import 'fasta/compiler_context.dart' show CompilerContext;
|
|
|
|
import 'fasta/crash.dart' show withCrashReporting;
|
|
|
|
import 'fasta/dill/dill_target.dart' show DillTarget;
|
|
|
|
import 'fasta/fasta_codes.dart' show LocatedMessage;
|
|
|
|
import 'fasta/kernel/kernel_api.dart';
|
|
|
|
import 'fasta/kernel/kernel_target.dart' show KernelTarget;
|
|
|
|
import 'fasta/kernel/utils.dart' show printComponentText, serializeComponent;
|
|
|
|
import 'fasta/kernel/verifier.dart' show verifyComponent;
|
|
|
|
import 'fasta/loader.dart' show Loader;
|
|
|
|
import 'fasta/uri_translator.dart' show UriTranslator;
|
|
|
|
import 'api_prototype/front_end.dart' show CompilerResult;
|
|
|
|
import 'api_prototype/file_system.dart' show FileSystem;
|
|
|
|
/// Implementation for the
|
|
/// `package:front_end/src/api_prototype/kernel_generator.dart` and
|
|
/// `package:front_end/src/api_prototype/summary_generator.dart` APIs.
|
|
Future<CompilerResult> generateKernel(ProcessedOptions options,
|
|
{bool buildSummary: false,
|
|
bool buildComponent: true,
|
|
bool truncateSummary: false,
|
|
bool includeOffsets: true,
|
|
bool includeHierarchyAndCoreTypes: false}) async {
|
|
return await CompilerContext.runWithOptions(options, (_) async {
|
|
return await generateKernelInternal(
|
|
buildSummary: buildSummary,
|
|
buildComponent: buildComponent,
|
|
truncateSummary: truncateSummary,
|
|
includeOffsets: includeOffsets,
|
|
includeHierarchyAndCoreTypes: includeHierarchyAndCoreTypes);
|
|
});
|
|
}
|
|
|
|
Future<CompilerResult> generateKernelInternal(
|
|
{bool buildSummary: false,
|
|
bool buildComponent: true,
|
|
bool truncateSummary: false,
|
|
bool includeOffsets: true,
|
|
bool retainDataForTesting: false,
|
|
bool includeHierarchyAndCoreTypes: false}) async {
|
|
ProcessedOptions options = CompilerContext.current.options;
|
|
FileSystem fs = options.fileSystem;
|
|
|
|
Loader sourceLoader;
|
|
return withCrashReporting<CompilerResult>(() async {
|
|
UriTranslator uriTranslator = await options.getUriTranslator();
|
|
|
|
DillTarget dillTarget =
|
|
new DillTarget(options.ticker, uriTranslator, options.target);
|
|
|
|
List<Component> loadedComponents = new List<Component>();
|
|
|
|
Component sdkSummary = await options.loadSdkSummary(null);
|
|
// By using the nameRoot of the the summary, we enable sharing the
|
|
// sdkSummary between multiple invocations.
|
|
CanonicalName nameRoot = sdkSummary?.root ?? new CanonicalName.root();
|
|
if (sdkSummary != null) {
|
|
if (options.nnbdMode == NnbdMode.Strong &&
|
|
!(sdkSummary.mode == NonNullableByDefaultCompiledMode.Strong ||
|
|
sdkSummary.mode == NonNullableByDefaultCompiledMode.Agnostic)) {
|
|
throw new FormatException(
|
|
'Provided SDK .dill does not support sound null safety.');
|
|
}
|
|
dillTarget.loader.appendLibraries(sdkSummary);
|
|
}
|
|
|
|
for (Component additionalDill
|
|
in await options.loadAdditionalDills(nameRoot)) {
|
|
if (options.nnbdMode == NnbdMode.Strong &&
|
|
!(additionalDill.mode == NonNullableByDefaultCompiledMode.Strong ||
|
|
// In some VM tests the SDK dill appears as an additionalDill so
|
|
// allow agnostic here as well.
|
|
additionalDill.mode ==
|
|
NonNullableByDefaultCompiledMode.Agnostic)) {
|
|
throw new FormatException(
|
|
'Provided .dill file for the following libraries does not support '
|
|
'sound null safety:\n'
|
|
'${additionalDill.libraries.join('\n')}');
|
|
}
|
|
loadedComponents.add(additionalDill);
|
|
dillTarget.loader.appendLibraries(additionalDill);
|
|
}
|
|
|
|
await dillTarget.buildOutlines();
|
|
|
|
KernelTarget kernelTarget =
|
|
new KernelTarget(fs, false, dillTarget, uriTranslator);
|
|
sourceLoader = kernelTarget.loader;
|
|
kernelTarget.setEntryPoints(options.inputs);
|
|
Component summaryComponent =
|
|
await kernelTarget.buildOutlines(nameRoot: nameRoot);
|
|
List<int> summary = null;
|
|
if (buildSummary) {
|
|
if (options.verify) {
|
|
for (LocatedMessage error in verifyComponent(summaryComponent)) {
|
|
options.report(error, Severity.error);
|
|
}
|
|
}
|
|
if (options.debugDump) {
|
|
printComponentText(summaryComponent,
|
|
libraryFilter: kernelTarget.isSourceLibrary);
|
|
}
|
|
|
|
// Create the requested component ("truncating" or not).
|
|
//
|
|
// Note: we don't pass the library argument to the constructor to
|
|
// preserve the the libraries parent pointer (it should continue to point
|
|
// to the component within KernelTarget).
|
|
Component trimmedSummaryComponent =
|
|
new Component(nameRoot: summaryComponent.root)
|
|
..libraries.addAll(truncateSummary
|
|
? kernelTarget.loader.libraries
|
|
: summaryComponent.libraries);
|
|
trimmedSummaryComponent.metadata.addAll(summaryComponent.metadata);
|
|
trimmedSummaryComponent.uriToSource.addAll(summaryComponent.uriToSource);
|
|
|
|
NonNullableByDefaultCompiledMode compiledMode =
|
|
NonNullableByDefaultCompiledMode.Disabled;
|
|
switch (options.nnbdMode) {
|
|
case NnbdMode.Weak:
|
|
compiledMode = NonNullableByDefaultCompiledMode.Weak;
|
|
break;
|
|
case NnbdMode.Strong:
|
|
compiledMode = NonNullableByDefaultCompiledMode.Strong;
|
|
break;
|
|
case NnbdMode.Agnostic:
|
|
compiledMode = NonNullableByDefaultCompiledMode.Agnostic;
|
|
break;
|
|
}
|
|
|
|
trimmedSummaryComponent.setMainMethodAndMode(
|
|
trimmedSummaryComponent.mainMethodName, false, compiledMode);
|
|
|
|
// As documented, we only run outline transformations when we are building
|
|
// summaries without building a full component (at this time, that's
|
|
// the only need we have for these transformations).
|
|
if (!buildComponent) {
|
|
options.target.performOutlineTransformations(trimmedSummaryComponent);
|
|
options.ticker.logMs("Transformed outline");
|
|
}
|
|
// Don't include source (but do add it above to include importUris).
|
|
summary = serializeComponent(trimmedSummaryComponent,
|
|
includeSources: false, includeOffsets: includeOffsets);
|
|
options.ticker.logMs("Generated outline");
|
|
}
|
|
|
|
Component component;
|
|
if (buildComponent) {
|
|
component = await kernelTarget.buildComponent(verify: options.verify);
|
|
if (options.debugDump) {
|
|
printComponentText(component,
|
|
libraryFilter: kernelTarget.isSourceLibrary);
|
|
}
|
|
options.ticker.logMs("Generated component");
|
|
}
|
|
|
|
return new InternalCompilerResult(
|
|
summary: summary,
|
|
component: component,
|
|
sdkComponent: sdkSummary,
|
|
loadedComponents: loadedComponents,
|
|
classHierarchy:
|
|
includeHierarchyAndCoreTypes ? kernelTarget.loader.hierarchy : null,
|
|
coreTypes:
|
|
includeHierarchyAndCoreTypes ? kernelTarget.loader.coreTypes : null,
|
|
deps: new List<Uri>.from(CompilerContext.current.dependencies),
|
|
kernelTargetForTesting: retainDataForTesting ? kernelTarget : null);
|
|
}, () => sourceLoader?.currentUriForCrashReporting ?? options.inputs.first);
|
|
}
|
|
|
|
/// Result object of [generateKernel].
|
|
class InternalCompilerResult implements CompilerResult {
|
|
/// The generated summary bytes, if it was requested.
|
|
final List<int> summary;
|
|
|
|
/// The generated component, if it was requested.
|
|
final Component component;
|
|
|
|
final Component sdkComponent;
|
|
|
|
final List<Component> loadedComponents;
|
|
|
|
/// Dependencies traversed by the compiler. Used only for generating
|
|
/// dependency .GN files in the dart-sdk build system.
|
|
/// Note this might be removed when we switch to compute dependencies without
|
|
/// using the compiler itself.
|
|
final List<Uri> deps;
|
|
|
|
final ClassHierarchy classHierarchy;
|
|
|
|
final CoreTypes coreTypes;
|
|
|
|
/// The [KernelTarget] used to generated the component.
|
|
///
|
|
/// This is only provided for use in testing.
|
|
final KernelTarget kernelTargetForTesting;
|
|
|
|
InternalCompilerResult(
|
|
{this.summary,
|
|
this.component,
|
|
this.sdkComponent,
|
|
this.loadedComponents,
|
|
this.deps,
|
|
this.classHierarchy,
|
|
this.coreTypes,
|
|
this.kernelTargetForTesting});
|
|
}
|