blob: 5c7c2f03a10e386543550a818bc30d5b1655bb2b [file] [log] [blame]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:typed_data';
import 'package:analyzer/dart/analysis/declared_variables.dart';
import 'package:analyzer/dart/ast/ast.dart' as ast;
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/dart/analysis/file_state.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
import 'package:analyzer/src/dart/element/name_union.dart';
import 'package:analyzer/src/summary2/bundle_writer.dart';
import 'package:analyzer/src/summary2/detach_nodes.dart';
import 'package:analyzer/src/summary2/library_builder.dart';
import 'package:analyzer/src/summary2/linked_element_factory.dart';
import 'package:analyzer/src/summary2/macro_application.dart';
import 'package:analyzer/src/summary2/macro_declarations.dart';
import 'package:analyzer/src/summary2/reference.dart';
import 'package:analyzer/src/summary2/simply_bounded.dart';
import 'package:analyzer/src/summary2/super_constructor_resolver.dart';
import 'package:analyzer/src/summary2/top_level_inference.dart';
import 'package:analyzer/src/summary2/type_alias.dart';
import 'package:analyzer/src/summary2/types_builder.dart';
import 'package:analyzer/src/summary2/variance_builder.dart';
import 'package:analyzer/src/util/performance/operation_performance.dart';
import 'package:analyzer/src/utilities/uri_cache.dart';
import 'package:macros/src/executor/multi_executor.dart' as macro;
Future<LinkResult> link({
required LinkedElementFactory elementFactory,
required OperationPerformanceImpl performance,
required List<LibraryFileKind> inputLibraries,
macro.MultiMacroExecutor? macroExecutor,
}) async {
var linker = Linker(elementFactory, macroExecutor);
await linker.link(
performance: performance,
inputLibraries: inputLibraries,
);
return LinkResult(
resolutionBytes: linker.resolutionBytes,
);
}
class Linker {
final LinkedElementFactory elementFactory;
final macro.MultiMacroExecutor? macroExecutor;
late final DeclarationBuilder macroDeclarationBuilder;
/// Libraries that are being linked.
final Map<Uri, LibraryBuilder> builders = {};
final Map<ElementImpl, ast.AstNode> elementNodes = Map.identity();
late InheritanceManager3 inheritance; // TODO(scheglov): cache it
late Uint8List resolutionBytes;
LibraryMacroApplier? _macroApplier;
Linker(this.elementFactory, this.macroExecutor) {
macroDeclarationBuilder = DeclarationBuilder(
nodeOfElement: (element) => elementNodes[element],
);
}
AnalysisContextImpl get analysisContext {
return elementFactory.analysisContext;
}
DeclaredVariables get declaredVariables {
return analysisContext.declaredVariables;
}
LibraryMacroApplier? get macroApplier => _macroApplier;
Reference get rootReference => elementFactory.rootReference;
bool get _isLinkingDartCore {
var dartCoreUri = uriCache.parse('dart:core');
return builders.containsKey(dartCoreUri);
}
/// If the [element] is part of a library being linked, return the node
/// from which it was created.
ast.AstNode? getLinkingNode(Element element) {
return elementNodes[element];
}
Future<void> link({
required OperationPerformanceImpl performance,
required List<LibraryFileKind> inputLibraries,
}) async {
for (var inputLibrary in inputLibraries) {
LibraryBuilder.build(this, inputLibrary);
}
await _buildOutlines(
performance: performance,
);
_writeLibraries();
}
void _buildClassSyntheticConstructors() {
for (var library in builders.values) {
library.buildClassSyntheticConstructors();
}
}
void _buildElementNameUnions() {
for (var builder in builders.values) {
var element = builder.element;
element.nameUnion = ElementNameUnion.forLibrary(element);
}
}
void _buildEnumChildren() {
for (var library in builders.values) {
library.buildEnumChildren();
}
}
void _buildEnumSyntheticConstructors() {
for (var library in builders.values) {
library.buildEnumSyntheticConstructors();
}
}
void _buildExportScopes() {
for (var library in builders.values) {
library.buildInitialExportScope();
}
var exportingBuilders = <LibraryBuilder>{};
var exportedBuilders = <LibraryBuilder>{};
for (var library in builders.values) {
library.addExporters();
}
for (var library in builders.values) {
if (library.exports.isNotEmpty) {
exportedBuilders.add(library);
for (var export in library.exports) {
exportingBuilders.add(export.exporter);
}
}
}
var both = <LibraryBuilder>{};
for (var exported in exportedBuilders) {
if (exportingBuilders.contains(exported)) {
both.add(exported);
}
for (var export in exported.exports) {
exported.exportScope.forEach(export.addToExportScope);
}
}
while (true) {
var hasChanges = false;
for (var exported in both) {
for (var export in exported.exports) {
exported.exportScope.forEach((name, reference) {
if (export.addToExportScope(name, reference)) {
hasChanges = true;
}
});
}
}
if (!hasChanges) break;
}
for (var library in builders.values) {
library.storeExportScope();
}
}
Future<LibraryMacroApplier?> _buildMacroApplier() async {
var macroExecutor = this.macroExecutor;
if (macroExecutor == null) {
return null;
}
var macroApplier = LibraryMacroApplier(
elementFactory: elementFactory,
macroExecutor: macroExecutor,
isLibraryBeingLinked: (uri) => builders.containsKey(uri),
declarationBuilder: macroDeclarationBuilder,
runDeclarationsPhase: _executeMacroDeclarationsPhase,
);
for (var library in builders.values) {
await library.fillMacroApplier(macroApplier);
}
return _macroApplier = macroApplier;
}
Future<void> _buildOutlines({
required OperationPerformanceImpl performance,
}) async {
_createTypeSystemIfNotLinkingDartCore();
await performance.runAsync(
'computeLibraryScopes',
(performance) async {
await _computeLibraryScopes(
performance: performance,
);
},
);
_createTypeSystem();
_resolveTypes();
_setDefaultSupertypes();
await performance.runAsync(
'executeMacroDeclarationsPhase',
(performance) async {
await _executeMacroDeclarationsPhase(
targetElement: null,
performance: performance,
);
},
);
_buildClassSyntheticConstructors();
_buildEnumSyntheticConstructors();
_replaceConstFieldsIfNoConstConstructor();
_resolveConstructorFieldFormals();
_buildEnumChildren();
_computeFieldPromotability();
SuperConstructorResolver(this).perform();
_performTopLevelInference();
_resolveConstructors();
_resolveConstantInitializers();
_resolveDefaultValues();
_resolveMetadata();
// TODO(scheglov): verify if any resolutions should happen after
await performance.runAsync(
'executeMacroDefinitionsPhase',
(performance) async {
await _executeMacroDefinitionsPhase(
performance: performance,
);
},
);
_collectMixinSuperInvokedNames();
_buildElementNameUnions();
_detachNodes();
await performance.runAsync(
'mergeMacroAugmentations',
(performance) async {
await _mergeMacroAugmentations(
performance: performance,
);
},
);
_disposeMacroApplications();
}
void _collectMixinSuperInvokedNames() {
for (var library in builders.values) {
library.collectMixinSuperInvokedNames();
}
}
void _computeFieldPromotability() {
for (var library in builders.values) {
library.computeFieldPromotability();
}
}
Future<void> _computeLibraryScopes({
required OperationPerformanceImpl performance,
}) async {
for (var library in builders.values) {
library.buildElements();
}
await performance.runAsync(
'buildMacroApplier',
(performance) async {
await _buildMacroApplier();
},
);
await performance.runAsync(
'executeMacroTypesPhase',
(performance) async {
for (var library in builders.values) {
await library.executeMacroTypesPhase(
performance: performance,
);
}
},
);
_buildExportScopes();
}
void _createTypeSystem() {
elementFactory.createTypeProviders(
elementFactory.dartCoreElement,
elementFactory.dartAsyncElement,
);
inheritance = InheritanceManager3();
}
/// To resolve macro annotations we need to access exported namespaces of
/// imported (and already linked) libraries. While computing it we might
/// need `Null` from `dart:core` (to convert null safe types to legacy).
void _createTypeSystemIfNotLinkingDartCore() {
if (!_isLinkingDartCore) {
_createTypeSystem();
}
}
void _detachNodes() {
for (var builder in builders.values) {
detachElementsFromNodes(builder.element);
}
}
void _disposeMacroApplications() {
for (var library in builders.values) {
library.disposeMacroApplications();
}
}
Future<void> _executeMacroDeclarationsPhase({
required ElementImpl? targetElement,
required OperationPerformanceImpl performance,
}) async {
while (true) {
var hasProgress = false;
for (var library in builders.values) {
var stepResult = await library.executeMacroDeclarationsPhase(
targetElement: targetElement,
performance: performance,
);
switch (stepResult) {
case MacroDeclarationsPhaseStepResult.nothing:
break;
case MacroDeclarationsPhaseStepResult.otherProgress:
hasProgress = true;
case MacroDeclarationsPhaseStepResult.topDeclaration:
hasProgress = true;
_buildExportScopes();
}
}
if (!hasProgress) {
break;
}
}
}
Future<void> _executeMacroDefinitionsPhase({
required OperationPerformanceImpl performance,
}) async {
for (var library in builders.values) {
await library.executeMacroDefinitionsPhase(
performance: performance,
);
}
}
Future<void> _mergeMacroAugmentations({
required OperationPerformanceImpl performance,
}) async {
for (var library in builders.values) {
await library.mergeMacroAugmentations(
performance: performance,
);
}
}
void _performTopLevelInference() {
TopLevelInference(this).infer();
}
void _replaceConstFieldsIfNoConstConstructor() {
for (var library in builders.values) {
library.replaceConstFieldsIfNoConstConstructor();
}
}
void _resolveConstantInitializers() {
ConstantInitializersResolver(this).perform();
}
void _resolveConstructorFieldFormals() {
for (var library in builders.values) {
library.resolveConstructorFieldFormals();
}
}
void _resolveConstructors() {
for (var library in builders.values) {
library.resolveConstructors();
}
}
void _resolveDefaultValues() {
for (var library in builders.values) {
library.resolveDefaultValues();
}
}
void _resolveMetadata() {
for (var library in builders.values) {
library.resolveMetadata();
}
}
void _resolveTypes() {
var nodesToBuildType = NodesToBuildType();
for (var library in builders.values) {
library.resolveTypes(nodesToBuildType);
}
VarianceBuilder(this).perform();
computeSimplyBounded(this);
TypeAliasSelfReferenceFinder().perform(this);
TypesBuilder(this).build(nodesToBuildType);
}
void _setDefaultSupertypes() {
for (var library in builders.values) {
library.setDefaultSupertypes();
}
}
void _writeLibraries() {
var bundleWriter = BundleWriter(
elementFactory.dynamicRef,
);
for (var builder in builders.values) {
bundleWriter.writeLibraryElement(builder.element);
}
var writeWriterResult = bundleWriter.finish();
resolutionBytes = writeWriterResult.resolutionBytes;
}
}
class LinkResult {
final Uint8List resolutionBytes;
LinkResult({
required this.resolutionBytes,
});
}