Version 2.18.0-243.0.dev
Merge commit 'abedfaf62a2a426d44142dc97aa342524feedf8f' into 'dev'
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index d19cc50..bd9d063 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -85,7 +85,7 @@
/// TODO(scheglov) Clean up the list of implicitly analyzed files.
class AnalysisDriver implements AnalysisDriverGeneric {
/// The version of data format, should be incremented on every format change.
- static const int DATA_VERSION = 226;
+ static const int DATA_VERSION = 227;
/// The number of exception contexts allowed to write. Once this field is
/// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index 8e11c437..9fd787f 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -150,15 +150,16 @@
Source? get exportedSource => null;
}
-/// [ExportDirectiveState] that has a valid URI that references a file.
-class ExportDirectiveWithFile extends ExportDirectiveState {
+/// [ExportDirectiveWithUri] that has a valid URI that references a file.
+class ExportDirectiveWithFile extends ExportDirectiveWithUri {
final LibraryOrAugmentationFileKind container;
final FileState exportedFile;
ExportDirectiveWithFile({
- required super.directive,
required this.container,
+ required super.directive,
required this.exportedFile,
+ required super.selectedUriStr,
}) {
exportedFile.referencingFiles.add(container.file);
}
@@ -189,14 +190,15 @@
}
}
-/// [ExportDirectiveState] with a URI that resolves to [InSummarySource].
-class ExportDirectiveWithInSummarySource extends ExportDirectiveState {
+/// [ExportDirectiveWithUri] with a URI that resolves to [InSummarySource].
+class ExportDirectiveWithInSummarySource extends ExportDirectiveWithUri {
@override
final InSummarySource exportedSource;
ExportDirectiveWithInSummarySource({
required super.directive,
required this.exportedSource,
+ required super.selectedUriStr,
});
@override
@@ -209,6 +211,16 @@
}
}
+/// [ExportDirectiveState] that has a valid URI string.
+class ExportDirectiveWithUri extends ExportDirectiveState {
+ final String selectedUriStr;
+
+ ExportDirectiveWithUri({
+ required super.directive,
+ required this.selectedUriStr,
+ });
+}
+
/// A library from [SummaryDataStore].
class ExternalLibrary {
final InSummarySource source;
@@ -366,6 +378,9 @@
List<FileState?> get exportedFiles {
return _exportedFiles ??= _unlinked2!.exports.map((directive) {
var uri = _selectRelativeUri(directive);
+ if (uri == null) {
+ return null;
+ }
return _fileForRelativeUri(uri).map(
(file) {
file?.referencingFiles.add(this);
@@ -383,6 +398,9 @@
List<FileState?> get importedFiles {
return _importedFiles ??= _unlinked2!.imports.map((directive) {
var uri = _selectRelativeUri(directive);
+ if (uri == null) {
+ return null;
+ }
return _fileForRelativeUri(uri).map(
(file) {
file?.referencingFiles.add(this);
@@ -452,16 +470,6 @@
return other is FileState && other.uri == uri;
}
- /// Collect all files that are transitively referenced by this file via
- /// imports, exports, and parts.
- void collectAllReferencedFiles(Set<String> referencedFiles) {
- for (final file in directReferencedFiles) {
- if (referencedFiles.add(file.path)) {
- file.collectAllReferencedFiles(referencedFiles);
- }
- }
- }
-
/// Return a new parsed unresolved [CompilationUnit].
CompilationUnitImpl parse([AnalysisErrorListener? errorListener]) {
errorListener ??= AnalysisErrorListener.NULL_LISTENER;
@@ -590,10 +598,6 @@
Either2<FileState?, ExternalLibrary> _fileForRelativeUri(
String relativeUri,
) {
- if (relativeUri.isEmpty) {
- return Either2.t1(null);
- }
-
Uri absoluteUri;
try {
absoluteUri = resolveRelativeUri(uri, Uri.parse(relativeUri));
@@ -661,7 +665,10 @@
var paths = <String>{};
- void addRelativeUri(String relativeUriStr) {
+ void addRelativeUri(String? relativeUriStr) {
+ if (relativeUriStr == null) {
+ return;
+ }
final Uri absoluteUri;
try {
final relativeUri = Uri.parse(relativeUriStr);
@@ -689,7 +696,7 @@
}
/// TODO(scheglov) move to _fsState?
- String _selectRelativeUri(UnlinkedNamespaceDirective directive) {
+ String? _selectRelativeUri(UnlinkedNamespaceDirective directive) {
for (var configuration in directive.configurations) {
var name = configuration.name;
var value = configuration.value;
@@ -711,12 +718,14 @@
final partOfNameDirective = unlinked2.partOfNameDirective;
final partOfUriDirective = unlinked2.partOfUriDirective;
if (libraryAugmentationDirective != null) {
- final uri = libraryAugmentationDirective.uri;
+ final uriStr = libraryAugmentationDirective.uri;
// TODO(scheglov) This could be a useful method of `Either`.
- final uriFile = _fileForRelativeUri(uri).map(
- (file) => file,
- (_) => null,
- );
+ final uriFile = uriStr != null
+ ? _fileForRelativeUri(uriStr).map(
+ (file) => file,
+ (_) => null,
+ )
+ : null;
if (uriFile != null) {
_kind = AugmentationKnownFileStateKind(
file: this,
@@ -740,11 +749,13 @@
directive: partOfNameDirective,
);
} else if (partOfUriDirective != null) {
- final uri = partOfUriDirective.uri;
- final uriFile = _fileForRelativeUri(uri).map(
- (file) => file,
- (_) => null,
- );
+ final uriStr = partOfUriDirective.uri;
+ final uriFile = uriStr != null
+ ? _fileForRelativeUri(uriStr).map(
+ (file) => file,
+ (_) => null,
+ )
+ : null;
if (uriFile != null) {
_kind = PartOfUriKnownFileStateKind(
file: this,
@@ -787,7 +798,7 @@
if (directive.augmentKeyword != null) {
augmentations.add(
UnlinkedImportAugmentationDirective(
- uri: directive.uri.stringValue ?? '',
+ uri: directive.uri.stringValue,
),
);
} else {
@@ -816,7 +827,7 @@
} else if (directive is PartDirective) {
parts.add(
UnlinkedPartDirective(
- uri: directive.uri.stringValue ?? '',
+ uri: directive.uri.stringValue,
),
);
} else if (directive is PartOfDirective) {
@@ -939,10 +950,10 @@
return UnlinkedNamespaceDirectiveConfiguration(
name: name,
value: value,
- uri: configuration.uri.stringValue ?? '',
+ uri: configuration.uri.stringValue,
);
}).toList(),
- uri: directive.uri.stringValue ?? '',
+ uri: directive.uri.stringValue,
);
}
}
@@ -1309,24 +1320,23 @@
}
/// Computes the set of [FileState]'s used/not used to analyze the given
- /// [files]. Removes the [FileState]'s of the files not used for analysis from
+ /// [paths]. Removes the [FileState]'s of the files not used for analysis from
/// the cache. Returns the set of unused [FileState]'s.
- Set<FileState> removeUnusedFiles(List<String> files) {
- var allReferenced = <String>{};
- for (var path in files) {
- allReferenced.add(path);
- _pathToFile[path]?.collectAllReferencedFiles(allReferenced);
+ Set<FileState> removeUnusedFiles(List<String> paths) {
+ final referenced = <FileState>{};
+ for (final path in paths) {
+ final library = _pathToFile[path]?.kind.library;
+ library?.collectTransitive(referenced);
}
- var unusedPaths = _pathToFile.keys.toSet();
- unusedPaths.removeAll(allReferenced);
-
- var removedFiles = <FileState>{};
- for (var path in unusedPaths) {
- changeFile(path, removedFiles);
+ final removed = <FileState>{};
+ for (final file in _pathToFile.values.toList()) {
+ if (!referenced.contains(file)) {
+ changeFile(file.path, removed);
+ }
}
- return removedFiles;
+ return removed;
}
/// Clear all [FileState] data - all maps from path or URI, etc.
@@ -1457,7 +1467,7 @@
Source? get importedSource => null;
}
-/// [PartDirectiveState] that has a valid URI that references a file.
+/// [ImportAugmentationWithUri] that has a valid URI that references a file.
class ImportAugmentationDirectiveWithFile
extends ImportAugmentationDirectiveState {
final LibraryOrAugmentationFileKind container;
@@ -1490,6 +1500,16 @@
}
}
+/// [ImportAugmentationDirectiveState] that has a valid URI.
+class ImportAugmentationWithUri extends ImportAugmentationDirectiveState {
+ final String uriStr;
+
+ ImportAugmentationWithUri({
+ required super.directive,
+ required this.uriStr,
+ });
+}
+
/// Information about a single `import` directive.
class ImportDirectiveState extends DirectiveState {
final UnlinkedNamespaceDirective directive;
@@ -1511,8 +1531,8 @@
bool get isSyntheticDartCoreImport => directive.isSyntheticDartCoreImport;
}
-/// [ImportDirectiveState] that has a valid URI that references a file.
-class ImportDirectiveWithFile extends ImportDirectiveState {
+/// [ImportDirectiveWithUri] that has a valid URI that references a file.
+class ImportDirectiveWithFile extends ImportDirectiveWithUri {
final LibraryOrAugmentationFileKind container;
final FileState importedFile;
@@ -1520,6 +1540,7 @@
required this.container,
required super.directive,
required this.importedFile,
+ required super.selectedUriStr,
}) {
importedFile.referencingFiles.add(container.file);
}
@@ -1550,14 +1571,15 @@
}
}
-/// [ImportDirectiveState] with a URI that resolves to [InSummarySource].
-class ImportDirectiveWithInSummarySource extends ImportDirectiveState {
+/// [ImportDirectiveWithUri] with a URI that resolves to [InSummarySource].
+class ImportDirectiveWithInSummarySource extends ImportDirectiveWithUri {
@override
final InSummarySource importedSource;
ImportDirectiveWithInSummarySource({
required super.directive,
required this.importedSource,
+ required super.selectedUriStr,
});
@override
@@ -1570,6 +1592,16 @@
}
}
+/// [ImportDirectiveState] that has a valid URI.
+class ImportDirectiveWithUri extends ImportDirectiveState {
+ final String selectedUriStr;
+
+ ImportDirectiveWithUri({
+ required super.directive,
+ required this.selectedUriStr,
+ });
+}
+
class LibraryFileStateKind extends LibraryOrAugmentationFileKind {
/// The name of the library from the `library` directive.
/// Or `null` if no `library` directive.
@@ -1626,32 +1658,53 @@
List<PartDirectiveState> get parts {
return _parts ??= file.unlinked2.parts.map((directive) {
- return file._fileForRelativeUri(directive.uri).map(
- (refFile) {
- if (refFile != null) {
- return PartDirectiveWithFile(
+ final uriStr = directive.uri;
+ if (uriStr != null) {
+ return file._fileForRelativeUri(uriStr).map(
+ (refFile) {
+ if (refFile != null) {
+ return PartDirectiveWithFile(
+ library: this,
+ directive: directive,
+ includedFile: refFile,
+ uriStr: uriStr,
+ );
+ } else {
+ return PartDirectiveWithUri(
+ library: this,
+ directive: directive,
+ uriStr: uriStr,
+ );
+ }
+ },
+ (externalLibrary) {
+ return PartDirectiveWithUri(
library: this,
directive: directive,
- includedFile: refFile,
+ uriStr: uriStr,
);
- } else {
- return PartDirectiveState(
- library: this,
- directive: directive,
- );
- }
- },
- (externalLibrary) {
- return PartDirectiveState(
- library: this,
- directive: directive,
- );
- },
- );
+ },
+ );
+ } else {
+ return PartDirectiveState(
+ library: this,
+ directive: directive,
+ );
+ }
}).toList();
}
@override
+ void collectTransitive(Set<FileState> files) {
+ super.collectTransitive(files);
+ for (final part in parts) {
+ if (part is PartDirectiveWithFile) {
+ files.add(part.includedFile);
+ }
+ }
+ }
+
+ @override
void discoverReferencedFiles() {
super.discoverReferencedFiles();
parts;
@@ -1697,83 +1750,132 @@
List<ImportAugmentationDirectiveState> get augmentations {
return _augmentations ??= file.unlinked2.augmentations.map((directive) {
- return file._fileForRelativeUri(directive.uri).map(
- (refFile) {
- if (refFile != null) {
- return ImportAugmentationDirectiveWithFile(
- container: this,
+ final uriStr = directive.uri;
+ if (uriStr != null) {
+ return file._fileForRelativeUri(uriStr).map(
+ (refFile) {
+ if (refFile != null) {
+ return ImportAugmentationDirectiveWithFile(
+ container: this,
+ directive: directive,
+ importedFile: refFile,
+ );
+ } else {
+ return ImportAugmentationWithUri(
+ directive: directive,
+ uriStr: uriStr,
+ );
+ }
+ },
+ (externalLibrary) {
+ return ImportAugmentationWithUri(
directive: directive,
- importedFile: refFile,
+ uriStr: uriStr,
);
- } else {
- return ImportAugmentationDirectiveState(
- directive: directive,
- );
- }
- },
- (externalLibrary) {
- return ImportAugmentationDirectiveState(
- directive: directive,
- );
- },
- );
+ },
+ );
+ } else {
+ return ImportAugmentationDirectiveState(
+ directive: directive,
+ );
+ }
}).toList();
}
List<ExportDirectiveState> get exports {
return _exports ??= file.unlinked2.exports.map((directive) {
final uriStr = file._selectRelativeUri(directive);
- return file._fileForRelativeUri(uriStr).map(
- (refFile) {
- if (refFile != null) {
- return ExportDirectiveWithFile(
- container: this,
+ if (uriStr != null) {
+ return file._fileForRelativeUri(uriStr).map(
+ (refFile) {
+ if (refFile != null) {
+ return ExportDirectiveWithFile(
+ container: this,
+ directive: directive,
+ exportedFile: refFile,
+ selectedUriStr: uriStr,
+ );
+ } else {
+ return ExportDirectiveWithUri(
+ directive: directive,
+ selectedUriStr: uriStr,
+ );
+ }
+ },
+ (externalLibrary) {
+ return ExportDirectiveWithInSummarySource(
directive: directive,
- exportedFile: refFile,
+ exportedSource: externalLibrary.source,
+ selectedUriStr: uriStr,
);
- } else {
- return ExportDirectiveState(
- directive: directive,
- );
- }
- },
- (externalLibrary) {
- return ExportDirectiveWithInSummarySource(
- directive: directive,
- exportedSource: externalLibrary.source,
- );
- },
- );
+ },
+ );
+ } else {
+ return ExportDirectiveState(
+ directive: directive,
+ );
+ }
}).toList();
}
List<ImportDirectiveState> get imports {
return _imports ??= file.unlinked2.imports.map((directive) {
final uriStr = file._selectRelativeUri(directive);
- return file._fileForRelativeUri(uriStr).map(
- (refFile) {
- if (refFile != null) {
- return ImportDirectiveWithFile(
- container: this,
+ if (uriStr != null) {
+ return file._fileForRelativeUri(uriStr).map(
+ (refFile) {
+ if (refFile != null) {
+ return ImportDirectiveWithFile(
+ container: this,
+ directive: directive,
+ importedFile: refFile,
+ selectedUriStr: uriStr,
+ );
+ } else {
+ return ImportDirectiveWithUri(
+ directive: directive,
+ selectedUriStr: uriStr,
+ );
+ }
+ },
+ (externalLibrary) {
+ return ImportDirectiveWithInSummarySource(
directive: directive,
- importedFile: refFile,
+ importedSource: externalLibrary.source,
+ selectedUriStr: uriStr,
);
- } else {
- return ImportDirectiveState(
- directive: directive,
- );
- }
- },
- (externalLibrary) {
- return ImportDirectiveWithInSummarySource(
- directive: directive,
- importedSource: externalLibrary.source,
- );
- },
- );
+ },
+ );
+ } else {
+ return ImportDirectiveState(
+ directive: directive,
+ );
+ }
}).toList();
}
+ /// Collect files that are transitively referenced by this library.
+ @mustCallSuper
+ void collectTransitive(Set<FileState> files) {
+ if (files.add(file)) {
+ for (final augmentation in augmentations) {
+ if (augmentation is ImportAugmentationDirectiveWithFile) {
+ augmentation.importedAugmentation?.collectTransitive(files);
+ }
+ }
+ for (final export in exports) {
+ if (export is ExportDirectiveWithFile) {
+ export.exportedLibrary?.collectTransitive(files);
+ }
+ }
+ for (final import in imports) {
+ if (import is ImportDirectiveWithFile) {
+ import.importedLibrary?.collectTransitive(files);
+ }
+ }
+ }
+ }
+
/// Directives are usually pulled lazily (so that we can parse a file
/// without pulling all its transitive references), but when we output
/// textual dumps we want to check that we reference only objects that
@@ -1826,13 +1928,14 @@
Source? get includedSource => null;
}
-/// [PartDirectiveState] that has a valid URI that references a file.
-class PartDirectiveWithFile extends PartDirectiveState {
+/// [PartDirectiveWithUri] that has a valid URI that references a file.
+class PartDirectiveWithFile extends PartDirectiveWithUri {
final FileState includedFile;
PartDirectiveWithFile({
required super.library,
required super.directive,
+ required super.uriStr,
required this.includedFile,
}) {
includedFile.referencingFiles.add(library.file);
@@ -1857,6 +1960,17 @@
}
}
+/// [PartDirectiveState] that has a valid URI.
+class PartDirectiveWithUri extends PartDirectiveState {
+ final String uriStr;
+
+ PartDirectiveWithUri({
+ required super.library,
+ required super.directive,
+ required this.uriStr,
+ });
+}
+
/// The file has `part of` directive.
abstract class PartFileStateKind extends FileStateKind {
PartFileStateKind({
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index a81f6e1..a584d14 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -618,13 +618,15 @@
directive.prefix?.staticElement = importElement.prefix;
final importDirectiveState = _library.imports[index];
// TODO(scheglov) rewrite
- if (importDirectiveState.importedSource != null) {
- if (importDirectiveState.importedLibrarySource == null) {
- libraryErrorReporter.reportErrorForNode(
- CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY,
- directive.uri,
- [importDirectiveState.directive.uri],
- );
+ if (importDirectiveState is ImportDirectiveWithUri) {
+ if (importDirectiveState.importedSource != null) {
+ if (importDirectiveState.importedLibrarySource == null) {
+ libraryErrorReporter.reportErrorForNode(
+ CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY,
+ directive.uri,
+ [importDirectiveState.selectedUriStr],
+ );
+ }
}
}
}
@@ -637,13 +639,15 @@
directive.element = exportElement;
final exportDirectiveState = _library.exports[index];
// TODO(scheglov) rewrite
- if (exportDirectiveState.exportedSource != null) {
- if (exportDirectiveState.exportedLibrarySource == null) {
- libraryErrorReporter.reportErrorForNode(
- CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
- directive.uri,
- [exportDirectiveState.directive.uri],
- );
+ if (exportDirectiveState is ExportDirectiveWithUri) {
+ if (exportDirectiveState.exportedSource != null) {
+ if (exportDirectiveState.exportedLibrarySource == null) {
+ libraryErrorReporter.reportErrorForNode(
+ CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
+ directive.uri,
+ [exportDirectiveState.selectedUriStr],
+ );
+ }
}
}
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart b/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart
index 41dc29c..0f37cef 100644
--- a/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart
@@ -91,7 +91,7 @@
}
class UnlinkedImportAugmentationDirective {
- final String uri;
+ final String? uri;
UnlinkedImportAugmentationDirective({
required this.uri,
@@ -101,17 +101,17 @@
SummaryDataReader reader,
) {
return UnlinkedImportAugmentationDirective(
- uri: reader.readStringUtf8(),
+ uri: reader.readOptionalStringUtf8(),
);
}
void write(BufferedSink sink) {
- sink.writeStringUtf8(uri);
+ sink.writeOptionalStringUtf8(uri);
}
}
class UnlinkedLibraryAugmentationDirective {
- final String uri;
+ final String? uri;
final UnlinkedSourceRange uriRange;
UnlinkedLibraryAugmentationDirective({
@@ -123,13 +123,13 @@
SummaryDataReader reader,
) {
return UnlinkedLibraryAugmentationDirective(
- uri: reader.readStringUtf8(),
+ uri: reader.readOptionalStringUtf8(),
uriRange: UnlinkedSourceRange.read(reader),
);
}
void write(BufferedSink sink) {
- sink.writeStringUtf8(uri);
+ sink.writeOptionalStringUtf8(uri);
uriRange.write(sink);
}
}
@@ -163,7 +163,7 @@
/// The URI referenced by this directive, nad used by default when none
/// of the [configurations] matches.
- final String uri;
+ final String? uri;
UnlinkedNamespaceDirective({
required this.configurations,
@@ -176,7 +176,7 @@
configurations: reader.readTypedList(
() => UnlinkedNamespaceDirectiveConfiguration.read(reader),
),
- uri: reader.readStringUtf8(),
+ uri: reader.readOptionalStringUtf8(),
isSyntheticDartCoreImport: reader.readBool(),
);
}
@@ -188,7 +188,7 @@
x.write(sink);
},
);
- sink.writeStringUtf8(uri);
+ sink.writeOptionalStringUtf8(uri);
sink.writeBool(isSyntheticDartCoreImport);
}
}
@@ -199,7 +199,7 @@
final String name;
/// The URI to be used if the condition is true.
- final String uri;
+ final String? uri;
/// The value to which the value of the declared variable will be compared,
/// or the empty string if the condition does not include an equality test.
@@ -216,20 +216,20 @@
) {
return UnlinkedNamespaceDirectiveConfiguration(
name: reader.readStringUtf8(),
- uri: reader.readStringUtf8(),
+ uri: reader.readOptionalStringUtf8(),
value: reader.readStringUtf8(),
);
}
void write(BufferedSink sink) {
sink.writeStringUtf8(name);
- sink.writeStringUtf8(uri);
+ sink.writeOptionalStringUtf8(uri);
sink.writeStringUtf8(value);
}
}
class UnlinkedPartDirective {
- final String uri;
+ final String? uri;
UnlinkedPartDirective({
required this.uri,
@@ -239,12 +239,12 @@
SummaryDataReader reader,
) {
return UnlinkedPartDirective(
- uri: reader.readStringUtf8(),
+ uri: reader.readOptionalStringUtf8(),
);
}
void write(BufferedSink sink) {
- sink.writeStringUtf8(uri);
+ sink.writeOptionalStringUtf8(uri);
}
}
@@ -273,7 +273,7 @@
}
class UnlinkedPartOfUriDirective {
- final String uri;
+ final String? uri;
final UnlinkedSourceRange uriRange;
UnlinkedPartOfUriDirective({
@@ -285,13 +285,13 @@
SummaryDataReader reader,
) {
return UnlinkedPartOfUriDirective(
- uri: reader.readStringUtf8(),
+ uri: reader.readOptionalStringUtf8(),
uriRange: UnlinkedSourceRange.read(reader),
);
}
void write(BufferedSink sink) {
- sink.writeStringUtf8(uri);
+ sink.writeOptionalStringUtf8(uri);
uriRange.write(sink);
}
}
diff --git a/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart b/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart
index 1c43336..3580fac 100644
--- a/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart
+++ b/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart
@@ -110,10 +110,11 @@
sink.write('notAugmentation ${idProvider.fileState(file)}');
}
sink.writeln();
+ } else if (import is ImportAugmentationWithUri) {
+ final uriStr = _stringOfUriStr(import.uriStr);
+ _writelnWithIndent('uri: $uriStr');
} else {
- sink.write(_indent);
- sink.write('uri: ${_stringOfUriStr(import.directive.uri)}');
- sink.writeln();
+ _writelnWithIndent('noUri');
}
},
);
@@ -202,10 +203,11 @@
sink.write(' notLibrary');
}
sink.writeln();
+ } else if (export is ExportDirectiveWithUri) {
+ final uriStr = _stringOfUriStr(export.selectedUriStr);
+ _writelnWithIndent('uri: $uriStr');
} else {
- sink.write(_indent);
- sink.write('uri: ${_stringOfUriStr(export.directive.uri)}');
- sink.writeln();
+ _writelnWithIndent('noUri');
}
},
);
@@ -252,13 +254,15 @@
sink.write(' synthetic');
}
sink.writeln();
- } else {
+ } else if (import is ImportDirectiveWithUri) {
sink.write(_indent);
- sink.write('uri: ${_stringOfUriStr(import.directive.uri)}');
+ sink.write('uri: ${_stringOfUriStr(import.selectedUriStr)}');
if (import.isSyntheticDartCoreImport) {
sink.write(' synthetic');
}
sink.writeln();
+ } else {
+ _writelnWithIndent('noUri');
}
},
);
@@ -548,10 +552,11 @@
sink.write('notPart ${idProvider.fileState(file)}');
}
sink.writeln();
+ } else if (part is PartDirectiveWithUri) {
+ final uriStr = _stringOfUriStr(part.uriStr);
+ _writelnWithIndent('uri: $uriStr');
} else {
- sink.write(_indent);
- sink.write('uri: ${_stringOfUriStr(part.directive.uri)}');
- sink.writeln();
+ _writelnWithIndent('noUri');
}
});
}
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 ef21d7a..1336d79 100644
--- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -1470,7 +1470,36 @@
''');
}
- test_newFile_library_augmentations_invalidRelativeUri() async {
+ test_newFile_library_augmentations_emptyUri() {
+ final a = newFile('$testPackageLibPath/a.dart', r'''
+import augment '';
+''');
+
+ fileStateFor(a);
+
+ assertDriverStateString(testFile, r'''
+files
+ /home/test/lib/a.dart
+ uri: package:test/a.dart
+ current
+ id: file_0
+ kind: library_0
+ imports
+ library_1 dart:core synthetic
+ augmentations
+ notAugmentation file_0
+ cycle_0
+ dependencies: dart:core
+ libraries: library_0
+ apiSignature_0
+ referencingFiles: file_0
+ unlinkedKey: k00
+libraryCycles
+elementFactory
+''');
+ }
+
+ test_newFile_library_augmentations_invalidUri_cannotParse() async {
final a = newFile('$testPackageLibPath/a.dart', r'''
import augment 'da:';
''');
@@ -1498,9 +1527,9 @@
''');
}
- test_newFile_library_augmentations_invalidRelativeUri_empty() {
+ test_newFile_library_augmentations_invalidUri_interpolation() async {
final a = newFile('$testPackageLibPath/a.dart', r'''
-import augment '';
+import augment '${'foo.dart'}';
''');
fileStateFor(a);
@@ -1515,7 +1544,7 @@
imports
library_1 dart:core synthetic
augmentations
- uri: ''
+ noUri
cycle_0
dependencies: dart:core
libraries: library_0
@@ -1623,6 +1652,35 @@
''');
}
+ test_newFile_library_exports_emptyUri() {
+ final a = newFile('$testPackageLibPath/a.dart', r'''
+export '';
+''');
+
+ fileStateFor(a);
+
+ assertDriverStateString(testFile, r'''
+files
+ /home/test/lib/a.dart
+ uri: package:test/a.dart
+ current
+ id: file_0
+ kind: library_0
+ imports
+ library_1 dart:core synthetic
+ exports
+ library_0
+ cycle_0
+ dependencies: dart:core
+ libraries: library_0
+ apiSignature_0
+ referencingFiles: file_0
+ unlinkedKey: k00
+libraryCycles
+elementFactory
+''');
+ }
+
test_newFile_library_exports_inSummary_library() async {
// Prepare a bundle where `package:foo/foo.dart` is a library.
final librarySummaryFiles = <File>[];
@@ -1801,7 +1859,7 @@
''');
}
- test_newFile_library_exports_invalidRelativeUri() async {
+ test_newFile_library_exports_invalidUri_cannotParse() async {
final a = newFile('$testPackageLibPath/a.dart', r'''
export 'net:';
''');
@@ -1829,9 +1887,9 @@
''');
}
- test_newFile_library_exports_invalidRelativeUri_empty() {
+ test_newFile_library_exports_invalidUri_interpolation() async {
final a = newFile('$testPackageLibPath/a.dart', r'''
-export '';
+export '${'foo.dart'}';
''');
fileStateFor(a);
@@ -1846,7 +1904,7 @@
imports
library_1 dart:core synthetic
exports
- uri: ''
+ noUri
cycle_0
dependencies: dart:core
libraries: library_0
@@ -2008,7 +2066,35 @@
''');
}
- test_newFile_library_imports_invalidRelativeUri() async {
+ test_newFile_library_imports_emptyUri() {
+ final a = newFile('$testPackageLibPath/a.dart', r'''
+import '';
+''');
+
+ fileStateFor(a);
+
+ assertDriverStateString(testFile, r'''
+files
+ /home/test/lib/a.dart
+ uri: package:test/a.dart
+ current
+ id: file_0
+ kind: library_0
+ imports
+ library_0
+ library_1 dart:core synthetic
+ cycle_0
+ dependencies: dart:core
+ libraries: library_0
+ apiSignature_0
+ referencingFiles: file_0
+ unlinkedKey: k00
+libraryCycles
+elementFactory
+''');
+ }
+
+ test_newFile_library_imports_invalidUri_cannotParse() async {
final a = newFile('$testPackageLibPath/a.dart', r'''
import 'da:';
''');
@@ -2035,9 +2121,9 @@
''');
}
- test_newFile_library_imports_invalidRelativeUri_empty() {
+ test_newFile_library_imports_invalidUri_interpolation() async {
final a = newFile('$testPackageLibPath/a.dart', r'''
-import '';
+import '${'foo.dart'}';
''');
fileStateFor(a);
@@ -2050,7 +2136,7 @@
id: file_0
kind: library_0
imports
- uri: ''
+ noUri
library_1 dart:core synthetic
cycle_0
dependencies: dart:core
@@ -2519,7 +2605,36 @@
''');
}
- test_newFile_library_parts_invalidRelativeUri() {
+ test_newFile_library_parts_emptyUri() {
+ final a = newFile('$testPackageLibPath/a.dart', r'''
+part '';
+''');
+
+ fileStateFor(a);
+
+ assertDriverStateString(testFile, r'''
+files
+ /home/test/lib/a.dart
+ uri: package:test/a.dart
+ current
+ id: file_0
+ kind: library_0
+ imports
+ library_1 dart:core synthetic
+ parts
+ notPart file_0
+ cycle_0
+ dependencies: dart:core
+ libraries: library_0
+ apiSignature_0
+ referencingFiles: file_0
+ unlinkedKey: k00
+libraryCycles
+elementFactory
+''');
+ }
+
+ test_newFile_library_parts_invalidUri_cannotParse() {
final a = newFile('$testPackageLibPath/a.dart', r'''
part 'da:';
''');
@@ -2547,9 +2662,9 @@
''');
}
- test_newFile_library_parts_invalidRelativeUri_empty() {
+ test_newFile_library_parts_invalidUri_interpolation() {
final a = newFile('$testPackageLibPath/a.dart', r'''
-part '';
+part '${'foo.dart'}';
''');
fileStateFor(a);
@@ -2564,7 +2679,7 @@
imports
library_1 dart:core synthetic
parts
- uri: ''
+ noUri
cycle_0
dependencies: dart:core
libraries: library_0
diff --git a/pkg/analyzer/test/src/summary/elements_test.dart b/pkg/analyzer/test/src/summary/elements_test.dart
index dc9ab8f..2c410d6 100644
--- a/pkg/analyzer/test/src/summary/elements_test.dart
+++ b/pkg/analyzer/test/src/summary/elements_test.dart
@@ -32861,6 +32861,7 @@
''');
}
+ /// TODO(scheglov) The part should disappear after finishing [PartElement].
test_part_emptyUri() async {
var library = await buildLibrary(r'''
part '';
@@ -32873,6 +32874,12 @@
class B @15
constructors
synthetic @-1
+ parts
+
+ classes
+ class B @15
+ constructors
+ synthetic @-1
''');
}
diff --git a/pkg/test_runner/lib/src/command.dart b/pkg/test_runner/lib/src/command.dart
index 8db8dfb..07241ef 100644
--- a/pkg/test_runner/lib/src/command.dart
+++ b/pkg/test_runner/lib/src/command.dart
@@ -267,6 +267,18 @@
index: index);
@override
+ Dart2jsCompilationCommand indexedCopy(int index) => Dart2jsCompilationCommand(
+ outputFile,
+ _bootstrapDependencies,
+ executable,
+ arguments,
+ environmentOverrides,
+ useSdk: useSdk,
+ alwaysCompile: _alwaysCompile,
+ workingDirectory: workingDirectory,
+ index: index);
+
+ @override
CommandOutput createOutput(int exitCode, bool timedOut, List<int> stdout,
List<int> stderr, Duration time, bool compilationSkipped,
[int? pid = 0]) {
@@ -322,6 +334,15 @@
index: index);
@override
+ DevCompilerCompilationCommand indexedCopy(int index) =>
+ DevCompilerCompilationCommand(outputFile, _bootstrapDependencies,
+ executable, arguments, environmentOverrides,
+ compilerPath: compilerPath,
+ alwaysCompile: _alwaysCompile,
+ workingDirectory: workingDirectory,
+ index: index);
+
+ @override
CommandOutput createOutput(int exitCode, bool timedOut, List<int> stdout,
List<int> stderr, Duration time, bool compilationSkipped,
[int pid = 0]) {
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index b3c5cbb..6a24139 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -957,8 +957,3 @@
int main(int argc, char** argv) {
return dart::bin::main(argc, argv);
}
-
-// TODO(riscv): Why is this missing from libc?
-#if defined(__riscv)
-char __libc_single_threaded = 0;
-#endif
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 2d8b531..3b07ebd 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -1442,8 +1442,3 @@
dart::bin::main(argc, argv);
UNREACHABLE();
}
-
-// TODO(riscv): Why is this missing from libc?
-#if defined(__riscv)
-char __libc_single_threaded = 0;
-#endif
diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc
index 994f542..db8c47d 100644
--- a/runtime/bin/run_vm_tests.cc
+++ b/runtime/bin/run_vm_tests.cc
@@ -426,8 +426,3 @@
int main(int argc, const char** argv) {
dart::bin::Platform::Exit(dart::Main(argc, argv));
}
-
-// TODO(riscv): Why is this missing from libc?
-#if defined(__riscv)
-char __libc_single_threaded = 0;
-#endif
diff --git a/runtime/lib/async.cc b/runtime/lib/async.cc
index 5a11f34..f2e539b 100644
--- a/runtime/lib/async.cc
+++ b/runtime/lib/async.cc
@@ -22,4 +22,44 @@
return Object::null();
}
+// Instantiate generic [closure] using the type argument T
+// corresponding to Future<T> in the given [future] instance
+// (which may extend or implement Future).
+DEFINE_NATIVE_ENTRY(SuspendState_instantiateClosureWithFutureTypeArgument,
+ 0,
+ 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(Closure, closure, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Instance, future, arguments->NativeArgAt(1));
+ IsolateGroup* isolate_group = thread->isolate_group();
+
+ const auto& future_class =
+ Class::Handle(zone, isolate_group->object_store()->future_class());
+ ASSERT(future_class.NumTypeArguments() == 1);
+
+ const auto& cls = Class::Handle(zone, future.clazz());
+ auto& type =
+ AbstractType::Handle(zone, cls.GetInstantiationOf(zone, future_class));
+ ASSERT(!type.IsNull());
+ if (!type.IsInstantiated()) {
+ const auto& instance_type_args =
+ TypeArguments::Handle(zone, future.GetTypeArguments());
+ type =
+ type.InstantiateFrom(instance_type_args, Object::null_type_arguments(),
+ kNoneFree, Heap::kNew);
+ }
+ auto& type_args = TypeArguments::Handle(zone, type.arguments());
+ if (type_args.Length() != 1) {
+ // Create a new TypeArguments vector of length 1.
+ type = type_args.TypeAtNullSafe(0);
+ type_args = TypeArguments::New(1);
+ type_args.SetTypeAt(0, type);
+ }
+ type_args = type_args.Canonicalize(thread, nullptr);
+
+ ASSERT(closure.delayed_type_arguments() ==
+ Object::empty_type_arguments().ptr());
+ closure.set_delayed_type_arguments(type_args);
+ return closure.ptr();
+}
+
} // namespace dart
diff --git a/runtime/vm/app_snapshot.cc b/runtime/vm/app_snapshot.cc
index 67d6ca8..dcf35fd 100644
--- a/runtime/vm/app_snapshot.cc
+++ b/runtime/vm/app_snapshot.cc
@@ -1988,14 +1988,12 @@
// indirectly by passing the field to the runtime. A const closure
// is a call target because its function may be called indirectly
// via a closure call.
- if (!only_call_targets || target->IsCode() || target->IsFunction() ||
- target->IsField() || target->IsClosure()) {
+ intptr_t cid = target->GetClassIdMayBeSmi();
+ if (!only_call_targets || (cid == kCodeCid) || (cid == kFunctionCid) ||
+ (cid == kFieldCid) || (cid == kClosureCid)) {
s->Push(target);
- } else {
- intptr_t cid = target->GetClassIdMayBeSmi();
- if (cid >= kNumPredefinedCids) {
- s->Push(s->isolate_group()->class_table()->At(cid));
- }
+ } else if (cid >= kNumPredefinedCids) {
+ s->Push(s->isolate_group()->class_table()->At(cid));
}
}
}
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index c2b2ddc..dbbaa95 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -66,6 +66,7 @@
V(SendPortImpl_sendInternal_, 2) \
V(Smi_bitNegate, 1) \
V(Smi_bitLength, 1) \
+ V(SuspendState_instantiateClosureWithFutureTypeArgument, 2) \
V(Mint_bitNegate, 1) \
V(Mint_bitLength, 1) \
V(Developer_debugger, 2) \
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 0e7442a..98a84ec 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -9500,8 +9500,7 @@
JSONArray jstream(&obj, "available");
Timeline::PrintFlagsToJSONArray(&jstream);
const char* js_str = js.ToCString();
-#define TIMELINE_STREAM_CHECK(name, fuchsia_name) \
- EXPECT_SUBSTRING(#name, js_str);
+#define TIMELINE_STREAM_CHECK(name, ...) EXPECT_SUBSTRING(#name, js_str);
TIMELINE_STREAM_LIST(TIMELINE_STREAM_CHECK)
#undef TIMELINE_STREAM_CHECK
}
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 85cf403..af7a225 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -296,7 +296,7 @@
#if defined(SUPPORT_TIMELINE)
static const char* const timeline_streams_enum_names[] = {
"all",
-#define DEFINE_NAME(name, unused) #name,
+#define DEFINE_NAME(name, ...) #name,
TIMELINE_STREAM_LIST(DEFINE_NAME)
#undef DEFINE_NAME
NULL};
@@ -328,7 +328,7 @@
return false;
}
-#define SET_ENABLE_STREAM(name, unused) \
+#define SET_ENABLE_STREAM(name, ...) \
Timeline::SetStream##name##Enabled(HasStream(streams, #name));
TIMELINE_STREAM_LIST(SET_ENABLE_STREAM);
#undef SET_ENABLE_STREAM
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index 90b0a23..f5140c6 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -202,7 +202,7 @@
ASSERT(recorder_ != NULL);
enabled_streams_ = GetEnabledByDefaultTimelineStreams();
// Global overrides.
-#define TIMELINE_STREAM_FLAG_DEFAULT(name, fuchsia_name) \
+#define TIMELINE_STREAM_FLAG_DEFAULT(name, ...) \
stream_##name##_.set_enabled(HasStream(enabled_streams_, #name));
TIMELINE_STREAM_LIST(TIMELINE_STREAM_FLAG_DEFAULT)
#undef TIMELINE_STREAM_FLAG_DEFAULT
@@ -218,7 +218,7 @@
#endif
// Disable global streams.
-#define TIMELINE_STREAM_DISABLE(name, fuchsia_name) \
+#define TIMELINE_STREAM_DISABLE(name, ...) \
Timeline::stream_##name##_.set_enabled(false);
TIMELINE_STREAM_LIST(TIMELINE_STREAM_DISABLE)
#undef TIMELINE_STREAM_DISABLE
@@ -265,7 +265,7 @@
#ifndef PRODUCT
void Timeline::PrintFlagsToJSONArray(JSONArray* arr) {
-#define ADD_RECORDED_STREAM_NAME(name, fuchsia_name) \
+#define ADD_RECORDED_STREAM_NAME(name, ...) \
if (stream_##name##_.enabled()) { \
arr->AddValue(#name); \
}
@@ -285,13 +285,13 @@
}
{
JSONArray availableStreams(&obj, "availableStreams");
-#define ADD_STREAM_NAME(name, fuchsia_name) availableStreams.AddValue(#name);
+#define ADD_STREAM_NAME(name, ...) availableStreams.AddValue(#name);
TIMELINE_STREAM_LIST(ADD_STREAM_NAME);
#undef ADD_STREAM_NAME
}
{
JSONArray recordedStreams(&obj, "recordedStreams");
-#define ADD_RECORDED_STREAM_NAME(name, fuchsia_name) \
+#define ADD_RECORDED_STREAM_NAME(name, ...) \
if (stream_##name##_.enabled()) { \
recordedStreams.AddValue(#name); \
}
@@ -402,8 +402,9 @@
MallocGrowableArray<char*>* Timeline::enabled_streams_ = NULL;
bool Timeline::recorder_discards_clock_values_ = false;
-#define TIMELINE_STREAM_DEFINE(name, fuchsia_name) \
- TimelineStream Timeline::stream_##name##_(#name, fuchsia_name, false);
+#define TIMELINE_STREAM_DEFINE(name, fuchsia_name, static_labels) \
+ TimelineStream Timeline::stream_##name##_(#name, fuchsia_name, \
+ static_labels, false);
TIMELINE_STREAM_LIST(TIMELINE_STREAM_DEFINE)
#undef TIMELINE_STREAM_DEFINE
@@ -774,6 +775,7 @@
TimelineStream::TimelineStream(const char* name,
const char* fuchsia_name,
+ bool has_static_labels,
bool enabled)
: name_(name),
fuchsia_name_(fuchsia_name),
@@ -786,6 +788,7 @@
#if defined(DART_HOST_OS_MACOS)
if (__builtin_available(iOS 12.0, macOS 10.14, *)) {
macos_log_ = os_log_create("Dart", name);
+ has_static_labels_ = has_static_labels;
}
#endif
}
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index 7b89e4b..8071185 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -57,23 +57,26 @@
#define STARTUP_RECORDER_NAME "Startup"
#define SYSTRACE_RECORDER_NAME "Systrace"
-// (name, fuchsia_name).
+// (name, fuchsia_name, has_static_labels).
#define TIMELINE_STREAM_LIST(V) \
- V(API, "dart:api") \
- V(Compiler, "dart:compiler") \
- V(CompilerVerbose, "dart:compiler.verbose") \
- V(Dart, "dart:dart") \
- V(Debugger, "dart:debugger") \
- V(Embedder, "dart:embedder") \
- V(GC, "dart:gc") \
- V(Isolate, "dart:isolate") \
- V(VM, "dart:vm")
+ V(API, "dart:api", true) \
+ V(Compiler, "dart:compiler", true) \
+ V(CompilerVerbose, "dart:compiler.verbose", true) \
+ V(Dart, "dart:dart", false) \
+ V(Debugger, "dart:debugger", true) \
+ V(Embedder, "dart:embedder", false) \
+ V(GC, "dart:gc", true) \
+ V(Isolate, "dart:isolate", true) \
+ V(VM, "dart:vm", true)
// A stream of timeline events. A stream has a name and can be enabled or
// disabled (globally and per isolate).
class TimelineStream {
public:
- TimelineStream(const char* name, const char* fuchsia_name, bool enabled);
+ TimelineStream(const char* name,
+ const char* fuchsia_name,
+ bool static_labels,
+ bool enabled);
const char* name() const { return name_; }
const char* fuchsia_name() const { return fuchsia_name_; }
@@ -105,7 +108,8 @@
#if defined(DART_HOST_OS_FUCHSIA)
trace_site_t* trace_site() { return &trace_site_; }
#elif defined(DART_HOST_OS_MACOS)
- os_log_t macos_log() { return macos_log_; }
+ os_log_t macos_log() const { return macos_log_; }
+ bool has_static_labels() const { return has_static_labels_; }
#endif
private:
@@ -120,6 +124,7 @@
trace_site_t trace_site_ = {};
#elif defined(DART_HOST_OS_MACOS)
os_log_t macos_log_ = {};
+ bool has_static_labels_ = false;
#endif
};
@@ -196,12 +201,12 @@
static void PrintFlagsToJSONArray(JSONArray* arr);
#endif
-#define TIMELINE_STREAM_ACCESSOR(name, fuchsia_name) \
+#define TIMELINE_STREAM_ACCESSOR(name, ...) \
static TimelineStream* Get##name##Stream() { return &stream_##name##_; }
TIMELINE_STREAM_LIST(TIMELINE_STREAM_ACCESSOR)
#undef TIMELINE_STREAM_ACCESSOR
-#define TIMELINE_STREAM_FLAGS(name, fuchsia_name) \
+#define TIMELINE_STREAM_FLAGS(name, ...) \
static void SetStream##name##Enabled(bool enabled) { \
stream_##name##_.set_enabled(enabled); \
}
@@ -216,7 +221,7 @@
static MallocGrowableArray<char*>* enabled_streams_;
static bool recorder_discards_clock_values_;
-#define TIMELINE_STREAM_DECLARE(name, fuchsia_name) \
+#define TIMELINE_STREAM_DECLARE(name, ...) \
static TimelineStream stream_##name##_;
TIMELINE_STREAM_LIST(TIMELINE_STREAM_DECLARE)
#undef TIMELINE_STREAM_DECLARE
diff --git a/runtime/vm/timeline_macos.cc b/runtime/vm/timeline_macos.cc
index d187617..55e0b24 100644
--- a/runtime/vm/timeline_macos.cc
+++ b/runtime/vm/timeline_macos.cc
@@ -30,39 +30,45 @@
}
const char* label = event->label();
+ bool is_static_label = event->stream_->has_static_labels();
uint8_t _Alignas(16) buffer[64];
buffer[0] = 0;
switch (event->event_type()) {
- case TimelineEvent::kInstant: {
- _os_signpost_emit_with_name_impl(&__dso_handle, log, OS_SIGNPOST_EVENT,
- OS_SIGNPOST_ID_EXCLUSIVE, label, "",
- buffer, sizeof(buffer));
+ case TimelineEvent::kInstant:
+ if (is_static_label) {
+ _os_signpost_emit_with_name_impl(&__dso_handle, log, OS_SIGNPOST_EVENT,
+ OS_SIGNPOST_ID_EXCLUSIVE, label, "",
+ buffer, sizeof(buffer));
+ } else {
+ os_signpost_event_emit(log, OS_SIGNPOST_ID_EXCLUSIVE, "Event", "%s",
+ label);
+ }
break;
- }
case TimelineEvent::kBegin:
- case TimelineEvent::kAsyncBegin: {
- _os_signpost_emit_with_name_impl(&__dso_handle, log,
- OS_SIGNPOST_INTERVAL_BEGIN, event->Id(),
- label, "", buffer, sizeof(buffer));
+ case TimelineEvent::kAsyncBegin:
+ if (is_static_label) {
+ _os_signpost_emit_with_name_impl(
+ &__dso_handle, log, OS_SIGNPOST_INTERVAL_BEGIN, event->Id(), label,
+ "", buffer, sizeof(buffer));
+ } else {
+ os_signpost_interval_begin(log, event->Id(), "Event", "%s", label);
+ }
break;
- }
case TimelineEvent::kEnd:
- case TimelineEvent::kAsyncEnd: {
- _os_signpost_emit_with_name_impl(&__dso_handle, log,
- OS_SIGNPOST_INTERVAL_END, event->Id(),
- label, "", buffer, sizeof(buffer));
+ case TimelineEvent::kAsyncEnd:
+ if (is_static_label) {
+ _os_signpost_emit_with_name_impl(&__dso_handle, log,
+ OS_SIGNPOST_INTERVAL_END, event->Id(),
+ label, "", buffer, sizeof(buffer));
+ } else {
+ os_signpost_interval_end(log, event->Id(), "Event");
+ }
break;
- }
- case TimelineEvent::kCounter: {
- const char* fmt = "%s";
- Utils::SNPrint(reinterpret_cast<char*>(buffer), sizeof(buffer), fmt,
- event->arguments()[0].value);
- _os_signpost_emit_with_name_impl(&__dso_handle, log, OS_SIGNPOST_EVENT,
- OS_SIGNPOST_ID_EXCLUSIVE, label, fmt,
- buffer, sizeof(buffer));
+ case TimelineEvent::kCounter:
+ os_signpost_event_emit(log, OS_SIGNPOST_ID_EXCLUSIVE, "Counter", "%s=%s",
+ label, event->arguments()[0].value);
break;
- }
default:
break;
}
diff --git a/runtime/vm/timeline_test.cc b/runtime/vm/timeline_test.cc
index 3c5ec04..09d226b 100644
--- a/runtime/vm/timeline_test.cc
+++ b/runtime/vm/timeline_test.cc
@@ -105,7 +105,7 @@
TEST_CASE(TimelineEventIsValid) {
// Create a test stream.
- TimelineStream stream("testStream", "testStream", true);
+ TimelineStream stream("testStream", "testStream", false, true);
TimelineEvent event;
TimelineTestHelper::SetStream(&event, &stream);
@@ -124,7 +124,7 @@
TEST_CASE(TimelineEventDuration) {
// Create a test stream.
- TimelineStream stream("testStream", "testStream", true);
+ TimelineStream stream("testStream", "testStream", false, true);
// Create a test event.
TimelineEvent event;
@@ -139,7 +139,7 @@
TEST_CASE(TimelineEventDurationPrintJSON) {
// Create a test stream.
- TimelineStream stream("testStream", "testStream", true);
+ TimelineStream stream("testStream", "testStream", false, true);
// Create a test event.
TimelineEvent event;
@@ -169,7 +169,7 @@
char buffer[kBufferLength];
// Create a test stream.
- TimelineStream stream("testStream", "testStream", true);
+ TimelineStream stream("testStream", "testStream", false, true);
// Create a test event.
TimelineEvent event;
@@ -213,7 +213,7 @@
TEST_CASE(TimelineEventArguments) {
// Create a test stream.
- TimelineStream stream("testStream", "testStream", true);
+ TimelineStream stream("testStream", "testStream", false, true);
// Create a test event.
TimelineEvent event;
@@ -233,7 +233,7 @@
TEST_CASE(TimelineEventArgumentsPrintJSON) {
// Create a test stream.
- TimelineStream stream("testStream", "testStream", true);
+ TimelineStream stream("testStream", "testStream", false, true);
// Create a test event.
TimelineEvent event;
@@ -296,7 +296,7 @@
}
// Create a test stream.
- TimelineStream stream("testStream", "testStream", true);
+ TimelineStream stream("testStream", "testStream", false, true);
TimelineEvent* event = NULL;
@@ -341,7 +341,7 @@
}
TEST_CASE(TimelineRingRecorderJSONOrder) {
- TimelineStream stream("testStream", "testStream", true);
+ TimelineStream stream("testStream", "testStream", false, true);
TimelineEventRingRecorder* recorder =
new TimelineEventRingRecorder(TimelineEventBlock::kBlockSize * 2);
diff --git a/sdk/lib/_internal/vm/lib/async_patch.dart b/sdk/lib/_internal/vm/lib/async_patch.dart
index 50a419b..976860f 100644
--- a/sdk/lib/_internal/vm/lib/async_patch.dart
+++ b/sdk/lib/_internal/vm/lib/async_patch.dart
@@ -419,6 +419,26 @@
zone.scheduleMicrotask(run);
}
+ @pragma("vm:invisible")
+ @pragma("vm:prefer-inline")
+ void _awaitUserDefinedFuture(Future future) {
+ // Create a generic callback closure and instantiate it
+ // using the type argument of Future.
+ // This is needed to avoid unsoundness which may happen if user-defined
+ // Future.then casts callback to Function(dynamic) passes a value of
+ // incorrect type.
+ @pragma("vm:invisible")
+ dynamic typedCallback<T>(T value) {
+ return unsafeCast<dynamic Function(dynamic)>(_thenCallback)(value);
+ }
+
+ future.then(
+ unsafeCast<dynamic Function(dynamic)>(
+ _instantiateClosureWithFutureTypeArgument(typedCallback, future)),
+ onError:
+ unsafeCast<dynamic Function(Object, StackTrace)>(_errorCallback));
+ }
+
@pragma("vm:entry-point", "call")
@pragma("vm:invisible")
Object? _await(Object? object) {
@@ -437,9 +457,7 @@
} else if (object is! Future) {
_awaitNotFuture(object);
} else {
- object.then(unsafeCast<dynamic Function(dynamic)>(_thenCallback),
- onError:
- unsafeCast<dynamic Function(Object, StackTrace)>(_errorCallback));
+ _awaitUserDefinedFuture(object);
}
return _functionData;
}
@@ -612,6 +630,11 @@
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
external _SuspendState _clone();
+
+ @pragma("vm:external-name",
+ "SuspendState_instantiateClosureWithFutureTypeArgument")
+ external static Function _instantiateClosureWithFutureTypeArgument(
+ dynamic Function<T>(T) closure, Future future);
}
class _SyncStarIterable<T> extends Iterable<T> {
diff --git a/tests/language/async/await_user_defined_future_soundness_test.dart b/tests/language/async/await_user_defined_future_soundness_test.dart
new file mode 100644
index 0000000..351d2ae
--- /dev/null
+++ b/tests/language/async/await_user_defined_future_soundness_test.dart
@@ -0,0 +1,51 @@
+// 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.
+
+// Verifies that user-define Future cannot provide a value of incorrect
+// type by casting 'onValue' callback.
+// Regression test for https://github.com/dart-lang/sdk/issues/49345.
+
+import 'dart:async';
+
+import "package:expect/expect.dart";
+
+import 'dart:async';
+
+bool checkpoint1 = false;
+bool checkpoint2 = false;
+bool checkpoint3 = false;
+bool checkpoint4 = false;
+
+Future<void> foo(Future<String> f) async {
+ checkpoint1 = true;
+ final String result = await f;
+ checkpoint3 = true;
+ print(result.runtimeType);
+}
+
+class F implements Future<String> {
+ Future<R> then<R>(FutureOr<R> Function(String) onValue, {Function? onError}) {
+ checkpoint2 = true;
+ final result = (onValue as FutureOr<R> Function(dynamic))(10);
+ checkpoint4 = true;
+ return Future.value(result);
+ }
+
+ @override
+ dynamic noSuchMethod(i) => throw 'Unimplimented';
+}
+
+void main() {
+ bool seenError = false;
+ runZoned(() {
+ foo(F());
+ }, onError: (e, st) {
+ seenError = true;
+ });
+ Expect.isTrue(checkpoint1);
+ Expect.isTrue(checkpoint2);
+ Expect.isFalse(checkpoint3);
+ Expect.isFalse(checkpoint4);
+ Expect.isTrue(seenError);
+}
diff --git a/tests/language_2/async/await_user_defined_future_soundness_test.dart b/tests/language_2/async/await_user_defined_future_soundness_test.dart
new file mode 100644
index 0000000..351cdd9
--- /dev/null
+++ b/tests/language_2/async/await_user_defined_future_soundness_test.dart
@@ -0,0 +1,53 @@
+// 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.
+
+// @dart = 2.9
+
+// Verifies that user-define Future cannot provide a value of incorrect
+// type by casting 'onValue' callback.
+// Regression test for https://github.com/dart-lang/sdk/issues/49345.
+
+import 'dart:async';
+
+import "package:expect/expect.dart";
+
+import 'dart:async';
+
+bool checkpoint1 = false;
+bool checkpoint2 = false;
+bool checkpoint3 = false;
+bool checkpoint4 = false;
+
+Future<void> foo(Future<String> f) async {
+ checkpoint1 = true;
+ final String result = await f;
+ checkpoint3 = true;
+ print(result.runtimeType);
+}
+
+class F implements Future<String> {
+ Future<R> then<R>(FutureOr<R> Function(String) onValue, {Function onError}) {
+ checkpoint2 = true;
+ final result = (onValue as FutureOr<R> Function(dynamic))(10);
+ checkpoint4 = true;
+ return Future.value(result);
+ }
+
+ @override
+ dynamic noSuchMethod(i) => throw 'Unimplimented';
+}
+
+void main() {
+ bool seenError = false;
+ runZoned(() {
+ foo(F());
+ }, onError: (e, st) {
+ seenError = true;
+ });
+ Expect.isTrue(checkpoint1);
+ Expect.isTrue(checkpoint2);
+ Expect.isFalse(checkpoint3);
+ Expect.isFalse(checkpoint4);
+ Expect.isTrue(seenError);
+}
diff --git a/tools/VERSION b/tools/VERSION
index ef321a3..bdb2bf8 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 18
PATCH 0
-PRERELEASE 242
+PRERELEASE 243
PRERELEASE_PATCH 0
\ No newline at end of file