Version 2.10.0-104.0.dev
Merge commit '4237fda6a52cb51b93a8968f3b5b4f2599564233' into 'dev'
diff --git a/DEPS b/DEPS
index 9ad040a..0b5e7df 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
# co19 is a cipd package. Use update.sh in tests/co19[_2] to update these
# hashes. It requires access to the dart-build-access group, which EngProd
# has.
- "co19_rev": "c99bc4280fe5ea323c4c937fd073c5e2d17fd975",
+ "co19_rev": "d21ed3a1dd64107916db68afdce21709df65e85f",
"co19_2_rev": "e48b3090826cf40b8037648f19d211e8eab1b4b6",
# The internal benchmarks to use. See go/dart-benchmarks-internal
@@ -112,7 +112,7 @@
"idl_parser_rev": "5fb1ebf49d235b5a70c9f49047e83b0654031eb7",
"intl_tag": "0.16.1",
"jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
- "json_rpc_2_rev": "995611cf006c927d51cc53cb28f1aa4356d5414f",
+ "json_rpc_2_rev": "8f189db8f0c299187a0e8fa959dba7e9b0254be5",
"linter_tag": "0.1.118",
"logging_rev": "9561ba016ae607747ae69b846c0e10958ca58ed4",
"markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
index 0b5c365..6508967 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
@@ -4,6 +4,8 @@
library _fe_analyzer_shared.parser.parser;
+import 'package:_fe_analyzer_shared/src/parser/type_info_impl.dart';
+
import '../messages/codes.dart' as codes;
import '../scanner/scanner.dart' show ErrorToken, Token;
@@ -1130,8 +1132,59 @@
}
if (optional('=', next)) {
equals = next;
- token = computeType(equals, /* required = */ true)
- .ensureTypeOrVoid(equals, this);
+ TypeInfo type = computeType(equals, /* required = */ true);
+ if (!type.isFunctionType) {
+ // Recovery: In certain cases insert missing 'Function' and missing
+ // parens.
+ Token skippedType = type.skipType(equals);
+ if (optional('(', skippedType.next) &&
+ skippedType.next.endGroup != null &&
+ optional(';', skippedType.next.endGroup.next)) {
+ // Turn "<return type>? '(' <whatever> ')';"
+ // into "<return type>? Function '(' <whatever> ')';".
+ // Assume the type is meant as the return type.
+ Token functionToken =
+ rewriter.insertSyntheticKeyword(skippedType, Keyword.FUNCTION);
+ reportRecoverableError(functionToken,
+ codes.templateExpectedButGot.withArguments('Function'));
+ type = computeType(equals, /* required = */ true);
+ } else if (type is NoType &&
+ optional('<', skippedType.next) &&
+ skippedType.next.endGroup != null) {
+ // Recover these two:
+ // "<whatever>;" => "Function<whatever>();"
+ // "<whatever>(<whatever>);" => "Function<whatever>(<whatever>);"
+ Token endGroup = skippedType.next.endGroup;
+ bool recover = false;
+ if (optional(';', endGroup.next)) {
+ // Missing parenthesis. Insert them.
+ // Turn "<whatever>;" in to "<whatever>();"
+ // Insert missing 'Function' below.
+ reportRecoverableError(endGroup,
+ missingParameterMessage(MemberKind.FunctionTypeAlias));
+ rewriter.insertParens(endGroup, /*includeIdentifier =*/ false);
+ recover = true;
+ } else if (optional('(', endGroup.next) &&
+ endGroup.next.endGroup != null &&
+ optional(';', endGroup.next.endGroup.next)) {
+ // "<whatever>(<whatever>);". Insert missing 'Function' below.
+ recover = true;
+ }
+
+ if (recover) {
+ // Assume the '<' indicates type arguments to the function.
+ // Insert 'Function' before them.
+ Token functionToken =
+ rewriter.insertSyntheticKeyword(equals, Keyword.FUNCTION);
+ reportRecoverableError(functionToken,
+ codes.templateExpectedButGot.withArguments('Function'));
+ type = computeType(equals, /* required = */ true);
+ }
+ } else {
+ // E.g. "typedef j = foo;" -- don't attempt any recovery.
+ }
+ }
+ token = type.ensureTypeOrVoid(equals, this);
} else {
// A rewrite caused the = to disappear
token = parseFormalParametersRequiredOpt(
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart b/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart
index 39c2633..260047a 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart
@@ -30,6 +30,10 @@
/// Return true if the receiver has a trailing `?`.
bool get isNullable;
+ /// Returns true if the type represents a function type, i.e. something like
+ /// void Function foo(int x);
+ bool get isFunctionType;
+
/// Call this function when the token after [token] must be a type (not void).
/// This function will call the appropriate event methods on the [Parser]'s
/// listener to handle the type, inserting a synthetic type reference if
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/type_info_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/type_info_impl.dart
index 9c27c64..6e81efc 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/type_info_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/type_info_impl.dart
@@ -102,6 +102,9 @@
bool get isNullable => false;
@override
+ bool get isFunctionType => false;
+
+ @override
Token ensureTypeNotVoid(Token token, Parser parser) {
parser.reportRecoverableErrorWithToken(
token.next, codes.templateExpectedType);
@@ -143,6 +146,9 @@
bool get isNullable => false;
@override
+ bool get isFunctionType => false;
+
+ @override
Token ensureTypeNotVoid(Token token, Parser parser) =>
parseType(token, parser);
@@ -192,6 +198,9 @@
bool get isNullable => true;
@override
+ bool get isFunctionType => false;
+
+ @override
Token parseTypeRest(Token start, Token token, Parser parser) {
token = token.next;
assert(optional('?', token));
@@ -223,6 +232,9 @@
bool get isNullable => false;
@override
+ bool get isFunctionType => false;
+
+ @override
Token ensureTypeNotVoid(Token token, Parser parser) =>
parseType(token, parser);
@@ -267,6 +279,9 @@
bool get isNullable => true;
@override
+ bool get isFunctionType => false;
+
+ @override
Token parseTypeRest(Token start, Parser parser) {
Token token = start.next;
assert(optional('?', token));
@@ -294,6 +309,9 @@
bool get isNullable => false;
@override
+ bool get isFunctionType => false;
+
+ @override
Token ensureTypeNotVoid(Token token, Parser parser) =>
parseType(token, parser);
@@ -339,6 +357,9 @@
bool get isNullable => false;
@override
+ bool get isFunctionType => false;
+
+ @override
Token ensureTypeNotVoid(Token token, Parser parser) {
// Report an error, then parse `void` as if it were a type name.
parser.reportRecoverableError(token.next, codes.messageInvalidVoid);
@@ -463,6 +484,9 @@
bool get isNullable => beforeQuestionMark != null;
@override
+ bool get isFunctionType => gftHasReturnType != null;
+
+ @override
Token ensureTypeNotVoid(Token token, Parser parser) =>
parseType(token, parser);
diff --git a/pkg/analysis_server/lib/src/computer/computer_signature.dart b/pkg/analysis_server/lib/src/computer/computer_signature.dart
index ac5038e..6c2f036 100644
--- a/pkg/analysis_server/lib/src/computer/computer_signature.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_signature.dart
@@ -17,10 +17,14 @@
class DartUnitSignatureComputer {
final DartdocDirectiveInfo _dartdocInfo;
final AstNode _node;
+ ArgumentList _argumentList;
DartUnitSignatureComputer(
this._dartdocInfo, CompilationUnit _unit, int _offset)
: _node = NodeLocator(_offset).searchWithin(_unit);
+ /// The [ArgumentList] node located by [compute].
+ ArgumentList get argumentList => _argumentList;
+
bool get offsetIsValid => _node != null;
/// Returns the computed signature information, maybe `null`.
@@ -64,6 +68,8 @@
return null;
}
+ _argumentList = args;
+
final parameters =
execElement.parameters.map((p) => _convertParam(p)).toList();
@@ -76,7 +82,9 @@
return ParameterInfo(
param.isOptionalPositional
? ParameterKind.OPTIONAL
- : param.isPositional ? ParameterKind.REQUIRED : ParameterKind.NAMED,
+ : param.isPositional
+ ? ParameterKind.REQUIRED
+ : ParameterKind.NAMED,
param.displayName,
param.type.getDisplayString(withNullability: false),
defaultValue: param.defaultValueCode);
diff --git a/pkg/analysis_server/lib/src/lsp/client_configuration.dart b/pkg/analysis_server/lib/src/lsp/client_configuration.dart
index fbca273..ebf42b7 100644
--- a/pkg/analysis_server/lib/src/lsp/client_configuration.dart
+++ b/pkg/analysis_server/lib/src/lsp/client_configuration.dart
@@ -10,6 +10,13 @@
bool get enableSdkFormatter => _settings['enableSdkFormatter'] ?? true;
int get lineLength => _settings['lineLength'];
+ /// A preview flag for enabling commit characters for completions.
+ ///
+ /// This is a temporary setting to allow this feature to be tested without
+ /// defaulting to on for everybody.
+ bool get previewCommitCharacters =>
+ _settings['previewCommitCharacters'] ?? false;
+
void replace(Map<String, dynamic> newConfig) {
_settings
..clear()
diff --git a/pkg/analysis_server/lib/src/lsp/constants.dart b/pkg/analysis_server/lib/src/lsp/constants.dart
index 93bf55a..5440da6 100644
--- a/pkg/analysis_server/lib/src/lsp/constants.dart
+++ b/pkg/analysis_server/lib/src/lsp/constants.dart
@@ -4,6 +4,19 @@
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+/// The characters that will cause the editor to automatically commit the selected
+/// completion item.
+///
+/// For example, pressing `(` at the location of `^` in the code below would
+/// automatically commit the functions name and insert a `(` to avoid either having
+/// to press `<enter>` and then `(` or having `()` included in the completion items
+/// `insertText` (which is incorrect when passing a function around rather than
+/// invoking it).
+///
+/// myLongFunctionName();
+/// print(myLong^)
+const dartCompletionCommitCharacters = ['.', '('];
+
/// Set the characters that will cause the editor to automatically
/// trigger completion.
/// TODO(dantup): There are several characters that we want to conditionally
@@ -26,10 +39,11 @@
/// for the VS Code implementation of this.
const dartCompletionTriggerCharacters = ['.', '=', '(', r'$'];
-/// TODO(dantup): Signature help triggering is even more sensitive to
-/// bad chars, so we'll need to implement the logic described here:
-/// https://github.com/dart-lang/sdk/issues/34241
-const dartSignatureHelpTriggerCharacters = <String>[];
+/// Characters that refresh signature help only if it's already open on the client.
+const dartSignatureHelpRetriggerCharacters = <String>[','];
+
+/// Characters that automatically trigger signature help when typed in the client.
+const dartSignatureHelpTriggerCharacters = <String>['('];
/// Characters to trigger formatting when format-on-type is enabled.
const dartTypeFormattingCharacters = ['}', ';'];
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart
index 9627589..de886e7 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart
@@ -10,22 +10,35 @@
import 'package:analysis_server/src/lsp/mapping.dart';
class SignatureHelpHandler
- extends MessageHandler<TextDocumentPositionParams, SignatureHelp> {
+ extends MessageHandler<SignatureHelpParams, SignatureHelp> {
SignatureHelpHandler(LspAnalysisServer server) : super(server);
@override
Method get handlesMessage => Method.textDocument_signatureHelp;
@override
- LspJsonHandler<TextDocumentPositionParams> get jsonHandler =>
- TextDocumentPositionParams.jsonHandler;
+ LspJsonHandler<SignatureHelpParams> get jsonHandler =>
+ SignatureHelpParams.jsonHandler;
@override
Future<ErrorOr<SignatureHelp>> handle(
- TextDocumentPositionParams params, CancellationToken token) async {
+ SignatureHelpParams params, CancellationToken token) async {
if (!isDartDocument(params.textDocument)) {
return success(null);
}
+ // If triggered automatically by pressing the trigger character, we will
+ // only provide results if the character we typed was the one that actually
+ // starts the argument list. This is to avoid popping open signature help
+ // whenever the user types a `(` that might not be the start of an argument
+ // list, as the client does not have any context and will always send the
+ // request.
+ final autoTriggered = params.context?.triggerKind ==
+ SignatureHelpTriggerKind.TriggerCharacter &&
+ // Retriggers can be ignored (treated as manual invocations) as it's
+ // fine to always generate results if the signature help is already
+ // visible on the client (it will just update, it doesn't pop up new UI).
+ params.context?.isRetrigger == false;
+
final pos = params.position;
final path = pathOfDoc(params.textDocument);
final unit = await path.mapResult(requireResolvedUnit);
@@ -43,6 +56,17 @@
if (signature == null) {
return success(); // No error, just no valid hover.
}
+
+ // Skip results if this was an auto-trigger but not from the start of the
+ // argument list.
+ // The ArgumentList's offset is before the paren, but the request offset
+ // will be after.
+ if (autoTriggered &&
+ computer.argumentList != null &&
+ offset != computer.argumentList.offset + 1) {
+ return success();
+ }
+
final formats = server?.clientCapabilities?.textDocument?.signatureHelp
?.signatureInformation?.documentationFormat;
return success(toSignatureHelp(formats, signature));
diff --git a/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart b/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
index ad70fb7..2dd8cd2 100644
--- a/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
+++ b/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
@@ -106,6 +106,8 @@
clientCapabilities.textDocument?.rename?.prepareSupport ?? false;
final enableFormatter = _server.clientConfiguration.enableSdkFormatter;
+ final previewCommitCharacters =
+ _server.clientConfiguration.previewCommitCharacters;
final dynamicRegistrations = ClientDynamicRegistrations(clientCapabilities);
@@ -132,6 +134,9 @@
? null
: CompletionOptions(
triggerCharacters: dartCompletionTriggerCharacters,
+ allCommitCharacters: previewCommitCharacters
+ ? dartCompletionCommitCharacters
+ : null,
resolveProvider: true,
),
hoverProvider: dynamicRegistrations.hover
@@ -141,6 +146,7 @@
? null
: SignatureHelpOptions(
triggerCharacters: dartSignatureHelpTriggerCharacters,
+ retriggerCharacters: dartSignatureHelpRetriggerCharacters,
),
definitionProvider: dynamicRegistrations.definition
? null
@@ -242,6 +248,8 @@
final registrations = <Registration>[];
final enableFormatter = _server.clientConfiguration.enableSdkFormatter;
+ final previewCommitCharacters =
+ _server.clientConfiguration.previewCommitCharacters;
/// Helper for creating registrations with IDs.
void register(bool condition, Method method, [ToJsonable options]) {
@@ -279,6 +287,8 @@
CompletionRegistrationOptions(
documentSelector: allTypes,
triggerCharacters: dartCompletionTriggerCharacters,
+ allCommitCharacters:
+ previewCommitCharacters ? dartCompletionCommitCharacters : null,
resolveProvider: true,
),
);
@@ -293,6 +303,7 @@
SignatureHelpRegistrationOptions(
documentSelector: allTypes,
triggerCharacters: dartSignatureHelpTriggerCharacters,
+ retriggerCharacters: dartSignatureHelpRetriggerCharacters,
),
);
register(
diff --git a/pkg/analysis_server/lib/src/services/correction/organize_imports.dart b/pkg/analysis_server/lib/src/services/correction/organize_imports.dart
index ae1b4c6..9d77655 100644
--- a/pkg/analysis_server/lib/src/services/correction/organize_imports.dart
+++ b/pkg/analysis_server/lib/src/services/correction/organize_imports.dart
@@ -80,15 +80,20 @@
}
// Check if the comment is the first comment in the document
if (firstComment != unit.beginToken.precedingComments) {
- var previousLine = lineInfo
+ var previousDirectiveLine = lineInfo
.getLocation(directive.beginToken.previous.end)
.lineNumber;
- // Check if the comment is after the last token of the previous line
- // Only connect, if it's not on the same line as the last token of the previous line
- if (lineInfo.getLocation(firstComment.offset).lineNumber !=
- previousLine) {
- offset = firstComment.offset;
+ // Skip over any comments on the same line as the previous directive
+ // as they will be attached to the end of it.
+ var comment = firstComment;
+ while (comment != null &&
+ previousDirectiveLine ==
+ lineInfo.getLocation(comment.offset).lineNumber) {
+ comment = comment.next;
+ }
+ if (comment != null) {
+ offset = comment.offset;
}
}
}
diff --git a/pkg/analysis_server/test/lsp/completion_test.dart b/pkg/analysis_server/test/lsp/completion_test.dart
index dc2b461..478aaf0 100644
--- a/pkg/analysis_server/test/lsp/completion_test.dart
+++ b/pkg/analysis_server/test/lsp/completion_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/src/lsp/constants.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:test/test.dart';
@@ -29,6 +30,41 @@
);
}
+ Future<void> test_commitCharacter_config() async {
+ final registrations = <Registration>[];
+ // Provide empty config and collect dynamic registrations during
+ // initialization.
+ await provideConfig(
+ () => monitorDynamicRegistrations(
+ registrations,
+ () => initialize(
+ textDocumentCapabilities: withAllSupportedDynamicRegistrations(
+ emptyTextDocumentClientCapabilities),
+ workspaceCapabilities:
+ withDidChangeConfigurationDynamicRegistration(
+ withConfigurationSupport(
+ emptyWorkspaceClientCapabilities))),
+ ),
+ {},
+ );
+
+ Registration registration(Method method) =>
+ registrationFor(registrations, method);
+
+ // By default, there should be no commit characters.
+ var reg = registration(Method.textDocument_completion);
+ var options = reg.registerOptions as CompletionRegistrationOptions;
+ expect(options.allCommitCharacters, isNull);
+
+ // When we change config, we should get a re-registration (unregister then
+ // register) for completion which now includes the commit characters.
+ await monitorDynamicReregistration(
+ registrations, () => updateConfig({'previewCommitCharacters': true}));
+ reg = registration(Method.textDocument_completion);
+ options = reg.registerOptions as CompletionRegistrationOptions;
+ expect(options.allCommitCharacters, equals(dartCompletionCommitCharacters));
+ }
+
Future<void> test_completionKinds_default() async {
newFile(join(projectFolderPath, 'file.dart'));
newFolder(join(projectFolderPath, 'folder'));
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index 4f9bb53..f7ec998 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -833,12 +833,14 @@
return expectSuccessfulResponseTo<List<Location>>(request);
}
- Future<SignatureHelp> getSignatureHelp(Uri uri, Position pos) {
+ Future<SignatureHelp> getSignatureHelp(Uri uri, Position pos,
+ [SignatureHelpContext context]) {
final request = makeRequest(
Method.textDocument_signatureHelp,
- TextDocumentPositionParams(
+ SignatureHelpParams(
textDocument: TextDocumentIdentifier(uri: uri.toString()),
position: pos,
+ context: context,
),
);
return expectSuccessfulResponseTo<SignatureHelp>(request);
@@ -1001,6 +1003,16 @@
);
}
+ /// Expects both unregistration and reregistration.
+ Future<ResponseMessage> monitorDynamicReregistration(
+ List<Registration> registrations,
+ Future<ResponseMessage> Function() f,
+ ) =>
+ monitorDynamicUnregistrations(
+ registrations,
+ () => monitorDynamicRegistrations(registrations, f),
+ );
+
/// Watches for `client/unregisterCapability` requests and updates
/// `registrations`.
Future<ResponseMessage> monitorDynamicUnregistrations(
diff --git a/pkg/analysis_server/test/lsp/signature_help_test.dart b/pkg/analysis_server/test/lsp/signature_help_test.dart
index 64937a9..889f9e8 100644
--- a/pkg/analysis_server/test/lsp/signature_help_test.dart
+++ b/pkg/analysis_server/test/lsp/signature_help_test.dart
@@ -153,6 +153,38 @@
);
}
+ Future<void> test_manualTrigger_invalidLocation() async {
+ // If the user invokes signature help, we should show it even if it's a
+ // location where we wouldn't automatically trigger (for example in a string).
+ final content = '''
+ /// Does foo.
+ foo(String s, int i) {
+ foo('this is a (^test');
+ }
+ ''';
+ final expectedLabel = 'foo(String s, int i)';
+ final expectedDoc = 'Does foo.';
+
+ await initialize(
+ textDocumentCapabilities: withSignatureHelpContentFormat(
+ emptyTextDocumentClientCapabilities, [MarkupKind.Markdown]));
+ await openFile(mainFileUri, withoutMarkers(content));
+
+ await testSignature(
+ content,
+ expectedLabel,
+ expectedDoc,
+ [
+ ParameterInformation(label: 'String s'),
+ ParameterInformation(label: 'int i'),
+ ],
+ expectedFormat: MarkupKind.Markdown,
+ context: SignatureHelpContext(
+ triggerKind: SignatureHelpTriggerKind.Invoked,
+ isRetrigger: false,
+ ));
+ }
+
Future<void> test_nonDartFile() async {
await initialize(
textDocumentCapabilities: withSignatureHelpContentFormat(
@@ -293,6 +325,62 @@
);
}
+ Future<void> test_triggerCharacter_invalidLocation() async {
+ // The client will automatically trigger when the user types ( so we need to
+ // ignore it when we're not in a suitable location.
+ final content = '''
+ /// Does foo.
+ foo(String s, int i) {
+ foo('this is a (^test');
+ }
+ ''';
+
+ await initialize(
+ textDocumentCapabilities: withSignatureHelpContentFormat(
+ emptyTextDocumentClientCapabilities, [MarkupKind.Markdown]));
+ await openFile(mainFileUri, withoutMarkers(content));
+
+ // Expect no result.
+ final res = await getSignatureHelp(
+ mainFileUri,
+ positionFromMarker(content),
+ SignatureHelpContext(
+ triggerKind: SignatureHelpTriggerKind.TriggerCharacter,
+ isRetrigger: false,
+ ),
+ );
+ expect(res, isNull);
+ }
+
+ Future<void> test_triggerCharacter_validLocation() async {
+ final content = '''
+ /// Does foo.
+ foo(String s, int i) {
+ foo(^
+ }
+ ''';
+ final expectedLabel = 'foo(String s, int i)';
+ final expectedDoc = 'Does foo.';
+
+ await initialize(
+ textDocumentCapabilities: withSignatureHelpContentFormat(
+ emptyTextDocumentClientCapabilities, [MarkupKind.Markdown]));
+ await openFile(mainFileUri, withoutMarkers(content));
+ await testSignature(
+ content,
+ expectedLabel,
+ expectedDoc,
+ [
+ ParameterInformation(label: 'String s'),
+ ParameterInformation(label: 'int i'),
+ ],
+ expectedFormat: MarkupKind.Markdown,
+ context: SignatureHelpContext(
+ triggerKind: SignatureHelpTriggerKind.Invoked,
+ isRetrigger: false,
+ ));
+ }
+
Future<void> test_unopenFile() async {
final content = '''
/// Does foo.
@@ -324,9 +412,10 @@
String expectedDoc,
List<ParameterInformation> expectedParams, {
MarkupKind expectedFormat = MarkupKind.Markdown,
+ SignatureHelpContext context,
}) async {
- final res =
- await getSignatureHelp(mainFileUri, positionFromMarker(fileContent));
+ final res = await getSignatureHelp(
+ mainFileUri, positionFromMarker(fileContent), context);
// TODO(dantup): Update this when there is clarification on how to handle
// no valid selected parameter.
diff --git a/pkg/analysis_server/test/services/correction/organize_directives_test.dart b/pkg/analysis_server/test/services/correction/organize_directives_test.dart
index e5180c5..c2e47ac 100644
--- a/pkg/analysis_server/test/services/correction/organize_directives_test.dart
+++ b/pkg/analysis_server/test/services/correction/organize_directives_test.dart
@@ -359,6 +359,32 @@
''');
}
+ Future<void> test_sort_imports_splits_comments() async {
+ // Here, the comments "b" and "ccc1" will be part of the same list
+ // of comments so need to be split.
+ await _computeUnitAndErrors(r'''
+// copyright
+import 'b.dart'; // b
+// ccc1
+// ccc2
+import 'c.dart'; // c
+// aaa1
+// aaa2
+import 'a.dart'; // a
+''');
+
+ _assertOrganize(r'''
+// copyright
+// aaa1
+// aaa2
+import 'a.dart'; // a
+import 'b.dart'; // b
+// ccc1
+// ccc2
+import 'c.dart'; // c
+''');
+ }
+
Future<void> test_sort_imports_with_library_keepPrecedingComments() async {
await _computeUnitAndErrors(r'''
/// Copyright...
diff --git a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
index 57ee4dc..efa84ae 100644
--- a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
+++ b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
@@ -113,6 +113,10 @@
codeLength = codeElement.codeLength;
}
+ if (codeOffset == null || codeLength == null) {
+ return null;
+ }
+
// Read the declaration so we can get the offset after the doc comments.
final declaration = codeElement.session
.getParsedLibrary(location.file)
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart b/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart
new file mode 100644
index 0000000..97618bf
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart
@@ -0,0 +1,14 @@
+typedef a = foo Function(int x); // OK.
+typedef b = Function(int x); // OK.
+typedef c = foo(int x); // error.
+typedef d = (int x); // error.
+typedef e = foo<F>(int x); // error.
+typedef f = <F>(int x); // error.
+typedef g = foo<F, G, H, I, J>(int x); // error.
+typedef h = <F, G, H, I, J>(int x); // error.
+typedef i = <F, G, H, I, J>; // error.
+
+// These should be error cases according to the spec, but are valid with the
+// experimental generalized typedef.
+typedef j = foo;
+typedef k = List<int>;
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.expect
new file mode 100644
index 0000000..b3607e5
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.expect
@@ -0,0 +1,368 @@
+Problems reported:
+
+parser/error_recovery/issue_26073:3:16: Expected 'Function' before this.
+typedef c = foo(int x); // error.
+ ^
+
+parser/error_recovery/issue_26073:4:13: Expected 'Function' before this.
+typedef d = (int x); // error.
+ ^
+
+parser/error_recovery/issue_26073:5:19: Expected 'Function' before this.
+typedef e = foo<F>(int x); // error.
+ ^
+
+parser/error_recovery/issue_26073:6:13: Expected 'Function' before this.
+typedef f = <F>(int x); // error.
+ ^
+
+parser/error_recovery/issue_26073:7:31: Expected 'Function' before this.
+typedef g = foo<F, G, H, I, J>(int x); // error.
+ ^
+
+parser/error_recovery/issue_26073:8:13: Expected 'Function' before this.
+typedef h = <F, G, H, I, J>(int x); // error.
+ ^
+
+parser/error_recovery/issue_26073:9:27: A typedef needs an explicit list of parameters.
+typedef i = <F, G, H, I, J>; // error.
+ ^
+
+parser/error_recovery/issue_26073:9:13: Expected 'Function' before this.
+typedef i = <F, G, H, I, J>; // error.
+ ^
+
+beginCompilationUnit(typedef)
+ beginMetadataStar(typedef)
+ endMetadataStar(0)
+ beginUncategorizedTopLevelDeclaration(typedef)
+ beginFunctionTypeAlias(typedef)
+ handleIdentifier(a, typedefDeclaration)
+ handleNoTypeVariables(=)
+ beginFunctionType(foo)
+ handleNoTypeVariables(()
+ handleIdentifier(foo, typeReference)
+ handleNoTypeArguments(Function)
+ handleType(foo, null)
+ beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ beginMetadataStar(int)
+ endMetadataStar(0)
+ beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(x)
+ handleType(int, null)
+ handleIdentifier(x, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ endFunctionType(Function, null)
+ endFunctionTypeAlias(typedef, =, ;)
+ endTopLevelDeclaration(typedef)
+ beginMetadataStar(typedef)
+ endMetadataStar(0)
+ beginUncategorizedTopLevelDeclaration(typedef)
+ beginFunctionTypeAlias(typedef)
+ handleIdentifier(b, typedefDeclaration)
+ handleNoTypeVariables(=)
+ beginFunctionType(Function)
+ handleNoTypeVariables(()
+ handleNoType(=)
+ beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ beginMetadataStar(int)
+ endMetadataStar(0)
+ beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(x)
+ handleType(int, null)
+ handleIdentifier(x, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ endFunctionType(Function, null)
+ endFunctionTypeAlias(typedef, =, ;)
+ endTopLevelDeclaration(typedef)
+ beginMetadataStar(typedef)
+ endMetadataStar(0)
+ beginUncategorizedTopLevelDeclaration(typedef)
+ beginFunctionTypeAlias(typedef)
+ handleIdentifier(c, typedefDeclaration)
+ handleNoTypeVariables(=)
+ handleRecoverableError(Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}], (, ()
+ beginFunctionType(foo)
+ handleNoTypeVariables(()
+ handleIdentifier(foo, typeReference)
+ handleNoTypeArguments(Function)
+ handleType(foo, null)
+ beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ beginMetadataStar(int)
+ endMetadataStar(0)
+ beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(x)
+ handleType(int, null)
+ handleIdentifier(x, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ endFunctionType(Function, null)
+ endFunctionTypeAlias(typedef, =, ;)
+ endTopLevelDeclaration(typedef)
+ beginMetadataStar(typedef)
+ endMetadataStar(0)
+ beginUncategorizedTopLevelDeclaration(typedef)
+ beginFunctionTypeAlias(typedef)
+ handleIdentifier(d, typedefDeclaration)
+ handleNoTypeVariables(=)
+ handleRecoverableError(Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}], (, ()
+ beginFunctionType(Function)
+ handleNoTypeVariables(()
+ handleNoType(=)
+ beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ beginMetadataStar(int)
+ endMetadataStar(0)
+ beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(x)
+ handleType(int, null)
+ handleIdentifier(x, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ endFunctionType(Function, null)
+ endFunctionTypeAlias(typedef, =, ;)
+ endTopLevelDeclaration(typedef)
+ beginMetadataStar(typedef)
+ endMetadataStar(0)
+ beginUncategorizedTopLevelDeclaration(typedef)
+ beginFunctionTypeAlias(typedef)
+ handleIdentifier(e, typedefDeclaration)
+ handleNoTypeVariables(=)
+ handleRecoverableError(Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}], (, ()
+ beginFunctionType(foo)
+ handleNoTypeVariables(()
+ handleIdentifier(foo, typeReference)
+ beginTypeArguments(<)
+ handleIdentifier(F, typeReference)
+ handleNoTypeArguments(>)
+ handleType(F, null)
+ endTypeArguments(1, <, >)
+ handleType(foo, null)
+ beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ beginMetadataStar(int)
+ endMetadataStar(0)
+ beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(x)
+ handleType(int, null)
+ handleIdentifier(x, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ endFunctionType(Function, null)
+ endFunctionTypeAlias(typedef, =, ;)
+ endTopLevelDeclaration(typedef)
+ beginMetadataStar(typedef)
+ endMetadataStar(0)
+ beginUncategorizedTopLevelDeclaration(typedef)
+ beginFunctionTypeAlias(typedef)
+ handleIdentifier(f, typedefDeclaration)
+ handleNoTypeVariables(=)
+ handleRecoverableError(Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}], <, <)
+ beginFunctionType(Function)
+ beginTypeVariables(<)
+ beginMetadataStar(F)
+ endMetadataStar(0)
+ handleIdentifier(F, typeVariableDeclaration)
+ beginTypeVariable(F)
+ handleTypeVariablesDefined(F, 1)
+ handleNoType(F)
+ endTypeVariable(>, 0, null, null)
+ endTypeVariables(<, >)
+ handleNoType(=)
+ beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ beginMetadataStar(int)
+ endMetadataStar(0)
+ beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(x)
+ handleType(int, null)
+ handleIdentifier(x, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ endFunctionType(Function, null)
+ endFunctionTypeAlias(typedef, =, ;)
+ endTopLevelDeclaration(typedef)
+ beginMetadataStar(typedef)
+ endMetadataStar(0)
+ beginUncategorizedTopLevelDeclaration(typedef)
+ beginFunctionTypeAlias(typedef)
+ handleIdentifier(g, typedefDeclaration)
+ handleNoTypeVariables(=)
+ handleRecoverableError(Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}], (, ()
+ beginFunctionType(foo)
+ handleNoTypeVariables(()
+ handleIdentifier(foo, typeReference)
+ beginTypeArguments(<)
+ handleIdentifier(F, typeReference)
+ handleNoTypeArguments(,)
+ handleType(F, null)
+ handleIdentifier(G, typeReference)
+ handleNoTypeArguments(,)
+ handleType(G, null)
+ handleIdentifier(H, typeReference)
+ handleNoTypeArguments(,)
+ handleType(H, null)
+ handleIdentifier(I, typeReference)
+ handleNoTypeArguments(,)
+ handleType(I, null)
+ handleIdentifier(J, typeReference)
+ handleNoTypeArguments(>)
+ handleType(J, null)
+ endTypeArguments(5, <, >)
+ handleType(foo, null)
+ beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ beginMetadataStar(int)
+ endMetadataStar(0)
+ beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(x)
+ handleType(int, null)
+ handleIdentifier(x, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ endFunctionType(Function, null)
+ endFunctionTypeAlias(typedef, =, ;)
+ endTopLevelDeclaration(typedef)
+ beginMetadataStar(typedef)
+ endMetadataStar(0)
+ beginUncategorizedTopLevelDeclaration(typedef)
+ beginFunctionTypeAlias(typedef)
+ handleIdentifier(h, typedefDeclaration)
+ handleNoTypeVariables(=)
+ handleRecoverableError(Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}], <, <)
+ beginFunctionType(Function)
+ beginTypeVariables(<)
+ beginMetadataStar(F)
+ endMetadataStar(0)
+ handleIdentifier(F, typeVariableDeclaration)
+ beginTypeVariable(F)
+ beginMetadataStar(G)
+ endMetadataStar(0)
+ handleIdentifier(G, typeVariableDeclaration)
+ beginTypeVariable(G)
+ beginMetadataStar(H)
+ endMetadataStar(0)
+ handleIdentifier(H, typeVariableDeclaration)
+ beginTypeVariable(H)
+ beginMetadataStar(I)
+ endMetadataStar(0)
+ handleIdentifier(I, typeVariableDeclaration)
+ beginTypeVariable(I)
+ beginMetadataStar(J)
+ endMetadataStar(0)
+ handleIdentifier(J, typeVariableDeclaration)
+ beginTypeVariable(J)
+ handleTypeVariablesDefined(J, 5)
+ handleNoType(J)
+ endTypeVariable(>, 4, null, null)
+ handleNoType(I)
+ endTypeVariable(,, 3, null, null)
+ handleNoType(H)
+ endTypeVariable(,, 2, null, null)
+ handleNoType(G)
+ endTypeVariable(,, 1, null, null)
+ handleNoType(F)
+ endTypeVariable(,, 0, null, null)
+ endTypeVariables(<, >)
+ handleNoType(=)
+ beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ beginMetadataStar(int)
+ endMetadataStar(0)
+ beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(x)
+ handleType(int, null)
+ handleIdentifier(x, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ endFunctionType(Function, null)
+ endFunctionTypeAlias(typedef, =, ;)
+ endTopLevelDeclaration(typedef)
+ beginMetadataStar(typedef)
+ endMetadataStar(0)
+ beginUncategorizedTopLevelDeclaration(typedef)
+ beginFunctionTypeAlias(typedef)
+ handleIdentifier(i, typedefDeclaration)
+ handleNoTypeVariables(=)
+ handleRecoverableError(MissingTypedefParameters, >, >)
+ handleRecoverableError(Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}], <, <)
+ beginFunctionType(Function)
+ beginTypeVariables(<)
+ beginMetadataStar(F)
+ endMetadataStar(0)
+ handleIdentifier(F, typeVariableDeclaration)
+ beginTypeVariable(F)
+ beginMetadataStar(G)
+ endMetadataStar(0)
+ handleIdentifier(G, typeVariableDeclaration)
+ beginTypeVariable(G)
+ beginMetadataStar(H)
+ endMetadataStar(0)
+ handleIdentifier(H, typeVariableDeclaration)
+ beginTypeVariable(H)
+ beginMetadataStar(I)
+ endMetadataStar(0)
+ handleIdentifier(I, typeVariableDeclaration)
+ beginTypeVariable(I)
+ beginMetadataStar(J)
+ endMetadataStar(0)
+ handleIdentifier(J, typeVariableDeclaration)
+ beginTypeVariable(J)
+ handleTypeVariablesDefined(J, 5)
+ handleNoType(J)
+ endTypeVariable(>, 4, null, null)
+ handleNoType(I)
+ endTypeVariable(,, 3, null, null)
+ handleNoType(H)
+ endTypeVariable(,, 2, null, null)
+ handleNoType(G)
+ endTypeVariable(,, 1, null, null)
+ handleNoType(F)
+ endTypeVariable(,, 0, null, null)
+ endTypeVariables(<, >)
+ handleNoType(=)
+ beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ endFormalParameters(0, (, ), MemberKind.GeneralizedFunctionType)
+ endFunctionType(Function, null)
+ endFunctionTypeAlias(typedef, =, ;)
+ endTopLevelDeclaration(typedef)
+ beginMetadataStar(typedef)
+ endMetadataStar(0)
+ beginUncategorizedTopLevelDeclaration(typedef)
+ beginFunctionTypeAlias(typedef)
+ handleIdentifier(j, typedefDeclaration)
+ handleNoTypeVariables(=)
+ handleIdentifier(foo, typeReference)
+ handleNoTypeArguments(;)
+ handleType(foo, null)
+ endFunctionTypeAlias(typedef, =, ;)
+ endTopLevelDeclaration(typedef)
+ beginMetadataStar(typedef)
+ endMetadataStar(0)
+ beginUncategorizedTopLevelDeclaration(typedef)
+ beginFunctionTypeAlias(typedef)
+ handleIdentifier(k, typedefDeclaration)
+ handleNoTypeVariables(=)
+ handleIdentifier(List, typeReference)
+ beginTypeArguments(<)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(>)
+ handleType(int, null)
+ endTypeArguments(1, <, >)
+ handleType(List, null)
+ endFunctionTypeAlias(typedef, =, ;)
+ endTopLevelDeclaration()
+endCompilationUnit(11, )
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.intertwined.expect
new file mode 100644
index 0000000..703ab59
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.intertwined.expect
@@ -0,0 +1,498 @@
+parseUnit(typedef)
+ skipErrorTokens(typedef)
+ listener: beginCompilationUnit(typedef)
+ syntheticPreviousToken(typedef)
+ parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+ parseMetadataStar()
+ listener: beginMetadataStar(typedef)
+ listener: endMetadataStar(0)
+ parseTopLevelKeywordDeclaration(, typedef, Instance of 'DirectiveContext')
+ parseTopLevelKeywordModifiers(, typedef)
+ parseTypedef(typedef)
+ listener: beginUncategorizedTopLevelDeclaration(typedef)
+ listener: beginFunctionTypeAlias(typedef)
+ ensureIdentifierPotentiallyRecovered(typedef, typedefDeclaration, true)
+ listener: handleIdentifier(a, typedefDeclaration)
+ listener: handleNoTypeVariables(=)
+ listener: beginFunctionType(foo)
+ listener: handleNoTypeVariables(()
+ ensureIdentifier(=, typeReference)
+ listener: handleIdentifier(foo, typeReference)
+ listener: handleNoTypeArguments(Function)
+ listener: handleType(foo, null)
+ parseFormalParametersRequiredOpt(Function, MemberKind.GeneralizedFunctionType)
+ parseFormalParametersRest((, MemberKind.GeneralizedFunctionType)
+ listener: beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ parseMetadataStar(()
+ listener: beginMetadataStar(int)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(x)
+ listener: handleType(int, null)
+ ensureIdentifier(int, formalParameterDeclaration)
+ listener: handleIdentifier(x, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ listener: endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ listener: endFunctionType(Function, null)
+ ensureSemicolon())
+ listener: endFunctionTypeAlias(typedef, =, ;)
+ listener: endTopLevelDeclaration(typedef)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(typedef)
+ listener: endMetadataStar(0)
+ parseTopLevelKeywordDeclaration(;, typedef, Instance of 'DirectiveContext')
+ parseTopLevelKeywordModifiers(;, typedef)
+ parseTypedef(typedef)
+ listener: beginUncategorizedTopLevelDeclaration(typedef)
+ listener: beginFunctionTypeAlias(typedef)
+ ensureIdentifierPotentiallyRecovered(typedef, typedefDeclaration, true)
+ listener: handleIdentifier(b, typedefDeclaration)
+ listener: handleNoTypeVariables(=)
+ listener: beginFunctionType(Function)
+ listener: handleNoTypeVariables(()
+ listener: handleNoType(=)
+ parseFormalParametersRequiredOpt(Function, MemberKind.GeneralizedFunctionType)
+ parseFormalParametersRest((, MemberKind.GeneralizedFunctionType)
+ listener: beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ parseMetadataStar(()
+ listener: beginMetadataStar(int)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(x)
+ listener: handleType(int, null)
+ ensureIdentifier(int, formalParameterDeclaration)
+ listener: handleIdentifier(x, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ listener: endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ listener: endFunctionType(Function, null)
+ ensureSemicolon())
+ listener: endFunctionTypeAlias(typedef, =, ;)
+ listener: endTopLevelDeclaration(typedef)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(typedef)
+ listener: endMetadataStar(0)
+ parseTopLevelKeywordDeclaration(;, typedef, Instance of 'DirectiveContext')
+ parseTopLevelKeywordModifiers(;, typedef)
+ parseTypedef(typedef)
+ listener: beginUncategorizedTopLevelDeclaration(typedef)
+ listener: beginFunctionTypeAlias(typedef)
+ ensureIdentifierPotentiallyRecovered(typedef, typedefDeclaration, true)
+ listener: handleIdentifier(c, typedefDeclaration)
+ listener: handleNoTypeVariables(=)
+ rewriter()
+ reportRecoverableError(Function, Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}])
+ listener: handleRecoverableError(Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}], (, ()
+ listener: beginFunctionType(foo)
+ listener: handleNoTypeVariables(()
+ ensureIdentifier(=, typeReference)
+ listener: handleIdentifier(foo, typeReference)
+ listener: handleNoTypeArguments(Function)
+ listener: handleType(foo, null)
+ parseFormalParametersRequiredOpt(Function, MemberKind.GeneralizedFunctionType)
+ parseFormalParametersRest((, MemberKind.GeneralizedFunctionType)
+ listener: beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ parseMetadataStar(()
+ listener: beginMetadataStar(int)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(x)
+ listener: handleType(int, null)
+ ensureIdentifier(int, formalParameterDeclaration)
+ listener: handleIdentifier(x, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ listener: endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ listener: endFunctionType(Function, null)
+ ensureSemicolon())
+ listener: endFunctionTypeAlias(typedef, =, ;)
+ listener: endTopLevelDeclaration(typedef)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(typedef)
+ listener: endMetadataStar(0)
+ parseTopLevelKeywordDeclaration(;, typedef, Instance of 'DirectiveContext')
+ parseTopLevelKeywordModifiers(;, typedef)
+ parseTypedef(typedef)
+ listener: beginUncategorizedTopLevelDeclaration(typedef)
+ listener: beginFunctionTypeAlias(typedef)
+ ensureIdentifierPotentiallyRecovered(typedef, typedefDeclaration, true)
+ listener: handleIdentifier(d, typedefDeclaration)
+ listener: handleNoTypeVariables(=)
+ rewriter()
+ reportRecoverableError(Function, Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}])
+ listener: handleRecoverableError(Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}], (, ()
+ listener: beginFunctionType(Function)
+ listener: handleNoTypeVariables(()
+ listener: handleNoType(=)
+ parseFormalParametersRequiredOpt(Function, MemberKind.GeneralizedFunctionType)
+ parseFormalParametersRest((, MemberKind.GeneralizedFunctionType)
+ listener: beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ parseMetadataStar(()
+ listener: beginMetadataStar(int)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(x)
+ listener: handleType(int, null)
+ ensureIdentifier(int, formalParameterDeclaration)
+ listener: handleIdentifier(x, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ listener: endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ listener: endFunctionType(Function, null)
+ ensureSemicolon())
+ listener: endFunctionTypeAlias(typedef, =, ;)
+ listener: endTopLevelDeclaration(typedef)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(typedef)
+ listener: endMetadataStar(0)
+ parseTopLevelKeywordDeclaration(;, typedef, Instance of 'DirectiveContext')
+ parseTopLevelKeywordModifiers(;, typedef)
+ parseTypedef(typedef)
+ listener: beginUncategorizedTopLevelDeclaration(typedef)
+ listener: beginFunctionTypeAlias(typedef)
+ ensureIdentifierPotentiallyRecovered(typedef, typedefDeclaration, true)
+ listener: handleIdentifier(e, typedefDeclaration)
+ listener: handleNoTypeVariables(=)
+ rewriter()
+ reportRecoverableError(Function, Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}])
+ listener: handleRecoverableError(Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}], (, ()
+ listener: beginFunctionType(foo)
+ listener: handleNoTypeVariables(()
+ ensureIdentifier(=, typeReference)
+ listener: handleIdentifier(foo, typeReference)
+ listener: beginTypeArguments(<)
+ listener: handleIdentifier(F, typeReference)
+ listener: handleNoTypeArguments(>)
+ listener: handleType(F, null)
+ listener: endTypeArguments(1, <, >)
+ listener: handleType(foo, null)
+ parseFormalParametersRequiredOpt(Function, MemberKind.GeneralizedFunctionType)
+ parseFormalParametersRest((, MemberKind.GeneralizedFunctionType)
+ listener: beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ parseMetadataStar(()
+ listener: beginMetadataStar(int)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(x)
+ listener: handleType(int, null)
+ ensureIdentifier(int, formalParameterDeclaration)
+ listener: handleIdentifier(x, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ listener: endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ listener: endFunctionType(Function, null)
+ ensureSemicolon())
+ listener: endFunctionTypeAlias(typedef, =, ;)
+ listener: endTopLevelDeclaration(typedef)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(typedef)
+ listener: endMetadataStar(0)
+ parseTopLevelKeywordDeclaration(;, typedef, Instance of 'DirectiveContext')
+ parseTopLevelKeywordModifiers(;, typedef)
+ parseTypedef(typedef)
+ listener: beginUncategorizedTopLevelDeclaration(typedef)
+ listener: beginFunctionTypeAlias(typedef)
+ ensureIdentifierPotentiallyRecovered(typedef, typedefDeclaration, true)
+ listener: handleIdentifier(f, typedefDeclaration)
+ listener: handleNoTypeVariables(=)
+ rewriter()
+ reportRecoverableError(Function, Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}])
+ listener: handleRecoverableError(Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}], <, <)
+ listener: beginFunctionType(Function)
+ listener: beginTypeVariables(<)
+ listener: beginMetadataStar(F)
+ listener: endMetadataStar(0)
+ listener: handleIdentifier(F, typeVariableDeclaration)
+ listener: beginTypeVariable(F)
+ listener: handleTypeVariablesDefined(F, 1)
+ listener: handleNoType(F)
+ listener: endTypeVariable(>, 0, null, null)
+ listener: endTypeVariables(<, >)
+ listener: handleNoType(=)
+ parseFormalParametersRequiredOpt(>, MemberKind.GeneralizedFunctionType)
+ parseFormalParametersRest((, MemberKind.GeneralizedFunctionType)
+ listener: beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ parseMetadataStar(()
+ listener: beginMetadataStar(int)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(x)
+ listener: handleType(int, null)
+ ensureIdentifier(int, formalParameterDeclaration)
+ listener: handleIdentifier(x, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ listener: endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ listener: endFunctionType(Function, null)
+ ensureSemicolon())
+ listener: endFunctionTypeAlias(typedef, =, ;)
+ listener: endTopLevelDeclaration(typedef)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(typedef)
+ listener: endMetadataStar(0)
+ parseTopLevelKeywordDeclaration(;, typedef, Instance of 'DirectiveContext')
+ parseTopLevelKeywordModifiers(;, typedef)
+ parseTypedef(typedef)
+ listener: beginUncategorizedTopLevelDeclaration(typedef)
+ listener: beginFunctionTypeAlias(typedef)
+ ensureIdentifierPotentiallyRecovered(typedef, typedefDeclaration, true)
+ listener: handleIdentifier(g, typedefDeclaration)
+ listener: handleNoTypeVariables(=)
+ rewriter()
+ reportRecoverableError(Function, Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}])
+ listener: handleRecoverableError(Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}], (, ()
+ listener: beginFunctionType(foo)
+ listener: handleNoTypeVariables(()
+ ensureIdentifier(=, typeReference)
+ listener: handleIdentifier(foo, typeReference)
+ listener: beginTypeArguments(<)
+ listener: handleIdentifier(F, typeReference)
+ listener: handleNoTypeArguments(,)
+ listener: handleType(F, null)
+ listener: handleIdentifier(G, typeReference)
+ listener: handleNoTypeArguments(,)
+ listener: handleType(G, null)
+ listener: handleIdentifier(H, typeReference)
+ listener: handleNoTypeArguments(,)
+ listener: handleType(H, null)
+ listener: handleIdentifier(I, typeReference)
+ listener: handleNoTypeArguments(,)
+ listener: handleType(I, null)
+ listener: handleIdentifier(J, typeReference)
+ listener: handleNoTypeArguments(>)
+ listener: handleType(J, null)
+ listener: endTypeArguments(5, <, >)
+ listener: handleType(foo, null)
+ parseFormalParametersRequiredOpt(Function, MemberKind.GeneralizedFunctionType)
+ parseFormalParametersRest((, MemberKind.GeneralizedFunctionType)
+ listener: beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ parseMetadataStar(()
+ listener: beginMetadataStar(int)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(x)
+ listener: handleType(int, null)
+ ensureIdentifier(int, formalParameterDeclaration)
+ listener: handleIdentifier(x, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ listener: endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ listener: endFunctionType(Function, null)
+ ensureSemicolon())
+ listener: endFunctionTypeAlias(typedef, =, ;)
+ listener: endTopLevelDeclaration(typedef)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(typedef)
+ listener: endMetadataStar(0)
+ parseTopLevelKeywordDeclaration(;, typedef, Instance of 'DirectiveContext')
+ parseTopLevelKeywordModifiers(;, typedef)
+ parseTypedef(typedef)
+ listener: beginUncategorizedTopLevelDeclaration(typedef)
+ listener: beginFunctionTypeAlias(typedef)
+ ensureIdentifierPotentiallyRecovered(typedef, typedefDeclaration, true)
+ listener: handleIdentifier(h, typedefDeclaration)
+ listener: handleNoTypeVariables(=)
+ rewriter()
+ reportRecoverableError(Function, Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}])
+ listener: handleRecoverableError(Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}], <, <)
+ listener: beginFunctionType(Function)
+ listener: beginTypeVariables(<)
+ parseMetadataStar(<)
+ listener: beginMetadataStar(F)
+ listener: endMetadataStar(0)
+ ensureIdentifier(<, typeVariableDeclaration)
+ listener: handleIdentifier(F, typeVariableDeclaration)
+ listener: beginTypeVariable(F)
+ parseMetadataStar(,)
+ listener: beginMetadataStar(G)
+ listener: endMetadataStar(0)
+ ensureIdentifier(,, typeVariableDeclaration)
+ listener: handleIdentifier(G, typeVariableDeclaration)
+ listener: beginTypeVariable(G)
+ parseMetadataStar(,)
+ listener: beginMetadataStar(H)
+ listener: endMetadataStar(0)
+ ensureIdentifier(,, typeVariableDeclaration)
+ listener: handleIdentifier(H, typeVariableDeclaration)
+ listener: beginTypeVariable(H)
+ parseMetadataStar(,)
+ listener: beginMetadataStar(I)
+ listener: endMetadataStar(0)
+ ensureIdentifier(,, typeVariableDeclaration)
+ listener: handleIdentifier(I, typeVariableDeclaration)
+ listener: beginTypeVariable(I)
+ parseMetadataStar(,)
+ listener: beginMetadataStar(J)
+ listener: endMetadataStar(0)
+ ensureIdentifier(,, typeVariableDeclaration)
+ listener: handleIdentifier(J, typeVariableDeclaration)
+ listener: beginTypeVariable(J)
+ listener: handleTypeVariablesDefined(J, 5)
+ listener: handleNoType(J)
+ listener: endTypeVariable(>, 4, null, null)
+ listener: handleNoType(I)
+ listener: endTypeVariable(,, 3, null, null)
+ listener: handleNoType(H)
+ listener: endTypeVariable(,, 2, null, null)
+ listener: handleNoType(G)
+ listener: endTypeVariable(,, 1, null, null)
+ listener: handleNoType(F)
+ listener: endTypeVariable(,, 0, null, null)
+ listener: endTypeVariables(<, >)
+ listener: handleNoType(=)
+ parseFormalParametersRequiredOpt(>, MemberKind.GeneralizedFunctionType)
+ parseFormalParametersRest((, MemberKind.GeneralizedFunctionType)
+ listener: beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ parseMetadataStar(()
+ listener: beginMetadataStar(int)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(int, MemberKind.GeneralizedFunctionType, null, null, null)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(x)
+ listener: handleType(int, null)
+ ensureIdentifier(int, formalParameterDeclaration)
+ listener: handleIdentifier(x, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.GeneralizedFunctionType)
+ listener: endFormalParameters(1, (, ), MemberKind.GeneralizedFunctionType)
+ listener: endFunctionType(Function, null)
+ ensureSemicolon())
+ listener: endFunctionTypeAlias(typedef, =, ;)
+ listener: endTopLevelDeclaration(typedef)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(typedef)
+ listener: endMetadataStar(0)
+ parseTopLevelKeywordDeclaration(;, typedef, Instance of 'DirectiveContext')
+ parseTopLevelKeywordModifiers(;, typedef)
+ parseTypedef(typedef)
+ listener: beginUncategorizedTopLevelDeclaration(typedef)
+ listener: beginFunctionTypeAlias(typedef)
+ ensureIdentifierPotentiallyRecovered(typedef, typedefDeclaration, true)
+ listener: handleIdentifier(i, typedefDeclaration)
+ listener: handleNoTypeVariables(=)
+ missingParameterMessage(MemberKind.FunctionTypeAlias)
+ reportRecoverableError(>, MissingTypedefParameters)
+ listener: handleRecoverableError(MissingTypedefParameters, >, >)
+ rewriter()
+ rewriter()
+ reportRecoverableError(Function, Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}])
+ listener: handleRecoverableError(Message[ExpectedButGot, Expected 'Function' before this., null, {string: Function}], <, <)
+ listener: beginFunctionType(Function)
+ listener: beginTypeVariables(<)
+ parseMetadataStar(<)
+ listener: beginMetadataStar(F)
+ listener: endMetadataStar(0)
+ ensureIdentifier(<, typeVariableDeclaration)
+ listener: handleIdentifier(F, typeVariableDeclaration)
+ listener: beginTypeVariable(F)
+ parseMetadataStar(,)
+ listener: beginMetadataStar(G)
+ listener: endMetadataStar(0)
+ ensureIdentifier(,, typeVariableDeclaration)
+ listener: handleIdentifier(G, typeVariableDeclaration)
+ listener: beginTypeVariable(G)
+ parseMetadataStar(,)
+ listener: beginMetadataStar(H)
+ listener: endMetadataStar(0)
+ ensureIdentifier(,, typeVariableDeclaration)
+ listener: handleIdentifier(H, typeVariableDeclaration)
+ listener: beginTypeVariable(H)
+ parseMetadataStar(,)
+ listener: beginMetadataStar(I)
+ listener: endMetadataStar(0)
+ ensureIdentifier(,, typeVariableDeclaration)
+ listener: handleIdentifier(I, typeVariableDeclaration)
+ listener: beginTypeVariable(I)
+ parseMetadataStar(,)
+ listener: beginMetadataStar(J)
+ listener: endMetadataStar(0)
+ ensureIdentifier(,, typeVariableDeclaration)
+ listener: handleIdentifier(J, typeVariableDeclaration)
+ listener: beginTypeVariable(J)
+ listener: handleTypeVariablesDefined(J, 5)
+ listener: handleNoType(J)
+ listener: endTypeVariable(>, 4, null, null)
+ listener: handleNoType(I)
+ listener: endTypeVariable(,, 3, null, null)
+ listener: handleNoType(H)
+ listener: endTypeVariable(,, 2, null, null)
+ listener: handleNoType(G)
+ listener: endTypeVariable(,, 1, null, null)
+ listener: handleNoType(F)
+ listener: endTypeVariable(,, 0, null, null)
+ listener: endTypeVariables(<, >)
+ listener: handleNoType(=)
+ parseFormalParametersRequiredOpt(>, MemberKind.GeneralizedFunctionType)
+ parseFormalParametersRest((, MemberKind.GeneralizedFunctionType)
+ listener: beginFormalParameters((, MemberKind.GeneralizedFunctionType)
+ listener: endFormalParameters(0, (, ), MemberKind.GeneralizedFunctionType)
+ listener: endFunctionType(Function, null)
+ ensureSemicolon())
+ listener: endFunctionTypeAlias(typedef, =, ;)
+ listener: endTopLevelDeclaration(typedef)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(typedef)
+ listener: endMetadataStar(0)
+ parseTopLevelKeywordDeclaration(;, typedef, Instance of 'DirectiveContext')
+ parseTopLevelKeywordModifiers(;, typedef)
+ parseTypedef(typedef)
+ listener: beginUncategorizedTopLevelDeclaration(typedef)
+ listener: beginFunctionTypeAlias(typedef)
+ ensureIdentifierPotentiallyRecovered(typedef, typedefDeclaration, true)
+ listener: handleIdentifier(j, typedefDeclaration)
+ listener: handleNoTypeVariables(=)
+ listener: handleIdentifier(foo, typeReference)
+ listener: handleNoTypeArguments(;)
+ listener: handleType(foo, null)
+ ensureSemicolon(foo)
+ listener: endFunctionTypeAlias(typedef, =, ;)
+ listener: endTopLevelDeclaration(typedef)
+ parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
+ parseMetadataStar(;)
+ listener: beginMetadataStar(typedef)
+ listener: endMetadataStar(0)
+ parseTopLevelKeywordDeclaration(;, typedef, Instance of 'DirectiveContext')
+ parseTopLevelKeywordModifiers(;, typedef)
+ parseTypedef(typedef)
+ listener: beginUncategorizedTopLevelDeclaration(typedef)
+ listener: beginFunctionTypeAlias(typedef)
+ ensureIdentifierPotentiallyRecovered(typedef, typedefDeclaration, true)
+ listener: handleIdentifier(k, typedefDeclaration)
+ listener: handleNoTypeVariables(=)
+ listener: handleIdentifier(List, typeReference)
+ listener: beginTypeArguments(<)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(>)
+ listener: handleType(int, null)
+ listener: endTypeArguments(1, <, >)
+ listener: handleType(List, null)
+ ensureSemicolon(>)
+ listener: endFunctionTypeAlias(typedef, =, ;)
+ listener: endTopLevelDeclaration()
+ reportAllErrorTokens(typedef)
+ listener: endCompilationUnit(11, )
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.parser.expect b/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.parser.expect
new file mode 100644
index 0000000..fe10d95
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.parser.expect
@@ -0,0 +1,33 @@
+NOTICE: Stream was rewritten by parser!
+
+typedef a = foo Function(int x);
+typedef b = Function(int x);
+typedef c = fooFunction(int x);
+typedef d = Function(int x);
+typedef e = foo<F>Function(int x);
+typedef f = Function<F>(int x);
+typedef g = foo<F, G, H, I, J>Function(int x);
+typedef h = Function<F, G, H, I, J>(int x);
+typedef i = Function<F, G, H, I, J>();
+
+
+
+typedef j = foo;
+typedef k = List<int>;
+
+
+typedef[KeywordToken] a[StringToken] =[SimpleToken] foo[StringToken] Function[KeywordToken]([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] b[StringToken] =[SimpleToken] Function[KeywordToken]([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] c[StringToken] =[SimpleToken] foo[StringToken]Function[SyntheticKeywordToken]([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] d[StringToken] =[SimpleToken] Function[SyntheticKeywordToken]([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] e[StringToken] =[SimpleToken] foo[StringToken]<[BeginToken]F[StringToken]>[SimpleToken]Function[SyntheticKeywordToken]([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] f[StringToken] =[SimpleToken] Function[SyntheticKeywordToken]<[BeginToken]F[StringToken]>[SimpleToken]([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] g[StringToken] =[SimpleToken] foo[StringToken]<[BeginToken]F[StringToken],[SimpleToken] G[StringToken],[SimpleToken] H[StringToken],[SimpleToken] I[StringToken],[SimpleToken] J[StringToken]>[SimpleToken]Function[SyntheticKeywordToken]([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] h[StringToken] =[SimpleToken] Function[SyntheticKeywordToken]<[BeginToken]F[StringToken],[SimpleToken] G[StringToken],[SimpleToken] H[StringToken],[SimpleToken] I[StringToken],[SimpleToken] J[StringToken]>[SimpleToken]([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] i[StringToken] =[SimpleToken] Function[SyntheticKeywordToken]<[BeginToken]F[StringToken],[SimpleToken] G[StringToken],[SimpleToken] H[StringToken],[SimpleToken] I[StringToken],[SimpleToken] J[StringToken]>[SimpleToken]([SyntheticBeginToken])[SyntheticToken];[SimpleToken]
+
+
+
+typedef[KeywordToken] j[StringToken] =[SimpleToken] foo[StringToken];[SimpleToken]
+typedef[KeywordToken] k[StringToken] =[SimpleToken] List[StringToken]<[BeginToken]int[StringToken]>[SimpleToken];[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.scanner.expect b/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.scanner.expect
new file mode 100644
index 0000000..8e713ed
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_26073.dart.scanner.expect
@@ -0,0 +1,31 @@
+typedef a = foo Function(int x);
+typedef b = Function(int x);
+typedef c = foo(int x);
+typedef d = (int x);
+typedef e = foo<F>(int x);
+typedef f = <F>(int x);
+typedef g = foo<F, G, H, I, J>(int x);
+typedef h = <F, G, H, I, J>(int x);
+typedef i = <F, G, H, I, J>;
+
+
+
+typedef j = foo;
+typedef k = List<int>;
+
+
+typedef[KeywordToken] a[StringToken] =[SimpleToken] foo[StringToken] Function[KeywordToken]([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] b[StringToken] =[SimpleToken] Function[KeywordToken]([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] c[StringToken] =[SimpleToken] foo[StringToken]([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] d[StringToken] =[SimpleToken] ([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] e[StringToken] =[SimpleToken] foo[StringToken]<[BeginToken]F[StringToken]>[SimpleToken]([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] f[StringToken] =[SimpleToken] <[BeginToken]F[StringToken]>[SimpleToken]([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] g[StringToken] =[SimpleToken] foo[StringToken]<[BeginToken]F[StringToken],[SimpleToken] G[StringToken],[SimpleToken] H[StringToken],[SimpleToken] I[StringToken],[SimpleToken] J[StringToken]>[SimpleToken]([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] h[StringToken] =[SimpleToken] <[BeginToken]F[StringToken],[SimpleToken] G[StringToken],[SimpleToken] H[StringToken],[SimpleToken] I[StringToken],[SimpleToken] J[StringToken]>[SimpleToken]([BeginToken]int[StringToken] x[StringToken])[SimpleToken];[SimpleToken]
+typedef[KeywordToken] i[StringToken] =[SimpleToken] <[BeginToken]F[StringToken],[SimpleToken] G[StringToken],[SimpleToken] H[StringToken],[SimpleToken] I[StringToken],[SimpleToken] J[StringToken]>[SimpleToken];[SimpleToken]
+
+
+
+typedef[KeywordToken] j[StringToken] =[SimpleToken] foo[StringToken];[SimpleToken]
+typedef[KeywordToken] k[StringToken] =[SimpleToken] List[StringToken]<[BeginToken]int[StringToken]>[SimpleToken];[SimpleToken]
+[SimpleToken]
diff --git a/pkg/vm_snapshot_analysis/lib/precompiler_trace.dart b/pkg/vm_snapshot_analysis/lib/precompiler_trace.dart
index 2fec35e..54d86fe 100644
--- a/pkg/vm_snapshot_analysis/lib/precompiler_trace.dart
+++ b/pkg/vm_snapshot_analysis/lib/precompiler_trace.dart
@@ -5,8 +5,7 @@
/// Helpers for working with the output of `--trace-precompiler-to` VM flag.
library vm_snapshot_analysis.precompiler_trace;
-import 'dart:math' as math;
-
+import 'package:vm_snapshot_analysis/src/dominators.dart' as dominators;
import 'package:vm_snapshot_analysis/name.dart';
import 'package:vm_snapshot_analysis/program_info.dart';
@@ -37,11 +36,6 @@
/// selector id).
final data;
- /// Preorder number of this node.
- ///
- /// Computed by [CallGraph.computeDominators].
- int _preorderNumber;
-
/// Dominator of this node.
///
/// Computed by [CallGraph.computeDominators].
@@ -175,122 +169,19 @@
}
/// Compute dominator tree of the call-graph.
- ///
- /// The code for dominator tree computation is taken verbatim from the
- /// native compiler (see runtime/vm/compiler/backend/flow_graph.cc).
void computeDominators() {
- final size = nodes.length;
-
- // Compute preorder numbering for the graph using DFS.
- final parent = List<int>.filled(size, -1);
- final preorder = List<CallGraphNode>.filled(size, null);
-
- var N = 0;
- void dfs() {
- final stack = [_DfsState(p: -1, n: nodes.first)];
- while (stack.isNotEmpty) {
- final s = stack.removeLast();
- final p = s.p;
- final n = s.n;
- if (n._preorderNumber == null) {
- n._preorderNumber = N;
- preorder[n._preorderNumber] = n;
- parent[n._preorderNumber] = p;
-
- for (var w in n.succ) {
- stack.add(_DfsState(p: n._preorderNumber, n: w));
- }
-
- N++;
- }
- }
- }
-
- dfs();
-
- for (var node in nodes) {
- if (node._preorderNumber == null) {
- print('${node} is unreachable');
- }
- }
-
- // Use the SEMI-NCA algorithm to compute dominators. This is a two-pass
- // version of the Lengauer-Tarjan algorithm (LT is normally three passes)
- // that eliminates a pass by using nearest-common ancestor (NCA) to
- // compute immediate dominators from semidominators. It also removes a
- // level of indirection in the link-eval forest data structure.
- //
- // The algorithm is described in Georgiadis, Tarjan, and Werneck's
- // "Finding Dominators in Practice".
- // See http://www.cs.princeton.edu/~rwerneck/dominators/ .
-
- // All arrays are maps between preorder basic-block numbers.
- final idom = parent.toList(); // Immediate dominator.
- final semi = List<int>.generate(size, (i) => i); // Semidominator.
- final label =
- List<int>.generate(size, (i) => i); // Label for link-eval forest.
-
- void compressPath(int start, int current) {
- final next = parent[current];
- if (next > start) {
- compressPath(start, next);
- label[current] = math.min(label[current], label[next]);
- parent[current] = parent[next];
- }
- }
-
- // 1. First pass: compute semidominators as in Lengauer-Tarjan.
- // Semidominators are computed from a depth-first spanning tree and are an
- // approximation of immediate dominators.
-
- // Use a link-eval data structure with path compression. Implement path
- // compression in place by mutating the parent array. Each block has a
- // label, which is the minimum block number on the compressed path.
-
- // Loop over the blocks in reverse preorder (not including the graph
- // entry).
- for (var block_index = size - 1; block_index >= 1; --block_index) {
- // Loop over the predecessors.
- final block = preorder[block_index];
- // Clear the immediately dominated blocks in case ComputeDominators is
- // used to recompute them.
- for (final pred in block.pred) {
- // Look for the semidominator by ascending the semidominator path
- // starting from pred.
- final pred_index = pred._preorderNumber;
- var best = pred_index;
- if (pred_index > block_index) {
- compressPath(block_index, pred_index);
- best = label[pred_index];
- }
-
- // Update the semidominator if we've found a better one.
- semi[block_index] = math.min(semi[block_index], semi[best]);
- }
-
- // Now use label for the semidominator.
- label[block_index] = semi[block_index];
- }
-
- // 2. Compute the immediate dominators as the nearest common ancestor of
- // spanning tree parent and semidominator, for all blocks except the entry.
- for (var block_index = 1; block_index < size; ++block_index) {
- var dom_index = idom[block_index];
- while (dom_index > semi[block_index]) {
- dom_index = idom[dom_index];
- }
- idom[block_index] = dom_index;
- preorder[dom_index]._addDominatedBlock(preorder[block_index]);
+ final dom = dominators.computeDominators(
+ size: nodes.length,
+ root: nodes.first.id,
+ succ: (i) => nodes[i].succ.map((n) => n.id),
+ predOf: (i) => nodes[i].pred.map((n) => n.id),
+ handleEdge: (from, to) {});
+ for (var i = 1; i < nodes.length; i++) {
+ nodes[dom[i]]._addDominatedBlock(nodes[i]);
}
}
}
-class _DfsState {
- final int p;
- final CallGraphNode n;
- _DfsState({this.p, this.n});
-}
-
/// Helper class for reading `--trace-precompiler-to` output.
///
/// See README.md for description of the format.
diff --git a/pkg/vm_snapshot_analysis/lib/src/dominators.dart b/pkg/vm_snapshot_analysis/lib/src/dominators.dart
new file mode 100644
index 0000000..5e9078f
--- /dev/null
+++ b/pkg/vm_snapshot_analysis/lib/src/dominators.dart
@@ -0,0 +1,126 @@
+// Copyright (c) 2020, 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.
+
+/// Utility methods for computing dominators of an arbitrary graph.
+library vm_snapshot_analysis.src.dominators;
+
+import 'dart:math' as math;
+
+/// Compute dominator tree of the graph.
+///
+/// The code for dominator tree computation is taken verbatim from the
+/// native compiler (see runtime/vm/compiler/backend/flow_graph.cc).
+@pragma('vm:prefer-inline')
+List<int> computeDominators({
+ int size,
+ int root,
+ Iterable<int> succ(int n),
+ Iterable<int> predOf(int n),
+ void handleEdge(int from, int to),
+}) {
+ // Compute preorder numbering for the graph using DFS.
+ final parent = List<int>.filled(size, -1);
+ final preorder = List<int>.filled(size, null);
+ final preorderNumber = List<int>.filled(size, null);
+
+ var N = 0;
+ void dfs() {
+ final stack = [_DfsState(p: -1, n: root)];
+ while (stack.isNotEmpty) {
+ final s = stack.removeLast();
+ final p = s.p;
+ final n = s.n;
+ handleEdge(s.n, s.p);
+ if (preorderNumber[n] == null) {
+ preorderNumber[n] = N;
+ preorder[preorderNumber[n]] = n;
+ parent[preorderNumber[n]] = p;
+
+ for (var w in succ(n)) {
+ stack.add(_DfsState(p: preorderNumber[n], n: w));
+ }
+
+ N++;
+ }
+ }
+ }
+
+ dfs();
+
+ // Use the SEMI-NCA algorithm to compute dominators. This is a two-pass
+ // version of the Lengauer-Tarjan algorithm (LT is normally three passes)
+ // that eliminates a pass by using nearest-common ancestor (NCA) to
+ // compute immediate dominators from semidominators. It also removes a
+ // level of indirection in the link-eval forest data structure.
+ //
+ // The algorithm is described in Georgiadis, Tarjan, and Werneck's
+ // "Finding Dominators in Practice".
+
+ // All arrays are maps between preorder basic-block numbers.
+ final idom = parent.toList(); // Immediate dominator.
+ final semi = List<int>.generate(size, (i) => i); // Semidominator.
+ final label =
+ List<int>.generate(size, (i) => i); // Label for link-eval forest.
+
+ void compressPath(int start, int current) {
+ final next = parent[current];
+ if (next > start) {
+ compressPath(start, next);
+ label[current] = math.min(label[current], label[next]);
+ parent[current] = parent[next];
+ }
+ }
+
+ // 1. First pass: compute semidominators as in Lengauer-Tarjan.
+ // Semidominators are computed from a depth-first spanning tree and are an
+ // approximation of immediate dominators.
+
+ // Use a link-eval data structure with path compression. Implement path
+ // compression in place by mutating the parent array. Each block has a
+ // label, which is the minimum block number on the compressed path.
+
+ // Loop over the blocks in reverse preorder (not including the graph
+ // entry).
+ for (var block_index = size - 1; block_index >= 1; --block_index) {
+ // Loop over the predecessors.
+ final block = preorder[block_index];
+ // Clear the immediately dominated blocks in case ComputeDominators is
+ // used to recompute them.
+ for (final pred in predOf(block)) {
+ // Look for the semidominator by ascending the semidominator path
+ // starting from pred.
+ final pred_index = preorderNumber[pred];
+ var best = pred_index;
+ if (pred_index > block_index) {
+ compressPath(block_index, pred_index);
+ best = label[pred_index];
+ }
+
+ // Update the semidominator if we've found a better one.
+ semi[block_index] = math.min(semi[block_index], semi[best]);
+ }
+
+ // Now use label for the semidominator.
+ label[block_index] = semi[block_index];
+ }
+
+ // 2. Compute the immediate dominators as the nearest common ancestor of
+ // spanning tree parent and semidominator, for all blocks except the entry.
+ final result = List<int>.filled(size, -1);
+ for (var block_index = 1; block_index < size; ++block_index) {
+ var dom_index = idom[block_index];
+ while (dom_index > semi[block_index]) {
+ dom_index = idom[dom_index];
+ }
+ idom[block_index] = dom_index;
+ result[preorder[block_index]] = preorder[dom_index];
+ }
+ return result;
+}
+
+class _DfsState {
+ final int p;
+ final int n;
+ _DfsState({this.p, this.n});
+}
diff --git a/pkg/vm_snapshot_analysis/lib/v8_profile.dart b/pkg/vm_snapshot_analysis/lib/v8_profile.dart
index 6f7db7b..0c824f2 100644
--- a/pkg/vm_snapshot_analysis/lib/v8_profile.dart
+++ b/pkg/vm_snapshot_analysis/lib/v8_profile.dart
@@ -7,8 +7,9 @@
library vm_snapshot_analysis.v8_profile;
import 'package:meta/meta.dart';
-import 'package:vm_snapshot_analysis/name.dart';
+import 'package:vm_snapshot_analysis/src/dominators.dart' as dominators;
+import 'package:vm_snapshot_analysis/name.dart';
import 'package:vm_snapshot_analysis/program_info.dart';
/// This class represents snapshot graph.
@@ -34,6 +35,8 @@
/// for the given node index.
final List<int> _edgesStartIndexForNode;
+ List<int> _dominators;
+
final List strings;
Snapshot._(this.meta, this.nodeCount, this.edgeCount, this._nodes,
@@ -48,6 +51,12 @@
/// Return all nodes in the snapshot.
Iterable<Node> get nodes => Iterable.generate(nodeCount, nodeAt);
+ /// Return dominator node for the given node [n].
+ Node dominatorOf(Node n) {
+ _dominators ??= _computeDominators(this);
+ return nodeAt(_dominators[n.index]);
+ }
+
/// Returns true if the given JSON object is likely to be a serialized
/// snapshot using V8 heap snapshot format.
static bool isV8HeapSnapshot(Object m) =>
@@ -575,3 +584,36 @@
structure nodes (usually VM internal objects).
--------------------------------------------------------------------------------
''';
+
+/// Compute dominator tree of the graph.
+///
+/// The code for dominator tree computation is taken verbatim from the
+/// native compiler (see runtime/vm/compiler/backend/flow_graph.cc).
+List<int> _computeDominators(Snapshot snap) {
+ final predecessors = List<Object>.filled(snap.nodeCount, null);
+ void addPred(int n, int p) {
+ if (predecessors[n] == null) {
+ predecessors[n] = p;
+ } else if (predecessors[n] is int) {
+ predecessors[n] = <int>[predecessors[n], p];
+ } else {
+ (predecessors[n] as List<int>).add(p);
+ }
+ }
+
+ Iterable<int> predOf(int n) sync* {
+ final ps = predecessors[n];
+ if (ps is int) {
+ yield ps;
+ } else if (ps is List<int>) {
+ yield* ps;
+ }
+ }
+
+ return dominators.computeDominators(
+ size: snap.nodeCount,
+ root: snap.nodes.first.index,
+ succ: (n) => snap.nodeAt(n).edges.map((e) => e.target.index),
+ predOf: predOf,
+ handleEdge: addPred);
+}
diff --git a/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart b/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart
index ee2a3d1..fd4cdd8 100644
--- a/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart
+++ b/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart
@@ -10,6 +10,7 @@
import 'package:vm_snapshot_analysis/program_info.dart';
import 'package:vm_snapshot_analysis/treemap.dart';
import 'package:vm_snapshot_analysis/utils.dart';
+import 'package:vm_snapshot_analysis/v8_profile.dart';
import 'utils.dart';
@@ -168,6 +169,29 @@
"""
};
+final chainOfStaticCalls = {
+ 'input.dart': """
+@pragma('vm:never-inline')
+String _private3(dynamic o) {
+ return "";
+}
+
+@pragma('vm:never-inline')
+String _private2(dynamic o) {
+ return _private3(o);
+}
+
+@pragma('vm:never-inline')
+String _private1(dynamic o) {
+ return _private2(o);
+}
+
+void main(List<String> args) {
+ _private1(null);
+}
+"""
+};
+
extension on Histogram {
String bucketFor(String pkg, String lib, String cls, String fun) =>
(this.bucketInfo as Bucketing).bucketFor(pkg, lib, cls, fun);
@@ -669,6 +693,19 @@
}
});
});
+
+ test('dominators', () async {
+ await withV8Profile('dominators', chainOfStaticCalls,
+ (profileJson) async {
+ // Note: computing dominators also verifies that we don't have
+ // unreachable nodes in the snapshot.
+ final infoJson = await loadJson(File(profileJson));
+ final snapshot = Snapshot.fromJson(infoJson);
+ for (var n in snapshot.nodes.skip(1)) {
+ expect(snapshot.dominatorOf(n), isNotNull);
+ }
+ });
+ });
});
}
diff --git a/runtime/bin/file_system_watcher_android.cc b/runtime/bin/file_system_watcher_android.cc
index d403351..67edb4a 100644
--- a/runtime/bin/file_system_watcher_android.cc
+++ b/runtime/bin/file_system_watcher_android.cc
@@ -48,7 +48,7 @@
list_events |= IN_CREATE;
}
if ((events & kModifyContent) != 0) {
- list_events |= IN_CLOSE_WRITE | IN_ATTRIB;
+ list_events |= IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY;
}
if ((events & kDelete) != 0) {
list_events |= IN_DELETE;
@@ -77,7 +77,7 @@
static int InotifyEventToMask(struct inotify_event* e) {
int mask = 0;
- if ((e->mask & IN_CLOSE_WRITE) != 0) {
+ if ((e->mask & IN_CLOSE_WRITE) != 0 || (e->mask & IN_MODIFY) != 0) {
mask |= FileSystemWatcher::kModifyContent;
}
if ((e->mask & IN_ATTRIB) != 0) {
diff --git a/runtime/bin/file_system_watcher_linux.cc b/runtime/bin/file_system_watcher_linux.cc
index daa2d26..fa48290 100644
--- a/runtime/bin/file_system_watcher_linux.cc
+++ b/runtime/bin/file_system_watcher_linux.cc
@@ -48,7 +48,7 @@
list_events |= IN_CREATE;
}
if ((events & kModifyContent) != 0) {
- list_events |= IN_CLOSE_WRITE | IN_ATTRIB;
+ list_events |= IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY;
}
if ((events & kDelete) != 0) {
list_events |= IN_DELETE;
@@ -76,7 +76,7 @@
static int InotifyEventToMask(struct inotify_event* e) {
int mask = 0;
- if ((e->mask & IN_CLOSE_WRITE) != 0) {
+ if ((e->mask & IN_CLOSE_WRITE) != 0 || (e->mask & IN_MODIFY) != 0) {
mask |= FileSystemWatcher::kModifyContent;
}
if ((e->mask & IN_ATTRIB) != 0) {
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 0040724..a973ce7 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -1517,7 +1517,7 @@
class CodeSerializationCluster : public SerializationCluster {
public:
explicit CodeSerializationCluster(Heap* heap)
- : SerializationCluster("Code") {}
+ : SerializationCluster("Code"), array_(Array::Handle()) {}
~CodeSerializationCluster() {}
void Trace(Serializer* s, ObjectPtr object) {
@@ -1552,11 +1552,23 @@
if (calls_array != Array::null()) {
// Some Code entries in the static calls target table may only be
// accessible via here, so push the Code objects.
- auto const length = Smi::Value(calls_array->ptr()->length_);
- for (intptr_t i = 0; i < length; i++) {
- auto const object = calls_array->ptr()->data()[i];
- if (object->IsHeapObject() && object->IsCode()) {
- s->Push(object);
+ array_ = calls_array;
+ for (auto entry : StaticCallsTable(array_)) {
+ auto kind = Code::KindField::decode(
+ Smi::Value(entry.Get<Code::kSCallTableKindAndOffset>()));
+ switch (kind) {
+ case Code::kCallViaCode:
+ // Code object in the pool.
+ continue;
+ case Code::kPcRelativeTTSCall:
+ // TTS will be reachable through type object which itself is
+ // in the pool.
+ continue;
+ case Code::kPcRelativeCall:
+ case Code::kPcRelativeTailCall:
+ auto destination = entry.Get<Code::kSCallTableCodeOrTypeTarget>();
+ ASSERT(destination->IsHeapObject() && destination->IsCode());
+ s->Push(destination);
}
}
}
@@ -1744,6 +1756,37 @@
WriteField(code, deopt_info_array_);
WriteField(code, static_calls_target_table_);
}
+
+#if defined(DART_PRECOMPILER)
+ if (FLAG_write_v8_snapshot_profile_to != nullptr &&
+ code->ptr()->static_calls_target_table_ != Array::null()) {
+ // If we are writing V8 snapshot profile then attribute references
+ // going through static calls.
+ array_ = code->ptr()->static_calls_target_table_;
+ intptr_t index = code->ptr()->object_pool_ != ObjectPool::null()
+ ? code->ptr()->object_pool_->ptr()->length_
+ : 0;
+ for (auto entry : StaticCallsTable(array_)) {
+ auto kind = Code::KindField::decode(
+ Smi::Value(entry.Get<Code::kSCallTableKindAndOffset>()));
+ switch (kind) {
+ case Code::kCallViaCode:
+ // Code object in the pool.
+ continue;
+ case Code::kPcRelativeTTSCall:
+ // TTS will be reachable through type object which itself is
+ // in the pool.
+ continue;
+ case Code::kPcRelativeCall:
+ case Code::kPcRelativeTailCall:
+ auto destination = entry.Get<Code::kSCallTableCodeOrTypeTarget>();
+ ASSERT(destination->IsHeapObject() && destination->IsCode());
+ s->AttributeElementRef(destination, index++);
+ }
+ }
+ }
+#endif // defined(DART_PRECOMPILER)
+
#if !defined(PRODUCT)
WriteField(code, return_address_metadata_);
if (FLAG_code_comments) {
@@ -1789,6 +1832,7 @@
GrowableArray<CodePtr> objects_;
GrowableArray<CodePtr> deferred_objects_;
+ Array& array_;
};
#endif // !DART_PRECOMPILED_RUNTIME
diff --git a/runtime/vm/compiler/ffi/call.cc b/runtime/vm/compiler/ffi/call.cc
index 93d4484..6bfba3c 100644
--- a/runtime/vm/compiler/ffi/call.cc
+++ b/runtime/vm/compiler/ffi/call.cc
@@ -38,17 +38,17 @@
// The signature function won't have any names for the parameters. We need to
// assign unique names for scope building and error messages.
+ function.CreateNameArrayIncludingFlags(Heap::kNew);
const intptr_t num_params = dart_signature.num_fixed_parameters();
- const Array& parameter_names = Array::Handle(zone, Array::New(num_params));
for (intptr_t i = 0; i < num_params; ++i) {
if (i == 0) {
name = Symbols::ClosureParameter().raw();
} else {
name = Symbols::NewFormatted(thread, ":ffi_param%" Pd, i);
}
- parameter_names.SetAt(i, name);
+ function.SetParameterNameAt(i, name);
}
- function.set_parameter_names(parameter_names);
+ function.TruncateUnusedParameterFlags();
function.SetFfiCSignature(c_signature);
Type& type = Type::Handle(zone);
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.cc b/runtime/vm/compiler/frontend/bytecode_reader.cc
index 69890d2..3d9cb93 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.cc
+++ b/runtime/vm/compiler/frontend/bytecode_reader.cc
@@ -580,17 +580,13 @@
func.set_num_fixed_parameters(num_required_params);
func.SetNumOptionalParameters(num_params - num_required_params,
!has_optional_named_params);
- const Array& parameter_types =
- Array::Handle(Z, Array::New(num_params, Heap::kOld));
- func.set_parameter_types(parameter_types);
- const Array& parameter_names = Array::Handle(
- Z, Array::New(Function::NameArrayLengthIncludingFlags(num_params),
- Heap::kOld));
- func.set_parameter_names(parameter_names);
+ func.set_parameter_types(
+ Array::Handle(Z, Array::New(num_params, Heap::kOld)));
+ func.CreateNameArrayIncludingFlags(Heap::kOld);
intptr_t i = 0;
- parameter_types.SetAt(i, AbstractType::dynamic_type());
- parameter_names.SetAt(i, Symbols::ClosureParameter());
+ func.SetParameterTypeAt(i, AbstractType::dynamic_type());
+ func.SetParameterNameAt(i, Symbols::ClosureParameter());
++i;
AbstractType& type = AbstractType::Handle(Z);
@@ -602,9 +598,9 @@
} else {
name = Symbols::NotNamed().raw();
}
- parameter_names.SetAt(i, name);
+ func.SetParameterNameAt(i, name);
type ^= ReadObject();
- parameter_types.SetAt(i, type);
+ func.SetParameterTypeAt(i, type);
}
if (has_parameter_flags) {
intptr_t num_flags = reader_.ReadUInt();
@@ -2261,7 +2257,6 @@
Object& script_class = Object::Handle(Z);
Function& function = Function::Handle(Z);
Array& parameter_types = Array::Handle(Z);
- Array& parameter_names = Array::Handle(Z);
AbstractType& type = AbstractType::Handle(Z);
name = cls.ScrubbedName();
@@ -2371,10 +2366,7 @@
parameter_types = Array::New(num_params, Heap::kOld);
function.set_parameter_types(parameter_types);
-
- parameter_names = Array::New(
- Function::NameArrayLengthIncludingFlags(num_params), Heap::kOld);
- function.set_parameter_names(parameter_names);
+ function.CreateNameArrayIncludingFlags(Heap::kOld);
intptr_t param_index = 0;
if (!is_static) {
@@ -2398,9 +2390,9 @@
for (; param_index < num_params; ++param_index) {
name ^= ReadObject();
- parameter_names.SetAt(param_index, name);
+ function.SetParameterNameAt(param_index, name);
type ^= ReadObject();
- parameter_types.SetAt(param_index, type);
+ function.SetParameterTypeAt(param_index, type);
}
type ^= ReadObject();
@@ -3109,6 +3101,7 @@
}
}
}
+ function.TruncateUnusedParameterFlags();
if (has_forwarding_stub_target) {
const intptr_t cp_index = reader_.ReadUInt();
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 9e65018..396cef9 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -2006,6 +2006,25 @@
// Required named arguments only exist if null_safety is enabled.
if (!Isolate::Current()->null_safety()) return Fragment();
+ if (descriptor.NamedCount() == 0) {
+ static_assert(compiler::target::kNumParameterFlags == 1,
+ "IL builder assumes only one flag bit per parameter");
+ // No named args were provided, so check for any required named params.
+ // Here, we assume that the only parameter flag saved is the required bit
+ // for named parameters. If this changes, we'll need to check each flag
+ // entry appropriately for any set required bits.
+ Fragment has_any;
+ has_any += LoadLocal(vars->num_max_params);
+ has_any += LoadLocal(vars->parameter_names);
+ has_any += LoadNativeField(Slot::Array_length());
+ TargetEntryInstr *no_required, *has_required;
+ has_any += BranchIfEqual(&no_required, &has_required);
+
+ Fragment(has_required) + Goto(nsm);
+
+ return Fragment(has_any.entry, no_required);
+ }
+
// Loop over the indexes of the named parameters of the function, checking
// whether the named parameter at that index is required. If it is, then
// check whether it matches any of the names in the ArgumentsDescriptor.
@@ -2050,39 +2069,20 @@
Fragment(invalid_index) + Goto(done);
- // Otherwise, we need to retrieve the value. If it's null, then this index
- // and others that map to the same entry cannot be required (but later ones
- // may be).
+ // Otherwise, we need to retrieve the value and check the appropriate bit.
loop_body.current = valid_index;
loop_body += LoadLocal(vars->parameter_names);
loop_body += LoadLocal(temp); // Index into parameter names array.
loop_body += LoadIndexed(compiler::target::kWordSize);
- // Store the result so we can use it in the non-null branch. We can reuse
- // :expr_temp as we don't need the names index once we've gotten the contents.
- loop_body += StoreLocal(TokenPosition::kNoSource, temp);
- TargetEntryInstr *null_smi, *flags_smi;
- loop_body += BranchIfNull(&null_smi, &flags_smi);
-
- // If it was null, then skip forward to the first named parameter index that
- // would map to the next parameter names index, since no other indices that
- // map to the same entry can be set either.
- Fragment skip_ahead(null_smi);
- skip_ahead += LoadLocal(vars->current_param_index);
- skip_ahead += IntConstant(compiler::target::kNumParameterFlagsPerElement);
- skip_ahead += SmiBinaryOp(Token::kADD, /*is_truncating=*/true);
- skip_ahead += StoreLocal(TokenPosition::kNoSource, vars->current_param_index);
- skip_ahead += Drop();
- skip_ahead += Goto(loop);
-
- // If not null, see if any of the flag bits are set for the given named
- // parameter. If so, this named parameter is required.
- loop_body.current = flags_smi;
- loop_body += LoadLocal(temp); // Flag bits loaded from parameter names array.
loop_body += LoadLocal(vars->current_param_index);
loop_body += IntConstant(compiler::target::kNumParameterFlagsPerElement - 1);
loop_body += SmiBinaryOp(Token::kBIT_AND);
+ if (compiler::target::kNumParameterFlags > 1) {
+ loop_body += IntConstant(compiler::target::kNumParameterFlags);
+ loop_body += SmiBinaryOp(Token::kMUL, /*is_truncating=*/false);
+ }
loop_body += SmiBinaryOp(Token::kSHR);
- loop_body += IntConstant(1);
+ loop_body += IntConstant(1 << compiler::target::kRequiredNamedParameterFlag);
loop_body += SmiBinaryOp(Token::kBIT_AND);
loop_body += IntConstant(0);
TargetEntryInstr *not_set, *set;
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index b185b81..d70966c 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -735,8 +735,7 @@
function.set_num_fixed_parameters(parameter_count);
function.set_parameter_types(
Array::Handle(Z, Array::New(parameter_count, Heap::kOld)));
- function.set_parameter_names(
- Array::Handle(Z, Array::New(parameter_count, Heap::kOld)));
+ function.CreateNameArrayIncludingFlags(Heap::kNew);
intptr_t pos = 0;
if (is_method) {
@@ -3075,32 +3074,25 @@
all_count = positional_count;
}
- const intptr_t all_count_with_receiver = all_count + 1;
- const Array& parameter_types =
- Array::Handle(Z, Array::New(all_count_with_receiver, Heap::kOld));
- signature_function.set_parameter_types(parameter_types);
- const Array& parameter_names = Array::Handle(
- Z, Array::New(simple ? all_count_with_receiver
- : Function::NameArrayLengthIncludingFlags(
- all_count_with_receiver),
- Heap::kOld));
- signature_function.set_parameter_names(parameter_names);
-
- intptr_t pos = 0;
- parameter_types.SetAt(pos, AbstractType::dynamic_type());
- parameter_names.SetAt(pos, H.DartSymbolPlain("_receiver_"));
- ++pos;
- for (intptr_t i = 0; i < positional_count; ++i, ++pos) {
- BuildTypeInternal(); // read ith positional parameter.
- parameter_types.SetAt(pos, result_);
- parameter_names.SetAt(pos, H.DartSymbolPlain("noname"));
- }
-
// The additional first parameter is the receiver type (set to dynamic).
signature_function.set_num_fixed_parameters(1 + required_count);
signature_function.SetNumOptionalParameters(
all_count - required_count, positional_count > required_count);
+ signature_function.set_parameter_types(
+ Array::Handle(Z, Array::New(1 + all_count, Heap::kOld)));
+ signature_function.CreateNameArrayIncludingFlags(Heap::kOld);
+
+ intptr_t pos = 0;
+ signature_function.SetParameterTypeAt(pos, AbstractType::dynamic_type());
+ signature_function.SetParameterNameAt(pos, H.DartSymbolPlain("_receiver_"));
+ ++pos;
+ for (intptr_t i = 0; i < positional_count; ++i, ++pos) {
+ BuildTypeInternal(); // read ith positional parameter.
+ signature_function.SetParameterTypeAt(pos, result_);
+ signature_function.SetParameterNameAt(pos, H.DartSymbolPlain("noname"));
+ }
+
if (!simple) {
const intptr_t named_count =
helper_->ReadListLength(); // read named_parameters list length.
@@ -3109,15 +3101,15 @@
String& name = H.DartSymbolObfuscate(helper_->ReadStringReference());
BuildTypeInternal(); // read named_parameters[i].type.
const uint8_t flags = helper_->ReadFlags(); // read flags
- parameter_types.SetAt(pos, result_);
- parameter_names.SetAt(pos, name);
+ signature_function.SetParameterTypeAt(pos, result_);
+ signature_function.SetParameterNameAt(pos, name);
if (!apply_legacy_erasure_ &&
(flags & static_cast<uint8_t>(NamedTypeFlags::kIsRequired)) != 0) {
signature_function.SetIsRequiredAt(pos);
}
}
- signature_function.TruncateUnusedParameterFlags();
}
+ signature_function.TruncateUnusedParameterFlags();
if (!simple) {
helper_->SkipOptionalDartType(); // read typedef type.
@@ -3554,10 +3546,7 @@
function.set_parameter_types(
Array::Handle(Z, Array::New(parameter_count, Heap::kOld)));
- const Array& parameter_names = Array::Handle(
- Z, Array::New(Function::NameArrayLengthIncludingFlags(parameter_count),
- Heap::kOld));
- function.set_parameter_names(parameter_names);
+ function.CreateNameArrayIncludingFlags(Heap::kOld);
intptr_t pos = 0;
if (is_method) {
ASSERT(!klass.IsNull());
diff --git a/runtime/vm/compiler/relocation.cc b/runtime/vm/compiler/relocation.cc
index 119b2f3..df7a9dd 100644
--- a/runtime/vm/compiler/relocation.cc
+++ b/runtime/vm/compiler/relocation.cc
@@ -90,14 +90,8 @@
}
trampolines_by_destination_.Clear();
- // We're done now, so we clear out the targets tables.
- auto& caller = Code::Handle(zone);
- if (!is_vm_isolate) {
- for (intptr_t i = 0; i < code_objects_->length(); ++i) {
- caller = (*code_objects_)[i];
- caller.set_static_calls_target_table(Array::empty_array());
- }
- }
+ // Don't drop static call targets table yet. Snapshotter will skip it anyway
+ // however we might need it to write information into V8 snapshot profile.
}
void CodeRelocator::FindInstructionAndCallLimits() {
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index 82be941..31fa267 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -299,17 +299,22 @@
extern const word kOldPageMask;
static constexpr intptr_t kObjectAlignment = ObjectAlignment::kObjectAlignment;
-// Parameter flags are stored in Smis. In particular, there is one flag (the
-// required flag), but we want ensure that the number of bits stored per Smi is
-// a power of two so we can simply uses shift to convert the parameter index to
-// calculate both the parameter flag index in the parameter names array to get
-// the packed flags and which bit in the packed flags to check.
+
+// Note: if other flags are added, then change the check for required parameters
+// when no named arguments are provided in
+// FlowGraphBuilder::BuildClosureCallHasRequiredNamedArgumentsCheck, since it
+// assumes there are no flag slots when no named parameters are required.
+enum ParameterFlags {
+ kRequiredNamedParameterFlag,
+ kNumParameterFlags,
+};
+// Parameter flags are stored in Smis. To ensure shifts and masks can be used to
+// calculate both the parameter flag index in the parameter names array and
+// which bit to check, kNumParameterFlagsPerElement should be a power of two.
static constexpr intptr_t kNumParameterFlagsPerElementLog2 =
- kBitsPerWordLog2 - 1;
+ kBitsPerWordLog2 - kNumParameterFlags;
static constexpr intptr_t kNumParameterFlagsPerElement =
1 << kNumParameterFlagsPerElementLog2;
-// Thus, in the untagged Smi value, only the lowest kNumParameterFlagsPerElement
-// bits are used for flags, with the other bits currently unused.
static_assert(kNumParameterFlagsPerElement <= kSmiBits,
"kNumParameterFlagsPerElement should fit in a Smi");
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index fd3f576..567f4e1 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -2431,11 +2431,11 @@
initializer_fun.set_num_fixed_parameters(1);
initializer_fun.set_parameter_types(
Array::Handle(zone, Array::New(1, Heap::kOld)));
- initializer_fun.set_parameter_names(
- Array::Handle(zone, Array::New(1, Heap::kOld)));
+ initializer_fun.CreateNameArrayIncludingFlags(Heap::kOld);
initializer_fun.SetParameterTypeAt(
0, AbstractType::Handle(zone, field_owner.DeclarationType()));
initializer_fun.SetParameterNameAt(0, Symbols::This());
+ initializer_fun.TruncateUnusedParameterFlags();
}
initializer_fun.set_result_type(AbstractType::Handle(zone, field.type()));
initializer_fun.set_is_reflectable(false);
diff --git a/runtime/vm/lockers.h b/runtime/vm/lockers.h
index 04fad54..4c46acb 100644
--- a/runtime/vm/lockers.h
+++ b/runtime/vm/lockers.h
@@ -320,8 +320,8 @@
SafepointRwLock() {}
~SafepointRwLock() {}
- bool IsCurrentThreadReader() {
#if defined(DEBUG)
+ bool IsCurrentThreadReader() {
ThreadId id = OSThread::GetCurrentThreadId();
if (IsCurrentThreadWriter()) {
return true;
@@ -332,25 +332,25 @@
}
}
return false;
-#else
- UNREACHABLE();
-#endif
}
+#endif // defined(DEBUG)
bool IsCurrentThreadWriter() {
-#if defined(DEBUG)
return writer_id_ == OSThread::GetCurrentThreadId();
-#else
- UNREACHABLE();
-#endif
}
private:
friend class SafepointReadRwLocker;
friend class SafepointWriteRwLocker;
- void EnterRead() {
+ // returns [true] if read lock was acuired,
+ // returns [false] if the thread didn't have to acquire read lock due
+ // to the thread already holding write lock
+ bool EnterRead() {
SafepointMonitorLocker ml(&monitor_);
+ if (IsCurrentThreadWriter()) {
+ return false;
+ }
while (state_ == -1) {
ml.Wait();
}
@@ -358,6 +358,7 @@
readers_ids_.Add(OSThread::GetCurrentThreadId());
#endif
++state_;
+ return true;
}
void LeaveRead() {
SafepointMonitorLocker ml(&monitor_);
@@ -381,21 +382,24 @@
void EnterWrite() {
SafepointMonitorLocker ml(&monitor_);
+ if (IsCurrentThreadWriter()) {
+ state_--;
+ return;
+ }
while (state_ != 0) {
ml.Wait();
}
-#if defined(DEBUG)
writer_id_ = OSThread::GetCurrentThreadId();
-#endif
state_ = -1;
}
void LeaveWrite() {
SafepointMonitorLocker ml(&monitor_);
- ASSERT(state_ == -1);
- state_ = 0;
-#if defined(DEBUG)
+ ASSERT(state_ < 0);
+ state_++;
+ if (state_ < 0) {
+ return;
+ }
writer_id_ = OSThread::kInvalidThreadId;
-#endif
ml.NotifyAll();
}
@@ -407,8 +411,8 @@
#if defined(DEBUG)
MallocGrowableArray<ThreadId> readers_ids_;
- ThreadId writer_id_ = OSThread::kInvalidThreadId;
#endif
+ ThreadId writer_id_ = OSThread::kInvalidThreadId;
};
/*
@@ -442,9 +446,17 @@
public:
SafepointReadRwLocker(ThreadState* thread_state, SafepointRwLock* rw_lock)
: StackResource(thread_state), rw_lock_(rw_lock) {
- rw_lock_->EnterRead();
+ ASSERT(rw_lock_ != nullptr);
+ if (!rw_lock_->EnterRead()) {
+ // if lock didn't have to be acquired, it doesn't have to be released.
+ rw_lock_ = nullptr;
+ }
}
- ~SafepointReadRwLocker() { rw_lock_->LeaveRead(); }
+ ~SafepointReadRwLocker() {
+ if (rw_lock_ != nullptr) {
+ rw_lock_->LeaveRead();
+ }
+ }
private:
SafepointRwLock* rw_lock_;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index cc72376..e19f14e 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -20,6 +20,7 @@
#include "vm/compiler/assembler/disassembler.h"
#include "vm/compiler/assembler/disassembler_kbc.h"
#include "vm/compiler/jit/compiler.h"
+#include "vm/compiler/runtime_api.h"
#include "vm/cpu.h"
#include "vm/dart.h"
#include "vm/dart_api_state.h"
@@ -3520,8 +3521,7 @@
false); // Not positional.
invocation.set_parameter_types(
Array::Handle(zone, Array::New(desc.Count(), Heap::kOld)));
- invocation.set_parameter_names(
- Array::Handle(zone, Array::New(desc.Count(), Heap::kOld)));
+ invocation.CreateNameArrayIncludingFlags(Heap::kOld);
// Receiver.
invocation.SetParameterTypeAt(0, Object::dynamic_type());
invocation.SetParameterNameAt(0, Symbols::This());
@@ -3541,6 +3541,7 @@
intptr_t index = i - desc.PositionalCount();
invocation.SetParameterNameAt(i, String::Handle(zone, desc.NameAt(index)));
}
+ invocation.TruncateUnusedParameterFlags();
invocation.set_result_type(Object::dynamic_type());
invocation.set_is_debuggable(false);
invocation.set_is_visible(false);
@@ -7434,19 +7435,38 @@
StorePointer(&raw_ptr()->parameter_names_, value.raw());
}
-intptr_t Function::NameArrayLengthIncludingFlags(intptr_t num_parameters) {
- return num_parameters +
- (num_parameters + compiler::target::kNumParameterFlagsPerElement - 1) /
- compiler::target::kNumParameterFlagsPerElement;
+void Function::CreateNameArrayIncludingFlags(Heap::Space space) const {
+ // Currently, we only store flags for named parameters that are required.
+ const intptr_t num_parameters = NumParameters();
+ intptr_t num_total_slots = num_parameters;
+ if (HasOptionalNamedParameters()) {
+ const intptr_t last_index = (NumOptionalNamedParameters() - 1) /
+ compiler::target::kNumParameterFlagsPerElement;
+ const intptr_t num_flag_slots = last_index + 1;
+ num_total_slots += num_flag_slots;
+ }
+ auto& array = Array::Handle(Array::New(num_total_slots, space));
+ if (num_total_slots > num_parameters) {
+ // Set flag slots to Smi 0 before handing off.
+ auto& empty_flags_smi = Smi::Handle(Smi::New(0));
+ for (intptr_t i = num_parameters; i < num_total_slots; i++) {
+ array.SetAt(i, empty_flags_smi);
+ }
+ }
+ set_parameter_names(array);
}
intptr_t Function::GetRequiredFlagIndex(intptr_t index,
intptr_t* flag_mask) const {
+ // If these calculations change, also change
+ // FlowGraphBuilder::BuildClosureCallHasRequiredNamedArgumentsCheck.
ASSERT(flag_mask != nullptr);
ASSERT(index >= num_fixed_parameters());
index -= num_fixed_parameters();
- *flag_mask = 1 << (static_cast<uintptr_t>(index) %
- compiler::target::kNumParameterFlagsPerElement);
+ *flag_mask = (1 << compiler::target::kRequiredNamedParameterFlag)
+ << ((static_cast<uintptr_t>(index) %
+ compiler::target::kNumParameterFlagsPerElement) *
+ compiler::target::kNumParameterFlags);
return NumParameters() +
index / compiler::target::kNumParameterFlagsPerElement;
}
@@ -7461,12 +7481,9 @@
if (flag_index >= parameter_names.Length()) {
return false;
}
- ObjectPtr element = parameter_names.At(flag_index);
- if (element == Object::null()) {
- return false;
- }
- const intptr_t flag = Smi::Value(Smi::RawCast(element));
- return (flag & flag_mask) != 0;
+ const intptr_t flags =
+ Smi::Value(Smi::RawCast(parameter_names.At(flag_index)));
+ return (flags & flag_mask) != 0;
}
void Function::SetIsRequiredAt(intptr_t index) const {
@@ -7474,27 +7491,26 @@
const intptr_t flag_index = GetRequiredFlagIndex(index, &flag_mask);
const Array& parameter_names = Array::Handle(raw_ptr()->parameter_names_);
ASSERT(flag_index < parameter_names.Length());
- intptr_t flag;
- ObjectPtr element = parameter_names.At(flag_index);
- if (element == Object::null()) {
- flag = 0;
- } else {
- flag = Smi::Value(Smi::RawCast(element));
- }
- parameter_names.SetAt(flag_index, Object::Handle(Smi::New(flag | flag_mask)));
+ const intptr_t flags =
+ Smi::Value(Smi::RawCast(parameter_names.At(flag_index)));
+ parameter_names.SetAt(flag_index, Smi::Handle(Smi::New(flags | flag_mask)));
}
void Function::TruncateUnusedParameterFlags() const {
- // Truncate the parameter names array to remove unused flags from the end.
const Array& parameter_names = Array::Handle(raw_ptr()->parameter_names_);
const intptr_t num_params = NumParameters();
- intptr_t last_required_flag = parameter_names.Length() - 1;
- for (; last_required_flag >= num_params; --last_required_flag) {
- if (parameter_names.At(last_required_flag) != Object::null()) {
+ if (parameter_names.Length() == num_params) {
+ // No flag slots to truncate.
+ return;
+ }
+ // Truncate the parameter names array to remove unused flags from the end.
+ intptr_t last_used = parameter_names.Length() - 1;
+ for (; last_used >= num_params; --last_used) {
+ if (Smi::Value(Smi::RawCast(parameter_names.At(last_used))) != 0) {
break;
}
}
- parameter_names.Truncate(last_required_flag + 1);
+ parameter_names.Truncate(last_used + 1);
}
void Function::set_type_parameters(const TypeArguments& value) const {
@@ -8867,14 +8883,11 @@
const int num_opt_params = NumOptionalParameters();
const bool has_opt_pos_params = HasOptionalPositionalParameters();
const int num_params = num_fixed_params + num_opt_params;
- const int num_required_flags =
- Array::Handle(zone, parameter_names()).Length() - NumParameters();
closure_function.set_num_fixed_parameters(num_fixed_params);
closure_function.SetNumOptionalParameters(num_opt_params, has_opt_pos_params);
closure_function.set_parameter_types(
Array::Handle(zone, Array::New(num_params, Heap::kOld)));
- closure_function.set_parameter_names(Array::Handle(
- zone, Array::New(num_params + num_required_flags, Heap::kOld)));
+ closure_function.CreateNameArrayIncludingFlags(Heap::kOld);
AbstractType& param_type = AbstractType::Handle(zone);
String& param_name = String::Handle(zone);
// Add implicit closure object parameter.
@@ -8890,6 +8903,7 @@
closure_function.SetIsRequiredAt(i);
}
}
+ closure_function.TruncateUnusedParameterFlags();
closure_function.InheritBinaryDeclarationFrom(*this);
// Change covariant parameter types to either Object? for an opted-in implicit
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 4f366ee..f399b23 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2607,24 +2607,27 @@
StringPtr ParameterNameAt(intptr_t index) const;
void SetParameterNameAt(intptr_t index, const String& value) const;
ArrayPtr parameter_names() const { return raw_ptr()->parameter_names_; }
- void set_parameter_names(const Array& value) const;
static intptr_t parameter_names_offset() {
return OFFSET_OF(FunctionLayout, parameter_names_);
}
- // The required flags are stored at the end of the parameter_names. The flags
- // are packed into SMIs, but omitted if they're 0.
- bool IsRequiredAt(intptr_t index) const;
- void SetIsRequiredAt(intptr_t index) const;
+ // Sets up the function's parameter name array, including appropriate space
+ // for any possible parameter flags. This may be an overestimate if some
+ // parameters don't have flags, and so TruncateUnusedParameterFlags() should
+ // be called after all parameter flags have been appropriately set.
+ //
+ // Assumes that the number of fixed and optional parameters for the function
+ // has already been set.
+ void CreateNameArrayIncludingFlags(Heap::Space space) const;
// Truncate the parameter names array to remove any unused flag slots. Make
// sure to only do this after calling SetIsRequiredAt as necessary.
void TruncateUnusedParameterFlags() const;
- // Returns the length of the parameter names array that is required to store
- // all the names plus all their flags. This may be an overestimate if some
- // parameters don't have flags.
- static intptr_t NameArrayLengthIncludingFlags(intptr_t num_parameters);
+ // The required flags are stored at the end of the parameter_names. The flags
+ // are packed into Smis.
+ bool IsRequiredAt(intptr_t index) const;
+ void SetIsRequiredAt(intptr_t index) const;
// The type parameters (and their bounds) are specified as an array of
// TypeParameter.
@@ -3768,6 +3771,7 @@
}
private:
+ void set_parameter_names(const Array& value) const;
void set_ic_data_array(const Array& value) const;
void SetInstructionsSafe(const Code& value) const;
@@ -3847,6 +3851,7 @@
friend class Class;
friend class SnapshotWriter;
friend class Parser; // For set_eval_script.
+ friend class ProgramVisitor; // For set_parameter_names.
// FunctionLayout::VisitFunctionPointers accesses the private constructor of
// Function.
friend class FunctionLayout;
diff --git a/runtime/vm/program_visitor.cc b/runtime/vm/program_visitor.cc
index fe04547..d2e13d2 100644
--- a/runtime/vm/program_visitor.cc
+++ b/runtime/vm/program_visitor.cc
@@ -408,6 +408,9 @@
ASSERT(FLAG_precompiled_mode);
// In precompiled mode, the Dart runtime won't patch static calls
// anymore, so drop the static call table to save space.
+ // Note: it is okay to drop the table fully even when generating
+ // V8 snapshot profile because code objects are linked through the
+ // pool.
code.set_static_calls_target_table(Object::empty_array());
}
}
diff --git a/runtime/vm/regexp.cc b/runtime/vm/regexp.cc
index 8b3e30f..0ffffe0 100644
--- a/runtime/vm/regexp.cc
+++ b/runtime/vm/regexp.cc
@@ -5527,8 +5527,7 @@
fn.set_num_fixed_parameters(kParamCount);
fn.set_parameter_types(
Array::Handle(zone, Array::New(kParamCount, Heap::kOld)));
- fn.set_parameter_names(
- Array::Handle(zone, Array::New(kParamCount, Heap::kOld)));
+ fn.CreateNameArrayIncludingFlags(Heap::kOld);
fn.SetParameterTypeAt(RegExpMacroAssembler::kParamRegExpIndex,
Object::dynamic_type());
fn.SetParameterNameAt(RegExpMacroAssembler::kParamRegExpIndex,
@@ -5542,6 +5541,7 @@
fn.SetParameterNameAt(RegExpMacroAssembler::kParamStartOffsetIndex,
Symbols::start_index_param());
fn.set_result_type(Type::Handle(zone, Type::ArrayType()));
+ fn.TruncateUnusedParameterFlags();
// Cache the result.
regexp.set_function(specialization_cid, sticky, fn);
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index eb5b676..a5618c6 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -963,26 +963,72 @@
}
}
-#if defined(DEBUG)
ISOLATE_UNIT_TEST_CASE(SafepointRwLockWithReadLock) {
SafepointRwLock lock;
SafepointReadRwLocker locker(Thread::Current(), &lock);
- EXPECT(lock.IsCurrentThreadReader());
+ DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
EXPECT(!lock.IsCurrentThreadWriter());
}
ISOLATE_UNIT_TEST_CASE(SafepointRwLockWithWriteLock) {
SafepointRwLock lock;
SafepointWriteRwLocker locker(Thread::Current(), &lock);
- EXPECT(lock.IsCurrentThreadReader());
+ DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
EXPECT(lock.IsCurrentThreadWriter());
}
ISOLATE_UNIT_TEST_CASE(SafepointRwLockWithoutAnyLocks) {
SafepointRwLock lock;
- EXPECT(!lock.IsCurrentThreadReader());
+ DEBUG_ONLY(EXPECT(!lock.IsCurrentThreadReader()));
EXPECT(!lock.IsCurrentThreadWriter());
}
-#endif
+
+ISOLATE_UNIT_TEST_CASE(SafepointRwLockReentrantReadLock) {
+ SafepointRwLock lock;
+ {
+ SafepointReadRwLocker locker(Thread::Current(), &lock);
+ {
+ SafepointReadRwLocker locker1(Thread::Current(), &lock);
+ DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
+ EXPECT(!lock.IsCurrentThreadWriter());
+ }
+ DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
+ EXPECT(!lock.IsCurrentThreadWriter());
+ }
+ DEBUG_ONLY(EXPECT(!lock.IsCurrentThreadReader()));
+ EXPECT(!lock.IsCurrentThreadWriter());
+}
+
+ISOLATE_UNIT_TEST_CASE(SafepointRwLockReentrantWriteLock) {
+ SafepointRwLock lock;
+ {
+ SafepointWriteRwLocker locker(Thread::Current(), &lock);
+ {
+ SafepointWriteRwLocker locker1(Thread::Current(), &lock);
+ DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
+ EXPECT(lock.IsCurrentThreadWriter());
+ }
+ DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
+ EXPECT(lock.IsCurrentThreadWriter());
+ }
+ DEBUG_ONLY(EXPECT(!lock.IsCurrentThreadReader()));
+ EXPECT(!lock.IsCurrentThreadWriter());
+}
+
+ISOLATE_UNIT_TEST_CASE(SafepointRwLockWriteToReadLock) {
+ SafepointRwLock lock;
+ {
+ SafepointWriteRwLocker locker(Thread::Current(), &lock);
+ {
+ SafepointReadRwLocker locker1(Thread::Current(), &lock);
+ DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
+ EXPECT(lock.IsCurrentThreadWriter());
+ }
+ DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
+ EXPECT(lock.IsCurrentThreadWriter());
+ }
+ DEBUG_ONLY(EXPECT(!lock.IsCurrentThreadReader()));
+ EXPECT(!lock.IsCurrentThreadWriter());
+}
} // namespace dart
diff --git a/tests/standalone/io/file_system_watcher_test.dart b/tests/standalone/io/file_system_watcher_test.dart
index 7714f38..dae7f9d 100644
--- a/tests/standalone/io/file_system_watcher_test.dart
+++ b/tests/standalone/io/file_system_watcher_test.dart
@@ -83,6 +83,33 @@
file.writeAsStringSync('a');
}
+void testWatchTruncateFile() {
+ var dir = Directory.systemTemp.createTempSync('dart_file_system_watcher');
+ var file = new File(join(dir.path, 'file'));
+ file.writeAsStringSync('ab');
+ var fileHandle = file.openSync(mode: FileMode.append);
+
+ var watcher = dir.watch();
+
+ asyncStart();
+ var sub;
+ sub = watcher.listen((event) {
+ if (event is FileSystemModifyEvent) {
+ Expect.isTrue(event.path.endsWith('file'));
+ Expect.isTrue(event.contentChanged);
+ sub.cancel();
+ asyncEnd();
+ fileHandle.closeSync();
+ dir.deleteSync(recursive: true);
+ }
+ }, onError: (e) {
+ dir.deleteSync(recursive: true);
+ throw e;
+ });
+
+ fileHandle.truncateSync(1);
+}
+
void testWatchMoveFile() {
// Mac OS doesn't report move events.
if (Platform.isMacOS) return;
@@ -468,6 +495,7 @@
testWatchCreateDir();
testWatchModifyFile();
testWatchMoveFile();
+ testWatchTruncateFile();
testWatchDeleteFile();
testWatchDeleteDir();
testWatchOnlyModifyFile();
diff --git a/tests/standalone_2/io/file_system_watcher_test.dart b/tests/standalone_2/io/file_system_watcher_test.dart
index d366ff8..6011831 100644
--- a/tests/standalone_2/io/file_system_watcher_test.dart
+++ b/tests/standalone_2/io/file_system_watcher_test.dart
@@ -83,6 +83,33 @@
file.writeAsStringSync('a');
}
+void testWatchTruncateFile() {
+ var dir = Directory.systemTemp.createTempSync('dart_file_system_watcher');
+ var file = new File(join(dir.path, 'file'));
+ file.writeAsStringSync('ab');
+ var fileHandle = file.openSync(mode: FileMode.append);
+
+ var watcher = dir.watch();
+
+ asyncStart();
+ var sub;
+ sub = watcher.listen((event) {
+ if (event is FileSystemModifyEvent) {
+ Expect.isTrue(event.path.endsWith('file'));
+ Expect.isTrue(event.contentChanged);
+ sub.cancel();
+ asyncEnd();
+ fileHandle.closeSync();
+ dir.deleteSync(recursive: true);
+ }
+ }, onError: (e) {
+ dir.deleteSync(recursive: true);
+ throw e;
+ });
+
+ fileHandle.truncateSync(1);
+}
+
void testWatchMoveFile() {
// Mac OS doesn't report move events.
if (Platform.isMacOS) return;
@@ -466,6 +493,7 @@
testWatchCreateFile();
testWatchCreateDir();
testWatchModifyFile();
+ testWatchTruncateFile();
testWatchMoveFile();
testWatchDeleteFile();
testWatchDeleteDir();
diff --git a/tools/VERSION b/tools/VERSION
index 3f1b7a3..bf9bd94 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 10
PATCH 0
-PRERELEASE 103
+PRERELEASE 104
PRERELEASE_PATCH 0
\ No newline at end of file