blob: 4d9a9f97af1d739e3a6c950242a75e63f93dc611 [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.
library fasta.source_loader;
import 'dart:collection' show Queue;
import 'dart:convert' show utf8;
import 'dart:typed_data' show Uint8List;
import 'package:_fe_analyzer_shared/src/parser/class_member_parser.dart'
show ClassMemberParser;
import 'package:_fe_analyzer_shared/src/parser/parser.dart'
show Parser, lengthForToken;
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart'
show
ErrorToken,
LanguageVersionToken,
Scanner,
ScannerConfiguration,
ScannerResult,
Token,
scan;
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart'
show ClassHierarchy, HandleAmbiguousSupertypes;
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:kernel/reference_from_index.dart' show ReferenceFromIndex;
import 'package:kernel/type_environment.dart';
import 'package:kernel/util/graph.dart';
import 'package:package_config/package_config.dart' as package_config;
import '../../api_prototype/experimental_flags.dart';
import '../../api_prototype/file_system.dart';
import '../../base/common.dart';
import '../../base/instrumentation.dart' show Instrumentation;
import '../../base/nnbd_mode.dart';
import '../builder/builder.dart';
import '../builder/class_builder.dart';
import '../builder/declaration_builder.dart';
import '../builder/extension_builder.dart';
import '../builder/field_builder.dart';
import '../builder/invalid_type_declaration_builder.dart';
import '../builder/library_builder.dart';
import '../builder/member_builder.dart';
import '../builder/metadata_builder.dart';
import '../builder/modifier_builder.dart';
import '../builder/named_type_builder.dart';
import '../builder/procedure_builder.dart';
import '../builder/type_alias_builder.dart';
import '../builder/type_builder.dart';
import '../builder/type_declaration_builder.dart';
import '../builder_graph.dart';
import '../crash.dart' show firstSourceUri;
import '../denylisted_classes.dart'
show denylistedCoreClasses, denylistedTypedDataClasses;
import '../dill/dill_library_builder.dart';
import '../export.dart' show Export;
import '../fasta_codes.dart';
import '../kernel/body_builder.dart' show BodyBuilder;
import '../kernel/hierarchy/class_member.dart';
import '../kernel/hierarchy/delayed.dart';
import '../kernel/hierarchy/hierarchy_builder.dart';
import '../kernel/hierarchy/members_builder.dart';
import '../kernel/kernel_helper.dart'
show SynthesizedFunctionNode, TypeDependency;
import '../kernel/kernel_target.dart' show KernelTarget;
import '../kernel/macro.dart';
import '../kernel/macro_annotation_parser.dart';
import '../kernel/transform_collections.dart' show CollectionTransformer;
import '../kernel/transform_set_literals.dart' show SetLiteralTransformer;
import '../kernel/type_builder_computer.dart' show TypeBuilderComputer;
import '../loader.dart' show Loader, untranslatableUriScheme;
import '../problems.dart' show internalProblem;
import '../scope.dart';
import '../ticker.dart' show Ticker;
import '../type_inference/type_inference_engine.dart';
import '../type_inference/type_inferrer.dart';
import '../util/helpers.dart';
import 'diet_listener.dart' show DietListener;
import 'diet_parser.dart' show DietParser, useImplicitCreationExpressionInCfe;
import 'name_scheme.dart';
import 'outline_builder.dart' show OutlineBuilder;
import 'source_class_builder.dart' show SourceClassBuilder;
import 'source_constructor_builder.dart';
import 'source_enum_builder.dart';
import 'source_field_builder.dart';
import 'source_library_builder.dart'
show
ImplicitLanguageVersion,
InvalidLanguageVersion,
LanguageVersion,
SourceLibraryBuilder;
import 'source_procedure_builder.dart';
import 'stack_listener_impl.dart' show offsetForToken;
class SourceLoader extends Loader {
/// The [FileSystem] which should be used to access files.
final FileSystem fileSystem;
/// Whether comments should be scanned and parsed.
final bool includeComments;
final Map<Uri, List<int>> sourceBytes = <Uri, List<int>>{};
ClassHierarchyBuilder? _hierarchyBuilder;
ClassMembersBuilder? _membersBuilder;
ReferenceFromIndex? referenceFromIndex;
/// Used when building directly to kernel.
ClassHierarchy? _hierarchy;
CoreTypes? _coreTypes;
TypeEnvironment? _typeEnvironment;
/// For builders created with a reference, this maps from that reference to
/// that builder. This is used for looking up source builders when finalizing
/// exports in dill builders.
Map<Reference, Builder> buildersCreatedWithReferences = {};
/// Used when checking whether a return type of an async function is valid.
///
/// The said return type is valid if it's a subtype of [futureOfBottom].
DartType? _futureOfBottom;
DartType get futureOfBottom => _futureOfBottom!;
/// Used when checking whether a return type of a sync* function is valid.
///
/// The said return type is valid if it's a subtype of [iterableOfBottom].
DartType? _iterableOfBottom;
DartType get iterableOfBottom => _iterableOfBottom!;
/// Used when checking whether a return type of an async* function is valid.
///
/// The said return type is valid if it's a subtype of [streamOfBottom].
DartType? _streamOfBottom;
DartType get streamOfBottom => _streamOfBottom!;
TypeInferenceEngineImpl? _typeInferenceEngine;
Instrumentation? instrumentation;
CollectionTransformer? collectionTransformer;
SetLiteralTransformer? setLiteralTransformer;
final SourceLoaderDataForTesting? dataForTesting;
final Map<Uri, LibraryBuilder> _builders = <Uri, LibraryBuilder>{};
List<SourceLibraryBuilder>? _sourceLibraryBuilders;
final Queue<LibraryBuilder> _unparsedLibraries = new Queue<LibraryBuilder>();
final List<Library> libraries = <Library>[];
@override
final KernelTarget target;
/// List of all handled compile-time errors seen so far by libraries loaded
/// by this loader.
///
/// A handled error is an error that has been added to the generated AST
/// already, for example, as a throw expression.
final List<LocatedMessage> handledErrors = <LocatedMessage>[];
/// List of all unhandled compile-time errors seen so far by libraries loaded
/// by this loader.
///
/// An unhandled error is an error that hasn't been handled, see
/// [handledErrors].
final List<LocatedMessage> unhandledErrors = <LocatedMessage>[];
/// List of all problems seen so far by libraries loaded by this loader that
/// does not belong directly to a library.
final List<FormattedMessage> allComponentProblems = <FormattedMessage>[];
/// The text of the messages that have been reported.
///
/// This is used filter messages so that we don't report the same error twice.
final Set<String> seenMessages = new Set<String>();
/// Set to `true` if one of the reported errors had severity `Severity.error`.
///
/// This is used for [hasSeenError].
bool _hasSeenError = false;
/// Clears the [seenMessages] and [hasSeenError] state.
void resetSeenMessages() {
seenMessages.clear();
_hasSeenError = false;
}
/// Returns `true` if a compile time error has been reported.
bool get hasSeenError => _hasSeenError;
LibraryBuilder? _coreLibrary;
LibraryBuilder? typedDataLibrary;
/// The first library that we've been asked to compile. When compiling a
/// program (aka script), this is the library that should have a main method.
Uri? _firstUri;
LibraryBuilder? get first => _builders[_firstUri];
Uri? get firstUri => _firstUri;
void set firstUri(Uri? value) {
_firstUri = value;
}
int byteCount = 0;
Uri? currentUriForCrashReporting;
ClassBuilder? _macroClassBuilder;
SourceLoader(this.fileSystem, this.includeComments, this.target)
: dataForTesting =
retainDataForTesting ? new SourceLoaderDataForTesting() : null;
bool containsLibraryBuilder(Uri importUri) =>
_builders.containsKey(importUri);
@override
LibraryBuilder? lookupLibraryBuilder(Uri importUri) => _builders[importUri];
/// The [LibraryBuilder]s for libraries built from source or loaded from dill.
///
/// Before [resolveParts] have been called, this includes parts and patches.
Iterable<LibraryBuilder> get libraryBuilders => _builders.values;
/// The [SourceLibraryBuilder]s for the libraries built from source by this
/// source loader.
///
/// This is available after [resolveParts] have been called and doesn't
/// include parts or patches. Orphaned parts _are_ included.
List<SourceLibraryBuilder> get sourceLibraryBuilders {
assert(
_sourceLibraryBuilders != null,
"Source library builder hasn't been computed yet. "
"The source libraries are in SourceLoader.resolveParts.");
return _sourceLibraryBuilders!;
}
Iterable<Uri> get libraryImportUris => _builders.keys;
void registerLibraryBuilder(LibraryBuilder libraryBuilder) {
Uri uri = libraryBuilder.importUri;
if (uri.scheme == "dart" && uri.path == "core") {
_coreLibrary = libraryBuilder;
}
_builders[uri] = libraryBuilder;
}
LibraryBuilder? deregisterLibraryBuilder(Uri importUri) {
return _builders.remove(importUri);
}
void clearLibraryBuilders() {
_builders.clear();
}
@override
LibraryBuilder get coreLibrary => _coreLibrary!;
Ticker get ticker => target.ticker;
/// Creates a [SourceLibraryBuilder] corresponding to [importUri], if one
/// doesn't exist already.
///
/// [fileUri] must not be null and is a URI that can be passed to FileSystem
/// to locate the corresponding file.
///
/// [origin] is non-null if the created library is a patch to [origin].
///
/// [packageUri] is the base uri for the package which the library belongs to.
/// For instance 'package:foo'.
///
/// This is used to associate libraries in for instance the 'bin' and 'test'
/// folders of a package source with the package uri of the 'lib' folder.
///
/// If the [packageUri] is `null` the package association of this library is
/// based on its [importUri].
///
/// For libraries with a 'package:' [importUri], the package path must match
/// the path in the [importUri]. For libraries with a 'dart:' [importUri] the
/// [packageUri] must be `null`.
///
/// [packageLanguageVersion] is the language version defined by the package
/// which the library belongs to, or the current sdk version if the library
/// doesn't belong to a package.
SourceLibraryBuilder createLibraryBuilder(
{required Uri importUri,
required Uri fileUri,
Uri? packageUri,
required LanguageVersion packageLanguageVersion,
SourceLibraryBuilder? origin,
Library? referencesFrom,
bool? referenceIsPartOwner}) {
return new SourceLibraryBuilder(
importUri: importUri,
fileUri: fileUri,
packageUri: packageUri,
packageLanguageVersion: packageLanguageVersion,
loader: this,
origin: origin,
referencesFrom: referencesFrom,
referenceIsPartOwner: referenceIsPartOwner);
}
SourceLibraryBuilder _createSourceLibraryBuilder(
Uri uri,
Uri? fileUri,
SourceLibraryBuilder? origin,
Library? referencesFrom,
bool? referenceIsPartOwner) {
if (fileUri != null &&
(fileUri.scheme == "dart" ||
fileUri.scheme == "package" ||
fileUri.scheme == "dart-ext")) {
fileUri = null;
}
package_config.Package? packageForLanguageVersion;
if (fileUri == null) {
switch (uri.scheme) {
case "package":
case "dart":
fileUri = target.translateUri(uri) ??
new Uri(
scheme: untranslatableUriScheme,
path: Uri.encodeComponent("$uri"));
if (uri.scheme == "package") {
packageForLanguageVersion = target.uriTranslator.getPackage(uri);
} else {
packageForLanguageVersion =
target.uriTranslator.packages.packageOf(fileUri);
}
break;
default:
fileUri = uri;
packageForLanguageVersion =
target.uriTranslator.packages.packageOf(fileUri);
break;
}
} else {
packageForLanguageVersion =
target.uriTranslator.packages.packageOf(fileUri);
}
LanguageVersion? packageLanguageVersion;
Uri? packageUri;
Message? packageLanguageVersionProblem;
if (packageForLanguageVersion != null) {
Uri importUri = origin?.importUri ?? uri;
if (importUri.scheme != 'dart' &&
importUri.scheme != 'package' &&
// ignore: unnecessary_null_comparison
packageForLanguageVersion.name != null) {
packageUri =
new Uri(scheme: 'package', path: packageForLanguageVersion.name);
}
if (packageForLanguageVersion.languageVersion != null) {
if (packageForLanguageVersion.languageVersion
is package_config.InvalidLanguageVersion) {
packageLanguageVersionProblem =
messageLanguageVersionInvalidInDotPackages;
packageLanguageVersion = new InvalidLanguageVersion(
fileUri, 0, noLength, target.currentSdkVersion, false);
} else {
Version version = new Version(
packageForLanguageVersion.languageVersion!.major,
packageForLanguageVersion.languageVersion!.minor);
if (version > target.currentSdkVersion) {
packageLanguageVersionProblem =
templateLanguageVersionTooHigh.withArguments(
target.currentSdkVersion.major,
target.currentSdkVersion.minor);
packageLanguageVersion = new InvalidLanguageVersion(
fileUri, 0, noLength, target.currentSdkVersion, false);
} else {
packageLanguageVersion = new ImplicitLanguageVersion(version);
}
}
}
}
packageLanguageVersion ??=
new ImplicitLanguageVersion(target.currentSdkVersion);
SourceLibraryBuilder libraryBuilder = createLibraryBuilder(
importUri: uri,
fileUri: fileUri,
packageUri: packageUri,
packageLanguageVersion: packageLanguageVersion,
origin: origin,
referencesFrom: referencesFrom,
referenceIsPartOwner: referenceIsPartOwner);
if (packageLanguageVersionProblem != null) {
libraryBuilder.addPostponedProblem(
packageLanguageVersionProblem, 0, noLength, libraryBuilder.fileUri);
}
// Add any additional logic after this block. Setting the
// firstSourceUri and first library should be done as early as
// possible.
firstSourceUri ??= uri;
firstUri ??= libraryBuilder.importUri;
_checkForDartCore(uri, libraryBuilder);
Uri libraryUri = origin?.importUri ?? uri;
if (target.backendTarget.mayDefineRestrictedType(libraryUri)) {
libraryBuilder.mayImplementRestrictedTypes = true;
}
if (uri.scheme == "dart") {
target.readPatchFiles(libraryBuilder);
}
_unparsedLibraries.addLast(libraryBuilder);
return libraryBuilder;
}
DillLibraryBuilder? _lookupDillLibraryBuilder(Uri uri) {
DillLibraryBuilder? libraryBuilder =
target.dillTarget.loader.lookupLibraryBuilder(uri);
if (libraryBuilder != null) {
_checkDillLibraryBuilderNnbdMode(libraryBuilder);
_checkForDartCore(uri, libraryBuilder);
}
return libraryBuilder;
}
void _checkDillLibraryBuilderNnbdMode(DillLibraryBuilder libraryBuilder) {
if (!libraryBuilder.isNonNullableByDefault &&
(nnbdMode == NnbdMode.Strong || nnbdMode == NnbdMode.Agnostic)) {
registerStrongOptOutLibrary(libraryBuilder);
} else {
NonNullableByDefaultCompiledMode libraryMode =
libraryBuilder.library.nonNullableByDefaultCompiledMode;
if (libraryMode == NonNullableByDefaultCompiledMode.Invalid) {
registerNnbdMismatchLibrary(
libraryBuilder, messageInvalidNnbdDillLibrary);
} else {
switch (nnbdMode) {
case NnbdMode.Weak:
if (libraryMode != NonNullableByDefaultCompiledMode.Agnostic &&
libraryMode != NonNullableByDefaultCompiledMode.Weak) {
registerNnbdMismatchLibrary(
libraryBuilder, messageWeakWithStrongDillLibrary);
}
break;
case NnbdMode.Strong:
if (libraryMode != NonNullableByDefaultCompiledMode.Agnostic &&
libraryMode != NonNullableByDefaultCompiledMode.Strong) {
registerNnbdMismatchLibrary(
libraryBuilder, messageStrongWithWeakDillLibrary);
}
break;
case NnbdMode.Agnostic:
if (libraryMode != NonNullableByDefaultCompiledMode.Agnostic) {
if (libraryMode == NonNullableByDefaultCompiledMode.Strong) {
registerNnbdMismatchLibrary(
libraryBuilder, messageAgnosticWithStrongDillLibrary);
} else {
registerNnbdMismatchLibrary(
libraryBuilder, messageAgnosticWithWeakDillLibrary);
}
}
break;
}
}
}
}
void _checkForDartCore(Uri uri, LibraryBuilder libraryBuilder) {
if (uri.scheme == "dart") {
if (uri.path == "core") {
_coreLibrary = libraryBuilder;
} else if (uri.path == "typed_data") {
typedDataLibrary = libraryBuilder;
}
}
// TODO(johnniwinther): If we save the created library in [_builders]
// here, i.e. before calling `target.loadExtraRequiredLibraries` below,
// the order of the libraries change, making `dart:core` come before the
// required arguments. Currently [DillLoader.appendLibrary] one works
// when this is not the case.
if (_coreLibrary == libraryBuilder) {
target.loadExtraRequiredLibraries(this);
}
}
/// Look up a library builder by the [uri], or if such doesn't exist, create
/// one. The canonical URI of the library is [uri], and its actual location is
/// [fileUri].
///
/// Canonical URIs have schemes like "dart", or "package", and the actual
/// location is often a file URI.
///
/// The [accessor] is the library that's trying to import, export, or include
/// as part [uri], and [charOffset] is the location of the corresponding
/// directive. If [accessor] isn't allowed to access [uri], it's a
/// compile-time error.
LibraryBuilder read(Uri uri, int charOffset,
{Uri? fileUri,
required LibraryBuilder accessor,
LibraryBuilder? origin,
Library? referencesFrom,
bool? referenceIsPartOwner}) {
LibraryBuilder libraryBuilder = _read(uri,
fileUri: fileUri,
origin: origin,
referencesFrom: referencesFrom,
referenceIsPartOwner: referenceIsPartOwner);
libraryBuilder.recordAccess(charOffset, noLength, accessor.fileUri);
if (!_hasLibraryAccess(imported: uri, importer: accessor.importUri) &&
!accessor.isPatch) {
accessor.addProblem(messagePlatformPrivateLibraryAccess, charOffset,
noLength, accessor.fileUri);
}
return libraryBuilder;
}
/// Reads the library [uri] as an entry point. This is used for reading the
/// entry point library of a script or the explicitly mention libraries of
/// a modular or incremental compilation.
///
/// This differs from [read] in that there is no accessor library, meaning
/// that access to platform private libraries cannot be granted.
LibraryBuilder readAsEntryPoint(Uri uri,
{Uri? fileUri, Library? referencesFrom}) {
LibraryBuilder libraryBuilder =
_read(uri, fileUri: fileUri, referencesFrom: referencesFrom);
// TODO(johnniwinther): Avoid using the first library, if present, as the
// accessor of [libraryBuilder]. Currently the incremental compiler doesn't
// handle errors reported without an accessor, since the messages are not
// associated with a library. This currently has the side effect that
// the first library is the accessor of itself.
LibraryBuilder? firstLibrary = first;
if (firstLibrary != null) {
libraryBuilder.recordAccess(-1, noLength, firstLibrary.fileUri);
}
if (!_hasLibraryAccess(imported: uri, importer: firstLibrary?.importUri)) {
if (firstLibrary != null) {
firstLibrary.addProblem(
messagePlatformPrivateLibraryAccess, -1, noLength, firstUri);
} else {
addProblem(messagePlatformPrivateLibraryAccess, -1, noLength, null);
}
}
return libraryBuilder;
}
bool _hasLibraryAccess({required Uri imported, required Uri? importer}) {
if (imported.scheme == "dart" && imported.path.startsWith("_")) {
if (importer == null) {
return false;
} else {
return target.backendTarget
.allowPlatformPrivateLibraryAccess(importer, imported);
}
}
return true;
}
LibraryBuilder _read(Uri uri,
{Uri? fileUri,
LibraryBuilder? origin,
Library? referencesFrom,
bool? referenceIsPartOwner}) {
LibraryBuilder? libraryBuilder = _builders[uri];
if (libraryBuilder == null) {
if (target.dillTarget.isLoaded) {
libraryBuilder = _lookupDillLibraryBuilder(uri);
}
if (libraryBuilder == null) {
libraryBuilder = _createSourceLibraryBuilder(
uri,
fileUri,
origin as SourceLibraryBuilder?,
referencesFrom,
referenceIsPartOwner);
}
_builders[uri] = libraryBuilder;
}
return libraryBuilder;
}
void _ensureCoreLibrary() {
if (_coreLibrary == null) {
readAsEntryPoint(Uri.parse("dart:core"));
// TODO(askesc): When all backends support set literals, we no longer
// need to index dart:collection, as it is only needed for desugaring of
// const sets. We can remove it from this list at that time.
readAsEntryPoint(Uri.parse("dart:collection"));
assert(_coreLibrary != null);
}
}
Future<Null> buildBodies() async {
assert(_coreLibrary != null);
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
currentUriForCrashReporting = library.importUri;
await buildBody(library);
}
currentUriForCrashReporting = null;
logSummary(templateSourceBodySummary);
}
void logSummary(Template<SummaryTemplate> template) {
ticker.log((Duration elapsed, Duration sinceStart) {
int libraryCount = 0;
for (LibraryBuilder library in libraryBuilders) {
if (library.loader == this) {
libraryCount++;
if (library is SourceLibraryBuilder) {
libraryCount += library.patchLibraries?.length ?? 0;
}
}
}
double ms = elapsed.inMicroseconds / Duration.microsecondsPerMillisecond;
Message message = template.withArguments(
libraryCount, byteCount, ms, byteCount / ms, ms / libraryCount);
print("$sinceStart: ${message.problemMessage}");
});
}
/// Register [message] as a problem with a severity determined by the
/// intrinsic severity of the message.
@override
FormattedMessage? addProblem(
Message message, int charOffset, int length, Uri? fileUri,
{bool wasHandled: false,
List<LocatedMessage>? context,
Severity? severity,
bool problemOnLibrary: false,
List<Uri>? involvedFiles}) {
return addMessage(message, charOffset, length, fileUri, severity,
wasHandled: wasHandled,
context: context,
problemOnLibrary: problemOnLibrary,
involvedFiles: involvedFiles);
}
/// All messages reported by the compiler (errors, warnings, etc.) are routed
/// through this method.
///
/// Returns a FormattedMessage if the message is new, that is, not previously
/// reported. This is important as some parser errors may be reported up to
/// three times by `OutlineBuilder`, `DietListener`, and `BodyBuilder`.
/// If the message is not new, [null] is reported.
///
/// If [severity] is `Severity.error`, the message is added to
/// [handledErrors] if [wasHandled] is true or to [unhandledErrors] if
/// [wasHandled] is false.
FormattedMessage? addMessage(Message message, int charOffset, int length,
Uri? fileUri, Severity? severity,
{bool wasHandled: false,
List<LocatedMessage>? context,
bool problemOnLibrary: false,
List<Uri>? involvedFiles}) {
severity ??= message.code.severity;
if (severity == Severity.ignored) return null;
String trace = """
message: ${message.problemMessage}
charOffset: $charOffset
fileUri: $fileUri
severity: $severity
""";
if (!seenMessages.add(trace)) return null;
if (message.code.severity == Severity.error) {
_hasSeenError = true;
}
if (message.code.severity == Severity.context) {
internalProblem(
templateInternalProblemContextSeverity
.withArguments(message.code.name),
charOffset,
fileUri);
}
target.context.report(
fileUri != null
? message.withLocation(fileUri, charOffset, length)
: message.withoutLocation(),
severity,
context: context,
involvedFiles: involvedFiles);
if (severity == Severity.error) {
(wasHandled ? handledErrors : unhandledErrors).add(fileUri != null
? message.withLocation(fileUri, charOffset, length)
: message.withoutLocation());
}
FormattedMessage formattedMessage = target.createFormattedMessage(
message, charOffset, length, fileUri, context, severity,
involvedFiles: involvedFiles);
if (!problemOnLibrary) {
allComponentProblems.add(formattedMessage);
}
return formattedMessage;
}
MemberBuilder getAbstractClassInstantiationError() {
return target.getAbstractClassInstantiationError(this);
}
MemberBuilder getCompileTimeError() => target.getCompileTimeError(this);
MemberBuilder getDuplicatedFieldInitializerError() {
return target.getDuplicatedFieldInitializerError(this);
}
MemberBuilder getNativeAnnotation() => target.getNativeAnnotation(this);
BodyBuilder createBodyBuilderForOutlineExpression(
SourceLibraryBuilder library,
DeclarationBuilder? declarationBuilder,
ModifierBuilder member,
Scope scope,
Uri fileUri) {
return new BodyBuilder.forOutlineExpression(
library, declarationBuilder, member, scope, fileUri);
}
NnbdMode get nnbdMode => target.context.options.nnbdMode;
bool get enableUnscheduledExperiments =>
target.context.options.enableUnscheduledExperiments;
CoreTypes get coreTypes {
assert(_coreTypes != null, "CoreTypes has not been computed.");
return _coreTypes!;
}
ClassHierarchy get hierarchy => _hierarchy!;
void set hierarchy(ClassHierarchy? value) {
if (_hierarchy != value) {
_hierarchy = value;
_typeEnvironment = null;
}
}
TypeEnvironment get typeEnvironment {
return _typeEnvironment ??= new TypeEnvironment(coreTypes, hierarchy);
}
TypeInferenceEngineImpl get typeInferenceEngine => _typeInferenceEngine!;
ClassHierarchyBuilder get hierarchyBuilder => _hierarchyBuilder!;
ClassMembersBuilder get membersBuilder => _membersBuilder!;
Template<SummaryTemplate> get outlineSummaryTemplate =>
templateSourceOutlineSummary;
Future<Token> tokenize(SourceLibraryBuilder library,
{bool suppressLexicalErrors: false}) async {
Uri fileUri = library.fileUri;
// Lookup the file URI in the cache.
List<int>? bytes = sourceBytes[fileUri];
if (bytes == null) {
// Error recovery.
if (fileUri.scheme == untranslatableUriScheme) {
Message message =
templateUntranslatableUri.withArguments(library.importUri);
library.addProblemAtAccessors(message);
bytes = synthesizeSourceForMissingFile(library.importUri, null);
} else if (!fileUri.hasScheme) {
return internalProblem(
templateInternalProblemUriMissingScheme.withArguments(fileUri),
-1,
library.importUri);
} else if (fileUri.scheme == SourceLibraryBuilder.MALFORMED_URI_SCHEME) {
library.addProblemAtAccessors(messageExpectedUri);
bytes = synthesizeSourceForMissingFile(library.importUri, null);
}
if (bytes != null) {
Uint8List zeroTerminatedBytes = new Uint8List(bytes.length + 1);
zeroTerminatedBytes.setRange(0, bytes.length, bytes);
bytes = zeroTerminatedBytes;
sourceBytes[fileUri] = bytes;
}
}
if (bytes == null) {
// If it isn't found in the cache, read the file read from the file
// system.
List<int> rawBytes;
try {
rawBytes = await fileSystem.entityForUri(fileUri).readAsBytes();
} on FileSystemException catch (e) {
Message message =
templateCantReadFile.withArguments(fileUri, e.message);
library.addProblemAtAccessors(message);
rawBytes = synthesizeSourceForMissingFile(library.importUri, message);
}
Uint8List zeroTerminatedBytes = new Uint8List(rawBytes.length + 1);
zeroTerminatedBytes.setRange(0, rawBytes.length, rawBytes);
bytes = zeroTerminatedBytes;
sourceBytes[fileUri] = bytes;
byteCount += rawBytes.length;
}
ScannerResult result = scan(bytes,
includeComments: includeComments,
configuration: new ScannerConfiguration(
enableTripleShift: target.isExperimentEnabledInLibraryByVersion(
ExperimentalFlag.tripleShift,
library.importUri,
library.packageLanguageVersion.version),
enableExtensionMethods:
target.isExperimentEnabledInLibraryByVersion(
ExperimentalFlag.extensionMethods,
library.importUri,
library.packageLanguageVersion.version),
enableNonNullable: target.isExperimentEnabledInLibraryByVersion(
ExperimentalFlag.nonNullable,
library.importUri,
library.packageLanguageVersion.version)),
languageVersionChanged:
(Scanner scanner, LanguageVersionToken version) {
if (!suppressLexicalErrors) {
library.registerExplicitLanguageVersion(
new Version(version.major, version.minor),
offset: version.offset,
length: version.length);
}
scanner.configuration = new ScannerConfiguration(
enableTripleShift: library.enableTripleShiftInLibrary,
enableExtensionMethods: library.enableExtensionMethodsInLibrary,
enableNonNullable: library.isNonNullableByDefault);
});
Token token = result.tokens;
if (!suppressLexicalErrors) {
List<int> source = getSource(bytes);
Uri importUri = library.importUri;
if (library.isPatch) {
// For patch files we create a "fake" import uri.
// We cannot use the import uri from the patched library because
// several different files would then have the same import uri,
// and the VM does not support that. Also, what would, for instance,
// setting a breakpoint on line 42 of some import uri mean, if the uri
// represented several files?
List<String> newPathSegments =
new List<String>.from(importUri.pathSegments);
newPathSegments.add(library.fileUri.pathSegments.last);
newPathSegments[0] = "${newPathSegments[0]}-patch";
importUri = importUri.replace(pathSegments: newPathSegments);
}
target.addSourceInformation(
importUri, library.fileUri, result.lineStarts, source);
}
library.issuePostponedProblems();
library.markLanguageVersionFinal();
while (token is ErrorToken) {
if (!suppressLexicalErrors) {
ErrorToken error = token;
library.addProblem(error.assertionMessage, offsetForToken(token),
lengthForToken(token), fileUri);
}
token = token.next!;
}
return token;
}
List<int> synthesizeSourceForMissingFile(Uri uri, Message? message) {
switch ("$uri") {
case "dart:core":
return utf8.encode(defaultDartCoreSource);
case "dart:async":
return utf8.encode(defaultDartAsyncSource);
case "dart:collection":
return utf8.encode(defaultDartCollectionSource);
case "dart:_internal":
return utf8.encode(defaultDartInternalSource);
case "dart:typed_data":
return utf8.encode(defaultDartTypedDataSource);
default:
return utf8
.encode(message == null ? "" : "/* ${message.problemMessage} */");
}
}
Set<LibraryBuilder>? _strongOptOutLibraries;
void registerStrongOptOutLibrary(LibraryBuilder libraryBuilder) {
_strongOptOutLibraries ??= {};
_strongOptOutLibraries!.add(libraryBuilder);
hasInvalidNnbdModeLibrary = true;
}
bool hasInvalidNnbdModeLibrary = false;
Map<LibraryBuilder, Message>? _nnbdMismatchLibraries;
void registerNnbdMismatchLibrary(
LibraryBuilder libraryBuilder, Message message) {
_nnbdMismatchLibraries ??= {};
_nnbdMismatchLibraries![libraryBuilder] = message;
hasInvalidNnbdModeLibrary = true;
}
void registerConstructorToBeInferred(
Constructor constructor, SourceConstructorBuilder builder) {
_typeInferenceEngine!.toBeInferred[constructor] = builder;
}
void registerTypeDependency(Member member, TypeDependency typeDependency) {
_typeInferenceEngine!.typeDependencies[member] = typeDependency;
}
Future<void> buildOutlines() async {
_ensureCoreLibrary();
while (_unparsedLibraries.isNotEmpty) {
LibraryBuilder library = _unparsedLibraries.removeFirst();
currentUriForCrashReporting = library.importUri;
await buildOutline(library as SourceLibraryBuilder);
}
currentUriForCrashReporting = null;
logSummary(outlineSummaryTemplate);
if (_strongOptOutLibraries != null) {
// We have libraries that are opted out in strong mode "non-explicitly",
// that is, either implicitly through the package version or loaded from
// .dill as opt out.
//
// To reduce the verbosity of the error messages we try to reduce the
// message to only include the package name once for packages that are
// opted out.
//
// We use the current package config to retrieve the package based
// language version to determine whether the package as a whole is opted
// out. If so, we only include the package name and not the library uri
// in the message. For package libraries with no corresponding package
// config we include each library uri in the message. For non-package
// libraries with no corresponding package config we generate a message
// per library.
giveCombinedErrorForNonStrongLibraries(_strongOptOutLibraries!,
emitNonPackageErrors: true);
_strongOptOutLibraries = null;
}
if (_nnbdMismatchLibraries != null) {
for (MapEntry<LibraryBuilder, Message> entry
in _nnbdMismatchLibraries!.entries) {
addProblem(entry.value, -1, noLength, entry.key.fileUri);
}
_nnbdMismatchLibraries = null;
}
}
FormattedMessage? giveCombinedErrorForNonStrongLibraries(
Set<LibraryBuilder> libraries,
{required bool emitNonPackageErrors}) {
Map<String?, List<LibraryBuilder>> libraryByPackage = {};
Map<package_config.Package, Version> enableNonNullableVersionByPackage = {};
for (LibraryBuilder libraryBuilder in libraries) {
final package_config.Package? package =
target.uriTranslator.getPackage(libraryBuilder.importUri);
if (package != null &&
package.languageVersion != null &&
package.languageVersion is! InvalidLanguageVersion) {
Version enableNonNullableVersion =
enableNonNullableVersionByPackage[package] ??=
target.getExperimentEnabledVersionInLibrary(
ExperimentalFlag.nonNullable,
new Uri(scheme: 'package', path: package.name));
Version version = new Version(
package.languageVersion!.major, package.languageVersion!.minor);
if (version < enableNonNullableVersion) {
(libraryByPackage[package.name] ??= []).add(libraryBuilder);
continue;
}
}
if (libraryBuilder.importUri.scheme == 'package') {
(libraryByPackage[null] ??= []).add(libraryBuilder);
} else {
if (emitNonPackageErrors) {
// Emit a message that doesn't mention running 'pub'.
addProblem(messageStrongModeNNBDButOptOut, -1, noLength,
libraryBuilder.fileUri);
}
}
}
if (libraryByPackage.isNotEmpty) {
List<Uri> involvedFiles = [];
List<String> dependencies = [];
libraryByPackage.forEach((String? name, List<LibraryBuilder> libraries) {
if (name != null) {
dependencies.add('package:$name');
for (LibraryBuilder libraryBuilder in libraries) {
involvedFiles.add(libraryBuilder.fileUri);
}
} else {
for (LibraryBuilder libraryBuilder in libraries) {
dependencies.add(libraryBuilder.importUri.toString());
involvedFiles.add(libraryBuilder.fileUri);
}
}
});
// Emit a message that suggests to run 'pub' to check for opted in
// versions of the packages.
return addProblem(
templateStrongModeNNBDPackageOptOut.withArguments(dependencies),
-1,
-1,
null,
involvedFiles: involvedFiles);
}
return null;
}
List<int> getSource(List<int> bytes) {
// bytes is 0-terminated. We don't want that included.
if (bytes is Uint8List) {
return new Uint8List.view(
bytes.buffer, bytes.offsetInBytes, bytes.length - 1);
}
return bytes.sublist(0, bytes.length - 1);
}
Future<Null> buildOutline(SourceLibraryBuilder library) async {
Token tokens = await tokenize(library);
// ignore: unnecessary_null_comparison
if (tokens == null) return;
OutlineBuilder listener = new OutlineBuilder(library);
new ClassMemberParser(listener).parseUnit(tokens);
}
/// Builds all the method bodies found in the given [library].
Future<Null> buildBody(SourceLibraryBuilder library) async {
Iterable<SourceLibraryBuilder>? patches = library.patchLibraries;
if (patches != null) {
for (SourceLibraryBuilder patchLibrary in patches) {
await buildBody(patchLibrary);
}
}
// We tokenize source files twice to keep memory usage low. This is the
// second time, and the first time was in [buildOutline] above. So this
// time we suppress lexical errors.
Token tokens = await tokenize(library, suppressLexicalErrors: true);
// ignore: unnecessary_null_comparison
if (tokens == null) return;
DietListener listener = createDietListener(library);
DietParser parser = new DietParser(listener);
parser.parseUnit(tokens);
for (LibraryBuilder part in library.parts) {
if (part.partOfLibrary != library) {
// Part was included in multiple libraries. Skip it here.
continue;
}
Token tokens = await tokenize(part as SourceLibraryBuilder,
suppressLexicalErrors: true);
// ignore: unnecessary_null_comparison
if (tokens != null) {
listener.uri = part.fileUri;
parser.parseUnit(tokens);
}
}
}
Future<Expression> buildExpression(
SourceLibraryBuilder libraryBuilder,
String? enclosingClassOrExtension,
bool isClassInstanceMember,
FunctionNode parameters,
VariableDeclaration? extensionThis) async {
Token token = await tokenize(libraryBuilder, suppressLexicalErrors: false);
DietListener dietListener = createDietListener(libraryBuilder);
Builder parent = libraryBuilder;
if (enclosingClassOrExtension != null) {
Builder? cls = dietListener.memberScope
.lookup(enclosingClassOrExtension, -1, libraryBuilder.fileUri);
if (cls is ClassBuilder) {
parent = cls;
dietListener
..currentDeclaration = cls
..memberScope = cls.scope.copyWithParent(
dietListener.memberScope.withTypeVariables(cls.typeVariables),
"debugExpression in class $enclosingClassOrExtension");
} else if (cls is ExtensionBuilder) {
parent = cls;
dietListener
..currentDeclaration = cls
..memberScope = cls.scope.copyWithParent(dietListener.memberScope,
"debugExpression in extension $enclosingClassOrExtension");
}
}
ProcedureBuilder builder = new SourceProcedureBuilder(
null,
0,
null,
"debugExpr",
null,
null,
ProcedureKind.Method,
libraryBuilder,
0,
0,
-1,
-1,
null,
null,
AsyncMarker.Sync,
new NameScheme(
className: null,
extensionName: null,
isExtensionMember: false,
isInstanceMember: false,
libraryReference: libraryBuilder.library.reference),
isInstanceMember: false,
isExtensionMember: false)
..parent = parent;
BodyBuilder listener = dietListener.createListener(
builder, dietListener.memberScope,
isDeclarationInstanceMember: isClassInstanceMember,
extensionThis: extensionThis);
return listener.parseSingleExpression(
new Parser(listener,
useImplicitCreationExpression: useImplicitCreationExpressionInCfe),
token,
parameters);
}
DietListener createDietListener(SourceLibraryBuilder library) {
return new DietListener(library, hierarchy, coreTypes, typeInferenceEngine);
}
void resolveParts() {
List<Uri> parts = <Uri>[];
List<SourceLibraryBuilder> libraries = [];
List<SourceLibraryBuilder> sourceLibraries = [];
List<SourceLibraryBuilder> patchLibraries = [];
_builders.forEach((Uri uri, LibraryBuilder library) {
if (library.loader == this && library is SourceLibraryBuilder) {
if (library.isPart) {
parts.add(uri);
} else {
if (library.isPatch) {
patchLibraries.add(library);
} else {
sourceLibraries.add(library);
}
libraries.add(library);
}
}
});
Set<Uri> usedParts = new Set<Uri>();
for (SourceLibraryBuilder library in libraries) {
library.includeParts(usedParts);
}
for (Uri uri in parts) {
if (usedParts.contains(uri)) {
LibraryBuilder? part = _builders.remove(uri);
if (_firstUri == uri) {
firstUri = part!.partOfLibrary!.importUri;
}
} else {
SourceLibraryBuilder part =
lookupLibraryBuilder(uri) as SourceLibraryBuilder;
part.addProblem(messagePartOrphan, 0, 1, part.fileUri);
part.validatePart(null, null);
sourceLibraries.add(part);
}
}
ticker.logMs("Resolved parts");
for (LibraryBuilder library in libraryBuilders) {
if (library.loader == this) {
library.applyPatches();
}
}
for (SourceLibraryBuilder patchLibrary in patchLibraries) {
_builders.remove(patchLibrary.fileUri);
patchLibrary.origin.addPatchLibrary(patchLibrary);
}
_sourceLibraryBuilders = sourceLibraries;
assert(
libraryBuilders.every((library) => !library.isPatch),
"Patch library found in libraryBuilders: "
"${libraryBuilders.where((library) => library.isPatch)}.");
assert(
sourceLibraries.every((library) => !library.isPatch),
"Patch library found in sourceLibraryBuilders: "
"${sourceLibraries.where((library) => library.isPatch)}.");
assert(
libraryBuilders.every((library) =>
library.loader != this || sourceLibraries.contains(library)),
"Source library not found in sourceLibraryBuilders:"
"${libraryBuilders.where((library) => // force line break
library.loader == this && !sourceLibraries.contains(library))}");
ticker.logMs("Applied patches");
}
void computeLibraryScopes() {
Set<LibraryBuilder> exporters = new Set<LibraryBuilder>();
Set<LibraryBuilder> exportees = new Set<LibraryBuilder>();
for (LibraryBuilder library in libraryBuilders) {
if (library.loader == this) {
SourceLibraryBuilder sourceLibrary = library as SourceLibraryBuilder;
sourceLibrary.buildInitialScopes();
}
if (library.exporters.isNotEmpty) {
exportees.add(library);
for (Export exporter in library.exporters) {
exporters.add(exporter.exporter);
}
}
Iterable<SourceLibraryBuilder>? patches =
library is SourceLibraryBuilder ? library.patchLibraries : null;
if (patches != null) {
for (SourceLibraryBuilder patchLibrary in patches) {
if (patchLibrary.exporters.isNotEmpty) {
exportees.add(patchLibrary);
for (Export exporter in patchLibrary.exporters) {
exporters.add(exporter.exporter);
}
}
}
}
}
Set<SourceLibraryBuilder> both = new Set<SourceLibraryBuilder>();
for (LibraryBuilder exported in exportees) {
if (exporters.contains(exported)) {
both.add(exported as SourceLibraryBuilder);
}
for (Export export in exported.exporters) {
exported.exportScope.forEach(export.addToExportScope);
}
}
bool wasChanged = false;
do {
wasChanged = false;
for (SourceLibraryBuilder exported in both) {
for (Export export in exported.exporters) {
exported.exportScope.forEach((String name, Builder member) {
if (export.addToExportScope(name, member)) {
wasChanged = true;
}
});
}
}
} while (wasChanged);
for (LibraryBuilder library in libraryBuilders) {
if (library.loader == this) {
SourceLibraryBuilder sourceLibrary = library as SourceLibraryBuilder;
sourceLibrary.addImportsToScope();
}
}
for (LibraryBuilder exportee in exportees) {
// TODO(ahe): Change how we track exporters. Currently, when a library
// (exporter) exports another library (exportee) we add a reference to
// exporter to exportee. This creates a reference in the wrong direction
// and can lead to memory leaks.
exportee.exporters.clear();
}
ticker.logMs("Computed library scopes");
// debugPrintExports();
}
void debugPrintExports() {
// TODO(sigmund): should be `covariant SourceLibraryBuilder`.
_builders.forEach((Uri uri, dynamic l) {
SourceLibraryBuilder library = l;
Set<Builder> members = new Set<Builder>();
Iterator<Builder> iterator = library.iterator;
while (iterator.moveNext()) {
members.add(iterator.current);
}
List<String> exports = <String>[];
library.exportScope.forEach((String name, Builder? member) {
while (member != null) {
if (!members.contains(member)) {
exports.add(name);
}
member = member.next;
}
});
if (exports.isNotEmpty) {
print("$uri exports $exports");
}
});
}
void resolveTypes() {
int typeCount = 0;
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
typeCount += library.resolveTypes();
}
ticker.logMs("Resolved $typeCount types");
}
void computeMacroDeclarations() {
if (!enableMacros) return;
LibraryBuilder? macroLibraryBuilder = lookupLibraryBuilder(macroLibraryUri);
if (macroLibraryBuilder == null) return;
Builder? macroClassBuilder =
macroLibraryBuilder.lookupLocalMember(macroClassName);
if (macroClassBuilder is! ClassBuilder) {
// TODO(johnniwinther): Report this when the actual macro builder package
// exists. It should at least be a warning.
return;
}
_macroClassBuilder = macroClassBuilder;
if (retainDataForTesting) {
dataForTesting!.macroDeclarationData.macrosAreAvailable = true;
}
Set<ClassBuilder> macroClasses = {macroClassBuilder};
Set<Uri> macroLibraries = {macroLibraryBuilder.importUri};
for (SourceLibraryBuilder sourceLibraryBuilder in sourceLibraryBuilders) {
Iterator<Builder> iterator = sourceLibraryBuilder.iterator;
while (iterator.moveNext()) {
Builder builder = iterator.current;
if (builder is SourceClassBuilder && builder.isMacro) {
macroClasses.add(builder);
macroLibraries.add(builder.library.importUri);
if (retainDataForTesting) {
(dataForTesting!.macroDeclarationData
.macroDeclarations[builder.library.importUri] ??= [])
.add(builder.name);
}
}
}
}
bool isDillLibrary(Uri uri) => _builders[uri]?.loader != this;
List<List<Uri>> computeCompilationSequence(Graph<Uri> libraryGraph,
{required bool Function(Uri) filter}) {
List<List<Uri>> stronglyConnectedComponents =
computeStrongComponents(libraryGraph);
Graph<List<Uri>> strongGraph =
new StrongComponentGraph(libraryGraph, stronglyConnectedComponents);
List<List<List<Uri>>> componentLayers =
topologicalSort(strongGraph).layers;
List<List<Uri>> layeredComponents = [];
List<Uri> currentLayer = [];
for (List<List<Uri>> layer in componentLayers) {
bool declaresMacro = false;
for (List<Uri> component in layer) {
for (Uri uri in component) {
if (filter(uri)) continue;
if (macroLibraries.contains(uri)) {
declaresMacro = true;
}
currentLayer.add(uri);
}
}
if (declaresMacro) {
layeredComponents.add(currentLayer);
currentLayer = [];
}
}
if (currentLayer.isNotEmpty) {
layeredComponents.add(currentLayer);
}
return layeredComponents;
}
List<List<Uri>> compilationSteps = computeCompilationSequence(
new BuilderGraph(_builders),
filter: isDillLibrary);
if (retainDataForTesting) {
dataForTesting!.macroDeclarationData.compilationSequence =
compilationSteps;
}
}
void computeMacroApplications() {
if (!enableMacros || _macroClassBuilder == null) return;
MacroApplications? computeApplications(
SourceLibraryBuilder enclosingLibrary,
Scope scope,
Uri fileUri,
List<MetadataBuilder>? annotations) {
List<MacroApplication>? result = prebuildAnnotations(
enclosingLibrary: enclosingLibrary,
metadataBuilders: annotations,
fileUri: fileUri,
scope: scope);
return result != null ? new MacroApplications(result) : null;
}
for (SourceLibraryBuilder libraryBuilder in sourceLibraryBuilders) {
// TODO(johnniwinther): Handle patch libraries.
LibraryMacroApplicationData libraryMacroApplicationData =
new LibraryMacroApplicationData();
Iterator<Builder> iterator = libraryBuilder.iterator;
while (iterator.moveNext()) {
Builder builder = iterator.current;
if (builder is SourceClassBuilder) {
SourceClassBuilder classBuilder = builder;
ClassMacroApplicationData classMacroApplicationData =
new ClassMacroApplicationData();
classMacroApplicationData.classApplications = computeApplications(
libraryBuilder,
classBuilder.scope,
classBuilder.fileUri,
classBuilder.metadata);
builder.forEach((String name, Builder memberBuilder) {
if (memberBuilder is SourceProcedureBuilder) {
MacroApplications? macroApplications = computeApplications(
libraryBuilder,
classBuilder.scope,
memberBuilder.fileUri,
memberBuilder.metadata);
if (macroApplications != null) {
classMacroApplicationData
.memberApplications[memberBuilder.procedure] =
macroApplications;
}
} else if (memberBuilder is SourceFieldBuilder) {
MacroApplications? macroApplications = computeApplications(
libraryBuilder,
classBuilder.scope,
memberBuilder.fileUri,
memberBuilder.metadata);
if (macroApplications != null) {
classMacroApplicationData
.memberApplications[memberBuilder.field] =
macroApplications;
}
}
});
classBuilder.forEachConstructor((String name, Builder memberBuilder) {
if (memberBuilder is SourceConstructorBuilder) {
MacroApplications? macroApplications = computeApplications(
libraryBuilder,
classBuilder.scope,
memberBuilder.fileUri,
memberBuilder.metadata);
if (macroApplications != null) {
classMacroApplicationData
.memberApplications[memberBuilder.constructor] =
macroApplications;
}
}
});
if (classMacroApplicationData.classApplications != null ||
classMacroApplicationData.memberApplications.isNotEmpty) {
libraryMacroApplicationData.classData[builder.cls] =
classMacroApplicationData;
}
} else if (builder is SourceProcedureBuilder) {
MacroApplications? macroApplications = computeApplications(
libraryBuilder,
libraryBuilder.scope,
builder.fileUri,
builder.metadata);
if (macroApplications != null) {
libraryMacroApplicationData.memberApplications[builder.procedure] =
macroApplications;
}
} else if (builder is SourceFieldBuilder) {
MacroApplications? macroApplications = computeApplications(
libraryBuilder,
libraryBuilder.scope,
builder.fileUri,
builder.metadata);
if (macroApplications != null) {
libraryMacroApplicationData.memberApplications[builder.field] =
macroApplications;
}
}
}
if (libraryMacroApplicationData.classData.isNotEmpty ||
libraryMacroApplicationData.memberApplications.isNotEmpty) {
if (retainDataForTesting) {
dataForTesting!
.macroApplicationData.libraryData[libraryBuilder.library] =
libraryMacroApplicationData;
}
}
}
}
void finishDeferredLoadTearoffs() {
int count = 0;
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
count += library.finishDeferredLoadTearoffs();
}
ticker.logMs("Finished deferred load tearoffs $count");
}
void finishNoSuchMethodForwarders() {
int count = 0;
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
count += library.finishForwarders();
}
ticker.logMs("Finished forwarders for $count procedures");
}
void resolveConstructors() {
int count = 0;
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
count += library.resolveConstructors();
}
ticker.logMs("Resolved $count constructors");
}
void installTypedefTearOffs() {
if (target.backendTarget.isTypedefTearOffLoweringEnabled) {
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
library.installTypedefTearOffs();
}
}
}
void finishTypeVariables(ClassBuilder object, TypeBuilder dynamicType) {
int count = 0;
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
count += library.finishTypeVariables(object, dynamicType);
}
ticker.logMs("Resolved $count type-variable bounds");
}
void computeVariances() {
int count = 0;
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
count += library.computeVariances();
}
ticker.logMs("Computed variances of $count type variables");
}
void computeDefaultTypes(TypeBuilder dynamicType, TypeBuilder nullType,
TypeBuilder bottomType, ClassBuilder objectClass) {
int count = 0;
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
count += library.computeDefaultTypes(
dynamicType, nullType, bottomType, objectClass);
}
ticker.logMs("Computed default types for $count type variables");
}
void finishNativeMethods() {
int count = 0;
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
count += library.finishNativeMethods();
}
ticker.logMs("Finished $count native methods");
}
void finishPatchMethods() {
int count = 0;
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
count += library.finishPatchMethods();
}
ticker.logMs("Finished $count patch methods");
}
/// Check that [objectClass] has no supertypes. Recover by removing any
/// found.
void checkObjectClassHierarchy(ClassBuilder objectClass) {
if (objectClass is SourceClassBuilder &&
objectClass.library.loader == this) {
if (objectClass.supertypeBuilder != null) {
objectClass.supertypeBuilder = null;
objectClass.addProblem(
messageObjectExtends, objectClass.charOffset, noLength);
}
if (objectClass.interfaceBuilders != null) {
objectClass.addProblem(
messageObjectImplements, objectClass.charOffset, noLength);
objectClass.interfaceBuilders = null;
}
if (objectClass.mixedInTypeBuilder != null) {
objectClass.addProblem(
messageObjectMixesIn, objectClass.charOffset, noLength);
objectClass.mixedInTypeBuilder = null;
}
}
}
/// Returns classes defined in libraries in this [SourceLoader].
List<SourceClassBuilder> collectSourceClasses() {
List<SourceClassBuilder> sourceClasses = <SourceClassBuilder>[];
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
library.collectSourceClasses(sourceClasses);
}
return sourceClasses;
}
/// Returns a list of all class builders declared in this loader. As the
/// classes are sorted, any cycles in the hierarchy are reported as
/// errors. Recover by breaking the cycles. This means that the rest of the
/// pipeline (including backends) can assume that there are no hierarchy
/// cycles.
List<SourceClassBuilder> handleHierarchyCycles(ClassBuilder objectClass) {
Set<ClassBuilder> denyListedClasses = new Set<ClassBuilder>();
for (int i = 0; i < denylistedCoreClasses.length; i++) {
denyListedClasses.add(coreLibrary.lookupLocalMember(
denylistedCoreClasses[i],
required: true) as ClassBuilder);
}
if (typedDataLibrary != null) {
for (int i = 0; i < denylistedTypedDataClasses.length; i++) {
// Allow the member to not exist. If it doesn't, nobody can extend it.
Builder? member = typedDataLibrary!
.lookupLocalMember(denylistedTypedDataClasses[i], required: false);
if (member != null) denyListedClasses.add(member as ClassBuilder);
}
}
// Sort the classes topologically.
_SourceClassGraph classGraph =
new _SourceClassGraph(collectSourceClasses(), objectClass);
TopologicalSortResult<SourceClassBuilder> result =
topologicalSort(classGraph);
List<SourceClassBuilder> classes = result.sortedVertices;
for (SourceClassBuilder cls in classes) {
checkClassSupertypes(
cls, classGraph.directSupertypeMap[cls]!, denyListedClasses);
}
List<SourceClassBuilder> classesWithCycles = result.cyclicVertices;
// Once the work list doesn't change in size, it's either empty, or
// contains all classes with cycles.
// Sort the classes to ensure consistent output.
classesWithCycles.sort();
for (int i = 0; i < classesWithCycles.length; i++) {
SourceClassBuilder cls = classesWithCycles[i];
target.breakCycle(cls);
classes.add(cls);
cls.addProblem(
templateCyclicClassHierarchy.withArguments(cls.fullNameForErrors),
cls.charOffset,
noLength);
}
ticker.logMs("Checked class hierarchy");
return classes;
}
void _checkConstructorsForMixin(
SourceClassBuilder cls, ClassBuilder builder) {
for (Builder constructor in builder.constructors.local.values) {
if (constructor.isConstructor && !constructor.isSynthetic) {
cls.addProblem(
templateIllegalMixinDueToConstructors
.withArguments(builder.fullNameForErrors),
cls.charOffset,
noLength,
context: [
templateIllegalMixinDueToConstructorsCause
.withArguments(builder.fullNameForErrors)
.withLocation(
constructor.fileUri!, constructor.charOffset, noLength)
]);
}
}
}
void checkClassSupertypes(
SourceClassBuilder cls,
Map<TypeDeclarationBuilder?, TypeAliasBuilder?> directSupertypeMap,
Set<ClassBuilder> denyListedClasses) {
// Check that the direct supertypes aren't deny-listed or enums.
List<TypeDeclarationBuilder?> directSupertypes =
directSupertypeMap.keys.toList();
for (int i = 0; i < directSupertypes.length; i++) {
TypeDeclarationBuilder? supertype = directSupertypes[i];
if (supertype is EnumBuilder) {
cls.addProblem(templateExtendingEnum.withArguments(supertype.name),
cls.charOffset, noLength);
} else if (!cls.library.mayImplementRestrictedTypes &&
denyListedClasses.contains(supertype)) {
TypeAliasBuilder? aliasBuilder = directSupertypeMap[supertype];
if (aliasBuilder != null) {
cls.addProblem(
templateExtendingRestricted
.withArguments(supertype!.fullNameForErrors),
cls.charOffset,
noLength,
context: [
messageTypedefCause.withLocation(
aliasBuilder.fileUri, aliasBuilder.charOffset, noLength),
]);
} else {
cls.addProblem(
templateExtendingRestricted
.withArguments(supertype!.fullNameForErrors),
cls.charOffset,
noLength);
}
}
}
// Check that the mixed-in type can be used as a mixin.
final TypeBuilder? mixedInTypeBuilder = cls.mixedInTypeBuilder;
if (mixedInTypeBuilder != null) {
bool isClassBuilder = false;
if (mixedInTypeBuilder is NamedTypeBuilder) {
TypeDeclarationBuilder? builder = mixedInTypeBuilder.declaration;
if (builder is TypeAliasBuilder) {
TypeAliasBuilder aliasBuilder = builder;
NamedTypeBuilder namedBuilder = mixedInTypeBuilder;
builder = aliasBuilder.unaliasDeclaration(namedBuilder.arguments,
isUsedAsClass: true,
usedAsClassCharOffset: namedBuilder.charOffset,
usedAsClassFileUri: namedBuilder.fileUri);
if (builder is! ClassBuilder) {
cls.addProblem(
templateIllegalMixin.withArguments(builder!.fullNameForErrors),
cls.charOffset,
noLength,
context: [
messageTypedefCause.withLocation(
aliasBuilder.fileUri, aliasBuilder.charOffset, noLength),
]);
return;
} else if (!cls.library.mayImplementRestrictedTypes &&
denyListedClasses.contains(builder)) {
cls.addProblem(
templateExtendingRestricted
.withArguments(mixedInTypeBuilder.fullNameForErrors),
cls.charOffset,
noLength,
context: [
messageTypedefUnaliasedTypeCause.withLocation(
builder.fileUri, builder.charOffset, noLength),
]);
return;
}
}
if (builder is ClassBuilder) {
isClassBuilder = true;
_checkConstructorsForMixin(cls, builder);
}
}
if (!isClassBuilder) {
// TODO(ahe): Either we need to check this for superclass and
// interfaces, or this shouldn't be necessary (or handled elsewhere).
cls.addProblem(
templateIllegalMixin
.withArguments(mixedInTypeBuilder.fullNameForErrors),
cls.charOffset,
noLength);
}
}
}
List<SourceClassBuilder> checkSemantics(ClassBuilder objectClass) {
checkObjectClassHierarchy(objectClass);
return handleHierarchyCycles(objectClass);
}
/// Builds the core AST structure needed for the outline of the component.
void buildComponent() {
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
Library target = library.build(coreLibrary);
if (library.referencesFrom != null) {
referenceFromIndex ??= new ReferenceFromIndex();
referenceFromIndex!
.addIndexedLibrary(target, library.referencesFromIndexed!);
}
libraries.add(target);
}
ticker.logMs("Built component");
}
Component computeFullComponent() {
Set<Library> libraries = new Set<Library>();
List<Library> workList = <Library>[];
for (LibraryBuilder libraryBuilder in libraryBuilders) {
if (!libraryBuilder.isPatch &&
(libraryBuilder.loader == this ||
libraryBuilder.importUri.scheme == "dart" ||
libraryBuilder == this.first)) {
if (libraries.add(libraryBuilder.library)) {
workList.add(libraryBuilder.library);
}
}
}
while (workList.isNotEmpty) {
Library library = workList.removeLast();
for (LibraryDependency dependency in library.dependencies) {
if (libraries.add(dependency.targetLibrary)) {
workList.add(dependency.targetLibrary);
}
}
}
return new Component()..libraries.addAll(libraries);
}
void computeHierarchy() {
List<AmbiguousTypesRecord>? ambiguousTypesRecords = [];
HandleAmbiguousSupertypes onAmbiguousSupertypes =
(Class cls, Supertype a, Supertype b) {
if (ambiguousTypesRecords != null) {
ambiguousTypesRecords.add(new AmbiguousTypesRecord(cls, a, b));
}
};
if (_hierarchy == null) {
hierarchy = new ClassHierarchy(computeFullComponent(), coreTypes,
onAmbiguousSupertypes: onAmbiguousSupertypes);
} else {
hierarchy.onAmbiguousSupertypes = onAmbiguousSupertypes;
Component component = computeFullComponent();
hierarchy.coreTypes = coreTypes;
hierarchy.applyTreeChanges(const [], component.libraries, const [],
reissueAmbiguousSupertypesFor: component);
}
for (AmbiguousTypesRecord record in ambiguousTypesRecords) {
handleAmbiguousSupertypes(record.cls, record.a, record.b);
}
ambiguousTypesRecords = null;
ticker.logMs("Computed class hierarchy");
}
void computeShowHideElements() {
for (SourceLibraryBuilder libraryBuilder in sourceLibraryBuilders) {
libraryBuilder.computeShowHideElements(membersBuilder);
}
ticker.logMs("Computed show and hide elements");
}
void handleAmbiguousSupertypes(Class cls, Supertype a, Supertype b) {
addProblem(
templateAmbiguousSupertypes.withArguments(cls.name, a.asInterfaceType,
b.asInterfaceType, cls.enclosingLibrary.isNonNullableByDefault),
cls.fileOffset,
noLength,
cls.fileUri);
}
void ignoreAmbiguousSupertypes(Class cls, Supertype a, Supertype b) {}
void computeCoreTypes(Component component) {
assert(_coreTypes == null, "CoreTypes has already been computed");
_coreTypes = new CoreTypes(component);
// These types are used on the left-hand side of the is-subtype-of relation
// to check if the return types of functions with async, sync*, and async*
// bodies are correct. It's valid to use the non-nullable types on the
// left-hand side in both opt-in and opt-out code.
_futureOfBottom = new InterfaceType(coreTypes.futureClass,
Nullability.nonNullable, <DartType>[const NeverType.nonNullable()]);
_iterableOfBottom = new InterfaceType(coreTypes.iterableClass,
Nullability.nonNullable, <DartType>[const NeverType.nonNullable()]);
_streamOfBottom = new InterfaceType(coreTypes.streamClass,
Nullability.nonNullable, <DartType>[const NeverType.nonNullable()]);
ticker.logMs("Computed core types");
}
void checkSupertypes(List<SourceClassBuilder> sourceClasses) {
for (SourceClassBuilder builder in sourceClasses) {
if (builder.library.loader == this && !builder.isPatch) {
builder.checkSupertypes(coreTypes);
}
}
ticker.logMs("Checked supertypes");
}
void checkTypes() {
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
library.checkTypesInOutline(typeInferenceEngine.typeSchemaEnvironment);
}
ticker.logMs("Checked type arguments of supers against the bounds");
}
void checkOverrides(List<SourceClassBuilder> sourceClasses) {
List<DelayedCheck> overrideChecks = membersBuilder.takeDelayedChecks();
for (int i = 0; i < overrideChecks.length; i++) {
overrideChecks[i].check(membersBuilder);
}
ticker.logMs("Checked ${overrideChecks.length} overrides");
typeInferenceEngine.finishTopLevelInitializingFormals();
ticker.logMs("Finished initializing formals");
}
void checkAbstractMembers(List<SourceClassBuilder> sourceClasses) {
List<ClassMember> delayedMemberChecks =
membersBuilder.takeDelayedMemberComputations();
Set<Class> changedClasses = new Set<Class>();
for (int i = 0; i < delayedMemberChecks.length; i++) {
delayedMemberChecks[i].getMember(membersBuilder);
changedClasses.add(delayedMemberChecks[i].classBuilder.cls);
}
ticker.logMs(
"Computed ${delayedMemberChecks.length} combined member signatures");
hierarchy.applyMemberChanges(changedClasses, findDescendants: false);
ticker
.logMs("Updated ${changedClasses.length} classes in kernel hierarchy");
}
void checkRedirectingFactories(List<SourceClassBuilder> sourceClasses) {
// TODO(ahe): Move this to [ClassHierarchyBuilder].
for (SourceClassBuilder builder in sourceClasses) {
if (builder.library.loader == this && !builder.isPatch) {
builder.checkRedirectingFactories(
typeInferenceEngine.typeSchemaEnvironment);
}
}
ticker.logMs("Checked redirecting factories");
}
void addNoSuchMethodForwarders(List<SourceClassBuilder> sourceClasses) {
// TODO(ahe): Move this to [ClassHierarchyBuilder].
if (!target.backendTarget.enableNoSuchMethodForwarders) return;
List<Class> changedClasses = <Class>[];
for (SourceClassBuilder builder in sourceClasses) {
if (builder.library.loader == this && !builder.isPatch) {
if (builder.addNoSuchMethodForwarders(target, hierarchy)) {
changedClasses.add(builder.cls);
}
}
}
hierarchy.applyMemberChanges(changedClasses, findDescendants: true);
ticker.logMs("Added noSuchMethod forwarders");
}
void checkMixins(List<SourceClassBuilder> sourceClasses) {
for (SourceClassBuilder builder in sourceClasses) {
if (builder.library.loader == this && !builder.isPatch) {
Class? mixedInClass = builder.cls.mixedInClass;
if (mixedInClass != null && mixedInClass.isMixinDeclaration) {
builder.checkMixinApplication(hierarchy, coreTypes);
}
}
}
ticker.logMs("Checked mixin declaration applications");
}
void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<SynthesizedFunctionNode> synthesizedFunctionNodes) {
List<DelayedActionPerformer> delayedActionPerformers =
<DelayedActionPerformer>[];
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
library.buildOutlineExpressions(
classHierarchy, synthesizedFunctionNodes, delayedActionPerformers);
}
for (DelayedActionPerformer delayedActionPerformer
in delayedActionPerformers) {
delayedActionPerformer.performDelayedActions();
}
ticker.logMs("Build outline expressions");
}
void buildClassHierarchy(
List<SourceClassBuilder> sourceClasses, ClassBuilder objectClass) {
ClassHierarchyBuilder hierarchyBuilder = _hierarchyBuilder =
ClassHierarchyBuilder.build(
objectClass, sourceClasses, this, coreTypes);
ClassMembersBuilder membersBuilder = _membersBuilder =
ClassMembersBuilder.build(hierarchyBuilder, sourceClasses);
typeInferenceEngine.hierarchyBuilder = hierarchyBuilder;
typeInferenceEngine.membersBuilder = membersBuilder;
ticker.logMs("Built class hierarchy");
}
void createTypeInferenceEngine() {
_typeInferenceEngine = new TypeInferenceEngineImpl(instrumentation);
}
void performTopLevelInference(List<SourceClassBuilder> sourceClasses) {
/// The first phase of top level initializer inference, which consists of
/// creating kernel objects for all fields and top level variables that
/// might be subject to type inference, and records dependencies between
/// them.
typeInferenceEngine.prepareTopLevel(coreTypes, hierarchy);
membersBuilder.computeTypes();
List<FieldBuilder> allImplicitlyTypedFields = <FieldBuilder>[];
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
library.collectImplicitlyTypedFields(allImplicitlyTypedFields);
}
for (int i = 0; i < allImplicitlyTypedFields.length; i++) {
// TODO(ahe): This can cause a crash for parts that failed to get
// included, see for example,
// tests/standalone_2/io/http_cookie_date_test.dart.
allImplicitlyTypedFields[i].inferType();
}
typeInferenceEngine.isTypeInferencePrepared = true;
// Since finalization of covariance may have added forwarding stubs, we need
// to recompute the class hierarchy so that method compilation will properly
// target those forwarding stubs.
hierarchy.onAmbiguousSupertypes = ignoreAmbiguousSupertypes;
ticker.logMs("Performed top level inference");
}
void transformPostInference(TreeNode node, bool transformSetLiterals,
bool transformCollections, Library clientLibrary) {
if (transformCollections) {
collectionTransformer ??= new CollectionTransformer(this);
collectionTransformer!.enterLibrary(clientLibrary);
node.accept(collectionTransformer!);
collectionTransformer!.exitLibrary();
}
if (transformSetLiterals) {
setLiteralTransformer ??= new SetLiteralTransformer(this);
setLiteralTransformer!.enterLibrary(clientLibrary);
node.accept(setLiteralTransformer!);
setLiteralTransformer!.exitLibrary();
}
}
void transformListPostInference(
List<TreeNode> list,
bool transformSetLiterals,
bool transformCollections,
Library clientLibrary) {
if (transformCollections) {
CollectionTransformer transformer =
collectionTransformer ??= new CollectionTransformer(this);
transformer.enterLibrary(clientLibrary);
for (int i = 0; i < list.length; ++i) {
list[i] = list[i].accept(transformer);
}
transformer.exitLibrary();
}
if (transformSetLiterals) {
SetLiteralTransformer transformer =
setLiteralTransformer ??= new SetLiteralTransformer(this);
transformer.enterLibrary(clientLibrary);
for (int i = 0; i < list.length; ++i) {
list[i] = list[i].accept(transformer);
}
transformer.exitLibrary();
}
}
Expression instantiateNoSuchMethodError(
Expression receiver, String name, Arguments arguments, int offset,
{bool isMethod: false,
bool isGetter: false,
bool isSetter: false,
bool isField: false,
bool isLocalVariable: false,
bool isDynamic: false,
bool isSuper: false,
bool isStatic: false,
bool isConstructor: false,
bool isTopLevel: false}) {
return target.backendTarget.instantiateNoSuchMethodError(
coreTypes, receiver, name, arguments, offset,
isMethod: isMethod,
isGetter: isGetter,
isSetter: isSetter,
isField: isField,
isLocalVariable: isLocalVariable,
isDynamic: isDynamic,
isSuper: isSuper,
isStatic: isStatic,
isConstructor: isConstructor,
isTopLevel: isTopLevel);
}
void _checkMainMethods(
SourceLibraryBuilder libraryBuilder, DartType listOfString) {
Iterable<SourceLibraryBuilder>? patches = libraryBuilder.patchLibraries;
if (patches != null) {
for (SourceLibraryBuilder patchLibrary in patches) {
_checkMainMethods(patchLibrary, listOfString);
}
}
if (libraryBuilder.isNonNullableByDefault) {
Builder? mainBuilder =
libraryBuilder.exportScope.lookupLocalMember('main', setter: false);
mainBuilder ??=
libraryBuilder.exportScope.lookupLocalMember('main', setter: true);
if (mainBuilder is MemberBuilder) {
if (mainBuilder is InvalidTypeDeclarationBuilder) {
// This is an ambiguous export, skip the check.
return;
}
if (mainBuilder.isField ||
mainBuilder.isGetter ||
mainBuilder.isSetter) {
if (mainBuilder.parent != libraryBuilder) {
libraryBuilder.addProblem(messageMainNotFunctionDeclarationExported,
libraryBuilder.charOffset, noLength, libraryBuilder.fileUri,
context: [
messageExportedMain.withLocation(mainBuilder.fileUri!,
mainBuilder.charOffset, mainBuilder.name.length)
]);
} else {
libraryBuilder.addProblem(
messageMainNotFunctionDeclaration,
mainBuilder.charOffset,
mainBuilder.name.length,
mainBuilder.fileUri);
}
} else {
Procedure procedure = mainBuilder.member as Procedure;
if (procedure.function.requiredParameterCount > 2) {
if (mainBuilder.parent != libraryBuilder) {
libraryBuilder.addProblem(
messageMainTooManyRequiredParametersExported,
libraryBuilder.charOffset,
noLength,
libraryBuilder.fileUri,
context: [
messageExportedMain.withLocation(mainBuilder.fileUri!,
mainBuilder.charOffset, mainBuilder.name.length)
]);
} else {
libraryBuilder.addProblem(
messageMainTooManyRequiredParameters,
mainBuilder.charOffset,
mainBuilder.name.length,
mainBuilder.fileUri);
}
} else if (procedure.function.namedParameters
.any((parameter) => parameter.isRequired)) {
if (mainBuilder.parent != libraryBuilder) {
libraryBuilder.addProblem(
messageMainRequiredNamedParametersExported,
libraryBuilder.charOffset,
noLength,
libraryBuilder.fileUri,
context: [
messageExportedMain.withLocation(mainBuilder.fileUri!,
mainBuilder.charOffset, mainBuilder.name.length)
]);
} else {
libraryBuilder.addProblem(
messageMainRequiredNamedParameters,
mainBuilder.charOffset,
mainBuilder.name.length,
mainBuilder.fileUri);
}
} else if (procedure.function.positionalParameters.length > 0) {
DartType parameterType =
procedure.function.positionalParameters.first.type;
if (!typeEnvironment.isSubtypeOf(listOfString, parameterType,
SubtypeCheckMode.withNullabilities)) {
if (mainBuilder.parent != libraryBuilder) {
libraryBuilder.addProblem(
templateMainWrongParameterTypeExported.withArguments(
parameterType,
listOfString,
libraryBuilder.isNonNullableByDefault),
libraryBuilder.charOffset,
noLength,
libraryBuilder.fileUri,
context: [
messageExportedMain.withLocation(mainBuilder.fileUri!,
mainBuilder.charOffset, mainBuilder.name.length)
]);
} else {
libraryBuilder.addProblem(
templateMainWrongParameterType.withArguments(parameterType,
listOfString, libraryBuilder.isNonNullableByDefault),
mainBuilder.charOffset,
mainBuilder.name.length,
mainBuilder.fileUri);
}
}
}
}
} else if (mainBuilder != null) {
if (mainBuilder.parent != libraryBuilder) {
libraryBuilder.addProblem(messageMainNotFunctionDeclarationExported,
libraryBuilder.charOffset, noLength, libraryBuilder.fileUri,
context: [
messageExportedMain.withLocation(
mainBuilder.fileUri!, mainBuilder.charOffset, noLength)
]);
} else {
libraryBuilder.addProblem(messageMainNotFunctionDeclaration,
mainBuilder.charOffset, noLength, mainBuilder.fileUri);
}
}
}
}
void checkMainMethods() {
DartType listOfString = new InterfaceType(coreTypes.listClass,
Nullability.nonNullable, [coreTypes.stringNonNullableRawType]);
for (SourceLibraryBuilder libraryBuilder in sourceLibraryBuilders) {
_checkMainMethods(libraryBuilder, listOfString);
}
}
void releaseAncillaryResources() {
hierarchy = null;
_hierarchyBuilder = null;
_membersBuilder = null;
_typeInferenceEngine = null;
_builders.clear();
libraries.clear();
firstUri = null;
sourceBytes.clear();
target.releaseAncillaryResources();
_coreTypes = null;
instrumentation = null;
collectionTransformer = null;
setLiteralTransformer = null;
}
@override
ClassBuilder computeClassBuilderFromTargetClass(Class cls) {
Library kernelLibrary = cls.enclosingLibrary;
LibraryBuilder? library = lookupLibraryBuilder(kernelLibrary.importUri);
if (library == null) {
return target.dillTarget.loader.computeClassBuilderFromTargetClass(cls);
}
return library.lookupLocalMember(cls.name, required: true) as ClassBuilder;
}
@override
TypeBuilder computeTypeBuilder(DartType type) {
return type.accept(new TypeBuilderComputer(this));
}
BodyBuilder createBodyBuilderForField(
FieldBuilder field, TypeInferrer typeInferrer) {
return new BodyBuilder.forField(field, typeInferrer);
}
}
/// A minimal implementation of dart:core that is sufficient to create an
/// instance of [CoreTypes] and compile a program.
const String defaultDartCoreSource = """
import 'dart:_internal';
import 'dart:async';
export 'dart:async' show Future, Stream;
print(object) {}
bool identical(a, b) => false;
class Iterator<E> {
bool moveNext() => null;
E get current => null;
}
class Iterable<E> {
Iterator<E> get iterator => null;
}
class List<E> extends Iterable<E> {
factory List() => null;
factory List.unmodifiable(elements) => null;
factory List.empty({bool growable = false}) => null;
factory List.filled(int length, E fill, {bool growable = false}) => null;
factory List.generate(int length, E generator(int index),
{bool growable = true}) => null;
factory List.of() => null;
void add(E element) {}
void addAll(Iterable<E> iterable) {}
E operator [](int index) => null;
}
class _GrowableList<E> {
factory _GrowableList(int length) => null;
factory _GrowableList.empty() => null;
factory _GrowableList.filled() => null;
factory _GrowableList.generate(int length, E generator(int index)) => null;
factory _GrowableList._literal1(E e0) => null;
factory _GrowableList._literal2(E e0, E e1) => null;
factory _GrowableList._literal3(E e0, E e1, E e2) => null;
factory _GrowableList._literal4(E e0, E e1, E e2, E e3) => null;
factory _GrowableList._literal5(E e0, E e1, E e2, E e3, E e4) => null;
factory _GrowableList._literal6(E e0, E e1, E e2, E e3, E e4, E e5) => null;
factory _GrowableList._literal7(E e0, E e1, E e2, E e3, E e4, E e5, E e6) => null;
factory _GrowableList._literal8(E e0, E e1, E e2, E e3, E e4, E e5, E e6, E e7) => null;
}
class _List<E> {
factory _List() => null;
factory _List.empty() => null;
factory _List.filled() => null;
factory _List.generate(int length, E generator(int index)) => null;
}
class MapEntry<K, V> {
K key;
V value;
}
abstract class Map<K, V> extends Iterable {
factory Map.unmodifiable(other) => null;
Iterable<MapEntry<K, V>> get entries;
void operator []=(K key, V value) {}
}
abstract class pragma {
String name;
Object options;
}
class AbstractClassInstantiationError {}
class NoSuchMethodError {
NoSuchMethodError.withInvocation(receiver, invocation);
}
class StackTrace {}
class Null {}
class Object {
const Object();
noSuchMethod(invocation) => null;
bool operator==(dynamic) {}
}
abstract class Enum {
}
abstract class _Enum {
}
class String {}
class Symbol {}
class Set<E> {
factory Set() = Set<E>._;
external factory Set._();
factory Set.of(o) = Set<E>._of;
external factory Set._of(o);
bool add(E element) {}
void addAll(Iterable<E> iterable) {}
}
class Type {}
class _InvocationMirror {
_InvocationMirror._withType(_memberName, _type, _typeArguments,
_positionalArguments, _namedArguments);
}
class bool {}
class double extends num {}
class int extends num {}
class num {}
class _SyncIterable {}
class _SyncIterator {
var _current;
var _yieldEachIterable;
}
class Function {}
""";
/// A minimal implementation of dart:async that is sufficient to create an
/// instance of [CoreTypes] and compile program.
const String defaultDartAsyncSource = """
_asyncErrorWrapperHelper(continuation) {}
void _asyncStarMoveNextHelper(var stream) {}
_asyncThenWrapperHelper(continuation) {}
_awaitHelper(object, thenCallback, errorCallback, awaiter) {}
_completeOnAsyncReturn(_future, value, async_jump_var) {}
_completeOnAsyncError(_future, e, st, async_jump_var) {}
class _AsyncStarStreamController {
add(event) {}
addError(error, stackTrace) {}
addStream(stream) {}
close() {}
get stream => null;
}
abstract class Completer {
factory Completer.sync() => null;
get future;
complete([value]);
completeError(error, [stackTrace]);
}
class Future<T> {
factory Future.microtask(computation) => null;
}
class FutureOr {
}
class _Future {
void _completeError(Object error, StackTrace stackTrace) {}
void _asyncCompleteError(Object error, StackTrace stackTrace) {}
}
class Stream {}
class _StreamIterator {
get current => null;
moveNext() {}
cancel() {}
}
""";
/// A minimal implementation of dart:collection that is sufficient to create an
/// instance of [CoreTypes] and compile program.
const String defaultDartCollectionSource = """
abstract class LinkedHashMap<K, V> implements Map<K, V> {
factory LinkedHashMap(
{bool Function(K, K)? equals,
int Function(K)? hashCode,
bool Function(dynamic)? isValidKey}) => null;
}
class _InternalLinkedHashMap<K, V> {
_InternalLinkedHashMap();
}
abstract class LinkedHashSet<E> implements Set<E> {
factory LinkedHashSet(
{bool Function(E, E)? equals,
int Function(E)? hashCode,
bool Function(dynamic)? isValidKey}) => null;
}
class _CompactLinkedHashSet<E> {
_CompactLinkedHashSet();
}
class _UnmodifiableSet {
final Map _map;
const _UnmodifiableSet(this._map);
}
""";
/// A minimal implementation of dart:_internal that is sufficient to create an
/// instance of [CoreTypes] and compile program.
const String defaultDartInternalSource = """
class Symbol {
const Symbol(String name);
}
T unsafeCast<T>(Object v) {}
class ReachabilityError {
ReachabilityError([message]);
}
""";
/// A minimal implementation of dart:typed_data that is sufficient to create an
/// instance of [CoreTypes] and compile program.
const String defaultDartTypedDataSource = """
class Endian {
static const Endian little = null;
static const Endian big = null;
static final Endian host = null;
}
""";
class AmbiguousTypesRecord {
final Class cls;
final Supertype a;
final Supertype b;
const AmbiguousTypesRecord(this.cls, this.a, this.b);
}
class SourceLoaderDataForTesting {
final Map<TreeNode, TreeNode> _aliasMap = {};
/// Registers that [original] has been replaced by [alias] in the generated
/// AST.
void registerAlias(TreeNode original, TreeNode alias) {
_aliasMap[alias] = original;
}
/// Returns the original node for [alias] or [alias] if it was not registered
/// as an alias.
TreeNode toOriginal(TreeNode alias) {
return _aliasMap[alias] ?? alias;
}
final MacroDeclarationData macroDeclarationData = new MacroDeclarationData();
final MacroApplicationData macroApplicationData = new MacroApplicationData();
}
class _SourceClassGraph implements Graph<SourceClassBuilder> {
@override
final List<SourceClassBuilder> vertices;
final ClassBuilder _objectClass;
final Map<SourceClassBuilder, Map<TypeDeclarationBuilder?, TypeAliasBuilder?>>
directSupertypeMap = {};
final Map<SourceClassBuilder, List<SourceClassBuilder>> _supertypeMap = {};
_SourceClassGraph(this.vertices, this._objectClass);
List<SourceClassBuilder> computeSuperClasses(SourceClassBuilder cls) {
Map<TypeDeclarationBuilder?, TypeAliasBuilder?> directSupertypes =
directSupertypeMap[cls] = cls.computeDirectSupertypes(_objectClass);
List<SourceClassBuilder> superClasses = [];
for (TypeDeclarationBuilder? directSupertype in directSupertypes.keys) {
if (directSupertype is SourceClassBuilder) {
superClasses.add(directSupertype);
}
}
return superClasses;
}
@override
Iterable<SourceClassBuilder> neighborsOf(SourceClassBuilder vertex) {
return _supertypeMap[vertex] ??= computeSuperClasses(vertex);
}
}