blob: e8836ca3c625c8795ed7bde568cb2c4afac250b3 [file] [log] [blame]
// Copyright (c) 2016, 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:typed_data';
import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
import 'package:kernel/core_types.dart';
import 'package:kernel/reference_from_index.dart'
show IndexedContainer, IndexedClass;
import 'package:kernel/target/changed_structure_notifier.dart'
show ChangedStructureNotifier;
import 'package:kernel/target/targets.dart' show DiagnosticReporter, Target;
import 'package:kernel/type_algebra.dart' show Substitution;
import 'package:kernel/type_environment.dart' show TypeEnvironment;
import 'package:kernel/verifier.dart' show VerificationStage;
import 'package:package_config/package_config.dart' hide LanguageVersion;
import '../api_prototype/experimental_flags.dart'
show ExperimentalFlag, GlobalFeatures;
import '../api_prototype/file_system.dart' show FileSystem;
import '../base/compiler_context.dart' show CompilerContext;
import '../base/crash.dart' show withCrashReporting;
import '../base/loader.dart' show Loader;
import '../base/messages.dart'
show
FormattedMessage,
LocatedMessage,
Message,
messageConstConstructorLateFinalFieldCause,
messageConstConstructorLateFinalFieldError,
messageConstConstructorNonFinalField,
messageConstConstructorNonFinalFieldCause,
messageConstConstructorRedirectionToNonConst,
noLength,
templateFieldNonNullableNotInitializedByConstructorError,
templateFieldNonNullableWithoutInitializerError,
templateFinalFieldNotInitialized,
templateFinalFieldNotInitializedByConstructor,
templateMissingImplementationCause,
templateSuperclassHasNoDefaultConstructor;
import '../base/processed_options.dart' show ProcessedOptions;
import '../base/scope.dart' show AmbiguousBuilder;
import '../base/ticker.dart' show Ticker;
import '../base/uri_offset.dart';
import '../base/uri_translator.dart' show UriTranslator;
import '../builder/builder.dart';
import '../builder/declaration_builders.dart';
import '../builder/library_builder.dart';
import '../builder/member_builder.dart';
import '../builder/method_builder.dart';
import '../builder/named_type_builder.dart';
import '../builder/nullability_builder.dart';
import '../builder/property_builder.dart';
import '../builder/type_builder.dart';
import '../dill/dill_target.dart' show DillTarget;
import '../fragment/constructor/declaration.dart';
import '../source/class_declaration.dart';
import '../source/constructor_declaration.dart';
import '../source/name_scheme.dart';
import '../source/source_class_builder.dart' show SourceClassBuilder;
import '../source/source_constructor_builder.dart';
import '../source/source_extension_type_declaration_builder.dart';
import '../source/source_library_builder.dart' show SourceLibraryBuilder;
import '../source/source_loader.dart'
show CompilationPhaseForProblemReporting, SourceLoader;
import '../source/source_property_builder.dart';
import '../type_inference/type_schema.dart';
import 'benchmarker.dart' show BenchmarkPhases, Benchmarker;
import 'cfe_verifier.dart' show verifyComponent, verifyGetStaticType;
import 'constant_evaluator.dart' as constants
show
transformLibraries,
transformProcedure,
ConstantCoverage,
ConstantEvaluationData;
import 'constructor_tearoff_lowering.dart';
import 'dynamic_module_validator.dart' as dynamic_module_validator;
import 'kernel_constants.dart' show KernelConstantErrorReporter;
import 'kernel_helper.dart';
import 'utils.dart';
class KernelTarget {
final Ticker ticker;
/// The [FileSystem] which should be used to access files.
final FileSystem fileSystem;
/// Whether comments should be scanned and parsed.
final bool includeComments;
final DillTarget dillTarget;
late final SourceLoader loader;
Component? component;
// 'dynamic' is always nullable.
// TODO(johnniwinther): Why isn't this using a FixedTypeBuilder?
final NamedTypeBuilder dynamicType = new NamedTypeBuilderImpl(
const PredefinedTypeName("dynamic"), const NullabilityBuilder.inherent(),
instanceTypeParameterAccess: InstanceTypeParameterAccessState.Unexpected);
final NamedTypeBuilder intType = new NamedTypeBuilderImpl(
const PredefinedTypeName("int"), const NullabilityBuilder.omitted(),
instanceTypeParameterAccess: InstanceTypeParameterAccessState.Unexpected);
final NamedTypeBuilder stringType = new NamedTypeBuilderImpl(
const PredefinedTypeName("String"), const NullabilityBuilder.omitted(),
instanceTypeParameterAccess: InstanceTypeParameterAccessState.Unexpected);
final NamedTypeBuilder objectType = new NamedTypeBuilderImpl(
const PredefinedTypeName("Object"), const NullabilityBuilder.omitted(),
instanceTypeParameterAccess: InstanceTypeParameterAccessState.Unexpected);
// Null is always nullable.
// TODO(johnniwinther): This could (maybe) use a FixedTypeBuilder when we
// have NullType?
final NamedTypeBuilder nullType = new NamedTypeBuilderImpl(
const PredefinedTypeName("Null"), const NullabilityBuilder.inherent(),
instanceTypeParameterAccess: InstanceTypeParameterAccessState.Unexpected);
// TODO(johnniwinther): Why isn't this using a FixedTypeBuilder?
final NamedTypeBuilder bottomType = new NamedTypeBuilderImpl(
const PredefinedTypeName("Never"), const NullabilityBuilder.omitted(),
instanceTypeParameterAccess: InstanceTypeParameterAccessState.Unexpected);
final NamedTypeBuilder enumType = new NamedTypeBuilderImpl(
const PredefinedTypeName("Enum"), const NullabilityBuilder.omitted(),
instanceTypeParameterAccess: InstanceTypeParameterAccessState.Unexpected);
final NamedTypeBuilder underscoreEnumType = new NamedTypeBuilderImpl(
const PredefinedTypeName("_Enum"), const NullabilityBuilder.omitted(),
instanceTypeParameterAccess: InstanceTypeParameterAccessState.Unexpected);
bool get excludeSource => !context.options.embedSourceText;
Map<String, String>? get environmentDefines =>
context.options.environmentDefines;
bool get errorOnUnevaluatedConstant =>
context.options.errorOnUnevaluatedConstant;
final Map<Member, DelayedDefaultValueCloner> _delayedDefaultValueCloners = {};
final UriTranslator uriTranslator;
final Target backendTarget;
final CompilerContext context;
/// Shared with [CompilerContext].
Map<Uri, Source> get uriToSource => context.uriToSource;
MemberBuilder? _cachedDuplicatedFieldInitializerError;
MemberBuilder? _cachedNativeAnnotation;
final ProcessedOptions _options;
final Benchmarker? benchmarker;
KernelTarget(this.context, this.fileSystem, this.includeComments,
DillTarget dillTarget, this.uriTranslator)
: dillTarget = dillTarget,
backendTarget = dillTarget.backendTarget,
_options = context.options,
ticker = dillTarget.ticker,
benchmarker = dillTarget.benchmarker {
assert(_options.haveBeenValidated, "Options have not been validated");
loader = createLoader();
}
GlobalFeatures get globalFeatures => _options.globalFeatures;
bool isExperimentEnabledInLibraryByVersion(
ExperimentalFlag flag, Uri importUri, Version version) {
return _options.isExperimentEnabledInLibraryByVersion(
flag, importUri, version);
}
Uri? translateUri(Uri uri) => uriTranslator.translate(uri);
/// Returns a reference to the constructor used for creating a runtime error
/// when a final field is initialized twice. The constructor is expected to
/// accept a single argument which is the name of the field.
MemberBuilder getDuplicatedFieldInitializerError(Loader loader) {
return _cachedDuplicatedFieldInitializerError ??= loader.coreLibrary
.getConstructor("_DuplicatedFieldInitializerError",
bypassLibraryPrivacy: true);
}
/// Returns a reference to the constructor used for creating `native`
/// annotations. The constructor is expected to accept a single argument of
/// type String, which is the name of the native method.
MemberBuilder getNativeAnnotation(SourceLoader loader) {
if (_cachedNativeAnnotation != null) return _cachedNativeAnnotation!;
LibraryBuilder internal =
loader.lookupLoadedLibraryBuilder(Uri.parse("dart:_internal"))!;
return _cachedNativeAnnotation = internal.getConstructor("ExternalName");
}
void loadExtraRequiredLibraries(SourceLoader loader) {
for (String uri in backendTarget.extraRequiredLibraries) {
loader.read(Uri.parse(uri), 0,
accessor: loader.coreLibraryCompilationUnit);
}
if (context.compilingPlatform) {
// Coverage-ignore-block(suite): Not run.
for (String uri in backendTarget.extraRequiredLibrariesPlatform) {
loader.read(Uri.parse(uri), 0,
accessor: loader.coreLibraryCompilationUnit);
}
}
}
FormattedMessage createFormattedMessage(
Message message,
int charOffset,
int length,
Uri? fileUri,
List<LocatedMessage>? messageContext,
Severity severity,
{List<Uri>? involvedFiles}) {
ProcessedOptions processedOptions = context.options;
return processedOptions.format(
context,
fileUri != null
? message.withLocation(fileUri, charOffset, length)
:
// Coverage-ignore(suite): Not run.
message.withoutLocation(),
severity,
messageContext,
involvedFiles: involvedFiles);
}
String get currentSdkVersionString {
return context.options.currentSdkVersion;
}
Version get leastSupportedVersion => const Version(2, 12);
Version? _currentSdkVersion;
Version get currentSdkVersion {
if (_currentSdkVersion == null) {
_parseCurrentSdkVersion();
}
return _currentSdkVersion!;
}
void _parseCurrentSdkVersion() {
bool good = false;
List<String> dotSeparatedParts = currentSdkVersionString.split(".");
if (dotSeparatedParts.length >= 2) {
_currentSdkVersion = new Version(int.tryParse(dotSeparatedParts[0])!,
int.tryParse(dotSeparatedParts[1])!);
good = true;
}
if (!good) {
throw new StateError(
"Unparsable sdk version given: $currentSdkVersionString");
}
}
SourceLoader createLoader() =>
new SourceLoader(fileSystem, includeComments, this);
bool _hasAddedSources = false;
void addSourceInformation(
Uri importUri, Uri fileUri, List<int> lineStarts, Uint8List sourceCode) {
Source source = new Source(lineStarts, sourceCode, importUri, fileUri);
uriToSource[fileUri] = source;
if (_hasAddedSources) {
// Coverage-ignore-block(suite): Not run.
// The sources have already been added to the component in [link] so we
// have to add source directly here to create a consistent component.
component?.uriToSource[fileUri] = excludeSource
? new Source.emptySource(
source.lineStarts, source.importUri, source.fileUri)
: source;
}
}
// Coverage-ignore(suite): Not run.
void removeSourceInformation(Uri fileUri) {
uriToSource.remove(fileUri);
if (_hasAddedSources) {
// The sources have already been added to the component in [link] so we
// have to remove source directly here to create a consistent component.
component?.uriToSource.remove(fileUri);
}
}
/// Return list of same size as input with possibly translated uris.
List<Uri> setEntryPoints(List<Uri> entryPoints) {
List<Uri> result = <Uri>[];
for (Uri entryPoint in entryPoints) {
Uri translatedEntryPoint = getEntryPointUri(entryPoint);
result.add(translatedEntryPoint);
loader.readAsEntryPoint(translatedEntryPoint,
fileUri: translatedEntryPoint != entryPoint ? entryPoint : null);
}
return result;
}
/// Return list of same size as input with possibly translated uris.
Uri getEntryPointUri(Uri entryPoint) {
String scheme = entryPoint.scheme;
switch (scheme) {
case "package":
case "dart":
case "data":
break;
default:
// Attempt to reverse-lookup [entryPoint] in package config.
String asString = "$entryPoint";
Package? package = uriTranslator.packages.packageOf(entryPoint);
if (package != null) {
String packageName = package.name;
Uri packageUri = package.packageUriRoot;
if (packageUri.hasFragment == true) {
// Coverage-ignore-block(suite): Not run.
packageUri = packageUri.removeFragment();
}
String prefix = "${packageUri}";
if (asString.startsWith(prefix)) {
// Coverage-ignore-block(suite): Not run.
Uri reversed = Uri.parse(
"package:$packageName/${asString.substring(prefix.length)}");
if (entryPoint == uriTranslator.translate(reversed)) {
entryPoint = reversed;
break;
}
}
}
}
return entryPoint;
}
bool _hasComputedNeededPrecompilations = false;
// TODO(johnniwinther): Remove this.
Future<void> computeNeededPrecompilations() async {
assert(!_hasComputedNeededPrecompilations,
"Needed precompilations have already been computed.");
_hasComputedNeededPrecompilations = true;
if (loader.roots.isEmpty) return null;
return await withCrashReporting<void>(() async {
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_kernelBuildOutlines);
await loader.buildOutlines();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_resolveParts);
loader.resolveParts();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_buildNameSpaces);
loader.buildNameSpaces(loader.sourceLibraryBuilders);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_becomeCoreLibrary);
loader.coreLibrary.becomeCoreLibrary();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_buildScopes);
loader.buildScopes(loader.sourceLibraryBuilders);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.unknownComputeNeededPrecompilations);
}, () => loader.currentUriForCrashReporting);
}
// Coverage-ignore(suite): Not run.
/// Builds [libraryBuilders] to the state expected after
/// [SourceLoader.buildScopes].
void buildSyntheticLibrariesUntilBuildScopes(
Iterable<SourceLibraryBuilder> libraryBuilders) {
loader.buildNameSpaces(libraryBuilders);
loader.buildScopes(libraryBuilders);
}
// Coverage-ignore(suite): Not run.
/// Builds [libraryBuilders] to the state expected after default types have
/// been computed.
///
/// This assumes that [libraryBuilders] are in the state after
/// [SourceLoader.buildScopes].
void buildSyntheticLibrariesUntilComputeDefaultTypes(
Iterable<SourceLibraryBuilder> libraryBuilders) {
loader.computeLibraryScopes(libraryBuilders);
loader.resolveTypes(libraryBuilders);
loader.computeSupertypes(libraryBuilders);
loader.computeDefaultTypes(
libraryBuilders, dynamicType, nullType, bottomType, objectClassBuilder);
}
Future<BuildResult> buildOutlines({CanonicalName? nameRoot}) async {
if (loader.roots.isEmpty) {
// Coverage-ignore-block(suite): Not run.
return new BuildResult();
}
return await withCrashReporting<BuildResult>(() async {
if (!_hasComputedNeededPrecompilations) {
// Coverage-ignore-block(suite): Not run.
await computeNeededPrecompilations();
}
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_computeLibraryScopes);
loader.computeLibraryScopes(loader.loadedLibraryBuilders);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_setupTopAndBottomTypes);
setupTopAndBottomTypes();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_resolveTypes);
loader.resolveTypes(loader.sourceLibraryBuilders);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_computeSupertypes);
loader.computeSupertypes(loader.sourceLibraryBuilders);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_computeMacroApplications);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_computeVariances);
loader.computeVariances(loader.sourceLibraryBuilders);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_computeDefaultTypes);
loader.computeDefaultTypes(loader.sourceLibraryBuilders, dynamicType,
nullType, bottomType, objectClassBuilder);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_checkSemantics);
List<SourceClassBuilder>? sortedSourceClassBuilders;
List<SourceExtensionTypeDeclarationBuilder>?
sortedSourceExtensionTypeBuilders;
(sortedSourceClassBuilders, sortedSourceExtensionTypeBuilders) =
loader.checkClassCycles(objectClassBuilder);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_finishTypeParameters);
loader.finishTypeParameters(
loader.sourceLibraryBuilders, objectClassBuilder, dynamicType);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_createTypeInferenceEngine);
loader.createTypeInferenceEngine();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_buildComponent);
loader.buildOutlineNodes();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_installDefaultSupertypes);
installDefaultSupertypes();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_link);
component =
link(new List<Library>.of(loader.libraries), nameRoot: nameRoot);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_computeCoreTypes);
computeCoreTypes();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_buildClassHierarchy);
loader.buildClassHierarchy(sortedSourceClassBuilders,
sortedSourceExtensionTypeBuilders, objectClassBuilder);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_checkSupertypes);
loader.checkSupertypes(
sortedSourceClassBuilders,
sortedSourceExtensionTypeBuilders,
objectClass,
enumClass,
underscoreEnumClass);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_installSyntheticConstructors);
installSyntheticConstructors(sortedSourceClassBuilders);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_resolveConstructors);
loader.resolveConstructors(loader.sourceLibraryBuilders);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_buildClassHierarchyMembers);
loader.buildClassHierarchyMembers(
sortedSourceClassBuilders, sortedSourceExtensionTypeBuilders);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_computeHierarchy);
loader.computeHierarchy();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_installTypedefTearOffs);
List<DelayedDefaultValueCloner>?
typedefTearOffsDelayedDefaultValueCloners =
loader.installTypedefTearOffs();
typedefTearOffsDelayedDefaultValueCloners
?.forEach(registerDelayedDefaultValueCloner);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_computeFieldPromotability);
loader.computeFieldPromotability();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_prepareTopLevelInference);
loader.prepareTopLevelInference();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(
BenchmarkPhases.outline_performRedirectingFactoryInference);
// TODO(johnniwinther): Add an interface for registering delayed actions.
List<DelayedDefaultValueCloner> delayedDefaultValueCloners = [];
loader.inferRedirectingFactories(delayedDefaultValueCloners);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_computeMemberTypes);
loader.computeMemberTypes();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_performTopLevelInference);
loader.performTopLevelInference(sortedSourceClassBuilders);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_checkOverrides);
loader.checkOverrides(sortedSourceClassBuilders);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_checkAbstractMembers);
loader.checkAbstractMembers(sortedSourceClassBuilders);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_checkMixins);
loader.checkMixins(sortedSourceClassBuilders);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_buildOutlineExpressions);
loader.buildOutlineExpressions(
loader.hierarchy, delayedDefaultValueCloners);
delayedDefaultValueCloners.forEach(registerDelayedDefaultValueCloner);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_checkTypes);
loader.checkTypes();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_checkRedirectingFactories);
loader.checkRedirectingFactories(
sortedSourceClassBuilders, sortedSourceExtensionTypeBuilders);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_finishSynthesizedParameters);
finishSynthesizedParameters(forOutline: true);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_checkMainMethods);
loader.checkMainMethods();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_installAllComponentProblems);
loader.installAllProblemsIntoComponent(component!,
currentPhase: CompilationPhaseForProblemReporting.outline);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.unknownBuildOutlines);
// For whatever reason sourceClassBuilders is kept alive for some amount
// of time, meaning that all source library builders will be kept alive
// (for whatever amount of time) even though we convert them to dill
// library builders. To avoid it we null it out here.
sortedSourceClassBuilders = null;
return new BuildResult(component: component);
}, () => loader.currentUriForCrashReporting);
}
/// Build the kernel representation of the component loaded by this
/// target. The component will contain full bodies for the code loaded from
/// sources, and only references to the code loaded by the [DillTarget],
/// which may or may not include method bodies (depending on what was loaded
/// into that target, an outline or a full kernel component).
///
/// If [verify], run the default kernel verification on the resulting
/// component.
Future<BuildResult> buildComponent(
{bool verify = false,
bool allowVerificationErrorForTesting = false}) async {
if (loader.roots.isEmpty) {
// Coverage-ignore-block(suite): Not run.
return new BuildResult();
}
return await withCrashReporting<BuildResult>(() async {
ticker.logMs("Building component");
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.body_buildBodies);
await loader.buildBodies(loader.sourceLibraryBuilders);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.body_checkMixinSuperAccesses);
loader.checkMixinSuperAccesses();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.body_finishSynthesizedParameters);
finishSynthesizedParameters();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.body_finishDeferredLoadTearoffs);
loader.finishDeferredLoadTearoffs();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.body_finishNoSuchMethodForwarders);
loader.finishNoSuchMethodForwarders();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.body_collectSourceClasses);
List<SourceClassBuilder>? sourceClasses = [];
List<SourceExtensionTypeDeclarationBuilder>? extensionTypeDeclarations =
[];
loader.collectSourceClasses(sourceClasses, extensionTypeDeclarations);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.body_finishNativeMethods);
loader.finishNativeMethods();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.body_finishAugmentationMethods);
loader.buildBodyNodes();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.body_finishAllConstructors);
finishAllConstructors(sourceClasses, extensionTypeDeclarations);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.body_validateDynamicModule);
await validateDynamicModule();
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.body_runBuildTransformations);
runBuildTransformations();
if (verify) {
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.body_verify);
_verify(
allowVerificationErrorForTesting: allowVerificationErrorForTesting);
}
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.body_installAllComponentProblems);
loader.installAllProblemsIntoComponent(component!,
currentPhase: CompilationPhaseForProblemReporting.bodyBuilding);
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.unknownBuildComponent);
// For whatever reason sourceClasses is kept alive for some amount
// of time, meaning that all source library builders will be kept alive
// (for whatever amount of time) even though we convert them to dill
// library builders. To avoid it we null it out here.
sourceClasses = null;
extensionTypeDeclarations = null;
context.options.hooksForTesting
// Coverage-ignore(suite): Not run.
?.onBuildComponentComplete(component!);
return new BuildResult(component: component);
}, () => loader.currentUriForCrashReporting);
}
/// Creates a component by combining [libraries] with the libraries of
/// `dillTarget.loader.component`.
Component link(List<Library> libraries, {CanonicalName? nameRoot}) {
libraries.addAll(dillTarget.loader.libraries);
// Copy source data from the map in [CompilerContext] into a new map that is
// put on the component.
Map<Uri, Source> uriToSource = new Map<Uri, Source>();
void copySource(Uri uri, Source source) {
uriToSource[uri] = excludeSource
?
// Coverage-ignore(suite): Not run.
new Source.emptySource(
source.lineStarts, source.importUri, source.fileUri)
: source;
}
this.uriToSource.forEach(copySource);
_hasAddedSources = true;
Component component = backendTarget.configureComponent(new Component(
nameRoot: nameRoot, libraries: libraries, uriToSource: uriToSource));
Reference? mainReference;
LibraryBuilder? firstRoot = loader.rootLibrary;
if (firstRoot != null) {
// TODO(sigmund): do only for full program
Builder? declaration =
firstRoot.exportNameSpace.lookupLocalMember("main")?.getable;
if (declaration is AmbiguousBuilder) {
// Coverage-ignore-block(suite): Not run.
AmbiguousBuilder problem = declaration;
declaration = problem.getFirstDeclaration();
}
if (declaration is MethodBuilder) {
mainReference = declaration.invokeTargetReference;
}
}
component.setMainMethodAndMode(mainReference, true);
ticker.logMs("Linked component");
return component;
}
void installDefaultSupertypes() {
Class objectClass = this.objectClass;
for (SourceLibraryBuilder library in loader.sourceLibraryBuilders) {
library.installDefaultSupertypes(objectClassBuilder, objectClass);
}
ticker.logMs("Installed Object as implicit superclass");
}
void installSyntheticConstructors(List<SourceClassBuilder> builders) {
Class objectClass = this.objectClass;
for (SourceClassBuilder builder in builders) {
if (builder.cls != objectClass) {
if (builder.isMixinDeclaration) {
continue;
}
if (builder.isMixinApplication) {
installForwardingConstructors(builder);
} else {
installDefaultConstructor(builder);
}
}
}
ticker.logMs("Installed synthetic constructors");
}
ClassBuilder get objectClassBuilder => objectType.declaration as ClassBuilder;
Class get objectClass => objectClassBuilder.cls;
ClassBuilder get enumClassBuilder => enumType.declaration as ClassBuilder;
Class get enumClass => enumClassBuilder.cls;
ClassBuilder get underscoreEnumBuilder =>
underscoreEnumType.declaration as ClassBuilder;
Class get underscoreEnumClass => underscoreEnumBuilder.cls;
/// If [builder] doesn't have a constructors, install the defaults.
void installDefaultConstructor(SourceClassBuilder builder) {
assert(!builder.isMixinApplication);
// TODO(askesc): Make this check light-weight in the absence of
// augmentations.
if (builder.cls.constructors.isNotEmpty) return;
for (Procedure proc in builder.cls.procedures) {
if (proc.isFactory) return;
}
IndexedContainer? indexedClass = builder.indexedClass;
Reference? constructorReference;
Reference? tearOffReference;
if (indexedClass != null) {
constructorReference =
indexedClass.lookupConstructorReference(new Name(""));
tearOffReference = indexedClass.lookupGetterReference(
new Name(constructorTearOffName(""), indexedClass.library));
}
/// From [Dart Programming Language Specification, 4th Edition](
/// https://ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf):
/// >Iff no constructor is specified for a class C, it implicitly has a
/// >default constructor C() : super() {}, unless C is class Object.
// The superinitializer is installed below in [finishConstructors].
builder.addSyntheticConstructor(_makeDefaultConstructor(
builder, constructorReference, tearOffReference));
}
void installForwardingConstructors(SourceClassBuilder builder) {
assert(builder.isMixinApplication);
if (builder.libraryBuilder.loader != loader) return;
if (builder.cls.constructors.isNotEmpty) {
// These were installed by a subclass in the recursive call below.
return;
}
/// From [Dart Programming Language Specification, 4th Edition](
/// https://ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf):
/// >A mixin application of the form S with M; defines a class C with
/// >superclass S.
/// >...
/// >Let LM be the library in which M is declared. For each generative
/// >constructor named qi(Ti1 ai1, . . . , Tiki aiki), i in 1..n of S
/// >that is accessible to LM , C has an implicitly declared constructor
/// >named q'i = [C/S]qi of the form q'i(ai1,...,aiki) :
/// >super(ai1,...,aiki);.
TypeBuilder? type = builder.supertypeBuilder;
TypeDeclarationBuilder? supertype =
type?.computeUnaliasedDeclaration(isUsedAsClass: true);
if (supertype is SourceClassBuilder && supertype.isMixinApplication) {
installForwardingConstructors(supertype);
}
IndexedContainer? indexedClass = builder.indexedClass;
Reference? constructorReference;
Reference? tearOffReference;
if (indexedClass != null) {
constructorReference =
indexedClass.lookupConstructorReference(new Name(""));
tearOffReference = indexedClass.lookupGetterReference(
new Name(constructorTearOffName(""), indexedClass.library));
}
switch (supertype) {
case ClassBuilder():
ClassBuilder superclassBuilder = supertype;
bool isConstructorAdded = false;
Map<TypeParameter, DartType>? substitutionMap;
Iterator<MemberBuilder> iterator = superclassBuilder
.filteredConstructorsIterator(includeDuplicates: false);
while (iterator.moveNext()) {
MemberBuilder memberBuilder = iterator.current;
String name = memberBuilder.name;
if (memberBuilder.invokeTarget is Constructor) {
substitutionMap ??=
builder.getSubstitutionMap(superclassBuilder.cls);
Reference? constructorReference;
Reference? tearOffReference;
if (indexedClass != null) {
constructorReference = indexedClass
// We use the name of the member builder here since it refers
// to the library of the original declaration when private.
// For instance:
//
// // lib1:
// class Super { Super._() }
// class Subclass extends Class {
// Subclass() : super._();
// }
// // lib2:
// class Mixin {}
// class Class = Super with Mixin;
//
// Here `super._()` in `Subclass` targets the forwarding stub
// added to `Class` whose name is `_` private to `lib1`.
.lookupConstructorReference(memberBuilder.invokeTarget!.name);
tearOffReference = indexedClass.lookupGetterReference(
new Name(constructorTearOffName(name), indexedClass.library));
}
builder.addSyntheticConstructor(_makeMixinApplicationConstructor(
builder,
builder.cls.mixin,
memberBuilder as MemberBuilderImpl,
substitutionMap,
constructorReference,
tearOffReference));
isConstructorAdded = true;
}
}
if (!isConstructorAdded) {
// Coverage-ignore-block(suite): Not run.
builder.addSyntheticConstructor(_makeDefaultConstructor(
builder, constructorReference, tearOffReference));
}
case TypeAliasBuilder():
case NominalParameterBuilder():
case StructuralParameterBuilder():
case ExtensionBuilder():
case ExtensionTypeDeclarationBuilder():
case InvalidTypeDeclarationBuilder():
case BuiltinTypeDeclarationBuilder():
case null:
builder.addSyntheticConstructor(_makeDefaultConstructor(
builder, constructorReference, tearOffReference));
}
}
SourceConstructorBuilder _makeMixinApplicationConstructor(
SourceClassBuilder classBuilder,
Class mixin,
MemberBuilder superConstructorBuilder,
Map<TypeParameter, DartType> substitutionMap,
Reference? constructorReference,
Reference? tearOffReference) {
bool hasTypeDependency = false;
Substitution substitution = Substitution.fromMap(substitutionMap);
VariableDeclaration copyFormal(VariableDeclaration formal) {
VariableDeclaration copy = new VariableDeclaration(formal.name,
isFinal: formal.isFinal,
isConst: formal.isConst,
isRequired: formal.isRequired,
hasDeclaredInitializer: formal.hasDeclaredInitializer,
type: const UnknownType());
if (!hasTypeDependency && formal.type is! UnknownType) {
copy.type = substitution.substituteType(formal.type);
} else {
hasTypeDependency = true;
}
return copy;
}
SourceLibraryBuilder libraryBuilder = classBuilder.libraryBuilder;
Class cls = classBuilder.cls;
Constructor superConstructor =
superConstructorBuilder.invokeTarget as Constructor;
bool isConst = superConstructor.isConst;
if (isConst && mixin.fields.isNotEmpty) {
for (Field field in mixin.fields) {
if (!field.isStatic) {
isConst = false;
break;
}
}
}
List<VariableDeclaration> positionalParameters = <VariableDeclaration>[];
List<VariableDeclaration> namedParameters = <VariableDeclaration>[];
List<Expression> positional = <Expression>[];
List<NamedExpression> named = <NamedExpression>[];
for (VariableDeclaration formal
in superConstructor.function.positionalParameters) {
positionalParameters.add(copyFormal(formal));
positional.add(new VariableGet(positionalParameters.last));
}
for (VariableDeclaration formal
in superConstructor.function.namedParameters) {
VariableDeclaration clone = copyFormal(formal);
namedParameters.add(clone);
named.add(new NamedExpression(
formal.name!, new VariableGet(namedParameters.last)));
}
FunctionNode function = new FunctionNode(new EmptyStatement(),
positionalParameters: positionalParameters,
namedParameters: namedParameters,
requiredParameterCount:
superConstructor.function.requiredParameterCount,
returnType: makeConstructorReturnType(cls));
SuperInitializer initializer = new SuperInitializer(
superConstructor, new Arguments(positional, named: named));
Constructor constructor = new Constructor(function,
name: superConstructor.name,
initializers: <Initializer>[initializer],
isSynthetic: true,
isConst: isConst,
reference: constructorReference,
fileUri: cls.fileUri)
..fileOffset = cls.fileOffset
// TODO(johnniwinther): Should we add file end offset to synthesized
// constructors?
//..fileEndOffset = cls.fileOffset
;
DelayedDefaultValueCloner delayedDefaultValueCloner =
new DelayedDefaultValueCloner(superConstructor, constructor,
libraryBuilder: libraryBuilder);
TypeDependency? typeDependency;
if (hasTypeDependency) {
typeDependency = new TypeDependency(
constructor, superConstructor, substitution,
copyReturnType: false);
}
Procedure? constructorTearOff = createConstructorTearOffProcedure(
new MemberName(libraryBuilder.libraryName,
constructorTearOffName(superConstructor.name.text)),
libraryBuilder,
cls.fileUri,
cls.fileOffset,
tearOffReference,
forAbstractClassOrEnumOrMixin: classBuilder.isAbstract);
if (constructorTearOff != null) {
DelayedDefaultValueCloner delayedDefaultValueCloner =
buildConstructorTearOffProcedure(
tearOff: constructorTearOff,
declarationConstructor: constructor,
implementationConstructor: constructor,
enclosingDeclarationTypeParameters:
classBuilder.cls.typeParameters,
libraryBuilder: libraryBuilder);
registerDelayedDefaultValueCloner(delayedDefaultValueCloner);
}
ConstructorDeclaration declaration = new ForwardingConstructorDeclaration(
constructor: constructor,
constructorTearOff: constructorTearOff,
// We pass on the original constructor and the cloned function nodes
// to ensure that the default values are computed and cloned for the
// outline. It is needed to make the default values a part of the
// outline for const constructors, and additionally it is required
// for a potential subclass using super initializing parameters that
// will required the cloning of the default values.
definingConstructor: superConstructorBuilder,
delayedDefaultValueCloner: delayedDefaultValueCloner,
typeDependency: typeDependency);
IndexedClass? indexedClass = classBuilder.indexedClass;
LibraryName libraryName = indexedClass != null
? new LibraryName(indexedClass.library.reference)
: libraryBuilder.libraryName;
NameScheme nameScheme = new NameScheme(
isInstanceMember: false,
containerName: new ClassName(classBuilder.name),
containerType: ContainerType.Class,
libraryName: libraryName);
SourceConstructorBuilder constructorBuilder = new SourceConstructorBuilder(
name: superConstructorBuilder.name,
libraryBuilder: libraryBuilder,
declarationBuilder: classBuilder,
fileOffset: classBuilder.fileOffset,
fileUri: classBuilder.fileUri,
constructorReference: constructorReference,
tearOffReference: tearOffReference,
nameScheme: nameScheme,
introductory: declaration,
isConst: isConst,
isExternal: false);
loader.registerConstructorToBeInferred(
new InferableConstructor(constructor, constructorBuilder));
return constructorBuilder;
}
void registerDelayedDefaultValueCloner(DelayedDefaultValueCloner cloner) {
// TODO(cstefantsova): Investigate the reason for the assumption breakage
// and uncomment the following line.
// assert(!_delayedDefaultValueCloners.containsKey(cloner.synthesized));
_delayedDefaultValueCloners[cloner.synthesized] ??= cloner;
}
void finishSynthesizedParameters({bool forOutline = false}) {
void cloneDefaultValues(
DelayedDefaultValueCloner delayedDefaultValueCloner) {
DelayedDefaultValueCloner? originalCloner =
_delayedDefaultValueCloners[delayedDefaultValueCloner.original];
if (originalCloner != null) {
cloneDefaultValues(originalCloner);
}
delayedDefaultValueCloner.cloneDefaultValues(loader.typeEnvironment);
}
for (DelayedDefaultValueCloner delayedDefaultValueCloner
in _delayedDefaultValueCloners.values) {
if (!forOutline || delayedDefaultValueCloner.isOutlineNode) {
cloneDefaultValues(delayedDefaultValueCloner);
}
}
if (!forOutline) {
_delayedDefaultValueCloners.clear();
}
ticker.logMs("Cloned default values of formals");
}
SourceConstructorBuilder _makeDefaultConstructor(
SourceClassBuilder classBuilder,
Reference? constructorReference,
Reference? tearOffReference) {
SourceLibraryBuilder libraryBuilder = classBuilder.libraryBuilder;
Class enclosingClass = classBuilder.cls;
Constructor constructor = new Constructor(
new FunctionNode(new EmptyStatement(),
returnType: makeConstructorReturnType(enclosingClass)),
name: new Name(""),
isSynthetic: true,
reference: constructorReference,
fileUri: enclosingClass.fileUri)
..fileOffset = enclosingClass.fileOffset
// TODO(johnniwinther): Should we add file end offsets to synthesized
// constructors?
//..fileEndOffset = enclosingClass.fileOffset
;
Procedure? constructorTearOff = createConstructorTearOffProcedure(
new MemberName(libraryBuilder.libraryName, constructorTearOffName('')),
libraryBuilder,
enclosingClass.fileUri,
enclosingClass.fileOffset,
tearOffReference,
forAbstractClassOrEnumOrMixin:
enclosingClass.isAbstract || enclosingClass.isEnum);
if (constructorTearOff != null) {
DelayedDefaultValueCloner delayedDefaultValueCloner =
buildConstructorTearOffProcedure(
tearOff: constructorTearOff,
declarationConstructor: constructor,
implementationConstructor: constructor,
enclosingDeclarationTypeParameters:
classBuilder.cls.typeParameters,
libraryBuilder: libraryBuilder);
registerDelayedDefaultValueCloner(delayedDefaultValueCloner);
}
ConstructorDeclaration declaration = new DefaultConstructorDeclaration(
constructor: constructor, constructorTearOff: constructorTearOff);
IndexedClass? indexedClass = classBuilder.indexedClass;
LibraryName libraryName = indexedClass != null
? new LibraryName(indexedClass.library.reference)
: libraryBuilder.libraryName;
NameScheme nameScheme = new NameScheme(
isInstanceMember: false,
containerName: new ClassName(classBuilder.name),
containerType: ContainerType.Class,
libraryName: libraryName);
return new SourceConstructorBuilder(
name: '',
libraryBuilder: libraryBuilder,
declarationBuilder: classBuilder,
fileOffset: classBuilder.fileOffset,
fileUri: classBuilder.fileUri,
constructorReference: constructorReference,
tearOffReference: tearOffReference,
nameScheme: nameScheme,
introductory: declaration,
isExternal: false,
isConst: false);
}
DartType makeConstructorReturnType(Class enclosingClass) {
List<DartType> typeParameterTypes = <DartType>[];
for (int i = 0; i < enclosingClass.typeParameters.length; i++) {
TypeParameter typeParameter = enclosingClass.typeParameters[i];
typeParameterTypes
.add(new TypeParameterType.withDefaultNullability(typeParameter));
}
return new InterfaceType(enclosingClass,
enclosingClass.enclosingLibrary.nonNullable, typeParameterTypes);
}
void setupTopAndBottomTypes() {
LibraryBuilder coreLibrary = loader.coreLibrary;
bindCoreType(coreLibrary, objectType);
bindCoreType(coreLibrary, stringType);
bindCoreType(coreLibrary, intType);
bindCoreType(coreLibrary, dynamicType);
bindCoreType(coreLibrary, nullType, isNullClass: true);
bindCoreType(coreLibrary, bottomType);
bindCoreType(coreLibrary, enumType);
bindCoreType(coreLibrary, underscoreEnumType);
}
void computeCoreTypes() {
List<Library> libraries = <Library>[];
for (String platformLibrary in [
"dart:_internal",
"dart:async",
"dart:core",
"dart:mirrors",
...backendTarget.extraIndexedLibraries
]) {
Uri uri = Uri.parse(platformLibrary);
LibraryBuilder? libraryBuilder = loader.lookupLoadedLibraryBuilder(uri);
if (libraryBuilder == null) {
// TODO(ahe): This is working around a bug in kernel_driver_test or
// kernel_driver.
bool found = false;
for (Library target in dillTarget.loader.libraries) {
if (target.importUri == uri) {
libraries.add(target);
found = true;
break;
}
}
if (!found && uri.path != "mirrors") {
// Coverage-ignore-block(suite): Not run.
// dart:mirrors is optional.
throw "Can't find $uri";
}
} else {
libraries.add(libraryBuilder.library);
}
}
Component platformLibraries =
backendTarget.configureComponent(new Component());
// Add libraries directly to prevent that their parents are changed.
platformLibraries.libraries.addAll(libraries);
loader.computeCoreTypes(platformLibraries);
}
void finishAllConstructors(
List<SourceClassBuilder> sourceClassBuilders,
List<SourceExtensionTypeDeclarationBuilder>
sourceExtensionTypeDeclarationBuilders) {
Class objectClass = this.objectClass;
for (SourceClassBuilder builder in sourceClassBuilders) {
Class cls = builder.cls;
if (cls != objectClass) {
finishConstructors(builder);
}
}
for (SourceExtensionTypeDeclarationBuilder builder
in sourceExtensionTypeDeclarationBuilders) {
finishExtensionTypeConstructors(builder);
}
ticker.logMs("Finished constructors");
}
/// Ensure constructors of [classBuilder] have the correct initializers and
/// other requirements.
void finishConstructors(SourceClassBuilder classBuilder) {
Class cls = classBuilder.cls;
Constructor? superTarget;
for (Constructor constructor in cls.constructors) {
if (constructor.isExternal) {
continue;
}
bool isRedirecting = false;
for (Initializer initializer in constructor.initializers) {
if (initializer is RedirectingInitializer) {
if (constructor.isConst && !initializer.target.isConst) {
classBuilder.libraryBuilder.addProblem(
messageConstConstructorRedirectionToNonConst,
initializer.fileOffset,
initializer.target.name.text.length,
constructor.fileUri);
}
isRedirecting = true;
break;
}
}
if (!isRedirecting) {
/// >If no superinitializer is provided, an implicit superinitializer
/// >of the form super() is added at the end of k’s initializer list,
/// >unless the enclosing class is class Object.
if (constructor.initializers.isEmpty) {
superTarget ??= defaultSuperConstructor(cls);
Initializer initializer;
if (superTarget == null) {
int offset = constructor.fileOffset;
Uri fileUri = constructor.fileUri;
if (offset == -1 &&
// Coverage-ignore(suite): Not run.
constructor.isSynthetic) {
// Coverage-ignore-block(suite): Not run.
offset = cls.fileOffset;
fileUri = cls.fileUri;
}
classBuilder.libraryBuilder.addProblem(
templateSuperclassHasNoDefaultConstructor
.withArguments(cls.superclass!.name),
offset,
noLength,
fileUri);
initializer = new InvalidInitializer();
} else {
initializer =
new SuperInitializer(superTarget, new Arguments.empty())
..isSynthetic = true;
}
constructor.initializers.add(initializer);
initializer.parent = constructor;
}
if (constructor.function.body == null) {
// Coverage-ignore-block(suite): Not run.
/// >If a generative constructor c is not a redirecting constructor
/// >and no body is provided, then c implicitly has an empty body {}.
/// We use an empty statement instead.
constructor.function.body = new EmptyStatement()
..parent = constructor.function;
}
}
}
_finishConstructors(classBuilder);
}
void finishExtensionTypeConstructors(
SourceExtensionTypeDeclarationBuilder extensionTypeDeclaration) {
_finishConstructors(extensionTypeDeclaration);
}
void _finishConstructors(ClassDeclarationBuilder classDeclaration) {
SourceLibraryBuilder libraryBuilder = classDeclaration.libraryBuilder;
/// Quotes below are from [Dart Programming Language Specification, 4th
/// Edition](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf):
List<SourcePropertyBuilder> uninitializedFields = [];
List<SourcePropertyBuilder> nonFinalFields = [];
List<SourcePropertyBuilder> lateFinalFields = [];
Iterator<SourcePropertyBuilder> fieldIterator =
classDeclaration.filteredMembersIterator(includeDuplicates: false);
while (fieldIterator.moveNext()) {
SourcePropertyBuilder fieldBuilder = fieldIterator.current;
if (!fieldBuilder.hasConcreteField) {
// Skip abstract and external fields. These are abstract/external
// getters/setters and have no initialization.
continue;
}
if (fieldBuilder.isDeclarationInstanceMember && !fieldBuilder.isFinal) {
nonFinalFields.add(fieldBuilder);
}
if (fieldBuilder.isDeclarationInstanceMember &&
fieldBuilder.isLate &&
fieldBuilder.isFinal) {
lateFinalFields.add(fieldBuilder);
}
if (!fieldBuilder.hasInitializer) {
uninitializedFields.add(fieldBuilder);
}
}
Map<ConstructorDeclarationBuilder, Set<SourcePropertyBuilder>>
constructorInitializedFields = new Map.identity();
Set<SourcePropertyBuilder>? initializedFieldBuilders = null;
Set<SourcePropertyBuilder>? uninitializedInstanceFields;
Iterator<ConstructorDeclarationBuilder> constructorIterator =
classDeclaration.filteredConstructorsIterator(includeDuplicates: false);
while (constructorIterator.moveNext()) {
ConstructorDeclarationBuilder constructor = constructorIterator.current;
if (constructor.isEffectivelyRedirecting) continue;
if (constructor.isConst && nonFinalFields.isNotEmpty) {
classDeclaration.libraryBuilder.addProblem(
messageConstConstructorNonFinalField,
constructor.fileOffset,
noLength,
constructor.fileUri,
context: nonFinalFields
.map((field) => messageConstConstructorNonFinalFieldCause
.withLocation(field.fileUri, field.fileOffset, noLength))
.toList());
nonFinalFields.clear();
}
if (constructor.isConst && lateFinalFields.isNotEmpty) {
for (SourcePropertyBuilder field in lateFinalFields) {
classDeclaration.libraryBuilder.addProblem2(
messageConstConstructorLateFinalFieldError, field.fieldUriOffset!,
context: [
messageConstConstructorLateFinalFieldCause.withLocation(
constructor.fileUri, constructor.fileOffset, noLength)
]);
}
lateFinalFields.clear();
}
if (constructor.isEffectivelyExternal) {
// Assume that an external constructor initializes all uninitialized
// instance fields.
uninitializedInstanceFields ??= uninitializedFields
.where(
(SourcePropertyBuilder fieldBuilder) => !fieldBuilder.isStatic)
.toSet();
constructorInitializedFields[constructor] = uninitializedInstanceFields;
(initializedFieldBuilders ??= new Set<SourcePropertyBuilder>.identity())
.addAll(uninitializedInstanceFields);
} else {
Set<SourcePropertyBuilder> fields =
constructor.takeInitializedFields() ?? const {};
constructorInitializedFields[constructor] = fields;
(initializedFieldBuilders ??= new Set<SourcePropertyBuilder>.identity())
.addAll(fields);
}
}
// Run through all fields that aren't initialized by any constructor, and
// set their initializer to `null`.
for (SourcePropertyBuilder fieldBuilder in uninitializedFields) {
if (fieldBuilder.isExtensionTypeDeclaredInstanceField) continue;
if (initializedFieldBuilders == null ||
!initializedFieldBuilders.contains(fieldBuilder)) {
if (!fieldBuilder.isLate) {
if (fieldBuilder.isFinal) {
String uri = '${libraryBuilder.importUri}';
String file = fieldBuilder.fileUri.pathSegments.last;
if (uri == 'dart:html' ||
uri == 'dart:svg' ||
uri == 'dart:_native_typed_data' ||
uri == 'dart:_interceptors' &&
// Coverage-ignore(suite): Not run.
file == 'js_string.dart') {
// TODO(johnniwinther): Use external getters instead of final
// fields. See https://github.com/dart-lang/sdk/issues/33762
} else {
libraryBuilder.addProblem(
templateFinalFieldNotInitialized
.withArguments(fieldBuilder.name),
fieldBuilder.fileOffset,
fieldBuilder.name.length,
fieldBuilder.fileUri);
}
} else if (fieldBuilder.fieldType is! InvalidType &&
fieldBuilder.fieldType.isPotentiallyNonNullable) {
libraryBuilder.addProblem(
templateFieldNonNullableWithoutInitializerError.withArguments(
fieldBuilder.name, fieldBuilder.fieldType),
fieldBuilder.fileOffset,
fieldBuilder.name.length,
fieldBuilder.fileUri);
}
fieldBuilder.buildImplicitDefaultValue();
}
}
}
// Run through all fields that are initialized by some constructor, and
// make sure that all other constructors also initialize them.
for (MapEntry<ConstructorDeclarationBuilder,
Set<SourcePropertyBuilder>> entry
in constructorInitializedFields.entries) {
ConstructorDeclarationBuilder constructorBuilder = entry.key;
Set<SourcePropertyBuilder> fieldBuilders = entry.value;
bool hasReportedErrors = false;
for (SourcePropertyBuilder fieldBuilder
in initializedFieldBuilders!.difference(fieldBuilders)) {
if (fieldBuilder.isExtensionTypeDeclaredInstanceField) continue;
if (!fieldBuilder.hasInitializer && !fieldBuilder.isLate) {
Initializer initializer = fieldBuilder.buildImplicitInitializer();
constructorBuilder.prependInitializer(initializer);
if (fieldBuilder.isFinal) {
// Avoid cascading error if the constructor is known to be
// erroneous: such constructors don't initialize the final fields
// properly.
if (!constructorBuilder.invokeTarget.isErroneous) {
libraryBuilder.addProblem(
templateFinalFieldNotInitializedByConstructor
.withArguments(fieldBuilder.name),
constructorBuilder.fileOffset,
constructorBuilder.name.length,
constructorBuilder.fileUri,
context: [
templateMissingImplementationCause
.withArguments(fieldBuilder.name)
.withLocation(fieldBuilder.fileUri,
fieldBuilder.fileOffset, fieldBuilder.name.length)
]);
hasReportedErrors = true;
}
} else if (fieldBuilder.fieldType is! InvalidType &&
!fieldBuilder.isLate &&
fieldBuilder.fieldType.isPotentiallyNonNullable) {
libraryBuilder.addProblem(
templateFieldNonNullableNotInitializedByConstructorError
.withArguments(fieldBuilder.name, fieldBuilder.fieldType),
constructorBuilder.fileOffset,
noLength,
constructorBuilder.fileUri,
context: [
templateMissingImplementationCause
.withArguments(fieldBuilder.name)
.withLocation(fieldBuilder.fileUri,
fieldBuilder.fileOffset, fieldBuilder.name.length)
]);
hasReportedErrors = true;
}
}
}
if (hasReportedErrors) {
constructorBuilder.markAsErroneous();
}
}
}
Future<void> validateDynamicModule() async {
final Uri? dynamicInterfaceSpecificationUri =
_options.dynamicInterfaceSpecificationUri;
if (dynamicInterfaceSpecificationUri != null) {
final String? dynamicInterfaceSpecification =
await _options.loadDynamicInterfaceSpecification();
if (dynamicInterfaceSpecification != null) {
dynamic_module_validator.validateDynamicModule(
dynamicInterfaceSpecification,
dynamicInterfaceSpecificationUri,
component!,
loader.coreTypes,
loader.hierarchy,
loader.libraries,
loader);
}
}
}
/// Run all transformations that are needed when building a bundle of
/// libraries for the first time.
void runBuildTransformations() {
backendTarget.performPreConstantEvaluationTransformations(
component!,
loader.coreTypes,
loader.libraries,
new KernelDiagnosticReporter(loader),
logger:
// Coverage-ignore(suite): Not run.
(String msg) => ticker.logMs(msg),
changedStructureNotifier: changedStructureNotifier);
TypeEnvironment environment =
new TypeEnvironment(loader.coreTypes, loader.hierarchy);
constants.ConstantEvaluationData constantEvaluationData =
constants.transformLibraries(
component!,
loader.libraries,
backendTarget,
environmentDefines,
environment,
new KernelConstantErrorReporter(loader),
evaluateAnnotations: true,
enableTripleShift: globalFeatures.tripleShift.isEnabled,
enableConstFunctions: globalFeatures.constFunctions.isEnabled,
enableConstructorTearOff:
globalFeatures.constructorTearoffs.isEnabled,
errorOnUnevaluatedConstant: errorOnUnevaluatedConstant,
exhaustivenessDataForTesting: loader
.dataForTesting
// Coverage-ignore(suite): Not run.
?.exhaustivenessData);
ticker.logMs("Evaluated constants");
markLibrariesUsed(constantEvaluationData.visitedLibraries);
constants.ConstantCoverage coverage = constantEvaluationData.coverage;
coverage.constructorCoverage.forEach((Uri fileUri, Set<Reference> value) {
Source? source = uriToSource[fileUri];
if (source != null) {
source.constantCoverageConstructors ??= new Set<Reference>();
source.constantCoverageConstructors!.addAll(value);
}
});
ticker.logMs("Added constant coverage");
backendTarget.performModularTransformationsOnLibraries(
component!,
loader.coreTypes,
loader.hierarchy,
loader.libraries,
environmentDefines,
new KernelDiagnosticReporter(loader),
loader.referenceFromIndex,
logger: (String msg) => ticker.logMs(msg),
changedStructureNotifier: changedStructureNotifier);
}
ChangedStructureNotifier? get changedStructureNotifier => null;
// Coverage-ignore(suite): Not run.
void runProcedureTransformations(Procedure procedure) {
TypeEnvironment environment =
new TypeEnvironment(loader.coreTypes, loader.hierarchy);
constants.transformProcedure(
procedure,
backendTarget,
component!,
environmentDefines,
environment,
new KernelConstantErrorReporter(loader),
evaluateAnnotations: true,
enableTripleShift: globalFeatures.tripleShift.isEnabled,
enableConstFunctions: globalFeatures.constFunctions.isEnabled,
enableConstructorTearOff: globalFeatures.constructorTearoffs.isEnabled,
errorOnUnevaluatedConstant: errorOnUnevaluatedConstant,
);
ticker.logMs("Evaluated constants");
backendTarget.performTransformationsOnProcedure(
loader.coreTypes, loader.hierarchy, procedure, environmentDefines,
logger: (String msg) => ticker.logMs(msg));
}
void _verify({required bool allowVerificationErrorForTesting}) {
// TODO(ahe): How to handle errors.
List<LocatedMessage> errors = verifyComponent(
context, VerificationStage.afterModularTransformations, component!,
skipPlatform: context.options.skipPlatformVerification);
assert(
allowVerificationErrorForTesting ||
// Coverage-ignore(suite): Not run.
errors.isEmpty,
"Verification errors found: $errors");
ClassHierarchy hierarchy =
new ClassHierarchy(component!, new CoreTypes(component!),
onAmbiguousSupertypes: (Class cls, Supertype a, Supertype b) {
// An error has already been reported.
});
verifyGetStaticType(
new TypeEnvironment(loader.coreTypes, hierarchy), component!,
skipPlatform: context.options.skipPlatformVerification);
ticker.logMs("Verified component");
}
// Coverage-ignore(suite): Not run.
/// Return `true` if the given [library] was built by this [KernelTarget]
/// from sources, and not loaded from a [DillTarget].
/// Note that this is meant for debugging etc and that it is slow, each
/// call takes O(# libraries).
bool isSourceLibraryForDebugging(Library library) {
return loader.libraries.contains(library);
}
void readPatchFiles(
SourceCompilationUnit compilationUnit, Uri originImportUri) {
assert(originImportUri.isScheme("dart"),
"Unexpected origin import uri: $originImportUri");
List<Uri>? patches = uriTranslator.getDartPatches(originImportUri.path);
if (patches != null) {
for (Uri patch in patches) {
compilationUnit.registerAugmentation(loader.read(patch, -1,
fileUri: patch,
originImportUri: originImportUri,
origin: compilationUnit,
accessor: compilationUnit,
isPatch: true));
}
}
}
void releaseAncillaryResources() {
component = null;
}
void markLibrariesUsed(Set<Library> visitedLibraries) {
// Default implementation does nothing.
}
}
/// Looks for a constructor call that matches `super()` from a constructor in
/// [cls]. Such a constructor may have optional arguments, but no required
/// arguments.
Constructor? defaultSuperConstructor(Class cls) {
Class? superclass = cls.superclass;
if (superclass != null) {
for (Constructor constructor in superclass.constructors) {
if (constructor.name.text.isEmpty) {
return constructor.function.requiredParameterCount == 0
? constructor
: null;
}
}
}
return null;
}
class KernelDiagnosticReporter
extends DiagnosticReporter<Message, LocatedMessage> {
final SourceLoader loader;
KernelDiagnosticReporter(this.loader);
@override
void report(Message message, int charOffset, int length, Uri? fileUri,
{List<LocatedMessage>? context}) {
loader.addProblem(message, charOffset, noLength, fileUri, context: context);
}
}
class BuildResult {
final Component? component;
BuildResult({this.component});
}