Version 2.18.0-216.0.dev
Merge commit '3c6720ac68cb824b1cf5da0252ac292cff69bad4' into 'dev'
diff --git a/DEPS b/DEPS
index 84c331d..e0f095f 100644
--- a/DEPS
+++ b/DEPS
@@ -66,8 +66,8 @@
# The list of revisions for these tools comes from Fuchsia, here:
# https://fuchsia.googlesource.com/integration/+/HEAD/toolchain
# If there are problems with the toolchain, contact fuchsia-toolchain@.
- "clang_revision": "aaaf8e4c409f080f35ea227b20dc6ac8a45c2fa4",
- "gn_revision": "e62d4e1938a45babc9afb6db543f388cd1802a52",
+ "clang_revision": "c2592c374e469f343ecea82d6728609650924259",
+ "gn_revision": "d7c2209cebcfe37f46dba7be4e1a7000ffc342fb",
# Scripts that make 'git cl format' work.
"clang_format_scripts_rev": "bb994c6f067340c1135eb43eed84f4b33cfa7397",
@@ -166,7 +166,7 @@
"webkit_inspection_protocol_rev": "57522d6b29d94903b765c757079d906555d5a171",
"yaml_edit_rev": "01589b3ce447b03aed991db49f1ec6445ad5476d",
"yaml_rev": "fda5b15692ccfa0feb7793a27fe3829b3d0f77fa",
- "zlib_rev": "64bbf988543996eb8df9a86877b32917187eba8f",
+ "zlib_rev": "27c2f474b71d0d20764f86f60ef8b00da1a16cda",
# Windows deps
"crashpad_rev": "bf327d8ceb6a669607b0dbab5a83a275d03f99ed",
diff --git a/pkg/analysis_server/lib/src/analysis_server_abstract.dart b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
index d199752..acfa949 100644
--- a/pkg/analysis_server/lib/src/analysis_server_abstract.dart
+++ b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
@@ -539,6 +539,9 @@
// every time the set of plugins changes, in which case we'll need to listen
// to the `PluginManager.pluginsChanged` stream.
analyticsManager.changedPlugins(pluginManager);
+ // For now we record context-dependent information only on shutdown. We
+ // might want to record it on start-up as well.
+ analyticsManager.createdAnalysisContexts(contextManager.analysisContexts);
pubPackageService.shutdown();
analyticsManager.shutdown();
diff --git a/pkg/analysis_server/lib/src/analytics/analytics_manager.dart b/pkg/analysis_server/lib/src/analytics/analytics_manager.dart
index f02612d..8a7f5e2 100644
--- a/pkg/analysis_server/lib/src/analytics/analytics_manager.dart
+++ b/pkg/analysis_server/lib/src/analytics/analytics_manager.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/analytics/google_analytics_manager.dart';
import 'package:analysis_server/src/plugin/plugin_manager.dart';
+import 'package:analyzer/dart/analysis/analysis_context.dart';
import 'package:telemetry/telemetry.dart';
/// An interface for managing and reporting analytics.
@@ -28,6 +29,9 @@
void changedWorkspaceFolders(
{required List<String> added, required List<String> removed});
+ /// Record that the [contexts] have been created.
+ void createdAnalysisContexts(List<AnalysisContext> contexts);
+
/// Record that the given [notification] was received and has been handled.
void handledNotificationMessage(
{required NotificationMessage notification,
diff --git a/pkg/analysis_server/lib/src/analytics/google_analytics_manager.dart b/pkg/analysis_server/lib/src/analytics/google_analytics_manager.dart
index 2b5f502..d9f99f0 100644
--- a/pkg/analysis_server/lib/src/analytics/google_analytics_manager.dart
+++ b/pkg/analysis_server/lib/src/analytics/google_analytics_manager.dart
@@ -11,6 +11,7 @@
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
import 'package:analysis_server/src/plugin/plugin_manager.dart';
import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analyzer/dart/analysis/analysis_context.dart';
import 'package:telemetry/telemetry.dart';
/// An implementation of [AnalyticsManager] that's appropriate to use when
@@ -36,6 +37,10 @@
/// that have been handled.
final Map<String, _NotificationData> _completedNotifications = {};
+ /// A map from the name of a lint to the number of contexts in which the lint
+ /// was enabled.
+ final Map<String, int> _lintUsageCounts = {};
+
/// Initialize a newly created analytics manager to report to the [analytics]
/// service.
GoogleAnalyticsManager(this.analytics);
@@ -55,6 +60,22 @@
}
@override
+ void createdAnalysisContexts(List<AnalysisContext> contexts) {
+ for (var context in contexts) {
+ for (var rule in context.analysisOptions.lintRules) {
+ var name = rule.name;
+ _lintUsageCounts[name] = (_lintUsageCounts[name] ?? 0) + 1;
+ }
+ // TODO(brianwilkerson) Collect other context-dependent information, such
+ // as which codes have a different severity assigned to them:
+ // for (var processor in context.analysisOptions.errorProcessors) {
+ // processor.code;
+ // processor.severity;
+ // }
+ }
+ }
+
+ @override
void handledNotificationMessage(
{required NotificationMessage notification,
required DateTime startTime,
@@ -118,6 +139,7 @@
_sendServerResponseTimes();
_sendPluginResponseTimes();
_sendNotificationHandlingTimes();
+ _sendLintUsageCounts();
analytics.waitForLastPing(timeout: Duration(milliseconds: 200)).then((_) {
analytics.close();
@@ -204,6 +226,12 @@
requestData.responseTimes.addValue(responseTime);
}
+ void _sendLintUsageCounts() {
+ analytics.sendEvent('language_server', 'lintUsageCounts', parameters: {
+ 'usageCounts': _lintUsageCounts.toString(),
+ });
+ }
+
/// Send information about the notifications handled by the server.
void _sendNotificationHandlingTimes() {
for (var data in _completedNotifications.values) {
diff --git a/pkg/analysis_server/lib/src/analytics/noop_analytics_manager.dart b/pkg/analysis_server/lib/src/analytics/noop_analytics_manager.dart
index 3f6c283..169bb79 100644
--- a/pkg/analysis_server/lib/src/analytics/noop_analytics_manager.dart
+++ b/pkg/analysis_server/lib/src/analytics/noop_analytics_manager.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/analytics/analytics_manager.dart';
import 'package:analysis_server/src/plugin/plugin_manager.dart';
+import 'package:analyzer/dart/analysis/analysis_context.dart';
/// An implementation of [AnalyticsManager] that's appropriate to use when
/// analytics have not been enabled.
@@ -19,6 +20,9 @@
{required List<String> added, required List<String> removed}) {}
@override
+ void createdAnalysisContexts(List<AnalysisContext> contexts) {}
+
+ @override
void handledNotificationMessage(
{required NotificationMessage notification,
required DateTime startTime,
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 47748d6..f6beb54 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_parser.dart';
+import 'package:analyzer/dart/analysis/analysis_context.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/file_system/file_system.dart';
@@ -46,6 +47,9 @@
/// Class that maintains a mapping from included/excluded paths to a set of
/// folders that should correspond to analysis contexts.
abstract class ContextManager {
+ /// Return the analysis contexts that are currently defined.
+ List<AnalysisContext> get analysisContexts;
+
/// Get the callback interface used to create, destroy, and update contexts.
ContextManagerCallbacks get callbacks;
@@ -237,6 +241,10 @@
}
@override
+ List<AnalysisContext> get analysisContexts =>
+ _collection?.contexts.cast<AnalysisContext>() ?? const [];
+
+ @override
DriverBasedAnalysisContext? getContextFor(String path) {
try {
return _collection?.contextFor(path);
diff --git a/pkg/analysis_server/test/src/analytics/google_analytics_manager_test.dart b/pkg/analysis_server/test/src/analytics/google_analytics_manager_test.dart
index 3542489..32a5783 100644
--- a/pkg/analysis_server/test/src/analytics/google_analytics_manager_test.dart
+++ b/pkg/analysis_server/test/src/analytics/google_analytics_manager_test.dart
@@ -10,7 +10,9 @@
import 'package:analysis_server/src/analytics/percentile_calculator.dart';
import 'package:analysis_server/src/plugin/plugin_manager.dart';
import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/dart/analysis/context_root.dart' as analyzer;
+import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:telemetry/telemetry.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -22,10 +24,31 @@
}
@reflectiveTest
-class GoogleAnalyticsManagerTest {
+class GoogleAnalyticsManagerTest with ResourceProviderMixin {
final analytics = _MockAnalytics();
late final manager = GoogleAnalyticsManager(analytics);
+ String get testPackageRootPath => '/home/package';
+
+ void test_createAnalysisContexts_single() {
+ _createAnalysisOptionsFile(lints: [
+ 'avoid_dynamic_calls',
+ 'await_only_futures',
+ 'unawaited_futures'
+ ]);
+ var collection =
+ AnalysisContextCollection(includedPaths: [testPackageRootPath]);
+ _defaultStartup();
+ manager.createdAnalysisContexts(collection.contexts);
+ manager.shutdown();
+ analytics.assertEvents([
+ _ExpectedEvent.session(),
+ _ExpectedEvent.lintUsageCounts(parameters: {
+ 'usageCounts': '{}',
+ }),
+ ]);
+ }
+
void test_plugin_request() {
_defaultStartup();
PluginManager.pluginResponseTimes[_MockPluginInfo('a')] = {
@@ -39,6 +62,7 @@
'method': 'analysis.getNavigation',
'duration': _IsPercentiles(),
}),
+ _ExpectedEvent.lintUsageCounts(),
]);
PluginManager.pluginResponseTimes.clear();
}
@@ -60,6 +84,7 @@
'method': Method.workspace_didCreateFiles.toString(),
'duration': _IsPercentiles(),
}),
+ _ExpectedEvent.lintUsageCounts(),
]);
}
@@ -89,6 +114,7 @@
'removed':
'{"count":1,"percentiles":[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]}',
}),
+ _ExpectedEvent.lintUsageCounts(),
]);
}
@@ -112,6 +138,7 @@
ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS_EXCLUDED:
'{"count":1,"percentiles":[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]}',
}),
+ _ExpectedEvent.lintUsageCounts(),
]);
}
@@ -133,6 +160,7 @@
ANALYSIS_REQUEST_SET_PRIORITY_FILES_FILES:
'{"count":1,"percentiles":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]}',
}),
+ _ExpectedEvent.lintUsageCounts(),
]);
}
@@ -153,6 +181,7 @@
'duration': _IsPercentiles(),
EDIT_REQUEST_GET_REFACTORING_KIND: '{"RENAME":1}',
}),
+ _ExpectedEvent.lintUsageCounts(),
]);
}
@@ -172,6 +201,7 @@
'parameters':
'closingLabels,onlyAnalyzeProjectsWithOpenFiles,suggestFromUnimportedLibraries',
}),
+ _ExpectedEvent.lintUsageCounts(),
]);
}
@@ -197,6 +227,7 @@
'openWorkspacePaths':
'{"count":1,"percentiles":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]}',
}),
+ _ExpectedEvent.lintUsageCounts(),
]);
}
@@ -213,6 +244,7 @@
'method': SERVER_REQUEST_SHUTDOWN,
'duration': _IsPercentiles(),
}),
+ _ExpectedEvent.lintUsageCounts(),
]);
}
@@ -240,6 +272,7 @@
'sdkVersion': sdkVersion,
'duration': _IsStringEncodedPositiveInt(),
}),
+ _ExpectedEvent.lintUsageCounts(),
]);
}
@@ -256,6 +289,7 @@
_ExpectedEvent.session(parameters: {
'plugins': '{"recordCount":1,"rootCounts":{"a":$counts,"b":$counts}}'
}),
+ _ExpectedEvent.lintUsageCounts(),
]);
}
@@ -280,9 +314,47 @@
'sdkVersion': sdkVersion,
'duration': _IsStringEncodedPositiveInt(),
}),
+ _ExpectedEvent.lintUsageCounts(),
]);
}
+ /// Create an analysis options file based on the given arguments.
+ void _createAnalysisOptionsFile({
+ String? path,
+ List<String>? experiments,
+ bool? implicitCasts,
+ List<String>? lints,
+ }) {
+ path ??= '$testPackageRootPath/analysis_options.yaml';
+ var buffer = StringBuffer();
+
+ if (experiments != null || implicitCasts != null) {
+ buffer.writeln('analyzer:');
+ }
+
+ if (experiments != null) {
+ buffer.writeln(' enable-experiment:');
+ for (var experiment in experiments) {
+ buffer.writeln(' - $experiment');
+ }
+ }
+
+ if (implicitCasts != null) {
+ buffer.writeln(' strong-mode:');
+ buffer.writeln(' implicit-casts: $implicitCasts');
+ }
+
+ if (lints != null) {
+ buffer.writeln('linter:');
+ buffer.writeln(' rules:');
+ for (var lint in lints) {
+ buffer.writeln(' - $lint');
+ }
+ }
+
+ newFile(path, buffer.toString());
+ }
+
void _defaultStartup() {
manager.startUp(
time: DateTime.now(),
@@ -319,6 +391,9 @@
this.value, // ignore: unused_element
this.parameters});
+ _ExpectedEvent.lintUsageCounts({Map<String, Object>? parameters})
+ : this('language_server', 'lintUsageCounts', parameters: parameters);
+
_ExpectedEvent.notification({Map<String, Object>? parameters})
: this('language_server', 'notification', parameters: parameters);
diff --git a/pkg/analysis_server/test/src/cider/cider_service.dart b/pkg/analysis_server/test/src/cider/cider_service.dart
index cdfefa6..6ebf3aa 100644
--- a/pkg/analysis_server/test/src/cider/cider_service.dart
+++ b/pkg/analysis_server/test/src/cider/cider_service.dart
@@ -15,6 +15,8 @@
import 'package:linter/src/rules.dart';
class CiderServiceTest with ResourceProviderMixin {
+ final FileResolverTestData testData = FileResolverTestData();
+
final StringBuffer logBuffer = StringBuffer();
late PerformanceLog logger;
@@ -45,8 +47,8 @@
workspace: workspace,
byteStore: MemoryByteStore(),
isGenerated: (_) => false,
+ testData: testData,
);
- fileResolver.testView = FileResolverTestView();
}
void setUp() {
diff --git a/pkg/analysis_server/test/src/cider/fixes_test.dart b/pkg/analysis_server/test/src/cider/fixes_test.dart
index 66f85fa..8eac9aa2 100644
--- a/pkg/analysis_server/test/src/cider/fixes_test.dart
+++ b/pkg/analysis_server/test/src/cider/fixes_test.dart
@@ -48,7 +48,7 @@
''');
// The file was resolved only once, even though we have 2 errors.
- expect(fileResolver.testView!.resolvedLibraries, [convertPath(testPath)]);
+ expect(testData.resolvedLibraries, [convertPath(testPath)]);
}
Future<void> test_createMethod() async {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart
index f64c69e..fc9a76e 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart
@@ -1998,7 +1998,7 @@
toggleableActiveColor: Colors.black,
hoverColor: Colors.white,
primaryColor: Colors.white,
- sliderTheme: SliderThemeData(),
+ sliderTheme: SliderThemeData()
);
print(themeData);
}
@@ -2012,7 +2012,7 @@
focusColor: Colors.black,
hoverColor: Colors.white,
primaryColor: Colors.white,
- sliderTheme: SliderThemeData(), checkboxTheme: CheckboxThemeData(), radioTheme: RadioThemeData(),
+ sliderTheme: SliderThemeData(), checkboxTheme: CheckboxThemeData(), radioTheme: RadioThemeData()
);
print(themeData);
}
@@ -2183,7 +2183,7 @@
toggleableActiveColor: Colors.black,
hoverColor: Colors.white,
primaryColor: Colors.white,
- sliderTheme: SliderThemeData(),
+ sliderTheme: SliderThemeData()
);
print(themeData);
}
@@ -2197,7 +2197,7 @@
focusColor: Colors.black,
hoverColor: Colors.white,
primaryColor: Colors.white,
- sliderTheme: SliderThemeData(), checkboxTheme: CheckboxThemeData(), radioTheme: RadioThemeData(),
+ sliderTheme: SliderThemeData(), checkboxTheme: CheckboxThemeData(), radioTheme: RadioThemeData()
);
print(themeData);
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/context_builder.dart b/pkg/analyzer/lib/src/dart/analysis/context_builder.dart
index 2c0bac1..d796e2b 100644
--- a/pkg/analyzer/lib/src/dart/analysis/context_builder.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/context_builder.dart
@@ -15,7 +15,7 @@
import 'package:analyzer/src/dart/analysis/byte_store.dart'
show ByteStore, MemoryByteStore;
import 'package:analyzer/src/dart/analysis/driver.dart'
- show AnalysisDriver, AnalysisDriverScheduler;
+ show AnalysisDriver, AnalysisDriverScheduler, AnalysisDriverTestView;
import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
import 'package:analyzer/src/dart/analysis/file_content_cache.dart';
import 'package:analyzer/src/dart/analysis/performance_logger.dart'
@@ -145,6 +145,7 @@
macroKernelBuilder: macroKernelBuilder,
macroExecutor: macroExecutor,
declaredVariables: declaredVariables,
+ testView: retainDataForTesting ? AnalysisDriverTestView() : null,
);
// AnalysisDriver reports results into streams.
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index f80867d..5f5d2d2 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -48,7 +48,6 @@
import 'package:analyzer/src/summary2/package_bundle_format.dart';
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
import 'package:analyzer/src/util/performance/operation_performance.dart';
-import 'package:meta/meta.dart';
/// This class computes [AnalysisResult]s for Dart files.
///
@@ -217,7 +216,7 @@
/// The instance of the [Search] helper.
late final Search _search;
- late final AnalysisDriverTestView _testView;
+ final AnalysisDriverTestView? testView;
late FeatureSetProvider featureSetProvider;
@@ -264,6 +263,7 @@
SummaryDataStore? externalSummaries,
DeclaredVariables? declaredVariables,
bool retainDataForTesting = false,
+ this.testView,
}) : _scheduler = scheduler,
_resourceProvider = resourceProvider,
_byteStore = byteStore,
@@ -277,8 +277,8 @@
declaredVariables = declaredVariables ?? DeclaredVariables(),
testingData = retainDataForTesting ? TestingData() : null {
analysisContext?.driver = this;
+ testView?.driver = this;
_onResults = _resultController.stream.asBroadcastStream();
- _testView = AnalysisDriverTestView(this);
_fileContentStrategy = StoredFileContentStrategy(_fileContentCache);
@@ -322,7 +322,7 @@
/// Return the context in which libraries should be analyzed.
LibraryContext get libraryContext {
return _libraryContext ??= LibraryContext(
- testView: _testView.libraryContextTestView,
+ testData: testView?.libraryContext,
analysisSession: AnalysisSessionImpl(this),
logger: _logger,
byteStore: _byteStore,
@@ -395,9 +395,6 @@
/// from file paths.
SourceFactory get sourceFactory => _sourceFactory;
- @visibleForTesting
- AnalysisDriverTestView get test => _testView;
-
@override
AnalysisDriverPriority get workPriority {
if (_resolveForCompletionRequests.isNotEmpty) {
@@ -567,7 +564,6 @@
/// library that was resynthesized, but after some initial analysis we might
/// not get again to many of these libraries. So, we should clear the context
/// periodically.
- @visibleForTesting
void clearLibraryContext() {
_libraryContext?.dispose();
_libraryContext = null;
@@ -1244,6 +1240,9 @@
break;
case _FileChangeKind.remove:
_fileTracker.removeFile(path);
+ // TODO(scheglov) We have to do this because we discard files.
+ // But this is not right, we need to handle removing better.
+ clearLibraryContext();
break;
}
}
@@ -1313,7 +1312,7 @@
return _logger.runAsync('Compute analysis result for $path', () async {
_logger.writeln('Work in $name');
try {
- _testView.numOfAnalyzedLibraries++;
+ testView?.numOfAnalyzedLibraries++;
if (!_hasLibraryByUri('dart:core')) {
return _newMissingDartLibraryResult(file, 'dart:core');
@@ -1323,7 +1322,10 @@
return _newMissingDartLibraryResult(file, 'dart:async');
}
- await libraryContext.load(library);
+ await libraryContext.load(
+ targetLibrary: library,
+ performance: OperationPerformanceImpl('<root>'),
+ );
var results = LibraryAnalyzer(
analysisOptions as AnalysisOptionsImpl,
@@ -1386,8 +1388,11 @@
) async {
final path = library.file.path;
return _logger.runAsync('Compute resolved library $path', () async {
- _testView.numOfAnalyzedLibraries++;
- await libraryContext.load(library);
+ testView?.numOfAnalyzedLibraries++;
+ await libraryContext.load(
+ targetLibrary: library,
+ performance: OperationPerformanceImpl('<root>'),
+ );
var unitResults = LibraryAnalyzer(
analysisOptions as AnalysisOptionsImpl,
@@ -1434,7 +1439,10 @@
return _logger.runAsync('Compute unit element for $path', () async {
_logger.writeln('Work in $name');
- await libraryContext.load(library);
+ await libraryContext.load(
+ targetLibrary: library,
+ performance: OperationPerformanceImpl('<root>'),
+ );
var element = libraryContext.computeUnitElement(library, file);
return UnitElementResultImpl(
currentSession,
@@ -1479,6 +1487,7 @@
fileContentStrategy: _fileContentStrategy,
prefetchFiles: null,
isGenerated: (_) => false,
+ testData: testView?.fileSystem,
);
_fileTracker = FileTracker(_logger, _fsState, _fileContentStrategy);
}
@@ -1667,15 +1676,14 @@
var affected = <FileState>{};
_fsState.collectAffected(path, affected);
+ final removedKeys = <String>{};
+ _libraryContext?.remove(affected.toList(), removedKeys);
+
for (var file in affected) {
file.invalidateLibraryCycle();
accumulatedAffected.add(file.path);
}
- _libraryContext?.elementFactory.removeLibraries(
- affected.map((e) => e.uri).toSet(),
- );
-
_libraryContext?.elementFactory.replaceAnalysisSession(
AnalysisSessionImpl(this),
);
@@ -1739,7 +1747,10 @@
final kind = file.kind;
final library = kind.library ?? kind.asLibrary;
- await libraryContext.load(library);
+ await libraryContext.load(
+ targetLibrary: library,
+ performance: OperationPerformanceImpl('<root>'),
+ );
var unitElement = libraryContext.computeUnitElement(library, file);
var analysisResult = LibraryAnalyzer(
@@ -2097,16 +2108,14 @@
}
}
-@visibleForTesting
class AnalysisDriverTestView {
- final AnalysisDriver driver;
- final LibraryContextTestView libraryContextTestView =
- LibraryContextTestView();
+ final fileSystem = FileSystemTestData();
+ final libraryContext = LibraryContextTestData();
+
+ late final AnalysisDriver driver;
int numOfAnalyzedLibraries = 0;
- AnalysisDriverTestView(this.driver);
-
FileTracker get fileTracker => driver._fileTracker;
Set<String> get loadedLibraryUriSet {
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index 8ce8e30..34b9105 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -1144,7 +1144,7 @@
late final FileSystemStateTestView _testView;
- FileSystemTestData? testData;
+ final FileSystemTestData? testData;
FileSystemState(
this._logger,
@@ -1162,6 +1162,7 @@
required this.fileContentStrategy,
required this.prefetchFiles,
required this.isGenerated,
+ required this.testData,
}) {
_testView = FileSystemStateTestView(this);
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_context.dart b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
index 9f4aeb5..8a81e56 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_context.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
@@ -2,6 +2,7 @@
// 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:collection';
import 'dart:typed_data';
import 'package:_fe_analyzer_shared/src/macros/executor/multi_executor.dart'
@@ -9,6 +10,7 @@
import 'package:analyzer/dart/analysis/declared_variables.dart';
import 'package:analyzer/dart/element/element.dart'
show CompilationUnitElement, LibraryElement;
+import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
@@ -28,6 +30,8 @@
import 'package:analyzer/src/summary2/macro.dart';
import 'package:analyzer/src/summary2/reference.dart';
import 'package:analyzer/src/util/performance/operation_performance.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
+import 'package:collection/collection.dart';
import 'package:path/src/context.dart';
/// Context information necessary to analyze one or more libraries within an
@@ -35,7 +39,7 @@
///
/// Currently this is implemented as a wrapper around [AnalysisContext].
class LibraryContext {
- final LibraryContextTestView testView;
+ final LibraryContextTestData? testData;
final PerformanceLog logger;
final ByteStore byteStore;
final FileSystemState fileSystemState;
@@ -46,8 +50,10 @@
late final AnalysisContextImpl analysisContext;
late LinkedElementFactory elementFactory;
+ Set<LibraryCycle> loadedBundles = Set.identity();
+
LibraryContext({
- required this.testView,
+ required this.testData,
required AnalysisSessionImpl analysisSession,
required this.logger,
required this.byteStore,
@@ -96,8 +102,13 @@
return element as CompilationUnitElementImpl;
}
- void dispose() {
+ /// Notifies this object that it is about to be discarded.
+ ///
+ /// Returns the keys of the artifacts that are no longer used.
+ Set<String> dispose() {
+ final keys = unloadAll();
elementFactory.dispose();
+ return keys;
}
/// Get the [LibraryElement] for the given library.
@@ -107,7 +118,10 @@
}
/// Load data required to access elements of the given [targetLibrary].
- Future<void> load(LibraryFileStateKind targetLibrary) async {
+ Future<void> load({
+ required LibraryFileStateKind targetLibrary,
+ required OperationPerformanceImpl performance,
+ }) async {
var librariesTotal = 0;
var librariesLoaded = 0;
var librariesLinked = 0;
@@ -117,10 +131,10 @@
var bytesPut = 0;
Future<void> loadBundle(LibraryCycle cycle) async {
- if (cycle.libraries.isEmpty ||
- elementFactory.hasLibrary(cycle.libraries.first.uri)) {
- return;
- }
+ if (!loadedBundles.add(cycle)) return;
+
+ performance.getDataInt('cycleCount').increment();
+ performance.getDataInt('libraryCount').add(cycle.libraries.length);
librariesTotal += cycle.libraries.length;
@@ -160,7 +174,7 @@
if (resolutionBytes == null) {
librariesLinkedTimer.start();
- testView.linkedCycles.add(
+ testData?.linkedCycles.add(
cycle.libraries.map((e) => e.path).toSet(),
);
@@ -175,6 +189,9 @@
var isSynthetic = !file.exists;
var unit = file.parse();
+ performance.getDataInt('parseCount').increment();
+ performance.getDataInt('parseLength').add(unit.length);
+
String? partUriStr;
if (partIndex >= 0) {
partUriStr = libraryFile.unlinked2.parts[partIndex];
@@ -218,10 +235,15 @@
resolutionBytes = linkResult.resolutionBytes;
byteStore.putGet(resolutionKey, resolutionBytes);
+ performance.getDataInt('bytesPut').add(resolutionBytes.length);
+ testData?.forCycle(cycle).putKeys.add(resolutionKey);
bytesPut += resolutionBytes.length;
librariesLinkedTimer.stop();
} else {
+ testData?.forCycle(cycle).getKeys.add(resolutionKey);
+ performance.getDataInt('bytesGet').add(resolutionBytes.length);
+ performance.getDataInt('libraryLoadCount').add(cycle.libraries.length);
// TODO(scheglov) Take / clear parsed units in files.
bytesGet += resolutionBytes.length;
librariesLoaded += cycle.libraries.length;
@@ -233,6 +255,8 @@
),
);
}
+ // TODO(scheglov) We probably should set this key when create the cycle
+ cycle.resolutionKey = resolutionKey;
final macroKernelBuilder = this.macroKernelBuilder;
if (macroKernelBuilder != null && macroLibraries.isNotEmpty) {
@@ -284,6 +308,42 @@
_createElementFactoryTypeProvider();
}
+ /// Remove libraries represented by the [removed] files.
+ /// If we need these libraries later, we will relink and reattach them.
+ void remove(List<FileState> removed, Set<String> removedKeys) {
+ elementFactory.removeLibraries(
+ removed.map((e) => e.uri).toSet(),
+ );
+
+ final removedSet = removed.toSet();
+
+ loadedBundles.removeWhere((cycle) {
+ if (cycle.libraries.any(removedSet.contains)) {
+ removedKeys.addIfNotNull(cycle.resolutionKey);
+ return true;
+ }
+ return false;
+ });
+ }
+
+ /// Unloads all loaded bundles.
+ ///
+ /// Returns the keys of the artifacts that are no longer used.
+ Set<String> unloadAll() {
+ final keySet = <String>{};
+ final uriSet = <Uri>{};
+
+ for (final cycle in loadedBundles) {
+ keySet.addIfNotNull(cycle.resolutionKey);
+ uriSet.addAll(cycle.libraries.map((e) => e.uri));
+ }
+
+ elementFactory.removeLibraries(uriSet);
+ loadedBundles.clear();
+
+ return keySet;
+ }
+
/// Ensure that type provider is created.
void _createElementFactoryTypeProvider() {
if (!analysisContext.hasTypeProvider) {
@@ -312,8 +372,27 @@
}
}
-class LibraryContextTestView {
+class LibraryContextTestData {
+ /// TODO(scheglov) Use [libraryCycles] and textual dumps for the driver too.
final List<Set<String>> linkedCycles = [];
+
+ /// Keys: the sorted list of library files.
+ final Map<List<File>, LibraryCycleTestData> libraryCycles = LinkedHashMap(
+ hashCode: Object.hashAll,
+ equals: const ListEquality<File>().equals,
+ );
+
+ LibraryCycleTestData forCycle(LibraryCycle cycle) {
+ final files = cycle.libraries.map((e) => e.resource).toList();
+ files.sortBy((file) => file.path);
+
+ return libraryCycles[files] ??= LibraryCycleTestData();
+ }
+}
+
+class LibraryCycleTestData {
+ final List<String> getKeys = [];
+ final List<String> putKeys = [];
}
class _MacroFileEntry implements MacroFileEntry {
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_graph.dart b/pkg/analyzer/lib/src/dart/analysis/library_graph.dart
index 89f3f5f..1fbd07c 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_graph.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_graph.dart
@@ -19,6 +19,9 @@
/// Information about libraries that reference each other, so form a cycle.
class LibraryCycle {
+ static int _nextId = 0;
+ final int id = _nextId++;
+
/// The libraries that belong to this cycle.
final List<FileState> libraries;
@@ -118,7 +121,7 @@
@override
String toString() {
- return '[${libraries.join(', ')}]';
+ return '[$id][${libraries.join(', ')}]';
}
}
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 765ffc5..a2bca9a 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -3649,7 +3649,7 @@
class LibraryAugmentationElementImpl extends LibraryOrAugmentationElementImpl
implements LibraryAugmentationElement {
@override
- final LibraryOrAugmentationElement augmented;
+ final LibraryOrAugmentationElementImpl augmented;
LibraryAugmentationElementImpl({
required this.augmented,
@@ -3677,7 +3677,7 @@
Scope get scope => throw UnimplementedError();
@override
- AnalysisSession get session => augmented.session;
+ AnalysisSessionImpl get session => augmented.session;
@override
TypeProvider get typeProvider => augmented.typeProvider;
@@ -4231,6 +4231,9 @@
_prefixes ??= buildPrefixesFromImports(imports);
@override
+ AnalysisSessionImpl get session;
+
+ @override
Source get source {
return _definingCompilationUnit.source;
}
@@ -5098,8 +5101,8 @@
super.enclosingElement as LibraryElement;
@override
- LibraryOrAugmentationElement get enclosingElement2 =>
- super.enclosingElement as LibraryOrAugmentationElement;
+ LibraryOrAugmentationElementImpl get enclosingElement2 =>
+ super.enclosingElement as LibraryOrAugmentationElementImpl;
@override
List<ImportElement> get imports {
diff --git a/pkg/analyzer/lib/src/dart/element/scope.dart b/pkg/analyzer/lib/src/dart/element/scope.dart
index 259ad2c..f57b6e0 100644
--- a/pkg/analyzer/lib/src/dart/element/scope.dart
+++ b/pkg/analyzer/lib/src/dart/element/scope.dart
@@ -108,10 +108,10 @@
}
class LibraryScope extends EnclosedScope {
- final LibraryElement _element;
+ final LibraryElementImpl _element;
final List<ExtensionElement> extensions = [];
- LibraryScope(LibraryElement element)
+ LibraryScope(LibraryElementImpl element)
: _element = element,
super(_LibraryImportScope(element)) {
extensions.addAll((_parent as _LibraryImportScope).extensions);
@@ -147,19 +147,18 @@
}
class PrefixScope implements Scope {
- final LibraryOrAugmentationElement _library;
+ final LibraryOrAugmentationElementImpl _library;
final Map<String, ImportedElement> _getters = {};
final Map<String, ImportedElement> _setters = {};
final Set<ExtensionElement> _extensions = {};
LibraryElement? _deferredLibrary;
PrefixScope(this._library, PrefixElement? prefix) {
- for (var import in _library.imports) {
+ final elementFactory = _library.session.elementFactory;
+ for (final import in _library.imports) {
if (import.prefix == prefix) {
final importedLibrary = import.importedLibrary;
if (importedLibrary is LibraryElementImpl) {
- // TODO(scheglov) Ask it from `_library`.
- final elementFactory = importedLibrary.session.elementFactory;
final combinators = import.combinators.build();
for (final exportedReference in importedLibrary.exportedReferences) {
final reference = exportedReference.reference;
@@ -330,11 +329,11 @@
}
class _LibraryImportScope implements Scope {
- final LibraryElement _library;
+ final LibraryElementImpl _library;
final PrefixScope _nullPrefixScope;
List<ExtensionElement>? _extensions;
- _LibraryImportScope(LibraryElement library)
+ _LibraryImportScope(LibraryElementImpl library)
: _library = library,
_nullPrefixScope = PrefixScope(library, null);
diff --git a/pkg/analyzer/lib/src/dart/micro/analysis_context.dart b/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
index 7f33467..887f483 100644
--- a/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
+++ b/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
@@ -10,7 +10,6 @@
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/uri_converter.dart';
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/dart/analysis/context_root.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/dart/analysis/results.dart';
@@ -20,7 +19,6 @@
import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/summary2/linked_element_factory.dart';
-import 'package:analyzer/src/summary2/reference.dart';
MicroContextObjects createMicroContextObjects({
required FileResolver fileResolver,
@@ -31,12 +29,6 @@
}) {
var declaredVariables = DeclaredVariables();
- var analysisContext = AnalysisContextImpl(
- analysisOptions: analysisOptions,
- declaredVariables: declaredVariables,
- sourceFactory: sourceFactory,
- );
-
var analysisSession = _MicroAnalysisSessionImpl(
fileResolver,
declaredVariables,
@@ -55,34 +47,24 @@
analysisContext2.currentSession = analysisSession;
analysisSession.analysisContext = analysisContext2;
- analysisSession.elementFactory = LinkedElementFactory(
- analysisContext,
- analysisSession,
- Reference.root(),
- );
-
return MicroContextObjects._(
declaredVariables: declaredVariables,
+ analysisOptions: analysisOptions,
analysisSession: analysisSession,
- analysisContext: analysisContext,
);
}
class MicroContextObjects {
final DeclaredVariables declaredVariables;
+ final AnalysisOptionsImpl analysisOptions;
final _MicroAnalysisSessionImpl analysisSession;
- final AnalysisContextImpl analysisContext;
MicroContextObjects._({
required this.declaredVariables,
+ required this.analysisOptions,
required this.analysisSession,
- required this.analysisContext,
});
- set analysisOptions(AnalysisOptionsImpl analysisOptions) {
- analysisContext.analysisOptions = analysisOptions;
- }
-
InheritanceManager3 get inheritanceManager {
return analysisSession.inheritanceManager;
}
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index b42bdf8..cb41ad2 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -2,14 +2,12 @@
// 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:collection';
import 'dart:typed_data';
import 'package:analyzer/dart/analysis/declared_variables.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/error/error.dart';
-import 'package:analyzer/error/listener.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/src/analysis_options/analysis_options_provider.dart';
@@ -21,7 +19,7 @@
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/dart/analysis/feature_set_provider.dart';
import 'package:analyzer/src/dart/analysis/file_state.dart';
-import 'package:analyzer/src/dart/analysis/library_graph.dart';
+import 'package:analyzer/src/dart/analysis/library_context.dart';
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
import 'package:analyzer/src/dart/analysis/results.dart';
import 'package:analyzer/src/dart/analysis/search.dart';
@@ -33,12 +31,9 @@
import 'package:analyzer/src/summary/api_signature.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
-import 'package:analyzer/src/summary2/bundle_reader.dart';
-import 'package:analyzer/src/summary2/link.dart';
-import 'package:analyzer/src/summary2/linked_element_factory.dart';
+import 'package:analyzer/src/summary/package_bundle_reader.dart';
import 'package:analyzer/src/task/options.dart';
import 'package:analyzer/src/util/performance/operation_performance.dart';
-import 'package:analyzer/src/utilities/extensions/collection.dart';
import 'package:analyzer/src/utilities/extensions/file_system.dart';
import 'package:analyzer/src/workspace/workspace.dart';
import 'package:collection/collection.dart';
@@ -177,7 +172,7 @@
final Workspace workspace;
/// This field gets value only during testing.
- FileResolverTestView? testView;
+ final FileResolverTestData? testData;
FileSystemState? fsState;
@@ -211,6 +206,7 @@
required this.workspace,
required this.isGenerated,
required this.byteStore,
+ this.testData,
});
/// Update the resolver to reflect the fact that the files with the given
@@ -421,7 +417,7 @@
await performance.runAsync('libraryContext', (performance) async {
await libraryContext!.load(
- targetLibrary: file,
+ targetLibrary: kind,
performance: performance,
);
});
@@ -474,11 +470,11 @@
performance: performance,
);
var file = fileContext.file;
- var libraryFile = file.kind.library!.file;
+ final libraryKind = file.kind.library ?? file.kind.asLibrary;
// Load the library, link if necessary.
await libraryContext!.load(
- targetLibrary: libraryFile,
+ targetLibrary: libraryKind,
performance: performance,
);
@@ -488,7 +484,7 @@
// Load the library again, the reference count is `>= 2`.
await libraryContext!.load(
- targetLibrary: libraryFile,
+ targetLibrary: libraryKind,
performance: performance,
);
@@ -602,12 +598,12 @@
await performance.runAsync('libraryContext', (performance) async {
await libraryContext!.load(
- targetLibrary: libraryFile,
+ targetLibrary: libraryKind,
performance: performance,
);
});
- testView?.addResolvedLibrary(path);
+ testData?.addResolvedLibrary(path);
late Map<FileState, UnitAnalysisResult> results;
@@ -617,7 +613,7 @@
contextObjects!.declaredVariables,
sourceFactory,
(_) => true, // _isLibraryUri
- contextObjects!.analysisContext,
+ libraryContext!.analysisContext,
libraryContext!.elementFactory,
contextObjects!.inheritanceManager,
libraryFile,
@@ -674,7 +670,7 @@
/// for another.
void _createContext(String path, AnalysisOptionsImpl fileAnalysisOptions) {
if (contextObjects != null) {
- contextObjects!.analysisOptions = fileAnalysisOptions;
+ libraryContext!.analysisContext.analysisOptions = fileAnalysisOptions;
return;
}
@@ -710,7 +706,8 @@
),
prefetchFiles: prefetchFiles,
isGenerated: isGenerated,
- )..testData = testView?.fileSystemTestData;
+ testData: testData?.fileSystem,
+ );
}
if (contextObjects == null) {
@@ -727,12 +724,21 @@
);
libraryContext = LibraryContext(
- testView,
- logger,
- resourceProvider,
- byteStore,
- contextObjects!,
+ declaredVariables: contextObjects!.declaredVariables,
+ byteStore: byteStore,
+ analysisOptions: contextObjects!.analysisOptions,
+ analysisSession: contextObjects!.analysisSession,
+ logger: logger,
+ fileSystemState: fsState!,
+ sourceFactory: sourceFactory,
+ externalSummaries: SummaryDataStore(),
+ macroExecutor: null,
+ macroKernelBuilder: null,
+ testData: testData?.libraryContext,
);
+
+ contextObjects!.analysisSession.elementFactory =
+ libraryContext!.elementFactory;
}
}
@@ -842,14 +848,9 @@
}
}
-class FileResolverTestView {
- final FileSystemTestData fileSystemTestData = FileSystemTestData();
-
- /// Keys: the sorted list of library files.
- final Map<List<File>, LibraryCycleTestData> libraryCycles = LinkedHashMap(
- hashCode: Object.hashAll,
- equals: const ListEquality<File>().equals,
- );
+class FileResolverTestData {
+ final fileSystem = FileSystemTestData();
+ final libraryContext = LibraryContextTestData();
/// The paths of libraries which were resolved.
///
@@ -859,220 +860,6 @@
void addResolvedLibrary(String path) {
resolvedLibraries.add(path);
}
-
- LibraryCycleTestData forCycle(LibraryCycle cycle) {
- final files = cycle.libraries.map((e) => e.resource).toList();
- files.sortBy((file) => file.path);
-
- return libraryCycles[files] ??= LibraryCycleTestData();
- }
-}
-
-class LibraryContext {
- final FileResolverTestView? testData;
- final PerformanceLog logger;
- final ResourceProvider resourceProvider;
- final ByteStore byteStore;
- final MicroContextObjects contextObjects;
-
- Set<LibraryCycle> loadedBundles = Set.identity();
-
- LibraryContext(
- this.testData,
- this.logger,
- this.resourceProvider,
- this.byteStore,
- this.contextObjects,
- );
-
- LinkedElementFactory get elementFactory {
- return contextObjects.analysisSession.elementFactory;
- }
-
- /// Notifies this object that it is about to be discarded.
- ///
- /// Returns the keys of the artifacts that are no longer used.
- Set<String> dispose() {
- return unloadAll();
- }
-
- /// Load data required to access elements of the given [targetLibrary].
- Future<void> load({
- required FileState targetLibrary,
- required OperationPerformanceImpl performance,
- }) async {
- var librariesLinked = 0;
- var librariesLinkedTimer = Stopwatch();
- var inputsTimer = Stopwatch();
-
- Future<void> loadBundle(LibraryCycle cycle) async {
- if (!loadedBundles.add(cycle)) return;
-
- performance.getDataInt('cycleCount').increment();
- performance.getDataInt('libraryCount').add(cycle.libraries.length);
-
- for (var directDependency in cycle.directDependencies) {
- await loadBundle(directDependency);
- }
-
- var resolutionKey = '${cycle.apiSignature}.linked_bundle';
- var resolutionBytes = byteStore.get(resolutionKey);
-
- var unitsInformativeBytes = <Uri, Uint8List>{};
- for (var library in cycle.libraries) {
- for (var file in library.libraryFiles) {
- unitsInformativeBytes[file.uri] = file.unlinked2.informativeBytes;
- }
- }
-
- if (resolutionBytes == null) {
- librariesLinkedTimer.start();
-
- inputsTimer.start();
- var inputLibraries = <LinkInputLibrary>[];
- for (var libraryFile in cycle.libraries) {
- var librarySource = libraryFile.source;
-
- var inputUnits = <LinkInputUnit>[];
- var partIndex = -1;
- for (var file in libraryFile.libraryFiles) {
- var isSynthetic = !file.exists;
-
- var content = file.getContent();
- performance.getDataInt('parseCount').increment();
- performance.getDataInt('parseLength').add(content.length);
-
- var unit = file.parse2(
- AnalysisErrorListener.NULL_LISTENER,
- content,
- );
-
- String? partUriStr;
- if (partIndex >= 0) {
- partUriStr = libraryFile.unlinked2.parts[partIndex];
- }
- partIndex++;
-
- inputUnits.add(
- LinkInputUnit(
- // TODO(scheglov) bad, group part data
- partDirectiveIndex: partIndex - 1,
- partUriStr: partUriStr,
- source: file.source,
- isSynthetic: isSynthetic,
- unit: unit,
- ),
- );
- }
-
- inputLibraries.add(
- LinkInputLibrary(
- source: librarySource,
- units: inputUnits,
- ),
- );
- }
- inputsTimer.stop();
-
- var linkResult = await performance.runAsync(
- 'link',
- (performance) async {
- return await link2(
- elementFactory: elementFactory,
- performance: performance,
- inputLibraries: inputLibraries,
- );
- },
- );
-
- librariesLinked += cycle.libraries.length;
-
- resolutionBytes = linkResult.resolutionBytes;
- resolutionBytes = byteStore.putGet(resolutionKey, resolutionBytes);
- performance.getDataInt('bytesPut').add(resolutionBytes.length);
- testData?.forCycle(cycle).putKeys.add(resolutionKey);
-
- librariesLinkedTimer.stop();
- } else {
- testData?.forCycle(cycle).getKeys.add(resolutionKey);
- performance.getDataInt('bytesGet').add(resolutionBytes.length);
- performance.getDataInt('libraryLoadCount').add(cycle.libraries.length);
- elementFactory.addBundle(
- BundleReader(
- elementFactory: elementFactory,
- unitsInformativeBytes: unitsInformativeBytes,
- resolutionBytes: resolutionBytes,
- ),
- );
- }
- cycle.resolutionKey = resolutionKey;
-
- // We might have just linked dart:core, ensure the type provider.
- _createElementFactoryTypeProvider();
- }
-
- await logger.runAsync('Prepare linked bundles', () async {
- var libraryCycle = targetLibrary.libraryCycle;
- await loadBundle(libraryCycle);
- logger.writeln(
- '[inputsTimer: ${inputsTimer.elapsedMilliseconds} ms]'
- '[librariesLinked: $librariesLinked]'
- '[librariesLinkedTimer: ${librariesLinkedTimer.elapsedMilliseconds} ms]',
- );
- });
- }
-
- /// Remove libraries represented by the [removed] files.
- /// If we need these libraries later, we will relink and reattach them.
- void remove(List<FileState> removed, Set<String> removedKeys) {
- elementFactory.removeLibraries(
- removed.map((e) => e.uri).toSet(),
- );
-
- var removedSet = removed.toSet();
-
- loadedBundles.removeWhere((cycle) {
- if (cycle.libraries.any(removedSet.contains)) {
- removedKeys.addIfNotNull(cycle.resolutionKey);
- return true;
- }
- return false;
- });
- }
-
- /// Unloads all loaded bundles.
- ///
- /// Returns the keys of the artifacts that are no longer used.
- Set<String> unloadAll() {
- final keySet = <String>{};
- final uriSet = <Uri>{};
-
- for (var cycle in loadedBundles) {
- keySet.addIfNotNull(cycle.resolutionKey);
- uriSet.addAll(cycle.libraries.map((e) => e.uri));
- }
-
- elementFactory.removeLibraries(uriSet);
- loadedBundles.clear();
-
- return keySet;
- }
-
- /// Ensure that type provider is created.
- void _createElementFactoryTypeProvider() {
- var analysisContext = contextObjects.analysisContext;
- if (!analysisContext.hasTypeProvider) {
- elementFactory.createTypeProviders(
- elementFactory.dartCoreElement,
- elementFactory.dartAsyncElement,
- );
- }
- }
-}
-
-class LibraryCycleTestData {
- final List<String> getKeys = [];
- final List<String> putKeys = [];
}
class _ContentWithDigest {
diff --git a/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart b/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart
new file mode 100644
index 0000000..7f4b276
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart
@@ -0,0 +1,211 @@
+// Copyright (c) 2022, 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 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/dart/analysis/byte_store.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/dart/analysis/library_context.dart';
+import 'package:analyzer/src/dart/micro/resolve_file.dart';
+import 'package:collection/collection.dart';
+import 'package:path/path.dart';
+
+class AnalyzerStatePrinter {
+ final MemoryByteStore byteStore;
+ final KeyShorter keyShorter;
+ final LibraryContext libraryContext;
+ final ResourceProvider resourceProvider;
+ final StringSink sink;
+
+ String _indent = '';
+
+ AnalyzerStatePrinter({
+ required this.byteStore,
+ required this.keyShorter,
+ required this.libraryContext,
+ required this.resourceProvider,
+ required this.sink,
+ });
+
+ FileSystemState get fileSystemState => libraryContext.fileSystemState;
+
+ void writeAnalysisDriver(AnalysisDriverTestView testData) {
+ _writeFiles(testData.fileSystem);
+ _writeLibraryContext(testData.libraryContext);
+ _writeElementFactory();
+ _writeByteStore();
+ }
+
+ void writeFileResolver(FileResolverTestData testData) {
+ _writeFiles(testData.fileSystem);
+ _writeLibraryContext(testData.libraryContext);
+ _writeElementFactory();
+ _writeByteStore();
+ }
+
+ /// If the path style is `Windows`, returns the corresponding Posix path.
+ /// Otherwise the path is already a Posix path, and it is returned as is.
+ String _posixPath(File file) {
+ final pathContext = resourceProvider.pathContext;
+ if (pathContext.style == Style.windows) {
+ final components = pathContext.split(file.path);
+ return '/${components.skip(1).join('/')}';
+ } else {
+ return file.path;
+ }
+ }
+
+ void _withIndent(void Function() f) {
+ var indent = _indent;
+ _indent = '$_indent ';
+ f();
+ _indent = indent;
+ }
+
+ void _writeByteStore() {
+ _writelnWithIndent('byteStore');
+ _withIndent(() {
+ final groups = byteStore.map.entries.groupListsBy((element) {
+ return element.value.refCount;
+ });
+
+ for (final groupEntry in groups.entries) {
+ final keys = groupEntry.value.map((e) => e.key).toList();
+ final shortKeys = keyShorter.shortKeys(keys)..sort();
+ _writelnWithIndent('${groupEntry.key}: $shortKeys');
+ }
+ });
+ }
+
+ void _writeElementFactory() {
+ _writelnWithIndent('elementFactory');
+ _withIndent(() {
+ final elementFactory = libraryContext.elementFactory;
+ _writeUriList(
+ 'hasElement',
+ elementFactory.uriListWithLibraryElements,
+ );
+ _writeUriList(
+ 'hasReader',
+ elementFactory.uriListWithLibraryReaders,
+ );
+ });
+ }
+
+ void _writeFiles(FileSystemTestData testData) {
+ _writelnWithIndent('files');
+ _withIndent(() {
+ final fileMap = testData.files;
+ final fileDataList = fileMap.values.toList();
+ fileDataList.sortBy((fileData) => fileData.file.path);
+
+ for (final fileData in fileDataList) {
+ final file = fileData.file;
+ _writelnWithIndent(_posixPath(file));
+ _withIndent(() {
+ final current = fileSystemState.getExistingFileForResource(file);
+ if (current != null) {
+ _writelnWithIndent('current');
+ _withIndent(() {
+ final unlinkedShort = keyShorter.shortKey(current.unlinkedKey);
+ _writelnWithIndent('unlinkedKey: $unlinkedShort');
+ });
+ }
+
+ final shortGets = keyShorter.shortKeys(fileData.unlinkedKeyGet);
+ final shortPuts = keyShorter.shortKeys(fileData.unlinkedKeyPut);
+ _writelnWithIndent('unlinkedGet: $shortGets');
+ _writelnWithIndent('unlinkedPut: $shortPuts');
+ });
+ }
+ });
+ }
+
+ void _writeLibraryContext(LibraryContextTestData testData) {
+ _writelnWithIndent('libraryCycles');
+ _withIndent(() {
+ final entries = testData.libraryCycles.entries
+ .mapKey((key) => key.map(_posixPath).join(' '))
+ .toList();
+ entries.sortBy((e) => e.key);
+
+ final loadedBundlesMap = Map.fromEntries(
+ libraryContext.loadedBundles.map((cycle) {
+ final key = cycle.libraries
+ .map((fileState) => fileState.resource)
+ .map(_posixPath)
+ .join(' ');
+ return MapEntry(key, cycle);
+ }),
+ );
+
+ for (final entry in entries) {
+ _writelnWithIndent(entry.key);
+ _withIndent(() {
+ final current = loadedBundlesMap[entry.key];
+ if (current != null) {
+ _writelnWithIndent('current');
+ _withIndent(() {
+ final short = keyShorter.shortKey(current.resolutionKey!);
+ _writelnWithIndent('key: $short');
+ });
+ }
+
+ final shortGets = keyShorter.shortKeys(entry.value.getKeys);
+ final shortPuts = keyShorter.shortKeys(entry.value.putKeys);
+ _writelnWithIndent('get: $shortGets');
+ _writelnWithIndent('put: $shortPuts');
+ });
+ }
+ });
+ }
+
+ void _writelnWithIndent(String line) {
+ sink.write(_indent);
+ sink.writeln(line);
+ }
+
+ void _writeUriList(String name, Iterable<Uri> uriIterable) {
+ final uriStrList = uriIterable.map((uri) => '$uri').toList();
+ if (uriStrList.isNotEmpty) {
+ uriStrList.sort();
+ _writelnWithIndent(name);
+ _withIndent(() {
+ for (final uriStr in uriStrList) {
+ _writelnWithIndent(uriStr);
+ }
+ });
+ }
+ }
+}
+
+/// Keys in the byte store are long hashes, which are hard to read.
+/// So, we generate short unique versions for them.
+class KeyShorter {
+ final Map<String, String> _keyToShort = {};
+ final Map<String, String> _shortToKey = {};
+
+ String shortKey(String key) {
+ var short = _keyToShort[key];
+ if (short == null) {
+ short = 'k${_keyToShort.length.toString().padLeft(2, '0')}';
+ _keyToShort[key] = short;
+ _shortToKey[short] = key;
+ }
+ return short;
+ }
+
+ List<String> shortKeys(List<String> keys) {
+ return keys.map(shortKey).toList();
+ }
+}
+
+extension<K, V> on Iterable<MapEntry<K, V>> {
+ Iterable<MapEntry<K2, V>> mapKey<K2>(K2 Function(K key) convertKey) {
+ return map((e) {
+ final newKey = convertKey(e.key);
+ return MapEntry(newKey, e.value);
+ });
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/base.dart b/pkg/analyzer/test/src/dart/analysis/base.dart
index 65e6668..7498837 100644
--- a/pkg/analyzer/test/src/dart/analysis/base.dart
+++ b/pkg/analyzer/test/src/dart/analysis/base.dart
@@ -91,6 +91,7 @@
}),
enableIndex: true,
externalSummaries: externalSummaries,
+ testView: AnalysisDriverTestView(),
);
}
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
index 7bb0a4e..e73428f 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_caching_test.dart
@@ -25,11 +25,14 @@
@reflectiveTest
class AnalysisDriverCachingTest extends PubPackageResolutionTest {
+ @override
+ bool get retainDataForTesting => true;
+
String get testFilePathPlatform => convertPath(testFilePath);
List<Set<String>> get _linkedCycles {
var driver = driverFor(testFilePath);
- return driver.test.libraryContextTestView.linkedCycles;
+ return driver.testView!.libraryContext.linkedCycles;
}
@override
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index ca5fff1..adf42bb 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -748,7 +748,7 @@
driver.priorityFiles = [a];
ResolvedUnitResult result1 = await driver.getResultValid(a);
- expect(driver.test.priorityResults, containsPair(a, result1));
+ expect(driver.testView!.priorityResults, containsPair(a, result1));
await waitForIdleWithoutExceptions();
allResults.clear();
@@ -779,26 +779,26 @@
driver.priorityFiles = [a];
ResolvedUnitResult result1 = await driver.getResultValid(a);
- expect(driver.test.priorityResults, containsPair(a, result1));
+ expect(driver.testView!.priorityResults, containsPair(a, result1));
// Change a file.
// The cache is flushed.
driver.changeFile(a);
- expect(driver.test.priorityResults, isEmpty);
+ expect(driver.testView!.priorityResults, isEmpty);
ResolvedUnitResult result2 = await driver.getResultValid(a);
- expect(driver.test.priorityResults, containsPair(a, result2));
+ expect(driver.testView!.priorityResults, containsPair(a, result2));
// Add a file.
// The cache is flushed.
driver.addFile(b);
- expect(driver.test.priorityResults, isEmpty);
+ expect(driver.testView!.priorityResults, isEmpty);
ResolvedUnitResult result3 = await driver.getResultValid(a);
- expect(driver.test.priorityResults, containsPair(a, result3));
+ expect(driver.testView!.priorityResults, containsPair(a, result3));
// Remove a file.
// The cache is flushed.
driver.removeFile(b);
- expect(driver.test.priorityResults, isEmpty);
+ expect(driver.testView!.priorityResults, isEmpty);
}
test_cachedPriorityResults_flush_onPrioritySetChange() async {
@@ -810,26 +810,26 @@
driver.priorityFiles = [a];
ResolvedUnitResult result1 = await driver.getResultValid(a);
- expect(driver.test.priorityResults, hasLength(1));
- expect(driver.test.priorityResults, containsPair(a, result1));
+ expect(driver.testView!.priorityResults, hasLength(1));
+ expect(driver.testView!.priorityResults, containsPair(a, result1));
// Make "a" and "b" priority.
// We still have the result for "a" cached.
driver.priorityFiles = [a, b];
- expect(driver.test.priorityResults, hasLength(1));
- expect(driver.test.priorityResults, containsPair(a, result1));
+ expect(driver.testView!.priorityResults, hasLength(1));
+ expect(driver.testView!.priorityResults, containsPair(a, result1));
// Get the result for "b".
ResolvedUnitResult result2 = await driver.getResultValid(b);
- expect(driver.test.priorityResults, hasLength(2));
- expect(driver.test.priorityResults, containsPair(a, result1));
- expect(driver.test.priorityResults, containsPair(b, result2));
+ expect(driver.testView!.priorityResults, hasLength(2));
+ expect(driver.testView!.priorityResults, containsPair(a, result1));
+ expect(driver.testView!.priorityResults, containsPair(b, result2));
// Only "b" is priority.
// The result for "a" is flushed.
driver.priorityFiles = [b];
- expect(driver.test.priorityResults, hasLength(1));
- expect(driver.test.priorityResults, containsPair(b, result2));
+ expect(driver.testView!.priorityResults, hasLength(1));
+ expect(driver.testView!.priorityResults, containsPair(b, result2));
}
test_cachedPriorityResults_notPriority() async {
@@ -837,7 +837,7 @@
newFile(a, 'var a = 1;');
ResolvedUnitResult result1 = await driver.getResultValid(a);
- expect(driver.test.priorityResults, isEmpty);
+ expect(driver.testView!.priorityResults, isEmpty);
// The file is not priority, so its result is not cached.
ResolvedUnitResult result2 = await driver.getResultValid(a);
@@ -872,7 +872,7 @@
driver.changeFile(b);
// "b" is not an added file, so it is not scheduled for analysis.
- expect(driver.test.fileTracker.hasPendingFiles, isFalse);
+ expect(driver.testView!.fileTracker.hasPendingFiles, isFalse);
// While "b" is not analyzed explicitly, it is analyzed implicitly.
// The change causes "a" to be reanalyzed.
@@ -3585,7 +3585,7 @@
Iterable<String>? included,
Iterable<String>? excluded,
}) {
- var uriSet = this.test.loadedLibraryUriSet;
+ var uriSet = testView!.loadedLibraryUriSet;
if (included != null) {
expect(uriSet, containsAll(included));
}
diff --git a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
index 403a89e..3cf0ed1 100644
--- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -122,6 +122,9 @@
@reflectiveTest
class FileSystemState_PubPackageTest extends PubPackageResolutionTest {
+ @override
+ bool get retainDataForTesting => true;
+
FileState get _dartAsyncState {
return fileStateForUriStr('dart:async');
}
@@ -2245,6 +2248,7 @@
),
prefetchFiles: null,
isGenerated: (_) => false,
+ testData: null,
);
}
diff --git a/pkg/analyzer/test/src/dart/micro/file_resolution.dart b/pkg/analyzer/test/src/dart/micro/file_resolution.dart
index db6d5af..dd4736b 100644
--- a/pkg/analyzer/test/src/dart/micro/file_resolution.dart
+++ b/pkg/analyzer/test/src/dart/micro/file_resolution.dart
@@ -8,6 +8,7 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/dart/analysis/library_context.dart';
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
import 'package:analyzer/src/dart/micro/resolve_file.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart';
@@ -17,12 +18,11 @@
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer/src/util/performance/operation_performance.dart';
import 'package:analyzer/src/workspace/bazel.dart';
-import 'package:collection/collection.dart';
import 'package:crypto/crypto.dart';
import 'package:linter/src/rules.dart';
-import 'package:path/path.dart';
import 'package:test/test.dart';
+import '../analysis/analyzer_state_printer.dart' as printer;
import '../resolution/resolution.dart';
/// [FileResolver] based implementation of [ResolutionTest].
@@ -31,14 +31,14 @@
final MemoryByteStore byteStore = MemoryByteStore();
- final FileResolverTestView testData = FileResolverTestView();
+ final FileResolverTestData testData = FileResolverTestData();
final StringBuffer logBuffer = StringBuffer();
late PerformanceLog logger;
late FileResolver fileResolver;
- final _KeyShorter _keyShorter = _KeyShorter();
+ final printer.KeyShorter _keyShorter = printer.KeyShorter();
FileSystemState get fsState => fileResolver.fsState!;
@@ -66,8 +66,13 @@
void assertStateString(String expected) {
final buffer = StringBuffer();
- ResolverStatePrinter(resourceProvider, buffer, _keyShorter)
- .write(byteStore, fileResolver.fsState!, libraryContext, testData);
+ printer.AnalyzerStatePrinter(
+ byteStore: byteStore,
+ keyShorter: _keyShorter,
+ libraryContext: libraryContext,
+ resourceProvider: resourceProvider,
+ sink: buffer,
+ ).writeFileResolver(testData);
final actual = buffer.toString();
if (actual != expected) {
@@ -97,8 +102,8 @@
workspace: workspace,
prefetchFiles: null,
isGenerated: (_) => false,
+ testData: testData,
);
- fileResolver.testView = testData;
}
Future<ErrorsResult> getTestErrors() async {
@@ -154,176 +159,3 @@
}
}
}
-
-class ResolverStatePrinter {
- final ResourceProvider _resourceProvider;
-
- /// The target sink to print.
- final StringSink _sink;
-
- final _KeyShorter _keyShorter;
-
- String _indent = '';
-
- ResolverStatePrinter(this._resourceProvider, this._sink, this._keyShorter);
-
- void write(MemoryByteStore byteStore, FileSystemState fileSystemState,
- LibraryContext libraryContext, FileResolverTestView testData) {
- _writelnWithIndent('files');
- _withIndent(() {
- final fileMap = testData.fileSystemTestData.files;
- final fileDataList = fileMap.values.toList();
- fileDataList.sortBy((fileData) => fileData.file.path);
-
- for (final fileData in fileDataList) {
- final file = fileData.file;
- _writelnWithIndent(_posixPath(file));
- _withIndent(() {
- final current = fileSystemState.getExistingFileForResource(file);
- if (current != null) {
- _writelnWithIndent('current');
- _withIndent(() {
- final unlinkedShort = _keyShorter.shortKey(current.unlinkedKey);
- _writelnWithIndent('unlinkedKey: $unlinkedShort');
- });
- }
-
- final shortGets = _keyShorter.shortKeys(fileData.unlinkedKeyGet);
- final shortPuts = _keyShorter.shortKeys(fileData.unlinkedKeyPut);
- _writelnWithIndent('unlinkedGet: $shortGets');
- _writelnWithIndent('unlinkedPut: $shortPuts');
- });
- }
- });
-
- _writelnWithIndent('libraryCycles');
- _withIndent(() {
- final entries = testData.libraryCycles.entries
- .mapKey((key) => key.map(_posixPath).join(' '))
- .toList();
- entries.sortBy((e) => e.key);
-
- final loadedBundlesMap = Map.fromEntries(
- libraryContext.loadedBundles.map((cycle) {
- final key = cycle.libraries
- .map((fileState) => fileState.resource)
- .map(_posixPath)
- .join(' ');
- return MapEntry(key, cycle);
- }),
- );
-
- for (final entry in entries) {
- _writelnWithIndent(entry.key);
- _withIndent(() {
- final current = loadedBundlesMap[entry.key];
- if (current != null) {
- _writelnWithIndent('current');
- _withIndent(() {
- final short = _keyShorter.shortKey(current.resolutionKey!);
- _writelnWithIndent('key: $short');
- });
- }
-
- final shortGets = _keyShorter.shortKeys(entry.value.getKeys);
- final shortPuts = _keyShorter.shortKeys(entry.value.putKeys);
- _writelnWithIndent('get: $shortGets');
- _writelnWithIndent('put: $shortPuts');
- });
- }
- });
-
- _writelnWithIndent('elementFactory');
- _withIndent(() {
- final elementFactory = libraryContext.elementFactory;
- _writeUriList(
- 'hasElement',
- elementFactory.uriListWithLibraryElements,
- );
- _writeUriList(
- 'hasReader',
- elementFactory.uriListWithLibraryReaders,
- );
- });
-
- _writelnWithIndent('byteStore');
- _withIndent(() {
- final groups = byteStore.map.entries.groupListsBy((element) {
- return element.value.refCount;
- });
-
- for (final groupEntry in groups.entries) {
- final keys = groupEntry.value.map((e) => e.key).toList();
- final shortKeys = _keyShorter.shortKeys(keys)..sort();
- _writelnWithIndent('${groupEntry.key}: $shortKeys');
- }
- });
- }
-
- /// If the path style is `Windows`, returns the corresponding Posix path.
- /// Otherwise the path is already a Posix path, and it is returned as is.
- String _posixPath(File file) {
- final pathContext = _resourceProvider.pathContext;
- if (pathContext.style == Style.windows) {
- final components = pathContext.split(file.path);
- return '/${components.skip(1).join('/')}';
- } else {
- return file.path;
- }
- }
-
- void _withIndent(void Function() f) {
- var indent = _indent;
- _indent = '$_indent ';
- f();
- _indent = indent;
- }
-
- void _writelnWithIndent(String line) {
- _sink.write(_indent);
- _sink.writeln(line);
- }
-
- void _writeUriList(String name, Iterable<Uri> uriIterable) {
- final uriStrList = uriIterable.map((uri) => '$uri').toList();
- if (uriStrList.isNotEmpty) {
- uriStrList.sort();
- _writelnWithIndent(name);
- _withIndent(() {
- for (final uriStr in uriStrList) {
- _writelnWithIndent(uriStr);
- }
- });
- }
- }
-}
-
-/// Keys in the byte store are long hashes, which are hard to read.
-/// So, we generate short unique versions for them.
-class _KeyShorter {
- final Map<String, String> _keyToShort = {};
- final Map<String, String> _shortToKey = {};
-
- String shortKey(String key) {
- var short = _keyToShort[key];
- if (short == null) {
- short = 'k${_keyToShort.length.toString().padLeft(2, '0')}';
- _keyToShort[key] = short;
- _shortToKey[short] = key;
- }
- return short;
- }
-
- List<String> shortKeys(List<String> keys) {
- return keys.map(shortKey).toList();
- }
-}
-
-extension<K, V> on Iterable<MapEntry<K, V>> {
- Iterable<MapEntry<K2, V>> mapKey<K2>(K2 Function(K key) convertKey) {
- return map((e) {
- final newKey = convertKey(e.key);
- return MapEntry(newKey, e.value);
- });
- }
-}
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index be50344..3bf1dce 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -2716,7 +2716,7 @@
List<File> expected, {
bool andClear = true,
}) {
- final actual = fileResolver.testView!.resolvedLibraries;
+ final actual = fileResolver.testData!.resolvedLibraries;
expect(actual, expected.map((e) => e.path).toList());
if (andClear) {
actual.clear();
diff --git a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
index 6c41892..a8d81f3 100644
--- a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
@@ -30,6 +30,7 @@
import '../../../generated/test_support.dart';
import '../../summary/macros_environment.dart';
+import '../analysis/analyzer_state_printer.dart';
import 'context_collection_resolution_caching.dart';
import 'resolution.dart';
@@ -122,7 +123,7 @@
with ResourceProviderMixin, ResolutionTest {
static bool _lintRulesAreRegistered = false;
- ByteStore _byteStore = getContextResolutionTestByteStore();
+ MemoryByteStore _byteStore = getContextResolutionTestByteStore();
Map<String, String> _declaredVariables = {};
AnalysisContextCollectionImpl? _analysisContextCollection;
@@ -137,6 +138,8 @@
/// Optional summaries to provide for the collection.
List<File>? librarySummaryFiles;
+ final KeyShorter _keyShorter = KeyShorter();
+
List<MockSdkLibrary> get additionalMockSdkLibraries => [];
List<String> get collectionIncludedPaths;
@@ -163,6 +166,25 @@
expect(workspace, TypeMatcher<BazelWorkspace>());
}
+ void assertDriverStateString(File file, String expected) {
+ final analysisDriver = driverFor(file.path);
+
+ final buffer = StringBuffer();
+ AnalyzerStatePrinter(
+ byteStore: _byteStore,
+ keyShorter: _keyShorter,
+ libraryContext: analysisDriver.libraryContext,
+ resourceProvider: resourceProvider,
+ sink: buffer,
+ ).writeAnalysisDriver(analysisDriver.testView!);
+ final actual = buffer.toString();
+
+ if (actual != expected) {
+ print(actual);
+ }
+ expect(actual, expected);
+ }
+
void assertGnWorkspaceFor(String path) {
var workspace = contextFor(path).contextRoot.workspace;
expect(workspace, TypeMatcher<GnWorkspace>());
diff --git a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution_caching.dart b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution_caching.dart
index 9f2dc62..9bef306 100644
--- a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution_caching.dart
+++ b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution_caching.dart
@@ -7,7 +7,7 @@
final _sharedByteStore = MemoryByteStore();
final _useSharedByteStore = false;
-ByteStore getContextResolutionTestByteStore() {
+MemoryByteStore getContextResolutionTestByteStore() {
if (_useSharedByteStore) {
return _sharedByteStore;
} else {
diff --git a/pkg/analyzer_plugin/CHANGELOG.md b/pkg/analyzer_plugin/CHANGELOG.md
index d691820..99be7f5 100644
--- a/pkg/analyzer_plugin/CHANGELOG.md
+++ b/pkg/analyzer_plugin/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 0.11.0
+- Using `AnalysisContextCollection` and `AnalysisContext` for analysis.
+
## 0.10.0
- Support version `4.x` of the `analyzer` package
diff --git a/pkg/analyzer_plugin/lib/plugin/plugin.dart b/pkg/analyzer_plugin/lib/plugin/plugin.dart
index f56f362..fe76e56 100644
--- a/pkg/analyzer_plugin/lib/plugin/plugin.dart
+++ b/pkg/analyzer_plugin/lib/plugin/plugin.dart
@@ -2,23 +2,20 @@
// 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 'package:analyzer/dart/analysis/analysis_context.dart';
+import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/overlay_file_system.dart';
-import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
-import 'package:analyzer/src/dart/analysis/driver.dart'
- show AnalysisDriver, AnalysisDriverGeneric, AnalysisDriverScheduler;
-import 'package:analyzer/src/dart/analysis/file_byte_store.dart';
-import 'package:analyzer/src/dart/analysis/performance_logger.dart';
-import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/dart/analysis/file_content_cache.dart';
import 'package:analyzer_plugin/channel/channel.dart';
import 'package:analyzer_plugin/protocol/protocol.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_constants.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';
-import 'package:analyzer_plugin/src/utilities/null_string_sink.dart';
import 'package:analyzer_plugin/utilities/subscriptions/subscription_manager.dart';
import 'package:pub_semver/pub_semver.dart';
@@ -28,9 +25,6 @@
/// Clients may not implement or mix-in this class, but are expected to extend
/// it.
abstract class ServerPlugin {
- /// A megabyte.
- static const int M = 1024 * 1024;
-
/// The communication channel being used to communicate with the analysis
/// server.
late PluginCommunicationChannel _channel;
@@ -38,48 +32,31 @@
/// The resource provider used to access the file system.
final OverlayResourceProvider resourceProvider;
+ late final ByteStore _byteStore = createByteStore();
+
+ AnalysisContextCollectionImpl? _contextCollection;
+
/// The next modification stamp for a changed file in the [resourceProvider].
int _overlayModificationStamp = 0;
+ /// The path to the Dart SDK, set by the analysis server.
+ String? _sdkPath;
+
+ /// Paths of priority files.
+ Set<String> priorityPaths = {};
+
/// The object used to manage analysis subscriptions.
final SubscriptionManager subscriptionManager = SubscriptionManager();
- /// The scheduler used by any analysis drivers that are created.
- late AnalysisDriverScheduler analysisDriverScheduler;
-
- /// A table mapping the current context roots to the analysis driver created
- /// for that root.
- final Map<ContextRoot, AnalysisDriverGeneric> driverMap =
- <ContextRoot, AnalysisDriverGeneric>{};
-
- /// The performance log used by any analysis drivers that are created.
- final PerformanceLog performanceLog = PerformanceLog(NullStringSink());
-
- /// The byte store used by any analysis drivers that are created, or `null` if
- /// the cache location isn't known because the 'plugin.version' request has not
- /// yet been received.
- late ByteStore _byteStore;
-
- /// The SDK manager used to manage SDKs.
- late DartSdkManager _sdkManager;
-
- /// Initialize a newly created analysis server plugin. If a resource [provider]
+ /// Initialize a newly created analysis server plugin. If a resource [resourceProvider]
/// is given, then it will be used to access the file system. Otherwise a
/// resource provider that accesses the physical file system will be used.
- ServerPlugin(ResourceProvider? provider)
- : resourceProvider = OverlayResourceProvider(
- provider ?? PhysicalResourceProvider.INSTANCE) {
- analysisDriverScheduler = AnalysisDriverScheduler(performanceLog);
- analysisDriverScheduler.start();
- }
-
- /// Return the byte store used by any analysis drivers that are created, or
- /// `null` if the cache location isn't known because the 'plugin.version'
- /// request has not yet been received.
- ByteStore get byteStore => _byteStore;
+ ServerPlugin({
+ required ResourceProvider resourceProvider,
+ }) : resourceProvider = OverlayResourceProvider(resourceProvider);
/// Return the communication channel being used to communicate with the
- /// analysis server, or `null` if the plugin has not been started.
+ /// analysis server.
PluginCommunicationChannel get channel => _channel;
/// Return the user visible information about how to contact the plugin authors
@@ -93,88 +70,150 @@
/// Return the user visible name of this plugin.
String get name;
- /// Return the SDK manager used to manage SDKs.
- DartSdkManager get sdkManager => _sdkManager;
-
/// Return the version number of the plugin spec required by this plugin,
/// encoded as a string.
String get version;
- /// Handle the fact that the file with the given [path] has been modified.
- void contentChanged(String path) {
- // Ignore changes to files.
+ /// This method is invoked when a new instance of [AnalysisContextCollection]
+ /// is created, so the plugin can perform initial analysis of analyzed files.
+ ///
+ /// By default analyzes every [AnalysisContext] with [analyzeFiles].
+ Future<void> afterNewContextCollection({
+ required AnalysisContextCollection contextCollection,
+ }) async {
+ await _forAnalysisContexts(contextCollection, (analysisContext) async {
+ final paths = analysisContext.contextRoot.analyzedFiles().toList();
+ await analyzeFiles(
+ analysisContext: analysisContext,
+ paths: paths,
+ );
+ });
}
- /// Return the context root containing the file at the given [filePath].
- ContextRoot? contextRootContaining(String filePath) {
- var pathContext = resourceProvider.pathContext;
+ /// Analyzes the given file.
+ Future<void> analyzeFile({
+ required AnalysisContext analysisContext,
+ required String path,
+ });
- /// Return `true` if the given [child] is either the same as or within the
- /// given [parent].
- bool isOrWithin(String parent, String child) {
- return parent == child || pathContext.isWithin(parent, child);
+ /// Analyzes the given files.
+ /// By default invokes [analyzeFile] for every file.
+ /// Implementations may override to optimize for batch analysis.
+ Future<void> analyzeFiles({
+ required AnalysisContext analysisContext,
+ required List<String> paths,
+ }) async {
+ final pathSet = paths.toSet();
+
+ // First analyze priority files.
+ for (final path in priorityPaths) {
+ pathSet.remove(path);
+ await analyzeFile(
+ analysisContext: analysisContext,
+ path: path,
+ );
}
- /// Return `true` if the given context [root] contains the target [file].
- bool ownsFile(ContextRoot root) {
- if (isOrWithin(root.root, filePath)) {
- var excludedPaths = root.exclude;
- for (var excludedPath in excludedPaths) {
- if (isOrWithin(excludedPath, filePath)) {
- return false;
- }
+ // Then analyze the remaining files.
+ for (final path in pathSet) {
+ await analyzeFile(
+ analysisContext: analysisContext,
+ path: path,
+ );
+ }
+ }
+
+ /// This method is invoked immediately before the current
+ /// [AnalysisContextCollection] is disposed.
+ Future<void> beforeContextCollectionDispose({
+ required AnalysisContextCollection contextCollection,
+ }) async {}
+
+ /// Handle the fact that files with [paths] were changed.
+ Future<void> contentChanged(List<String> paths) async {
+ final contextCollection = _contextCollection;
+ if (contextCollection != null) {
+ await _forAnalysisContexts(contextCollection, (analysisContext) async {
+ for (final path in paths) {
+ analysisContext.changeFile(path);
}
- return true;
- }
- return false;
+ final affected = await analysisContext.applyPendingFileChanges();
+ await handleAffectedFiles(
+ analysisContext: analysisContext,
+ paths: affected,
+ );
+ });
}
-
- for (var root in driverMap.keys) {
- if (ownsFile(root)) {
- return root;
- }
- }
- return null;
}
- /// Create an analysis driver that can analyze the files within the given
- /// [contextRoot].
- AnalysisDriverGeneric createAnalysisDriver(ContextRoot contextRoot);
+ /// This method is invoked once to create the [ByteStore] that is used for
+ /// all [AnalysisContextCollection] instances, and reused when new instances
+ /// are created (and so can perform analysis faster).
+ ByteStore createByteStore() {
+ return MemoryCachingByteStore(
+ NullByteStore(),
+ 1024 * 1024 * 256,
+ );
+ }
- /// Return the driver being used to analyze the file with the given [path].
- AnalysisDriverGeneric? driverForPath(String path) {
- var contextRoot = contextRootContaining(path);
- if (contextRoot == null) {
- return null;
+ /// Plugin implementations can use this method to flush the state of
+ /// analysis, so reduce the used heap size, after performing a set of
+ /// operations, e.g. in [afterNewContextCollection] or [handleAffectedFiles].
+ ///
+ /// The next analysis operation will be slower, because it will restore
+ /// the state from the byte store cache, or recompute.
+ Future<void> flushAnalysisState({
+ bool elementModels = true,
+ }) async {
+ final contextCollection = _contextCollection;
+ if (contextCollection != null) {
+ for (final analysisContext in contextCollection.contexts) {
+ if (elementModels) {
+ analysisContext.driver.clearLibraryContext();
+ }
+ }
}
- return driverMap[contextRoot];
}
/// Return the result of analyzing the file with the given [path].
///
- /// Throw a [RequestFailure] is the file cannot be analyzed or if the driver
- /// associated with the file is not an [AnalysisDriver].
+ /// Throw a [RequestFailure] is the file cannot be analyzed.
Future<ResolvedUnitResult> getResolvedUnitResult(String path) async {
- var driver = driverForPath(path);
- if (driver is! AnalysisDriver) {
- // Return an error from the request.
- throw RequestFailure(
- RequestErrorFactory.pluginError('Failed to analyze $path', null));
+ final contextCollection = _contextCollection;
+ if (contextCollection != null) {
+ final analysisContext = contextCollection.contextFor(path);
+ final analysisSession = analysisContext.currentSession;
+ final unitResult = await analysisSession.getResolvedUnit(path);
+ if (unitResult is ResolvedUnitResult) {
+ return unitResult;
+ }
}
- var result = await driver.getResult(path);
- if (result is! ResolvedUnitResult) {
- // Return an error from the request.
- throw RequestFailure(
- RequestErrorFactory.pluginError('Failed to analyze $path', null));
- }
- return result;
+ // Return an error from the request.
+ throw RequestFailure(
+ RequestErrorFactory.pluginError('Failed to analyze $path', null),
+ );
+ }
+
+ /// Handles files that might have been affected by a content change of
+ /// one or more files. The implementation may check if these files should
+ /// be analyzed, do such analysis, and send diagnostics.
+ ///
+ /// By default invokes [analyzeFiles].
+ Future<void> handleAffectedFiles({
+ required AnalysisContext analysisContext,
+ required List<String> paths,
+ }) async {
+ await analyzeFiles(
+ analysisContext: analysisContext,
+ paths: paths,
+ );
}
/// Handle an 'analysis.getNavigation' request.
///
/// Throw a [RequestFailure] if the request could not be handled.
Future<AnalysisGetNavigationResult> handleAnalysisGetNavigation(
- AnalysisGetNavigationParams params) async {
+ AnalysisGetNavigationParams parameters) async {
return AnalysisGetNavigationResult(
<String>[], <NavigationTarget>[], <NavigationRegion>[]);
}
@@ -190,7 +229,7 @@
// TODO(brianwilkerson) Handle the event.
break;
case WatchEventType.MODIFY:
- contentChanged(event.path);
+ await contentChanged([event.path]);
break;
case WatchEventType.REMOVE:
// TODO(brianwilkerson) Handle the event.
@@ -208,27 +247,27 @@
/// Throw a [RequestFailure] if the request could not be handled.
Future<AnalysisSetContextRootsResult> handleAnalysisSetContextRoots(
AnalysisSetContextRootsParams parameters) async {
- var contextRoots = parameters.roots;
- var oldRoots = driverMap.keys.toList();
- for (var contextRoot in contextRoots) {
- if (!oldRoots.remove(contextRoot)) {
- // The context is new, so we create a driver for it. Creating the driver
- // has the side-effect of adding it to the analysis driver scheduler.
- var driver = createAnalysisDriver(contextRoot);
- driverMap[contextRoot] = driver;
- _addFilesToDriver(
- driver,
- resourceProvider.getResource(contextRoot.root),
- contextRoot.exclude);
- }
+ final currentContextCollection = _contextCollection;
+ if (currentContextCollection != null) {
+ _contextCollection = null;
+ await beforeContextCollectionDispose(
+ contextCollection: currentContextCollection,
+ );
+ currentContextCollection.dispose();
}
- for (var contextRoot in oldRoots) {
- // The context has been removed, so we remove its driver.
- var driver = driverMap.remove(contextRoot);
- // The `dispose` method has the side-effect of removing the driver from
- // the analysis driver scheduler.
- driver?.dispose();
- }
+
+ final includedPaths = parameters.roots.map((e) => e.root).toList();
+ final contextCollection = AnalysisContextCollectionImpl(
+ resourceProvider: resourceProvider,
+ includedPaths: includedPaths,
+ byteStore: _byteStore,
+ sdkPath: _sdkPath,
+ fileContentCache: FileContentCache(resourceProvider),
+ );
+ _contextCollection = contextCollection;
+ await afterNewContextCollection(
+ contextCollection: contextCollection,
+ );
return AnalysisSetContextRootsResult();
}
@@ -237,19 +276,7 @@
/// Throw a [RequestFailure] if the request could not be handled.
Future<AnalysisSetPriorityFilesResult> handleAnalysisSetPriorityFiles(
AnalysisSetPriorityFilesParams parameters) async {
- var files = parameters.files;
- var filesByDriver = <AnalysisDriverGeneric, List<String>>{};
- for (var file in files) {
- var contextRoot = contextRootContaining(file);
- if (contextRoot != null) {
- // TODO(brianwilkerson) Which driver should we use if there is no context root?
- var driver = driverMap[contextRoot]!;
- filesByDriver.putIfAbsent(driver, () => <String>[]).add(file);
- }
- }
- filesByDriver.forEach((AnalysisDriverGeneric driver, List<String> files) {
- driver.priorityFiles = files;
- });
+ priorityPaths = parameters.files.toSet();
return AnalysisSetPriorityFilesResult();
}
@@ -273,13 +300,14 @@
/// Throw a [RequestFailure] if the request could not be handled.
Future<AnalysisUpdateContentResult> handleAnalysisUpdateContent(
AnalysisUpdateContentParams parameters) async {
- var files = parameters.files;
- files.forEach((String filePath, Object? overlay) {
+ final changedPaths = <String>{};
+ var paths = parameters.files;
+ paths.forEach((String path, Object? overlay) {
// Prepare the old overlay contents.
String? oldContents;
try {
- if (resourceProvider.hasOverlay(filePath)) {
- var file = resourceProvider.getFile(filePath);
+ if (resourceProvider.hasOverlay(path)) {
+ var file = resourceProvider.getFile(path);
oldContents = file.readAsStringSync();
}
} catch (_) {}
@@ -307,16 +335,17 @@
if (newContents != null) {
resourceProvider.setOverlay(
- filePath,
+ path,
content: newContents,
modificationStamp: _overlayModificationStamp++,
);
} else {
- resourceProvider.removeOverlay(filePath);
+ resourceProvider.removeOverlay(path);
}
- contentChanged(filePath);
+ changedPaths.add(path);
});
+ await contentChanged(changedPaths.toList());
return AnalysisUpdateContentResult();
}
@@ -386,15 +415,9 @@
/// Throw a [RequestFailure] if the request could not be handled.
Future<PluginVersionCheckResult> handlePluginVersionCheck(
PluginVersionCheckParams parameters) async {
- var byteStorePath = parameters.byteStorePath;
- var sdkPath = parameters.sdkPath;
+ _sdkPath = parameters.sdkPath;
var versionString = parameters.version;
var serverVersion = Version.parse(versionString);
- _byteStore = MemoryCachingByteStore(
- FileByteStore(byteStorePath,
- tempNameSuffix: DateTime.now().millisecondsSinceEpoch.toString()),
- 64 * M);
- _sdkManager = DartSdkManager(sdkPath);
return PluginVersionCheckResult(
isCompatibleWith(serverVersion), name, version, fileGlobsToAnalyze,
contactInfo: contactInfo);
@@ -479,25 +502,23 @@
_channel.listen(_onRequest, onError: onError, onDone: onDone);
}
- /// Add all of the files contained in the given [resource] that are not in the
- /// list of [excluded] resources to the given [driver].
- void _addFilesToDriver(
- AnalysisDriverGeneric driver, Resource resource, List<String> excluded) {
- var path = resource.path;
- if (excluded.contains(path)) {
- return;
- }
- if (resource is File) {
- driver.addFile(path);
- } else if (resource is Folder) {
- try {
- for (var child in resource.getChildren()) {
- _addFilesToDriver(driver, child, excluded);
- }
- } on FileSystemException {
- // The folder does not exist, so ignore it.
+ /// Invokes [f] first for priority analysis contexts, then for the rest.
+ Future<void> _forAnalysisContexts(
+ AnalysisContextCollection contextCollection,
+ Future<void> Function(AnalysisContext analysisContext) f,
+ ) async {
+ final nonPriorityAnalysisContexts = <AnalysisContext>[];
+ for (final analysisContext in contextCollection.contexts) {
+ if (_isPriorityAnalysisContext(analysisContext)) {
+ await f(analysisContext);
+ } else {
+ nonPriorityAnalysisContexts.add(analysisContext);
}
}
+
+ for (final analysisContext in nonPriorityAnalysisContexts) {
+ await f(analysisContext);
+ }
}
/// Compute the response that should be returned for the given [request], or
@@ -571,6 +592,10 @@
return result.toResponse(request.id, requestTime);
}
+ bool _isPriorityAnalysisContext(AnalysisContext analysisContext) {
+ return priorityPaths.any(analysisContext.contextRoot.isAnalyzed);
+ }
+
/// The method that is called when a [request] is received from the analysis
/// server.
Future<void> _onRequest(Request request) async {
diff --git a/pkg/analyzer_plugin/pubspec.yaml b/pkg/analyzer_plugin/pubspec.yaml
index 0115b6f..c3322ed 100644
--- a/pkg/analyzer_plugin/pubspec.yaml
+++ b/pkg/analyzer_plugin/pubspec.yaml
@@ -1,13 +1,13 @@
name: analyzer_plugin
description: A framework and support code for building plugins for the analysis server.
-version: 0.10.0
+version: 0.11.0
repository: https://github.com/dart-lang/sdk/tree/main/pkg/analyzer_plugin
environment:
- sdk: '>=2.14.0 <3.0.0'
+ sdk: '>=2.17.0 <3.0.0'
dependencies:
- analyzer: ^4.0.0
+ analyzer: ^4.1.0
collection: ^1.15.0
dart_style: ^2.2.1
pub_semver: ^2.0.0
@@ -20,6 +20,7 @@
dev_dependencies:
analyzer_utilities: any
html: any
+ meta: any
path: any
test_reflective_loader: any
test: any
diff --git a/pkg/analyzer_plugin/test/plugin/assist_mixin_test.dart b/pkg/analyzer_plugin/test/plugin/assist_mixin_test.dart
index 475a6552..4c1e64c 100644
--- a/pkg/analyzer_plugin/test/plugin/assist_mixin_test.dart
+++ b/pkg/analyzer_plugin/test/plugin/assist_mixin_test.dart
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/plugin/assist_mixin.dart';
+import 'package:analyzer_plugin/plugin/plugin.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
import 'package:analyzer_plugin/src/utilities/assist/assist.dart';
@@ -13,29 +13,31 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'mocks.dart';
+import 'plugin_test.dart';
void main() {
defineReflectiveTests(AssistsMixinTest);
}
@reflectiveTest
-class AssistsMixinTest with ResourceProviderMixin {
+class AssistsMixinTest extends AbstractPluginTest {
late String packagePath1;
late String filePath1;
late ContextRoot contextRoot1;
- late MockChannel channel;
- late _TestServerPlugin plugin;
+ @override
+ ServerPlugin createPlugin() {
+ return _TestServerPlugin(resourceProvider);
+ }
- void setUp() {
+ @override
+ Future<void> setUp() async {
+ await super.setUp();
+
packagePath1 = convertPath('/package1');
filePath1 = join(packagePath1, 'lib', 'test.dart');
newFile(filePath1, '');
contextRoot1 = ContextRoot(packagePath1, <String>[]);
-
- channel = MockChannel();
- plugin = _TestServerPlugin(resourceProvider);
- plugin.start(channel);
}
Future<void> test_handleEditGetAssists() async {
diff --git a/pkg/analyzer_plugin/test/plugin/completion_mixin_test.dart b/pkg/analyzer_plugin/test/plugin/completion_mixin_test.dart
index ad201a7..9c3a563 100644
--- a/pkg/analyzer_plugin/test/plugin/completion_mixin_test.dart
+++ b/pkg/analyzer_plugin/test/plugin/completion_mixin_test.dart
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/plugin/completion_mixin.dart';
+import 'package:analyzer_plugin/plugin/plugin.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
import 'package:analyzer_plugin/src/utilities/completion/completion_core.dart';
@@ -13,29 +13,30 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'mocks.dart';
+import 'plugin_test.dart';
void main() {
defineReflectiveTests(CompletionMixinTest);
}
@reflectiveTest
-class CompletionMixinTest with ResourceProviderMixin {
+class CompletionMixinTest extends AbstractPluginTest {
late String packagePath1;
late String filePath1;
late ContextRoot contextRoot1;
- late MockChannel channel;
- late _TestServerPlugin plugin;
+ @override
+ ServerPlugin createPlugin() {
+ return _TestServerPlugin(resourceProvider);
+ }
- void setUp() {
+ @override
+ Future<void> setUp() async {
+ await super.setUp();
packagePath1 = convertPath('/package1');
filePath1 = join(packagePath1, 'lib', 'test.dart');
newFile(filePath1, 'int foo = bar;');
contextRoot1 = ContextRoot(packagePath1, <String>[]);
-
- channel = MockChannel();
- plugin = _TestServerPlugin(resourceProvider);
- plugin.start(channel);
}
Future<void> test_handleCompletionGetSuggestions() async {
diff --git a/pkg/analyzer_plugin/test/plugin/fix_mixin_test.dart b/pkg/analyzer_plugin/test/plugin/fix_mixin_test.dart
index 34b456d..f095acd 100644
--- a/pkg/analyzer_plugin/test/plugin/fix_mixin_test.dart
+++ b/pkg/analyzer_plugin/test/plugin/fix_mixin_test.dart
@@ -6,8 +6,8 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/plugin/fix_mixin.dart';
+import 'package:analyzer_plugin/plugin/plugin.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart'
hide AnalysisError;
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
@@ -17,29 +17,30 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'mocks.dart';
+import 'plugin_test.dart';
void main() {
defineReflectiveTests(FixesMixinTest);
}
@reflectiveTest
-class FixesMixinTest with ResourceProviderMixin {
+class FixesMixinTest extends AbstractPluginTest {
late String packagePath1;
late String filePath1;
late ContextRoot contextRoot1;
- late MockChannel channel;
- late _TestServerPlugin plugin;
+ @override
+ ServerPlugin createPlugin() {
+ return _TestServerPlugin(resourceProvider);
+ }
- void setUp() {
+ @override
+ Future<void> setUp() async {
+ await super.setUp();
packagePath1 = convertPath('/package1');
filePath1 = join(packagePath1, 'lib', 'test.dart');
newFile(filePath1, '');
contextRoot1 = ContextRoot(packagePath1, <String>[]);
-
- channel = MockChannel();
- plugin = _TestServerPlugin(resourceProvider);
- plugin.start(channel);
}
Future<void> test_handleEditGetFixes() async {
diff --git a/pkg/analyzer_plugin/test/plugin/folding_mixin_test.dart b/pkg/analyzer_plugin/test/plugin/folding_mixin_test.dart
index c1986c4..528a37d 100644
--- a/pkg/analyzer_plugin/test/plugin/folding_mixin_test.dart
+++ b/pkg/analyzer_plugin/test/plugin/folding_mixin_test.dart
@@ -5,8 +5,8 @@
import 'dart:async';
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/plugin/folding_mixin.dart';
+import 'package:analyzer_plugin/plugin/plugin.dart';
import 'package:analyzer_plugin/protocol/protocol.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
@@ -16,29 +16,30 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'mocks.dart';
+import 'plugin_test.dart';
void main() {
defineReflectiveTests(FoldingMixinTest);
}
@reflectiveTest
-class FoldingMixinTest with ResourceProviderMixin {
+class FoldingMixinTest extends AbstractPluginTest {
late String packagePath1;
late String filePath1;
late ContextRoot contextRoot1;
- late MockChannel channel;
- late _TestServerPlugin plugin;
+ @override
+ ServerPlugin createPlugin() {
+ return _TestServerPlugin(resourceProvider);
+ }
- void setUp() {
+ @override
+ Future<void> setUp() async {
+ await super.setUp();
packagePath1 = convertPath('/package1');
filePath1 = join(packagePath1, 'lib', 'test.dart');
newFile(filePath1, '');
contextRoot1 = ContextRoot(packagePath1, <String>[]);
-
- channel = MockChannel();
- plugin = _TestServerPlugin(resourceProvider);
- plugin.start(channel);
}
Future<void> test_sendFoldingNotification() async {
diff --git a/pkg/analyzer_plugin/test/plugin/highlights_mixin_test.dart b/pkg/analyzer_plugin/test/plugin/highlights_mixin_test.dart
index 409eafa..c7f0a33 100644
--- a/pkg/analyzer_plugin/test/plugin/highlights_mixin_test.dart
+++ b/pkg/analyzer_plugin/test/plugin/highlights_mixin_test.dart
@@ -5,8 +5,8 @@
import 'dart:async';
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/plugin/highlights_mixin.dart';
+import 'package:analyzer_plugin/plugin/plugin.dart';
import 'package:analyzer_plugin/protocol/protocol.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
@@ -16,29 +16,30 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'mocks.dart';
+import 'plugin_test.dart';
void main() {
defineReflectiveTests(HighlightsMixinTest);
}
@reflectiveTest
-class HighlightsMixinTest with ResourceProviderMixin {
+class HighlightsMixinTest extends AbstractPluginTest {
late String packagePath1;
late String filePath1;
late ContextRoot contextRoot1;
- late MockChannel channel;
- late _TestServerPlugin plugin;
+ @override
+ ServerPlugin createPlugin() {
+ return _TestServerPlugin(resourceProvider);
+ }
- void setUp() {
+ @override
+ Future<void> setUp() async {
+ await super.setUp();
packagePath1 = convertPath('/package1');
filePath1 = join(packagePath1, 'lib', 'test.dart');
newFile(filePath1, '');
contextRoot1 = ContextRoot(packagePath1, <String>[]);
-
- channel = MockChannel();
- plugin = _TestServerPlugin(resourceProvider);
- plugin.start(channel);
}
Future<void> test_sendHighlightsNotification() async {
diff --git a/pkg/analyzer_plugin/test/plugin/kythe_mixin_test.dart b/pkg/analyzer_plugin/test/plugin/kythe_mixin_test.dart
index e038fe0..59fccaa 100644
--- a/pkg/analyzer_plugin/test/plugin/kythe_mixin_test.dart
+++ b/pkg/analyzer_plugin/test/plugin/kythe_mixin_test.dart
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/plugin/kythe_mixin.dart';
+import 'package:analyzer_plugin/plugin/plugin.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
import 'package:analyzer_plugin/src/utilities/kythe/entries.dart';
@@ -13,29 +13,30 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'mocks.dart';
+import 'plugin_test.dart';
void main() {
defineReflectiveTests(KytheMixinTest);
}
@reflectiveTest
-class KytheMixinTest with ResourceProviderMixin {
+class KytheMixinTest extends AbstractPluginTest {
late String packagePath1;
late String filePath1;
late ContextRoot contextRoot1;
- late MockChannel channel;
- late _TestServerPlugin plugin;
+ @override
+ ServerPlugin createPlugin() {
+ return _TestServerPlugin(resourceProvider);
+ }
- void setUp() {
+ @override
+ Future<void> setUp() async {
+ await super.setUp();
packagePath1 = convertPath('/package1');
filePath1 = join(packagePath1, 'lib', 'test.dart');
newFile(filePath1, '');
contextRoot1 = ContextRoot(packagePath1, <String>[]);
-
- channel = MockChannel();
- plugin = _TestServerPlugin(resourceProvider);
- plugin.start(channel);
}
Future<void> test_handleEditGetAssists() async {
@@ -44,7 +45,7 @@
var result = await plugin
.handleKytheGetKytheEntries(KytheGetKytheEntriesParams(filePath1));
- expect(result, isNotNull);
+ result!;
expect(result.entries, hasLength(3));
}
}
diff --git a/pkg/analyzer_plugin/test/plugin/mocks.dart b/pkg/analyzer_plugin/test/plugin/mocks.dart
index fd3665f..69cd682 100644
--- a/pkg/analyzer_plugin/test/plugin/mocks.dart
+++ b/pkg/analyzer_plugin/test/plugin/mocks.dart
@@ -4,6 +4,7 @@
import 'dart:async';
+import 'package:analyzer/dart/analysis/analysis_context.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/file_system/file_system.dart';
@@ -14,7 +15,6 @@
import 'package:analyzer_plugin/channel/channel.dart';
import 'package:analyzer_plugin/plugin/plugin.dart';
import 'package:analyzer_plugin/protocol/protocol.dart';
-import 'package:analyzer_plugin/protocol/protocol_generated.dart';
import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';
import 'package:test/test.dart';
@@ -138,7 +138,8 @@
/// A concrete implementation of a server plugin that is suitable for testing.
class MockServerPlugin extends ServerPlugin {
- MockServerPlugin(ResourceProvider resourceProvider) : super(resourceProvider);
+ MockServerPlugin(ResourceProvider resourceProvider)
+ : super(resourceProvider: resourceProvider);
@override
List<String> get fileGlobsToAnalyze => <String>['*.dart'];
@@ -150,9 +151,10 @@
String get version => '0.1.0';
@override
- AnalysisDriverGeneric createAnalysisDriver(ContextRoot contextRoot) {
- return MockAnalysisDriver();
- }
+ Future<void> analyzeFile({
+ required AnalysisContext analysisContext,
+ required String path,
+ }) async {}
}
class MockSource implements Source {
diff --git a/pkg/analyzer_plugin/test/plugin/navigation_mixin_test.dart b/pkg/analyzer_plugin/test/plugin/navigation_mixin_test.dart
index 38cb85a..3978d56 100644
--- a/pkg/analyzer_plugin/test/plugin/navigation_mixin_test.dart
+++ b/pkg/analyzer_plugin/test/plugin/navigation_mixin_test.dart
@@ -5,8 +5,8 @@
import 'dart:async';
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/plugin/navigation_mixin.dart';
+import 'package:analyzer_plugin/plugin/plugin.dart';
import 'package:analyzer_plugin/protocol/protocol.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
@@ -16,29 +16,30 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'mocks.dart';
+import 'plugin_test.dart';
void main() {
defineReflectiveTests(NavigationMixinTest);
}
@reflectiveTest
-class NavigationMixinTest with ResourceProviderMixin {
+class NavigationMixinTest extends AbstractPluginTest {
late String packagePath1;
late String filePath1;
late ContextRoot contextRoot1;
- late MockChannel channel;
- late _TestServerPlugin plugin;
+ @override
+ ServerPlugin createPlugin() {
+ return _TestServerPlugin(resourceProvider);
+ }
- void setUp() {
+ @override
+ Future<void> setUp() async {
+ await super.setUp();
packagePath1 = convertPath('/package1');
filePath1 = join(packagePath1, 'lib', 'test.dart');
newFile(filePath1, '');
contextRoot1 = ContextRoot(packagePath1, <String>[]);
-
- channel = MockChannel();
- plugin = _TestServerPlugin(resourceProvider);
- plugin.start(channel);
}
Future<void> test_handleAnalysisGetNavigation() async {
diff --git a/pkg/analyzer_plugin/test/plugin/occurrences_mixin_test.dart b/pkg/analyzer_plugin/test/plugin/occurrences_mixin_test.dart
index fa1aec6..c44404a 100644
--- a/pkg/analyzer_plugin/test/plugin/occurrences_mixin_test.dart
+++ b/pkg/analyzer_plugin/test/plugin/occurrences_mixin_test.dart
@@ -5,8 +5,8 @@
import 'dart:async';
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/plugin/occurrences_mixin.dart';
+import 'package:analyzer_plugin/plugin/plugin.dart';
import 'package:analyzer_plugin/protocol/protocol.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
@@ -16,29 +16,30 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'mocks.dart';
+import 'plugin_test.dart';
void main() {
defineReflectiveTests(OccurrencesMixinTest);
}
@reflectiveTest
-class OccurrencesMixinTest with ResourceProviderMixin {
+class OccurrencesMixinTest extends AbstractPluginTest {
late String packagePath1;
late String filePath1;
late ContextRoot contextRoot1;
- late MockChannel channel;
- late _TestServerPlugin plugin;
+ @override
+ ServerPlugin createPlugin() {
+ return _TestServerPlugin(resourceProvider);
+ }
- void setUp() {
+ @override
+ Future<void> setUp() async {
+ await super.setUp();
packagePath1 = convertPath('/package1');
filePath1 = join(packagePath1, 'lib', 'test.dart');
newFile(filePath1, '');
contextRoot1 = ContextRoot(packagePath1, <String>[]);
-
- channel = MockChannel();
- plugin = _TestServerPlugin(resourceProvider);
- plugin.start(channel);
}
Future<void> test_sendOccurrencesNotification() async {
diff --git a/pkg/analyzer_plugin/test/plugin/outline_mixin_test.dart b/pkg/analyzer_plugin/test/plugin/outline_mixin_test.dart
index 1b4ff4e..55a632d 100644
--- a/pkg/analyzer_plugin/test/plugin/outline_mixin_test.dart
+++ b/pkg/analyzer_plugin/test/plugin/outline_mixin_test.dart
@@ -5,8 +5,8 @@
import 'dart:async';
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/plugin/outline_mixin.dart';
+import 'package:analyzer_plugin/plugin/plugin.dart';
import 'package:analyzer_plugin/protocol/protocol.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
@@ -16,29 +16,30 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'mocks.dart';
+import 'plugin_test.dart';
void main() {
defineReflectiveTests(OutlineMixinTest);
}
@reflectiveTest
-class OutlineMixinTest with ResourceProviderMixin {
+class OutlineMixinTest extends AbstractPluginTest {
late String packagePath1;
late String filePath1;
late ContextRoot contextRoot1;
- late MockChannel channel;
- late _TestServerPlugin plugin;
+ @override
+ ServerPlugin createPlugin() {
+ return _TestServerPlugin(resourceProvider);
+ }
- void setUp() {
+ @override
+ Future<void> setUp() async {
+ await super.setUp();
packagePath1 = convertPath('/package1');
filePath1 = join(packagePath1, 'lib', 'test.dart');
newFile(filePath1, '');
contextRoot1 = ContextRoot(packagePath1, <String>[]);
-
- channel = MockChannel();
- plugin = _TestServerPlugin(resourceProvider);
- plugin.start(channel);
}
Future<void> test_sendOutlineNotification() async {
diff --git a/pkg/analyzer_plugin/test/plugin/plugin_test.dart b/pkg/analyzer_plugin/test/plugin/plugin_test.dart
index a221850..a398fa6 100644
--- a/pkg/analyzer_plugin/test/plugin/plugin_test.dart
+++ b/pkg/analyzer_plugin/test/plugin/plugin_test.dart
@@ -2,12 +2,17 @@
// 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 'package:analyzer/dart/analysis/analysis_context.dart';
+import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/test_utilities/mock_sdk.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
+import 'package:analyzer_plugin/plugin/plugin.dart';
import 'package:analyzer_plugin/protocol/protocol.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
+import 'package:meta/meta.dart';
+import 'package:pub_semver/pub_semver.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -17,11 +22,40 @@
defineReflectiveTests(ServerPluginTest);
}
-@reflectiveTest
-class ServerPluginTest with ResourceProviderMixin {
- late MockChannel channel;
- late _TestServerPlugin plugin;
+abstract class AbstractPluginTest with ResourceProviderMixin {
+ final MockChannel channel = MockChannel();
+ late final ServerPlugin plugin;
+ Folder get byteStoreRoot => getFolder('/byteStore');
+
+ Version get pluginSpecificationVersion => Version(0, 1, 0);
+
+ Folder get sdkRoot => getFolder('/sdk');
+
+ ServerPlugin createPlugin();
+
+ @mustCallSuper
+ Future<void> setUp() async {
+ createMockSdk(
+ resourceProvider: resourceProvider,
+ root: sdkRoot,
+ );
+
+ plugin = createPlugin();
+ plugin.start(channel);
+
+ await plugin.handlePluginVersionCheck(
+ PluginVersionCheckParams(
+ byteStoreRoot.path,
+ sdkRoot.path,
+ pluginSpecificationVersion.canonicalizedVersion,
+ ),
+ );
+ }
+}
+
+@reflectiveTest
+class ServerPluginTest extends AbstractPluginTest {
late String packagePath1;
late String filePath1;
late ContextRoot contextRoot1;
@@ -30,7 +64,14 @@
late String filePath2;
late ContextRoot contextRoot2;
- void setUp() {
+ @override
+ ServerPlugin createPlugin() {
+ return _TestServerPlugin(resourceProvider);
+ }
+
+ @override
+ Future<void> setUp() async {
+ await super.setUp();
packagePath1 = convertPath('/package1');
filePath1 = join(packagePath1, 'lib', 'test.dart');
newFile(filePath1, '');
@@ -40,28 +81,6 @@
filePath2 = join(packagePath2, 'lib', 'test.dart');
newFile(filePath2, '');
contextRoot2 = ContextRoot(packagePath2, <String>[]);
-
- channel = MockChannel();
- plugin = _TestServerPlugin(resourceProvider);
- plugin.start(channel);
- }
-
- Future<void> test_contextRootContaining_insideRoot() async {
- await plugin.handleAnalysisSetContextRoots(
- AnalysisSetContextRootsParams([contextRoot1]));
-
- expect(plugin.contextRootContaining(filePath1), isNotNull);
- }
-
- void test_contextRootContaining_noRoots() {
- expect(plugin.contextRootContaining(filePath1), isNull);
- }
-
- Future<void> test_contextRootContaining_outsideRoot() async {
- await plugin.handleAnalysisSetContextRoots(
- AnalysisSetContextRootsParams([contextRoot1]));
-
- expect(plugin.contextRootContaining(filePath2), isNull);
}
Future<void> test_handleAnalysisGetNavigation() async {
@@ -76,15 +95,6 @@
expect(result, isNotNull);
}
- Future<void> test_handleAnalysisSetContextRoots() async {
- var result = await plugin.handleAnalysisSetContextRoots(
- AnalysisSetContextRootsParams([contextRoot1]));
- expect(result, isNotNull);
- var driver = _getDriver(contextRoot1);
- expect(driver, isNotNull);
- expect((driver as MockAnalysisDriver).addedFiles, hasLength(1));
- }
-
Future<void> test_handleAnalysisSetPriorityFiles() async {
await plugin.handleAnalysisSetContextRoots(
AnalysisSetContextRootsParams([contextRoot1]));
@@ -239,12 +249,22 @@
}
Future<void> test_onRequest_analysisSetContextRoots() async {
+ final plugin = this.plugin as _TestServerPlugin;
+
+ final analyzedPaths = <String>[];
+ plugin.analyzeFileHandler = ({
+ required AnalysisContext analysisContext,
+ required String path,
+ }) {
+ analyzedPaths.add(path);
+ };
+
var result = await channel
.sendRequest(AnalysisSetContextRootsParams([contextRoot1]));
expect(result, isNotNull);
- var driver = _getDriver(contextRoot1);
- expect(driver, isNotNull);
- expect((driver as MockAnalysisDriver).addedFiles, hasLength(1));
+
+ expect(plugin.invoked_afterNewContextCollection, isTrue);
+ expect(analyzedPaths, [getFile('/package1/lib/test.dart').path]);
}
Future<void> test_onRequest_analysisSetPriorityFiles() async {
@@ -346,7 +366,7 @@
service3: [filePath2]
});
plugin.sendNotificationsForFile(filePath1);
- var notifications = plugin.sentNotifications;
+ var notifications = (plugin as _TestServerPlugin).sentNotifications;
expect(notifications, hasLength(1));
var services = notifications[filePath1];
expect(services, unorderedEquals([service1, service2]));
@@ -356,7 +376,7 @@
var subscriptions = <String, List<AnalysisService>>{};
plugin.sendNotificationsForSubscriptions(subscriptions);
- var notifications = plugin.sentNotifications;
+ var notifications = (plugin as _TestServerPlugin).sentNotifications;
expect(notifications, hasLength(subscriptions.length));
for (var path in subscriptions.keys) {
var subscribedServices = subscriptions[path];
@@ -367,25 +387,44 @@
reason: 'Wrong notifications for file $path');
}
}
-
- AnalysisDriverGeneric? _getDriver(ContextRoot targetRoot) {
- for (var root in plugin.driverMap.keys) {
- if (root.root == targetRoot.root) {
- return plugin.driverMap[root];
- }
- }
- return null;
- }
}
class _TestServerPlugin extends MockServerPlugin {
Map<String, List<AnalysisService>> sentNotifications =
<String, List<AnalysisService>>{};
+ bool invoked_afterNewContextCollection = false;
+
+ void Function({
+ required AnalysisContext analysisContext,
+ required String path,
+ })? analyzeFileHandler;
+
_TestServerPlugin(ResourceProvider resourceProvider)
: super(resourceProvider);
@override
+ Future<void> afterNewContextCollection({
+ required AnalysisContextCollection contextCollection,
+ }) async {
+ invoked_afterNewContextCollection = true;
+ return super.afterNewContextCollection(
+ contextCollection: contextCollection,
+ );
+ }
+
+ @override
+ Future<void> analyzeFile({
+ required AnalysisContext analysisContext,
+ required String path,
+ }) async {
+ analyzeFileHandler?.call(
+ analysisContext: analysisContext,
+ path: path,
+ );
+ }
+
+ @override
Future<void> sendFoldingNotification(String path) {
_sent(path, AnalysisService.FOLDING);
return Future.value();
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index d562113..7b61cef0 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -559,7 +559,10 @@
}
} else {
closedWorldAndIndices = await serializationTask.deserializeClosedWorld(
- environment, abstractValueStrategy, component);
+ environment,
+ abstractValueStrategy,
+ component,
+ useDeferredSourceReads);
}
if (closedWorldAndIndices != null && retainDataForTesting) {
backendClosedWorldForTesting = closedWorldAndIndices.data;
@@ -568,13 +571,16 @@
return closedWorldAndIndices;
}
+ bool get shouldStopAfterClosedWorldFromFlags =>
+ stopAfterClosedWorldForTesting ||
+ options.stopAfterProgramSplit ||
+ options.writeClosedWorldUri != null;
+
bool shouldStopAfterClosedWorld(
DataAndIndices<JsClosedWorld> closedWorldAndIndices) =>
closedWorldAndIndices == null ||
closedWorldAndIndices.data == null ||
- stopAfterClosedWorldForTesting ||
- options.stopAfterProgramSplit ||
- options.writeClosedWorldUri != null;
+ shouldStopAfterClosedWorldFromFlags;
Future<DataAndIndices<GlobalTypeInferenceResults>>
produceGlobalTypeInferenceResults(
@@ -597,7 +603,8 @@
environment,
abstractValueStrategy,
closedWorld.elementMap.programEnv.mainComponent,
- closedWorldAndIndices);
+ closedWorldAndIndices,
+ useDeferredSourceReads);
}
return globalTypeInferenceResults;
}
@@ -631,13 +638,20 @@
backendStrategy,
globalTypeInferenceResults.data,
codegenInputs,
- globalTypeInferenceResults.indices);
+ globalTypeInferenceResults.indices,
+ useDeferredSourceReads);
}
return codegenResults;
}
bool get shouldStopAfterCodegen => options.writeCodegenUri != null;
+ bool get useDeferredSourceReads =>
+ !shouldStopAfterClosedWorldFromFlags &&
+ !shouldStopAfterGlobalTypeInference &&
+ !shouldStopAfterCodegen &&
+ !shouldStopAfterModularAnalysis;
+
void runSequentialPhases() async {
// Load kernel.
load_kernel.Output output = await produceKernel();
diff --git a/pkg/compiler/lib/src/inferrer/abstract_value_strategy.dart b/pkg/compiler/lib/src/inferrer/abstract_value_strategy.dart
index de87183..87d5b7d1 100644
--- a/pkg/compiler/lib/src/inferrer/abstract_value_strategy.dart
+++ b/pkg/compiler/lib/src/inferrer/abstract_value_strategy.dart
@@ -4,7 +4,7 @@
// @dart = 2.10
-import '../universe/world_builder.dart';
+import '../universe/world_builder.dart' show SelectorConstraintsStrategy;
import '../world.dart';
import 'abstract_value_domain.dart';
diff --git a/pkg/compiler/lib/src/inferrer/types.dart b/pkg/compiler/lib/src/inferrer/types.dart
index 92ee1c5..8705fb2 100644
--- a/pkg/compiler/lib/src/inferrer/types.dart
+++ b/pkg/compiler/lib/src/inferrer/types.dart
@@ -19,6 +19,7 @@
import '../js_model/element_map.dart';
import '../js_model/js_world.dart';
import '../js_model/locals.dart';
+import '../serialization/deferrable.dart';
import '../serialization/serialization.dart';
import '../universe/selector.dart' show Selector;
import '../world.dart' show JClosedWorld;
@@ -219,17 +220,35 @@
final GlobalTypeInferenceMemberResult _deadMethodResult;
final AbstractValue _trivialParameterResult;
- final Map<MemberEntity, GlobalTypeInferenceMemberResult> memberResults;
- final Map<Local, AbstractValue> parameterResults;
+ final Deferrable<Map<MemberEntity, GlobalTypeInferenceMemberResult>>
+ _memberResults;
+ final Deferrable<Map<Local, AbstractValue>> _parameterResults;
final Set<Selector> returnsListElementTypeSet;
- final Map<ir.TreeNode, AbstractValue> _allocatedLists;
+ final Deferrable<Map<ir.TreeNode, AbstractValue>> _allocatedLists;
GlobalTypeInferenceResultsImpl(
this.closedWorld,
this.globalLocalsMap,
this.inferredData,
- this.memberResults,
- this.parameterResults,
+ Map<MemberEntity, GlobalTypeInferenceMemberResult> memberResults,
+ Map<Local, AbstractValue> parameterResults,
+ this.returnsListElementTypeSet,
+ Map<ir.TreeNode, AbstractValue> allocatedLists)
+ : _memberResults = Deferrable.eager(memberResults),
+ _parameterResults = Deferrable.eager(parameterResults),
+ _allocatedLists = Deferrable.eager(allocatedLists),
+ _deadFieldResult =
+ DeadFieldGlobalTypeInferenceResult(closedWorld.abstractValueDomain),
+ _deadMethodResult = DeadMethodGlobalTypeInferenceResult(
+ closedWorld.abstractValueDomain),
+ _trivialParameterResult = closedWorld.abstractValueDomain.dynamicType;
+
+ GlobalTypeInferenceResultsImpl._deserialized(
+ this.closedWorld,
+ this.globalLocalsMap,
+ this.inferredData,
+ this._memberResults,
+ this._parameterResults,
this.returnsListElementTypeSet,
this._allocatedLists)
: _deadFieldResult =
@@ -247,22 +266,25 @@
source.registerLocalLookup(LocalLookupImpl(globalLocalsMap));
source.begin(tag);
- Map<MemberEntity, GlobalTypeInferenceMemberResult> memberResults =
- source.readMemberMap((MemberEntity member) =>
- GlobalTypeInferenceMemberResult.readFromDataSource(
- source,
- elementMap.getMemberContextNode(member),
- closedWorld.abstractValueDomain));
- Map<Local, AbstractValue> parameterResults = source.readLocalMap(() =>
- closedWorld.abstractValueDomain
- .readAbstractValueFromDataSource(source));
+ Deferrable<Map<MemberEntity, GlobalTypeInferenceMemberResult>>
+ memberResults = source.readDeferrable(() => source.readMemberMap(
+ (MemberEntity member) =>
+ GlobalTypeInferenceMemberResult.readFromDataSource(
+ source,
+ elementMap.getMemberContextNode(member),
+ closedWorld.abstractValueDomain)));
+ Deferrable<Map<Local, AbstractValue>> parameterResults =
+ source.readDeferrable(() => source.readLocalMap(() => closedWorld
+ .abstractValueDomain
+ .readAbstractValueFromDataSource(source)));
Set<Selector> returnsListElementTypeSet =
source.readList(() => Selector.readFromDataSource(source)).toSet();
- Map<ir.TreeNode, AbstractValue> allocatedLists = source.readTreeNodeMap(
- () => closedWorld.abstractValueDomain
- .readAbstractValueFromDataSource(source));
+ Deferrable<Map<ir.TreeNode, AbstractValue>> allocatedLists =
+ source.readDeferrable(() => source.readTreeNodeMap(() => closedWorld
+ .abstractValueDomain
+ .readAbstractValueFromDataSource(source)));
source.end(tag);
- return GlobalTypeInferenceResultsImpl(
+ return GlobalTypeInferenceResultsImpl._deserialized(
closedWorld,
globalLocalsMap,
inferredData,
@@ -276,23 +298,23 @@
void writeToDataSink(DataSinkWriter sink, JsToElementMap elementMap) {
sink.writeBool(false); // Is _not_ trivial.
sink.begin(tag);
- sink.writeMemberMap(
- memberResults,
+ sink.writeDeferrable(() => sink.writeMemberMap(
+ _memberResults.loaded(),
(MemberEntity member, GlobalTypeInferenceMemberResult result) =>
result.writeToDataSink(
sink,
elementMap.getMemberContextNode(member),
- closedWorld.abstractValueDomain));
- sink.writeLocalMap(
- parameterResults,
+ closedWorld.abstractValueDomain)));
+ sink.writeDeferrable(() => sink.writeLocalMap(
+ _parameterResults.loaded(),
(AbstractValue value) => closedWorld.abstractValueDomain
- .writeAbstractValueToDataSink(sink, value));
+ .writeAbstractValueToDataSink(sink, value)));
sink.writeList(returnsListElementTypeSet,
(Selector selector) => selector.writeToDataSink(sink));
- sink.writeTreeNodeMap(
- _allocatedLists,
+ sink.writeDeferrable(() => sink.writeTreeNodeMap(
+ _allocatedLists.loaded(),
(AbstractValue value) => closedWorld.abstractValueDomain
- .writeAbstractValueToDataSink(sink, value));
+ .writeAbstractValueToDataSink(sink, value)));
sink.end(tag);
}
@@ -308,7 +330,7 @@
// don't exist..
/*assert(memberResults.containsKey(member) || member is JSignatureMethod,
"No inference result for member $member");*/
- return memberResults[member] ??
+ return _memberResults.loaded()[member] ??
(member is FunctionEntity ? _deadMethodResult : _deadFieldResult);
}
@@ -318,7 +340,7 @@
// don't exist.
/*assert(parameterResults.containsKey(parameter),
"No inference result for parameter $parameter");*/
- return parameterResults[parameter] ?? _trivialParameterResult;
+ return _parameterResults.loaded()[parameter] ?? _trivialParameterResult;
}
@override
@@ -399,10 +421,11 @@
}
@override
- AbstractValue typeOfNewList(ir.Node node) => _allocatedLists[node];
+ AbstractValue typeOfNewList(ir.Node node) => _allocatedLists.loaded()[node];
@override
- AbstractValue typeOfListLiteral(ir.Node node) => _allocatedLists[node];
+ AbstractValue typeOfListLiteral(ir.Node node) =>
+ _allocatedLists.loaded()[node];
}
class GlobalTypeInferenceMemberResultImpl
diff --git a/pkg/compiler/lib/src/js_backend/backend_usage.dart b/pkg/compiler/lib/src/js_backend/backend_usage.dart
index 30138eb..9b41b8e 100644
--- a/pkg/compiler/lib/src/js_backend/backend_usage.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_usage.dart
@@ -9,7 +9,7 @@
import '../elements/entities.dart';
import '../elements/types.dart';
import '../ir/runtime_type_analysis.dart';
-import '../kernel/kernel_strategy.dart';
+import '../kernel/kernel_strategy.dart' show KernelFrontendStrategy;
import '../serialization/serialization_interfaces.dart';
import '../universe/feature.dart';
import '../util/util.dart' show Setlet;
diff --git a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
index c62f4a3..8069eda 100644
--- a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
+++ b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
@@ -8,7 +8,7 @@
import '../common/elements.dart' show CommonElements;
import '../common/names.dart' show Identifiers, Selectors;
import '../elements/entities.dart';
-import '../inferrer/types.dart';
+import '../inferrer/types.dart' show GlobalTypeInferenceResults;
import '../kernel/no_such_method_resolver.dart';
import '../serialization/serialization_interfaces.dart';
diff --git a/pkg/compiler/lib/src/js_backend/specialized_checks.dart b/pkg/compiler/lib/src/js_backend/specialized_checks.dart
index 3c6558b..0dbc18d 100644
--- a/pkg/compiler/lib/src/js_backend/specialized_checks.dart
+++ b/pkg/compiler/lib/src/js_backend/specialized_checks.dart
@@ -9,7 +9,6 @@
import '../elements/entities.dart';
import '../elements/types.dart';
import '../js_backend/interceptor_data.dart' show InterceptorData;
-import '../ssa/nodes.dart' show HGraph;
import '../universe/class_hierarchy.dart' show ClassHierarchy;
import '../world.dart' show JClosedWorld;
@@ -26,20 +25,20 @@
class SpecializedChecks {
static IsTestSpecialization findIsTestSpecialization(
- DartType dartType, HGraph graph, JClosedWorld closedWorld) {
+ DartType dartType, MemberEntity compiland, JClosedWorld closedWorld) {
if (dartType is LegacyType) {
DartType base = dartType.baseType;
// `Never*` accepts only `null`.
if (base is NeverType) return IsTestSpecialization.isNull;
// `Object*` is top and should be handled by constant folding.
if (base.isObject) return null;
- return _findIsTestSpecialization(base, graph, closedWorld);
+ return _findIsTestSpecialization(base, compiland, closedWorld);
}
- return _findIsTestSpecialization(dartType, graph, closedWorld);
+ return _findIsTestSpecialization(dartType, compiland, closedWorld);
}
static IsTestSpecialization _findIsTestSpecialization(
- DartType dartType, HGraph graph, JClosedWorld closedWorld) {
+ DartType dartType, MemberEntity compiland, JClosedWorld closedWorld) {
if (dartType is InterfaceType) {
ClassEntity element = dartType.element;
JCommonElements commonElements = closedWorld.commonElements;
@@ -101,7 +100,7 @@
classHierarchy.isInstantiated(element) &&
!interceptorData.isInterceptedClass(element) &&
outputUnitData.hasOnlyNonDeferredImportPathsToClass(
- graph.element, element)) {
+ compiland, element)) {
assert(!dartType.isObject); // Checked above.
return IsTestSpecialization.instanceof;
}
diff --git a/pkg/compiler/lib/src/js_model/closure.dart b/pkg/compiler/lib/src/js_model/closure.dart
index fad1f00..a08b941 100644
--- a/pkg/compiler/lib/src/js_model/closure.dart
+++ b/pkg/compiler/lib/src/js_model/closure.dart
@@ -19,9 +19,11 @@
import '../js_model/element_map.dart';
import '../js_model/env.dart';
import '../ordered_typeset.dart';
+import '../serialization/deferrable.dart';
import '../serialization/serialization.dart';
import '../universe/selector.dart';
import 'elements.dart';
+import 'jrecord_field_interface.dart';
import 'js_world_builder.dart' show JsClosedWorldBuilder;
class ClosureDataImpl implements ClosureData {
@@ -32,19 +34,35 @@
final JsToElementMap _elementMap;
/// Map of the scoping information that corresponds to a particular entity.
- final Map<MemberEntity, ScopeInfo> _scopeMap;
- final Map<ir.TreeNode, CapturedScope> _capturedScopesMap;
+ final Deferrable<Map<MemberEntity, ScopeInfo>> _scopeMap;
+ final Deferrable<Map<ir.TreeNode, CapturedScope>> _capturedScopesMap;
// Indicates the type variables (if any) that are captured in a given
// Signature function.
- final Map<MemberEntity, CapturedScope> _capturedScopeForSignatureMap;
+ final Deferrable<Map<MemberEntity, CapturedScope>>
+ _capturedScopeForSignatureMap;
- final Map<ir.LocalFunction, ClosureRepresentationInfo>
+ final Deferrable<Map<ir.LocalFunction, ClosureRepresentationInfo>>
_localClosureRepresentationMap;
final Map<MemberEntity, MemberEntity> _enclosingMembers;
ClosureDataImpl(
this._elementMap,
+ Map<MemberEntity, ScopeInfo> scopeMap,
+ Map<ir.TreeNode, CapturedScope> capturedScopesMap,
+ Map<MemberEntity, CapturedScope> capturedScopeForSignatureMap,
+ Map<ir.LocalFunction, ClosureRepresentationInfo>
+ localClosureRepresentationMap,
+ this._enclosingMembers)
+ : _scopeMap = Deferrable.eager(scopeMap),
+ _capturedScopesMap = Deferrable.eager(capturedScopesMap),
+ _capturedScopeForSignatureMap =
+ Deferrable.eager(capturedScopeForSignatureMap),
+ _localClosureRepresentationMap =
+ Deferrable.eager(localClosureRepresentationMap);
+
+ ClosureDataImpl._deserialized(
+ this._elementMap,
this._scopeMap,
this._capturedScopesMap,
this._capturedScopeForSignatureMap,
@@ -56,20 +74,20 @@
JsToElementMap elementMap, DataSourceReader source) {
source.begin(tag);
// TODO(johnniwinther): Support shared [ScopeInfo].
- Map<MemberEntity, ScopeInfo> scopeMap = source.readMemberMap(
- (MemberEntity member) => ScopeInfo.readFromDataSource(source));
- Map<ir.TreeNode, CapturedScope> capturedScopesMap =
- source.readTreeNodeMap(() => CapturedScope.readFromDataSource(source));
- Map<MemberEntity, CapturedScope> capturedScopeForSignatureMap =
+ final scopeMap = source.readDeferrable(() => source.readMemberMap(
+ (MemberEntity member) => ScopeInfo.readFromDataSource(source)));
+ final capturedScopesMap = source.readDeferrable(() =>
+ source.readTreeNodeMap(() => CapturedScope.readFromDataSource(source)));
+ final capturedScopeForSignatureMap = source.readDeferrable(() =>
source.readMemberMap(
- (MemberEntity member) => CapturedScope.readFromDataSource(source));
- Map<ir.LocalFunction, ClosureRepresentationInfo>
- localClosureRepresentationMap = source.readTreeNodeMap(
- () => ClosureRepresentationInfo.readFromDataSource(source));
+ (MemberEntity member) => CapturedScope.readFromDataSource(source)));
+ final localClosureRepresentationMap = source.readDeferrable(() =>
+ source.readTreeNodeMap<ir.LocalFunction, ClosureRepresentationInfo>(
+ () => ClosureRepresentationInfo.readFromDataSource(source)));
Map<MemberEntity, MemberEntity> enclosingMembers =
source.readMemberMap((member) => source.readMember());
source.end(tag);
- return ClosureDataImpl(
+ return ClosureDataImpl._deserialized(
elementMap,
scopeMap,
capturedScopesMap,
@@ -82,19 +100,21 @@
@override
void writeToDataSink(DataSinkWriter sink) {
sink.begin(tag);
- sink.writeMemberMap(_scopeMap,
- (MemberEntity member, ScopeInfo info) => info.writeToDataSink(sink));
- sink.writeTreeNodeMap(_capturedScopesMap, (CapturedScope scope) {
- scope.writeToDataSink(sink);
- });
- sink.writeMemberMap(
- _capturedScopeForSignatureMap,
+ sink.writeDeferrable(() => sink.writeMemberMap(_scopeMap.loaded(),
+ (MemberEntity member, ScopeInfo info) => info.writeToDataSink(sink)));
+ sink.writeDeferrable(() => sink.writeTreeNodeMap(
+ _capturedScopesMap.loaded(), (CapturedScope scope) {
+ scope.writeToDataSink(sink);
+ }));
+ sink.writeDeferrable(() => sink.writeMemberMap(
+ _capturedScopeForSignatureMap.loaded(),
(MemberEntity member, CapturedScope scope) =>
- scope.writeToDataSink(sink));
- sink.writeTreeNodeMap(_localClosureRepresentationMap,
- (ClosureRepresentationInfo info) {
- info.writeToDataSink(sink);
- });
+ scope.writeToDataSink(sink)));
+ sink.writeDeferrable(() => sink
+ .writeTreeNodeMap(_localClosureRepresentationMap.loaded(),
+ (ClosureRepresentationInfo info) {
+ info.writeToDataSink(sink);
+ }));
sink.writeMemberMap(_enclosingMembers,
(MemberEntity member, MemberEntity value) {
sink.writeMember(value);
@@ -112,7 +132,7 @@
entity = constructorBody.constructor;
}
- ScopeInfo scopeInfo = _scopeMap[entity];
+ ScopeInfo scopeInfo = _scopeMap.loaded()[entity];
assert(
scopeInfo != null, failedAt(entity, "Missing scope info for $entity."));
return scopeInfo;
@@ -128,9 +148,11 @@
case MemberKind.constructor:
case MemberKind.constructorBody:
case MemberKind.closureCall:
- return _capturedScopesMap[definition.node] ?? const CapturedScope();
+ return _capturedScopesMap.loaded()[definition.node] ??
+ const CapturedScope();
case MemberKind.signature:
- return _capturedScopeForSignatureMap[entity] ?? const CapturedScope();
+ return _capturedScopeForSignatureMap.loaded()[entity] ??
+ const CapturedScope();
default:
throw failedAt(entity, "Unexpected member definition $definition");
}
@@ -140,15 +162,15 @@
// TODO(efortuna): Eventually capturedScopesMap[node] should always
// be non-null, and we should just test that with an assert.
CapturedLoopScope getCapturedLoopScope(ir.Node loopNode) =>
- _capturedScopesMap[loopNode] ?? const CapturedLoopScope();
+ _capturedScopesMap.loaded()[loopNode] ?? const CapturedLoopScope();
@override
ClosureRepresentationInfo getClosureInfo(ir.LocalFunction node) {
- var closure = _localClosureRepresentationMap[node];
+ var closure = _localClosureRepresentationMap.loaded()[node];
assert(
closure != null,
"Corresponding closure class not found for $node. "
- "Closures found for ${_localClosureRepresentationMap.keys}");
+ "Closures found for ${_localClosureRepresentationMap.loaded().keys}");
return closure;
}
@@ -1065,7 +1087,7 @@
/// A variable that has been "boxed" to prevent name shadowing with the
/// original variable and ensure that this variable is updated/read with the
/// most recent value.
-class JRecordField extends JField {
+class JRecordField extends JField implements JRecordFieldInterface {
/// Tag used for identifying serialized [JRecordField] objects in a
/// debugging data stream.
static const String tag = 'record-field';
@@ -1209,7 +1231,8 @@
final FunctionType functionType;
@override
- final ir.FunctionNode functionNode;
+ ir.FunctionNode get functionNode => _functionNode.loaded();
+ final Deferrable<ir.FunctionNode> _functionNode;
@override
final ClassTypeVariableAccess classTypeVariableAccess;
@@ -1219,7 +1242,16 @@
ClosureMemberDefinition definition,
InterfaceType memberThisType,
this.functionType,
- this.functionNode,
+ ir.FunctionNode functionNode,
+ this.classTypeVariableAccess)
+ : _functionNode = Deferrable.eager(functionNode),
+ super(definition, memberThisType);
+
+ ClosureFunctionData._deserialized(
+ ClosureMemberDefinition definition,
+ InterfaceType memberThisType,
+ this.functionType,
+ this._functionNode,
this.classTypeVariableAccess)
: super(definition, memberThisType);
@@ -1230,12 +1262,13 @@
InterfaceType /*?*/ memberThisType =
source.readDartTypeOrNull() as InterfaceType /*?*/;
FunctionType functionType = source.readDartType();
- ir.FunctionNode functionNode = source.readTreeNode();
+ Deferrable<ir.FunctionNode> functionNode =
+ source.readDeferrable(() => source.readTreeNode());
ClassTypeVariableAccess classTypeVariableAccess =
source.readEnum(ClassTypeVariableAccess.values);
source.end(tag);
- return ClosureFunctionData(definition, memberThisType, functionType,
- functionNode, classTypeVariableAccess);
+ return ClosureFunctionData._deserialized(definition, memberThisType,
+ functionType, functionNode, classTypeVariableAccess);
}
@override
@@ -1245,7 +1278,7 @@
definition.writeToDataSink(sink);
sink.writeDartTypeOrNull(memberThisType);
sink.writeDartType(functionType);
- sink.writeTreeNode(functionNode);
+ sink.writeDeferrable(() => sink.writeTreeNode(functionNode));
sink.writeEnum(classTypeVariableAccess);
sink.end(tag);
}
@@ -1338,9 +1371,15 @@
@override
final MemberKind kind;
@override
- final ir.TreeNode node;
+ ir.TreeNode get node => _node.loaded();
+ final Deferrable<ir.TreeNode> _node;
- ClosureMemberDefinition(this.location, this.kind, this.node)
+ ClosureMemberDefinition(this.location, this.kind, ir.TreeNode node)
+ : _node = Deferrable.eager(node),
+ assert(
+ kind == MemberKind.closureCall || kind == MemberKind.closureField);
+
+ ClosureMemberDefinition._deserialized(this.location, this.kind, this._node)
: assert(
kind == MemberKind.closureCall || kind == MemberKind.closureField);
@@ -1348,9 +1387,10 @@
DataSourceReader source, MemberKind kind) {
source.begin(tag);
SourceSpan location = source.readSourceSpan();
- ir.TreeNode node = source.readTreeNode();
+ Deferrable<ir.TreeNode> node =
+ source.readDeferrable(() => source.readTreeNode());
source.end(tag);
- return ClosureMemberDefinition(location, kind, node);
+ return ClosureMemberDefinition._deserialized(location, kind, node);
}
@override
@@ -1358,7 +1398,7 @@
sink.writeEnum(kind);
sink.begin(tag);
sink.writeSourceSpan(location);
- sink.writeTreeNode(node);
+ sink.writeDeferrable(() => sink.writeTreeNode(node));
sink.end(tag);
}
diff --git a/pkg/compiler/lib/src/js_model/element_map.dart b/pkg/compiler/lib/src/js_model/element_map.dart
index 9ba22fe..5de2c8d 100644
--- a/pkg/compiler/lib/src/js_model/element_map.dart
+++ b/pkg/compiler/lib/src/js_model/element_map.dart
@@ -20,6 +20,7 @@
import '../js_model/class_type_variable_access.dart';
import '../js_model/elements.dart' show JGeneratorBody;
import '../native/behavior.dart';
+import '../serialization/deferrable.dart';
import '../serialization/serialization.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
@@ -413,25 +414,30 @@
static const String tag = 'special-member-definition';
@override
- final ir.TreeNode node;
+ ir.TreeNode get node => _node.loaded();
+ final Deferrable<ir.TreeNode> _node;
@override
final MemberKind kind;
- SpecialMemberDefinition(this.node, this.kind);
+ SpecialMemberDefinition(ir.TreeNode node, this.kind)
+ : _node = Deferrable.eager(node);
+
+ SpecialMemberDefinition._deserialized(this._node, this.kind);
factory SpecialMemberDefinition.readFromDataSource(
DataSourceReader source, MemberKind kind) {
source.begin(tag);
- ir.TreeNode node = source.readTreeNode();
+ Deferrable<ir.TreeNode> node =
+ source.readDeferrable(() => source.readTreeNode());
source.end(tag);
- return SpecialMemberDefinition(node, kind);
+ return SpecialMemberDefinition._deserialized(node, kind);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(kind);
sink.begin(tag);
- sink.writeTreeNode(node);
+ sink.writeDeferrable(() => sink.writeTreeNode(node));
sink.end(tag);
}
diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart
index c794980..149eb78 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -394,6 +394,8 @@
source.begin(typeVariableDataTag);
entityLookup.forEachTypeVariable((int index, JTypeVariable typeVariable) {
+ // TODO(natebiggs): Defer reading these type variables as they trigger
+ // loading of some method bodies in the Kernel AST.
JTypeVariableData data = JTypeVariableData.readFromDataSource(source);
typeVariableMap[data.node] =
typeVariables.registerByIndex(index, typeVariable, data);
diff --git a/pkg/compiler/lib/src/js_model/env.dart b/pkg/compiler/lib/src/js_model/env.dart
index b2a9bd3..0bf7e80 100644
--- a/pkg/compiler/lib/src/js_model/env.dart
+++ b/pkg/compiler/lib/src/js_model/env.dart
@@ -17,6 +17,7 @@
import '../ir/util.dart';
import '../js_model/class_type_variable_access.dart';
import '../ordered_typeset.dart';
+import '../serialization/deferrable.dart';
import '../serialization/serialization.dart';
import 'closure.dart';
import 'element_map.dart';
@@ -574,9 +575,13 @@
final MemberDefinition definition;
@override
- final StaticTypeCache staticTypes;
+ StaticTypeCache get staticTypes => _staticTypes.loaded();
+ final Deferrable<StaticTypeCache> _staticTypes;
- JMemberDataImpl(this.node, this.definition, this.staticTypes);
+ JMemberDataImpl(this.node, this.definition, StaticTypeCache staticTypes)
+ : _staticTypes = Deferrable.eager(staticTypes);
+
+ JMemberDataImpl._deserialized(this.node, this.definition, this._staticTypes);
@override
InterfaceType getMemberThisType(JsToElementMap elementMap) {
@@ -691,6 +696,10 @@
MemberDefinition definition, StaticTypeCache staticTypes)
: super(node, definition, staticTypes);
+ FunctionDataImpl._deserialized(ir.Member node, this.functionNode,
+ MemberDefinition definition, Deferrable<StaticTypeCache> staticTypes)
+ : super._deserialized(node, definition, staticTypes);
+
factory FunctionDataImpl.readFromDataSource(DataSourceReader source) {
source.begin(tag);
ir.Member node = source.readMemberNode();
@@ -704,10 +713,11 @@
"Unexpected member node $node (${node.runtimeType}).");
}
MemberDefinition definition = MemberDefinition.readFromDataSource(source);
- StaticTypeCache staticTypes =
- StaticTypeCache.readFromDataSource(source, node);
+ Deferrable<StaticTypeCache> staticTypes = source
+ .readDeferrable(() => StaticTypeCache.readFromDataSource(source, node));
source.end(tag);
- return FunctionDataImpl(node, functionNode, definition, staticTypes);
+ return FunctionDataImpl._deserialized(
+ node, functionNode, definition, staticTypes);
}
@override
@@ -716,7 +726,7 @@
sink.begin(tag);
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
- staticTypes.writeToDataSink(sink, node);
+ sink.writeDeferrable(() => staticTypes.writeToDataSink(sink, node));
sink.end(tag);
}
@@ -745,21 +755,27 @@
final InterfaceType memberThisType;
@override
final ClassTypeVariableAccess classTypeVariableAccess;
- final List<ir.TypeParameter> typeParameters;
+ List<ir.TypeParameter> get typeParameters => _typeParameters.loaded();
+ final Deferrable<List<ir.TypeParameter>> _typeParameters;
SignatureFunctionData(this.definition, this.memberThisType,
- this.typeParameters, this.classTypeVariableAccess);
+ List<ir.TypeParameter> typeParameters, this.classTypeVariableAccess)
+ : _typeParameters = Deferrable.eager(typeParameters);
+
+ SignatureFunctionData._deserialized(this.definition, this.memberThisType,
+ this._typeParameters, this.classTypeVariableAccess);
factory SignatureFunctionData.readFromDataSource(DataSourceReader source) {
source.begin(tag);
MemberDefinition definition = MemberDefinition.readFromDataSource(source);
InterfaceType /*?*/ memberThisType =
source.readDartTypeOrNull() as InterfaceType /*?*/;
- List<ir.TypeParameter> typeParameters = source.readTypeParameterNodes();
+ Deferrable<List<ir.TypeParameter>> typeParameters =
+ source.readDeferrable(() => source.readTypeParameterNodes());
ClassTypeVariableAccess classTypeVariableAccess =
source.readEnum(ClassTypeVariableAccess.values);
source.end(tag);
- return SignatureFunctionData(
+ return SignatureFunctionData._deserialized(
definition, memberThisType, typeParameters, classTypeVariableAccess);
}
@@ -769,7 +785,7 @@
sink.begin(tag);
definition.writeToDataSink(sink);
sink.writeDartTypeOrNull(memberThisType);
- sink.writeTypeParameterNodes(typeParameters);
+ sink.writeDeferrable(() => sink.writeTypeParameterNodes(typeParameters));
sink.writeEnum(classTypeVariableAccess);
sink.end(tag);
}
@@ -891,6 +907,13 @@
MemberDefinition definition, StaticTypeCache staticTypes)
: super(node, functionNode, definition, staticTypes);
+ JConstructorDataImpl._deserialized(
+ ir.Member node,
+ ir.FunctionNode functionNode,
+ MemberDefinition definition,
+ Deferrable<StaticTypeCache> staticTypes)
+ : super._deserialized(node, functionNode, definition, staticTypes);
+
factory JConstructorDataImpl.readFromDataSource(DataSourceReader source) {
source.begin(tag);
ir.Member node = source.readMemberNode();
@@ -904,10 +927,11 @@
"Unexpected member node $node (${node.runtimeType}).");
}
MemberDefinition definition = MemberDefinition.readFromDataSource(source);
- StaticTypeCache staticTypes =
- StaticTypeCache.readFromDataSource(source, node);
+ Deferrable<StaticTypeCache> staticTypes = source
+ .readDeferrable(() => StaticTypeCache.readFromDataSource(source, node));
source.end(tag);
- return JConstructorDataImpl(node, functionNode, definition, staticTypes);
+ return JConstructorDataImpl._deserialized(
+ node, functionNode, definition, staticTypes);
}
@override
@@ -917,7 +941,7 @@
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
assert(constructorBody == null);
- staticTypes.writeToDataSink(sink, node);
+ sink.writeDeferrable(() => staticTypes.writeToDataSink(sink, node));
sink.end(tag);
}
@@ -935,6 +959,13 @@
MemberDefinition definition, StaticTypeCache staticTypes)
: super(node, functionNode, definition, staticTypes);
+ ConstructorBodyDataImpl._deserialized(
+ ir.Member node,
+ ir.FunctionNode functionNode,
+ MemberDefinition definition,
+ Deferrable<StaticTypeCache> staticTypes)
+ : super._deserialized(node, functionNode, definition, staticTypes);
+
factory ConstructorBodyDataImpl.readFromDataSource(DataSourceReader source) {
source.begin(tag);
ir.Member node = source.readMemberNode();
@@ -948,10 +979,11 @@
"Unexpected member node $node (${node.runtimeType}).");
}
MemberDefinition definition = MemberDefinition.readFromDataSource(source);
- StaticTypeCache staticTypes =
- StaticTypeCache.readFromDataSource(source, node);
+ Deferrable<StaticTypeCache> staticTypes = source
+ .readDeferrable(() => StaticTypeCache.readFromDataSource(source, node));
source.end(tag);
- return ConstructorBodyDataImpl(node, functionNode, definition, staticTypes);
+ return ConstructorBodyDataImpl._deserialized(
+ node, functionNode, definition, staticTypes);
}
@override
@@ -960,7 +992,7 @@
sink.begin(tag);
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
- staticTypes.writeToDataSink(sink, node);
+ sink.writeDeferrable(() => staticTypes.writeToDataSink(sink, node));
sink.end(tag);
}
@@ -986,14 +1018,18 @@
ir.Field node, MemberDefinition definition, StaticTypeCache staticTypes)
: super(node, definition, staticTypes);
+ JFieldDataImpl._deserialized(ir.Field node, MemberDefinition definition,
+ Deferrable<StaticTypeCache> staticTypes)
+ : super._deserialized(node, definition, staticTypes);
+
factory JFieldDataImpl.readFromDataSource(DataSourceReader source) {
source.begin(tag);
ir.Member node = source.readMemberNode();
MemberDefinition definition = MemberDefinition.readFromDataSource(source);
- StaticTypeCache staticTypes =
- StaticTypeCache.readFromDataSource(source, node);
+ Deferrable<StaticTypeCache> staticTypes = source
+ .readDeferrable(() => StaticTypeCache.readFromDataSource(source, node));
source.end(tag);
- return JFieldDataImpl(node, definition, staticTypes);
+ return JFieldDataImpl._deserialized(node, definition, staticTypes);
}
@override
@@ -1002,7 +1038,7 @@
sink.begin(tag);
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
- staticTypes.writeToDataSink(sink, node);
+ sink.writeDeferrable(() => staticTypes.writeToDataSink(sink, node));
sink.end(tag);
}
diff --git a/pkg/compiler/lib/src/js_model/jrecord_field_interface.dart b/pkg/compiler/lib/src/js_model/jrecord_field_interface.dart
new file mode 100644
index 0000000..17f3bd0
--- /dev/null
+++ b/pkg/compiler/lib/src/js_model/jrecord_field_interface.dart
@@ -0,0 +1,6 @@
+// Copyright (c) 2022, 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.
+
+// TODO(48820): delete this class once migration is complete.
+abstract class JRecordFieldInterface {}
diff --git a/pkg/compiler/lib/src/js_model/locals.dart b/pkg/compiler/lib/src/js_model/locals.dart
index f76178a..7cdd82c 100644
--- a/pkg/compiler/lib/src/js_model/locals.dart
+++ b/pkg/compiler/lib/src/js_model/locals.dart
@@ -14,6 +14,7 @@
import '../elements/indexed.dart';
import '../elements/jumps.dart';
import '../elements/types.dart';
+import '../serialization/deferrable.dart';
import '../serialization/serialization.dart';
import 'element_map.dart';
@@ -43,18 +44,19 @@
MemberEntity Function(MemberEntity) localMapKeyLookup,
DataSourceReader source) {
source.begin(tag);
- Map<MemberEntity, KernelToLocalsMap> _localsMaps = {};
+ Map<MemberEntity, Deferrable<KernelToLocalsMap>> _localsMaps = {};
int mapCount = source.readInt();
for (int i = 0; i < mapCount; i++) {
- KernelToLocalsMap localsMap =
- KernelToLocalsMapImpl.readFromDataSource(source);
+ Deferrable<KernelToLocalsMap> localsMap = source.readDeferrable(
+ () => KernelToLocalsMapImpl.readFromDataSource(source));
List<MemberEntity> members = source.readMembers();
for (MemberEntity member in members) {
_localsMaps[member] = localsMap;
}
}
source.end(tag);
- return GlobalLocalsMap.internal(localMapKeyLookup, _localsMaps);
+ return GlobalLocalsMap.internal(
+ localMapKeyLookup, DeferrableValueMap(_localsMaps));
}
/// Serializes this [GlobalLocalsMap] to [sink].
@@ -72,7 +74,7 @@
sink.writeInt(reverseMap.length);
reverseMap
.forEach((KernelToLocalsMap localsMap, List<MemberEntity> members) {
- localsMap.writeToDataSink(sink);
+ sink.writeDeferrable(() => localsMap.writeToDataSink(sink));
sink.writeMembers(members);
});
sink.end(tag);
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index 3c1e721..563f4a5 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.10
-
import '../common.dart';
import '../common/elements.dart' show CommonElements, ElementEnvironment;
import '../constants/values.dart';
@@ -20,7 +18,7 @@
import 'native_throw_behavior.dart';
export 'native_throw_behavior.dart';
-typedef TypeLookup = Object /*DartType|SpecialType*/
+typedef TypeLookup = Object? /*DartType|SpecialType*/
Function(String typeString, {bool required});
/// This class is a temporary work-around until we get a more powerful DartType.
@@ -87,10 +85,10 @@
/// element.
final List<Object> typesInstantiated = [];
- String codeTemplateText;
+ String? codeTemplateText;
// If this behavior is for a JS expression, [codeTemplate] contains the
// parsed tree.
- js.Template codeTemplate;
+ js.Template? codeTemplate;
final SideEffects sideEffects;
@@ -128,7 +126,7 @@
List<Object> typesReturned = readTypes();
List<Object> typesInstantiated = readTypes();
- String codeTemplateText = source.readStringOrNull();
+ String? codeTemplateText = source.readStringOrNull();
SideEffects sideEffects = SideEffects.readFromDataSource(source);
int throwBehavior = source.readInt();
bool isAllocation = source.readBool();
@@ -160,7 +158,7 @@
if (type is DartType) {
dartTypes.add(type);
} else {
- specialTypes.add(type);
+ specialTypes.add(type as SpecialType);
}
}
sink.writeDartTypes(dartTypes);
@@ -284,14 +282,14 @@
/// [validTags] can be used to restrict which tags are accepted.
static void processSpecString(DartTypes dartTypes,
DiagnosticReporter reporter, Spannable spannable, String specString,
- {Iterable<String> validTags,
- void setSideEffects(SideEffects newEffects),
- void setThrows(NativeThrowBehavior throwKind),
- void setIsAllocation(bool isAllocation),
- void setUseGvn(bool useGvn),
- TypeLookup lookupType,
- List<Object> typesReturned,
- List<Object> typesInstantiated,
+ {Iterable<String>? validTags,
+ required void setSideEffects(SideEffects newEffects),
+ void Function(NativeThrowBehavior)? setThrows,
+ void Function(bool)? setIsAllocation,
+ void Function(bool)? setUseGvn,
+ required TypeLookup lookupType,
+ required List<Object> typesReturned,
+ required List<Object> typesInstantiated,
objectType,
nullType}) {
bool seenError = false;
@@ -317,7 +315,9 @@
/// * '' or 'var' - in which case [onVar] is called,
/// * 'T1|...|Tn' - in which case [onType] is called for each resolved Ti.
void resolveTypesString(DartTypes dartTypes, String typesString,
- {onVoid(), onVar(), onType(type)}) {
+ {void Function()? onVoid,
+ void Function()? onVar,
+ required void Function(Object) onType}) {
// Various things that are not in fact types.
if (typesString == 'void') {
if (onVoid != null) {
@@ -382,11 +382,8 @@
}
// Enum-like tags are looked up in a map. True signature is:
- //
- // T tagValueLookup<T>(String tag, Map<String, T> map);
- //
- dynamic tagValueLookup(String tag, Map<String, dynamic> map) {
- String tagString = values[tag];
+ T? tagValueLookup<T>(String tag, Map<String, T> map) {
+ String? tagString = values[tag];
if (tagString == null) return null;
var value = map[tagString];
if (value == null) {
@@ -395,7 +392,7 @@
return value;
}
- String returns = values['returns'];
+ String? returns = values['returns'];
if (returns != null) {
resolveTypesString(dartTypes, returns, onVar: () {
typesReturned.add(objectType);
@@ -405,7 +402,7 @@
});
}
- String creates = values['creates'];
+ String? creates = values['creates'];
if (creates != null) {
resolveTypesString(dartTypes, creates, onVoid: () {
reportError("Invalid type string 'creates:$creates'");
@@ -427,11 +424,11 @@
const boolOptions = <String, bool>{'true': true, 'false': false};
- SideEffects sideEffects =
+ SideEffects? sideEffects =
processEffects(reportError, values['effects'], values['depends']);
- NativeThrowBehavior throwsKind = tagValueLookup('throws', throwsOption);
- bool isAllocation = tagValueLookup('new', boolOptions);
- bool useGvn = tagValueLookup('gvn', boolOptions);
+ NativeThrowBehavior? throwsKind = tagValueLookup('throws', throwsOption);
+ bool? isAllocation = tagValueLookup('new', boolOptions);
+ bool? useGvn = tagValueLookup('gvn', boolOptions);
if (isAllocation == true && useGvn == true) {
reportError("'new' and 'gvn' are incompatible");
@@ -442,13 +439,31 @@
// TODO(sra): Simplify [throwBehavior] using [sideEffects].
if (sideEffects != null) setSideEffects(sideEffects);
- if (throwsKind != null) setThrows(throwsKind);
- if (isAllocation != null) setIsAllocation(isAllocation);
- if (useGvn != null) setUseGvn(useGvn);
+ if (throwsKind != null) {
+ if (setThrows == null) {
+ reportError("'throws' not allowed here");
+ } else {
+ setThrows(throwsKind);
+ }
+ }
+ if (isAllocation != null) {
+ if (setIsAllocation == null) {
+ reportError("'allocation' not allowed here");
+ } else {
+ setIsAllocation(isAllocation);
+ }
+ }
+ if (useGvn != null) {
+ if (setUseGvn == null) {
+ reportError("'gvn' not allowed here");
+ } else {
+ setUseGvn(useGvn);
+ }
+ }
}
- static SideEffects processEffects(
- void reportError(String message), String effects, String depends) {
+ static SideEffects? processEffects(
+ void reportError(String message), String? effects, String? depends) {
if (effects == null && depends == null) return null;
if (effects == null || depends == null) {
@@ -530,7 +545,7 @@
NativeBehavior behavior = NativeBehavior();
behavior.codeTemplateText = codeString;
- behavior.codeTemplate = js.js.parseForeignJS(behavior.codeTemplateText);
+ behavior.codeTemplate = js.js.parseForeignJS(codeString);
bool sideEffectsAreEncodedInSpecString = false;
@@ -565,11 +580,12 @@
nullType: commonElements.nullType);
if (!sideEffectsAreEncodedInSpecString) {
- SideEffectsVisitor(behavior.sideEffects).visit(behavior.codeTemplate.ast);
+ SideEffectsVisitor(behavior.sideEffects)
+ .visit(behavior.codeTemplate!.ast);
}
if (!throwBehaviorFromSpecString) {
behavior.throwBehavior =
- ThrowBehaviorVisitor().analyze(behavior.codeTemplate.ast);
+ ThrowBehaviorVisitor().analyze(behavior.codeTemplate!.ast);
}
return behavior;
@@ -582,7 +598,7 @@
TypeLookup lookupType,
DiagnosticReporter reporter,
CommonElements commonElements,
- {List<String> validTags}) {
+ {List<String>? validTags}) {
void setSideEffects(SideEffects newEffects) {
behavior.sideEffects.setTo(newEffects);
}
@@ -628,7 +644,7 @@
return behavior;
}
- static dynamic /*DartType|SpecialType*/ _parseType(
+ static Object /*DartType|SpecialType*/ _parseType(
DartTypes dartTypes, String typeString, TypeLookup lookupType) {
if (typeString == '=Object') return SpecialType.JsObject;
if (typeString == 'dynamic') {
@@ -685,7 +701,7 @@
final CompilerOptions options;
DartTypes get dartTypes => commonElements.dartTypes;
- NativeBehavior _behavior;
+ late NativeBehavior _behavior;
BehaviorBuilder(this.elementEnvironment, this.commonElements,
this.nativeBasicData, this.reporter, this.options);
@@ -694,8 +710,8 @@
Iterable<String> returnsAnnotations, TypeLookup lookupType) {
if (createsAnnotations.isEmpty && returnsAnnotations.isEmpty) return;
- List<Object> creates = _collect(createsAnnotations, lookupType);
- List<Object> returns = _collect(returnsAnnotations, lookupType);
+ List<Object>? creates = _collect(createsAnnotations, lookupType);
+ List<Object>? returns = _collect(returnsAnnotations, lookupType);
if (creates != null) {
_behavior.typesInstantiated
@@ -712,14 +728,13 @@
/// Returns a list of type constraints from the annotations of
/// [annotationClass].
/// Returns `null` if no constraints.
- List<dynamic> _collect(Iterable<String> annotations, TypeLookup lookupType) {
- List<dynamic> types = null;
+ List<Object>? _collect(Iterable<String> annotations, TypeLookup lookupType) {
+ List<Object>? types = null;
for (String specString in annotations) {
for (final typeString in specString.split('|')) {
var type = NativeBehavior._parseType(
commonElements.dartTypes, typeString, lookupType);
- if (types == null) types = [];
- types.add(type);
+ (types ??= []).add(type);
}
}
return types;
@@ -804,7 +819,7 @@
Iterable<String> createsAnnotations,
Iterable<String> returnsAnnotations,
TypeLookup lookupType,
- {bool isJsInterop}) {
+ {required bool isJsInterop}) {
_behavior = NativeBehavior();
// TODO(sigmund,sra): consider doing something better for numeric types.
_addReturnType(!isJsInterop ? type : commonElements.dynamicType);
@@ -829,7 +844,7 @@
Iterable<String> createAnnotations,
Iterable<String> returnsAnnotations,
TypeLookup lookupType,
- {bool isJsInterop}) {
+ {required bool isJsInterop}) {
_behavior = NativeBehavior();
DartType returnType = type.returnType;
// Note: For dart:html and other internal libraries we maintain, we can
diff --git a/pkg/compiler/lib/src/serialization/binary_sink.dart b/pkg/compiler/lib/src/serialization/binary_sink.dart
index c408ccc..01e6d89 100644
--- a/pkg/compiler/lib/src/serialization/binary_sink.dart
+++ b/pkg/compiler/lib/src/serialization/binary_sink.dart
@@ -13,6 +13,7 @@
final Sink<List<int>> sink;
// Nullable and non-final to allow storage to be released.
BufferedSink? _bufferedSink;
+ final Map<int, int> _deferredOffsetToSize = {};
int _length = 0;
BinaryDataSink(this.sink) : _bufferedSink = BufferedSink(sink);
@@ -54,6 +55,21 @@
}
}
+ void _writeUInt32(int value) {
+ _length += 4;
+ _bufferedSink!.addByte4((value >> 24) & 0xFF, (value >> 16) & 0xFF,
+ (value >> 8) & 0xFF, value & 0xFF);
+ }
+
+ @override
+ void writeDeferred(void writer()) {
+ final indexOffset = _length;
+ writeInt(0); // Padding so the offset won't collide with a nested write.
+ final dataStartOffset = _length;
+ writer();
+ _deferredOffsetToSize[indexOffset] = _length - dataStartOffset;
+ }
+
@override
void writeEnum(dynamic value) {
writeInt(value.index);
@@ -61,8 +77,16 @@
@override
void close() {
+ final deferredDataStart = _length;
+ writeInt(_deferredOffsetToSize.length);
+ for (final entry in _deferredOffsetToSize.entries) {
+ writeInt(entry.key);
+ writeInt(entry.value);
+ }
+ _writeUInt32(deferredDataStart);
_bufferedSink!.flushAndDestroy();
_bufferedSink = null;
+ _deferredOffsetToSize.clear();
sink.close();
}
}
diff --git a/pkg/compiler/lib/src/serialization/binary_source.dart b/pkg/compiler/lib/src/serialization/binary_source.dart
index 12ecd79..3d8ba61 100644
--- a/pkg/compiler/lib/src/serialization/binary_source.dart
+++ b/pkg/compiler/lib/src/serialization/binary_source.dart
@@ -14,10 +14,22 @@
int _byteOffset = 0;
final List<int> _bytes;
final StringInterner? _stringInterner;
+ late final Map<int, int> _deferredOffsetToSize;
BinaryDataSource(this._bytes, {StringInterner? stringInterner})
: _stringInterner = stringInterner {
assert((_bytes as dynamic) != null); // TODO(48820): Remove when sound.
+ final deferredDataStart = readAtOffset(_bytes.length - 4, _readUint32);
+ _deferredOffsetToSize = readAtOffset(deferredDataStart, () {
+ final deferredSizesCount = readInt();
+ final result = <int, int>{};
+ for (var i = 0; i < deferredSizesCount; i++) {
+ final offset = readInt();
+ final size = readInt();
+ result[offset] = size;
+ }
+ return result;
+ });
}
@override
@@ -76,6 +88,29 @@
return value;
}
+ int _readUint32() {
+ return (_readByte() << 24) |
+ (_readByte() << 16) |
+ (_readByte() << 8) |
+ _readByte();
+ }
+
+ @override
+ int readDeferred() {
+ final indexOffset = _byteOffset;
+ readInt(); // Read collision padding.
+ final dataOffset = _byteOffset;
+ final dataLength = _deferredOffsetToSize[indexOffset]!;
+ _byteOffset += dataLength;
+ return dataOffset;
+ }
+
+ @override
+ E readDeferredAsEager<E>(E reader()) {
+ readInt(); // Read collision padding.
+ return reader();
+ }
+
@override
int get length => _bytes.length;
diff --git a/pkg/compiler/lib/src/serialization/data_sink.dart b/pkg/compiler/lib/src/serialization/data_sink.dart
index b87ebcd..ef8cc8b 100644
--- a/pkg/compiler/lib/src/serialization/data_sink.dart
+++ b/pkg/compiler/lib/src/serialization/data_sink.dart
@@ -25,6 +25,10 @@
/// Serialization of a section end tag. May be omitted by some writers.
void endTag(String tag);
+ /// Writes a deferred entity which can be skipped when reading and read later
+ /// via an offset read.
+ void writeDeferred(void writer());
+
/// Closes any underlying data sinks.
void close();
}
diff --git a/pkg/compiler/lib/src/serialization/data_source.dart b/pkg/compiler/lib/src/serialization/data_source.dart
index 9ebc18b..dec8bab 100644
--- a/pkg/compiler/lib/src/serialization/data_source.dart
+++ b/pkg/compiler/lib/src/serialization/data_source.dart
@@ -22,8 +22,15 @@
/// Deserialization of an enum value in [values].
E readEnum<E>(List<E> values);
+ /// Returns the offset for a deferred entity and skips it in the read queue.
+ /// The offset can later be passed to [readAtOffset] to get the value.
+ int readDeferred();
+
+ /// Eagerly reads and returns the value for a deferred entity.
+ E readDeferredAsEager<E>(E reader());
+
/// Calls [reader] to read a value at the provided offset in the underlying
- /// data stream.
+ /// data stream. Use with [readDeferred] to read a deferred value.
E readAtOffset<E>(int offset, E reader());
/// The length of the underlying data source.
diff --git a/pkg/compiler/lib/src/serialization/deferrable.dart b/pkg/compiler/lib/src/serialization/deferrable.dart
new file mode 100644
index 0000000..9b84e93
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/deferrable.dart
@@ -0,0 +1,146 @@
+// Copyright (c) 2022, 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:collection';
+
+import 'package:compiler/src/serialization/serialization_interfaces.dart';
+
+/// Interface for data that may be deserialized lazily.
+///
+/// This interface should be used to wrap data objects that aren't needed in
+/// later phases of the compiler. Usage of this class should follow a set
+/// pattern. Given a class `C` with a field `m0` of type `E` that we wish to
+/// make deferrable:
+///
+/// 1) `m0` should be replaced with an internal field, `_m1`, of type
+/// `Deferrable<E>`.
+/// 2) An internal constructor should be added to `C` that takes a `d` of type
+/// `Deferrable<E>` to initialize `_m1`. This internal constructor should be
+/// called from the readFromSource method/factory to create the instance
+/// of `C`. `d` should be obtained using [DataSourceReader.readDeferrable].
+/// 3) Any existing constructors of `C` should maintain the same signature
+/// and initialize `_m1` passing `m` to [Deferrable.eager] where m is the value
+/// previously used to initialize `m0`.
+/// 4) If there are external references to `m0` then `C`s interface should be
+/// maintained. A getter `m0` should be added: `E get m0 => _m1.loaded()`
+/// 5) If all references to `m0` were internal, they can simply be replaced
+/// with calls to `_m1.loaded()`.
+///
+/// Example class before:
+///
+/// class Foo {
+/// final Bar bar;
+///
+/// Foo(this.bar);
+///
+/// factory Foo.readFromSource(DataSourceReader reader) {
+/// return Foo(Bar.readFromSource(reader));
+/// }
+/// }
+///
+/// After:
+///
+/// class Foo {
+/// Bar get bar => _bar.loaded();
+/// final Deferrable<Bar> _bar;
+///
+/// Foo(Bar bar) : _bar = Deferrable.eager(bar);
+/// Foo._deserialized(this._bar);
+///
+/// factory Foo.readFromSource(DataSourceReader reader) {
+/// return Foo._deserialized(
+/// reader.readDeferrable(() => Bar.readFromSource(reader)));
+/// }
+/// }
+abstract class Deferrable<E> {
+ E loaded();
+ static int count = 0;
+
+ factory Deferrable.deferred(DataSourceReader reader, E f(), int offset,
+ {bool cacheData = true}) =>
+ cacheData
+ ? _DeferredCache(reader, f, offset)
+ : _Deferred(reader, f, offset);
+ const factory Deferrable.eager(E data) = _Eager;
+
+ const Deferrable();
+}
+
+class _Eager<E> extends Deferrable<E> {
+ final E _data;
+ @override
+ E loaded() => _data;
+ const _Eager(this._data);
+}
+
+class _Deferred<E> extends Deferrable<E> {
+ final DataSourceReader _reader;
+ final E Function() _dataLoader;
+ final int _dataOffset;
+ @override
+ E loaded() => _reader.readWithOffset(_dataOffset, _dataLoader);
+ _Deferred(this._reader, this._dataLoader, this._dataOffset);
+}
+
+class _DeferredCache<E> extends Deferrable<E> {
+ final int _dataOffset;
+ // Below fields are nullable so they can be cleared after loading.
+ DataSourceReader? _reader;
+ E Function()? _dataLoader;
+ late final E _data = _loadData();
+
+ @override
+ E loaded() => _data;
+
+ E _loadData() {
+ final reader = _reader!;
+ final dataLoader = _dataLoader!;
+ _reader = null;
+ _dataLoader = null;
+ return reader.readWithOffset(_dataOffset, dataLoader);
+ }
+
+ _DeferredCache(this._reader, this._dataLoader, this._dataOffset);
+}
+
+/// Implementation of [Map] in which each value of type [V] is internally
+/// [Deferrable].
+///
+/// This map should be used when values of type [V] are expensive to
+/// deserialize. This abstracts away the laziness allowing the deferred map to
+/// be used as if the values were not deferred.
+///
+/// The provided map can have a mix of eager and lazy [Deferrable]s if
+/// there are a mix of expensive and cheap values.
+class DeferrableValueMap<K, V> with MapMixin<K, V> {
+ DeferrableValueMap(this._map);
+ final Map<K, Deferrable<V>> _map;
+ @override
+ V? operator [](Object? key) {
+ return _map[key]?.loaded();
+ }
+
+ @override
+ void operator []=(K key, V value) {
+ _map[key] = Deferrable.eager(value);
+ }
+
+ @override
+ void clear() {
+ _map.clear();
+ }
+
+ @override
+ Iterable<K> get keys => _map.keys;
+
+ @override
+ V? remove(Object? key) {
+ return _map.remove(key)?.loaded();
+ }
+
+ @override
+ V putIfAbsent(K key, V ifAbsent()) {
+ return _map.putIfAbsent(key, () => Deferrable.eager(ifAbsent())).loaded();
+ }
+}
diff --git a/pkg/compiler/lib/src/serialization/object_sink.dart b/pkg/compiler/lib/src/serialization/object_sink.dart
index 3bbbd3b..8e8c984 100644
--- a/pkg/compiler/lib/src/serialization/object_sink.dart
+++ b/pkg/compiler/lib/src/serialization/object_sink.dart
@@ -44,6 +44,17 @@
}
@override
+ void writeDeferred(void writer()) {
+ assert((writer as dynamic) != null); // TODO(48820): Remove when sound.
+ final sizeIndex = length;
+ writeInt(0); // placeholder
+ final startIndex = length;
+ writer();
+ final endIndex = length;
+ _data![sizeIndex] = endIndex - startIndex;
+ }
+
+ @override
void close() {
_data = null;
}
diff --git a/pkg/compiler/lib/src/serialization/object_source.dart b/pkg/compiler/lib/src/serialization/object_source.dart
index 0a7ca9d..6ea211a 100644
--- a/pkg/compiler/lib/src/serialization/object_source.dart
+++ b/pkg/compiler/lib/src/serialization/object_source.dart
@@ -60,6 +60,19 @@
}
@override
+ int readDeferred() {
+ final dataOffset = _index;
+ _index += readInt();
+ return dataOffset;
+ }
+
+ @override
+ E readDeferredAsEager<E>(E reader()) {
+ readInt(); // Read and throw away the length.
+ return reader();
+ }
+
+ @override
int get length => _data.length;
@override
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
index 7300d00..e15e038 100644
--- a/pkg/compiler/lib/src/serialization/serialization.dart
+++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -26,6 +26,7 @@
import '../options.dart';
import 'data_sink.dart';
import 'data_source.dart';
+import 'deferrable.dart';
import 'member_data.dart';
import 'serialization_interfaces.dart' as migrated
show DataSourceReader, DataSinkWriter;
diff --git a/pkg/compiler/lib/src/serialization/serialization_interfaces.dart b/pkg/compiler/lib/src/serialization/serialization_interfaces.dart
index 8a4ec2b..dfc601b 100644
--- a/pkg/compiler/lib/src/serialization/serialization_interfaces.dart
+++ b/pkg/compiler/lib/src/serialization/serialization_interfaces.dart
@@ -9,6 +9,7 @@
import '../elements/types.dart' show DartType;
import '../inferrer/abstract_value_domain.dart' show AbstractValue;
+import 'deferrable.dart';
export 'tags.dart';
abstract class StringInterner {
@@ -113,6 +114,8 @@
{bool allowNull = false});
void writeAbstractValue(AbstractValue value);
+
+ void writeDeferrable(void f());
}
/// Migrated interface for methods of DataSourceReader.
@@ -192,4 +195,5 @@
E readWithSource<E>(DataSourceReader source, E f());
E readWithOffset<E>(int offset, E f());
+ Deferrable<E> readDeferrable<E>(E f(), {bool cacheData = true});
}
diff --git a/pkg/compiler/lib/src/serialization/sink.dart b/pkg/compiler/lib/src/serialization/sink.dart
index c3d96ab..f1ae16d 100644
--- a/pkg/compiler/lib/src/serialization/sink.dart
+++ b/pkg/compiler/lib/src/serialization/sink.dart
@@ -137,6 +137,15 @@
}
}
+ @override
+ void writeDeferrable(void f()) {
+ if (enableDeferredStrategy) {
+ _sinkWriter.writeDeferred(f);
+ } else {
+ f();
+ }
+ }
+
/// Writes a reference to [value] to this data sink. If [value] has not yet
/// been serialized, [f] is called to serialize the value itself.
@override
diff --git a/pkg/compiler/lib/src/serialization/source.dart b/pkg/compiler/lib/src/serialization/source.dart
index 287a402..c512786 100644
--- a/pkg/compiler/lib/src/serialization/source.dart
+++ b/pkg/compiler/lib/src/serialization/source.dart
@@ -20,6 +20,7 @@
List<ir.DartType>.empty();
final bool enableDeferredStrategy;
+ final bool useDeferredStrategy;
final bool useDataKinds;
final ValueInterner /*?*/ interner;
DataSourceIndices importedIndices;
@@ -96,7 +97,10 @@
}
DataSourceReader(this._sourceReader, CompilerOptions options,
- {this.useDataKinds = false, this.importedIndices, this.interner})
+ {this.useDataKinds = false,
+ this.importedIndices,
+ this.interner,
+ this.useDeferredStrategy = false})
: enableDeferredStrategy =
(options?.features?.deferredSerialization?.isEnabled ?? false),
endOffset = (importedIndices?.previousSourceReader?.endOffset ?? 0) +
@@ -228,6 +232,16 @@
return _sourceReader.readAtOffset(offset, f);
}
+ @override
+ Deferrable<E> readDeferrable<E>(E f(), {bool cacheData = true}) {
+ return enableDeferredStrategy
+ ? (useDeferredStrategy
+ ? Deferrable<E>.deferred(this, f, _sourceReader.readDeferred(),
+ cacheData: cacheData)
+ : Deferrable<E>.eager(_sourceReader.readDeferredAsEager(f)))
+ : Deferrable<E>.eager(f());
+ }
+
/// Invoke [f] in the context of [member]. This sets up support for
/// deserialization of `ir.TreeNode`s using the `readTreeNode*InContext`
/// methods.
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart
index 0635047..265359b 100644
--- a/pkg/compiler/lib/src/serialization/task.dart
+++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -245,7 +245,8 @@
Future<DataAndIndices<JsClosedWorld>> deserializeClosedWorld(
Environment environment,
AbstractValueStrategy abstractValueStrategy,
- ir.Component component) async {
+ ir.Component component,
+ bool useDeferredSourceReads) async {
return await measureIoSubtask('deserialize closed world', () async {
_reporter.log('Reading data from ${_options.readClosedWorldUri}');
api.Input<List<int>> dataInput = await _provider.readFromUri(
@@ -254,7 +255,8 @@
DataSourceReader source = DataSourceReader(
BinaryDataSource(dataInput.data, stringInterner: _stringInterner),
_options,
- interner: _valueInterner);
+ interner: _valueInterner,
+ useDeferredStrategy: useDeferredSourceReads);
var closedWorld = deserializeClosedWorldFromSource(_options, _reporter,
environment, abstractValueStrategy, component, source);
return DataAndIndices(closedWorld, source.exportIndices());
@@ -283,7 +285,8 @@
Environment environment,
AbstractValueStrategy abstractValueStrategy,
ir.Component component,
- DataAndIndices<JsClosedWorld> closedWorldAndIndices) async {
+ DataAndIndices<JsClosedWorld> closedWorldAndIndices,
+ bool useDeferredSourceReads) async {
return await measureIoSubtask('deserialize data', () async {
_reporter.log('Reading data from ${_options.readDataUri}');
api.Input<List<int>> dataInput = await _provider
@@ -292,7 +295,8 @@
BinaryDataSource(dataInput.data, stringInterner: _stringInterner),
_options,
interner: _valueInterner,
- importedIndices: closedWorldAndIndices.indices);
+ importedIndices: closedWorldAndIndices.indices,
+ useDeferredStrategy: useDeferredSourceReads);
return DataAndIndices(
deserializeGlobalTypeInferenceResultsFromSource(
_options,
@@ -346,7 +350,8 @@
JsBackendStrategy backendStrategy,
GlobalTypeInferenceResults globalTypeInferenceResults,
CodegenInputs codegenInputs,
- DataSourceIndices indices) async {
+ DataSourceIndices indices,
+ bool useDeferredSourceReads) async {
int shards = _options.codegenShards;
JClosedWorld closedWorld = globalTypeInferenceResults.closedWorld;
Map<MemberEntity, CodegenResult> results = {};
@@ -358,8 +363,8 @@
await _provider.readFromUri(uri, inputKind: api.InputKind.binary);
// TODO(36983): This code is extracted because there appeared to be a
// memory leak for large buffer held by `source`.
- _deserializeCodegenInput(
- backendStrategy, closedWorld, uri, dataInput, indices, results);
+ _deserializeCodegenInput(backendStrategy, closedWorld, uri, dataInput,
+ indices, results, useDeferredSourceReads);
dataInput.release();
});
}
@@ -373,12 +378,14 @@
Uri uri,
api.Input<List<int>> dataInput,
DataSourceIndices importedIndices,
- Map<MemberEntity, CodegenResult> results) {
+ Map<MemberEntity, CodegenResult> results,
+ bool useDeferredSourceReads) {
DataSourceReader source = DataSourceReader(
BinaryDataSource(dataInput.data, stringInterner: _stringInterner),
_options,
interner: _valueInterner,
- importedIndices: importedIndices);
+ importedIndices: importedIndices,
+ useDeferredStrategy: useDeferredSourceReads);
backendStrategy.prepareCodegenReader(source);
Map<MemberEntity, CodegenResult> codegenResults =
source.readMemberMap((MemberEntity member) {
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index e608892..85797a1 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -2097,7 +2097,7 @@
IsTestSpecialization specialization =
SpecializedChecks.findIsTestSpecialization(
- node.dartType, _graph, _closedWorld);
+ node.dartType, _graph.element, _closedWorld);
if (specialization == IsTestSpecialization.isNull ||
specialization == IsTestSpecialization.notNull) {
diff --git a/pkg/compiler/lib/src/universe/member_usage.dart b/pkg/compiler/lib/src/universe/member_usage.dart
index 9bb2a33..84df30c 100644
--- a/pkg/compiler/lib/src/universe/member_usage.dart
+++ b/pkg/compiler/lib/src/universe/member_usage.dart
@@ -2,14 +2,12 @@
// 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.
-// @dart = 2.10
-
import 'dart:math' as Math;
import '../common.dart';
import '../constants/values.dart';
import '../elements/entities.dart';
-import '../js_model/closure.dart' show JRecordField;
+import '../js_model/jrecord_field_interface.dart' show JRecordFieldInterface;
import '../serialization/serialization_interfaces.dart';
import '../util/enumset.dart';
import 'call_structure.dart';
@@ -52,10 +50,10 @@
MemberUsage.cloned(this.entity, EnumSet<MemberUse> pendingUse)
: super.cloned(pendingUse);
- factory MemberUsage(MemberEntity member, {MemberAccess potentialAccess}) {
+ factory MemberUsage(MemberEntity member, {MemberAccess? potentialAccess}) {
/// Create the set of potential accesses to [member], limited to [original]
/// if provided.
- EnumSet<Access> createPotentialAccessSet(EnumSet<Access> original) {
+ EnumSet<Access> createPotentialAccessSet(EnumSet<Access>? original) {
if (original != null) {
if (original.isEmpty) return emptySet;
return original.clone();
@@ -66,7 +64,7 @@
} else if (member.isInstanceMember) {
return EnumSet.fromValues(Access.values);
} else {
- assert(member is JRecordField, "Unexpected member: $member");
+ assert(member is JRecordFieldInterface, "Unexpected member: $member");
return EnumSet();
}
}
@@ -89,7 +87,7 @@
return createPotentialAccessSet(potentialAccess?.invokes);
}
- if (member.isField) {
+ if (member is FieldEntity) {
if (member.isAssignable) {
return FieldUsage(member,
potentialReads: createPotentialReads(),
@@ -101,33 +99,35 @@
potentialWrites: emptySet,
potentialInvokes: createPotentialInvokes());
}
- } else if (member.isGetter) {
- return PropertyUsage(member,
- potentialReads: createPotentialReads(),
- potentialWrites: emptySet,
- potentialInvokes: createPotentialInvokes());
- } else if (member.isSetter) {
- return PropertyUsage(member,
- potentialReads: emptySet,
- potentialWrites: createPotentialWrites(),
- potentialInvokes: emptySet);
- } else if (member.isConstructor) {
- return MethodUsage(member,
- potentialReads: emptySet, potentialInvokes: createPotentialInvokes());
- } else {
- assert(member is FunctionEntity,
- failedAt(member, "Unexpected member: $member"));
- return MethodUsage(member,
- potentialReads: createPotentialReads(),
- potentialInvokes: createPotentialInvokes());
+ } else if (member is FunctionEntity) {
+ if (member.isGetter) {
+ return PropertyUsage(member,
+ potentialReads: createPotentialReads(),
+ potentialWrites: emptySet,
+ potentialInvokes: createPotentialInvokes());
+ } else if (member.isSetter) {
+ return PropertyUsage(member,
+ potentialReads: emptySet,
+ potentialWrites: createPotentialWrites(),
+ potentialInvokes: emptySet);
+ } else if (member.isConstructor) {
+ return MethodUsage(member,
+ potentialReads: emptySet,
+ potentialInvokes: createPotentialInvokes());
+ } else {
+ return MethodUsage(member,
+ potentialReads: createPotentialReads(),
+ potentialInvokes: createPotentialInvokes());
+ }
}
+ throw failedAt(member, "Unexpected member: $member");
}
/// `true` if [entity] has been initialized.
bool get hasInit => true;
/// The set of constant initial values for a field.
- Iterable<ConstantValue> get initialConstants => null;
+ Iterable<ConstantValue>? get initialConstants => null;
/// `true` if [entity] has been read as a value. For a field this is a normal
/// read access, for a function this is a closurization.
@@ -165,7 +165,7 @@
/// Returns the [ParameterStructure] corresponding to the parameters that are
/// used in invocations of [entity]. For a field, getter or setter this is
/// always `null`.
- ParameterStructure get invokedParameters => null;
+ ParameterStructure? get invokedParameters => null;
/// Whether this member has any potential but unregistered dynamic reads,
/// writes or invocations.
@@ -279,28 +279,32 @@
final EnumSet<Access> invokes;
PropertyUsage.cloned(MemberEntity member, EnumSet<MemberUse> pendingUse,
- {this.potentialReads,
- this.potentialWrites,
- this.potentialInvokes,
- this.reads,
- this.writes,
- this.invokes})
- : assert(potentialReads != null),
- assert(potentialWrites != null),
- assert(potentialInvokes != null),
- assert(reads != null),
- assert(writes != null),
- assert(invokes != null),
+ {required this.potentialReads,
+ required this.potentialWrites,
+ required this.potentialInvokes,
+ required this.reads,
+ required this.writes,
+ required this.invokes})
+ : // TODO(48820): Remove asserts when sound.
+ assert((potentialReads as dynamic) != null),
+ assert((potentialWrites as dynamic) != null),
+ assert((potentialInvokes as dynamic) != null),
+ assert((reads as dynamic) != null),
+ assert((writes as dynamic) != null),
+ assert((invokes as dynamic) != null),
super.cloned(member, pendingUse);
PropertyUsage(MemberEntity member,
- {this.potentialReads, this.potentialWrites, this.potentialInvokes})
+ {required this.potentialReads,
+ required this.potentialWrites,
+ required this.potentialInvokes})
: reads = EnumSet(),
writes = EnumSet(),
invokes = EnumSet(),
- assert(potentialReads != null),
- assert(potentialWrites != null),
- assert(potentialInvokes != null),
+ // TODO(48820): Remove asserts when sound.
+ assert((potentialReads as dynamic) != null),
+ assert((potentialWrites as dynamic) != null),
+ assert((potentialInvokes as dynamic) != null),
super.internal(member);
@override
@@ -384,33 +388,37 @@
@override
final EnumSet<Access> writes;
- List<ConstantValue> _initialConstants;
+ List<ConstantValue>? _initialConstants;
FieldUsage.cloned(FieldEntity field, EnumSet<MemberUse> pendingUse,
- {this.potentialReads,
- this.potentialWrites,
- this.potentialInvokes,
- this.hasInit,
- this.reads,
- this.writes,
- this.invokes})
- : assert(potentialReads != null),
- assert(potentialWrites != null),
- assert(potentialInvokes != null),
- assert(reads != null),
- assert(writes != null),
- assert(invokes != null),
+ {required this.potentialReads,
+ required this.potentialWrites,
+ required this.potentialInvokes,
+ required this.hasInit,
+ required this.reads,
+ required this.writes,
+ required this.invokes})
+ : // TODO(48820): Remove asserts when sound.
+ assert((potentialReads as dynamic) != null),
+ assert((potentialWrites as dynamic) != null),
+ assert((potentialInvokes as dynamic) != null),
+ assert((reads as dynamic) != null),
+ assert((writes as dynamic) != null),
+ assert((invokes as dynamic) != null),
super.cloned(field, pendingUse);
FieldUsage(FieldEntity field,
- {this.potentialReads, this.potentialWrites, this.potentialInvokes})
+ {required this.potentialReads,
+ required this.potentialWrites,
+ required this.potentialInvokes})
: hasInit = false,
reads = EnumSet(),
writes = EnumSet(),
invokes = EnumSet(),
- assert(potentialReads != null),
- assert(potentialWrites != null),
- assert(potentialInvokes != null),
+ // TODO(48820): Remove asserts when sound.
+ assert((potentialReads as dynamic) != null),
+ assert((potentialWrites as dynamic) != null),
+ assert((potentialInvokes as dynamic) != null),
super.internal(field);
@override
@@ -427,8 +435,7 @@
@override
EnumSet<MemberUse> constantInit(ConstantValue constant) {
- _initialConstants ??= [];
- _initialConstants.add(constant);
+ (_initialConstants ??= []).add(constant);
return init();
}
@@ -475,7 +482,7 @@
@override
MemberUsage clone() {
- return FieldUsage.cloned(entity, _pendingUse.clone(),
+ return FieldUsage.cloned(entity as FieldEntity, _pendingUse.clone(),
potentialReads: potentialReads.clone(),
potentialWrites: potentialWrites.clone(),
potentialInvokes: potentialInvokes.clone(),
@@ -515,20 +522,23 @@
MethodUsage.cloned(FunctionEntity function, this.parameterUsage,
EnumSet<MemberUse> pendingUse,
- {this.potentialReads, this.reads, this.potentialInvokes, this.invokes})
- : assert(potentialReads != null),
- assert(potentialInvokes != null),
- assert(reads != null),
- assert(invokes != null),
+ {required this.potentialReads,
+ required this.reads,
+ required this.potentialInvokes,
+ required this.invokes})
+ : assert((potentialReads as dynamic) != null),
+ assert((potentialInvokes as dynamic) != null),
+ assert((reads as dynamic) != null),
+ assert((invokes as dynamic) != null),
super.cloned(function, pendingUse);
MethodUsage(FunctionEntity function,
- {this.potentialReads, this.potentialInvokes})
+ {required this.potentialReads, required this.potentialInvokes})
: reads = EnumSet(),
invokes = EnumSet(),
parameterUsage = ParameterUsage(function.parameterStructure),
- assert(potentialReads != null),
- assert(potentialInvokes != null),
+ assert((potentialReads as dynamic) != null),
+ assert((potentialInvokes as dynamic) != null),
super.internal(function);
@override
@@ -576,7 +586,7 @@
}
@override
- ParameterStructure get invokedParameters => parameterUsage.invokedParameters;
+ ParameterStructure? get invokedParameters => parameterUsage.invokedParameters;
@override
bool get hasPendingDynamicInvoke =>
@@ -586,7 +596,7 @@
@override
MemberUsage clone() {
return MethodUsage.cloned(
- entity, parameterUsage.clone(), _pendingUse.clone(),
+ entity as FunctionEntity, parameterUsage.clone(), _pendingUse.clone(),
reads: reads.clone(),
potentialReads: potentialReads.clone(),
invokes: invokes.clone(),
@@ -682,26 +692,25 @@
final ParameterStructure _parameterStructure;
/// `true` if the method or constructor has at least one invocation.
- bool _hasInvoke;
+ bool _hasInvoke = false;
/// The maximum number of (optional) positional parameters provided in
/// invocations of the method or constructor.
///
/// If all positional parameters having been provided this is set to `null`.
- int _providedPositionalParameters;
+ int? _providedPositionalParameters;
/// `true` if all type parameters have been provided in at least one
/// invocation of the method or constructor.
- bool _areAllTypeParametersProvided;
+ late bool _areAllTypeParametersProvided;
/// The set of named parameters that have not yet been provided in any
/// invocation of the method or constructor.
///
/// If all named parameters have been provided this is set to `null`.
- Set<String> _unprovidedNamedParameters;
+ Set<String>? _unprovidedNamedParameters;
ParameterUsage(this._parameterStructure) {
- _hasInvoke = false;
_areAllTypeParametersProvided = _parameterStructure.typeParameters == 0;
_providedPositionalParameters = _parameterStructure.positionalParameters ==
_parameterStructure.requiredPositionalParameters
@@ -714,10 +723,10 @@
}
ParameterUsage.cloned(this._parameterStructure,
- {bool hasInvoke,
- int providedPositionalParameters,
- bool areAllTypeParametersProvided,
- Set<String> unprovidedNamedParameters})
+ {required bool hasInvoke,
+ required providedPositionalParameters,
+ required bool areAllTypeParametersProvided,
+ required Set<String>? unprovidedNamedParameters})
: _hasInvoke = hasInvoke,
_providedPositionalParameters = providedPositionalParameters,
_areAllTypeParametersProvided = areAllTypeParametersProvided,
@@ -729,22 +738,23 @@
bool changed = false;
if (_providedPositionalParameters != null) {
int newProvidedPositionalParameters = Math.max(
- _providedPositionalParameters, callStructure.positionalArgumentCount);
+ _providedPositionalParameters!,
+ callStructure.positionalArgumentCount);
changed |=
newProvidedPositionalParameters != _providedPositionalParameters;
_providedPositionalParameters = newProvidedPositionalParameters;
- if (_providedPositionalParameters >=
+ if (_providedPositionalParameters! >=
_parameterStructure.positionalParameters) {
_providedPositionalParameters = null;
}
}
if (_unprovidedNamedParameters != null &&
callStructure.namedArguments.isNotEmpty) {
- int _providedNamedParametersCount = _unprovidedNamedParameters.length;
- _unprovidedNamedParameters.removeAll(callStructure.namedArguments);
+ int _providedNamedParametersCount = _unprovidedNamedParameters!.length;
+ _unprovidedNamedParameters!.removeAll(callStructure.namedArguments);
changed |=
- _providedNamedParametersCount != _unprovidedNamedParameters.length;
- if (_unprovidedNamedParameters.isEmpty) {
+ _providedNamedParametersCount != _unprovidedNamedParameters!.length;
+ if (_unprovidedNamedParameters!.isEmpty) {
_unprovidedNamedParameters = null;
}
}
@@ -770,7 +780,7 @@
_areAllTypeParametersProvided = true;
}
- ParameterStructure get invokedParameters {
+ ParameterStructure? get invokedParameters {
if (!_hasInvoke) return null;
if (isFullyUsed) return _parameterStructure;
return ParameterStructure(
@@ -780,7 +790,7 @@
_unprovidedNamedParameters == null
? _parameterStructure.namedParameters
: _parameterStructure.namedParameters
- .where((n) => !_unprovidedNamedParameters.contains(n))
+ .where((n) => !_unprovidedNamedParameters!.contains(n))
.toList(),
_parameterStructure.requiredNamedParameters,
_areAllTypeParametersProvided ? _parameterStructure.typeParameters : 0);
diff --git a/pkg/compiler/lib/src/universe/strong_mode_constraint.dart b/pkg/compiler/lib/src/universe/strong_mode_constraint.dart
new file mode 100644
index 0000000..571df2e
--- /dev/null
+++ b/pkg/compiler/lib/src/universe/strong_mode_constraint.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2022, 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.
+
+// TODO(48820): delete this class once migration is complete.
+abstract class StrongModeConstraintInterface {
+ bool get isThis;
+ bool get isExact;
+ String get className;
+}
diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart
index 28fdeed..ed7a7c3 100644
--- a/pkg/compiler/lib/src/universe/use.dart
+++ b/pkg/compiler/lib/src/universe/use.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.10
-
/// This library defines individual world impacts.
///
/// We call these building blocks `uses`. Each `use` is a single impact of the
@@ -24,11 +22,11 @@
import '../elements/entities.dart';
import '../inferrer/abstract_value_domain.dart';
import '../serialization/serialization_interfaces.dart';
-import '../js_model/closure.dart' show JRecordField;
+import '../js_model/jrecord_field_interface.dart' show JRecordFieldInterface;
import '../util/util.dart' show equalElements, Hashing;
import 'call_structure.dart' show CallStructure;
import 'selector.dart' show Selector;
-import 'world_builder.dart' show StrongModeConstraint;
+import 'strong_mode_constraint.dart' show StrongModeConstraintInterface;
enum DynamicUseKind {
INVOKE,
@@ -43,8 +41,8 @@
static const String tag = 'dynamic-use';
final Selector selector;
- final Object receiverConstraint;
- final List<DartType> _typeArguments;
+ final Object? receiverConstraint;
+ final List<DartType>? _typeArguments;
DynamicUse(this.selector, this.receiverConstraint, this._typeArguments)
: assert(
@@ -65,11 +63,11 @@
source.begin(tag);
Selector selector = Selector.readFromDataSource(source);
bool hasConstraint = source.readBool();
- Object receiverConstraint;
+ Object? receiverConstraint;
if (hasConstraint) {
receiverConstraint = source.readAbstractValue();
}
- List<DartType> typeArguments = source.readDartTypesOrNull();
+ List<DartType>? typeArguments = source.readDartTypesOrNull();
source.end(tag);
return DynamicUse(selector, receiverConstraint, typeArguments);
}
@@ -77,13 +75,14 @@
void writeToDataSink(DataSinkWriter sink) {
sink.begin(tag);
selector.writeToDataSink(sink);
- sink.writeBool(receiverConstraint != null);
- if (receiverConstraint != null) {
- if (receiverConstraint is AbstractValue) {
- sink.writeAbstractValue(receiverConstraint);
+ var constraint = receiverConstraint;
+ sink.writeBool(constraint != null);
+ if (constraint != null) {
+ if (constraint is AbstractValue) {
+ sink.writeAbstractValue(constraint);
} else {
throw UnsupportedError(
- "Unsupported receiver constraint: ${receiverConstraint}");
+ "Unsupported receiver constraint: ${constraint}");
}
}
sink.writeDartTypesOrNull(_typeArguments);
@@ -95,20 +94,20 @@
StringBuffer sb = StringBuffer();
if (receiverConstraint != null) {
var constraint = receiverConstraint;
- if (constraint is StrongModeConstraint) {
+ if (constraint is StrongModeConstraintInterface) {
if (constraint.isThis) {
sb.write('this:');
} else if (constraint.isExact) {
sb.write('exact:');
}
- sb.write(constraint.cls.name);
+ sb.write(constraint.className);
} else {
sb.write(constraint);
}
sb.write('.');
}
sb.write(selector.name);
- if (typeArguments != null && typeArguments.isNotEmpty) {
+ if (typeArguments.isNotEmpty) {
sb.write('<');
sb.write(typeArguments.join(','));
sb.write('>');
@@ -183,11 +182,11 @@
final StaticUseKind kind;
@override
final int hashCode;
- final InterfaceType type;
- final CallStructure callStructure;
- final ImportEntity deferredImport;
- final ConstantValue constant;
- final List<DartType> typeArguments;
+ final InterfaceType? type;
+ final CallStructure? callStructure;
+ final ImportEntity? deferredImport;
+ final ConstantValue? constant;
+ final List<DartType>? typeArguments;
StaticUse.internal(Entity element, this.kind,
{this.type,
@@ -221,13 +220,12 @@
source.begin(tag);
MemberEntity element = source.readMember();
StaticUseKind kind = source.readEnum(StaticUseKind.values);
- InterfaceType /*?*/ type =
- source.readDartTypeOrNull() as InterfaceType /*?*/;
- CallStructure callStructure =
+ InterfaceType? type = source.readDartTypeOrNull() as InterfaceType?;
+ CallStructure? callStructure =
source.readValueOrNull(() => CallStructure.readFromDataSource(source));
- ImportEntity deferredImport = source.readImportOrNull();
- ConstantValue constant = source.readConstantOrNull();
- List<DartType> typeArguments = source.readDartTypesOrNull();
+ ImportEntity? deferredImport = source.readImportOrNull();
+ ConstantValue? constant = source.readConstantOrNull();
+ List<DartType>? typeArguments = source.readDartTypesOrNull();
source.end(tag);
return StaticUse.internal(element, kind,
type: type,
@@ -239,8 +237,7 @@
void writeToDataSink(DataSinkWriter sink) {
sink.begin(tag);
- assert(element is MemberEntity, "Unsupported entity: $element");
- sink.writeMember(element);
+ sink.writeMember(element as MemberEntity);
sink.writeEnum(kind);
sink.writeDartTypeOrNull(type);
sink.writeValueOrNull(
@@ -269,40 +266,41 @@
break;
default:
}
- if (element is MemberEntity) {
- MemberEntity member = element;
+ final member = element;
+ if (member is MemberEntity) {
if (member.enclosingClass != null) {
- sb.write(member.enclosingClass.name);
+ sb.write(member.enclosingClass!.name);
sb.write('.');
}
}
- if (element.name == null) {
+ if (member.name == null) {
sb.write('<anonymous>');
} else {
- sb.write(element.name);
+ sb.write(member.name);
}
- if (typeArguments != null && typeArguments.isNotEmpty) {
+ if (typeArguments != null && typeArguments!.isNotEmpty) {
sb.write('<');
- sb.write(typeArguments.join(','));
+ sb.write(typeArguments!.join(','));
sb.write('>');
}
- if (callStructure != null) {
+ final callStructureLocal = callStructure;
+ if (callStructureLocal != null) {
sb.write('(');
- sb.write(callStructure.positionalArgumentCount);
- if (callStructure.namedArgumentCount > 0) {
+ sb.write(callStructureLocal.positionalArgumentCount);
+ if (callStructureLocal.namedArgumentCount > 0) {
sb.write(',');
- sb.write(callStructure.getOrderedNamedArguments().join(','));
+ sb.write(callStructureLocal.getOrderedNamedArguments().join(','));
}
sb.write(')');
}
if (deferredImport != null) {
sb.write('{');
- sb.write(deferredImport.name);
+ sb.write(deferredImport!.name);
sb.write('}');
}
if (constant != null) {
sb.write('=');
- sb.write(constant.toStructuredText(null));
+ sb.write(constant!.toStructuredText(null));
}
return sb.toString();
}
@@ -311,7 +309,7 @@
/// [callStructure].
factory StaticUse.staticInvoke(
FunctionEntity element, CallStructure callStructure,
- [List<DartType> typeArguments, ImportEntity deferredImport]) {
+ [List<DartType>? typeArguments, ImportEntity? deferredImport]) {
assert(
element.isStatic || element.isTopLevel,
failedAt(
@@ -321,10 +319,9 @@
assert(element.isFunction,
failedAt(element, "Static get element $element must be a function."));
assert(
- callStructure != null,
+ (callStructure as dynamic) != null, // TODO(48820): remove when sound
failedAt(element,
"Not CallStructure for static invocation of element $element."));
-
StaticUse staticUse = StaticUse.internal(
element, StaticUseKind.STATIC_INVOKE,
callStructure: callStructure,
@@ -336,7 +333,7 @@
/// Closurization of a static or top-level function [element].
factory StaticUse.staticTearOff(FunctionEntity element,
- [ImportEntity deferredImport]) {
+ [ImportEntity? deferredImport]) {
assert(
element.isStatic || element.isTopLevel,
failedAt(
@@ -351,7 +348,7 @@
/// Read access of a static or top-level field or getter [element].
factory StaticUse.staticGet(MemberEntity element,
- [ImportEntity deferredImport]) {
+ [ImportEntity? deferredImport]) {
assert(
element.isStatic || element.isTopLevel,
failedAt(
@@ -368,7 +365,7 @@
/// Write access of a static or top-level field or setter [element].
factory StaticUse.staticSet(MemberEntity element,
- [ImportEntity deferredImport]) {
+ [ImportEntity? deferredImport]) {
assert(
element.isStatic || element.isTopLevel,
failedAt(
@@ -400,13 +397,13 @@
/// Invocation of a super method [element] with the given [callStructure].
factory StaticUse.superInvoke(
FunctionEntity element, CallStructure callStructure,
- [List<DartType> typeArguments]) {
+ [List<DartType>? typeArguments]) {
assert(
element.isInstanceMember,
failedAt(element,
"Super invoke element $element must be an instance method."));
assert(
- callStructure != null,
+ (callStructure as dynamic) != null, // TODO(48820): remove when sound
failedAt(element,
"Not CallStructure for super invocation of element $element."));
StaticUse staticUse = StaticUse.internal(
@@ -471,7 +468,7 @@
"Constructor invoke element $element must be a "
"generative constructor."));
assert(
- callStructure != null,
+ (callStructure as dynamic) != null, // TODO(48820): remove when sound
failedAt(
element,
"Not CallStructure for super constructor invocation of element "
@@ -485,7 +482,7 @@
factory StaticUse.constructorBodyInvoke(
ConstructorBodyEntity element, CallStructure callStructure) {
assert(
- callStructure != null,
+ (callStructure as dynamic) != null, // TODO(48820): remove when sound
failedAt(
element,
"Not CallStructure for constructor body invocation of element "
@@ -549,7 +546,7 @@
failedAt(element,
"Constructor invocation element $element must be a constructor."));
assert(
- callStructure != null,
+ (callStructure as dynamic) != null, // TODO(48820): remove when sound
failedAt(
element,
"Not CallStructure for constructor invocation of element "
@@ -565,7 +562,8 @@
CallStructure callStructure,
InterfaceType type,
ImportEntity deferredImport) {
- assert(type != null,
+ assert(
+ (type as dynamic) != null, // TODO(48820): remove when sound
failedAt(element, "No type provided for constructor invocation."));
assert(
element.isConstructor,
@@ -586,7 +584,8 @@
CallStructure callStructure,
InterfaceType type,
ImportEntity deferredImport) {
- assert(type != null,
+ assert(
+ (type as dynamic) != null, // TODO(48820): remove when sound
failedAt(element, "No type provided for constructor invocation."));
assert(
element.isConstructor,
@@ -623,7 +622,7 @@
/// Read access of an instance field or boxed field [element].
factory StaticUse.fieldGet(FieldEntity element) {
assert(
- element.isInstanceMember || element is JRecordField,
+ element.isInstanceMember || element is JRecordFieldInterface,
failedAt(element,
"Field init element $element must be an instance or boxed field."));
return StaticUse.internal(element, StaticUseKind.INSTANCE_FIELD_GET);
@@ -632,7 +631,7 @@
/// Write access of an instance field or boxed field [element].
factory StaticUse.fieldSet(FieldEntity element) {
assert(
- element.isInstanceMember || element is JRecordField,
+ element.isInstanceMember || element is JRecordFieldInterface,
failedAt(element,
"Field init element $element must be an instance or boxed field."));
return StaticUse.internal(element, StaticUseKind.INSTANCE_FIELD_SET);
@@ -723,7 +722,7 @@
final TypeUseKind kind;
@override
final int hashCode;
- final ImportEntity deferredImport;
+ final ImportEntity? deferredImport;
TypeUse.internal(DartType type, TypeUseKind kind, [this.deferredImport])
: this.type = type,
@@ -734,7 +733,7 @@
source.begin(tag);
DartType type = source.readDartType();
TypeUseKind kind = source.readEnum(TypeUseKind.values);
- ImportEntity deferredImport = source.readImportOrNull();
+ ImportEntity? deferredImport = source.readImportOrNull();
source.end(tag);
return TypeUse.internal(type, kind, deferredImport);
}
@@ -797,7 +796,7 @@
sb.write(type);
if (deferredImport != null) {
sb.write('{');
- sb.write(deferredImport.name);
+ sb.write(deferredImport!.name);
sb.write('}');
}
return sb.toString();
diff --git a/pkg/compiler/lib/src/universe/world_builder.dart b/pkg/compiler/lib/src/universe/world_builder.dart
index 64a68ab..7d3e254 100644
--- a/pkg/compiler/lib/src/universe/world_builder.dart
+++ b/pkg/compiler/lib/src/universe/world_builder.dart
@@ -16,6 +16,7 @@
import '../world.dart' show World;
import 'selector.dart' show Selector;
import 'use.dart' show DynamicUse, StaticUse;
+import 'strong_mode_constraint.dart' show StrongModeConstraintInterface;
/// The combined constraints on receivers all the dynamic call sites of the same
/// selector.
@@ -167,7 +168,7 @@
}
}
-class StrongModeConstraint {
+class StrongModeConstraint implements StrongModeConstraintInterface {
final ClassEntity cls;
final ClassRelation relation;
@@ -191,11 +192,16 @@
return world.isInheritedIn(element, cls, relation);
}
+ @override
bool get isExact => relation == ClassRelation.exact;
+ @override
bool get isThis => relation == ClassRelation.thisExpression;
@override
+ String get className => cls.name;
+
+ @override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is StrongModeConstraint &&
diff --git a/pkg/compiler/lib/src/universe/world_impact.dart b/pkg/compiler/lib/src/universe/world_impact.dart
index a4a4c43..0d91e03 100644
--- a/pkg/compiler/lib/src/universe/world_impact.dart
+++ b/pkg/compiler/lib/src/universe/world_impact.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.10
-
library dart2js.universe.world_impact;
import '../elements/entities.dart';
@@ -24,7 +22,9 @@
class WorldImpact {
const WorldImpact();
- MemberEntity get member => null;
+ /// [member] may be `null` when the impact is for something that is not a
+ /// member, e.g. a constant, or external or native dependencies.
+ MemberEntity? get member => null;
Iterable<DynamicUse> get dynamicUses => const [];
@@ -39,16 +39,17 @@
Iterable<ConstantUse> get constantUses => const [];
- void _forEach<U>(Iterable<U> uses, void Function(MemberEntity, U) visitUse) =>
+ void _forEach<U>(
+ Iterable<U> uses, void Function(MemberEntity?, U) visitUse) =>
uses.forEach((use) => visitUse(member, use));
- void forEachDynamicUse(void Function(MemberEntity, DynamicUse) visitUse) =>
+ void forEachDynamicUse(void Function(MemberEntity?, DynamicUse) visitUse) =>
_forEach(dynamicUses, visitUse);
- void forEachStaticUse(void Function(MemberEntity, StaticUse) visitUse) =>
+ void forEachStaticUse(void Function(MemberEntity?, StaticUse) visitUse) =>
_forEach(staticUses, visitUse);
- void forEachTypeUse(void Function(MemberEntity, TypeUse) visitUse) =>
+ void forEachTypeUse(void Function(MemberEntity?, TypeUse) visitUse) =>
_forEach(typeUses, visitUse);
- void forEachConstantUse(void Function(MemberEntity, ConstantUse) visitUse) =>
+ void forEachConstantUse(void Function(MemberEntity?, ConstantUse) visitUse) =>
_forEach(constantUses, visitUse);
bool get isEmpty => true;
@@ -89,14 +90,14 @@
class WorldImpactBuilderImpl extends WorldImpactBuilder {
/// The [MemberEntity] associated with this set of impacts. Maybe null.
@override
- final MemberEntity member;
+ final MemberEntity? member;
// TODO(johnniwinther): Do we benefit from lazy initialization of the
// [Setlet]s?
- Set<DynamicUse> _dynamicUses;
- Set<StaticUse> _staticUses;
- Set<TypeUse> _typeUses;
- Set<ConstantUse> _constantUses;
+ Set<DynamicUse>? _dynamicUses;
+ Set<StaticUse>? _staticUses;
+ Set<TypeUse>? _typeUses;
+ Set<ConstantUse>? _constantUses;
WorldImpactBuilderImpl([this.member]);
@@ -122,9 +123,8 @@
@override
void registerDynamicUse(DynamicUse dynamicUse) {
- assert(dynamicUse != null);
- _dynamicUses ??= Setlet();
- _dynamicUses.add(dynamicUse);
+ assert((dynamicUse as dynamic) != null); // TODO(48820): Remove when sound.
+ (_dynamicUses ??= Setlet()).add(dynamicUse);
}
@override
@@ -134,9 +134,8 @@
@override
void registerTypeUse(TypeUse typeUse) {
- assert(typeUse != null);
- _typeUses ??= Setlet();
- _typeUses.add(typeUse);
+ assert((typeUse as dynamic) != null); // TODO(48820): Remove when sound.
+ (_typeUses ??= Setlet()).add(typeUse);
}
@override
@@ -146,9 +145,8 @@
@override
void registerStaticUse(StaticUse staticUse) {
- assert(staticUse != null);
- _staticUses ??= Setlet();
- _staticUses.add(staticUse);
+ assert((staticUse as dynamic) != null); // TODO(48820): Remove when sound.
+ (_staticUses ??= Setlet()).add(staticUse);
}
@override
@@ -158,9 +156,8 @@
@override
void registerConstantUse(ConstantUse constantUse) {
- assert(constantUse != null);
- _constantUses ??= Setlet();
- _constantUses.add(constantUse);
+ assert((constantUse as dynamic) != null); // TODO(48820): Remove when sound.
+ (_constantUses ??= Setlet()).add(constantUse);
}
@override
@@ -174,15 +171,15 @@
class TransformedWorldImpact extends WorldImpactBuilder {
final WorldImpact worldImpact;
- Setlet<StaticUse> _staticUses;
- Setlet<TypeUse> _typeUses;
- Setlet<DynamicUse> _dynamicUses;
- Setlet<ConstantUse> _constantUses;
+ Setlet<StaticUse>? _staticUses;
+ Setlet<TypeUse>? _typeUses;
+ Setlet<DynamicUse>? _dynamicUses;
+ Setlet<ConstantUse>? _constantUses;
TransformedWorldImpact(this.worldImpact);
@override
- MemberEntity get member => worldImpact.member;
+ MemberEntity? get member => worldImpact.member;
@override
bool get isEmpty {
@@ -201,13 +198,13 @@
@override
void registerDynamicUse(DynamicUse dynamicUse) {
_dynamicUses ??= Setlet.of(worldImpact.dynamicUses);
- _dynamicUses.add(dynamicUse);
+ _dynamicUses!.add(dynamicUse);
}
@override
void registerTypeUse(TypeUse typeUse) {
_typeUses ??= Setlet.of(worldImpact.typeUses);
- _typeUses.add(typeUse);
+ _typeUses!.add(typeUse);
}
@override
@@ -218,7 +215,7 @@
@override
void registerStaticUse(StaticUse staticUse) {
_staticUses ??= Setlet.of(worldImpact.staticUses);
- _staticUses.add(staticUse);
+ _staticUses!.add(staticUse);
}
@override
@@ -234,7 +231,7 @@
@override
void registerConstantUse(ConstantUse constantUse) {
_constantUses ??= Setlet.of(worldImpact.constantUses);
- _constantUses.add(constantUse);
+ _constantUses!.add(constantUse);
}
@override
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_command.dart b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
index 97e214a..ffa5832 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_command.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.9
-
import 'dart:io';
import 'package:args/args.dart';
@@ -84,7 +82,7 @@
final String multiRootScheme;
/// Path to set multi-root files relative to when generating source-maps.
- final String multiRootOutputPath;
+ final String? multiRootOutputPath;
/// Experimental language features that are enabled/disabled, see
/// [the spec](https://github.com/dart-lang/sdk/blob/master/docs/process/experimental-flags.md)
@@ -107,8 +105,8 @@
this.emitFullCompiledKernel = false,
this.summaryModules = const {},
this.moduleFormats = const [],
- this.moduleName,
- this.multiRootScheme,
+ required this.moduleName,
+ this.multiRootScheme = 'org-dartlang-app',
this.multiRootOutputPath,
this.experiments = const {},
this.soundNullSafety = false,
@@ -132,7 +130,7 @@
moduleFormats: parseModuleFormatOption(args),
moduleName: _getModuleName(args),
multiRootScheme: args['multi-root-scheme'] as String,
- multiRootOutputPath: args['multi-root-output-path'] as String,
+ multiRootOutputPath: args['multi-root-output-path'] as String?,
experiments: parseExperimentalArguments(
args['enable-experiment'] as List<String>),
soundNullSafety: args['sound-null-safety'] as bool,
@@ -147,7 +145,7 @@
moduleName:
args['module-name'] != null ? _getModuleName(args) : 'dart_sdk',
multiRootScheme: args['multi-root-scheme'] as String,
- multiRootOutputPath: args['multi-root-output-path'] as String,
+ multiRootOutputPath: args['multi-root-output-path'] as String?,
experiments: parseExperimentalArguments(
args['enable-experiment'] as List<String>),
soundNullSafety: args['sound-null-safety'] as bool,
@@ -230,18 +228,15 @@
}
static String _getModuleName(ArgResults args) {
- var moduleName = args['module-name'] as String;
+ var moduleName = args['module-name'] as String?;
if (moduleName == null) {
- var outPaths = args['out'];
- var outPath = outPaths is String
- ? outPaths
- : (outPaths as List<String>)
- .firstWhere((_) => true, orElse: () => null);
-
- // TODO(jmesserly): fix the debugger console so it's not passing invalid
- // options.
- if (outPath == null) return null;
-
+ var outPaths = args['out'] as List<String>;
+ if (outPaths.isEmpty) {
+ throw UnsupportedError(
+ 'No module name provided and unable to synthesize one without any '
+ 'output paths.');
+ }
+ var outPath = outPaths.first;
moduleName = p.basenameWithoutExtension(outPath);
}
// TODO(jmesserly): this should probably use sourcePathToUri.
@@ -260,9 +255,8 @@
/// allow working with summaries whose physical location is outside of the
/// module root directory.
Map<String, String> _parseCustomSummaryModules(List<String> summaryPaths,
- [String moduleRoot, String summaryExt]) {
+ [String? moduleRoot, String? summaryExt]) {
var pathToModule = <String, String>{};
- if (summaryPaths == null) return pathToModule;
for (var summaryPath in summaryPaths) {
var equalSign = summaryPath.indexOf('=');
String modulePath;
@@ -299,7 +293,7 @@
if (abbreviation != null) {
knownAbbreviations.add(abbreviation);
}
- if (option.negatable) {
+ if (option.negatable != null && option.negatable!) {
knownOptions.add('no-$name');
}
});
@@ -331,10 +325,7 @@
/// Convert a [source] string to a Uri, where the source may be a
/// dart/file/package URI or a local win/mac/linux path.
-///
-/// If [source] is null, this will return null.
-Uri sourcePathToUri(String source, {bool windows}) {
- if (source == null) return null;
+Uri sourcePathToUri(String source, {bool? windows}) {
if (windows == null) {
// Running on the web the Platform check will fail, and we can't use
// fromEnvironment because internally it's set to true for dart.library.io.
@@ -358,7 +349,7 @@
return result;
}
-Uri sourcePathToRelativeUri(String source, {bool windows}) {
+Uri sourcePathToRelativeUri(String source, {bool? windows}) {
var uri = sourcePathToUri(source, windows: windows);
if (uri.isScheme('file')) {
var uriPath = uri.path;
@@ -388,8 +379,8 @@
// TODO(#40251): Remove this logic from dev_compiler itself, push it to the
// invokers of dev_compiler which have more knowledge about how they want
// source paths to look.
-Map placeSourceMap(Map sourceMap, String sourceMapPath, String multiRootScheme,
- {String multiRootOutputPath, String sourceMapBase}) {
+Map placeSourceMap(Map sourceMap, String sourceMapPath, String? multiRootScheme,
+ {String? multiRootOutputPath, String? sourceMapBase}) {
var map = Map.from(sourceMap);
// Convert to a local file path if it's not.
sourceMapPath = sourcePathToUri(p.absolute(p.fromUri(sourceMapPath))).path;
@@ -446,7 +437,7 @@
/// Optionally provides the front_end state from the previous compilation,
/// which can be passed to [compile] to potentially speed up the next
/// compilation.
- final InitializedCompilerState kernelState;
+ final InitializedCompilerState? kernelState;
/// The process exit code of the compiler.
final int exitCode;
@@ -454,7 +445,7 @@
CompilerResult(this.exitCode, {this.kernelState});
/// Gets the kernel compiler state, if any.
- Object get compilerState => kernelState;
+ Object? get compilerState => kernelState;
/// Whether the program compiled without any fatal errors (equivalent to
/// [exitCode] == 0).
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 7e981bd..713f095 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -276,7 +276,7 @@
compileSdk,
sourcePathToUri(getSdkPath()),
compileSdk ? null : sourcePathToUri(sdkSummaryPath),
- sourcePathToUri(packageFile),
+ packageFile != null ? sourcePathToUri(packageFile) : null,
sourcePathToUri(librarySpecPath),
additionalDills,
DevCompilerTarget(TargetFlags(
@@ -314,7 +314,7 @@
compileSdk,
sourcePathToUri(getSdkPath()),
compileSdk ? null : sourcePathToUri(sdkSummaryPath),
- sourcePathToUri(packageFile),
+ packageFile != null ? sourcePathToUri(packageFile) : null,
sourcePathToUri(librarySpecPath),
additionalDills,
inputDigests,
diff --git a/pkg/front_end/lib/src/api_unstable/ddc.dart b/pkg/front_end/lib/src/api_unstable/ddc.dart
index 2ebfdf1..d462d69 100644
--- a/pkg/front_end/lib/src/api_unstable/ddc.dart
+++ b/pkg/front_end/lib/src/api_unstable/ddc.dart
@@ -113,10 +113,10 @@
InitializedCompilerState initializeCompiler(
InitializedCompilerState? oldState,
bool compileSdk,
- Uri sdkRoot,
- Uri sdkSummary,
- Uri packagesFile,
- Uri librariesSpecificationUri,
+ Uri? sdkRoot,
+ Uri? sdkSummary,
+ Uri? packagesFile,
+ Uri? librariesSpecificationUri,
List<Uri> additionalDills,
Target target,
{FileSystem? fileSystem,
@@ -166,14 +166,14 @@
/// Re-uses cached components from [oldState.workerInputCache], and reloads them
/// as necessary based on [workerInputDigests].
Future<InitializedCompilerState> initializeIncrementalCompiler(
- InitializedCompilerState oldState,
+ InitializedCompilerState? oldState,
Set<String> tags,
List<Component> doneAdditionalDills,
bool compileSdk,
- Uri sdkRoot,
- Uri sdkSummary,
- Uri packagesFile,
- Uri librariesSpecificationUri,
+ Uri? sdkRoot,
+ Uri? sdkSummary,
+ Uri? packagesFile,
+ Uri? librariesSpecificationUri,
List<Uri> additionalDills,
Map<Uri, List<int>> workerInputDigests,
Target target,
diff --git a/runtime/vm/compiler/assembler/assembler_riscv_test.cc b/runtime/vm/compiler/assembler/assembler_riscv_test.cc
index 34c1060..ff2bfb3 100644
--- a/runtime/vm/compiler/assembler/assembler_riscv_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_riscv_test.cc
@@ -3369,11 +3369,31 @@
EXPECT_EQ(-3.0f, CallF(test->entry(), -3.0f, -3.0f));
EXPECT_EQ(-5.0f, CallF(test->entry(), -3.0f, -5.0f));
+ EXPECT_EQ(bit_cast<uint32_t>(-0.0f),
+ bit_cast<uint32_t>(CallF(test->entry(), 0.0f, -0.0f)));
+ EXPECT_EQ(bit_cast<uint32_t>(-0.0f),
+ bit_cast<uint32_t>(CallF(test->entry(), -0.0f, 0.0f)));
+
float qNAN = std::numeric_limits<float>::quiet_NaN();
EXPECT_EQ(3.0f, CallF(test->entry(), 3.0f, qNAN));
EXPECT_EQ(3.0f, CallF(test->entry(), qNAN, 3.0f));
EXPECT_EQ(-3.0f, CallF(test->entry(), -3.0f, qNAN));
EXPECT_EQ(-3.0f, CallF(test->entry(), qNAN, -3.0f));
+
+ float sNAN = std::numeric_limits<float>::signaling_NaN();
+ EXPECT_EQ(3.0f, CallF(test->entry(), 3.0f, sNAN));
+ EXPECT_EQ(3.0f, CallF(test->entry(), sNAN, 3.0f));
+ EXPECT_EQ(-3.0f, CallF(test->entry(), -3.0f, sNAN));
+ EXPECT_EQ(-3.0f, CallF(test->entry(), sNAN, -3.0f));
+
+ EXPECT_EQ(bit_cast<uint32_t>(qNAN),
+ bit_cast<uint32_t>(CallF(test->entry(), qNAN, qNAN)));
+ EXPECT_EQ(bit_cast<uint32_t>(qNAN),
+ bit_cast<uint32_t>(CallF(test->entry(), sNAN, sNAN)));
+ EXPECT_EQ(bit_cast<uint32_t>(qNAN),
+ bit_cast<uint32_t>(CallF(test->entry(), qNAN, sNAN)));
+ EXPECT_EQ(bit_cast<uint32_t>(qNAN),
+ bit_cast<uint32_t>(CallF(test->entry(), sNAN, qNAN)));
}
ASSEMBLER_TEST_GENERATE(SingleMax, assembler) {
@@ -3399,11 +3419,31 @@
EXPECT_EQ(-3.0f, CallF(test->entry(), -3.0f, -3.0f));
EXPECT_EQ(-3.0f, CallF(test->entry(), -3.0f, -5.0f));
+ EXPECT_EQ(bit_cast<uint32_t>(0.0f),
+ bit_cast<uint32_t>(CallF(test->entry(), 0.0f, -0.0f)));
+ EXPECT_EQ(bit_cast<uint32_t>(0.0f),
+ bit_cast<uint32_t>(CallF(test->entry(), -0.0f, 0.0f)));
+
float qNAN = std::numeric_limits<float>::quiet_NaN();
EXPECT_EQ(3.0f, CallF(test->entry(), 3.0f, qNAN));
EXPECT_EQ(3.0f, CallF(test->entry(), qNAN, 3.0f));
EXPECT_EQ(-3.0f, CallF(test->entry(), -3.0f, qNAN));
EXPECT_EQ(-3.0f, CallF(test->entry(), qNAN, -3.0f));
+
+ float sNAN = std::numeric_limits<float>::signaling_NaN();
+ EXPECT_EQ(3.0f, CallF(test->entry(), 3.0f, sNAN));
+ EXPECT_EQ(3.0f, CallF(test->entry(), sNAN, 3.0f));
+ EXPECT_EQ(-3.0f, CallF(test->entry(), -3.0f, sNAN));
+ EXPECT_EQ(-3.0f, CallF(test->entry(), sNAN, -3.0f));
+
+ EXPECT_EQ(bit_cast<uint32_t>(qNAN),
+ bit_cast<uint32_t>(CallF(test->entry(), qNAN, qNAN)));
+ EXPECT_EQ(bit_cast<uint32_t>(qNAN),
+ bit_cast<uint32_t>(CallF(test->entry(), sNAN, sNAN)));
+ EXPECT_EQ(bit_cast<uint32_t>(qNAN),
+ bit_cast<uint32_t>(CallF(test->entry(), qNAN, sNAN)));
+ EXPECT_EQ(bit_cast<uint32_t>(qNAN),
+ bit_cast<uint32_t>(CallF(test->entry(), sNAN, qNAN)));
}
ASSEMBLER_TEST_GENERATE(SingleEqual, assembler) {
@@ -4312,11 +4352,31 @@
EXPECT_EQ(-3.0, CallD(test->entry(), -3.0, -3.0));
EXPECT_EQ(-5.0, CallD(test->entry(), -3.0, -5.0));
+ EXPECT_EQ(bit_cast<uint64_t>(-0.0),
+ bit_cast<uint64_t>(CallD(test->entry(), 0.0, -0.0)));
+ EXPECT_EQ(bit_cast<uint64_t>(-0.0),
+ bit_cast<uint64_t>(CallD(test->entry(), -0.0, 0.0)));
+
double qNAN = std::numeric_limits<double>::quiet_NaN();
EXPECT_EQ(3.0, CallD(test->entry(), 3.0, qNAN));
EXPECT_EQ(3.0, CallD(test->entry(), qNAN, 3.0));
EXPECT_EQ(-3.0, CallD(test->entry(), -3.0, qNAN));
EXPECT_EQ(-3.0, CallD(test->entry(), qNAN, -3.0));
+
+ double sNAN = std::numeric_limits<double>::signaling_NaN();
+ EXPECT_EQ(3.0, CallD(test->entry(), 3.0, sNAN));
+ EXPECT_EQ(3.0, CallD(test->entry(), sNAN, 3.0));
+ EXPECT_EQ(-3.0, CallD(test->entry(), -3.0, sNAN));
+ EXPECT_EQ(-3.0, CallD(test->entry(), sNAN, -3.0));
+
+ EXPECT_EQ(bit_cast<uint64_t>(qNAN),
+ bit_cast<uint64_t>(CallD(test->entry(), sNAN, sNAN)));
+ EXPECT_EQ(bit_cast<uint64_t>(qNAN),
+ bit_cast<uint64_t>(CallD(test->entry(), qNAN, qNAN)));
+ EXPECT_EQ(bit_cast<uint64_t>(qNAN),
+ bit_cast<uint64_t>(CallD(test->entry(), qNAN, sNAN)));
+ EXPECT_EQ(bit_cast<uint64_t>(qNAN),
+ bit_cast<uint64_t>(CallD(test->entry(), sNAN, qNAN)));
}
ASSEMBLER_TEST_GENERATE(DoubleMax, assembler) {
@@ -4342,11 +4402,31 @@
EXPECT_EQ(-3.0, CallD(test->entry(), -3.0, -3.0));
EXPECT_EQ(-3.0, CallD(test->entry(), -3.0, -5.0));
+ EXPECT_EQ(bit_cast<uint64_t>(0.0),
+ bit_cast<uint64_t>(CallD(test->entry(), 0.0, -0.0)));
+ EXPECT_EQ(bit_cast<uint64_t>(0.0),
+ bit_cast<uint64_t>(CallD(test->entry(), -0.0, 0.0)));
+
double qNAN = std::numeric_limits<double>::quiet_NaN();
EXPECT_EQ(3.0, CallD(test->entry(), 3.0, qNAN));
EXPECT_EQ(3.0, CallD(test->entry(), qNAN, 3.0));
EXPECT_EQ(-3.0, CallD(test->entry(), -3.0, qNAN));
EXPECT_EQ(-3.0, CallD(test->entry(), qNAN, -3.0));
+
+ double sNAN = std::numeric_limits<double>::signaling_NaN();
+ EXPECT_EQ(3.0, CallD(test->entry(), 3.0, sNAN));
+ EXPECT_EQ(3.0, CallD(test->entry(), sNAN, 3.0));
+ EXPECT_EQ(-3.0, CallD(test->entry(), -3.0, sNAN));
+ EXPECT_EQ(-3.0, CallD(test->entry(), sNAN, -3.0));
+
+ EXPECT_EQ(bit_cast<uint64_t>(qNAN),
+ bit_cast<uint64_t>(CallD(test->entry(), sNAN, sNAN)));
+ EXPECT_EQ(bit_cast<uint64_t>(qNAN),
+ bit_cast<uint64_t>(CallD(test->entry(), qNAN, qNAN)));
+ EXPECT_EQ(bit_cast<uint64_t>(qNAN),
+ bit_cast<uint64_t>(CallD(test->entry(), qNAN, sNAN)));
+ EXPECT_EQ(bit_cast<uint64_t>(qNAN),
+ bit_cast<uint64_t>(CallD(test->entry(), sNAN, qNAN)));
}
ASSEMBLER_TEST_GENERATE(DoubleToSingle, assembler) {
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index ed01f6a..8b6c799 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -485,6 +485,11 @@
}
{
GcSafepointOperationScope safepoint_operation(thread);
+ if (reason == GCReason::kFinalize &&
+ old_space_.phase() != PageSpace::kAwaitingFinalization) {
+ return; // Lost race.
+ }
+
thread->isolate_group()->ForEachIsolate(
[&](Isolate* isolate) {
// Discard regexp backtracking stacks to further reduce memory usage.
diff --git a/runtime/vm/malloc_hooks_ia32.cc b/runtime/vm/malloc_hooks_ia32.cc
index 0572ac0..2b7a371 100644
--- a/runtime/vm/malloc_hooks_ia32.cc
+++ b/runtime/vm/malloc_hooks_ia32.cc
@@ -11,9 +11,9 @@
namespace dart {
#if defined(DEBUG)
-const intptr_t kSkipCount = 7;
-#elif !(defined(PRODUCT) || defined(DEBUG))
const intptr_t kSkipCount = 6;
+#elif !(defined(PRODUCT) || defined(DEBUG))
+const intptr_t kSkipCount = 5;
#endif
} // namespace dart
diff --git a/runtime/vm/simulator_riscv.cc b/runtime/vm/simulator_riscv.cc
index 2229c31..3b2034f 100644
--- a/runtime/vm/simulator_riscv.cc
+++ b/runtime/vm/simulator_riscv.cc
@@ -1997,6 +1997,42 @@
pc_ += instr.length();
}
+// "For the purposes of these instructions only, the value −0.0 is considered to
+// be less than the value +0.0. If both inputs are NaNs, the result is the
+// canonical NaN. If only one operand is a NaN, the result is the non-NaN
+// operand."
+static double rv_fmin(double x, double y) {
+ if (isnan(x) && isnan(y)) return std::numeric_limits<double>::quiet_NaN();
+ if (isnan(x)) return y;
+ if (isnan(y)) return x;
+ if (x == y) return signbit(x) ? x : y;
+ return fmin(x, y);
+}
+
+static double rv_fmax(double x, double y) {
+ if (isnan(x) && isnan(y)) return std::numeric_limits<double>::quiet_NaN();
+ if (isnan(x)) return y;
+ if (isnan(y)) return x;
+ if (x == y) return signbit(x) ? y : x;
+ return fmax(x, y);
+}
+
+static float rv_fminf(float x, float y) {
+ if (isnan(x) && isnan(y)) return std::numeric_limits<float>::quiet_NaN();
+ if (isnan(x)) return y;
+ if (isnan(y)) return x;
+ if (x == y) return signbit(x) ? x : y;
+ return fminf(x, y);
+}
+
+static float rv_fmaxf(float x, float y) {
+ if (isnan(x) && isnan(y)) return std::numeric_limits<float>::quiet_NaN();
+ if (isnan(x)) return y;
+ if (isnan(y)) return x;
+ if (x == y) return signbit(x) ? y : x;
+ return fmaxf(x, y);
+}
+
static bool is_quiet(float x) {
// Warning: This is true on Intel/ARM, but not everywhere.
return (bit_cast<uint32_t>(x) & (static_cast<uint32_t>(1) << 22)) != 0;
@@ -2258,10 +2294,10 @@
float rs2 = get_fregs(instr.frs2());
switch (instr.funct3()) {
case MIN:
- set_fregs(instr.frd(), fminf(rs1, rs2));
+ set_fregs(instr.frd(), rv_fminf(rs1, rs2));
break;
case MAX:
- set_fregs(instr.frd(), fmaxf(rs1, rs2));
+ set_fregs(instr.frd(), rv_fmaxf(rs1, rs2));
break;
default:
IllegalInstruction(instr);
@@ -2412,10 +2448,10 @@
double rs2 = get_fregd(instr.frs2());
switch (instr.funct3()) {
case MIN:
- set_fregd(instr.frd(), fmin(rs1, rs2));
+ set_fregd(instr.frd(), rv_fmin(rs1, rs2));
break;
case MAX:
- set_fregd(instr.frd(), fmax(rs1, rs2));
+ set_fregd(instr.frd(), rv_fmax(rs1, rs2));
break;
default:
IllegalInstruction(instr);
diff --git a/tools/VERSION b/tools/VERSION
index 122e79d..43b8d36 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 18
PATCH 0
-PRERELEASE 215
+PRERELEASE 216
PRERELEASE_PATCH 0
\ No newline at end of file