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