Version 3.6.0-334.1.beta

Merge 3.6.0-334.0.dev into beta
diff --git a/.github/workflows/issue-triage.yml b/.github/workflows/issue-triage.yml
index fa0f414..a9f0eb9 100644
--- a/.github/workflows/issue-triage.yml
+++ b/.github/workflows/issue-triage.yml
@@ -21,7 +21,7 @@
     runs-on: ubuntu-latest
     if: ${{ github.repository_owner == 'dart-lang' }}
     steps:
-      - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+      - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
         with:
           repository: dart-lang/ecosystem
 
diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml
index c88f096..a2bea94 100644
--- a/.github/workflows/scorecards-analysis.yml
+++ b/.github/workflows/scorecards-analysis.yml
@@ -24,7 +24,7 @@
 
     steps:
       - name: "Checkout code"
-        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+        uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
         with:
           persist-credentials: false
 
@@ -44,7 +44,7 @@
 
       # Upload the results as artifacts (optional).
       - name: "Upload artifact"
-        uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a
+        uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874
         with:
           name: SARIF file
           path: results.sarif
@@ -52,6 +52,6 @@
 
       # Upload the results to GitHub's code scanning dashboard.
       - name: "Upload to code-scanning"
-        uses: github/codeql-action/upload-sarif@2c779ab0d087cd7fe7b826087247c2c81f27bfa6
+        uses: github/codeql-action/upload-sarif@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea
         with:
           sarif_file: results.sarif
diff --git a/.github/workflows/third-party-deps-scan.yml b/.github/workflows/third-party-deps-scan.yml
index 594e5c3..bddebde 100644
--- a/.github/workflows/third-party-deps-scan.yml
+++ b/.github/workflows/third-party-deps-scan.yml
@@ -22,17 +22,17 @@
       contents: read
     steps:
       - name: "Checkout code"
-        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+        uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
         with:
           persist-credentials: false
       - name: "setup python"
-        uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f
+        uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3
         with:
           python-version: '3.7.7' # install the python version needed
       - name: "extract deps, find commit hash, pass to osv-scanner"
         run: python .github/extract_deps.py --output osv-lockfile-${{github.sha}}.json
       - name: "upload osv-scanner deps"
-        uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a
+        uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874
         with:
           # use github.ref in name to avoid duplicated artifacts
           name: osv-lockfile-${{github.sha}}
diff --git a/.gitignore b/.gitignore
index 083421b..2be1232 100644
--- a/.gitignore
+++ b/.gitignore
@@ -112,3 +112,4 @@
 logs/results.json
 .dart_tool/bisect_dart/
 doc/api/
+runtime/tools/heapsnapshot/.dart_tool
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 733ccfe..c762e33 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -55,6 +55,8 @@
 - Added `length` and `[]`/`[]=` operators to `JSArray`.
 - Added `toJSCaptureThis` so `this` is passed in from JavaScript to the
   callback as the first parameter.
+- Added a static `from` method on `JSArray` to create a `JSArray` from a given
+  JavaScript iterable or array-like object.
 
 ### Tools
 
@@ -69,6 +71,12 @@
 
 [#56466]: https://github.com/dart-lang/sdk/issues/56466
 
+#### Dart format
+
+- Preserve type parameters on old-style function-typed formals that also use
+  `this.` or `super.`.
+- Correctly format imports with both `as` and `if` clauses.
+
 #### Wasm compiler (dart2wasm)
 
 - The condition `dart.library.js` is now false on conditional imports in
@@ -77,6 +85,50 @@
 
 [#55266]: https://github.com/dart-lang/sdk/issues/55266
 
+#### Pub
+
+- Support for workspaces. This allows you to develop and resolve multiple
+  packages from the same repo together. See https://dart.dev/go/pub-workspaces
+  for more info.
+- New command `dart pub bump`. Increments the version number of the current
+  package.
+
+  For example: `dart pub bump minor` will change the version from `1.2.3` to
+  `1.3.0`.
+- New validation: `dart pub publish` will warn if your `git status` is not
+  clean.
+- New flag `dart pub upgrade --unlock-transitive`.
+
+- `dart pub upgrade --unlock-transitive pkg`, will unlock and upgrade all the
+  dependencies of `pkg` instead of just `pkg`.
+
+#### Analyzer
+
+- Add the [`use_truncating_division`][] lint rule.
+- Add the experimental [`omit_obvious_local_variable_types`][] lint rule.
+- Add the experimental [`specify_nonobvious_local_variable_types`][] lint rule.
+- Add the experimental [`avoid_futureor_void`][] lint rule.
+- Add quick fixes for more than 14 diagnostics.
+- Add new assists: "add digit separators", "remove digit separators", and
+  "invert conditional expression".
+
+[`use_truncating_division`]: https://dart.dev/lints/use_truncating_division
+[`omit_obvious_local_variable_types`]: https://dart.dev/lints/omit_obvious_local_variable_types
+[`specify_nonobvious_local_variable_types`]: https://dart.dev/lints/specify_nonobvious_local_variable_types
+[`avoid_futureor_void`]: https://dart.dev/lints/avoid_futureor_void
+
+## 3.5.3 - 2024-09-11
+
+- Fixes an issue with the DevTools Memory tool causing OOMs. and an
+issue resulting in a missing tab bar when DevTools is embedded in
+IntelliJ and Android Studio (issue[#56607][]).
+- Fixes an issue with the DevTools release notes showing each time
+DevTools is opened instead of only the first time (issue[#56607][]).
+- Fixes an issue resulting in a missing tab bar when DevTools is
+embedded in IntelliJ and Android Studio (issue[#56607][]).
+
+[#56607]: https://github.com/dart-lang/sdk/issues/56607
+
 ## 3.5.2 - 2024-08-28
 
 - Fixes a bug where `ZLibDecoder` would incorrectly attempt to decompress data
@@ -213,11 +265,16 @@
 
 ### Tools
 
-#### Linter
+#### Analyzer
 
-- Added the [`unintended_html_in_doc_comment`][] lint.
-- Added the [`invalid_runtime_check_with_js_interop_types`][] lint.
-- Added the [`document_ignores`][] lint.
+- Add the [`unintended_html_in_doc_comment`][] lint rule.
+- Add the [`invalid_runtime_check_with_js_interop_types`][] lint rule.
+- Add the [`document_ignores`][] lint rule.
+- Add quick fixes for more than 70 diagnostics.
+- The "Add missing switch cases" quick fix now adds multiple cases, such that
+  the switch becomes exhaustive.
+- The "Remove const" quick fix now adds `const` keywords to child nodes, where
+  appropriate.
 
 [`unintended_html_in_doc_comment`]: https://dart.dev/lints/unintended_html_in_doc_comment
 [`invalid_runtime_check_with_js_interop_types`]: https://dart.dev/lints/invalid_runtime_check_with_js_interop_types
diff --git a/DEPS b/DEPS
index e075762..edbdcbc 100644
--- a/DEPS
+++ b/DEPS
@@ -54,7 +54,7 @@
 
   # co19 is a cipd package automatically generated for each co19 commit.
   # Use tests/co19/update.sh to update this hash.
-  "co19_rev": "767bb1f623a4f005072224cd7a49726a5b644296",
+  "co19_rev": "3af31b33ccaf1b56002dbd3df989f6a97b321ae9",
 
   # The internal benchmarks to use. See go/dart-benchmarks-internal
   "benchmarks_internal_rev": "3bd6bc6d207dfb7cf687537e819863cf9a8f2470",
@@ -71,21 +71,21 @@
   # self-service update these by following the go/dart-engprod/browsers.md
   # instructions. d8, the V8 shell, is always checked out.
   "checkout_javascript_engines": False,
-  "d8_tag": "version:12.9.98",
-  "jsshell_tag": "version:127.0.2",
-  "jsc_tag": "version:282418",
+  "d8_tag": "version:13.1.113",
+  "jsshell_tag": "version:130.0.1",
+  "jsc_tag": "version:284301",
 
   # https://chrome-infra-packages.appspot.com/p/fuchsia/third_party/clang
-  "clang_version": "git_revision:0cfd03ac0d3f9713090a581bda07584754c73a49",
+  "clang_version": "git_revision:3928edecfbd116d56bbe7411365d50bb567380a1",
 
   # https://chrome-infra-packages.appspot.com/p/gn/gn
-  "gn_version": "git_revision:05eed8f6252e2dd6b555e0b65192ef03e2c4a276",
+  "gn_version": "git_revision:20806f79c6b4ba295274e3a589d85db41a02fdaa",
 
   "reclient_version": "git_revision:c7349324c93c6e0d85bc1e00b5d7526771006ea0",
   "download_reclient": True,
 
   # Update from https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core
-  "fuchsia_sdk_version": "version:23.20240812.3.1",
+  "fuchsia_sdk_version": "version:24.20240917.7.1",
   "download_fuchsia_deps": False,
 
   # Ninja, runs the build based on files generated by GN.
@@ -102,7 +102,7 @@
   "boringssl_rev": "2db0eb3f96a5756298dcd7f9319e56a98585bd10",
   "browser-compat-data_tag": "ac8cae697014da1ff7124fba33b0b4245cc6cd1b", # v1.0.22
   "cpu_features_rev": "936b9ab5515dead115606559502e3864958f7f6e",
-  "devtools_rev": "25053ae4af8f162188388c6f3786e03349652e51",
+  "devtools_rev": "f5e84f91b32b219d646cfb87a891cd143dc84056",
   "icu_rev": "43953f57b037778a1b8005564afabe214834f7bd",
   "jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
   "libcxx_rev": "44079a4cc04cdeffb9cfe8067bfb3c276fb2bab0",
@@ -120,19 +120,19 @@
   # EOL comment after a dependency to disable this and pin it at its current
   # revision.
 
-  "args_rev": "1a24d614423e7861ae2e341bfb19050959cef0cd",
+  "args_rev": "e623652744c82533829f2e62b1aba1a6cf06e291",
   "async_rev": "c0d81f8699682d01d657a9bf827107d11904a247",
-  "bazel_worker_rev": "02f190b88df771fc8e05c07d4b64ae942c02f456",
-  "benchmark_harness_rev": "a06785cdfc51538e3556c1d59bb4f03426e9e1c5",
-  "boolean_selector_rev": "c5468f44fd9ca0ea3435e1a0a84ff9b6fac38261",
-  "browser_launcher_rev": "fa98c77e7a2fee21a4ad3528dd79da0f4df6bd0f",
+  "bazel_worker_rev": "aa3cc9e826350b960e0c5a67e6065bcedba8b0ac",
+  "benchmark_harness_rev": "44f125ae1d045aa3de09fe88a8dd70cb7352d563",
+  "boolean_selector_rev": "d6c7c36ae1111f11cc24306d71d3ab2deea8fa68",
+  "browser_launcher_rev": "e5fc5d488eb5038bfec2a6690c72ab8dd353e101",
   "characters_rev": "7633a16a22c626e19ca750223237396315268a06",
-  "cli_util_rev": "6a0bb9292ea4bb2c9e547af03da4c9948f9556a1",
-  "clock_rev": "6e43768a0b135a0d36fc886907b70c4bf27117e6",
-  "collection_rev": "0c1f829c29da1d63488be774f430b2035a565d6f",
+  "cli_util_rev": "c36b3941e38092d6d6f87ac27d9e88f153d3ac38",
+  "clock_rev": "7956d60042f4ea979c4554d43eeb57d087627869",
+  "collection_rev": "24b75d85df6a26aac7be13b56ff1ce4360c04a64",
   "convert_rev": "9035cafefc1da4315f26058734d0c2a19d5ab56a",
   "crypto_rev": "eede7d6918c51159c1422b7449f40dbac660ee57",
-  "csslib_rev": "192d720f121792ab05ca157ea280edc7e0410e9c",
+  "csslib_rev": "a3700b05bbcc42782e8a7024790dbf019d89c249",
   # Note: Updates to dart_style have to be coordinated with the infrastructure
   # team so that the internal formatter `tools/sdks/dart-sdk/bin/dart format`
   # matches the version here. Please follow this process to make updates:
@@ -143,59 +143,57 @@
   #   and land the review.
   #
   # For more details, see https://github.com/dart-lang/sdk/issues/30164.
-  "dart_style_rev": "f7bd4c42ad6015143f08931540631448048f692d", # disable tools/rev_sdk_deps.dart
-  "dartdoc_rev": "b4449742c0f7d7fa0179897cac163388e03236c2",
-  "ecosystem_rev": "8626bffad30d08792f0acbc813391800838e8207",
-  "file_rev": "855831c242a17c2dee163828d52710d9043c7c8d",
-  "fixnum_rev": "6c19e60366ce3d5edfaed51a7c12c98e7977977e",
+  "dart_style_rev": "5d35f4d829ffb8532d345d95d3e9504ae6cd839e", # disable tools/rev_sdk_deps.dart
+  "dartdoc_rev": "5df03dd913a0a2e20421cac61112aa84111160e0",
+  "ecosystem_rev": "2d58550f9e3fd8ecbc3b2e4444095fcb204a66c6",
+  "file_rev": "6842feaef1c4e06239bd30f8d3ef722838b1c97e",
+  "fixnum_rev": "83293b8ed86ccd574a94fcf4a2da43f31c1b43e0",
   "flute_rev": "a531c96a8b43d015c6bfbbfe3ab54867b0763b8b",
-  "glob_rev": "8b05be87f84f74d90dc0c15956f3ff95805322e5",
-  "html_rev": "0da420ca1e196cda54ede476d0d8d3ecf55375ef",
-  "http_rev": "b97b8dc22ea808c4fbd63f73abd7af8ecf694323",
-  "http_multi_server_rev": "8348be1bf8fd17881e2643086e68c9d2b28dd9ce",
+  "glob_rev": "00a9c82d31c01ae88ec9ae4021d842e9b832aa52",
+  "html_rev": "6d3bc86cf2ab530ef3fa5f84b5980dc318a02af4",
+  "http_rev": "f59cd79e1322c6272481e4f2ccfa9afcb37a6525",
+  "http_multi_server_rev": "e7515b5896b83d522189802a1e14e103e19426c0",
   "http_parser_rev": "ce528cf82f3d26ac761e29b2494a9e0c270d4939",
   "intl_rev": "5d65e3808ce40e6282e40881492607df4e35669f",
   "json_rpc_2_rev": "b4810dc7bee5828f240586c81f3f34853cacdbce",
   "leak_tracker_rev": "f5620600a5ce1c44f65ddaa02001e200b096e14c", # manually rolled
-  "lints_rev": "894b5006c463d2e1967fba3a8c3540d8ae249061",
-  "logging_rev": "8752902b75a476d2c7b64dcf01aaaee885f35c4c",
-  "markdown_rev": "f6eaea38146d8901756418c4e7123eb7bd77249e",
-  "matcher_rev": "d6d573d0f8d65b36550ce62aad3ce6b5e987b642",
+  "lints_rev": "5016d63c889936b2100520f999591d0492d9afe3",
+  "logging_rev": "6fa056098ceca03d399bff64592822b2ae5dee6e",
+  "markdown_rev": "d53feae0760a4f0aae5ffdfb12d8e6acccf14b40",
+  "matcher_rev": "31f13583630e093731c8cf2b843c14196d748c5c",
   "material_color_utilities_rev": "799b6ba2f3f1c28c67cc7e0b4f18e0c7d7f3c03e",
-  "mime_rev": "11fec7d6df509a4efd554051cc27e3bf82df9c96",
-  "mockito_rev": "eb4d1daa20c105c94ac29689c1975f0850fa18f2",
-  "native_rev": "5e9e4795d1faa39efeb92ae42fc0fa353778308f", # dart-native-interop-team@ is rolling breaking changes manually while the assets features are in experimental.
-  "package_config_rev": "76934c2ca25922ec72909bbff7dfbddaf0d02bd9",
+  "mockito_rev": "3de67548e833a8eef66a2a49070b197c2c08b3ab",
+  "native_rev": "659511886501bcce638c3966590df04984909ef0", # dart-native-interop-team@ is rolling breaking changes manually while the assets features are in experimental.
+  "package_config_rev": "bafff8e90be25e1985f7e3ee40ea1d22571a93e6",
   "path_rev": "e969f42ed112dd702a9453beb9df6c12ae2d3805",
   "pool_rev": "924fb04353cec915d927f9f1aed88e2eda92b98a",
   "protobuf_rev": "ccf104dbc36929c0f8708285d5f3a8fae206343e",
-  "pub_rev": "31fa75baa5872e7f094a554c0ec7741742889530", # disable tools/rev_sdk_deps.dart
-  "pub_semver_rev": "d9e5ee68a350fbf4319bd4dfcb895fc016337d3a",
-  "shelf_rev": "9f2dffecbe8f219146a077e401758602752d486a",
-  "source_map_stack_trace_rev": "741b6ceb4b6cdb8ff620664337d7ecc63ca52cc1",
-  "source_maps_rev": "5f82c613664ade03c7a6d0e6c59687c69dec894b",
-  "source_span_rev": "f81cd4a2df630a97264fb4015fb93944b5b98b11",
+  "pub_rev": "1efd3f5e274e153637d99698b0ee454f6f2550ab", # disable tools/rev_sdk_deps.dart
+  "pub_semver_rev": "8cce9d00431b6653026cdfcf6cf8548078c56f02",
+  "shelf_rev": "f5600534e3e49ebed02e1e14ec82553958d86f36",
+  "source_maps_rev": "17695e81d9ad129d20effd3d5c4f1cfa03f5add8",
+  "source_span_rev": "ec100b7f12e9d36d2cdb3c369fefde736de4a550",
   "sse_rev": "af2c5c572a8da6d2f7551b80d75121f2a38a4c79",
-  "stack_trace_rev": "090d3d186c085fdb913fe5350c666f8d0bd0f60f",
-  "stream_channel_rev": "c0c5a978b225d2e02be858e98e24455b7f79b1a0",
-  "string_scanner_rev": "a40bbbd83f1176bcc0021b336f5841310f91d8cb",
+  "stack_trace_rev": "115bcd9591d251dab7a5ad518655c2124a1cc525",
+  "stream_channel_rev": "f4407168b275fcde9187baefd7dbce76d0992825",
+  "string_scanner_rev": "2139417ffcd0392bde3ba9bc83ee13eaa5fbed01",
   "sync_http_rev": "91c0dd5ef9a008f0277aadcfd83036f82e572d09",
   "tar_rev": "32ceb55e673141abff4e84b99483fe5eb881c291",
-  "term_glyph_rev": "38a158f55006cf30942c928171ea601ee5e0308f",
-  "test_rev": "cd3dbd51fe765f7243ea51783318d82b4031fa7a",
-  "test_descriptor_rev": "90743bc16bc00526a1b9a64f813614be9b2479d9",
-  "test_process_rev": "6223572ca16d7585d5f08d9281de6a5734e45150",
-  "test_reflective_loader_rev": "6e648863b39aab8d0204e769d25805eea9db0ac4",
-  "tools_rev": "5b15f8b60bf950a2f06dad3258dee61c153fdb44",
-  "typed_data_rev": "365468a74251c930a463daf5b8f13227e269111a",
+  "term_glyph_rev": "19d8c08a4e81122639129c62049896021910c932",
+  "test_rev": "8e8a83607d90a7a6813fa378b2d1962a2fc0d44b",
+  "test_descriptor_rev": "a3db1efe3dc725dcae9ee61647d3bfc19b3231ac",
+  "test_process_rev": "52ee3f5ab70ed965bb7122c1d499081fbccd0bde",
+  "test_reflective_loader_rev": "598af2f503955020af0eaa82558d574a03934078",
+  "tools_rev": "d4995d47b99d5e9564abfed2218f4a23df75983b",
+  "typed_data_rev": "2bb9e6ead6394e2d4ec6068c5ece8b2ec0e2b945",
   "vector_math_rev": "2cfbe2c115a57b368ccbc3c89ebd38a06764d3d1",
-  "watcher_rev": "0484625589d8512b36a7ad898a6cc6351d24c556",
-  "web_rev": "4996dc2acd30ff06f7e500ec76fde8a66db82c0c",
+  "watcher_rev": "3b850778ad0b62db3aa2cfe48832870c2461db30",
+  "web_rev": "8478cd27d574249eca3d41f9135458dfda2762c8",
   "web_socket_channel_rev": "0e1d6e2eb5a0bfd62e45b772ac7107d796176cf6",
-  "webdev_rev": "75417c09181c97786d9539a662834bed9d2f1e77",
-  "webdriver_rev": "b181c9e5eca657ea4a12621332f47d9579106fda",
-  "webkit_inspection_protocol_rev": "119b877ae82bd2ca4cf7e5144d3a5ec104055164",
-  "yaml_rev": "a645c3905fc3cc2bbd3def9879ba8dedd26e3aa5",
+  "webdev_rev": "5f30c560dc4e3df341356c43ec1a766ee6b74a7c",
+  "webdriver_rev": "accfed557c005c87df56ffb626458f87da9f2125",
+  "webkit_inspection_protocol_rev": "b459c427b74bf5e0919a083a97a167fb74d8bff1",
+  "yaml_rev": "e773005ab84e1b4d24132b0a687be7f9a3bfda15",
   "yaml_edit_rev": "5c54d455f272bbb83c948ac420c677371e69ae77",
 
   # Windows deps
@@ -207,9 +205,9 @@
   # meant to be downloaded by users for local testing. You can self-service
   # update these by following the go/dart-engprod/browsers.md instructions.
   "download_chrome": False,
-  "chrome_tag": "128.0.6613.36",
+  "chrome_tag": "130.0.6723.31",
   "download_firefox": False,
-  "firefox_tag": "129.0",
+  "firefox_tag": "131.0",
 
   # Emscripten is used in dart2wasm tests.
   "download_emscripten": False,
@@ -340,7 +338,7 @@
   Var("dart_root") + "/third_party/gsutil": {
       "packages": [{
           "package": "infra/3pp/tools/gsutil",
-          "version": "version:2@5.5",
+          "version": "version:3@5.30",
       }],
       "dep_type": "cipd",
   },
@@ -458,8 +456,6 @@
            "@" + Var("material_color_utilities_rev"),
     "condition": "checkout_flute",
   },
-  Var("dart_root") + "/third_party/pkg/mime":
-      Var("dart_git") + "mime.git" + "@" + Var("mime_rev"),
   Var("dart_root") + "/third_party/pkg/mockito":
       Var("dart_git") + "mockito.git" + "@" + Var("mockito_rev"),
   Var("dart_root") + "/third_party/pkg/native":
@@ -483,9 +479,6 @@
       Var("dart_git") + "source_maps.git" + "@" + Var("source_maps_rev"),
   Var("dart_root") + "/third_party/pkg/source_span":
       Var("dart_git") + "source_span.git" + "@" + Var("source_span_rev"),
-  Var("dart_root") + "/third_party/pkg/source_map_stack_trace":
-      Var("dart_git") + "source_map_stack_trace.git" +
-      "@" + Var("source_map_stack_trace_rev"),
   Var("dart_root") + "/third_party/pkg/sse":
       Var("dart_git") + "sse.git" + "@" + Var("sse_rev"),
   Var("dart_root") + "/third_party/pkg/stack_trace":
@@ -701,7 +694,7 @@
     "packages": [
       {
       "package": "chromium/fuchsia/test-scripts",
-      "version": "oGxqx29_HA1eEBnt9pRiZYDa_BkzACC6l3_3xYYKLjYC",
+      "version": "Itifj1g1iG3RWRIzMMJA1o0Ngx-UZsT6YT7kOeNCXK8C",
       }
     ],
     "condition": 'download_fuchsia_deps',
@@ -712,7 +705,7 @@
     "packages": [
       {
       "package": "chromium/fuchsia/gn-sdk",
-      "version": "OKGFjciA5Vd0TQks4ow7-ppfxy_Y6v5hSjjn2w6LWjwC",
+      "version": "em2Jr5ylJrKKI86rUNPyGXlpTo4qGNTePgT70PDtRT8C",
       }
     ],
     "condition": 'download_fuchsia_deps',
diff --git a/benchmarks/Omnibus/dart/Omnibus.dart b/benchmarks/Omnibus/dart/Omnibus.dart
index 4a3f1f2..08cb9c5 100644
--- a/benchmarks/Omnibus/dart/Omnibus.dart
+++ b/benchmarks/Omnibus/dart/Omnibus.dart
@@ -26,8 +26,10 @@
     as lib_SkeletalAnimation;
 import '../../SkeletalAnimationSIMD/dart/SkeletalAnimationSIMD.dart'
     as lib_SkeletalAnimationSIMD;
+import '../../SwitchFSM/dart/SwitchFSM.dart' as lib_SwitchFSM;
 import '../../TypedDataDuplicate/dart/TypedDataDuplicate.dart'
     as lib_TypedDataDuplicate;
+import '../../UiMatrix/dart/UiMatrixHarness.dart' as lib_UiMatrix;
 import '../../Utf8Decode/dart/Utf8Decode.dart' as lib_Utf8Decode;
 import '../../Utf8Encode/dart/Utf8Encode.dart' as lib_Utf8Encode;
 
@@ -43,7 +45,9 @@
   'SHA256': lib_SHA256.main,
   'SkeletalAnimation': lib_SkeletalAnimation.main,
   'SkeletalAnimationSIMD': lib_SkeletalAnimationSIMD.main,
+  'SwitchFSM': lib_SwitchFSM.main,
   'TypedDataDuplicate': lib_TypedDataDuplicate.main,
+  'UiMatrix': lib_UiMatrix.main,
   'Utf8Decode': () => lib_Utf8Decode.main([]),
   'Utf8Encode': () => lib_Utf8Encode.main([]),
 };
diff --git a/benchmarks/OmnibusDeferred/dart/OmnibusDeferred.dart b/benchmarks/OmnibusDeferred/dart/OmnibusDeferred.dart
index 0775db9..cb497c7 100644
--- a/benchmarks/OmnibusDeferred/dart/OmnibusDeferred.dart
+++ b/benchmarks/OmnibusDeferred/dart/OmnibusDeferred.dart
@@ -26,8 +26,10 @@
     deferred as lib_SkeletalAnimation;
 import '../../SkeletalAnimationSIMD/dart/SkeletalAnimationSIMD.dart'
     deferred as lib_SkeletalAnimationSIMD;
+import '../../SwitchFSM/dart/SwitchFSM.dart' deferred as lib_SwitchFSM;
 import '../../TypedDataDuplicate/dart/TypedDataDuplicate.dart'
     deferred as lib_TypedDataDuplicate;
+import '../../UiMatrix/dart/UiMatrixHarness.dart' deferred as lib_UiMatrix;
 import '../../Utf8Decode/dart/Utf8Decode.dart' deferred as lib_Utf8Decode;
 import '../../Utf8Encode/dart/Utf8Encode.dart' deferred as lib_Utf8Encode;
 
@@ -82,10 +84,18 @@
     lib_SkeletalAnimationSIMD.loadLibrary,
     () => lib_SkeletalAnimationSIMD.main(),
   ),
+  'SwitchFSM': Lib(
+    lib_SwitchFSM.loadLibrary,
+    () => lib_SwitchFSM.main(),
+  ),
   'TypedDataDuplicate': Lib(
     lib_TypedDataDuplicate.loadLibrary,
     () => lib_TypedDataDuplicate.main(),
   ),
+  'UiMatrix': Lib(
+    lib_UiMatrix.loadLibrary,
+    () => lib_UiMatrix.main(),
+  ),
   'Utf8Decode': Lib(
     lib_Utf8Decode.loadLibrary,
     () => lib_Utf8Decode.main([]),
diff --git a/build/config/fuchsia/gn_configs.gni b/build/config/fuchsia/gn_configs.gni
index 76d7bc4..0233099 100644
--- a/build/config/fuchsia/gn_configs.gni
+++ b/build/config/fuchsia/gn_configs.gni
@@ -4,40 +4,9 @@
 
 assert(is_fuchsia)
 
-declare_args() {
-  # Path to the fuchsia SDK. This is intended for use in other templates &
-  # rules to reference the contents of the fuchsia SDK.
-  fuchsia_sdk = "//third_party/fuchsia/sdk/$host_os"
-
-  # ID uniquely identifying the Fuchsia IDK build. This is exposed as a
-  # property so it can be used to locate images and packages on GCS and
-  # as a marker to indicate the "version" of the IDK.
-  # Defaults to the id found in the manifest.json file of the SDK.
-  fuchsia_sdk_id = ""
-}
-
-declare_args() {
-  # The SDK manifest file. This is useful to include as a dependency
-  # for some targets in order to cause a rebuild when the version of the
-  # SDK is changed.
-  fuchsia_sdk_manifest_file = "$fuchsia_sdk/meta/manifest.json"
-
-  # fuchsia_tool_dir is used to specify the directory in the SDK to locate
-  # tools for the host cpu architecture. If the host_cpu is not recognized,
-  # then tool dir defaults to x64.
-  fuchsia_tool_dir = "${fuchsia_sdk}/tools/x64"
-  if (host_cpu == "arm64") {
-    fuchsia_tool_dir = "${fuchsia_sdk}/tools/arm64"
-  }
-}
-
-if (fuchsia_sdk_id == "") {
-  # Note: If we need to expose more than just the id in the future,
-  # we should consider exposing the entire json object for the metadata vs.
-  # adding a bunch of variables.
-  _meta = read_file(fuchsia_sdk_manifest_file, "json")
-  fuchsia_sdk_id = _meta.id
-}
+# Path to the fuchsia SDK. This is intended for use in other templates &
+# rules to reference the contents of the fuchsia SDK.
+fuchsia_sdk = "//third_party/fuchsia/sdk/$host_os"
 
 declare_args() {
   # Specify a readelf_exec path to use. If not specified, the host's system
diff --git a/build/dart/dart_action.gni b/build/dart/dart_action.gni
index a33c58e..c9dce56 100644
--- a/build/dart/dart_action.gni
+++ b/build/dart/dart_action.gni
@@ -191,6 +191,7 @@
 #    depfile
 #    deps
 #    inputs
+#    metadata
 #    outputs
 #    testonly
 #    visibility
@@ -229,6 +230,7 @@
 #    depfile
 #    deps
 #    inputs
+#    metadata
 #    outputs
 #    testonly
 #    visibility
@@ -250,6 +252,7 @@
                              "depfile",
                              "deps",
                              "inputs",
+                             "metadata",
                              "outputs",
                              "pool",
                              "tool",
@@ -301,6 +304,7 @@
 #    depfile
 #    deps
 #    inputs
+#    metadata
 #    outputs
 #    testonly
 #    visibility
@@ -314,6 +318,7 @@
                              "depfile",
                              "deps",
                              "inputs",
+                             "metadata",
                              "outputs",
                              "packages",
                              "pool",
@@ -357,6 +362,7 @@
 #    depfile
 #    deps
 #    inputs
+#    metadata
 #    outputs
 #    testonly
 #    visibility
@@ -379,6 +385,7 @@
                              "depfile",
                              "deps",
                              "inputs",
+                             "metadata",
                              "outputs",
                              "packages",
                              "pool",
diff --git a/build/gn_run_binary.py b/build/gn_run_binary.py
index 99cd20c..26dc769 100755
--- a/build/gn_run_binary.py
+++ b/build/gn_run_binary.py
@@ -24,8 +24,8 @@
         subprocess.check_output(command, stderr=subprocess.STDOUT)
         return 0
     except subprocess.CalledProcessError as e:
-        return ("Command failed: " + ' '.join(command) + "\n" + "output: " +
-                _decode(e.output))
+        return ("Command failed: " + ' '.join(command) + "\n" + "exitCode: " +
+                str(e.returncode) + "\n" + "output: " + _decode(e.output))
     except OSError as e:
         return ("Command failed: " + ' '.join(command) + "\n" + "output: " +
                 _decode(e.strerror))
diff --git a/build/secondary/third_party/libcxxabi/BUILD.gn b/build/secondary/third_party/libcxxabi/BUILD.gn
index a086276..afe2c58 100644
--- a/build/secondary/third_party/libcxxabi/BUILD.gn
+++ b/build/secondary/third_party/libcxxabi/BUILD.gn
@@ -70,7 +70,7 @@
     sources += [ "src/cxa_guard.cpp" ]
   }
 
-  if (is_fuchsia || (is_posix && !is_ios && !is_macos)) {
+  if (is_fuchsia || (is_posix && !is_ios && !is_mac)) {
     sources += [ "src/cxa_thread_atexit.cpp" ]
   }
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/exhaustiveness/exhaustive.dart b/pkg/_fe_analyzer_shared/lib/src/exhaustiveness/exhaustive.dart
index eb8cae8..372dc88 100644
--- a/pkg/_fe_analyzer_shared/lib/src/exhaustiveness/exhaustive.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/exhaustiveness/exhaustive.dart
@@ -16,42 +16,57 @@
   return checkExhaustiveness(fieldLookup, valueSpace, caseSpaces) == null;
 }
 
-/// Checks the [cases] representing a series of switch cases to see if they
+/// Checks the [caseSpaces] representing a series of switch cases to see if they
 /// exhaustively cover all possible values of the matched [valueType]. Also
 /// checks to see if any case can't be matched because it's covered by previous
 /// cases.
 ///
-/// Returns a list of any unreachable case or non-exhaustive match errors.
-/// Returns an empty list if all cases are reachable and the cases are
-/// exhaustive.
-List<ExhaustivenessError> reportErrors(
-    ObjectPropertyLookup fieldLookup, StaticType valueType, List<Space> cases,
-    {required bool computeUnreachable}) {
+/// [caseIsGuarded] should be a list of booleans indicating whether each case in
+/// [caseSpaces] has an associated `when` clause.
+///
+/// If any unreachable cases are found, information about them is appended to
+/// [caseUnreachabilities]. (If `null` is passed for [caseUnreachabilities],
+/// then no information about unreachable cases is generated).
+///
+/// If the switch cases are not fully exhaustive, details about how they fail to
+/// be exhaustive are returned using a data structure of type
+/// [NonExhaustiveness]; otherwise `null` is returned.
+///
+/// Note that if a non-null value is returned, that doesn't necessarily mean
+/// that an error should be reported; the caller still must check whether the
+/// switch has a `default` clause and whether the scrutinee type is an "always
+/// exhaustive" type.
+NonExhaustiveness? computeExhaustiveness(ObjectPropertyLookup fieldLookup,
+    StaticType valueType, List<bool> caseIsGuarded, List<Space> caseSpaces,
+    {List<CaseUnreachability>? caseUnreachabilities}) {
   _Checker checker = new _Checker(fieldLookup);
 
-  List<ExhaustivenessError> errors = <ExhaustivenessError>[];
-
   Space valuePattern = new Space(const Path.root(), valueType);
-  List<List<Space>> caseRows = cases.map((space) => [space]).toList();
+  List<List<Space>> caseRows = [];
 
-  if (computeUnreachable) {
-    for (int i = 1; i < caseRows.length; i++) {
+  for (int i = 0; i < caseSpaces.length; i++) {
+    late List<Space> caseRow = [caseSpaces[i]];
+    if (caseUnreachabilities != null && i > 0) {
       // See if this case is covered by previous ones.
-      if (checker._unmatched(caseRows.sublist(0, i), caseRows[i],
+      if (checker._unmatched(caseRows, caseRow,
               returnMultipleWitnesses: false) ==
           null) {
-        errors.add(new UnreachableCaseError(valueType, cases, i));
+        caseUnreachabilities
+            .add(new CaseUnreachability(valueType, caseSpaces, i));
       }
     }
+    if (!caseIsGuarded[i]) {
+      caseRows.add(caseRow);
+    }
   }
 
   List<Witness>? witnesses = checker._unmatched(caseRows, [valuePattern],
       returnMultipleWitnesses: true);
   if (witnesses != null) {
-    errors.add(new NonExhaustiveError(valueType, cases, witnesses));
+    return new NonExhaustiveness(valueType, caseSpaces, witnesses);
+  } else {
+    return null;
   }
-
-  return errors;
 }
 
 /// Determines if [cases] is exhaustive over all values contained by
@@ -357,28 +372,26 @@
   return result;
 }
 
-class ExhaustivenessError {}
-
-class NonExhaustiveError implements ExhaustivenessError {
+class NonExhaustiveness {
   final StaticType valueType;
 
   final List<Space> cases;
 
   final List<Witness> witnesses;
 
-  NonExhaustiveError(this.valueType, this.cases, this.witnesses);
+  NonExhaustiveness(this.valueType, this.cases, this.witnesses);
 
   @override
   String toString() =>
       '$valueType is not exhaustively matched by ${cases.join('|')}.';
 }
 
-class UnreachableCaseError implements ExhaustivenessError {
+class CaseUnreachability {
   final StaticType valueType;
   final List<Space> cases;
   final int index;
 
-  UnreachableCaseError(this.valueType, this.cases, this.index);
+  CaseUnreachability(this.valueType, this.cases, this.index);
 
   @override
   String toString() => 'Case #${index + 1} ${cases[index]} is unreachable.';
diff --git a/pkg/_fe_analyzer_shared/lib/src/exhaustiveness/shared.dart b/pkg/_fe_analyzer_shared/lib/src/exhaustiveness/shared.dart
index a7a1747..c418f57 100644
--- a/pkg/_fe_analyzer_shared/lib/src/exhaustiveness/shared.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/exhaustiveness/shared.dart
@@ -403,14 +403,9 @@
       {required bool nonNull});
 
   /// Creates the root space for [pattern].
-  Space createRootSpace(StaticType contextType, Pattern pattern,
-      {required bool hasGuard}) {
-    if (hasGuard) {
-      return createUnknownSpace(const Path.root());
-    } else {
-      return dispatchPattern(const Path.root(), contextType, pattern,
-          nonNull: false);
-    }
+  Space createRootSpace(StaticType contextType, Pattern pattern) {
+    return dispatchPattern(const Path.root(), contextType, pattern,
+        nonNull: false);
   }
 
   /// Creates the [Space] at [path] for a variable pattern of the declared
diff --git a/pkg/_fe_analyzer_shared/lib/src/exhaustiveness/test_helper.dart b/pkg/_fe_analyzer_shared/lib/src/exhaustiveness/test_helper.dart
index 4ed5094..ef31075 100644
--- a/pkg/_fe_analyzer_shared/lib/src/exhaustiveness/test_helper.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/exhaustiveness/test_helper.dart
@@ -80,25 +80,20 @@
   return sb.toString();
 }
 
-String errorToText(ExhaustivenessError error) {
-  if (error is NonExhaustiveError) {
-    StringBuffer sb = new StringBuffer();
-    sb.write('non-exhaustive:');
-    String delimiter = '';
-    for (Witness witness in error.witnesses) {
-      sb.write(delimiter);
-      String witnessText = witness.asWitness;
-      String correctionText = witness.asCorrection;
-      if (witnessText != correctionText) {
-        sb.write('$witnessText/$correctionText');
-      } else {
-        sb.write(witnessText);
-      }
-      delimiter = ';';
+String nonExhaustivenessToText(NonExhaustiveness nonExhaustiveness) {
+  StringBuffer sb = new StringBuffer();
+  sb.write('non-exhaustive:');
+  String delimiter = '';
+  for (Witness witness in nonExhaustiveness.witnesses) {
+    sb.write(delimiter);
+    String witnessText = witness.asWitness;
+    String correctionText = witness.asCorrection;
+    if (witnessText != correctionText) {
+      sb.write('$witnessText/$correctionText');
+    } else {
+      sb.write(witnessText);
     }
-    return sb.toString();
-  } else {
-    assert(error is UnreachableCaseError);
-    return 'unreachable';
+    delimiter = ';';
   }
+  return sb.toString();
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/experiments/flags.dart b/pkg/_fe_analyzer_shared/lib/src/experiments/flags.dart
index 2f24e7a..96b4039 100644
--- a/pkg/_fe_analyzer_shared/lib/src/experiments/flags.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/experiments/flags.dart
@@ -108,6 +108,20 @@
       experimentEnabledVersion: const Version(3, 4),
       experimentReleasedVersion: const Version(3, 4)),
 
+  inferenceUpdate4(
+      name: 'inference-update-4',
+      isEnabledByDefault: false,
+      isExpired: false,
+      experimentEnabledVersion: defaultLanguageVersion,
+      experimentReleasedVersion: defaultLanguageVersion),
+
+  inferenceUsingBounds(
+      name: 'inference-using-bounds',
+      isEnabledByDefault: false,
+      isExpired: false,
+      experimentEnabledVersion: defaultLanguageVersion,
+      experimentReleasedVersion: defaultLanguageVersion),
+
   inlineClass(
       name: 'inline-class',
       isEnabledByDefault: true,
@@ -164,6 +178,13 @@
       experimentEnabledVersion: const Version(3, 0),
       experimentReleasedVersion: const Version(3, 0)),
 
+  recordUse(
+      name: 'record-use',
+      isEnabledByDefault: false,
+      isExpired: false,
+      experimentEnabledVersion: defaultLanguageVersion,
+      experimentReleasedVersion: defaultLanguageVersion),
+
   records(
       name: 'records',
       isEnabledByDefault: true,
@@ -171,13 +192,6 @@
       experimentEnabledVersion: const Version(3, 0),
       experimentReleasedVersion: const Version(3, 0)),
 
-  resourceIdentifiers(
-      name: 'resource-identifiers',
-      isEnabledByDefault: false,
-      isExpired: false,
-      experimentEnabledVersion: defaultLanguageVersion,
-      experimentReleasedVersion: defaultLanguageVersion),
-
   sealedClass(
       name: 'sealed-class',
       isEnabledByDefault: true,
@@ -227,6 +241,13 @@
       experimentEnabledVersion: const Version(2, 19),
       experimentReleasedVersion: const Version(2, 19)),
 
+  unquotedImports(
+      name: 'unquoted-imports',
+      isEnabledByDefault: false,
+      isExpired: false,
+      experimentEnabledVersion: defaultLanguageVersion,
+      experimentReleasedVersion: defaultLanguageVersion),
+
   variance(
       name: 'variance',
       isEnabledByDefault: false,
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index 6a6273a..3255c82 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -67,11 +67,6 @@
   final Type _type;
 
   /// The flow model representing execution state after the expression is
-  /// evaluated, assuming nothing about the result of the evaluation.
-  @visibleForTesting
-  final FlowModel<Type> after;
-
-  /// The flow model representing execution state after the expression is
   /// evaluated, if the expression evaluates to `true`.
   @visibleForTesting
   final FlowModel<Type> ifTrue;
@@ -86,31 +81,27 @@
   /// target, which causes a promotion if it evaluates to `true`).
   @visibleForTesting
   ExpressionInfo(
-      {required Type type,
-      required this.after,
-      required this.ifTrue,
-      required this.ifFalse})
+      {required Type type, required this.ifTrue, required this.ifFalse})
       : _type = type;
 
   /// Creates an [ExpressionInfo] for an expression whose value doesn't
   /// influence the flow model.
   @visibleForTesting
-  ExpressionInfo.trivial({required Type type, required this.after})
+  ExpressionInfo.trivial({required Type type, required FlowModel<Type> model})
       : _type = type,
-        ifTrue = after,
-        ifFalse = after;
+        ifTrue = model,
+        ifFalse = model;
 
   /// Determines if the value of the expression represented by `this` influences
   /// the flow model.
-  bool get isNonTrivial =>
-      !identical(after, ifTrue) || !identical(after, ifFalse);
+  bool get isNonTrivial => !identical(ifTrue, ifFalse);
 
   /// Indicates whether the expression represented by `this` is a `null`
   /// literal.
   bool get isNull => false;
 
   @override
-  String toString() => 'ExpressionInfo(type: $_type, after: $after, '
+  String toString() => 'ExpressionInfo(type: $_type, '
       '_ifTrue: $ifTrue, ifFalse: $ifFalse)';
 
   /// Creates an [ExpressionInfo] containing information about the logical
@@ -119,8 +110,7 @@
   /// produces an [ExpressionInfo] containing information about the expression
   /// `x != null`.
   ExpressionInfo<Type> _invert() => isNonTrivial
-      ? new ExpressionInfo<Type>(
-          type: _type, after: after, ifTrue: ifFalse, ifFalse: ifTrue)
+      ? new ExpressionInfo<Type>(type: _type, ifTrue: ifFalse, ifFalse: ifTrue)
       : this;
 }
 
@@ -703,6 +693,13 @@
   /// not be called until after processing the method call to `z(x)`.
   void nullAwareAccess_rightBegin(Expression? target, Type targetType);
 
+  /// Call this method after visiting the value of a null-aware map entry.
+  void nullAwareMapEntry_end({required bool isKeyNullAware});
+
+  /// Call this method after visiting the key of a null-aware map entry.
+  void nullAwareMapEntry_valueBegin(Expression key, Type keyType,
+      {required bool isKeyNullAware});
+
   /// Call this method before visiting the subpattern of a null-check or a
   /// null-assert pattern. [isAssert] indicates whether the pattern is a
   /// null-check or a null-assert pattern.
@@ -1656,6 +1653,22 @@
   }
 
   @override
+  void nullAwareMapEntry_end({required bool isKeyNullAware}) {
+    return _wrap('nullAwareMapEntry_end(isKeyNullAware: $isKeyNullAware)',
+        () => _wrapped.nullAwareMapEntry_end(isKeyNullAware: isKeyNullAware));
+  }
+
+  @override
+  void nullAwareMapEntry_valueBegin(Expression key, Type keyType,
+      {required bool isKeyNullAware}) {
+    _wrap(
+        'nullAwareMapEntry_valueBegin($key, $keyType, '
+        'isKeyNullAware: $isKeyNullAware)',
+        () => _wrapped.nullAwareMapEntry_valueBegin(key, keyType,
+            isKeyNullAware: isKeyNullAware));
+  }
+
+  @override
   bool nullCheckOrAssertPattern_begin(
       {required bool isAssert, required Type matchedValueType}) {
     return _wrap(
@@ -2455,14 +2468,14 @@
         infoFor(helper, reference.promotionKey, ssaNode: reference.ssaNode);
     if (info.writeCaptured) {
       return new ExpressionInfo<Type>.trivial(
-          after: this, type: helper.boolType);
+          model: this, type: helper.boolType);
     }
 
     Type previousType = reference._type;
     Type newType = helper.typeOperations.promoteToNonNull(previousType);
     if (newType == previousType) {
       return new ExpressionInfo<Type>.trivial(
-          after: this, type: helper.boolType);
+          model: this, type: helper.boolType);
     }
     assert(helper.typeOperations.isSubtypeOf(newType, previousType));
 
@@ -2470,7 +2483,7 @@
         _finishTypeTest(helper, reference, info, null, newType);
 
     return new ExpressionInfo<Type>(
-        type: helper.boolType, after: this, ifTrue: ifTrue, ifFalse: this);
+        type: helper.boolType, ifTrue: ifTrue, ifFalse: this);
   }
 
   /// Returns an [ExpressionInfo] indicating the result of casting the given
@@ -2515,7 +2528,7 @@
         infoFor(helper, reference.promotionKey, ssaNode: reference.ssaNode);
     if (info.writeCaptured) {
       return new ExpressionInfo<Type>.trivial(
-          after: this, type: helper.boolType);
+          model: this, type: helper.boolType);
     }
 
     Type previousType = reference._type;
@@ -2544,7 +2557,7 @@
         _finishTypeTest(helper, reference, info, type, typeIfFalse);
 
     return new ExpressionInfo<Type>(
-        type: helper.boolType, after: this, ifTrue: ifTrue, ifFalse: ifFalse);
+        type: helper.boolType, ifTrue: ifTrue, ifFalse: ifFalse);
   }
 
   /// Returns a [FlowModel] indicating the result of removing a control flow
@@ -4041,13 +4054,13 @@
 
 /// Specialization of [ExpressionInfo] for the case where the expression is a
 /// reference to a variable, and the information we have about the expression is
-/// trivial (meaning we know by construction that the expression's [after],
-/// [ifTrue], and [ifFalse] models are all the same).
+/// trivial (meaning we know by construction that the expression's [ifTrue] and
+/// [ifFalse] models are the same).
 @visibleForTesting
 class TrivialVariableReference<Type extends Object> extends _Reference<Type> {
   TrivialVariableReference(
       {required super.type,
-      required super.after,
+      required super.model,
       required super.promotionKey,
       required super.isThisOrSuper,
       required super.ssaNode})
@@ -4070,13 +4083,9 @@
       FlowModelHelper<Type> helper, FlowModel<Type> current) {
     if (previousExpressionInfo != null && previousExpressionInfo.isNonTrivial) {
       // [previousExpression] contained non-trivial flow analysis information,
-      // so we need to rebase its [ifTrue] and [ifFalse] flow models. We don't
-      // need to rebase its [after] model, since that just represents the flow
-      // state after reading the variable (without regard to the value read), so
-      // that's just the same as [current].
+      // so we need to rebase its [ifTrue] and [ifFalse] flow models.
       return new _Reference(
           promotionKey: promotionKey,
-          after: current,
           type: _type,
           isThisOrSuper: isThisOrSuper,
           ifTrue: previousExpressionInfo.ifTrue.rebaseForward(helper, current),
@@ -4091,7 +4100,7 @@
   }
 
   @override
-  String toString() => 'TrivialVariableReference(type: $_type, after: $after, '
+  String toString() => 'TrivialVariableReference(type: $_type, '
       'promotionKey: $promotionKey, isThisOrSuper: $isThisOrSuper)';
 }
 
@@ -4160,15 +4169,29 @@
 
 /// [_FlowContext] representing a conditional expression.
 class _ConditionalContext<Type extends Object> extends _BranchContext<Type> {
-  /// Flow models associated with the value of the conditional expression in the
-  /// circumstance where the "then" branch is taken.
+  /// Expression info for the "then" expression, or `null` if the "then"
+  /// expression hasn't been analyzed yet.
+  ///
+  /// This object records flow-analysis-related information about the value of
+  /// the "then" expression, such as whether it refers to a promotable value,
+  /// and if it's a boolean expression, whether anything should be promoted
+  /// in flow control paths where it evaluates to true or false.
   ExpressionInfo<Type>? _thenInfo;
 
+  /// Flow model leaving the "then" expression, or `null` if the "then"
+  /// expression hasn't been analyzed yet.
+  ///
+  /// This object records flow-analysis-related information about the state of
+  /// the program in the flow control path leaving the "then" expression, such
+  /// as whether anything is promoted after the "then" expression executes.
+  FlowModel<Type>? _thenModel;
+
   _ConditionalContext(super._branchModel);
 
   @override
-  Map<String, Object?> get _debugFields =>
-      super._debugFields..['thenInfo'] = _thenInfo;
+  Map<String, Object?> get _debugFields => super._debugFields
+    ..['thenInfo'] = _thenInfo
+    ..['thenModel'] = _thenModel;
 
   @override
   String get _debugType => '_ConditionalContext';
@@ -4367,15 +4390,9 @@
         expression,
         value
             ? new ExpressionInfo(
-                type: boolType,
-                after: _current,
-                ifTrue: _current,
-                ifFalse: unreachable)
+                type: boolType, ifTrue: _current, ifFalse: unreachable)
             : new ExpressionInfo(
-                type: boolType,
-                after: _current,
-                ifTrue: unreachable,
-                ifFalse: _current));
+                type: boolType, ifTrue: unreachable, ifFalse: _current));
   }
 
   @override
@@ -4436,6 +4453,7 @@
     _ConditionalContext<Type> context =
         _stack.last as _ConditionalContext<Type>;
     context._thenInfo = _expressionEnd(thenExpression, thenType);
+    context._thenModel = _current;
     _current = context._branchModel;
   }
 
@@ -4448,12 +4466,14 @@
     _ConditionalContext<Type> context =
         _stack.removeLast() as _ConditionalContext<Type>;
     ExpressionInfo<Type> thenInfo = context._thenInfo!;
+    FlowModel<Type> thenModel = context._thenModel!;
     ExpressionInfo<Type> elseInfo = _expressionEnd(elseExpression, elseType);
+    FlowModel<Type> elseModel = _current;
+    _current = _join(thenModel, elseModel).unsplit();
     _storeExpressionInfo(
         conditionalExpression,
         new ExpressionInfo(
             type: conditionalExpressionType,
-            after: _join(thenInfo.after, elseInfo.after).unsplit(),
             ifTrue: _join(thenInfo.ifTrue, elseInfo.ifTrue).unsplit(),
             ifFalse: _join(thenInfo.ifFalse, elseInfo.ifFalse).unsplit()));
   }
@@ -4555,7 +4575,7 @@
   @override
   ExpressionInfo<Type> equalityOperand_end(Expression operand, Type type) =>
       _getExpressionInfo(operand) ??
-      new ExpressionInfo<Type>.trivial(after: _current, type: type);
+      new ExpressionInfo<Type>.trivial(model: _current, type: type);
 
   @override
   void equalityOperation_end(
@@ -4626,7 +4646,6 @@
     ExpressionInfo<Type> conditionInfo = condition == null
         ? new ExpressionInfo(
             type: boolType,
-            after: _current,
             ifTrue: _current,
             ifFalse: _current.setUnreachable())
         : _expressionEnd(condition, boolType);
@@ -4931,11 +4950,11 @@
       trueResult = _join(context._branchModel, rhsInfo.ifTrue);
       falseResult = rhsInfo.ifFalse;
     }
+    _current = _join(trueResult, falseResult).unsplit();
     _storeExpressionInfo(
         wholeExpression,
         new ExpressionInfo(
             type: boolType,
-            after: _join(trueResult, falseResult).unsplit(),
             ifTrue: trueResult.unsplit(),
             ifFalse: falseResult.unsplit()));
   }
@@ -5033,6 +5052,35 @@
   }
 
   @override
+  void nullAwareMapEntry_end({required bool isKeyNullAware}) {
+    if (!isKeyNullAware) return;
+    _NullAwareMapEntryContext<Type> context =
+        _stack.removeLast() as _NullAwareMapEntryContext<Type>;
+    _current = _join(_current, context._shortcutState).unsplit();
+  }
+
+  @override
+  void nullAwareMapEntry_valueBegin(Expression key, Type keyType,
+      {required bool isKeyNullAware}) {
+    if (!isKeyNullAware) return;
+    _Reference<Type>? keyReference = _getExpressionReference(key);
+    FlowModel<Type> shortcutState;
+    _current = _current.split();
+    if (keyReference != null) {
+      ExpressionInfo<Type> expressionInfo =
+          _current.tryMarkNonNullable(this, keyReference);
+      _current = expressionInfo.ifTrue;
+      shortcutState = expressionInfo.ifFalse;
+    } else {
+      shortcutState = _current;
+    }
+    if (operations.classifyType(keyType) == TypeClassification.nonNullable) {
+      shortcutState = shortcutState.setUnreachable();
+    }
+    _stack.add(new _NullAwareMapEntryContext<Type>(shortcutState));
+  }
+
+  @override
   bool nullCheckOrAssertPattern_begin(
       {required bool isAssert, required Type matchedValueType}) {
     if (!isAssert) {
@@ -5063,7 +5111,7 @@
   @override
   void nullLiteral(Expression expression, Type type) {
     _storeExpressionInfo(
-        expression, new _NullInfo(after: _current, type: type));
+        expression, new _NullInfo(model: _current, type: type));
   }
 
   @override
@@ -5225,7 +5273,7 @@
         propertyName: propertyName,
         propertyMember: propertyMember,
         promotionKey: propertySsaNode.promotionKey,
-        after: _current,
+        model: _current,
         type: unpromotedType,
         ssaNode: propertySsaNode);
     if (wholeExpression != null) {
@@ -5247,7 +5295,7 @@
         propertyName: propertyName,
         propertyMember: propertyMember,
         promotionKey: propertySsaNode.promotionKey,
-        after: _current,
+        model: _current,
         type: unpromotedType,
         ssaNode: propertySsaNode);
     _stack.add(new _PropertyPatternContext<Type>(
@@ -5630,7 +5678,7 @@
   /// [ExpressionInfo] is created recording the current flow analysis state.
   ExpressionInfo<Type> _expressionEnd(Expression? expression, Type type) =>
       _getExpressionInfo(expression) ??
-      new ExpressionInfo<Type>.trivial(after: _current, type: type);
+      new ExpressionInfo<Type>.trivial(model: _current, type: type);
 
   void _forwardExpression(Expression newExpression, Expression oldExpression) {
     if (identical(_expressionWithInfo, oldExpression)) {
@@ -5935,7 +5983,7 @@
             ssaNode: ssaNode));
     return new TrivialVariableReference(
         promotionKey: promotionKey,
-        after: _current,
+        model: _current,
         type: type,
         isThisOrSuper: false,
         ssaNode: ssaNode);
@@ -6050,7 +6098,6 @@
       Expression expression, ExpressionInfo<Type> expressionInfo) {
     _expressionWithInfo = expression;
     _expressionInfo = expressionInfo;
-    _current = expressionInfo.after;
   }
 
   /// Associates [expression], which should be the most recently visited
@@ -6065,7 +6112,7 @@
           {required bool isSuper}) =>
       new TrivialVariableReference<Type>(
           promotionKey: promotionKeyStore.thisPromotionKey,
-          after: _current,
+          model: _current,
           type: staticType,
           isThisOrSuper: true,
           ssaNode: isSuper ? _superSsaNode : _thisSsaNode);
@@ -6075,7 +6122,7 @@
     PromotionModel<Type> info = _current.promotionInfo!.get(this, variableKey)!;
     return new TrivialVariableReference<Type>(
         promotionKey: variableKey,
-        after: _current,
+        model: _current,
         type: info.promotedTypes?.last ?? unpromotedType,
         isThisOrSuper: false,
         ssaNode: info.ssaNode ?? new SsaNode<Type>(null));
@@ -6641,6 +6688,13 @@
   void nullAwareAccess_rightBegin(Expression? target, Type targetType) {}
 
   @override
+  void nullAwareMapEntry_end({required bool isKeyNullAware}) {}
+
+  @override
+  void nullAwareMapEntry_valueBegin(Expression key, Type keyType,
+      {required bool isKeyNullAware}) {}
+
+  @override
   bool nullCheckOrAssertPattern_begin(
           {required bool isAssert, required Type matchedValueType}) =>
       false;
@@ -6922,16 +6976,35 @@
   String get _debugType => '_NullAwareAccessContext';
 }
 
+/// [_FlowContext] representing a null-aware map entry (`{?a: ?b}`).
+///
+/// This context should only be created for a null-aware map entry that has a
+/// null-aware key.
+class _NullAwareMapEntryContext<Type extends Object> extends _FlowContext {
+  /// The state if the operation short-cuts (i.e. if the key expression was
+  /// `null`.
+  final FlowModel<Type> _shortcutState;
+
+  _NullAwareMapEntryContext(this._shortcutState);
+
+  @override
+  Map<String, Object?> get _debugFields =>
+      super._debugFields..['shortcutState'] = _shortcutState;
+
+  @override
+  String get _debugType => '_NullAwareMapEntryContext';
+}
+
 /// Specialization of [ExpressionInfo] for the case where the expression is a
 /// `null` literal.
 class _NullInfo<Type extends Object> extends ExpressionInfo<Type> {
-  _NullInfo({required super.type, required super.after}) : super.trivial();
+  _NullInfo({required super.type, required super.model}) : super.trivial();
 
   @override
   bool get isNull => true;
 
   @override
-  String toString() => '_NullInfo(type: $_type, after: $after)';
+  String toString() => '_NullInfo(type: $_type)';
 }
 
 /// [_FlowContext] representing a logical-or pattern.
@@ -6976,7 +7049,7 @@
           Type matchedType, FlowModel<Type> current) =>
       new TrivialVariableReference(
           promotionKey: _matchedValueInfo.promotionKey,
-          after: current,
+          model: current,
           type: matchedType,
           isThisOrSuper: false,
           ssaNode: new SsaNode<Type>(null));
@@ -7012,7 +7085,7 @@
 
   _PropertyReference(
       {required super.type,
-      required super.after,
+      required super.model,
       required this.propertyName,
       required this.propertyMember,
       required super.promotionKey,
@@ -7021,7 +7094,7 @@
 
   @override
   String toString() => '_PropertyReference('
-      'type: $_type, after: $after, propertyName: $propertyName, '
+      'type: $_type, propertyName: $propertyName, '
       'propertyMember: $propertyMember, promotionKey: $promotionKey)';
 }
 
@@ -7082,7 +7155,6 @@
 
   _Reference(
       {required super.type,
-      required super.after,
       required super.ifTrue,
       required super.ifFalse,
       required this.promotionKey,
@@ -7091,14 +7163,14 @@
 
   _Reference.trivial(
       {required super.type,
-      required super.after,
+      required super.model,
       required this.promotionKey,
       required this.isThisOrSuper,
       required this.ssaNode})
       : super.trivial();
 
   @override
-  String toString() => '_Reference(type: $_type, after: $after, '
+  String toString() => '_Reference(type: $_type, '
       'ifTrue: $ifTrue, ifFalse: $ifFalse, promotionKey: $promotionKey, '
       'isThisOrSuper: $isThisOrSuper, ssaNode: $ssaNode)';
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 3ba6203..9e622a7 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -3377,65 +3377,30 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(String name, Uri uri_, Uri uri2_)>
-    templateDuplicatedExportInType =
+    templateDuplicatedImport =
     const Template<Message Function(String name, Uri uri_, Uri uri2_)>(
-  "DuplicatedExportInType",
-  problemMessageTemplate:
-      r"""'#name' is exported from both '#uri' and '#uri2'.""",
-  withArguments: _withArgumentsDuplicatedExportInType,
-);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String name, Uri uri_, Uri uri2_)>
-    codeDuplicatedExportInType =
-    const Code<Message Function(String name, Uri uri_, Uri uri2_)>(
-  "DuplicatedExportInType",
-);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsDuplicatedExportInType(String name, Uri uri_, Uri uri2_) {
-  if (name.isEmpty) throw 'No name provided';
-  name = demangleMixinApplicationName(name);
-  String? uri = relativizeUri(uri_);
-  String? uri2 = relativizeUri(uri2_);
-  return new Message(
-    codeDuplicatedExportInType,
-    problemMessage:
-        """'${name}' is exported from both '${uri}' and '${uri2}'.""",
-    arguments: {
-      'name': name,
-      'uri': uri_,
-      'uri2': uri2_,
-    },
-  );
-}
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<Message Function(String name, Uri uri_, Uri uri2_)>
-    templateDuplicatedImportInType =
-    const Template<Message Function(String name, Uri uri_, Uri uri2_)>(
-  "DuplicatedImportInType",
+  "DuplicatedImport",
   problemMessageTemplate:
       r"""'#name' is imported from both '#uri' and '#uri2'.""",
-  withArguments: _withArgumentsDuplicatedImportInType,
+  withArguments: _withArgumentsDuplicatedImport,
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name, Uri uri_, Uri uri2_)>
-    codeDuplicatedImportInType =
+    codeDuplicatedImport =
     const Code<Message Function(String name, Uri uri_, Uri uri2_)>(
-  "DuplicatedImportInType",
+  "DuplicatedImport",
   analyzerCodes: <String>["AMBIGUOUS_IMPORT"],
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsDuplicatedImportInType(String name, Uri uri_, Uri uri2_) {
+Message _withArgumentsDuplicatedImport(String name, Uri uri_, Uri uri2_) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
   String? uri = relativizeUri(uri_);
   String? uri2 = relativizeUri(uri2_);
   return new Message(
-    codeDuplicatedImportInType,
+    codeDuplicatedImport,
     problemMessage:
         """'${name}' is imported from both '${uri}' and '${uri2}'.""",
     arguments: {
@@ -15040,6 +15005,17 @@
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeRecordUseCannotBePlacedHere =
+    messageRecordUseCannotBePlacedHere;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageRecordUseCannotBePlacedHere = const MessageCode(
+  "RecordUseCannotBePlacedHere",
+  problemMessage:
+      r"""`RecordUse` annotation cannot be placed on this element.""",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeRecordUsedAsCallable = messageRecordUsedAsCallable;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -15226,28 +15202,6 @@
 );
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Null> codeResourceIdentifiersMultiple =
-    messageResourceIdentifiersMultiple;
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const MessageCode messageResourceIdentifiersMultiple = const MessageCode(
-  "ResourceIdentifiersMultiple",
-  problemMessage:
-      r"""Only one resource identifier pragma can be used at a time.""",
-);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Null> codeResourceIdentifiersNotStatic =
-    messageResourceIdentifiersNotStatic;
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const MessageCode messageResourceIdentifiersNotStatic = const MessageCode(
-  "ResourceIdentifiersNotStatic",
-  problemMessage:
-      r"""Resource identifier pragma can be used on a static method only.""",
-);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeRestPatternInMapPattern = messageRestPatternInMapPattern;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
index a0fea03..357780a 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
@@ -392,9 +392,18 @@
       Token? covariantToken,
       Token? varFinalOrConst,
       Token? getOrSet,
-      Token name) {
-    listener?.beginMethod(declarationKind, augmentToken, externalToken,
-        staticToken, covariantToken, varFinalOrConst, getOrSet, name);
+      Token name,
+      String? enclosingDeclarationName) {
+    listener?.beginMethod(
+        declarationKind,
+        augmentToken,
+        externalToken,
+        staticToken,
+        covariantToken,
+        varFinalOrConst,
+        getOrSet,
+        name,
+        enclosingDeclarationName);
   }
 
   @override
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
index d96dfe2..76af8f0 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
@@ -1183,7 +1183,8 @@
       Token? covariantToken,
       Token? varFinalOrConst,
       Token? getOrSet,
-      Token name) {}
+      Token name,
+      String? enclosingDeclarationName) {}
 
   /// Handle the end of a class method declaration.  Substructures:
   /// - metadata
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info.dart b/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info.dart
index 9c81f25..81d07d7 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import '../scanner/scanner.dart';
+import '../scanner/token.dart';
 import 'identifier_context.dart';
 import 'literal_entry_info_impl.dart';
 import 'parser_impl.dart';
@@ -56,14 +56,15 @@
 /// Compute the [LiteralEntryInfo] for the literal list, map, or set entry.
 LiteralEntryInfo computeLiteralEntry(Token token) {
   Token next = token.next!;
-  if (optional('if', next)) {
+  if (optional2(Keyword.IF, next)) {
     return ifCondition;
-  } else if (optional('for', next) ||
-      (optional('await', next) && optional('for', next.next!))) {
+  } else if (optional2(Keyword.FOR, next) ||
+      (optional2(Keyword.AWAIT, next) && optional2(Keyword.FOR, next.next!))) {
     return new ForCondition();
-  } else if (optional('...', next) || optional('...?', next)) {
+  } else if (optional2(TokenType.PERIOD_PERIOD_PERIOD, next) ||
+      optional2(TokenType.PERIOD_PERIOD_PERIOD_QUESTION, next)) {
     return spreadOperator;
-  } else if (optional('?', next)) {
+  } else if (optional2(TokenType.QUESTION, next)) {
     return nullAwareEntry;
   }
   return simpleEntry;
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info_impl.dart
index a8add65..dfe8876 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/literal_entry_info_impl.dart
@@ -254,6 +254,8 @@
       return new Nested(ifCondition, const IfElseComplete());
     } else if (optional('...', next) || optional('...?', next)) {
       return const ElseSpread();
+    } else if (optional('?', next)) {
+      return new Nested(nullAwareEntry, const IfElseComplete());
     }
     return const ElseEntry();
   }
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/parser.dart b/pkg/_fe_analyzer_shared/lib/src/parser/parser.dart
index 77584b2..6c591d6 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/parser.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser.dart
@@ -41,7 +41,7 @@
 
 export 'top_level_parser.dart' show TopLevelParser;
 
-export 'util.dart' show lengthForToken, lengthOfSpan, optional;
+export 'util.dart' show lengthForToken, lengthOfSpan, optional, optional2;
 
 class ErrorCollectingListener extends Listener {
   final List<ParserError> recoverableErrors = <ParserError>[];
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 4f37e6e..1f35033 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
@@ -129,7 +129,8 @@
         findPreviousNonZeroLengthToken,
         isOneOf,
         isOneOfOrEof,
-        optional;
+        optional,
+        optional2;
 
 /// An event generating parser of Dart programs. This parser expects all tokens
 /// in a linked list (aka a token stream).
@@ -1281,7 +1282,7 @@
   Token parseMetadataStar(Token token) {
     listener.beginMetadataStar(token.next!);
     int count = 0;
-    while (optional('@', token.next!)) {
+    while (optional2(TokenType.AT, token.next!)) {
       token = parseMetadata(token);
       count++;
     }
@@ -1334,10 +1335,10 @@
     token = ensureIdentifier(atToken, IdentifierContext.metadataReference);
     token =
         parseQualifiedRestOpt(token, IdentifierContext.metadataContinuation);
-    bool hasTypeArguments = optional("<", token.next!);
+    bool hasTypeArguments = optional2(TokenType.LT, token.next!);
     token = computeTypeParamOrArg(token).parseArguments(token, this);
     Token? period = null;
-    if (optional('.', token.next!)) {
+    if (optional2(TokenType.PERIOD, token.next!)) {
       period = token.next!;
       token = ensureIdentifier(
           period, IdentifierContext.metadataContinuationAfterTypeArguments);
@@ -1540,7 +1541,7 @@
   Token parseGetterOrFormalParameters(
       Token token, Token name, bool isGetter, MemberKind kind) {
     Token next = token.next!;
-    if (optional("(", next)) {
+    if (optional2(TokenType.OPEN_PAREN, next)) {
       if (isGetter) {
         reportRecoverableError(next, codes.messageGetterWithFormals);
       }
@@ -1781,7 +1782,7 @@
     int parameterCount = 0;
     while (true) {
       Token next = token.next!;
-      if (optional(')', next)) {
+      if (optional2(TokenType.CLOSE_PAREN, next)) {
         token = next;
         break;
       }
@@ -1805,7 +1806,7 @@
       token = parseFormalParameter(
           token, FormalParameterKind.requiredPositional, kind);
       next = token.next!;
-      if (!optional(',', next)) {
+      if (!optional2(TokenType.COMMA, next)) {
         Token next = token.next!;
         if (optional(')', next)) {
           token = next;
@@ -2043,7 +2044,7 @@
         IdentifierContext.formalParameterDeclaration;
 
     if (!inFunctionType &&
-        (optional('this', next) || optional('super', next))) {
+        (optional2(Keyword.THIS, next) || optional2(Keyword.SUPER, next))) {
       Token originalToken = token;
       if (optional('this', next)) {
         thisKeyword = token = next;
@@ -2083,7 +2084,7 @@
     }
     Token? beforeInlineFunctionType;
     TypeParamOrArgInfo typeParam = noTypeParamOrArg;
-    if (optional("<", next)) {
+    if (optional2(TokenType.LT, next)) {
       typeParam = computeTypeParamOrArg(token);
       if (typeParam != noTypeParamOrArg) {
         Token closer = typeParam.skip(token);
@@ -2097,7 +2098,7 @@
           next = token.next!;
         }
       }
-    } else if (optional("(", next)) {
+    } else if (optional2(TokenType.OPEN_PAREN, next)) {
       if (varFinalOrConst != null) {
         reportRecoverableError(
             varFinalOrConst, codes.messageFunctionTypedParameterVar);
@@ -2324,7 +2325,7 @@
   /// ```
   Token parseQualifiedRestOpt(
       Token token, IdentifierContext continuationContext) {
-    if (optional('.', token.next!)) {
+    if (optional2(TokenType.PERIOD, token.next!)) {
       return parseQualifiedRest(token, continuationContext);
     } else {
       return token;
@@ -3355,8 +3356,7 @@
   }
 
   bool notEofOrValue(String value, Token token) {
-    return !identical(token.kind, EOF_TOKEN) &&
-        !identical(value, token.stringValue);
+    return token.kind != EOF_TOKEN && value != token.stringValue;
   }
 
   Token parseTypeVariablesOpt(Token token) {
@@ -3974,7 +3974,7 @@
   }
 
   Token parseInitializersOpt(Token token) {
-    if (optional(':', token.next!)) {
+    if (optional2(TokenType.COLON, token.next!)) {
       return parseInitializers(token.next!);
     } else {
       listener.handleNoInitializers();
@@ -4278,7 +4278,7 @@
   /// Call `parseLiteralString` and return the result.
   Token ensureLiteralString(Token token) {
     Token next = token.next!;
-    if (!identical(next.kind, STRING_TOKEN)) {
+    if (next.kind != STRING_TOKEN) {
       codes.Message message = codes.templateExpectedString.withArguments(next);
       Token newToken = new SyntheticStringToken(
           TokenType.STRING, '""', next.charOffset, /* _length = */ 0);
@@ -4295,7 +4295,7 @@
     // to use this method, remove similar semicolon recovery code
     // from the handleError method in element_listener.dart.
     Token next = token.next!;
-    if (optional(';', next)) return next;
+    if (optional2(TokenType.SEMICOLON, next)) return next;
 
     // Find a token on the same line as where the ';' should be inserted.
     // Reporting the error on this token makes it easier
@@ -4831,8 +4831,8 @@
     if (getOrSet == null && optional('operator', name)) {
       Token operator = name.next!;
       if (operator.isOperator ||
-          identical(operator.kind, EQ_EQ_EQ_TOKEN) ||
-          identical(operator.kind, BANG_EQ_EQ_TOKEN) ||
+          operator.kind == EQ_EQ_EQ_TOKEN ||
+          operator.kind == BANG_EQ_EQ_TOKEN ||
           isUnaryMinus(operator)) {
         isOperator = true;
         if (optional(">>", operator) &&
@@ -4878,8 +4878,16 @@
 
     // TODO(danrubel): Consider parsing the name before calling beginMethod
     // rather than passing the name token into beginMethod.
-    listener.beginMethod(kind, augmentToken, externalToken, staticToken,
-        covariantToken, varFinalOrConst, getOrSet, name);
+    listener.beginMethod(
+        kind,
+        augmentToken,
+        externalToken,
+        staticToken,
+        covariantToken,
+        varFinalOrConst,
+        getOrSet,
+        name,
+        enclosingDeclarationName);
 
     Token token = typeInfo.parseType(beforeType, this);
     assert(token.next == (getOrSet ?? name) ||
@@ -5350,7 +5358,7 @@
     assert(!isExpression);
     token = skipAsyncModifier(token);
     Token next = token.next!;
-    if (optional('native', next)) {
+    if (optional2(Keyword.NATIVE, next)) {
       Token nativeToken = next;
       // TODO(danrubel): skip the native clause rather than parsing it
       // or remove this code completely when we remove support
@@ -5537,7 +5545,7 @@
     Token? star;
     asyncState = AsyncModifier.Sync;
     Token next = token.next!;
-    if (optional('async', next)) {
+    if (optional2(Keyword.ASYNC, next)) {
       async = token = next;
       next = token.next!;
       if (optional('*', next)) {
@@ -5547,7 +5555,7 @@
       } else {
         asyncState = AsyncModifier.Async;
       }
-    } else if (optional('sync', next)) {
+    } else if (optional2(Keyword.SYNC, next)) {
       async = token = next;
       next = token.next!;
       if (optional('*', next)) {
@@ -5579,7 +5587,7 @@
   }
 
   Token parseStatementX(Token token) {
-    if (identical(token.next!.kind, IDENTIFIER_TOKEN)) {
+    if (token.next!.kind == IDENTIFIER_TOKEN) {
       if (optional(':', token.next!.next!)) {
         return parseLabeledStatement(token);
       }
@@ -5820,7 +5828,7 @@
       if (allowPatterns && looksLikeOuterPatternEquals(token)) {
         token = parsePatternAssignment(token);
       } else {
-        token = optional('throw', token.next!)
+        token = optional2(Keyword.THROW, token.next!)
             ? parseThrowExpression(token, /* allowCascades = */ true)
             : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE,
                 /* allowCascades = */ true, ConstantPatternContext.none);
@@ -5884,7 +5892,7 @@
     assert(precedence <= SELECTOR_PRECEDENCE);
     token = parseUnaryExpression(token, allowCascades, constantPatternContext);
     Token bangToken = token;
-    if (optional('!', token.next!)) {
+    if (optional2(TokenType.BANG, token.next!)) {
       bangToken = token.next!;
     }
     TypeParamOrArgInfo typeArg = computeMethodTypeArguments(bangToken);
@@ -5965,10 +5973,10 @@
     for (int level = tokenLevel; level >= precedence; --level) {
       int lastBinaryExpressionLevel = -1;
       Token? lastCascade;
-      while (identical(tokenLevel, level)) {
+      while (tokenLevel == level) {
         enteredLoop = true;
         Token operator = next;
-        if (identical(tokenLevel, CASCADE_PRECEDENCE)) {
+        if (tokenLevel == CASCADE_PRECEDENCE) {
           if (!allowCascades) {
             return token;
           } else if (lastCascade != null && optional('?..', next)) {
@@ -5977,7 +5985,7 @@
           }
           lastCascade = next;
           token = parseCascadeExpression(token);
-        } else if (identical(tokenLevel, ASSIGNMENT_PRECEDENCE)) {
+        } else if (tokenLevel == ASSIGNMENT_PRECEDENCE) {
           // Right associative, so we recurse at the same precedence
           // level.
           Token next = token.next!;
@@ -5996,7 +6004,7 @@
               : parsePrecedenceExpression(
                   next, level, allowCascades, ConstantPatternContext.none);
           listener.handleAssignmentExpression(operator, token);
-        } else if (identical(tokenLevel, POSTFIX_PRECEDENCE)) {
+        } else if (tokenLevel == POSTFIX_PRECEDENCE) {
           if ((identical(type, TokenType.PLUS_PLUS)) ||
               (identical(type, TokenType.MINUS_MINUS))) {
             listener.handleUnaryPostfixAssignmentExpression(token.next!);
@@ -6005,7 +6013,7 @@
             listener.handleNonNullAssertExpression(next);
             token = next;
           }
-        } else if (identical(tokenLevel, SELECTOR_PRECEDENCE)) {
+        } else if (tokenLevel == SELECTOR_PRECEDENCE) {
           if (identical(type, TokenType.PERIOD) ||
               identical(type, TokenType.QUESTION_PERIOD)) {
             // Left associative, so we recurse at the next higher precedence
@@ -6020,7 +6028,7 @@
             listener.handleEndingBinaryExpression(operator, token);
 
             Token bangToken = token;
-            if (optional('!', token.next!)) {
+            if (optional2(TokenType.BANG, token.next!)) {
               bangToken = token.next!;
             }
             typeArg = computeMethodTypeArguments(bangToken);
@@ -6341,7 +6349,7 @@
       next = token.next!;
     } while (!identical(mark, token));
 
-    if (identical(next.type.precedence, ASSIGNMENT_PRECEDENCE)) {
+    if (next.type.precedence == ASSIGNMENT_PRECEDENCE) {
       Token assignment = next;
       token = parseExpressionWithoutCascade(next);
       listener.handleAssignmentExpression(assignment, token);
@@ -6417,12 +6425,12 @@
       return token;
     } else if (useImplicitCreationExpression && token.next!.isIdentifier) {
       Token identifier = token.next!;
-      if (optional(".", identifier.next!)) {
+      if (optional2(TokenType.PERIOD, identifier.next!)) {
         identifier = identifier.next!.next!;
       }
       if (identifier.isIdentifier) {
         // Looking at `identifier ('.' identifier)?`.
-        if (optional("<", identifier.next!)) {
+        if (optional2(TokenType.LT, identifier.next!)) {
           TypeParamOrArgInfo typeArg = computeTypeParamOrArg(identifier);
           if (typeArg != noTypeParamOrArg) {
             Token endTypeArguments = typeArg.skip(identifier);
@@ -6684,12 +6692,10 @@
     if (mayParseFunctionExpressions) {
       Token nextToken = next.endGroup!.next!;
       int kind = nextToken.kind;
-      if ((identical(kind, FUNCTION_TOKEN) ||
-          identical(kind, OPEN_CURLY_BRACKET_TOKEN))) {
+      if (kind == FUNCTION_TOKEN || kind == OPEN_CURLY_BRACKET_TOKEN) {
         listener.handleNoTypeVariables(next);
         return parseFunctionExpression(token);
-      } else if (identical(kind, KEYWORD_TOKEN) ||
-          identical(kind, IDENTIFIER_TOKEN)) {
+      } else if (kind == KEYWORD_TOKEN || kind == IDENTIFIER_TOKEN) {
         if (optional('async', nextToken) || optional('sync', nextToken)) {
           listener.handleNoTypeVariables(next);
           return parseFunctionExpression(token);
@@ -6699,8 +6705,7 @@
         // because the user is typing (e.g. `() asy {}`) then continue parsing
         // and allow parseFunctionExpression to report an unexpected token.
         kind = nextToken.next!.kind;
-        if ((identical(kind, FUNCTION_TOKEN) ||
-            identical(kind, OPEN_CURLY_BRACKET_TOKEN))) {
+        if (kind == FUNCTION_TOKEN || kind == OPEN_CURLY_BRACKET_TOKEN) {
           listener.handleNoTypeVariables(next);
           return parseFunctionExpression(token);
         }
@@ -7101,9 +7106,9 @@
     // Scanner ensures `(` has matching `)`.
     Token next = token.next!.endGroup!.next!;
     int kind = next.kind;
-    if (!identical(kind, FUNCTION_TOKEN) &&
-        !identical(kind, OPEN_CURLY_BRACKET_TOKEN) &&
-        (!identical(kind, KEYWORD_TOKEN) ||
+    if (kind != FUNCTION_TOKEN &&
+        kind != OPEN_CURLY_BRACKET_TOKEN &&
+        (kind != KEYWORD_TOKEN ||
             !optional('async', next) && !optional('sync', next))) {
       reportRecoverableErrorWithToken(next, codes.templateUnexpectedToken);
     }
@@ -7191,7 +7196,7 @@
     if (name.isIdentifier) {
       TypeParamOrArgInfo typeParam = computeTypeParamOrArg(name);
       Token next = typeParam.skip(name).next!;
-      if (optional('(', next)) {
+      if (optional2(TokenType.OPEN_PAREN, next)) {
         if (looksLikeFunctionBody(next.endGroup!.next!)) {
           return parseFunctionLiteral(
               token, beforeName, name, typeInfo, typeParam, context);
@@ -7499,7 +7504,7 @@
     mayParseFunctionExpressions = true;
     token = parseSingleLiteralString(token);
     int count = 1;
-    while (identical(token.next!.kind, STRING_TOKEN)) {
+    while (token.next!.kind == STRING_TOKEN) {
       token = parseSingleLiteralString(token);
       count++;
     }
@@ -7550,7 +7555,7 @@
     Token next = token.next!;
     int kind = next.kind;
     while (kind != EOF_TOKEN) {
-      if (identical(kind, STRING_INTERPOLATION_TOKEN)) {
+      if (kind == STRING_INTERPOLATION_TOKEN) {
         // Parsing ${expression}.
         token = parseExpression(next).next!;
         if (!optional('}', token)) {
@@ -7559,7 +7564,7 @@
           token = next.endGroup!;
         }
         listener.handleInterpolationExpression(next, token);
-      } else if (identical(kind, STRING_INTERPOLATION_IDENTIFIER_TOKEN)) {
+      } else if (kind == STRING_INTERPOLATION_IDENTIFIER_TOKEN) {
         // Parsing $identifier.
         token = parseIdentifierExpression(next);
         listener.handleInterpolationExpression(next, /* rightBracket = */ null);
@@ -7667,7 +7672,8 @@
     potentialTypeArg ??= computeTypeParamOrArg(token);
     afterToken ??= potentialTypeArg.skip(token).next!;
     TypeParamOrArgInfo typeArg;
-    if (optional('(', afterToken) && !potentialTypeArg.recovered) {
+    if (optional2(TokenType.OPEN_PAREN, afterToken) &&
+        !potentialTypeArg.recovered) {
       typeArg = potentialTypeArg;
     } else {
       typeArg = noTypeParamOrArg;
@@ -7711,7 +7717,7 @@
   /// https://github.com/dart-lang/language/blob/master/accepted/future-releases/records/records-feature-specification.md#ambiguity-with-metadata-annotations
   Token parseArgumentsOptMetadata(Token token, bool hasTypeArguments) {
     final Token next = token.next!;
-    if (!optional('(', next)) {
+    if (!optional2(TokenType.OPEN_PAREN, next)) {
       listener.handleNoArguments(next);
       return token;
     } else if (token.charEnd == next.charOffset) {
@@ -7747,7 +7753,7 @@
 
   Token parseArgumentsOpt(Token token) {
     Token next = token.next!;
-    if (!optional('(', next)) {
+    if (!optional2(TokenType.OPEN_PAREN, next)) {
       listener.handleNoArguments(next);
       return token;
     } else {
@@ -7783,12 +7789,13 @@
     mayParseFunctionExpressions = true;
     while (true) {
       Token next = token.next!;
-      if (optional(')', next)) {
+      if (optional2(TokenType.CLOSE_PAREN, next)) {
         token = next;
         break;
       }
       Token? colon = null;
-      if (optional(':', next.next!) || /* recovery */ optional(':', next)) {
+      if (optional2(TokenType.COLON, next.next!) || /* recovery */
+          optional2(TokenType.COLON, next)) {
         token =
             ensureIdentifier(token, IdentifierContext.namedArgumentReference)
                 .next!;
@@ -7798,8 +7805,8 @@
       next = token.next!;
       if (colon != null) listener.handleNamedArgument(colon);
       ++argumentCount;
-      if (!optional(',', next)) {
-        if (optional(')', next)) {
+      if (!optional2(TokenType.COMMA, next)) {
+        if (optional2(TokenType.CLOSE_PAREN, next)) {
           token = next;
           break;
         }
@@ -7928,7 +7935,7 @@
   /// without a return type.
   bool looksLikeLocalFunction(Token token) {
     if (token.isIdentifier) {
-      if (optional('<', token.next!)) {
+      if (optional2(TokenType.LT, token.next!)) {
         TypeParamOrArgInfo typeParam = computeTypeParamOrArg(token);
         if (typeParam == noTypeParamOrArg) {
           return false;
@@ -7936,7 +7943,7 @@
         token = typeParam.skip(token);
       }
       token = token.next!;
-      if (optional('(', token)) {
+      if (optional2(TokenType.OPEN_PAREN, token)) {
         token = token.endGroup!.next!;
         return optional('{', token) ||
             optional('=>', token) ||
@@ -7952,10 +7959,10 @@
 
   /// Returns true if [token] could be the start of a function body.
   bool looksLikeFunctionBody(Token token) {
-    return optional('{', token) ||
-        optional('=>', token) ||
-        optional('async', token) ||
-        optional('sync', token);
+    return optional2(TokenType.OPEN_CURLY_BRACKET, token) ||
+        optional2(TokenType.FUNCTION, token) ||
+        optional2(Keyword.ASYNC, token) ||
+        optional2(Keyword.SYNC, token);
   }
 
   Token parseExpressionStatementOrConstDeclaration(final Token start) {
@@ -9069,7 +9076,7 @@
     listener.beginSwitchCase(labelCount, expressionCount, begin);
     // Finally zero or more statements.
     int statementCount = 0;
-    while (!identical(token.next!.kind, EOF_TOKEN)) {
+    while (token.next!.kind != EOF_TOKEN) {
       String? value = peek.stringValue;
       if ((identical(value, 'case')) ||
           (identical(value, 'default')) ||
@@ -10252,7 +10259,7 @@
   bool looksLikeOuterPatternEquals(Token token) {
     Token? afterOuterPattern = skipOuterPattern(token);
     if (afterOuterPattern == null) return false;
-    return optional('=', afterOuterPattern.next!);
+    return optional2(TokenType.EQ, afterOuterPattern.next!);
   }
 
   /// Tries to advance beyond an "outer pattern" starting from [token].  If the
@@ -10268,7 +10275,7 @@
     if (next.isIdentifier) {
       token = next;
       next = token.next!;
-      if (!optional('.', next)) {
+      if (!optional2(TokenType.PERIOD, next)) {
         return skipObjectPatternRest(token);
       }
       token = next;
@@ -10283,15 +10290,17 @@
     TypeParamOrArgInfo typeParamOrArg = computeTypeParamOrArg(token);
     token = typeParamOrArg.skip(token);
     next = token.next!;
-    if (optional('[]', next)) {
+    if (optional2(TokenType.INDEX, next)) {
       // Empty list pattern
       return next;
     }
-    if (optional('[', next) || optional('{', next)) {
+    if (optional2(TokenType.OPEN_SQUARE_BRACKET, next) ||
+        optional2(TokenType.OPEN_CURLY_BRACKET, next)) {
       // List or map pattern
       return next.endGroup;
     }
-    if (typeParamOrArg == noTypeParamOrArg && optional('(', next)) {
+    if (typeParamOrArg == noTypeParamOrArg &&
+        optional2(TokenType.OPEN_PAREN, next)) {
       // Record or parenthesized pattern
       return next.endGroup;
     }
@@ -10309,7 +10318,7 @@
     token = typeParamOrArg.skip(token);
     Token? next = token.next;
     if (next == null) return null;
-    if (!optional('(', next)) return null;
+    if (!optional2(TokenType.OPEN_PAREN, next)) return null;
     return next.endGroup;
   }
 
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 241b1ef..f03aa12 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart
@@ -4,7 +4,7 @@
 
 library _fe_analyzer_shared.parser.type_info;
 
-import '../scanner/token.dart' show Token, TokenType;
+import '../scanner/token.dart' show Keyword, Token, TokenType;
 
 import '../scanner/token_constants.dart' show IDENTIFIER_TOKEN, KEYWORD_TOKEN;
 
@@ -14,7 +14,7 @@
 
 import 'type_info_impl.dart';
 
-import 'util.dart' show isOneOf, optional;
+import 'util.dart' show isOneOf, optional, optional2;
 
 /// [TypeInfo] provides information collected by [computeType]
 /// about a particular type reference.
@@ -125,12 +125,13 @@
 const TypeInfo voidType = const VoidType();
 
 bool isGeneralizedFunctionType(Token token) {
-  return optional('Function', token) &&
-      (optional('<', token.next!) || optional('(', token.next!));
+  return optional2(Keyword.FUNCTION, token) &&
+      (optional2(TokenType.LT, token.next!) ||
+          optional2(TokenType.OPEN_PAREN, token.next!));
 }
 
 bool isPossibleRecordType(Token token) {
-  return optional('(', token) &&
+  return optional2(TokenType.OPEN_PAREN, token) &&
       token.endGroup != null &&
       !token.endGroup!.isSynthetic;
 }
@@ -202,7 +203,7 @@
     return noType;
   }
 
-  if (optional('void', next)) {
+  if (optional2(Keyword.VOID, next)) {
     next = next.next!;
     if (isGeneralizedFunctionType(next)) {
       // `void` `Function` ...
@@ -244,7 +245,7 @@
     if (typeParamOrArg.isSimpleTypeArgument) {
       // We've seen identifier `<` identifier `>`
       next = typeParamOrArg.skip(next).next!;
-      if (optional('?', next)) {
+      if (optional2(TokenType.QUESTION, next)) {
         next = next.next!;
         if (!isGeneralizedFunctionType(next)) {
           if ((required || looksLikeName(next)) &&
@@ -276,14 +277,14 @@
   assert(typeParamOrArg == noTypeParamOrArg);
   next = next.next!;
 
-  if (optional('.', next)) {
+  if (optional2(TokenType.PERIOD, next)) {
     next = next.next!;
     if (isValidNonRecordTypeReference(next)) {
       // We've seen identifier `.` identifier
       typeParamOrArg = computeTypeParamOrArg(next, inDeclaration);
       next = next.next!;
       if (typeParamOrArg == noTypeParamOrArg) {
-        if (optional('?', next)) {
+        if (optional2(TokenType.QUESTION, next)) {
           next = next.next!;
           if (!isGeneralizedFunctionType(next)) {
             if (required || looksLikeName(next)) {
@@ -327,7 +328,7 @@
         .computeIdentifierGFT(required);
   }
 
-  if (optional('?', next)) {
+  if (optional2(TokenType.QUESTION, next)) {
     next = next.next!;
     if (isGeneralizedFunctionType(next)) {
       // identifier `?` Function `(`
@@ -383,7 +384,7 @@
 TypeParamOrArgInfo computeTypeParamOrArg(Token token,
     [bool inDeclaration = false, bool allowsVariance = false]) {
   Token beginGroup = token.next!;
-  if (!optional('<', beginGroup)) {
+  if (!optional2(TokenType.LT, beginGroup)) {
     return noTypeParamOrArg;
   }
 
@@ -391,11 +392,11 @@
   // are handled by ComplexTypeInfo.
   Token next = beginGroup.next!;
   if ((next.kind == IDENTIFIER_TOKEN || next.type.isPseudo)) {
-    if (optional('>', next.next!)) {
+    if (optional2(TokenType.GT, next.next!)) {
       return simpleTypeArgument1;
-    } else if (optional('>>', next.next!)) {
+    } else if (optional2(TokenType.GT_GT, next.next!)) {
       return simpleTypeArgument1GtGt;
-    } else if (optional('>=', next.next!)) {
+    } else if (optional2(TokenType.GT_EQ, next.next!)) {
       return simpleTypeArgument1GtEq;
     }
   } else if (optional('(', next)) {
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 a144e6e..2762236 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
@@ -6,7 +6,7 @@
 
 import '../messages/codes.dart' as codes;
 
-import '../scanner/token.dart' show SyntheticToken, Token, TokenType;
+import '../scanner/token.dart' show Keyword, SyntheticToken, Token, TokenType;
 
 import '../scanner/token_constants.dart' show IDENTIFIER_TOKEN;
 
@@ -28,6 +28,7 @@
     show
         isOneOfOrEof,
         optional,
+        optional2,
         skipMetadata,
         splitGtEq,
         splitGtFromGtGtEq,
@@ -484,8 +485,8 @@
 
 bool looksLikeName(Token token) {
   return token.kind == IDENTIFIER_TOKEN ||
-      optional('this', token) ||
-      optional('super', token) ||
+      optional2(Keyword.THIS, token) ||
+      optional2(Keyword.SUPER, token) ||
       (token.isIdentifier &&
           // Although `typedef` is a legal identifier,
           // type `typedef` identifier is not legal and in this situation
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/util.dart b/pkg/_fe_analyzer_shared/lib/src/parser/util.dart
index 2eb8e4d..acd6b89 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/util.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/util.dart
@@ -13,6 +13,12 @@
 import '../scanner/token.dart'
     show BeginToken, SimpleToken, SyntheticToken, TokenType;
 
+/// Returns true if [token] has the token type [value].
+@pragma("vm:prefer-inline")
+bool optional2(TokenType value, Token token) {
+  return value.index == token.typeIndex;
+}
+
 /// Returns true if [token] is the symbol or keyword [value].
 bool optional(String value, Token token) {
   return identical(value, token.stringValue);
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart
index f44f6af..ce86e42 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart
@@ -146,7 +146,7 @@
 
   AbstractScanner(ScannerConfiguration? config, this.includeComments,
       this.languageVersionChanged,
-      {int? numberOfBytesHint, this.allowLazyStrings = true})
+      {required int numberOfBytesHint, this.allowLazyStrings = true})
       : lineStarts = new LineStarts(numberOfBytesHint),
         inRecoveryOption = false {
     this.tail = this.tokens;
@@ -252,6 +252,7 @@
   /**
    * Notifies that a new token starts at current offset.
    */
+  @pragma("vm:prefer-inline")
   void beginToken() {
     tokenStart = stringOffset;
   }
@@ -324,7 +325,7 @@
    */
   int select(int choice, TokenType yes, TokenType no) {
     int next = advance();
-    if (identical(next, choice)) {
+    if (next == choice) {
       appendPrecedenceToken(yes);
       return advance();
     } else {
@@ -387,8 +388,7 @@
     appendToken(token);
 
     // { [ ${ cannot appear inside a type parameters / arguments.
-    if (!identical(type.kind, LT_TOKEN) &&
-        !identical(type.kind, OPEN_PAREN_TOKEN)) {
+    if (type.kind != LT_TOKEN && type.kind != OPEN_PAREN_TOKEN) {
       discardOpenLt();
     }
     groupingStack = groupingStack.prepend(token);
@@ -401,7 +401,7 @@
    * and [appendGtGtGt].
    */
   int appendEndGroup(TokenType type, int openKind) {
-    assert(!identical(openKind, LT_TOKEN)); // openKind is < for > and >>
+    assert(openKind != LT_TOKEN); // openKind is < for > and >>
     bool foundMatchingBrace = discardBeginGroupUntil(openKind);
     return appendEndGroupInternal(foundMatchingBrace, type, openKind);
   }
@@ -421,7 +421,7 @@
     appendPrecedenceToken(type);
     Token close = tail;
     BeginToken begin = groupingStack.head;
-    if (!identical(begin.kind, openKind)) {
+    if (begin.kind != openKind) {
       assert(begin.kind == STRING_INTERPOLATION_TOKEN &&
           openKind == OPEN_CURLY_BRACKET_TOKEN);
       // We're ending an interpolated expression.
@@ -444,7 +444,7 @@
   void appendGt(TokenType type) {
     appendPrecedenceToken(type);
     if (groupingStack.isEmpty) return;
-    if (identical(groupingStack.head.kind, LT_TOKEN)) {
+    if (groupingStack.head.kind == LT_TOKEN) {
       groupingStack.head.endGroup = tail;
       groupingStack = groupingStack.tail!;
     }
@@ -458,13 +458,13 @@
   void appendGtGt(TokenType type) {
     appendPrecedenceToken(type);
     if (groupingStack.isEmpty) return;
-    if (identical(groupingStack.head.kind, LT_TOKEN)) {
+    if (groupingStack.head.kind == LT_TOKEN) {
       // Don't assign endGroup: in "T<U<V>>", the '>>' token closes the outer
       // '<', the inner '<' is left without endGroup.
       groupingStack = groupingStack.tail!;
     }
     if (groupingStack.isEmpty) return;
-    if (identical(groupingStack.head.kind, LT_TOKEN)) {
+    if (groupingStack.head.kind == LT_TOKEN) {
       groupingStack.head.endGroup = tail;
       groupingStack = groupingStack.tail!;
     }
@@ -480,15 +480,15 @@
 
     // Don't assign endGroup: in "T<U<V<X>>>", the '>>>' token closes the
     // outer '<', all the inner '<' are left without endGroups.
-    if (identical(groupingStack.head.kind, LT_TOKEN)) {
+    if (groupingStack.head.kind == LT_TOKEN) {
       groupingStack = groupingStack.tail!;
     }
     if (groupingStack.isEmpty) return;
-    if (identical(groupingStack.head.kind, LT_TOKEN)) {
+    if (groupingStack.head.kind == LT_TOKEN) {
       groupingStack = groupingStack.tail!;
     }
     if (groupingStack.isEmpty) return;
-    if (identical(groupingStack.head.kind, LT_TOKEN)) {
+    if (groupingStack.head.kind == LT_TOKEN) {
       groupingStack.head.endGroup = tail;
       groupingStack = groupingStack.tail!;
     }
@@ -655,7 +655,7 @@
     // This recovers nicely from situations like "{[}".
     while (!identical(originalStack, entryToUse)) {
       // Don't report unmatched errors for <; it is also the less-than operator.
-      if (!identical(entryToUse.head.kind, LT_TOKEN)) {
+      if (entryToUse.head.kind != LT_TOKEN) {
         unmatchedBeginGroup(originalStack.head);
       }
       originalStack = originalStack.tail!;
@@ -674,8 +674,7 @@
    * list, like the '=' in the above example.
    */
   void discardOpenLt() {
-    while (!groupingStack.isEmpty &&
-        identical(groupingStack.head.kind, LT_TOKEN)) {
+    while (!groupingStack.isEmpty && groupingStack.head.kind == LT_TOKEN) {
       groupingStack = groupingStack.tail!;
     }
   }
@@ -691,7 +690,7 @@
       BeginToken beginToken = groupingStack.head;
       unmatchedBeginGroup(beginToken);
       groupingStack = groupingStack.tail!;
-      if (identical(beginToken.kind, STRING_INTERPOLATION_TOKEN)) break;
+      if (beginToken.kind == STRING_INTERPOLATION_TOKEN) break;
     }
   }
 
@@ -756,20 +755,20 @@
       int next = advance();
 
       // Scan the header looking for a language version
-      if (!identical(next, $EOF)) {
+      if (next != $EOF) {
         Token oldTail = tail;
         next = bigHeaderSwitch(next);
-        if (!identical(next, $EOF) && tail.kind == SCRIPT_TOKEN) {
+        if (next != $EOF && tail.kind == SCRIPT_TOKEN) {
           oldTail = tail;
           next = bigHeaderSwitch(next);
         }
-        while (!identical(next, $EOF) && tail == oldTail) {
+        while (next != $EOF && tail == oldTail) {
           next = bigHeaderSwitch(next);
         }
         next = next;
       }
 
-      while (!identical(next, $EOF)) {
+      while (next != $EOF) {
         next = bigSwitch(next);
       }
       if (atEndOfFile()) {
@@ -791,7 +790,7 @@
   int recoveryOptionTokenizer(int next) {
     int iterations = 0;
     while (!atEndOfFile()) {
-      while (!identical(next, $EOF)) {
+      while (next != $EOF) {
         // TODO(jensj): Look at number of lines, tokens, parenthesis stack,
         // semi-colon etc, not just number of iterations.
         next = bigSwitch(next);
@@ -815,11 +814,11 @@
   }
 
   int bigHeaderSwitch(int next) {
-    if (!identical(next, $SLASH)) {
+    if (next != $SLASH) {
       return bigSwitch(next);
     }
     beginToken();
-    if (!identical($SLASH, peek())) {
+    if ($SLASH != peek()) {
       return tokenizeSlashOrComment(next);
     }
     return tokenizeLanguageVersionOrSingleLineComment(next);
@@ -827,14 +826,11 @@
 
   int bigSwitch(int next) {
     beginToken();
-    if (identical(next, $SPACE) ||
-        identical(next, $TAB) ||
-        identical(next, $LF) ||
-        identical(next, $CR)) {
+    if (next == $SPACE || next == $TAB || next == $LF || next == $CR) {
       appendWhiteSpace(next);
       next = advance();
       // Sequences of spaces are common, so advance through them fast.
-      while (identical(next, $SPACE)) {
+      while (next == $SPACE) {
         // We don't invoke [:appendWhiteSpace(next):] here for efficiency,
         // assuming that it does not do anything for space characters.
         next = advance();
@@ -845,90 +841,90 @@
     int nextLower = next | 0x20;
 
     if ($a <= nextLower && nextLower <= $z) {
-      if (identical($r, next)) {
+      if ($r == next) {
         return tokenizeRawStringKeywordOrIdentifier(next);
       }
       return tokenizeKeywordOrIdentifier(next, /* allowDollar = */ true);
     }
 
-    if (identical(next, $CLOSE_PAREN)) {
+    if (next == $CLOSE_PAREN) {
       return appendEndGroup(TokenType.CLOSE_PAREN, OPEN_PAREN_TOKEN);
     }
 
-    if (identical(next, $OPEN_PAREN)) {
+    if (next == $OPEN_PAREN) {
       appendBeginGroup(TokenType.OPEN_PAREN);
       return advance();
     }
 
-    if (identical(next, $SEMICOLON)) {
+    if (next == $SEMICOLON) {
       appendPrecedenceToken(TokenType.SEMICOLON);
       // Type parameters and arguments cannot contain semicolon.
       discardOpenLt();
       return advance();
     }
 
-    if (identical(next, $PERIOD)) {
+    if (next == $PERIOD) {
       return tokenizeDotsOrNumber(next);
     }
 
-    if (identical(next, $COMMA)) {
+    if (next == $COMMA) {
       appendPrecedenceToken(TokenType.COMMA);
       return advance();
     }
 
-    if (identical(next, $EQ)) {
+    if (next == $EQ) {
       return tokenizeEquals(next);
     }
 
-    if (identical(next, $CLOSE_CURLY_BRACKET)) {
+    if (next == $CLOSE_CURLY_BRACKET) {
       return appendEndGroup(
           TokenType.CLOSE_CURLY_BRACKET, OPEN_CURLY_BRACKET_TOKEN);
     }
 
-    if (identical(next, $SLASH)) {
+    if (next == $SLASH) {
       return tokenizeSlashOrComment(next);
     }
 
-    if (identical(next, $OPEN_CURLY_BRACKET)) {
+    if (next == $OPEN_CURLY_BRACKET) {
       appendBeginGroup(TokenType.OPEN_CURLY_BRACKET);
       return advance();
     }
 
-    if (identical(next, $DQ) || identical(next, $SQ)) {
+    if (next == $DQ || next == $SQ) {
       return tokenizeString(next, scanOffset, /* raw = */ false);
     }
 
-    if (identical(next, $_)) {
+    if (next == $_) {
       return tokenizeKeywordOrIdentifier(next, /* allowDollar = */ true);
     }
 
-    if (identical(next, $COLON)) {
+    if (next == $COLON) {
       appendPrecedenceToken(TokenType.COLON);
       return advance();
     }
 
-    if (identical(next, $LT)) {
+    if (next == $LT) {
       return tokenizeLessThan(next);
     }
 
-    if (identical(next, $GT)) {
+    if (next == $GT) {
       return tokenizeGreaterThan(next);
     }
 
-    if (identical(next, $BANG)) {
+    if (next == $BANG) {
       return tokenizeExclamation(next);
     }
 
-    if (identical(next, $OPEN_SQUARE_BRACKET)) {
+    if (next == $OPEN_SQUARE_BRACKET) {
       return tokenizeOpenSquareBracket(next);
     }
 
-    if (identical(next, $CLOSE_SQUARE_BRACKET)) {
+    if (next == $CLOSE_SQUARE_BRACKET) {
       return appendEndGroup(
           TokenType.CLOSE_SQUARE_BRACKET, OPEN_SQUARE_BRACKET_TOKEN);
     }
 
-    if (identical(next, $AT)) {
+    if (next == $AT) {
       return tokenizeAt(next);
     }
 
@@ -936,61 +932,61 @@
       return tokenizeNumber(next);
     }
 
-    if (identical(next, $AMPERSAND)) {
+    if (next == $AMPERSAND) {
       return tokenizeAmpersand(next);
     }
 
-    if (identical(next, $0)) {
+    if (next == $0) {
       return tokenizeHexOrNumber(next);
     }
 
-    if (identical(next, $QUESTION)) {
+    if (next == $QUESTION) {
       return tokenizeQuestion(next);
     }
 
-    if (identical(next, $BAR)) {
+    if (next == $BAR) {
       return tokenizeBar(next);
     }
 
-    if (identical(next, $PLUS)) {
+    if (next == $PLUS) {
       return tokenizePlus(next);
     }
 
-    if (identical(next, $$)) {
+    if (next == $$) {
       return tokenizeKeywordOrIdentifier(next, /* allowDollar = */ true);
     }
 
-    if (identical(next, $MINUS)) {
+    if (next == $MINUS) {
       return tokenizeMinus(next);
     }
 
-    if (identical(next, $STAR)) {
+    if (next == $STAR) {
       return tokenizeMultiply(next);
     }
 
-    if (identical(next, $CARET)) {
+    if (next == $CARET) {
       return tokenizeCaret(next);
     }
 
-    if (identical(next, $TILDE)) {
+    if (next == $TILDE) {
       return tokenizeTilde(next);
     }
 
-    if (identical(next, $PERCENT)) {
+    if (next == $PERCENT) {
       return tokenizePercent(next);
     }
 
-    if (identical(next, $BACKPING)) {
+    if (next == $BACKPING) {
       appendPrecedenceToken(TokenType.BACKPING);
       return advance();
     }
 
-    if (identical(next, $BACKSLASH)) {
+    if (next == $BACKSLASH) {
       appendPrecedenceToken(TokenType.BACKSLASH);
       return advance();
     }
 
-    if (identical(next, $HASH)) {
+    if (next == $HASH) {
       return tokenizeTag(next);
     }
 
@@ -1006,15 +1002,13 @@
   int tokenizeTag(int next) {
     // # or #!.*[\n\r]
     if (scanOffset == 0) {
-      if (identical(peek(), $BANG)) {
+      if (peek() == $BANG) {
         int start = scanOffset;
         bool asciiOnly = true;
         do {
           next = advance();
           if (next > 127) asciiOnly = false;
-        } while (!identical(next, $LF) &&
-            !identical(next, $CR) &&
-            !identical(next, $EOF));
+        } while (next != $LF && next != $CR && next != $EOF);
         if (!asciiOnly) handleUnicode(start);
         appendSubstringToken(TokenType.SCRIPT_TAG, start, asciiOnly);
         return next;
@@ -1027,7 +1021,7 @@
   int tokenizeTilde(int next) {
     // ~ ~/ ~/=
     next = advance();
-    if (identical(next, $SLASH)) {
+    if (next == $SLASH) {
       return select($EQ, TokenType.TILDE_SLASH_EQ, TokenType.TILDE_SLASH);
     } else {
       appendPrecedenceToken(TokenType.TILDE);
@@ -1038,7 +1032,7 @@
   int tokenizeOpenSquareBracket(int next) {
     // [ [] []=
     next = advance();
-    if (identical(next, $CLOSE_SQUARE_BRACKET)) {
+    if (next == $CLOSE_SQUARE_BRACKET) {
       return select($EQ, TokenType.INDEX_EQ, TokenType.INDEX);
     }
     appendBeginGroup(TokenType.OPEN_SQUARE_BRACKET);
@@ -1053,13 +1047,13 @@
   int tokenizeQuestion(int next) {
     // ? ?. ?.. ?? ??=
     next = advance();
-    if (identical(next, $QUESTION)) {
+    if (next == $QUESTION) {
       return select(
           $EQ, TokenType.QUESTION_QUESTION_EQ, TokenType.QUESTION_QUESTION);
-    } else if (identical(next, $PERIOD)) {
+    } else if (next == $PERIOD) {
       next = advance();
       if (_enableNonNullable) {
-        if (identical($PERIOD, next)) {
+        if ($PERIOD == next) {
           appendPrecedenceToken(TokenType.QUESTION_PERIOD_PERIOD);
           return advance();
         }
@@ -1075,15 +1069,15 @@
   int tokenizeBar(int next) {
     // | || |= ||=
     next = advance();
-    if (identical(next, $BAR)) {
+    if (next == $BAR) {
       next = advance();
-      if (LAZY_ASSIGNMENT_ENABLED && identical(next, $EQ)) {
+      if (LAZY_ASSIGNMENT_ENABLED && next == $EQ) {
         appendPrecedenceToken(TokenType.BAR_BAR_EQ);
         return advance();
       }
       appendPrecedenceToken(TokenType.BAR_BAR);
       return next;
-    } else if (identical(next, $EQ)) {
+    } else if (next == $EQ) {
       appendPrecedenceToken(TokenType.BAR_EQ);
       return advance();
     } else {
@@ -1095,15 +1089,15 @@
   int tokenizeAmpersand(int next) {
     // && &= & &&=
     next = advance();
-    if (identical(next, $AMPERSAND)) {
+    if (next == $AMPERSAND) {
       next = advance();
-      if (LAZY_ASSIGNMENT_ENABLED && identical(next, $EQ)) {
+      if (LAZY_ASSIGNMENT_ENABLED && next == $EQ) {
         appendPrecedenceToken(TokenType.AMPERSAND_AMPERSAND_EQ);
         return advance();
       }
       appendPrecedenceToken(TokenType.AMPERSAND_AMPERSAND);
       return next;
-    } else if (identical(next, $EQ)) {
+    } else if (next == $EQ) {
       appendPrecedenceToken(TokenType.AMPERSAND_EQ);
       return advance();
     } else {
@@ -1125,10 +1119,10 @@
   int tokenizeMinus(int next) {
     // - -- -=
     next = advance();
-    if (identical(next, $MINUS)) {
+    if (next == $MINUS) {
       appendPrecedenceToken(TokenType.MINUS_MINUS);
       return advance();
-    } else if (identical(next, $EQ)) {
+    } else if (next == $EQ) {
       appendPrecedenceToken(TokenType.MINUS_EQ);
       return advance();
     } else {
@@ -1140,10 +1134,10 @@
   int tokenizePlus(int next) {
     // + ++ +=
     next = advance();
-    if (identical($PLUS, next)) {
+    if ($PLUS == next) {
       appendPrecedenceToken(TokenType.PLUS_PLUS);
       return advance();
-    } else if (identical($EQ, next)) {
+    } else if ($EQ == next) {
       appendPrecedenceToken(TokenType.PLUS_EQ);
       return advance();
     } else {
@@ -1157,10 +1151,10 @@
     // !== is kept for user-friendly error reporting.
 
     next = advance();
-    if (identical(next, $EQ)) {
+    if (next == $EQ) {
       //was `return select($EQ, TokenType.BANG_EQ_EQ, TokenType.BANG_EQ);`
       int next = advance();
-      if (identical(next, $EQ)) {
+      if (next == $EQ) {
         appendPrecedenceToken(TokenType.BANG_EQ_EQ);
         prependErrorToken(new UnsupportedOperator(tail, tokenStart));
         return advance();
@@ -1182,10 +1176,10 @@
     discardOpenLt();
 
     next = advance();
-    if (identical(next, $EQ)) {
+    if (next == $EQ) {
       // was `return select($EQ, TokenType.EQ_EQ_EQ, TokenType.EQ_EQ);`
       int next = advance();
-      if (identical(next, $EQ)) {
+      if (next == $EQ) {
         appendPrecedenceToken(TokenType.EQ_EQ_EQ);
         prependErrorToken(new UnsupportedOperator(tail, tokenStart));
         return advance();
@@ -1193,7 +1187,7 @@
         appendPrecedenceToken(TokenType.EQ_EQ);
         return next;
       }
-    } else if (identical(next, $GT)) {
+    } else if (next == $GT) {
       appendPrecedenceToken(TokenType.FUNCTION);
       return advance();
     }
@@ -1204,21 +1198,21 @@
   int tokenizeGreaterThan(int next) {
     // > >= >> >>= >>> >>>=
     next = advance();
-    if (identical($EQ, next)) {
+    if ($EQ == next) {
       // Saw `>=` only.
       appendPrecedenceToken(TokenType.GT_EQ);
       return advance();
-    } else if (identical($GT, next)) {
+    } else if ($GT == next) {
       // Saw `>>` so far.
       next = advance();
-      if (identical($EQ, next)) {
+      if ($EQ == next) {
         // Saw `>>=` only.
         appendPrecedenceToken(TokenType.GT_GT_EQ);
         return advance();
-      } else if (_enableTripleShift && identical($GT, next)) {
+      } else if (_enableTripleShift && $GT == next) {
         // Saw `>>>` so far.
         next = advance();
-        if (identical($EQ, next)) {
+        if ($EQ == next) {
           // Saw `>>>=` only.
           appendPrecedenceToken(TokenType.GT_GT_GT_EQ);
           return advance();
@@ -1242,10 +1236,10 @@
   int tokenizeLessThan(int next) {
     // < <= << <<=
     next = advance();
-    if (identical($EQ, next)) {
+    if ($EQ == next) {
       appendPrecedenceToken(TokenType.LT_EQ);
       return advance();
-    } else if (identical($LT, next)) {
+    } else if ($LT == next) {
       return select($EQ, TokenType.LT_LT_EQ, TokenType.LT_LT);
     } else {
       appendBeginGroup(TokenType.LT);
@@ -1262,11 +1256,11 @@
       if ($0 <= next && next <= $9) {
         previousWasSeparator = false;
         continue;
-      } else if (identical(next, $_)) {
+      } else if (next == $_) {
         hasSeparators = true;
         previousWasSeparator = true;
         continue;
-      } else if (identical(next, $e) || identical(next, $E)) {
+      } else if (next == $e || next == $E) {
         if (previousWasSeparator) {
           // Not allowed.
           prependErrorToken(new UnterminatedToken(
@@ -1274,7 +1268,7 @@
         }
         return tokenizeFractionPart(next, start, hasSeparators);
       } else {
-        if (identical(next, $PERIOD)) {
+        if (next == $PERIOD) {
           if (previousWasSeparator) {
             // Not allowed.
             prependErrorToken(new UnterminatedToken(
@@ -1305,7 +1299,7 @@
 
   int tokenizeHexOrNumber(int next) {
     int x = peek();
-    if (identical(x, $x) || identical(x, $X)) {
+    if (x == $x || x == $X) {
       return tokenizeHex(next);
     }
     return tokenizeNumber(next);
@@ -1324,7 +1318,7 @@
           ($a <= next && next <= $f)) {
         hasDigits = true;
         previousWasSeparator = false;
-      } else if (identical(next, $_)) {
+      } else if (next == $_) {
         if (!hasDigits) {
           // Not allowed.
           prependErrorToken(new UnterminatedToken(
@@ -1360,11 +1354,11 @@
     next = advance();
     if (($0 <= next && next <= $9)) {
       return tokenizeFractionPart(next, start, /* hasSeparators = */ false);
-    } else if (identical($PERIOD, next)) {
+    } else if ($PERIOD == next) {
       next = advance();
-      if (identical(next, $PERIOD)) {
+      if (next == $PERIOD) {
         next = advance();
-        if (identical(next, $QUESTION)) {
+        if (next == $QUESTION) {
           appendPrecedenceToken(TokenType.PERIOD_PERIOD_PERIOD_QUESTION);
           return advance();
         } else {
@@ -1390,14 +1384,14 @@
       if ($0 <= next && next <= $9) {
         hasDigit = true;
         previousWasSeparator = false;
-      } else if (identical($_, next)) {
+      } else if ($_ == next) {
         if (!hasDigit) {
           prependErrorToken(new UnterminatedToken(
               messageUnexpectedSeparatorInNumber, start, stringOffset));
         }
         hasSeparators = true;
         previousWasSeparator = true;
-      } else if (identical($e, next) || identical($E, next)) {
+      } else if ($e == next || $E == next) {
         if (previousWasSeparator) {
           // Not allowed.
           prependErrorToken(new UnterminatedToken(
@@ -1406,14 +1400,14 @@
         hasDigit = true;
         previousWasSeparator = false;
         next = advance();
-        while (identical(next, $_)) {
+        while (next == $_) {
           prependErrorToken(new UnterminatedToken(
               messageUnexpectedSeparatorInNumber, start, stringOffset));
           hasSeparators = true;
           previousWasSeparator = true;
           next = advance();
         }
-        if (identical(next, $PLUS) || identical(next, $MINUS)) {
+        if (next == $PLUS || next == $MINUS) {
           previousWasSeparator = false;
           next = advance();
         }
@@ -1422,7 +1416,7 @@
           if ($0 <= next && next <= $9) {
             hasExponentDigits = true;
             previousWasSeparator = false;
-          } else if (identical(next, $_)) {
+          } else if (next == $_) {
             if (!hasExponentDigits) {
               prependErrorToken(new UnterminatedToken(
                   messageUnexpectedSeparatorInNumber, start, stringOffset));
@@ -1467,7 +1461,7 @@
 
       // TODO(ahe): Wrong offset for the period. Cannot call beginToken because
       // the scanner already advanced past the period.
-      if (identical($PERIOD, next)) {
+      if ($PERIOD == next) {
         return select(
             $PERIOD, TokenType.PERIOD_PERIOD_PERIOD, TokenType.PERIOD_PERIOD);
       }
@@ -1483,11 +1477,11 @@
   int tokenizeSlashOrComment(int next) {
     int start = scanOffset;
     next = advance();
-    if (identical($STAR, next)) {
+    if ($STAR == next) {
       return tokenizeMultiLineComment(next, start);
-    } else if (identical($SLASH, next)) {
+    } else if ($SLASH == next) {
       return tokenizeSingleLineComment(next, start);
-    } else if (identical($EQ, next)) {
+    } else if ($EQ == next) {
       appendPrecedenceToken(TokenType.SLASH_EQ);
       return advance();
     } else {
@@ -1501,47 +1495,47 @@
     next = advance();
 
     // Dart doc
-    if (identical($SLASH, peek())) {
+    if ($SLASH == peek()) {
       return tokenizeSingleLineComment(next, start);
     }
 
     // "@dart"
     next = advance();
-    while (identical($SPACE, next)) {
+    while ($SPACE == next) {
       next = advance();
     }
-    if (!identical($AT, next)) {
+    if ($AT != next) {
       return tokenizeSingleLineCommentRest(next, start, /* dartdoc = */ false);
     }
     next = advance();
-    if (!identical($d, next)) {
+    if ($d != next) {
       return tokenizeSingleLineCommentRest(next, start, /* dartdoc = */ false);
     }
     next = advance();
-    if (!identical($a, next)) {
+    if ($a != next) {
       return tokenizeSingleLineCommentRest(next, start, /* dartdoc = */ false);
     }
     next = advance();
-    if (!identical($r, next)) {
+    if ($r != next) {
       return tokenizeSingleLineCommentRest(next, start, /* dartdoc = */ false);
     }
     next = advance();
-    if (!identical($t, next)) {
+    if ($t != next) {
       return tokenizeSingleLineCommentRest(next, start, /* dartdoc = */ false);
     }
     next = advance();
 
     // "="
-    while (identical($SPACE, next)) {
+    while ($SPACE == next) {
       next = advance();
     }
-    if (!identical($EQ, next)) {
+    if ($EQ != next) {
       return tokenizeSingleLineCommentRest(next, start, /* dartdoc = */ false);
     }
     next = advance();
 
     // major
-    while (identical($SPACE, next)) {
+    while ($SPACE == next) {
       next = advance();
     }
     int major = 0;
@@ -1555,7 +1549,7 @@
     }
 
     // minor
-    if (!identical($PERIOD, next)) {
+    if ($PERIOD != next) {
       return tokenizeSingleLineCommentRest(next, start, /* dartdoc = */ false);
     }
     next = advance();
@@ -1570,7 +1564,7 @@
     }
 
     // trailing spaces
-    while (identical($SPACE, next)) {
+    while ($SPACE == next) {
       next = advance();
     }
     if (next != $LF && next != $CR && next != $EOF) {
@@ -1594,7 +1588,7 @@
   }
 
   int tokenizeSingleLineComment(int next, int start) {
-    bool dartdoc = identical($SLASH, peek());
+    bool dartdoc = $SLASH == peek();
     next = advance();
     return tokenizeSingleLineCommentRest(next, start, dartdoc);
   }
@@ -1603,9 +1597,7 @@
     bool asciiOnly = true;
     while (true) {
       if (next > 127) asciiOnly = false;
-      if (identical($LF, next) ||
-          identical($CR, next) ||
-          identical($EOF, next)) {
+      if ($LF == next || $CR == next || $EOF == next) {
         if (!asciiOnly) handleUnicode(start);
         if (dartdoc) {
           appendDartDoc(start, TokenType.SINGLE_LINE_COMMENT, asciiOnly);
@@ -1624,17 +1616,17 @@
     int unicodeStart = start;
     int nesting = 1;
     next = advance();
-    bool dartdoc = identical($STAR, next);
+    bool dartdoc = $STAR == next;
     while (true) {
-      if (identical($EOF, next)) {
+      if ($EOF == next) {
         if (!asciiOnlyLines) handleUnicode(unicodeStart);
         prependErrorToken(new UnterminatedToken(
             messageUnterminatedComment, tokenStart, stringOffset));
-        advanceAfterError(/* shouldAdvance = */ true);
+        advanceAfterError();
         break;
-      } else if (identical($STAR, next)) {
+      } else if ($STAR == next) {
         next = advance();
-        if (identical($SLASH, next)) {
+        if ($SLASH == next) {
           --nesting;
           if (0 == nesting) {
             if (!asciiOnlyLines) handleUnicode(unicodeStart);
@@ -1651,13 +1643,13 @@
             next = advance();
           }
         }
-      } else if (identical($SLASH, next)) {
+      } else if ($SLASH == next) {
         next = advance();
-        if (identical($STAR, next)) {
+        if ($STAR == next) {
           next = advance();
           ++nesting;
         }
-      } else if (identical(next, $LF)) {
+      } else if (next == $LF) {
         if (!asciiOnlyLines) {
           // Synchronize the string offset in the utf8 scanner.
           handleUnicode(unicodeStart);
@@ -1720,7 +1712,7 @@
   int tokenizeRawStringKeywordOrIdentifier(int next) {
     // [next] is $r.
     int nextnext = peek();
-    if (identical(nextnext, $DQ) || identical(nextnext, $SQ)) {
+    if (nextnext == $DQ || nextnext == $SQ) {
       int start = scanOffset;
       next = advance();
       return tokenizeString(next, start, /* raw = */ true);
@@ -1764,8 +1756,8 @@
     }
     if (($A <= next && next <= $Z) ||
         ($0 <= next && next <= $9) ||
-        identical(next, $_) ||
-        (allowDollar && identical(next, $$))) {
+        next == $_ ||
+        (allowDollar && next == $$)) {
       return tokenizeIdentifier(next, start, allowDollar);
     } else {
       appendKeywordToken(keyword);
@@ -1803,9 +1795,9 @@
   int tokenizeString(int next, int start, bool raw) {
     int quoteChar = next;
     next = advance();
-    if (identical(quoteChar, next)) {
+    if (quoteChar == next) {
       next = advance();
-      if (identical(quoteChar, next)) {
+      if (quoteChar == next) {
         // Multiline string.
         return tokenizeMultiLineString(quoteChar, start, raw);
       } else {
@@ -1836,20 +1828,17 @@
   int tokenizeSingleLineString(int next, int quoteChar, int quoteStart) {
     int start = quoteStart;
     bool asciiOnly = true;
-    while (!identical(next, quoteChar)) {
-      if (identical(next, $BACKSLASH)) {
+    while (next != quoteChar) {
+      if (next == $BACKSLASH) {
         next = advance();
-      } else if (identical(next, $$)) {
+      } else if (next == $$) {
         if (!asciiOnly) handleUnicode(start);
         next = tokenizeStringInterpolation(start, asciiOnly);
         start = scanOffset;
         asciiOnly = true;
         continue;
       }
-      if (next <= $CR &&
-          (identical(next, $LF) ||
-              identical(next, $CR) ||
-              identical(next, $EOF))) {
+      if (next <= $CR && (next == $LF || next == $CR || next == $EOF)) {
         if (!asciiOnly) handleUnicode(start);
         unterminatedString(quoteChar, quoteStart, start,
             asciiOnly: asciiOnly, isMultiLine: false, isRaw: false);
@@ -1869,7 +1858,7 @@
     appendSubstringToken(TokenType.STRING, start, asciiOnly);
     beginToken(); // $ starts here.
     int next = advance();
-    if (identical(next, $OPEN_CURLY_BRACKET)) {
+    if (next == $OPEN_CURLY_BRACKET) {
       return tokenizeInterpolatedExpression(next);
     } else {
       return tokenizeInterpolatedIdentifier(next);
@@ -1880,10 +1869,10 @@
     appendBeginGroup(TokenType.STRING_INTERPOLATION_EXPRESSION);
     beginToken(); // The expression starts here.
     next = advance(); // Move past the curly bracket.
-    while (!identical(next, $EOF) && !identical(next, $STX)) {
+    while (next != $EOF && next != $STX) {
       next = bigSwitch(next);
     }
-    if (identical(next, $EOF)) {
+    if (next == $EOF) {
       beginToken();
       discardInterpolation();
       return next;
@@ -1896,9 +1885,7 @@
   int tokenizeInterpolatedIdentifier(int next) {
     appendPrecedenceToken(TokenType.STRING_INTERPOLATION_IDENTIFIER);
 
-    if ($a <= next && next <= $z ||
-        $A <= next && next <= $Z ||
-        identical(next, $_)) {
+    if ($a <= next && next <= $z || $A <= next && next <= $Z || next == $_) {
       beginToken(); // The identifier starts here.
       next = tokenizeKeywordOrIdentifier(next, /* allowDollar = */ false);
     } else {
@@ -1915,12 +1902,12 @@
   int tokenizeSingleLineRawString(int next, int quoteChar, int quoteStart) {
     bool asciiOnly = true;
     while (next != $EOF) {
-      if (identical(next, quoteChar)) {
+      if (next == quoteChar) {
         if (!asciiOnly) handleUnicode(quoteStart);
         next = advance();
         appendSubstringToken(TokenType.STRING, quoteStart, asciiOnly);
         return next;
-      } else if (identical(next, $LF) || identical(next, $CR)) {
+      } else if (next == $LF || next == $CR) {
         if (!asciiOnly) handleUnicode(quoteStart);
         unterminatedString(quoteChar, quoteStart, quoteStart,
             asciiOnly: asciiOnly, isMultiLine: false, isRaw: true);
@@ -1942,9 +1929,9 @@
     int unicodeStart = quoteStart;
     int next = advance(); // Advance past the (last) quote (of three).
     outer:
-    while (!identical(next, $EOF)) {
-      while (!identical(next, quoteChar)) {
-        if (identical(next, $LF)) {
+    while (next != $EOF) {
+      while (next != quoteChar) {
+        if (next == $LF) {
           if (!asciiOnlyLine) {
             // Synchronize the string offset in the utf8 scanner.
             handleUnicode(unicodeStart);
@@ -1957,12 +1944,12 @@
           asciiOnlyString = false;
         }
         next = advance();
-        if (identical(next, $EOF)) break outer;
+        if (next == $EOF) break outer;
       }
       next = advance();
-      if (identical(next, quoteChar)) {
+      if (next == quoteChar) {
         next = advance();
-        if (identical(next, quoteChar)) {
+        if (next == quoteChar) {
           if (!asciiOnlyLine) handleUnicode(unicodeStart);
           next = advance();
           appendSubstringToken(TokenType.STRING, quoteStart, asciiOnlyString);
@@ -1983,8 +1970,8 @@
     bool asciiOnlyLine = true;
     int unicodeStart = start;
     int next = advance(); // Advance past the (last) quote (of three).
-    while (!identical(next, $EOF)) {
-      if (identical(next, $$)) {
+    while (next != $EOF) {
+      if (next == $$) {
         if (!asciiOnlyLine) handleUnicode(unicodeStart);
         next = tokenizeStringInterpolation(start, asciiOnlyString);
         start = scanOffset;
@@ -1993,11 +1980,11 @@
         asciiOnlyLine = true;
         continue;
       }
-      if (identical(next, quoteChar)) {
+      if (next == quoteChar) {
         next = advance();
-        if (identical(next, quoteChar)) {
+        if (next == quoteChar) {
           next = advance();
-          if (identical(next, quoteChar)) {
+          if (next == quoteChar) {
             if (!asciiOnlyLine) handleUnicode(unicodeStart);
             next = advance();
             appendSubstringToken(TokenType.STRING, start, asciiOnlyString);
@@ -2006,11 +1993,11 @@
         }
         continue;
       }
-      if (identical(next, $BACKSLASH)) {
+      if (next == $BACKSLASH) {
         next = advance();
-        if (identical(next, $EOF)) break;
+        if (next == $EOF) break;
       }
-      if (identical(next, $LF)) {
+      if (next == $LF) {
         if (!asciiOnlyLine) {
           // Synchronize the string offset in the utf8 scanner.
           handleUnicode(unicodeStart);
@@ -2045,7 +2032,7 @@
       }
       codeUnits.add(errorToken.character);
       prependErrorToken(errorToken);
-      int next = advanceAfterError(/* shouldAdvance = */ true);
+      int next = advanceAfterError();
       while (_isIdentifierChar(next, /* allowDollar = */ true)) {
         codeUnits.add(next);
         next = advance();
@@ -2056,7 +2043,7 @@
       return next;
     } else {
       prependErrorToken(errorToken);
-      return advanceAfterError(/* shouldAdvance = */ true);
+      return advanceAfterError();
     }
   }
 
@@ -2079,13 +2066,9 @@
     prependErrorToken(new UnterminatedString(prefix, errorStart, stringOffset));
   }
 
-  int advanceAfterError(bool shouldAdvance) {
+  int advanceAfterError() {
     if (atEndOfFile()) return $EOF;
-    if (shouldAdvance) {
-      return advance(); // Ensure progress.
-    } else {
-      return -1;
-    }
+    return advance(); // Ensure progress.
   }
 }
 
@@ -2103,7 +2086,7 @@
   List<int> array;
   int arrayLength = 0;
 
-  LineStarts(int? numberOfBytesHint)
+  LineStarts(int numberOfBytesHint)
       : array = _createInitialArray(numberOfBytesHint) {
     // The first line starts at character offset 0.
     add(/* value = */ 0);
@@ -2169,10 +2152,7 @@
     array = newArray;
   }
 
-  static List<int> _createInitialArray(int? numberOfBytesHint) {
-    // Let's assume the average Dart file is 300 bytes.
-    numberOfBytesHint ??= 300;
-
+  static List<int> _createInitialArray(int numberOfBytesHint) {
     // Let's assume we have on average 22 bytes per line.
     final int expectedNumberOfLines = 1 + (numberOfBytesHint ~/ 22);
 
@@ -2218,6 +2198,6 @@
   return ($a <= next && next <= $z) ||
       ($A <= next && next <= $Z) ||
       ($0 <= next && next <= $9) ||
-      identical(next, $_) ||
-      (identical(next, $$) && allowDollar);
+      next == $_ ||
+      (next == $$ && allowDollar);
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/characters.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/characters.dart
index 305d071..d0cc9ff 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/characters.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/characters.dart
@@ -4,7 +4,7 @@
 
 library _fe_analyzer_shared.scanner.characters;
 
-const int $EOF = 0;
+const int $EOF = -1;
 const int $STX = 2;
 const int $BS = 8;
 const int $TAB = 9;
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/io.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/io.dart
index f51fbd6..6269939 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/io.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/io.dart
@@ -4,38 +4,14 @@
 
 library _fe_analyzer_shared.scanner.io;
 
-import 'dart:io' show File, RandomAccessFile;
+import 'dart:io' show File;
 
 import 'dart:typed_data' show Uint8List;
 
 Uint8List readBytesFromFileSync(Uri uri) {
-  RandomAccessFile file = new File.fromUri(uri).openSync();
-  Uint8List list;
-  try {
-    int length = file.lengthSync();
-    // +1 to have a 0 terminated list, see [Scanner].
-    list = new Uint8List(length + 1);
-    file.readIntoSync(list, /* start = */ 0, length);
-  } finally {
-    file.closeSync();
-  }
-  return list;
+  return new File.fromUri(uri).readAsBytesSync();
 }
 
-Future<Uint8List> readBytesFromFile(Uri uri,
-    {bool ensureZeroTermination = true}) async {
-  RandomAccessFile file = await new File.fromUri(uri).open();
-  Uint8List list;
-  try {
-    int length = await file.length();
-    // +1 to have a 0 terminated list, see [Scanner].
-    list = new Uint8List(ensureZeroTermination ? length + 1 : length);
-    int read = await file.readInto(list);
-    if (read != length) {
-      throw "Error reading file: ${uri}";
-    }
-  } finally {
-    await file.close();
-  }
-  return list;
+Future<Uint8List> readBytesFromFile(Uri uri) async {
+  return await new File.fromUri(uri).readAsBytes();
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/scanner.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/scanner.dart
index f76528d..7cb2790 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/scanner.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/scanner.dart
@@ -73,9 +73,6 @@
     bool includeComments = false,
     LanguageVersionChanged? languageVersionChanged,
     bool allowLazyStrings = true}) {
-  if (bytes.last != 0) {
-    throw new ArgumentError("[bytes]: the last byte must be 0.");
-  }
   Scanner scanner = new Utf8BytesScanner(bytes,
       configuration: configuration,
       includeComments: includeComments,
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart
index 6646339..44266ca 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart
@@ -4,6 +4,8 @@
 
 library dart2js.scanner.string_scanner;
 
+import 'characters.dart' show $EOF;
+
 import 'token.dart'
     show
         CommentToken,
@@ -35,21 +37,24 @@
  */
 class StringScanner extends AbstractScanner {
   /** The file content. */
-  final String string;
+  final String _string;
+  final int _stringLengthMinusOne;
 
-  /** The current offset in [string]. */
+  /** The current offset in [_string]. */
   @override
   int scanOffset = -1;
 
-  StringScanner(String string,
+  StringScanner(this._string,
       {ScannerConfiguration? configuration,
       bool includeComments = false,
       LanguageVersionChanged? languageVersionChanged})
-      : string = ensureZeroTermination(string),
-        super(configuration, includeComments, languageVersionChanged);
+      : _stringLengthMinusOne = _string.length - 1,
+        super(configuration, includeComments, languageVersionChanged,
+            numberOfBytesHint: _string.length);
 
   StringScanner.recoveryOptionScanner(StringScanner super.copyFrom)
-      : string = copyFrom.string,
+      : _string = copyFrom._string,
+        _stringLengthMinusOne = copyFrom._stringLengthMinusOne,
         scanOffset = copyFrom.scanOffset,
         super.recoveryOptionScanner();
 
@@ -58,13 +63,6 @@
     return new StringScanner.recoveryOptionScanner(this);
   }
 
-  static String ensureZeroTermination(String string) {
-    return (string.isEmpty || string.codeUnitAt(string.length - 1) != 0)
-        // TODO(lry): abort instead of copying the array, or warn?
-        ? string + '\x00'
-        : string;
-  }
-
   static bool isLegalIdentifier(String identifier) {
     StringScanner scanner = new StringScanner(identifier);
     Token startToken = scanner.tokenize();
@@ -72,9 +70,21 @@
   }
 
   @override
-  int advance() => string.codeUnitAt(++scanOffset);
+  @pragma('vm:unsafe:no-bounds-checks')
+  int advance() {
+    // Always increment so scanOffset goes past the end.
+    ++scanOffset;
+    if (scanOffset > _stringLengthMinusOne) return $EOF;
+    return _string.codeUnitAt(scanOffset);
+  }
+
   @override
-  int peek() => string.codeUnitAt(scanOffset + 1);
+  @pragma('vm:unsafe:no-bounds-checks')
+  int peek() {
+    int next = scanOffset + 1;
+    if (next > _stringLengthMinusOne) return $EOF;
+    return _string.codeUnitAt(next);
+  }
 
   @override
   int get stringOffset => scanOffset;
@@ -89,7 +99,7 @@
   analyzer.StringToken createSubstringToken(TokenType type, int start,
       bool asciiOnly, int extraOffset, bool allowLazy) {
     return new StringTokenImpl.fromSubstring(
-        type, string, start, scanOffset + extraOffset, tokenStart,
+        type, _string, start, scanOffset + extraOffset, tokenStart,
         canonicalize: true,
         precedingComments: comments,
         allowLazyFoo: allowLazy);
@@ -99,9 +109,9 @@
   analyzer.StringToken createSyntheticSubstringToken(
       TokenType type, int start, bool asciiOnly, String syntheticChars) {
     String value = syntheticChars.length == 0
-        ? canonicalizeSubString(string, start, scanOffset)
+        ? canonicalizeSubString(_string, start, scanOffset)
         : canonicalizeString(
-            string.substring(start, scanOffset) + syntheticChars);
+            _string.substring(start, scanOffset) + syntheticChars);
     return new SyntheticStringToken(
         type, value, tokenStart, value.length - syntheticChars.length);
   }
@@ -110,7 +120,7 @@
   CommentToken createCommentToken(TokenType type, int start, bool asciiOnly,
       [int extraOffset = 0]) {
     return new CommentTokenImpl.fromSubstring(
-        type, string, start, scanOffset + extraOffset, tokenStart,
+        type, _string, start, scanOffset + extraOffset, tokenStart,
         canonicalize: true);
   }
 
@@ -118,7 +128,7 @@
   DartDocToken createDartDocToken(TokenType type, int start, bool asciiOnly,
       [int extraOffset = 0]) {
     return new DartDocToken.fromSubstring(
-        type, string, start, scanOffset + extraOffset, tokenStart,
+        type, _string, start, scanOffset + extraOffset, tokenStart,
         canonicalize: true);
   }
 
@@ -126,10 +136,15 @@
   LanguageVersionToken createLanguageVersionToken(
       int start, int major, int minor) {
     return new LanguageVersionTokenImpl.fromSubstring(
-        string, start, scanOffset, tokenStart, major, minor,
+        _string, start, scanOffset, tokenStart, major, minor,
         canonicalize: true);
   }
 
   @override
-  bool atEndOfFile() => scanOffset >= string.length - 1;
+  // This class used to enforce zero-terminated input, so we only return true
+  // once advance has been out of bounds.
+  // TODO(jensj): This should probably change.
+  // It's at least used in tests (where the eof token has its offset reduced
+  // by one to 'fix' this.)
+  bool atEndOfFile() => scanOffset > _stringLengthMinusOne;
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart
index 8430d3e..3bba6be 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart
@@ -528,6 +528,12 @@
   TokenType get type => _tokenTypesByIndex[_typeAndOffset & 0xff];
 
   /**
+   * The index of the type.
+   */
+  @override
+  int get typeIndex => _typeAndOffset & 0xff;
+
+  /**
    * The offset from the beginning of the file to the first character in the
    * token.
    */
@@ -715,7 +721,7 @@
       : _value = StringUtilities.intern(value);
 
   @override
-  bool get isIdentifier => identical(kind, IDENTIFIER_TOKEN);
+  bool get isIdentifier => kind == IDENTIFIER_TOKEN;
 
   @override
   String get lexeme => _value;
@@ -1021,6 +1027,11 @@
   TokenType get type;
 
   /**
+   * Return the index of the type of the token.
+   */
+  int get typeIndex;
+
+  /**
    * Return `true` if this token has any one of the given [types].
    */
   bool matchesAny(List<TokenType> types);
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/token_impl.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/token_impl.dart
index 980a30d..b384fc5 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/token_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/token_impl.dart
@@ -88,7 +88,7 @@
   String get lexeme => valueOrLazySubstring = valueOrLazySubstring.toString();
 
   @override
-  bool get isIdentifier => identical(kind, IDENTIFIER_TOKEN);
+  bool get isIdentifier => kind == IDENTIFIER_TOKEN;
 
   @override
   String toString() => lexeme;
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart
index 764ea95e..2ea201e 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart
@@ -9,6 +9,8 @@
 
 import 'dart:convert' show unicodeBomCharacterRune, utf8;
 
+import 'characters.dart' show $EOF;
+
 import 'token.dart' show LanguageVersionToken, SyntheticStringToken, TokenType;
 
 import 'token.dart' as analyzer;
@@ -33,12 +35,9 @@
  * that points to substrings.
  */
 class Utf8BytesScanner extends AbstractScanner {
-  /**
-   * The file content.
-   *
-   * The content is zero-terminated.
-   */
-  final Uint8List bytes;
+  /// The raw file content.
+  final Uint8List _bytes;
+  final int _bytesLengthMinusOne;
 
   /**
    * Points to the offset of the last byte returned by [advance].
@@ -85,24 +84,15 @@
    */
   int utf8Slack = 0;
 
-  /**
-   * Creates a new Utf8BytesScanner. The source file is expected to be a
-   * [Utf8BytesSourceFile] that holds a list of UTF-8 bytes. Otherwise the
-   * string text of the source file is decoded.
-   *
-   * The list of UTF-8 bytes [file.slowUtf8Bytes()] is expected to return an
-   * array whose last element is '0' to signal the end of the file. If this
-   * is not the case, the entire array is copied before scanning.
-   */
-  Utf8BytesScanner(this.bytes,
+  Utf8BytesScanner(this._bytes,
       {ScannerConfiguration? configuration,
       bool includeComments = false,
       LanguageVersionChanged? languageVersionChanged,
       bool allowLazyStrings = true})
-      : super(configuration, includeComments, languageVersionChanged,
-            numberOfBytesHint: bytes.length,
+      : _bytesLengthMinusOne = _bytes.length - 1,
+        super(configuration, includeComments, languageVersionChanged,
+            numberOfBytesHint: _bytes.length,
             allowLazyStrings: allowLazyStrings) {
-    assert(bytes.last == 0);
     // Skip a leading BOM.
     if (containsBomAt(/* offset = */ 0)) {
       byteOffset += 3;
@@ -111,7 +101,8 @@
   }
 
   Utf8BytesScanner.createRecoveryOptionScanner(Utf8BytesScanner copyFrom)
-      : bytes = copyFrom.bytes,
+      : _bytes = copyFrom._bytes,
+        _bytesLengthMinusOne = copyFrom._bytesLengthMinusOne,
         super.recoveryOptionScanner(copyFrom) {
     this.byteOffset = copyFrom.byteOffset;
     this.scanSlack = copyFrom.scanSlack;
@@ -127,17 +118,28 @@
   bool containsBomAt(int offset) {
     const List<int> BOM_UTF8 = const [0xEF, 0xBB, 0xBF];
 
-    return offset + 3 < bytes.length &&
-        bytes[offset] == BOM_UTF8[0] &&
-        bytes[offset + 1] == BOM_UTF8[1] &&
-        bytes[offset + 2] == BOM_UTF8[2];
+    return offset + 3 < _bytes.length &&
+        _bytes[offset] == BOM_UTF8[0] &&
+        _bytes[offset + 1] == BOM_UTF8[1] &&
+        _bytes[offset + 2] == BOM_UTF8[2];
   }
 
   @override
-  int advance() => bytes[++byteOffset];
+  @pragma('vm:unsafe:no-bounds-checks')
+  int advance() {
+    // Always increment so byteOffset goes past the end.
+    ++byteOffset;
+    if (byteOffset > _bytesLengthMinusOne) return $EOF;
+    return _bytes[byteOffset];
+  }
 
   @override
-  int peek() => bytes[byteOffset + 1];
+  @pragma('vm:unsafe:no-bounds-checks')
+  int peek() {
+    int next = byteOffset + 1;
+    if (next > _bytesLengthMinusOne) return $EOF;
+    return _bytes[next];
+  }
 
   /// Returns the unicode code point starting at the byte offset [startOffset]
   /// with the byte [nextByte].
@@ -156,7 +158,9 @@
     }
     int numBytes = 0;
     for (int i = 0; i < expectedHighBytes; i++) {
-      if (bytes[byteOffset + i] < 0x80) {
+      int next = byteOffset + i;
+      if (next > _bytesLengthMinusOne) break;
+      if (_bytes[next] < 0x80) {
         break;
       }
       numBytes++;
@@ -169,7 +173,7 @@
     // TODO(lry): measurably slow, decode creates first a Utf8Decoder and a
     // _Utf8Decoder instance. Also the sublist is eagerly allocated.
     String codePoint =
-        utf8.decode(bytes.sublist(startOffset, end), allowMalformed: true);
+        utf8.decode(_bytes.sublist(startOffset, end), allowMalformed: true);
     if (codePoint.length == 0) {
       // The UTF-8 decoder discards leading BOM characters.
       // TODO(floitsch): don't just assume that removed characters were the
@@ -214,7 +218,7 @@
     int end = byteOffset;
     // TODO(lry): this measurably slows down the scanner for files with unicode.
     String s =
-        utf8.decode(bytes.sublist(startScanOffset, end), allowMalformed: true);
+        utf8.decode(_bytes.sublist(startScanOffset, end), allowMalformed: true);
     utf8Slack += (end - startScanOffset) - s.length;
   }
 
@@ -246,7 +250,7 @@
   analyzer.StringToken createSubstringToken(TokenType type, int start,
       bool asciiOnly, int extraOffset, bool allowLazy) {
     return new StringTokenImpl.fromUtf8Bytes(
-        type, bytes, start, byteOffset + extraOffset, asciiOnly, tokenStart,
+        type, _bytes, start, byteOffset + extraOffset, asciiOnly, tokenStart,
         precedingComments: comments, allowLazyFoo: allowLazy);
   }
 
@@ -254,9 +258,10 @@
   analyzer.StringToken createSyntheticSubstringToken(
       TokenType type, int start, bool asciiOnly, String syntheticChars) {
     String value = syntheticChars.length == 0
-        ? canonicalizeUtf8SubString(bytes, start, byteOffset, asciiOnly)
+        ? canonicalizeUtf8SubString(_bytes, start, byteOffset, asciiOnly)
         : canonicalizeString(
-            decodeString(bytes, start, byteOffset, asciiOnly) + syntheticChars);
+            decodeString(_bytes, start, byteOffset, asciiOnly) +
+                syntheticChars);
     return new SyntheticStringToken(
         type, value, tokenStart, value.length - syntheticChars.length);
   }
@@ -266,23 +271,28 @@
       TokenType type, int start, bool asciiOnly,
       [int extraOffset = 0]) {
     return new CommentTokenImpl.fromUtf8Bytes(
-        type, bytes, start, byteOffset + extraOffset, asciiOnly, tokenStart);
+        type, _bytes, start, byteOffset + extraOffset, asciiOnly, tokenStart);
   }
 
   @override
   DartDocToken createDartDocToken(TokenType type, int start, bool asciiOnly,
       [int extraOffset = 0]) {
     return new DartDocToken.fromUtf8Bytes(
-        type, bytes, start, byteOffset + extraOffset, asciiOnly, tokenStart);
+        type, _bytes, start, byteOffset + extraOffset, asciiOnly, tokenStart);
   }
 
   @override
   LanguageVersionToken createLanguageVersionToken(
       int start, int major, int minor) {
     return new LanguageVersionTokenImpl.fromUtf8Bytes(
-        bytes, start, byteOffset, tokenStart, major, minor);
+        _bytes, start, byteOffset, tokenStart, major, minor);
   }
 
   @override
-  bool atEndOfFile() => byteOffset >= bytes.length - 1;
+  // This class used to require zero-terminated input, so we only return true
+  // once advance has been out of bounds.
+  // TODO(jensj): This should probably change.
+  // It's at least used in tests (where the eof token has its offset reduced
+  // by one to 'fix' this.)
+  bool atEndOfFile() => byteOffset > _bytesLengthMinusOne;
 }
diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/shared_inference_log.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/shared_inference_log.dart
index 1ccdf14..91803ce 100644
--- a/pkg/_fe_analyzer_shared/lib/src/type_inference/shared_inference_log.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/shared_inference_log.dart
@@ -124,7 +124,8 @@
 abstract interface class SharedInferenceLogWriter<
     TypeStructure extends SharedTypeStructure<TypeStructure>,
     Type extends SharedTypeStructure<Type>,
-    TypeParameter extends Object> {
+    TypeParameterStructure extends SharedTypeParameterStructure<
+        TypeStructure>> {
   /// If [inProgress] is `true`, verifies that generic type inference is in
   /// progress; otherwise, verifies that generic type inference is not in
   /// progress.
@@ -170,7 +171,8 @@
   void enterFunctionExpressionInvocationTarget(Object node);
 
   /// Called when generic type inference begins.
-  void enterGenericInference(List<TypeParameter> typeFormals, Type template);
+  void enterGenericInference(
+      List<TypeParameterStructure> typeFormals, Type template);
 
   /// Called when type inference begins inferring the left hand side of an
   /// assignment.
@@ -239,8 +241,9 @@
   /// Records a constraint that was generated during the process of matching one
   /// type schema to another.
   void recordGeneratedConstraint(
-      TypeParameter parameter,
-      MergedTypeConstraint<TypeStructure, TypeParameter, Object, Type, Object>
+      TypeParameterStructure parameter,
+      MergedTypeConstraint<TypeStructure, TypeParameterStructure, Object, Type,
+              Object>
           constraint);
 
   /// Records that type inference has resolved a method name.
@@ -271,8 +274,10 @@
 abstract class SharedInferenceLogWriterImpl<
         TypeStructure extends SharedTypeStructure<TypeStructure>,
         Type extends SharedTypeStructure<Type>,
-        TypeParameter extends Object>
-    implements SharedInferenceLogWriter<TypeStructure, Type, TypeParameter> {
+        TypeParameterStructure extends SharedTypeParameterStructure<
+            TypeStructure>>
+    implements
+        SharedInferenceLogWriter<TypeStructure, Type, TypeParameterStructure> {
   /// A stack of [State] objects representing the calls that have been made to
   /// `enter...` methods without any matched `exit...` method.
   ///
@@ -450,13 +455,14 @@
   }
 
   @override
-  void enterGenericInference(List<TypeParameter> typeFormals, Type template) {
+  void enterGenericInference(
+      List<TypeParameterStructure> typeFormals, Type template) {
     if (state.kind == StateKind.genericInference) {
       fail('Tried to start generic inference when already in progress');
     }
     String typeFormalNames = [
-      for (TypeParameter typeFormal in typeFormals)
-        getTypeParameterName(typeFormal)
+      for (TypeParameterStructure typeFormal in typeFormals)
+        typeFormal.displayName
     ].join(', ');
     pushState(new GenericInferenceState(
         writer: this,
@@ -628,12 +634,6 @@
     throw new StateError(message);
   }
 
-  /// Gets the name of [typeParameter].
-  ///
-  /// This is required since there is no common base class for type parameters
-  /// that is shared by the analyzer and CFE.
-  String getTypeParameterName(TypeParameter typeParameter);
-
   /// Pops the most recently pushed [State] from [_stateStack].
   void popState() {
     if (_stateStack.length == 1) {
@@ -688,8 +688,9 @@
 
   @override
   void recordGeneratedConstraint(
-      TypeParameter parameter,
-      MergedTypeConstraint<TypeStructure, TypeParameter, Object, Type, Object>
+      TypeParameterStructure parameter,
+      MergedTypeConstraint<TypeStructure, TypeParameterStructure, Object, Type,
+              Object>
           constraint) {
     checkCall(
         method: 'recordGeneratedConstraint',
diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart
index e41a822..e93327a 100644
--- a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart
@@ -269,7 +269,7 @@
     Variable extends Object,
     Pattern extends Node,
     Error,
-    InferableParameter extends Object,
+    TypeParameterStructure extends SharedTypeParameterStructure<TypeStructure>,
     TypeDeclarationType extends Object,
     TypeDeclaration extends Object> {
   TypeAnalyzerErrors<Node, Statement, Expression, Variable,
@@ -281,7 +281,7 @@
 
   /// The [TypeAnalyzerOperations], used to access types, check subtyping, and
   /// query variable types.
-  TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
+  TypeAnalyzerOperations<TypeStructure, Variable, TypeParameterStructure,
       TypeDeclarationType, TypeDeclaration> get operations;
 
   /// Options affecting the behavior of [TypeAnalyzer].
@@ -1552,10 +1552,12 @@
     SharedTypeView<TypeStructure> matchedValueType = flow.getMatchedValueType();
     List<SharedTypeView<TypeStructure>> demonstratedPositionalTypes = [];
     List<(String, SharedTypeView<TypeStructure>)> demonstratedNamedTypes = [];
-    void dispatchField(
-      RecordPatternField<Node, Pattern> field,
-      SharedTypeView<TypeStructure> matchedType,
-    ) {
+
+    Map<int, Error>? duplicateRecordPatternFieldErrors =
+        _reportDuplicateRecordPatternFields(node, fields);
+
+    void dispatchField(int i, SharedTypeView<TypeStructure> matchedType) {
+      RecordPatternField<Node, Pattern> field = fields[i];
       flow.pushSubpattern(matchedType);
       dispatchPattern(
         context.withUnnecessaryWildcardKind(null),
@@ -1566,7 +1568,8 @@
       String? name = field.name;
       if (name == null) {
         demonstratedPositionalTypes.add(demonstratedType);
-      } else {
+      } else if (duplicateRecordPatternFieldErrors == null ||
+          !duplicateRecordPatternFieldErrors.containsKey(i)) {
         demonstratedNamedTypes.add((name, demonstratedType));
       }
       flow.popSubpattern();
@@ -1574,21 +1577,20 @@
 
     void dispatchFields(SharedTypeView<TypeStructure> matchedType) {
       for (int i = 0; i < fields.length; i++) {
-        dispatchField(fields[i], matchedType);
+        dispatchField(i, matchedType);
       }
     }
 
-    Map<int, Error>? duplicateRecordPatternFieldErrors =
-        _reportDuplicateRecordPatternFields(node, fields);
-
     // Build the required type.
     int requiredTypePositionalCount = 0;
     List<(String, SharedTypeView<TypeStructure>)> requiredTypeNamedTypes = [];
-    for (RecordPatternField<Node, Pattern> field in fields) {
+    for (int i = 0; i < fields.length; i++) {
+      RecordPatternField<Node, Pattern> field = fields[i];
       String? name = field.name;
       if (name == null) {
         requiredTypePositionalCount++;
-      } else {
+      } else if (duplicateRecordPatternFieldErrors == null ||
+          !duplicateRecordPatternFieldErrors.containsKey(i)) {
         requiredTypeNamedTypes.add(
           (name, operations.objectQuestionType),
         );
@@ -1611,7 +1613,7 @@
       if (fieldTypes != null) {
         assert(fieldTypes.length == fields.length);
         for (int i = 0; i < fields.length; i++) {
-          dispatchField(fields[i], fieldTypes[i]);
+          dispatchField(i, fieldTypes[i]);
         }
       } else {
         dispatchFields(operations.objectQuestionType);
diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart
index 7bc5f93..1f3ad2b 100644
--- a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart
@@ -22,7 +22,9 @@
 abstract interface class TypeAnalyzerOperations<
         TypeStructure extends SharedTypeStructure<TypeStructure>,
         Variable extends Object,
-        InferableParameter extends Object,
+        // Work around https://github.com/dart-lang/dart_style/issues/1568
+        // ignore: lines_longer_than_80_chars
+        TypeParameterStructure extends SharedTypeParameterStructure<TypeStructure>,
         TypeDeclarationType extends Object,
         TypeDeclaration extends Object>
     implements FlowAnalysisOperations<Variable, SharedTypeView<TypeStructure>> {
@@ -63,16 +65,6 @@
   SharedTypeView<TypeStructure> futureType(
       SharedTypeView<TypeStructure> argumentType);
 
-  /// Returns the type schema `Future` with omitted nullability and type
-  /// argument [argumentTypeSchema].
-  ///
-  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
-  /// [TypeAnalyzerOperationsMixin] and implement [futureTypeInternal] to
-  /// receive a concrete implementation of [futureTypeSchema] instead of
-  /// implementing [futureTypeSchema] directly.
-  SharedTypeSchemaView<TypeStructure> futureTypeSchema(
-      SharedTypeSchemaView<TypeStructure> argumentTypeSchema);
-
   /// [futureTypeInternal] should be implemented by concrete classes
   /// implementing [TypeAnalyzerOperations]. The implementations of [futureType]
   /// and [futureTypeSchema] are provided by mixing in
@@ -98,6 +90,16 @@
   /// step too.
   TypeStructure futureTypeInternal(TypeStructure typeStructure);
 
+  /// Returns the type schema `Future` with omitted nullability and type
+  /// argument [argumentTypeSchema].
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [futureTypeInternal] to
+  /// receive a concrete implementation of [futureTypeSchema] instead of
+  /// implementing [futureTypeSchema] directly.
+  SharedTypeSchemaView<TypeStructure> futureTypeSchema(
+      SharedTypeSchemaView<TypeStructure> argumentTypeSchema);
+
   /// If [type] was introduced by a class, mixin, enum, or extension type,
   /// returns a [TypeDeclarationKind] indicating what kind of thing it was
   /// introduced by. Otherwise, returns `null`.
@@ -108,6 +110,8 @@
   TypeDeclarationKind? getTypeDeclarationKind(
       SharedTypeView<TypeStructure> type);
 
+  TypeDeclarationKind? getTypeDeclarationKindInternal(TypeStructure type);
+
   /// Returns variance for of the type parameter at index [parameterIndex] in
   /// [typeDeclaration].
   Variance getTypeParameterVariance(
@@ -125,8 +129,6 @@
   TypeDeclarationKind? getTypeSchemaDeclarationKind(
       SharedTypeSchemaView<TypeStructure> typeSchema);
 
-  TypeDeclarationKind? getTypeDeclarationKindInternal(TypeStructure type);
-
   /// Computes the greatest lower bound of [type1] and [type2].
   ///
   /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
@@ -135,16 +137,6 @@
   SharedTypeView<TypeStructure> glb(
       SharedTypeView<TypeStructure> type1, SharedTypeView<TypeStructure> type2);
 
-  /// Computes the greatest lower bound of [typeSchema1] and [typeSchema2].
-  ///
-  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
-  /// [TypeAnalyzerOperationsMixin] and implement [glbInternal] to receive a
-  /// concrete implementation of [typeSchemaGlb] instead of implementing
-  /// [typeSchemaGlb] directly.
-  SharedTypeSchemaView<TypeStructure> typeSchemaGlb(
-      SharedTypeSchemaView<TypeStructure> typeSchema1,
-      SharedTypeSchemaView<TypeStructure> typeSchema2);
-
   /// [glbInternal] should be implemented by concrete classes implementing
   /// [TypeAnalyzerOperations]. The implementations of [glb] and [typeSchemaGlb]
   /// are provided by mixing in [TypeAnalyzerOperationsMixin], which defines
@@ -190,9 +182,6 @@
   /// non-negative n, and some types T1, ..., Tn.
   bool isExtensionType(SharedTypeView<TypeStructure> type);
 
-  /// Returns `true` if [type] is `F`, `F?`, or `F*` for some function type `F`.
-  bool isFunctionType(SharedTypeView<TypeStructure> type);
-
   /// Returns `true` if [type] is `A<T1, ..., Tn>`, `A<T1, ..., Tn>?`, or
   /// `A<T1, ..., Tn>*` for some class, mixin, or enum A, some non-negative n,
   /// and some types T1, ..., Tn. The method returns `false` if [type] is an
@@ -200,6 +189,9 @@
   /// type `X`.
   bool isInterfaceType(SharedTypeView<TypeStructure> type);
 
+  @override
+  bool isNever(SharedTypeView<TypeStructure> type);
+
   /// Returns `true` if `Null` is not a subtype of all types matching
   /// [typeSchema].
   ///
@@ -214,6 +206,16 @@
   /// `false` for `Object?` and `Object*`.
   bool isObject(SharedTypeView<TypeStructure> type);
 
+  /// The concrete classes implementing [TypeAnalyzerOperations] should
+  /// implement [isSubtypeOfInternal] in order to receive the implementations of
+  /// [typeIsSubtypeOfTypeSchema], [typeSchemaIsSubtypeOfType], and
+  /// [typeSchemaIsSubtypeOfTypeSchema] by mixing in
+  /// [TypeAnalyzerOperationsMixin].
+  bool isSubtypeOfInternal(TypeStructure left, TypeStructure right);
+
+  @override
+  bool isTypeParameterType(SharedTypeView<TypeStructure> type);
+
   /// Returns `true` if the type [type] satisfies the type schema [typeSchema].
   bool isTypeSchemaSatisfied(
       {required SharedTypeSchemaView<TypeStructure> typeSchema,
@@ -235,15 +237,6 @@
   SharedTypeView<TypeStructure> listType(
       SharedTypeView<TypeStructure> elementType);
 
-  /// Returns the type schema `List`, with type argument [elementTypeSchema].
-  ///
-  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
-  /// [TypeAnalyzerOperationsMixin] and implement [listTypeInternal] to receive
-  /// a concrete implementation of [listTypeSchema] instead of implementing
-  /// [listTypeSchema] directly.
-  SharedTypeSchemaView<TypeStructure> listTypeSchema(
-      SharedTypeSchemaView<TypeStructure> elementTypeSchema);
-
   /// [listTypeInternal] should be implemented by concrete classes implementing
   /// [TypeAnalyzerOperations]. The implementations of [listType] and
   /// [listTypeSchema] are provided by mixing in [TypeAnalyzerOperationsMixin],
@@ -268,6 +261,15 @@
   /// step too.
   TypeStructure listTypeInternal(TypeStructure elementType);
 
+  /// Returns the type schema `List`, with type argument [elementTypeSchema].
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [listTypeInternal] to receive
+  /// a concrete implementation of [listTypeSchema] instead of implementing
+  /// [listTypeSchema] directly.
+  SharedTypeSchemaView<TypeStructure> listTypeSchema(
+      SharedTypeSchemaView<TypeStructure> elementTypeSchema);
+
   /// Computes the least upper bound of [type1] and [type2].
   ///
   /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
@@ -276,16 +278,6 @@
   SharedTypeView<TypeStructure> lub(
       SharedTypeView<TypeStructure> type1, SharedTypeView<TypeStructure> type2);
 
-  /// Computes the least upper bound of [typeSchema1] and [typeSchema2].
-  ///
-  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
-  /// [TypeAnalyzerOperationsMixin] and implement [lubInternal] to receive a
-  /// concrete implementation of [typeSchemaLub] instead of implementing
-  /// [typeSchemaLub] directly.
-  SharedTypeSchemaView<TypeStructure> typeSchemaLub(
-      SharedTypeSchemaView<TypeStructure> typeSchema1,
-      SharedTypeSchemaView<TypeStructure> typeSchema2);
-
   /// [lubInternal] should be implemented by concrete classes implementing
   /// [TypeAnalyzerOperations]. The implementations of [lub] and [typeSchemaLub]
   /// are provided by mixing in [TypeAnalyzerOperationsMixin], which defines
@@ -318,15 +310,6 @@
   SharedTypeView<TypeStructure> makeNullable(
       SharedTypeView<TypeStructure> type);
 
-  /// Computes the nullable form of [typeSchema].
-  ///
-  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
-  /// [TypeAnalyzerOperationsMixin] and implement [makeNullableInternal] to
-  /// receive a concrete implementation of [makeTypeSchemaNullable] instead of
-  /// implementing [makeTypeSchemaNullable] directly.
-  SharedTypeSchemaView<TypeStructure> makeTypeSchemaNullable(
-      SharedTypeSchemaView<TypeStructure> typeSchema);
-
   /// [makeNullableInternal] should be implemented by concrete classes
   /// implementing [TypeAnalyzerOperations]. The implementations of
   /// [makeNullable] and [makeTypeSchemaNullable] are provided by mixing in
@@ -352,6 +335,15 @@
   /// step too.
   TypeStructure makeNullableInternal(TypeStructure type);
 
+  /// Computes the nullable form of [typeSchema].
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [makeNullableInternal] to
+  /// receive a concrete implementation of [makeTypeSchemaNullable] instead of
+  /// implementing [makeTypeSchemaNullable] directly.
+  SharedTypeSchemaView<TypeStructure> makeTypeSchemaNullable(
+      SharedTypeSchemaView<TypeStructure> typeSchema);
+
   /// Returns the type `Map`, with type arguments.
   ///
   /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
@@ -363,18 +355,6 @@
     required SharedTypeView<TypeStructure> valueType,
   });
 
-  /// Returns the type schema `Map`, with type arguments [keyTypeSchema] and
-  /// [valueTypeSchema].
-  ///
-  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
-  /// [TypeAnalyzerOperationsMixin] and implement [mapTypeInternal] to receive a
-  /// concrete implementation of [makeTypeSchemaNullable] instead of
-  /// implementing [makeTypeSchemaNullable] directly.
-  SharedTypeSchemaView<TypeStructure> mapTypeSchema({
-    required SharedTypeSchemaView<TypeStructure> keyTypeSchema,
-    required SharedTypeSchemaView<TypeStructure> valueTypeSchema,
-  });
-
   /// [mapTypeInternal] should be implemented by concrete classes implementing
   /// [TypeAnalyzerOperations]. The implementations of [mapType] and
   /// [makeTypeSchemaNullable] are provided by mixing in
@@ -403,6 +383,18 @@
     required TypeStructure valueType,
   });
 
+  /// Returns the type schema `Map`, with type arguments [keyTypeSchema] and
+  /// [valueTypeSchema].
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [mapTypeInternal] to receive a
+  /// concrete implementation of [makeTypeSchemaNullable] instead of
+  /// implementing [makeTypeSchemaNullable] directly.
+  SharedTypeSchemaView<TypeStructure> mapTypeSchema({
+    required SharedTypeSchemaView<TypeStructure> keyTypeSchema,
+    required SharedTypeSchemaView<TypeStructure> valueTypeSchema,
+  });
+
   /// If [type] takes the form `FutureOr<T>`, `FutureOr<T>?`, or `FutureOr<T>*`
   /// for some `T`, returns the type `T`. Otherwise returns `null`.
   ///
@@ -413,17 +405,6 @@
   SharedTypeView<TypeStructure>? matchFutureOr(
       SharedTypeView<TypeStructure> type);
 
-  /// If [typeSchema] takes the form `FutureOr<T>`, `FutureOr<T>?`, or
-  /// `FutureOr<T>*` for some `T`, returns the type schema `T`. Otherwise
-  /// returns `null`.
-  ///
-  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
-  /// [TypeAnalyzerOperationsMixin] and implement [matchFutureOrInternal] to
-  /// receive a concrete implementation of [matchTypeSchemaFutureOr] instead of
-  /// implementing [matchTypeSchemaFutureOr] directly.
-  SharedTypeSchemaView<TypeStructure>? matchTypeSchemaFutureOr(
-      SharedTypeSchemaView<TypeStructure> typeSchema);
-
   /// [matchFutureOrInternal] should be implemented by concrete classes
   /// implementing [TypeAnalyzerOperations]. The implementations of
   /// [matchFutureOr] and [matchTypeSchemaFutureOr] are provided by mixing in
@@ -458,7 +439,7 @@
   /// `foo`.
   ///
   ///   X foo<X>(bool c, X x1, X x2) => c ? x1 : x2;
-  InferableParameter? matchInferableParameter(
+  TypeParameterStructure? matchInferableParameter(
       SharedTypeView<TypeStructure> type);
 
   /// If [type] is a subtype of the type `Iterable<T>?` for some `T`, returns
@@ -471,16 +452,6 @@
   SharedTypeView<TypeStructure>? matchIterableType(
       SharedTypeView<TypeStructure> type);
 
-  /// If [typeSchema] is the type schema `Iterable<T>?` (or a subtype thereof),
-  /// for some `T`, returns the type `T`. Otherwise returns `null`.
-  ///
-  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
-  /// [TypeAnalyzerOperationsMixin] and implement [matchIterableTypeInternal] to
-  /// receive a concrete implementation of [matchIterableTypeSchema] instead of
-  /// implementing [matchIterableTypeSchema] directly.
-  SharedTypeSchemaView<TypeStructure>? matchIterableTypeSchema(
-      SharedTypeSchemaView<TypeStructure> typeSchema);
-
   /// [matchIterableTypeInternal] should be implemented by concrete classes
   /// implementing [TypeAnalyzerOperations]. The implementations of
   /// [matchIterableType] and [matchIterableTypeSchema] are provided by mixing
@@ -506,6 +477,16 @@
   /// the abstraction step too.
   TypeStructure? matchIterableTypeInternal(TypeStructure type);
 
+  /// If [typeSchema] is the type schema `Iterable<T>?` (or a subtype thereof),
+  /// for some `T`, returns the type `T`. Otherwise returns `null`.
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [matchIterableTypeInternal] to
+  /// receive a concrete implementation of [matchIterableTypeSchema] instead of
+  /// implementing [matchIterableTypeSchema] directly.
+  SharedTypeSchemaView<TypeStructure>? matchIterableTypeSchema(
+      SharedTypeSchemaView<TypeStructure> typeSchema);
+
   /// If [type] is a subtype of the type `List<T>?` for some `T`, returns the
   /// type `T`.  Otherwise returns `null`.
   SharedTypeView<TypeStructure>? matchListType(
@@ -529,14 +510,30 @@
   ///
   /// If [type] isn't introduced by a class, mixin, enum, or extension type,
   /// returns null.
-  TypeDeclarationMatchResult? matchTypeDeclarationType(
-      SharedTypeView<TypeStructure> type);
+  TypeDeclarationMatchResult<TypeDeclarationType, TypeDeclaration,
+          TypeStructure>?
+      matchTypeDeclarationType(SharedTypeView<TypeStructure> type);
+
+  /// If [typeSchema] takes the form `FutureOr<T>`, `FutureOr<T>?`, or
+  /// `FutureOr<T>*` for some `T`, returns the type schema `T`. Otherwise
+  /// returns `null`.
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [matchFutureOrInternal] to
+  /// receive a concrete implementation of [matchTypeSchemaFutureOr] instead of
+  /// implementing [matchTypeSchemaFutureOr] directly.
+  SharedTypeSchemaView<TypeStructure>? matchTypeSchemaFutureOr(
+      SharedTypeSchemaView<TypeStructure> typeSchema);
 
   /// Computes `NORM` of [type].
   /// https://github.com/dart-lang/language
   /// See `resources/type-system/normalization.md`
   SharedTypeView<TypeStructure> normalize(SharedTypeView<TypeStructure> type);
 
+  @override
+  SharedTypeView<TypeStructure> promoteToNonNull(
+      SharedTypeView<TypeStructure> type);
+
   /// Builds the client specific record type.
   ///
   /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
@@ -547,16 +544,6 @@
       {required List<SharedTypeView<TypeStructure>> positional,
       required List<(String, SharedTypeView<TypeStructure>)> named});
 
-  /// Builds the client specific record type schema.
-  ///
-  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
-  /// [TypeAnalyzerOperationsMixin] and implement [recordTypeInternal] to
-  /// receive a concrete implementation of [recordTypeSchema] instead of
-  /// implementing [recordTypeSchema] directly.
-  SharedTypeSchemaView<TypeStructure> recordTypeSchema(
-      {required List<SharedTypeSchemaView<TypeStructure>> positional,
-      required List<(String, SharedTypeSchemaView<TypeStructure>)> named});
-
   /// [recordTypeInternal] should be implemented by concrete classes
   /// implementing [TypeAnalyzerOperations]. The implementations of [recordType]
   /// and [recordTypeSchema] are provided by mixing in
@@ -584,10 +571,24 @@
       {required List<TypeStructure> positional,
       required List<(String, TypeStructure)> named});
 
+  /// Builds the client specific record type schema.
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [recordTypeInternal] to
+  /// receive a concrete implementation of [recordTypeSchema] instead of
+  /// implementing [recordTypeSchema] directly.
+  SharedTypeSchemaView<TypeStructure> recordTypeSchema(
+      {required List<SharedTypeSchemaView<TypeStructure>> positional,
+      required List<(String, SharedTypeSchemaView<TypeStructure>)> named});
+
   /// Returns the type schema `Stream`, with type argument [elementTypeSchema].
   SharedTypeSchemaView<TypeStructure> streamTypeSchema(
       SharedTypeSchemaView<TypeStructure> elementTypeSchema);
 
+  @override
+  SharedTypeView<TypeStructure>? tryPromoteToType(
+      SharedTypeView<TypeStructure> to, SharedTypeView<TypeStructure> from);
+
   /// Returns `true` if [leftType] is a subtype of the greatest closure of
   /// [rightSchema].
   ///
@@ -604,6 +605,16 @@
   bool typeIsSubtypeOfTypeSchema(SharedTypeView<TypeStructure> leftType,
       SharedTypeSchemaView<TypeStructure> rightSchema);
 
+  /// Computes the greatest lower bound of [typeSchema1] and [typeSchema2].
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [glbInternal] to receive a
+  /// concrete implementation of [typeSchemaGlb] instead of implementing
+  /// [typeSchemaGlb] directly.
+  SharedTypeSchemaView<TypeStructure> typeSchemaGlb(
+      SharedTypeSchemaView<TypeStructure> typeSchema1,
+      SharedTypeSchemaView<TypeStructure> typeSchema2);
+
   /// Returns `true` if the least closure of [leftSchema] is a subtype of
   /// [rightType].
   ///
@@ -637,12 +648,15 @@
       SharedTypeSchemaView<TypeStructure> leftSchema,
       SharedTypeSchemaView<TypeStructure> rightSchema);
 
-  /// The concrete classes implementing [TypeAnalyzerOperations] should
-  /// implement [isSubtypeOfInternal] in order to receive the implementations of
-  /// [typeIsSubtypeOfTypeSchema], [typeSchemaIsSubtypeOfType], and
-  /// [typeSchemaIsSubtypeOfTypeSchema] by mixing in
-  /// [TypeAnalyzerOperationsMixin].
-  bool isSubtypeOfInternal(TypeStructure left, TypeStructure right);
+  /// Computes the least upper bound of [typeSchema1] and [typeSchema2].
+  ///
+  /// The concrete classes implementing [TypeAnalyzerOperations] should mix in
+  /// [TypeAnalyzerOperationsMixin] and implement [lubInternal] to receive a
+  /// concrete implementation of [typeSchemaLub] instead of implementing
+  /// [typeSchemaLub] directly.
+  SharedTypeSchemaView<TypeStructure> typeSchemaLub(
+      SharedTypeSchemaView<TypeStructure> typeSchema1,
+      SharedTypeSchemaView<TypeStructure> typeSchema2);
 
   /// Converts a type into a corresponding type schema.
   SharedTypeSchemaView<TypeStructure> typeToSchema(
@@ -651,30 +665,18 @@
   /// Returns [type] suffixed with the [suffix].
   SharedTypeView<TypeStructure> withNullabilitySuffix(
       SharedTypeView<TypeStructure> type, NullabilitySuffix suffix);
-
-  @override
-  bool isNever(SharedTypeView<TypeStructure> type);
-
-  @override
-  bool isTypeParameterType(SharedTypeView<TypeStructure> type);
-
-  @override
-  SharedTypeView<TypeStructure> promoteToNonNull(
-      SharedTypeView<TypeStructure> type);
-
-  @override
-  SharedTypeView<TypeStructure>? tryPromoteToType(
-      SharedTypeView<TypeStructure> to, SharedTypeView<TypeStructure> from);
 }
 
 mixin TypeAnalyzerOperationsMixin<
         TypeStructure extends SharedTypeStructure<TypeStructure>,
         Variable extends Object,
-        InferableParameter extends Object,
+        // Work around https://github.com/dart-lang/dart_style/issues/1568
+        // ignore: lines_longer_than_80_chars
+        TypeParameterStructure extends SharedTypeParameterStructure<TypeStructure>,
         TypeDeclarationType extends Object,
         TypeDeclaration extends Object>
     implements
-        TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
+        TypeAnalyzerOperations<TypeStructure, Variable, TypeParameterStructure,
             TypeDeclarationType, TypeDeclaration> {
   @override
   SharedTypeView<TypeStructure> futureType(
@@ -710,12 +712,10 @@
   }
 
   @override
-  SharedTypeSchemaView<TypeStructure> typeSchemaGlb(
-      SharedTypeSchemaView<TypeStructure> typeSchema1,
-      SharedTypeSchemaView<TypeStructure> typeSchema2) {
-    return new SharedTypeSchemaView(glbInternal(
-        typeSchema1.unwrapTypeSchemaView(),
-        typeSchema2.unwrapTypeSchemaView()));
+  bool isSubtypeOf(SharedTypeView<TypeStructure> leftType,
+      SharedTypeView<TypeStructure> rightType) {
+    return isSubtypeOfInternal(
+        leftType.unwrapTypeView(), rightType.unwrapTypeView());
   }
 
   @override
@@ -739,15 +739,6 @@
   }
 
   @override
-  SharedTypeSchemaView<TypeStructure> typeSchemaLub(
-      SharedTypeSchemaView<TypeStructure> typeSchema1,
-      SharedTypeSchemaView<TypeStructure> typeSchema2) {
-    return new SharedTypeSchemaView(lubInternal(
-        typeSchema1.unwrapTypeSchemaView(),
-        typeSchema2.unwrapTypeSchemaView()));
-  }
-
-  @override
   SharedTypeView<TypeStructure> makeNullable(
       SharedTypeView<TypeStructure> type) {
     return new SharedTypeView(makeNullableInternal(type.unwrapTypeView()));
@@ -786,13 +777,6 @@
   }
 
   @override
-  SharedTypeSchemaView<TypeStructure>? matchTypeSchemaFutureOr(
-      SharedTypeSchemaView<TypeStructure> typeSchema) {
-    return matchFutureOrInternal(typeSchema.unwrapTypeSchemaView())
-        ?.wrapSharedTypeSchemaView();
-  }
-
-  @override
   SharedTypeView<TypeStructure>? matchIterableType(
       SharedTypeView<TypeStructure> type) {
     return matchIterableTypeInternal(type.unwrapTypeView())
@@ -807,6 +791,13 @@
   }
 
   @override
+  SharedTypeSchemaView<TypeStructure>? matchTypeSchemaFutureOr(
+      SharedTypeSchemaView<TypeStructure> typeSchema) {
+    return matchFutureOrInternal(typeSchema.unwrapTypeSchemaView())
+        ?.wrapSharedTypeSchemaView();
+  }
+
+  @override
   SharedTypeView<TypeStructure> recordType(
       {required List<SharedTypeView<TypeStructure>> positional,
       required List<(String, SharedTypeView<TypeStructure>)> named}) {
@@ -825,13 +816,6 @@
   }
 
   @override
-  bool isSubtypeOf(SharedTypeView<TypeStructure> leftType,
-      SharedTypeView<TypeStructure> rightType) {
-    return isSubtypeOfInternal(
-        leftType.unwrapTypeView(), rightType.unwrapTypeView());
-  }
-
-  @override
   bool typeIsSubtypeOfTypeSchema(SharedTypeView<TypeStructure> leftType,
       SharedTypeSchemaView<TypeStructure> rightSchema) {
     return isSubtypeOfInternal(
@@ -839,6 +823,15 @@
   }
 
   @override
+  SharedTypeSchemaView<TypeStructure> typeSchemaGlb(
+      SharedTypeSchemaView<TypeStructure> typeSchema1,
+      SharedTypeSchemaView<TypeStructure> typeSchema2) {
+    return new SharedTypeSchemaView(glbInternal(
+        typeSchema1.unwrapTypeSchemaView(),
+        typeSchema2.unwrapTypeSchemaView()));
+  }
+
+  @override
   bool typeSchemaIsSubtypeOfType(SharedTypeSchemaView<TypeStructure> leftSchema,
       SharedTypeView<TypeStructure> rightType) {
     return isSubtypeOfInternal(
@@ -854,12 +847,507 @@
   }
 
   @override
+  SharedTypeSchemaView<TypeStructure> typeSchemaLub(
+      SharedTypeSchemaView<TypeStructure> typeSchema1,
+      SharedTypeSchemaView<TypeStructure> typeSchema2) {
+    return new SharedTypeSchemaView(lubInternal(
+        typeSchema1.unwrapTypeSchemaView(),
+        typeSchema2.unwrapTypeSchemaView()));
+  }
+
+  @override
   SharedTypeSchemaView<TypeStructure> typeToSchema(
       SharedTypeView<TypeStructure> type) {
     return new SharedTypeSchemaView(type.unwrapTypeView());
   }
 }
 
+/// Abstract interface of a type constraint generator.
+abstract class TypeConstraintGenerator<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    FunctionParameterStructure extends SharedNamedFunctionParameterStructure<
+        TypeStructure>,
+    Variable extends Object,
+    TypeParameterStructure extends SharedTypeParameterStructure<TypeStructure>,
+    TypeDeclarationType extends Object,
+    TypeDeclaration extends Object,
+    AstNode extends Object> {
+  /// The current sate of the constraint generator.
+  ///
+  /// The states of the generator obtained via [currentState] can be treated as
+  /// checkpoints in the constraint generation process, and the generator can
+  /// be rolled back to a state via [restoreState].
+  TypeConstraintGeneratorState get currentState;
+
+  /// True if FutureOr types are required to have the empty [NullabilitySuffix]
+  /// when they are matched.
+  ///
+  /// For more information about the discrepancy between the Analyzer and the
+  /// CFE in treatment of FutureOr types, see
+  /// https://github.com/dart-lang/sdk/issues/55344 and
+  /// https://github.com/dart-lang/sdk/issues/51156#issuecomment-2158825417.
+  bool get enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr;
+
+  /// Abstract type operations to be used in the matching methods.
+  TypeAnalyzerOperations<TypeStructure, Variable, TypeParameterStructure,
+      TypeDeclarationType, TypeDeclaration> get typeAnalyzerOperations;
+
+  /// Returns the type arguments of the supertype of [type] that is an
+  /// instantiation of [typeDeclaration]. If none of the supertypes of [type]
+  /// are instantiations of [typeDeclaration], returns null.
+  List<TypeStructure>? getTypeArgumentsAsInstanceOf(
+      TypeDeclarationType type, TypeDeclaration typeDeclaration);
+
+  /// Matches [p] against [q].
+  ///
+  /// If [p] and [q] are both non-generic function types, and [p] is a subtype
+  /// of [q] under some constraints, the constraints making the relation
+  /// possible are recorded, and `true` is returned. Otherwise, the constraint
+  /// state is unchanged (or rolled back using [restoreState]), and `null` is
+  /// returned.
+  ///
+  /// An invariant of the type inference is that only [p] or [q] may be a
+  /// schema (in other words, may contain the unknown type `_`); the other must
+  /// be simply a type. If [leftSchema] is `true`, [p] may contain `_`; if it is
+  /// `false`, [q] may contain `_`.
+  bool? performSubtypeConstraintGenerationForFunctionTypes(
+      TypeStructure p, TypeStructure q,
+      {required bool leftSchema, required AstNode? astNodeForTesting}) {
+    if (p is SharedFunctionTypeStructure<TypeStructure, TypeParameterStructure,
+            FunctionParameterStructure> &&
+        q is SharedFunctionTypeStructure<TypeStructure, TypeParameterStructure,
+            FunctionParameterStructure>) {
+      // A function type (M0,..., Mn, [M{n+1}, ..., Mm]) -> R0 is a subtype
+      // match for a function type (N0,..., Nk, [N{k+1}, ..., Nr]) -> R1 with
+      // respect to L under constraints C0 + ... + Cr + C
+      //
+      // If R0 is a subtype match for a type R1 with respect to L under
+      // constraints C.  If n <= k and r <= m.  And for i in 0...r, Ni is a
+      // subtype match for Mi with respect to L under constraints Ci.
+
+      if (p.typeFormals.isEmpty &&
+          q.typeFormals.isEmpty &&
+          p.sortedNamedParameters.isEmpty &&
+          q.sortedNamedParameters.isEmpty &&
+          p.requiredPositionalParameterCount <=
+              q.requiredPositionalParameterCount &&
+          p.positionalParameterTypes.length >=
+              q.positionalParameterTypes.length) {
+        final TypeConstraintGeneratorState state = currentState;
+
+        if (!performSubtypeConstraintGenerationInternal(
+            p.returnType, q.returnType,
+            leftSchema: leftSchema, astNodeForTesting: astNodeForTesting)) {
+          return null;
+        }
+        for (int i = 0; i < q.positionalParameterTypes.length; ++i) {
+          if (!performSubtypeConstraintGenerationInternal(
+              q.positionalParameterTypes[i], p.positionalParameterTypes[i],
+              leftSchema: !leftSchema, astNodeForTesting: astNodeForTesting)) {
+            restoreState(state);
+            return null;
+          }
+        }
+        return true;
+      } else if (p.typeFormals.isEmpty &&
+          q.typeFormals.isEmpty &&
+          p.positionalParameterTypes.length ==
+              p.requiredPositionalParameterCount &&
+          q.positionalParameterTypes.length ==
+              q.requiredPositionalParameterCount &&
+          p.requiredPositionalParameterCount ==
+              q.requiredPositionalParameterCount &&
+          p.sortedNamedParameters.isNotEmpty &&
+          q.sortedNamedParameters.length <= p.sortedNamedParameters.length) {
+        // Function types with named parameters are treated analogously to the
+        // positional parameter case above.
+
+        final TypeConstraintGeneratorState state = currentState;
+
+        if (!performSubtypeConstraintGenerationInternal(
+            p.returnType, q.returnType,
+            leftSchema: leftSchema, astNodeForTesting: astNodeForTesting)) {
+          return null;
+        }
+        for (int i = 0; i < p.positionalParameterTypes.length; ++i) {
+          if (!performSubtypeConstraintGenerationInternal(
+              q.positionalParameterTypes[i], p.positionalParameterTypes[i],
+              leftSchema: !leftSchema, astNodeForTesting: astNodeForTesting)) {
+            restoreState(state);
+            return null;
+          }
+        }
+        // Consume parameter names from p and q in order. Since the named
+        // parameters in p and q are already sorted by name, we can do this by
+        // iterating through both lists in tandem.
+        int i = 0;
+        int j = 0;
+        while (true) {
+          // Determine whether the next parameter should be consumed from p,
+          // q, or both (because the next set of names matches). If the next
+          // parameter should be consumed from p, comparisonResult will be set
+          // to a value < 0. If the next parameter should be consumed from q,
+          // comparisonResult will be set to a value > 0. If the next
+          // parameter should be consumed from both, comparisonResult will be
+          // set to 0.
+          int comparisonResult;
+          if (i >= p.sortedNamedParameters.length) {
+            if (j >= q.sortedNamedParameters.length) {
+              // No parameters left.
+              return true;
+            } else {
+              // No more parameters in p, so the next parameter must come from
+              // q.
+              comparisonResult = 1;
+            }
+          } else if (j >= q.sortedNamedParameters.length) {
+            // No more parameters in q, so the next parameter must come from
+            // p.
+            comparisonResult = -1;
+          } else {
+            comparisonResult = p.sortedNamedParameters[i].name
+                .compareTo(q.sortedNamedParameters[j].name);
+          }
+          if (comparisonResult > 0) {
+            // Extra parameter in q that q that doesn't exist in p. No match.
+            restoreState(state);
+            return null;
+          } else if (comparisonResult < 0) {
+            // Extra parameter in p that doesn't exist in q. Ok if not
+            // required.
+            if (p.sortedNamedParameters[i].isRequired) {
+              restoreState(state);
+              return null;
+            } else {
+              i++;
+            }
+          } else {
+            // The next parameter in p and q matches, so match their types.
+            if (!performSubtypeConstraintGenerationInternal(
+                q.sortedNamedParameters[j].type,
+                p.sortedNamedParameters[i].type,
+                leftSchema: !leftSchema,
+                astNodeForTesting: astNodeForTesting)) {
+              restoreState(state);
+              return null;
+            }
+            i++;
+            j++;
+          }
+        }
+      }
+    }
+
+    return null;
+  }
+
+  /// Matches [p] against [q].
+  ///
+  /// If [q] is of the form `FutureOr<q0>` for some `q0`, and [p] is a subtype
+  /// of [q] under some constraints, the constraints making the relation
+  /// possible are recorded, and `true` is returned. Otherwise, the constraint
+  /// state is unchanged (or rolled back using [restoreState]), and `false` is
+  /// returned.
+  ///
+  /// An invariant of the type inference is that only [p] or [q] may be a
+  /// schema (in other words, may contain the unknown type `_`); the other must
+  /// be simply a type. If [leftSchema] is `true`, [p] may contain `_`; if it is
+  /// `false`, [q] may contain `_`.
+  bool performSubtypeConstraintGenerationForFutureOr(
+      TypeStructure p, TypeStructure q,
+      {required bool leftSchema, required AstNode? astNodeForTesting}) {
+    // If `Q` is `FutureOr<Q0>` the match holds under constraint set `C`:
+    if (typeAnalyzerOperations.matchFutureOrInternal(q) case TypeStructure q0?
+        when enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr ||
+            q.nullabilitySuffix == NullabilitySuffix.none) {
+      final TypeConstraintGeneratorState state = currentState;
+
+      // If `P` is `FutureOr<P0>` and `P0` is a subtype match for `Q0` under
+      // constraint set `C`.
+      if (typeAnalyzerOperations.matchFutureOrInternal(p) case TypeStructure p0?
+          when enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr ||
+              p.nullabilitySuffix == NullabilitySuffix.none) {
+        if (performSubtypeConstraintGenerationInternal(p0, q0,
+            leftSchema: leftSchema, astNodeForTesting: astNodeForTesting)) {
+          return true;
+        }
+      }
+
+      // Or if `P` is a subtype match for `Future<Q0>` under non-empty
+      // constraint set `C`.
+      bool isMatchWithFuture = performSubtypeConstraintGenerationInternal(
+          p, typeAnalyzerOperations.futureTypeInternal(q0),
+          leftSchema: leftSchema, astNodeForTesting: astNodeForTesting);
+      bool matchWithFutureAddsConstraints = currentState != state;
+      if (isMatchWithFuture && matchWithFutureAddsConstraints) {
+        return true;
+      }
+
+      // Or if `P` is a subtype match for `Q0` under constraint set `C`.
+      if (performSubtypeConstraintGenerationInternal(p, q0,
+          leftSchema: leftSchema, astNodeForTesting: astNodeForTesting)) {
+        return true;
+      }
+
+      // Or if `P` is a subtype match for `Future<Q0>` under empty
+      // constraint set `C`.
+      if (isMatchWithFuture && !matchWithFutureAddsConstraints) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  /// Matches [p] against [q] as a subtype against supertype.
+  ///
+  /// If [p] and [q] are both type declaration types, then:
+  ///
+  /// - If [p] is a subtype of [q] under some constraints, the constraints
+  ///   making the relation possible are recorded, and `true` is returned.
+  /// - Otherwise, the constraint state is unchanged (or rolled back using
+  ///   [restoreState]), and `false` is returned.
+  ///
+  /// Otherwise (either [p] or [q] is not a type declaration type), the
+  /// constraint state is unchanged, and `null` is returned.
+  ///
+  /// An invariant of the type inference is that only [p] or [q] may be a
+  /// schema (in other words, may contain the unknown type `_`); the other must
+  /// be simply a type. If [leftSchema] is `true`, [p] may contain `_`; if it is
+  /// `false`, [q] may contain `_`.
+  bool? performSubtypeConstraintGenerationForTypeDeclarationTypes(
+      TypeStructure p, TypeStructure q,
+      {required bool leftSchema, required AstNode? astNodeForTesting}) {
+    switch ((
+      typeAnalyzerOperations.matchTypeDeclarationType(new SharedTypeView(p)),
+      typeAnalyzerOperations.matchTypeDeclarationType(new SharedTypeView(q))
+    )) {
+      // If `P` is `C<M0, ..., Mk> and `Q` is `C<N0, ..., Nk>`, then the match
+      // holds under constraints `C0 + ... + Ck`:
+      //   If `Mi` is a subtype match for `Ni` with respect to L under
+      //   constraints `Ci`.
+      case (
+            TypeDeclarationMatchResult(
+              typeDeclarationKind: TypeDeclarationKind pTypeDeclarationKind,
+              typeDeclaration: TypeDeclaration pDeclarationObject,
+              typeArguments: List<TypeStructure> pTypeArguments
+            ),
+            TypeDeclarationMatchResult(
+              typeDeclarationKind: TypeDeclarationKind qTypeDeclarationKind,
+              typeDeclaration: TypeDeclaration qDeclarationObject,
+              typeArguments: List<TypeStructure> qTypeArguments
+            )
+          )
+          when pTypeDeclarationKind == qTypeDeclarationKind &&
+              pDeclarationObject == qDeclarationObject:
+        return _interfaceTypeArguments(
+            pDeclarationObject, pTypeArguments, qTypeArguments, leftSchema,
+            astNodeForTesting: astNodeForTesting);
+
+      case (TypeDeclarationMatchResult(), TypeDeclarationMatchResult()):
+        return _interfaceTypes(p, q, leftSchema,
+            astNodeForTesting: astNodeForTesting);
+
+      case (
+          TypeDeclarationMatchResult? pMatched,
+          TypeDeclarationMatchResult? qMatched
+        ):
+        assert(pMatched == null || qMatched == null);
+        return null;
+    }
+  }
+
+  /// Implementation backing [performSubtypeConstraintGenerationLeftSchema] and
+  /// [performSubtypeConstraintGenerationRightSchema].
+  ///
+  /// If [p] is a subtype of [q] under some constraints, the constraints making
+  /// the relation possible are recorded, and `true` is returned. Otherwise,
+  /// the constraint state is unchanged (or rolled back using [restoreState]),
+  /// and `false` is returned.
+  ///
+  /// [performSubtypeConstraintGenerationInternal] should be implemented by
+  /// concrete classes implementing [TypeConstraintGenerator]. The
+  /// implementations of [performSubtypeConstraintGenerationLeftSchema] and
+  /// [performSubtypeConstraintGenerationRightSchema] are provided by mixing in
+  /// [TypeConstraintGeneratorMixin], which defines
+  /// [performSubtypeConstraintGenerationLeftSchema] and
+  /// [performSubtypeConstraintGenerationRightSchema] in terms of
+  /// [performSubtypeConstraintGenerationInternal].
+  ///
+  /// The main purpose of this method is to avoid code duplication in the
+  /// concrete classes implementing [TypeAnalyzerOperations], so they can
+  /// implement only one member, in this case
+  /// [performSubtypeConstraintGenerationInternal], and receive the
+  /// implementation of both [performSubtypeConstraintGenerationLeftSchema] and
+  /// [performSubtypeConstraintGenerationRightSchema] from the mixin.
+  bool performSubtypeConstraintGenerationInternal(
+      TypeStructure p, TypeStructure q,
+      {required bool leftSchema, required AstNode? astNodeForTesting});
+
+  /// Matches type schema [p] against type [q] as a subtype against supertype,
+  /// assuming [p] is the constraining type schema, and [q] contains the type
+  /// parameters to constrain, and returns true if [p] is a subtype of [q]
+  /// under some constraints, and false otherwise.
+  ///
+  /// As the generator computes the constraints making the relation possible,
+  /// it changes its internal state. The current state of the generator can be
+  /// obtained by [currentState], and the generator can be restored to a state
+  /// via [restoreState]. If this method returns `false`, it restores the state,
+  /// so it is not necessary for the caller to do so.
+  ///
+  /// The algorithm for subtype constraint generation is described in
+  /// https://github.com/dart-lang/language/blob/main/resources/type-system/inference.md#subtype-constraint-generation
+  bool performSubtypeConstraintGenerationLeftSchema(
+      SharedTypeSchemaView<TypeStructure> p, SharedTypeView<TypeStructure> q,
+      {required AstNode? astNodeForTesting});
+
+  /// Matches type [p] against type schema [q] as a subtype against supertype,
+  /// assuming [p] contains the type parameters to constrain, and [q] is the
+  /// constraining type schema, and returns true if [p] is a subtype of [q]
+  /// under some constraints, and false otherwise.
+  ///
+  /// As the generator computes the constraints making the relation possible,
+  /// it changes its internal state. The current state of the generator can be
+  /// obtained by [currentState], and the generator can be restored to a state
+  /// via [restoreState]. If this method returns `false`, it restores the state,
+  /// so it is not necessary for the caller to do so.
+  ///
+  /// The algorithm for subtype constraint generation is described in
+  /// https://github.com/dart-lang/language/blob/main/resources/type-system/inference.md#subtype-constraint-generation
+  bool performSubtypeConstraintGenerationRightSchema(
+      SharedTypeView<TypeStructure> p, SharedTypeSchemaView<TypeStructure> q,
+      {required AstNode? astNodeForTesting});
+
+  /// Restores the constraint generator to [state].
+  ///
+  /// The [state] to restore the constraint generator to can be obtained via
+  /// [currentState].
+  void restoreState(TypeConstraintGeneratorState state);
+
+  /// Match arguments [pTypeArguments] of P against arguments [qTypeArguments]
+  /// of Q, taking into account the variance of type variables in [declaration].
+  /// If returns `false`, the constraints are unchanged.
+  bool _interfaceTypeArguments(
+      TypeDeclaration declaration,
+      List<TypeStructure> pTypeArguments,
+      List<TypeStructure> qTypeArguments,
+      bool leftSchema,
+      {required AstNode? astNodeForTesting}) {
+    assert(pTypeArguments.length == qTypeArguments.length);
+
+    final TypeConstraintGeneratorState state = currentState;
+
+    for (int i = 0; i < pTypeArguments.length; i++) {
+      Variance variance =
+          typeAnalyzerOperations.getTypeParameterVariance(declaration, i);
+      TypeStructure M = pTypeArguments[i];
+      TypeStructure N = qTypeArguments[i];
+      if ((variance == Variance.covariant || variance == Variance.invariant) &&
+          !performSubtypeConstraintGenerationInternal(M, N,
+              leftSchema: leftSchema, astNodeForTesting: astNodeForTesting)) {
+        restoreState(state);
+        return false;
+      }
+      if ((variance == Variance.contravariant ||
+              variance == Variance.invariant) &&
+          !performSubtypeConstraintGenerationInternal(N, M,
+              leftSchema: !leftSchema, astNodeForTesting: astNodeForTesting)) {
+        restoreState(state);
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  /// Matches [p] against [q], assuming both [p] and [q] are both type
+  /// declaration types that refer to different type declarations.
+  ///
+  /// If [p] is a subtype of [q] under some constraints, the constraints making
+  /// the relation possible are recorded, and `true` is returned. Otherwise,
+  /// the constraint state is unchanged (or rolled back using [restoreState]),
+  /// and `false` is returned.
+  bool _interfaceTypes(TypeStructure p, TypeStructure q, bool leftSchema,
+      {required AstNode? astNodeForTesting}) {
+    if (p.nullabilitySuffix != NullabilitySuffix.none) {
+      return false;
+    }
+
+    if (q.nullabilitySuffix != NullabilitySuffix.none) {
+      return false;
+    }
+
+    // If `P` is `C0<M0, ..., Mk>` and `Q` is `C1<N0, ..., Nj>` then the match
+    // holds with respect to `L` under constraints `C`:
+    //   If `C1<B0, ..., Bj>` is a superinterface of `C0<M0, ..., Mk>` and
+    //   `C1<B0, ..., Bj>` is a subtype match for `C1<N0, ..., Nj>` with
+    //   respect to `L` under constraints `C`.
+
+    if ((
+      typeAnalyzerOperations.matchTypeDeclarationType(new SharedTypeView(p)),
+      typeAnalyzerOperations.matchTypeDeclarationType(new SharedTypeView(q))
+    )
+        case (
+          TypeDeclarationMatchResult(
+            typeDeclarationType: TypeDeclarationType pTypeDeclarationType
+          ),
+          TypeDeclarationMatchResult(
+            typeDeclaration: TypeDeclaration qTypeDeclaration,
+            typeArguments: List<TypeStructure> qTypeArguments
+          )
+        )) {
+      if (getTypeArgumentsAsInstanceOf(pTypeDeclarationType, qTypeDeclaration)
+          case List<TypeStructure> typeArguments) {
+        return _interfaceTypeArguments(
+            qTypeDeclaration, typeArguments, qTypeArguments, leftSchema,
+            astNodeForTesting: astNodeForTesting);
+      }
+    }
+
+    return false;
+  }
+}
+
+mixin TypeConstraintGeneratorMixin<
+        TypeStructure extends SharedTypeStructure<TypeStructure>,
+        // Work around https://github.com/dart-lang/dart_style/issues/1568
+        // ignore: lines_longer_than_80_chars
+        FunctionParameterStructure extends SharedNamedFunctionParameterStructure<
+            TypeStructure>,
+        Variable extends Object,
+        // Work around https://github.com/dart-lang/dart_style/issues/1568
+        // ignore: lines_longer_than_80_chars
+        TypeParameterStructure extends SharedTypeParameterStructure<TypeStructure>,
+        TypeDeclarationType extends Object,
+        TypeDeclaration extends Object,
+        AstNode extends Object>
+    on TypeConstraintGenerator<
+        TypeStructure,
+        FunctionParameterStructure,
+        Variable,
+        TypeParameterStructure,
+        TypeDeclarationType,
+        TypeDeclaration,
+        AstNode> {
+  @override
+  bool performSubtypeConstraintGenerationLeftSchema(
+      SharedTypeSchemaView<TypeStructure> p, SharedTypeView<TypeStructure> q,
+      {required AstNode? astNodeForTesting}) {
+    return performSubtypeConstraintGenerationInternal(
+        p.unwrapTypeSchemaView(), q.unwrapTypeView(),
+        leftSchema: true, astNodeForTesting: astNodeForTesting);
+  }
+
+  @override
+  bool performSubtypeConstraintGenerationRightSchema(
+      SharedTypeView<TypeStructure> p, SharedTypeSchemaView<TypeStructure> q,
+      {required AstNode? astNodeForTesting}) {
+    return performSubtypeConstraintGenerationInternal(
+        p.unwrapTypeView(), q.unwrapTypeSchemaView(),
+        leftSchema: false, astNodeForTesting: astNodeForTesting);
+  }
+}
+
 /// Describes all possibility for a type to be derived from a declaration.
 ///
 /// This enum is intended to exhaustively handle all possibilities for a type to
@@ -1041,327 +1529,6 @@
   }
 }
 
-/// Abstract interface of a type constraint generator.
-abstract class TypeConstraintGenerator<
-    TypeStructure extends SharedTypeStructure<TypeStructure>,
-    Variable extends Object,
-    InferableParameter extends Object,
-    TypeDeclarationType extends Object,
-    TypeDeclaration extends Object,
-    AstNode extends Object> {
-  /// The current sate of the constraint generator.
-  ///
-  /// The states of the generator obtained via [currentState] can be treated as
-  /// checkpoints in the constraint generation process, and the generator can
-  /// be rolled back to a state via [restoreState].
-  TypeConstraintGeneratorState get currentState;
-
-  /// Restores the constraint generator to [state].
-  ///
-  /// The [state] to restore the constraint generator to can be obtained via
-  /// [currentState].
-  void restoreState(TypeConstraintGeneratorState state);
-
-  /// Abstract type operations to be used in the matching methods.
-  TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
-      TypeDeclarationType, TypeDeclaration> get typeAnalyzerOperations;
-
-  /// True if FutureOr types are required to have the empty [NullabilitySuffix]
-  /// when they are matched.
-  ///
-  /// For more information about the discrepancy between the Analyzer and the
-  /// CFE in treatment of FutureOr types, see
-  /// https://github.com/dart-lang/sdk/issues/55344 and
-  /// https://github.com/dart-lang/sdk/issues/51156#issuecomment-2158825417.
-  bool get enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr;
-
-  /// Matches type [p] against type schema [q] as a subtype against supertype,
-  /// assuming [p] contains the type parameters to constrain, and [q] is the
-  /// constraining type schema, and returns true if [p] is a subtype of [q]
-  /// under some constraints, and false otherwise.
-  ///
-  /// As the generator computes the constraints making the relation possible,
-  /// it changes its internal state. The current state of the generator can be
-  /// obtained by [currentState], and the generator can be restored to a state
-  /// via [restoreState]. All of the shared constraint generation methods are
-  /// supposed to restore the generator to the prior state in case of a
-  /// mismatch, taking that responsibility away from the caller.
-  ///
-  /// The algorithm for subtype constraint generation is described in
-  /// https://github.com/dart-lang/language/blob/main/resources/type-system/inference.md#subtype-constraint-generation
-  bool performSubtypeConstraintGenerationRightSchema(
-      SharedTypeView<TypeStructure> p, SharedTypeSchemaView<TypeStructure> q,
-      {required AstNode? astNodeForTesting});
-
-  /// Matches type schema [p] against type [q] as a subtype against supertype,
-  /// assuming [p] is the constraining type schema, and [q] contains the type
-  /// parameters to constrain, and returns true if [p] is a subtype of [q]
-  /// under some constraints, and false otherwise.
-  ///
-  /// As the generator computes the constraints making the relation possible,
-  /// it changes its internal state. The current state of the generator can be
-  /// obtained by [currentState], and the generator can be restored to a state
-  /// via [restoreState]. All of the shared constraint generation methods are
-  /// supposed to restore the generator to the prior state in case of a
-  /// mismatch, taking that responsibility away from the caller.
-  ///
-  /// The algorithm for subtype constraint generation is described in
-  /// https://github.com/dart-lang/language/blob/main/resources/type-system/inference.md#subtype-constraint-generation
-  bool performSubtypeConstraintGenerationLeftSchema(
-      SharedTypeSchemaView<TypeStructure> p, SharedTypeView<TypeStructure> q,
-      {required AstNode? astNodeForTesting});
-
-  /// [performSubtypeConstraintGenerationInternal] should be implemented by
-  /// concrete classes implementing [TypeConstraintGenerator]. The
-  /// implementations of [performSubtypeConstraintGenerationLeftSchema] and
-  /// [performSubtypeConstraintGenerationRightSchema] are provided by mixing in
-  /// [TypeConstraintGeneratorMixin], which defines
-  /// [performSubtypeConstraintGenerationLeftSchema] and
-  /// [performSubtypeConstraintGenerationRightSchema] in terms of
-  /// [performSubtypeConstraintGenerationInternal].
-  ///
-  /// The main purpose of this method is to avoid code duplication in the
-  /// concrete classes implementing [TypeAnalyzerOperations], so they can
-  /// implement only one member, in this case
-  /// [performSubtypeConstraintGenerationInternal], and receive the
-  /// implementation of both [performSubtypeConstraintGenerationLeftSchema] and
-  /// [performSubtypeConstraintGenerationRightSchema] from the mixin.
-  bool performSubtypeConstraintGenerationInternal(
-      TypeStructure p, TypeStructure q,
-      {required bool leftSchema, required AstNode? astNodeForTesting});
-
-  /// Matches type [p] against type schema [q] as a subtype against supertype
-  /// and returns true if [p] and [q] are both FutureOr, with or without
-  /// nullability suffixes as defined by
-  /// [enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr], and [p] is
-  /// a subtype of [q] under some constraints imposed on type parameters
-  /// occurring in [p], and false otherwise.
-  ///
-  /// As the generator computes the constraints making the relation possible,
-  /// it changes its internal state. The current state of the generator can be
-  /// obtained by [currentState], and the generator can be restored to a state
-  /// via [restoreState]. All of the shared constraint generation methods are
-  /// supposed to restore the generator to the prior state in case of a
-  /// mismatch, taking that responsibility away from the caller.
-  bool performSubtypeConstraintGenerationForFutureOrRightSchema(
-      SharedTypeView<TypeStructure> p, SharedTypeSchemaView<TypeStructure> q,
-      {required AstNode? astNodeForTesting}) {
-    return _performSubtypeConstraintGenerationForFutureOrInternal(
-        p.unwrapTypeView(), q.unwrapTypeSchemaView(),
-        leftSchema: false, astNodeForTesting: astNodeForTesting);
-  }
-
-  /// Matches type schema [p] against type [q] as a subtype against supertype
-  /// and returns true if [p] and [q] are both FutureOr, with or without
-  /// nullability suffixes as defined by
-  /// [enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr], and [p] is
-  /// a subtype of [q] under some constraints imposed on type parameters
-  /// occurring in [q], and false otherwise.
-  ///
-  /// As the generator computes the constraints making the relation possible,
-  /// it changes its internal state. The current state of the generator can be
-  /// obtained by [currentState], and the generator can be restored to a state
-  /// via [restoreState]. All of the shared constraint generation methods are
-  /// supposed to restore the generator to the prior state in case of a
-  /// mismatch, taking that responsibility away from the caller.
-  bool performSubtypeConstraintGenerationForFutureOrLeftSchema(
-      SharedTypeSchemaView<TypeStructure> p, SharedTypeView<TypeStructure> q,
-      {required AstNode? astNodeForTesting}) {
-    return _performSubtypeConstraintGenerationForFutureOrInternal(
-        p.unwrapTypeSchemaView(), q.unwrapTypeView(),
-        leftSchema: true, astNodeForTesting: astNodeForTesting);
-  }
-
-  bool _performSubtypeConstraintGenerationForFutureOrInternal(
-      TypeStructure p, TypeStructure q,
-      {required bool leftSchema, required AstNode? astNodeForTesting}) {
-    // If `Q` is `FutureOr<Q0>` the match holds under constraint set `C`:
-    if (typeAnalyzerOperations.matchFutureOrInternal(q) case TypeStructure q0?
-        when enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr ||
-            q.nullabilitySuffix == NullabilitySuffix.none) {
-      final TypeConstraintGeneratorState state = currentState;
-
-      // If `P` is `FutureOr<P0>` and `P0` is a subtype match for `Q0` under
-      // constraint set `C`.
-      if (typeAnalyzerOperations.matchFutureOrInternal(p) case TypeStructure p0?
-          when enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr ||
-              p.nullabilitySuffix == NullabilitySuffix.none) {
-        if (performSubtypeConstraintGenerationInternal(p0, q0,
-            leftSchema: leftSchema, astNodeForTesting: astNodeForTesting)) {
-          return true;
-        }
-        restoreState(state);
-      }
-
-      // Or if `P` is a subtype match for `Future<Q0>` under non-empty
-      // constraint set `C`.
-      bool isMatchWithFuture = performSubtypeConstraintGenerationInternal(
-          p, typeAnalyzerOperations.futureTypeInternal(q0),
-          leftSchema: leftSchema, astNodeForTesting: astNodeForTesting);
-      bool matchWithFutureAddsConstraints = currentState != state;
-      if (isMatchWithFuture && matchWithFutureAddsConstraints) {
-        return true;
-      }
-      restoreState(state);
-
-      // Or if `P` is a subtype match for `Q0` under constraint set `C`.
-      if (performSubtypeConstraintGenerationInternal(p, q0,
-          leftSchema: leftSchema, astNodeForTesting: astNodeForTesting)) {
-        return true;
-      }
-      restoreState(state);
-
-      // Or if `P` is a subtype match for `Future<Q0>` under empty
-      // constraint set `C`.
-      if (isMatchWithFuture && !matchWithFutureAddsConstraints) {
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-  /// Matches [p] against [q] as a subtype against supertype and returns true if
-  /// [p] and [q] are both type declaration types as defined by the enum
-  /// [TypeDeclarationKind], and [p] is a subtype of [q] under some constraints
-  /// imposed on type parameters occurring in [q], and false otherwise.
-  ///
-  /// An invariant of the type inference is that only [p] or [q] may be a
-  /// schema (in other words, may contain the unknown type `_`); the other must
-  /// be simply a type. If [leftSchema] is `true`, [p] may contain `_`; if it is
-  /// `false`, [q] may contain `_`.
-  ///
-  /// As the generator computes the constraints making the relation possible, it
-  /// changes its internal state. The current state of the generator can be
-  /// obtained by [currentState], and the generator can be restored to a state
-  /// via [restoreState]. All of the shared constraint generation methods are
-  /// supposed to restore the generator to the prior state in case of a
-  /// mismatch, taking that responsibility away from the caller.
-  bool? performSubtypeConstraintGenerationForTypeDeclarationTypes(
-      TypeStructure p, TypeStructure q,
-      {required bool leftSchema, required AstNode? astNodeForTesting}) {
-    switch ((
-      typeAnalyzerOperations.matchTypeDeclarationType(new SharedTypeView(p)),
-      typeAnalyzerOperations.matchTypeDeclarationType(new SharedTypeView(q))
-    )) {
-      // If `P` is `C<M0, ..., Mk> and `Q` is `C<N0, ..., Nk>`, then the match
-      // holds under constraints `C0 + ... + Ck`:
-      //   If `Mi` is a subtype match for `Ni` with respect to L under
-      //   constraints `Ci`.
-      case (
-            TypeDeclarationMatchResult(
-              typeDeclarationKind: TypeDeclarationKind pTypeDeclarationKind,
-              typeDeclaration: TypeDeclaration pDeclarationObject,
-              typeArguments: List<TypeStructure> pTypeArguments
-            ),
-            TypeDeclarationMatchResult(
-              typeDeclarationKind: TypeDeclarationKind qTypeDeclarationKind,
-              typeDeclaration: TypeDeclaration qDeclarationObject,
-              typeArguments: List<TypeStructure> qTypeArguments
-            )
-          )
-          when pTypeDeclarationKind == qTypeDeclarationKind &&
-              pDeclarationObject == qDeclarationObject:
-        return _interfaceTypeArguments(
-            pDeclarationObject, pTypeArguments, qTypeArguments, leftSchema,
-            astNodeForTesting: astNodeForTesting);
-
-      case (TypeDeclarationMatchResult(), TypeDeclarationMatchResult()):
-        return _interfaceTypes(p, q, leftSchema,
-            astNodeForTesting: astNodeForTesting);
-
-      case (
-          TypeDeclarationMatchResult? pMatched,
-          TypeDeclarationMatchResult? qMatched
-        ):
-        assert(pMatched == null || qMatched == null);
-        return null;
-    }
-  }
-
-  /// Match arguments [pTypeArguments] of P against arguments [qTypeArguments]
-  /// of Q, taking into account the variance of type variables in [declaration].
-  /// If returns `false`, the constraints are unchanged.
-  bool _interfaceTypeArguments(
-      TypeDeclaration declaration,
-      List<TypeStructure> pTypeArguments,
-      List<TypeStructure> qTypeArguments,
-      bool leftSchema,
-      {required AstNode? astNodeForTesting}) {
-    assert(pTypeArguments.length == qTypeArguments.length);
-
-    final TypeConstraintGeneratorState state = currentState;
-
-    for (int i = 0; i < pTypeArguments.length; i++) {
-      Variance variance =
-          typeAnalyzerOperations.getTypeParameterVariance(declaration, i);
-      TypeStructure M = pTypeArguments[i];
-      TypeStructure N = qTypeArguments[i];
-      if ((variance == Variance.covariant || variance == Variance.invariant) &&
-          !performSubtypeConstraintGenerationInternal(M, N,
-              leftSchema: leftSchema, astNodeForTesting: astNodeForTesting)) {
-        restoreState(state);
-        return false;
-      }
-      if ((variance == Variance.contravariant ||
-              variance == Variance.invariant) &&
-          !performSubtypeConstraintGenerationInternal(N, M,
-              leftSchema: !leftSchema, astNodeForTesting: astNodeForTesting)) {
-        restoreState(state);
-        return false;
-      }
-    }
-
-    return true;
-  }
-
-  bool _interfaceTypes(TypeStructure p, TypeStructure q, bool leftSchema,
-      {required AstNode? astNodeForTesting}) {
-    if (p.nullabilitySuffix != NullabilitySuffix.none) {
-      return false;
-    }
-
-    if (q.nullabilitySuffix != NullabilitySuffix.none) {
-      return false;
-    }
-
-    // If `P` is `C0<M0, ..., Mk>` and `Q` is `C1<N0, ..., Nj>` then the match
-    // holds with respect to `L` under constraints `C`:
-    //   If `C1<B0, ..., Bj>` is a superinterface of `C0<M0, ..., Mk>` and
-    //   `C1<B0, ..., Bj>` is a subtype match for `C1<N0, ..., Nj>` with
-    //   respect to `L` under constraints `C`.
-
-    if ((
-      typeAnalyzerOperations.matchTypeDeclarationType(new SharedTypeView(p)),
-      typeAnalyzerOperations.matchTypeDeclarationType(new SharedTypeView(q))
-    )
-        case (
-          TypeDeclarationMatchResult(
-            typeDeclarationType: TypeDeclarationType pTypeDeclarationType
-          ),
-          TypeDeclarationMatchResult(
-            typeDeclaration: TypeDeclaration qTypeDeclaration,
-            typeArguments: List<TypeStructure> qTypeArguments
-          )
-        )) {
-      if (getTypeArgumentsAsInstanceOf(pTypeDeclarationType, qTypeDeclaration)
-          case List<TypeStructure> typeArguments) {
-        return _interfaceTypeArguments(
-            qTypeDeclaration, typeArguments, qTypeArguments, leftSchema,
-            astNodeForTesting: astNodeForTesting);
-      }
-    }
-
-    return false;
-  }
-
-  /// Returns the type arguments of the supertype of [type] that is an
-  /// instantiation of [typeDeclaration]. If none of the supertypes of [type]
-  /// are instantiations of [typeDeclaration], returns null.
-  List<TypeStructure>? getTypeArgumentsAsInstanceOf(
-      TypeDeclarationType type, TypeDeclaration typeDeclaration);
-}
-
 /// Representation of the state of [TypeConstraintGenerator].
 ///
 /// The state can be obtained via [TypeConstraintGenerator.currentState]. A
@@ -1372,31 +1539,3 @@
 /// constraints generated so far. Since the count only increases as the
 /// generator proceeds, restoring to a state means discarding some constraints.
 extension type TypeConstraintGeneratorState(int count) {}
-
-mixin TypeConstraintGeneratorMixin<
-        TypeStructure extends SharedTypeStructure<TypeStructure>,
-        Variable extends Object,
-        InferableParameter extends Object,
-        TypeDeclarationType extends Object,
-        TypeDeclaration extends Object,
-        AstNode extends Object>
-    on TypeConstraintGenerator<TypeStructure, Variable, InferableParameter,
-        TypeDeclarationType, TypeDeclaration, AstNode> {
-  @override
-  bool performSubtypeConstraintGenerationLeftSchema(
-      SharedTypeSchemaView<TypeStructure> p, SharedTypeView<TypeStructure> q,
-      {required AstNode? astNodeForTesting}) {
-    return performSubtypeConstraintGenerationInternal(
-        p.unwrapTypeSchemaView(), q.unwrapTypeView(),
-        leftSchema: true, astNodeForTesting: astNodeForTesting);
-  }
-
-  @override
-  bool performSubtypeConstraintGenerationRightSchema(
-      SharedTypeView<TypeStructure> p, SharedTypeSchemaView<TypeStructure> q,
-      {required AstNode? astNodeForTesting}) {
-    return performSubtypeConstraintGenerationInternal(
-        p.unwrapTypeView(), q.unwrapTypeSchemaView(),
-        leftSchema: false, astNodeForTesting: astNodeForTesting);
-  }
-}
diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart
index 32e8e68..58beeed 100644
--- a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart
@@ -11,10 +11,10 @@
 /// `constraint <: typeParameter` otherwise.
 class GeneratedTypeConstraint<
     TypeStructure extends SharedTypeStructure<TypeStructure>,
-    TypeParameter extends Object,
+    TypeParameterStructure extends SharedTypeParameterStructure<TypeStructure>,
     Variable extends Object> {
   /// The type parameter that is constrained by [constraint].
-  final TypeParameter typeParameter;
+  final TypeParameterStructure typeParameter;
 
   /// The type schema constraining the type parameter.
   final SharedTypeSchemaView<TypeStructure> constraint;
@@ -40,7 +40,7 @@
 /// A constraint on a type parameter that we're inferring.
 class MergedTypeConstraint<
     TypeStructure extends SharedTypeStructure<TypeStructure>,
-    TypeParameter extends Object,
+    TypeParameterStructure extends SharedTypeParameterStructure<TypeStructure>,
     Variable extends Object,
     TypeDeclarationType extends Object,
     TypeDeclaration extends Object> {
@@ -90,7 +90,7 @@
   SharedTypeSchemaView<TypeStructure> upper;
 
   /// Where this constraint comes from, used for error messages.
-  TypeConstraintOrigin<TypeStructure, Variable, TypeParameter,
+  TypeConstraintOrigin<TypeStructure, Variable, TypeParameterStructure,
       TypeDeclarationType, TypeDeclaration> origin;
 
   MergedTypeConstraint(
@@ -100,8 +100,8 @@
       {required String typeParameterName,
       required SharedTypeView<TypeStructure> boundType,
       required SharedTypeView<TypeStructure> extendsType,
-      required TypeAnalyzerOperations<TypeStructure, Variable, TypeParameter,
-              TypeDeclarationType, TypeDeclaration>
+      required TypeAnalyzerOperations<TypeStructure, Variable,
+              TypeParameterStructure, TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations})
       : this(
             origin: new TypeConstraintFromExtendsClause(
@@ -112,13 +112,13 @@
             upper: typeAnalyzerOperations.typeToSchema(extendsType),
             lower: typeAnalyzerOperations.unknownType);
 
-  MergedTypeConstraint<TypeStructure, TypeParameter, Variable,
+  MergedTypeConstraint<TypeStructure, TypeParameterStructure, Variable,
       TypeDeclarationType, TypeDeclaration> clone() {
     return new MergedTypeConstraint(lower: lower, upper: upper, origin: origin);
   }
 
   bool isEmpty(
-      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameterStructure,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     return lower is SharedUnknownTypeStructure &&
@@ -127,7 +127,7 @@
 
   bool isSatisfiedBy(
       SharedTypeView<TypeStructure> type,
-      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameterStructure,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     return typeAnalyzerOperations.typeIsSubtypeOfTypeSchema(type, upper) &&
@@ -135,9 +135,9 @@
   }
 
   void mergeIn(
-      GeneratedTypeConstraint<TypeStructure, TypeParameter, Variable>
+      GeneratedTypeConstraint<TypeStructure, TypeParameterStructure, Variable>
           generatedTypeConstraint,
-      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameterStructure,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     if (generatedTypeConstraint.isUpper) {
@@ -149,72 +149,38 @@
     }
   }
 
-  void mergeInTypeSchemaUpper(
-      SharedTypeSchemaView<TypeStructure> constraint,
-      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameter,
-              TypeDeclarationType, TypeDeclaration>
-          typeAnalyzerOperations) {
-    upper = typeAnalyzerOperations.typeSchemaGlb(upper, constraint);
-  }
-
   void mergeInTypeSchemaLower(
       SharedTypeSchemaView<TypeStructure> constraint,
-      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameterStructure,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     lower = typeAnalyzerOperations.typeSchemaLub(lower, constraint);
   }
 
+  void mergeInTypeSchemaUpper(
+      SharedTypeSchemaView<TypeStructure> constraint,
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameterStructure,
+              TypeDeclarationType, TypeDeclaration>
+          typeAnalyzerOperations) {
+    upper = typeAnalyzerOperations.typeSchemaGlb(upper, constraint);
+  }
+
   @override
   String toString() {
     return '${lower} <: <type> <: ${upper}';
   }
 }
 
-/// The origin of a type constraint, for the purposes of producing a human
-/// readable error message during type inference as well as determining whether
-/// the constraint was used to fix the type parameter or not.
-abstract class TypeConstraintOrigin<
-    TypeStructure extends SharedTypeStructure<TypeStructure>,
-    Variable extends Object,
-    TypeParameter extends Object,
-    TypeDeclarationType extends Object,
-    TypeDeclaration extends Object> {
-  const TypeConstraintOrigin();
-
-  List<String> formatError(
-      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameter,
-              TypeDeclarationType, TypeDeclaration>
-          typeAnalyzerOperations);
-}
-
-class UnknownTypeConstraintOrigin<
-        TypeStructure extends SharedTypeStructure<TypeStructure>,
-        Variable extends Object,
-        InferableParameter extends Object,
-        TypeDeclarationType extends Object,
-        TypeDeclaration extends Object>
-    extends TypeConstraintOrigin<TypeStructure, Variable, InferableParameter,
-        TypeDeclarationType, TypeDeclaration> {
-  const UnknownTypeConstraintOrigin();
-
-  @override
-  List<String> formatError(
-      TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
-              TypeDeclarationType, TypeDeclaration>
-          typeAnalyzerOperations) {
-    return <String>[];
-  }
-}
-
 class TypeConstraintFromArgument<
         TypeStructure extends SharedTypeStructure<TypeStructure>,
         Variable extends Object,
-        InferableParameter extends Object,
+        // Work around https://github.com/dart-lang/dart_style/issues/1568
+        // ignore: lines_longer_than_80_chars
+        TypeParameterStructure extends SharedTypeParameterStructure<TypeStructure>,
         TypeDeclarationType extends Object,
         TypeDeclaration extends Object>
-    extends TypeConstraintOrigin<TypeStructure, Variable, InferableParameter,
-        TypeDeclarationType, TypeDeclaration> {
+    extends TypeConstraintOrigin<TypeStructure, Variable,
+        TypeParameterStructure, TypeDeclarationType, TypeDeclaration> {
   final SharedTypeView<TypeStructure> argumentType;
   final SharedTypeView<TypeStructure> parameterType;
   final String parameterName;
@@ -230,7 +196,7 @@
 
   @override
   List<String> formatError(
-      TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameterStructure,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     // TODO(cstefantsova): we should highlight the span. That would be more
@@ -259,11 +225,13 @@
 class TypeConstraintFromExtendsClause<
         TypeStructure extends SharedTypeStructure<TypeStructure>,
         Variable extends Object,
-        InferableParameter extends Object,
+        // Work around https://github.com/dart-lang/dart_style/issues/1568
+        // ignore: lines_longer_than_80_chars
+        TypeParameterStructure extends SharedTypeParameterStructure<TypeStructure>,
         TypeDeclarationType extends Object,
         TypeDeclaration extends Object>
-    extends TypeConstraintOrigin<TypeStructure, Variable, InferableParameter,
-        TypeDeclarationType, TypeDeclaration> {
+    extends TypeConstraintOrigin<TypeStructure, Variable,
+        TypeParameterStructure, TypeDeclarationType, TypeDeclaration> {
   /// Name of the type parameter with the extends clause.
   final String typeParameterName;
 
@@ -286,7 +254,7 @@
 
   @override
   List<String> formatError(
-      TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameterStructure,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     String boundStr = boundType.getDisplayString();
@@ -303,11 +271,13 @@
         Type extends SharedTypeStructure<Type>,
         TypeSchema extends SharedTypeStructure<TypeSchema>,
         Variable extends Object,
-        InferableParameter extends Object,
+        // Work around https://github.com/dart-lang/dart_style/issues/1568
+        // ignore: lines_longer_than_80_chars
+        TypeParameterStructure extends SharedTypeParameterStructure<TypeStructure>,
         TypeDeclarationType extends Object,
         TypeDeclaration extends Object>
-    extends TypeConstraintOrigin<TypeStructure, Variable, InferableParameter,
-        TypeDeclarationType, TypeDeclaration> {
+    extends TypeConstraintOrigin<TypeStructure, Variable,
+        TypeParameterStructure, TypeDeclarationType, TypeDeclaration> {
   final Type contextType;
   final Type functionType;
 
@@ -316,7 +286,7 @@
 
   @override
   List<String> formatError(
-      TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameterStructure,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     return [
@@ -332,11 +302,13 @@
         Type extends SharedTypeStructure<Type>,
         TypeSchema extends SharedTypeStructure<TypeSchema>,
         Variable extends Object,
-        InferableParameter extends Object,
+        // Work around https://github.com/dart-lang/dart_style/issues/1568
+        // ignore: lines_longer_than_80_chars
+        TypeParameterStructure extends SharedTypeParameterStructure<TypeStructure>,
         TypeDeclarationType extends Object,
         TypeDeclaration extends Object>
-    extends TypeConstraintOrigin<TypeStructure, Variable, InferableParameter,
-        TypeDeclarationType, TypeDeclaration> {
+    extends TypeConstraintOrigin<TypeStructure, Variable,
+        TypeParameterStructure, TypeDeclarationType, TypeDeclaration> {
   final Type contextType;
   final Type declaredType;
 
@@ -345,7 +317,7 @@
 
   @override
   List<String> formatError(
-      TypeAnalyzerOperations<TypeStructure, Variable, InferableParameter,
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameterStructure,
               TypeDeclarationType, TypeDeclaration>
           typeAnalyzerOperations) {
     return [
@@ -355,3 +327,41 @@
     ];
   }
 }
+
+/// The origin of a type constraint, for the purposes of producing a human
+/// readable error message during type inference as well as determining whether
+/// the constraint was used to fix the type parameter or not.
+abstract class TypeConstraintOrigin<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    Variable extends Object,
+    TypeParameterStructure extends SharedTypeParameterStructure<TypeStructure>,
+    TypeDeclarationType extends Object,
+    TypeDeclaration extends Object> {
+  const TypeConstraintOrigin();
+
+  List<String> formatError(
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameterStructure,
+              TypeDeclarationType, TypeDeclaration>
+          typeAnalyzerOperations);
+}
+
+class UnknownTypeConstraintOrigin<
+        TypeStructure extends SharedTypeStructure<TypeStructure>,
+        Variable extends Object,
+        // Work around https://github.com/dart-lang/dart_style/issues/1568
+        // ignore: lines_longer_than_80_chars
+        TypeParameterStructure extends SharedTypeParameterStructure<TypeStructure>,
+        TypeDeclarationType extends Object,
+        TypeDeclaration extends Object>
+    extends TypeConstraintOrigin<TypeStructure, Variable,
+        TypeParameterStructure, TypeDeclarationType, TypeDeclaration> {
+  const UnknownTypeConstraintOrigin();
+
+  @override
+  List<String> formatError(
+      TypeAnalyzerOperations<TypeStructure, Variable, TypeParameterStructure,
+              TypeDeclarationType, TypeDeclaration>
+          typeAnalyzerOperations) {
+    return <String>[];
+  }
+}
diff --git a/pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart b/pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart
index c775ee0..691cbed 100644
--- a/pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart
@@ -11,6 +11,31 @@
     implements SharedTypeStructure<TypeStructure> {}
 
 /// Common interface for data structures used by the implementations to
+/// represent function types.
+abstract interface class SharedFunctionTypeStructure<
+    TypeStructure extends SharedTypeStructure<TypeStructure>,
+    TypeParameterStructure extends SharedTypeParameterStructure<TypeStructure>,
+    FunctionParameterStructure extends SharedNamedFunctionParameterStructure<
+        TypeStructure>> implements SharedTypeStructure<TypeStructure> {
+  /// All the positional parameter types, starting with the required ones, and
+  /// followed by the optional ones.
+  List<TypeStructure> get positionalParameterTypes;
+
+  /// The number of elements of [positionalParameterTypes] that are required
+  /// parameters.
+  int get requiredPositionalParameterCount;
+
+  /// The return type.
+  TypeStructure get returnType;
+
+  /// All the named parameters, sorted by name.
+  List<FunctionParameterStructure> get sortedNamedParameters;
+
+  /// The type parameters of the function type.
+  List<TypeParameterStructure> get typeFormals;
+}
+
+/// Common interface for data structures used by the implementations to
 /// represent a type resulting from a compile-time error.
 ///
 /// The implementations may choose to suppress further errors that arise from
@@ -20,6 +45,20 @@
     implements SharedTypeStructure<TypeStructure> {}
 
 /// Common interface for data structures used by the implementations to
+/// represent a named parameter of a function type.
+abstract interface class SharedNamedFunctionParameterStructure<
+    TypeStructure extends SharedTypeStructure<TypeStructure>> {
+  /// Whether this named parameter is required.
+  bool get isRequired;
+
+  /// The name of the parameter.
+  String get name;
+
+  /// The type of the parameter.
+  TypeStructure get type;
+}
+
+/// Common interface for data structures used by the implementations to
 /// represent a name/type pair.
 abstract interface class SharedNamedTypeStructure<
     TypeStructure extends SharedTypeStructure<TypeStructure>> {
@@ -32,12 +71,21 @@
 abstract interface class SharedRecordTypeStructure<
         TypeStructure extends SharedTypeStructure<TypeStructure>>
     implements SharedTypeStructure<TypeStructure> {
+  /// All the named fields, sorted by name.
   List<SharedNamedTypeStructure<TypeStructure>> get namedTypes;
 
   List<TypeStructure> get positionalTypes;
 }
 
 /// Common interface for data structures used by the implementations to
+/// represent a generic type parameter.
+abstract interface class SharedTypeParameterStructure<
+    TypeStructure extends SharedTypeStructure<TypeStructure>> {
+  /// The name of the type parameter, for display to the user.
+  String get displayName;
+}
+
+/// Common interface for data structures used by the implementations to
 /// represent a type.
 abstract interface class SharedTypeStructure<
     TypeStructure extends SharedTypeStructure<TypeStructure>> {
@@ -71,34 +119,53 @@
         TypeStructure extends SharedTypeStructure<TypeStructure>>
     implements SharedTypeStructure<TypeStructure> {}
 
-extension type SharedTypeView<
-        TypeStructure extends SharedTypeStructure<TypeStructure>>(
-    SharedTypeStructure<TypeStructure> _typeStructure) implements Object {
-  TypeStructure unwrapTypeView() => _typeStructure as TypeStructure;
-
-  NullabilitySuffix get nullabilitySuffix => _typeStructure.nullabilitySuffix;
-
-  String getDisplayString() => _typeStructure.getDisplayString();
-}
+extension type SharedDynamicTypeSchemaView<
+            TypeStructure extends SharedTypeStructure<TypeStructure>>(
+        SharedDynamicTypeStructure<TypeStructure> _typeStructure)
+    implements SharedTypeSchemaView<TypeStructure> {}
 
 extension type SharedDynamicTypeView<
             TypeStructure extends SharedTypeStructure<TypeStructure>>(
         SharedDynamicTypeStructure<TypeStructure> _typeStructure)
     implements SharedTypeView<TypeStructure> {}
 
+extension type SharedInvalidTypeSchemaView<
+            TypeStructure extends SharedTypeStructure<TypeStructure>>(
+        SharedInvalidTypeStructure<TypeStructure> _typeStructure)
+    implements SharedTypeSchemaView<TypeStructure> {}
+
 extension type SharedInvalidTypeView<
             TypeStructure extends SharedTypeStructure<TypeStructure>>(
         SharedInvalidTypeStructure<TypeStructure> _typeStructure)
     implements SharedTypeView<TypeStructure> {}
 
+extension type SharedNamedTypeSchemaView<
+        TypeStructure extends SharedTypeStructure<TypeStructure>>(
+    SharedNamedTypeStructure<TypeStructure> _typeStructure) implements Object {}
+
 extension type SharedNamedTypeView<
             TypeStructure extends SharedTypeStructure<TypeStructure>>(
         SharedNamedTypeStructure<TypeStructure> _namedTypeStructure)
     implements Object {
+  String get name => _namedTypeStructure.name;
+
   SharedTypeView<TypeStructure> get type =>
       new SharedTypeView(_namedTypeStructure.type);
+}
 
-  String get name => _namedTypeStructure.name;
+extension type SharedRecordTypeSchemaView<
+            TypeStructure extends SharedTypeStructure<TypeStructure>>(
+        SharedRecordTypeStructure<TypeStructure> _typeStructure)
+    implements SharedTypeSchemaView<TypeStructure> {
+  List<SharedNamedTypeSchemaView<TypeStructure>> get namedTypes {
+    return _typeStructure.namedTypes
+        as List<SharedNamedTypeSchemaView<TypeStructure>>;
+  }
+
+  List<SharedTypeSchemaView<TypeStructure>> get positionalTypes {
+    return _typeStructure.positionalTypes
+        as List<SharedTypeSchemaView<TypeStructure>>;
+  }
 }
 
 extension type SharedRecordTypeView<
@@ -116,48 +183,24 @@
   }
 }
 
-extension type SharedVoidTypeView<
-            TypeStructure extends SharedTypeStructure<TypeStructure>>(
-        SharedVoidTypeStructure<TypeStructure> _typeStructure)
-    implements SharedTypeView<TypeStructure> {}
-
 extension type SharedTypeSchemaView<
         TypeStructure extends SharedTypeStructure<TypeStructure>>(
     SharedTypeStructure<TypeStructure> _typeStructure) implements Object {
-  TypeStructure unwrapTypeSchemaView() => _typeStructure as TypeStructure;
-
   NullabilitySuffix get nullabilitySuffix => _typeStructure.nullabilitySuffix;
 
   String getDisplayString() => _typeStructure.getDisplayString();
+
+  TypeStructure unwrapTypeSchemaView() => _typeStructure as TypeStructure;
 }
 
-extension type SharedDynamicTypeSchemaView<
-            TypeStructure extends SharedTypeStructure<TypeStructure>>(
-        SharedDynamicTypeStructure<TypeStructure> _typeStructure)
-    implements SharedTypeSchemaView<TypeStructure> {}
-
-extension type SharedInvalidTypeSchemaView<
-            TypeStructure extends SharedTypeStructure<TypeStructure>>(
-        SharedInvalidTypeStructure<TypeStructure> _typeStructure)
-    implements SharedTypeSchemaView<TypeStructure> {}
-
-extension type SharedNamedTypeSchemaView<
+extension type SharedTypeView<
         TypeStructure extends SharedTypeStructure<TypeStructure>>(
-    SharedNamedTypeStructure<TypeStructure> _typeStructure) implements Object {}
+    SharedTypeStructure<TypeStructure> _typeStructure) implements Object {
+  NullabilitySuffix get nullabilitySuffix => _typeStructure.nullabilitySuffix;
 
-extension type SharedRecordTypeSchemaView<
-            TypeStructure extends SharedTypeStructure<TypeStructure>>(
-        SharedRecordTypeStructure<TypeStructure> _typeStructure)
-    implements SharedTypeSchemaView<TypeStructure> {
-  List<SharedNamedTypeSchemaView<TypeStructure>> get namedTypes {
-    return _typeStructure.namedTypes
-        as List<SharedNamedTypeSchemaView<TypeStructure>>;
-  }
+  String getDisplayString() => _typeStructure.getDisplayString();
 
-  List<SharedTypeSchemaView<TypeStructure>> get positionalTypes {
-    return _typeStructure.positionalTypes
-        as List<SharedTypeSchemaView<TypeStructure>>;
-  }
+  TypeStructure unwrapTypeView() => _typeStructure as TypeStructure;
 }
 
 /// Note that there is no `SharedUnknownTypeView`, only
@@ -174,6 +217,11 @@
         SharedVoidTypeStructure<TypeStructure> _typeStructure)
     implements SharedTypeSchemaView<TypeStructure> {}
 
+extension type SharedVoidTypeView<
+            TypeStructure extends SharedTypeStructure<TypeStructure>>(
+        SharedVoidTypeStructure<TypeStructure> _typeStructure)
+    implements SharedTypeView<TypeStructure> {}
+
 /// Extension methods of [SharedTypeStructureExtension] are intended to avoid
 /// explicit null-testing on types before wrapping them into [SharedTypeView] or
 /// [SharedTypeSchemaView].
@@ -193,13 +241,13 @@
 extension SharedTypeStructureExtension<
         TypeStructure extends SharedTypeStructure<TypeStructure>>
     on SharedTypeStructure<TypeStructure> {
-  SharedTypeView<TypeStructure> wrapSharedTypeView() {
-    return new SharedTypeView(this);
-  }
-
   SharedTypeSchemaView<TypeStructure> wrapSharedTypeSchemaView() {
     return new SharedTypeSchemaView(this);
   }
+
+  SharedTypeView<TypeStructure> wrapSharedTypeView() {
+    return new SharedTypeView(this);
+  }
 }
 
 extension SharedTypeStructureMapEntryExtension<
diff --git a/pkg/_fe_analyzer_shared/pubspec.yaml b/pkg/_fe_analyzer_shared/pubspec.yaml
index 9e2eac0..bedf240 100644
--- a/pkg/_fe_analyzer_shared/pubspec.yaml
+++ b/pkg/_fe_analyzer_shared/pubspec.yaml
@@ -1,5 +1,5 @@
 name: _fe_analyzer_shared
-version: 73.0.0
+version: 74.0.0
 description: Logic that is shared between the front_end and analyzer packages.
 repository: https://github.com/dart-lang/sdk/tree/main/pkg/_fe_analyzer_shared
 
diff --git a/pkg/_fe_analyzer_shared/test/exhaustiveness/data/unknown.dart b/pkg/_fe_analyzer_shared/test/exhaustiveness/data/unknown.dart
index daba176..8f08622 100644
--- a/pkg/_fe_analyzer_shared/test/exhaustiveness/data/unknown.dart
+++ b/pkg/_fe_analyzer_shared/test/exhaustiveness/data/unknown.dart
@@ -2,7 +2,10 @@
 // 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.
 
-final unknownShouldNotIncludeNull = /*type=Null*/ switch (null) {
-  int(:var isEven) when isEven /*space=?*/ => 1,
+final unknownShouldNotIncludeNull = /*fields={isEven:-},
+ type=Null
+*/
+    switch (null) {
+  int(:var isEven) when isEven /*space=int(isEven: bool)*/ => 1,
   _ /*space=Null*/ => 0,
 };
diff --git a/pkg/_fe_analyzer_shared/test/exhaustiveness/data/when.dart b/pkg/_fe_analyzer_shared/test/exhaustiveness/data/when.dart
index a64aff5..34b2faf 100644
--- a/pkg/_fe_analyzer_shared/test/exhaustiveness/data/when.dart
+++ b/pkg/_fe_analyzer_shared/test/exhaustiveness/data/when.dart
@@ -45,7 +45,7 @@
    type=A
   */
   switch (a) {
-    /*space=?*/ case B(:var field) when field > 0:
+    /*space=B(field: int)*/ case B(:var field) when field > 0:
     /*space=C(field: int)*/ case C(:var field):
   }
   /*
@@ -57,6 +57,6 @@
   */
   switch (a) {
     /*space=B(field: int)*/ case B(:var field):
-    /*space=?*/ case C(:var field) when field > 0:
+    /*space=C(field: int)*/ case C(:var field) when field > 0:
   }
 }
diff --git a/pkg/_fe_analyzer_shared/test/exhaustiveness/report_errors_test.dart b/pkg/_fe_analyzer_shared/test/exhaustiveness/report_errors_test.dart
index d7038ca..d8915fc 100644
--- a/pkg/_fe_analyzer_shared/test/exhaustiveness/report_errors_test.dart
+++ b/pkg/_fe_analyzer_shared/test/exhaustiveness/report_errors_test.dart
@@ -36,61 +36,74 @@
 
     test('exhaustiveness', () {
       // Case matching top type covers all subtypes.
-      expectReportErrors(env, a, [a]);
-      expectReportErrors(env, b, [a]);
-      expectReportErrors(env, d, [a]);
+      expectExhaustiveness(env, a, [a]);
+      expectExhaustiveness(env, b, [a]);
+      expectExhaustiveness(env, d, [a]);
 
       // Case matching subtype doesn't cover supertype.
-      expectReportErrors(env, a, [b], 'A is not exhaustively matched by B.');
-      expectReportErrors(env, b, [b]);
-      expectReportErrors(env, d, [b]);
-      expectReportErrors(env, e, [b]);
+      expectExhaustiveness(env, a, [b],
+          errors: 'A is not exhaustively matched by B.');
+      expectExhaustiveness(env, b, [b]);
+      expectExhaustiveness(env, d, [b]);
+      expectExhaustiveness(env, e, [b]);
 
       // Matching subtypes of sealed type is exhaustive.
-      expectReportErrors(env, a, [b, c]);
-      expectReportErrors(env, a, [d, e, f]);
-      expectReportErrors(env, a, [b, f]);
-      expectReportErrors(
-          env, a, [c, d], 'A is not exhaustively matched by C|D.');
-      expectReportErrors(
-          env, f, [g, h], 'F is not exhaustively matched by G|H.');
+      expectExhaustiveness(env, a, [b, c]);
+      expectExhaustiveness(env, a, [d, e, f]);
+      expectExhaustiveness(env, a, [b, f]);
+      expectExhaustiveness(env, a, [c, d],
+          errors: 'A is not exhaustively matched by C|D.');
+      expectExhaustiveness(env, f, [g, h],
+          errors: 'F is not exhaustively matched by G|H.');
     });
 
     test('unreachable case', () {
       // Same type.
-      expectReportErrors(env, b, [b, b], 'Case #2 B is unreachable.');
+      expectExhaustiveness(env, b, [b, b], errors: 'Case #2 B is unreachable.');
 
       // Previous case is supertype.
-      expectReportErrors(env, b, [a, b], 'Case #2 B is unreachable.');
+      expectExhaustiveness(env, b, [a, b], errors: 'Case #2 B is unreachable.');
 
       // Previous subtype cases cover sealed supertype.
-      expectReportErrors(env, a, [b, c, a], 'Case #3 A is unreachable.');
-      expectReportErrors(env, a, [d, e, f, a], 'Case #4 A is unreachable.');
-      expectReportErrors(env, a, [b, f, a], 'Case #3 A is unreachable.');
-      expectReportErrors(env, a, [c, d, a]);
+      expectExhaustiveness(env, a, [b, c, a],
+          errors: 'Case #3 A is unreachable.');
+      expectExhaustiveness(env, a, [d, e, f, a],
+          errors: 'Case #4 A is unreachable.');
+      expectExhaustiveness(env, a, [b, f, a],
+          errors: 'Case #3 A is unreachable.');
+      expectExhaustiveness(env, a, [c, d, a]);
 
       // Previous subtype cases do not cover unsealed supertype.
-      expectReportErrors(env, f, [g, h, f]);
+      expectExhaustiveness(env, f, [g, h, f]);
+
+      // Guarded case is reachable
+      expectExhaustiveness(env, b, [d, e, d],
+          caseIsGuarded: [true, false, false]);
+
+      // Guarded case is unreachable
+      expectExhaustiveness(env, b, [d, e, d],
+          caseIsGuarded: [false, false, true],
+          errors: 'Case #3 D is unreachable.');
     });
 
     test('covered record destructuring |', () {
       var r = env.createRecordType({x: a, y: a, z: a});
 
       // Wider field is not covered.
-      expectReportErrors(env, r, [
+      expectExhaustiveness(env, r, [
         ty(r, {x: b}),
         ty(r, {x: a}),
       ]);
 
       // Narrower field is covered.
-      expectReportErrors(
+      expectExhaustiveness(
           env,
           r,
           [
             ty(r, {x: a}),
             ty(r, {x: b}),
           ],
-          'Case #2 (x: B, y: A, z: A) is unreachable.');
+          errors: 'Case #2 (x: B, y: A, z: A) is unreachable.');
     });
 
     test('nullable sealed |', () {
@@ -107,40 +120,45 @@
       var e = env.createClass('E', inherits: [c]);
 
       // Must cover null.
-      expectReportErrors(env, a.nullable, [b, d, e],
-          'A? is not exhaustively matched by B|D|E.');
+      expectExhaustiveness(env, a.nullable, [b, d, e],
+          errors: 'A? is not exhaustively matched by B|D|E.');
 
       // Can cover null with any nullable subtype.
-      expectReportErrors(env, a.nullable, [b.nullable, c]);
-      expectReportErrors(env, a.nullable, [b, c.nullable]);
-      expectReportErrors(env, a.nullable, [b, d.nullable, e]);
-      expectReportErrors(env, a.nullable, [b, d, e.nullable]);
+      expectExhaustiveness(env, a.nullable, [b.nullable, c]);
+      expectExhaustiveness(env, a.nullable, [b, c.nullable]);
+      expectExhaustiveness(env, a.nullable, [b, d.nullable, e]);
+      expectExhaustiveness(env, a.nullable, [b, d, e.nullable]);
 
       // Can cover null with a null space.
-      expectReportErrors(env, a.nullable, [b, c, StaticType.nullType]);
-      expectReportErrors(env, a.nullable, [b, d, e, StaticType.nullType]);
+      expectExhaustiveness(env, a.nullable, [b, c, StaticType.nullType]);
+      expectExhaustiveness(env, a.nullable, [b, d, e, StaticType.nullType]);
 
       // Nullable covers the non-null.
-      expectReportErrors(
-          env, a.nullable, [a.nullable, a], 'Case #2 A is unreachable.');
-      expectReportErrors(
-          env, b.nullable, [a.nullable, b], 'Case #2 B is unreachable.');
+      expectExhaustiveness(env, a.nullable, [a.nullable, a],
+          errors: 'Case #2 A is unreachable.');
+      expectExhaustiveness(env, b.nullable, [a.nullable, b],
+          errors: 'Case #2 B is unreachable.');
 
       // Nullable covers null.
-      expectReportErrors(env, a.nullable, [a.nullable, StaticType.nullType],
-          'Case #2 Null is unreachable.');
-      expectReportErrors(env, b.nullable, [a.nullable, StaticType.nullType],
-          'Case #2 Null is unreachable.');
+      expectExhaustiveness(env, a.nullable, [a.nullable, StaticType.nullType],
+          errors: 'Case #2 Null is unreachable.');
+      expectExhaustiveness(env, b.nullable, [a.nullable, StaticType.nullType],
+          errors: 'Case #2 Null is unreachable.');
     });
   });
 }
 
-void expectReportErrors(ObjectPropertyLookup objectFieldLookup,
+void expectExhaustiveness(ObjectPropertyLookup objectFieldLookup,
     StaticType valueType, List<Object> cases,
-    [String errors = '']) {
+    {List<bool>? caseIsGuarded, String errors = ''}) {
+  List<CaseUnreachability> caseUnreachabilities = [];
+  var nonExhaustiveness = computeExhaustiveness(objectFieldLookup, valueType,
+      caseIsGuarded ?? List.filled(cases.length, false), parseSpaces(cases),
+      caseUnreachabilities: caseUnreachabilities);
   expect(
-      reportErrors(objectFieldLookup, valueType, parseSpaces(cases),
-              computeUnreachable: true)
-          .join('\n'),
+      [
+        ...caseUnreachabilities,
+        if (nonExhaustiveness != null) nonExhaustiveness
+      ].join('\n'),
       errors);
 }
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
index 4a4d073..c125b81 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
@@ -20,9 +20,20 @@
   late FlowAnalysisTestHarness h;
 
   setUp(() {
+    TypeRegistry.init();
+    TypeRegistry.addInterfaceTypeName('A');
+    TypeRegistry.addInterfaceTypeName('B');
+    TypeRegistry.addInterfaceTypeName('C');
+    TypeRegistry.addInterfaceTypeName('D');
+    TypeRegistry.addInterfaceTypeName('E');
+    TypeRegistry.addInterfaceTypeName('F');
     h = FlowAnalysisTestHarness();
   });
 
+  tearDown(() {
+    TypeRegistry.uninit();
+  });
+
   group('API', () {
     test('asExpression_end promotes variables', () {
       var x = Var('x');
@@ -1348,7 +1359,7 @@
     group('initialize() promotes implicitly typed vars to type parameter types',
         () {
       test('when not final', () {
-        h.addTypeVariable('T');
+        TypeRegistry.addTypeParameter('T');
         var x = Var('x');
         h.run([
           declare(x, initializer: expr('T&int')),
@@ -1357,7 +1368,7 @@
       });
 
       test('when final', () {
-        h.addTypeVariable('T');
+        TypeRegistry.addTypeParameter('T');
         var x = Var('x');
         h.run([
           declare(x,
@@ -1374,7 +1385,7 @@
         'parameter types', () {
       test('when not final', () {
         var x = Var('x');
-        h.addTypeVariable('T');
+        TypeRegistry.addTypeParameter('T');
         h.run([
           declare(x, type: 'T', initializer: expr('T&int')),
           checkNotPromoted(x),
@@ -1383,7 +1394,7 @@
 
       test('when final', () {
         var x = Var('x');
-        h.addTypeVariable('T');
+        TypeRegistry.addTypeParameter('T');
         h.run([
           declare(x, isFinal: true, type: 'T', initializer: expr('T&int')),
           checkNotPromoted(x),
@@ -1423,7 +1434,6 @@
         getSsaNodes((nodes) {
           var info = nodes[x]!.expressionInfo!;
           var key = h.promotionKeyStore.keyForVariable(y);
-          expect(info.after.promotionInfo!.get(h, key)!.promotedTypes, null);
           expect(info.ifTrue.promotionInfo!.get(h, key)!.promotedTypes, null);
           expect(
               info.ifFalse.promotionInfo!
@@ -3440,10 +3450,17 @@
   });
 
   group('State', () {
-    var intVar = Var('x')..type = Type('int');
-    var intQVar = Var('x')..type = Type('int?');
-    var objectQVar = Var('x')..type = Type('Object?');
-    var nullVar = Var('x')..type = Type('Null');
+    late Var intVar;
+    late Var intQVar;
+    late Var objectQVar;
+    late Var nullVar;
+
+    setUp(() {
+      intVar = Var('x')..type = Type('int');
+      intQVar = Var('x')..type = Type('int?');
+      objectQVar = Var('x')..type = Type('Object?');
+      nullVar = Var('x')..type = Type('Null');
+    });
 
     group('setUnreachable', () {
       var unreachable = FlowModel<SharedTypeView<Type>>(
@@ -3593,7 +3610,11 @@
     });
 
     group('write', () {
-      var objectQVar = Var('x')..type = Type('Object?');
+      late Var objectQVar;
+
+      setUp(() {
+        objectQVar = Var('x')..type = Type('Object?');
+      });
 
       test('without declaration', () {
         // This should not happen in valid code, but test that we don't crash.
@@ -4104,7 +4125,11 @@
     });
 
     group('declare', () {
-      var objectQVar = Var('x')..type = Type('Object?');
+      late Var objectQVar;
+
+      setUp(() {
+        objectQVar = Var('x')..type = Type('Object?');
+      });
 
       test('initialized', () {
         var s = FlowModel<SharedTypeView<Type>>(Reachability.initial)
@@ -4462,10 +4487,17 @@
   });
 
   group('joinPromotionChains', () {
-    var doubleType = Type('double');
-    var intType = Type('int');
-    var numType = Type('num');
-    var objectType = Type('Object');
+    late Type doubleType;
+    late Type intType;
+    late Type numType;
+    late Type objectType;
+
+    setUp(() {
+      doubleType = Type('double');
+      intType = Type('int');
+      numType = Type('num');
+      objectType = Type('Object');
+    });
 
     test('should handle nulls', () {
       expect(
@@ -4670,15 +4702,18 @@
     late int y;
     late int z;
     late int w;
-    var intType = Type('int');
-    var intQType = Type('int?');
-    var stringType = Type('String');
+    late Type intType;
+    late Type intQType;
+    late Type stringType;
 
     setUp(() {
       x = h.promotionKeyStore.keyForVariable(Var('x')..type = Type('Object?'));
       y = h.promotionKeyStore.keyForVariable(Var('y')..type = Type('Object?'));
       z = h.promotionKeyStore.keyForVariable(Var('z')..type = Type('Object?'));
       w = h.promotionKeyStore.keyForVariable(Var('w')..type = Type('Object?'));
+      intType = Type('int');
+      intQType = Type('int?');
+      stringType = Type('String');
     });
 
     PromotionModel<SharedTypeView<Type>> model(
@@ -4881,11 +4916,13 @@
 
   group('inheritTested', () {
     late int x;
-    var intType = Type('int');
-    var stringType = Type('String');
+    late Type intType;
+    late Type stringType;
 
     setUp(() {
       x = h.promotionKeyStore.keyForVariable(Var('x')..type = Type('Object?'));
+      intType = Type('int');
+      stringType = Type('String');
     });
 
     PromotionModel<SharedTypeView<Type>> model(
@@ -5653,6 +5690,7 @@
         });
 
         test('even when the declared type is a type variable', () {
+          TypeRegistry.addTypeParameter('T');
           h.enableLegacy();
           h.addPromotionException('T', 'int', 'T&int');
           var x = Var('x');
@@ -8605,6 +8643,82 @@
       });
     });
 
+    group('Null-aware map entry:', () {
+      test('Promotes key within value', () {
+        var a = Var('a');
+
+        h.run([
+          declare(a, type: 'String?', initializer: expr('String?')),
+          mapLiteral(keyType: 'String', valueType: 'dynamic', [
+            mapEntry(a, checkPromoted(a, 'String'), isKeyNullAware: true),
+          ]),
+          checkNotPromoted(a),
+        ]);
+      });
+
+      test('Non-null-aware key', () {
+        var a = Var('a');
+
+        h.run([
+          declare(a, type: 'String?', initializer: expr('String?')),
+          mapLiteral(keyType: 'String?', valueType: 'dynamic', [
+            mapEntry(a, checkNotPromoted(a), isKeyNullAware: false),
+          ]),
+          checkNotPromoted(a),
+        ]);
+      });
+
+      test('Promotes', () {
+        var a = Var('a');
+        var x = Var('x');
+
+        h.run([
+          declare(a, type: 'String', initializer: expr('String')),
+          declare(x, type: 'num', initializer: expr('num')),
+          mapLiteral(keyType: 'String', valueType: 'dynamic', [
+            mapEntry(a, x.as_('int'), isKeyNullAware: true),
+          ]),
+          checkPromoted(x, 'int'),
+        ]);
+      });
+
+      test('Affects promotion', () {
+        var a = Var('a');
+        var x = Var('x');
+
+        h.run([
+          declare(a, type: 'String?', initializer: expr('String?')),
+          declare(x, type: 'num', initializer: expr('num')),
+          mapLiteral(keyType: 'String', valueType: 'dynamic', [
+            mapEntry(a, x.as_('int'), isKeyNullAware: true),
+          ]),
+          checkNotPromoted(x),
+        ]);
+      });
+
+      test('Unreachable', () {
+        var a = Var('a');
+        h.run([
+          declare(a, type: 'String', initializer: expr('String')),
+          mapLiteral(keyType: 'String', valueType: 'dynamic', [
+            mapEntry(a, throw_(expr('Object')), isKeyNullAware: true),
+          ]),
+          checkReachable(false),
+        ]);
+      });
+
+      test('Reachable', () {
+        var a = Var('a');
+        h.run([
+          declare(a, type: 'String?', initializer: expr('String?')),
+          mapLiteral(keyType: 'String', valueType: 'dynamic', [
+            mapEntry(a, throw_(expr('Object')), isKeyNullAware: true),
+          ]),
+          checkReachable(true),
+        ]);
+      });
+    });
+
     group('Map pattern:', () {
       test('Promotes', () {
         var x = Var('x');
@@ -8823,6 +8937,7 @@
           //         // x still might be `null`
           //       }
           //     }
+          TypeRegistry.addInterfaceTypeName('T');
           h.addDownwardInfer(name: 'T', context: 'Object?', result: 'int?');
           h.addMember('int?', 'foo', 'dynamic');
           var x = Var('x');
@@ -8991,6 +9106,7 @@
           //         // x still might be `null`
           //       }
           //     }
+          TypeRegistry.addInterfaceTypeName('T');
           h.addDownwardInfer(name: 'T', context: 'Object?', result: 'int?');
           h.addMember('int?', 'foo', 'dynamic');
           var x = Var('x');
@@ -11254,7 +11370,7 @@
           FlowAnalysisTestHarness h, Var variable) =>
       new TrivialVariableReference<SharedTypeView<Type>>(
           promotionKey: _varRef(h, variable),
-          after: this,
+          model: this,
           type: promotionInfo
                   ?.get(h, h.promotionKeyStore.keyForVariable(variable))
                   ?.promotedTypes
diff --git a/pkg/_fe_analyzer_shared/test/inference/type_constraint_generation/data/function_upper_constraint/main.dart b/pkg/_fe_analyzer_shared/test/inference/type_constraint_generation/data/function_upper_constraint/main.dart
index f5b58cd..139ea54 100644
--- a/pkg/_fe_analyzer_shared/test/inference/type_constraint_generation/data/function_upper_constraint/main.dart
+++ b/pkg/_fe_analyzer_shared/test/inference/type_constraint_generation/data/function_upper_constraint/main.dart
@@ -29,5 +29,5 @@
   foo2a(bar2a /*T :> num*/ ());
   foo2b(bar2b /*T :> int,T :> num*/ ());
   foo3a(bar3a());
-  foo3b /*T :> String*/ (bar3b());
+  foo3b /*cfe.T :> String,T :> String*/ /*analyzer.T :> String*/ (bar3b());
 }
diff --git a/pkg/_fe_analyzer_shared/test/inference/type_constraint_generation/data/future_or_upper_constraint/main.dart b/pkg/_fe_analyzer_shared/test/inference/type_constraint_generation/data/future_or_upper_constraint/main.dart
index 11d5508..12a1435 100644
--- a/pkg/_fe_analyzer_shared/test/inference/type_constraint_generation/data/future_or_upper_constraint/main.dart
+++ b/pkg/_fe_analyzer_shared/test/inference/type_constraint_generation/data/future_or_upper_constraint/main.dart
@@ -14,6 +14,8 @@
 context2(Object x) {}
 
 main() {
-  context1(inferable1 /*T <: num,T :> int*/ (0));
-  context2(inferable2 /*T <: Object,T :> bool*/ (false));
+  context1(inferable1 /*cfe.T <: num,T :> int,T :> int*/
+      /*analyzer.T <: num,T :> int*/ (0));
+  context2(inferable2 /*cfe.T <: Object,T :> bool,T :> bool*/
+      /*analyzer.T <: Object,T :> bool*/ (false));
 }
diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
index f2fd58e..c8b4067 100644
--- a/pkg/_fe_analyzer_shared/test/mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -109,7 +109,8 @@
     stackLine = callStack[2];
     assert(
         stackLine.contains('type_inference_test.dart') ||
-            stackLine.contains('flow_analysis_test.dart'),
+            stackLine.contains('flow_analysis_test.dart') ||
+            stackLine.contains('type_constraint_gatherer_test.dart'),
         'Unexpected file: $stackLine');
   }
 
@@ -298,11 +299,12 @@
 }
 
 /// Creates a map entry containing the given [key] and [value] subexpressions.
-CollectionElement mapEntry(ProtoExpression key, ProtoExpression value) {
+CollectionElement mapEntry(ProtoExpression key, ProtoExpression value,
+    {bool isKeyNullAware = false}) {
   var location = computeLocation();
   return MapEntry._(key.asExpression(location: location),
       value.asExpression(location: location),
-      location: location);
+      isKeyNullAware: isKeyNullAware, location: location);
 }
 
 /// Creates a map literal containing the given [elements].
@@ -1775,10 +1777,6 @@
     operations.addSuperInterfaces(className, template);
   }
 
-  void addTypeVariable(String name, {String? bound}) {
-    operations.addTypeVariable(name, bound: bound);
-  }
-
   void disableFieldPromotion() {
     assert(!_started);
     _fieldPromotionEnabled = false;
@@ -2526,8 +2524,10 @@
 class MapEntry extends CollectionElement {
   final Expression key;
   final Expression value;
+  final bool isKeyNullAware;
 
-  MapEntry._(this.key, this.value, {required super.location});
+  MapEntry._(this.key, this.value,
+      {required this.isKeyNullAware, required super.location});
 
   @override
   void preVisit(PreVisitor visitor) {
@@ -2536,7 +2536,7 @@
   }
 
   @override
-  String toString() => '$key: $value';
+  String toString() => '${isKeyNullAware ? '?' : ''}$key: $value';
 
   @override
   void visit(Harness h, CollectionElementContext context) {
@@ -2549,8 +2549,11 @@
       default:
         keySchema = valueSchema = h.operations.unknownType;
     }
-    h.typeAnalyzer.analyzeExpression(key, keySchema);
+    var keyType = h.typeAnalyzer.analyzeExpression(key, keySchema);
+    h.flow.nullAwareMapEntry_valueBegin(key, keyType,
+        isKeyNullAware: isKeyNullAware);
     h.typeAnalyzer.analyzeExpression(value, valueSchema);
+    h.flow.nullAwareMapEntry_end(isKeyNullAware: isKeyNullAware);
     h.irBuilder.apply(
         'mapEntry', [Kind.expression, Kind.expression], Kind.collectionElement,
         location: location);
@@ -2668,12 +2671,8 @@
 }
 
 class MiniAstOperations
-    with
-        TypeAnalyzerOperationsMixin<Type, Var, PromotedTypeVariableType, Type,
-            String>
-    implements
-        TypeAnalyzerOperations<Type, Var, PromotedTypeVariableType, Type,
-            String> {
+    with TypeAnalyzerOperationsMixin<Type, Var, TypeParameter, Type, String>
+    implements TypeAnalyzerOperations<Type, Var, TypeParameter, Type, String> {
   static const Map<String, bool> _coreExhaustiveness = const {
     '()': true,
     '(int, int?)': false,
@@ -2779,6 +2778,8 @@
 
   final TypeSystem _typeSystem = TypeSystem();
 
+  final _variance = <String, List<Variance>>{};
+
   @override
   final SharedTypeView<Type> boolType = SharedTypeView(Type('bool'));
 
@@ -2835,8 +2836,8 @@
     _typeSystem.addSuperInterfaces(className, template);
   }
 
-  void addTypeVariable(String name, {String? bound}) {
-    _typeSystem.addTypeVariable(name, bound: bound);
+  void addVariance(String typeName, List<Variance> varianceByArgument) {
+    _variance[typeName] = varianceByArgument;
   }
 
   @override
@@ -2874,7 +2875,7 @@
 
   @override
   Type futureTypeInternal(Type argumentType) {
-    return PrimaryType('Future', args: [argumentType]);
+    return PrimaryType(TypeRegistry.future, args: [argumentType]);
   }
 
   @override
@@ -2891,8 +2892,7 @@
   @override
   Variance getTypeParameterVariance(
       String typeDeclaration, int parameterIndex) {
-    // TODO(cstefantsova): Support variance of type parameters in Mini AST.
-    return Variance.covariant;
+    return _variance[typeDeclaration]?[parameterIndex] ?? Variance.covariant;
   }
 
   @override
@@ -2950,11 +2950,6 @@
   }
 
   @override
-  bool isFunctionType(SharedTypeView<Type> type) {
-    return type.unwrapTypeView() is FunctionType;
-  }
-
-  @override
   bool isInterfaceType(SharedTypeView<Type> type) {
     Type unwrappedType = type.unwrapTypeView();
     return unwrappedType is PrimaryType && unwrappedType.isInterfaceType;
@@ -2975,9 +2970,13 @@
         unwrappedType is VoidType ||
         unwrappedType is NullType) {
       return false;
-    } else if (unwrappedType is PromotedTypeVariableType &&
-        unwrappedType.nullabilitySuffix == NullabilitySuffix.none) {
-      return isNonNullable(SharedTypeSchemaView(unwrappedType.promotion));
+    } else if (unwrappedType
+        case TypeParameterType(
+          :var promotion,
+          nullabilitySuffix: NullabilitySuffix.none
+        )) {
+      return promotion != null &&
+          isNonNullable(SharedTypeSchemaView(promotion));
     } else if (type.nullabilitySuffix == NullabilitySuffix.question) {
       return false;
     } else if (matchFutureOrInternal(unwrappedType) case Type typeArgument?) {
@@ -3015,7 +3014,7 @@
   @override
   bool isTypeParameterType(SharedTypeView<Type> type) {
     Type unwrappedType = type.unwrapTypeView();
-    return unwrappedType is PromotedTypeVariableType &&
+    return unwrappedType is TypeParameterType &&
         unwrappedType.nullabilitySuffix == NullabilitySuffix.none;
   }
 
@@ -3035,13 +3034,13 @@
   @override
   SharedTypeSchemaView<Type> iterableTypeSchema(
       SharedTypeSchemaView<Type> elementTypeSchema) {
-    return SharedTypeSchemaView(PrimaryType('Iterable',
+    return SharedTypeSchemaView(PrimaryType(TypeRegistry.iterable,
         args: [elementTypeSchema.unwrapTypeSchemaView()]));
   }
 
   @override
   Type listTypeInternal(Type elementType) {
-    return PrimaryType('List', args: [elementType]);
+    return PrimaryType(TypeRegistry.list, args: [elementType]);
   }
 
   @override
@@ -3084,7 +3083,7 @@
     required Type keyType,
     required Type valueType,
   }) {
-    return PrimaryType('Map', args: [keyType, valueType]);
+    return PrimaryType(TypeRegistry.map, args: [keyType, valueType]);
   }
 
   @override
@@ -3096,9 +3095,16 @@
   }
 
   @override
-  PromotedTypeVariableType? matchInferableParameter(SharedTypeView<Type> type) {
-    // TODO(cstefantsova): Add support for type parameter objects in Mini AST.
-    return null;
+  TypeParameter? matchInferableParameter(SharedTypeView<Type> type) {
+    if (type.unwrapTypeView()
+        case TypeParameterType(
+          :var typeParameter,
+          nullabilitySuffix: NullabilitySuffix.none
+        )) {
+      return typeParameter;
+    } else {
+      return null;
+    }
   }
 
   @override
@@ -3155,25 +3161,23 @@
   }
 
   @override
-  TypeDeclarationMatchResult? matchTypeDeclarationType(
+  TypeDeclarationMatchResult<Type, String, Type>? matchTypeDeclarationType(
       SharedTypeView<Type> type) {
     Type unwrappedType = type.unwrapTypeView();
     if (unwrappedType is! PrimaryType) return null;
+    TypeDeclarationKind typeDeclarationKind;
     if (unwrappedType.isInterfaceType) {
-      return new TypeDeclarationMatchResult(
-          typeDeclarationKind: TypeDeclarationKind.interfaceDeclaration,
-          typeDeclaration: unwrappedType.type,
-          typeDeclarationType: unwrappedType,
-          typeArguments: unwrappedType.args);
+      typeDeclarationKind = TypeDeclarationKind.interfaceDeclaration;
     } else if (isExtensionType(type)) {
-      return new TypeDeclarationMatchResult(
-          typeDeclarationKind: TypeDeclarationKind.extensionTypeDeclaration,
-          typeDeclaration: unwrappedType.type,
-          typeDeclarationType: unwrappedType,
-          typeArguments: unwrappedType.args);
+      typeDeclarationKind = TypeDeclarationKind.extensionTypeDeclaration;
     } else {
       return null;
     }
+    return new TypeDeclarationMatchResult(
+        typeDeclarationKind: typeDeclarationKind,
+        typeDeclaration: unwrappedType.name,
+        typeDeclarationType: unwrappedType,
+        typeArguments: unwrappedType.args);
   }
 
   @override
@@ -3203,14 +3207,14 @@
       positionalTypes: positional,
       namedTypes: [
         for (var (name, type) in named) NamedType(name: name, type: type)
-      ],
+      ]..sort((a, b) => a.name.compareTo(b.name)),
     );
   }
 
   @override
   SharedTypeSchemaView<Type> streamTypeSchema(
       SharedTypeSchemaView<Type> elementTypeSchema) {
-    return SharedTypeSchemaView(PrimaryType('Stream',
+    return SharedTypeSchemaView(PrimaryType(TypeRegistry.stream,
         args: [elementTypeSchema.unwrapTypeSchemaView()]));
   }
 
@@ -3266,6 +3270,8 @@
 
   String? _errorId;
 
+  factory Node.placeholder() => Node._(location: computeLocation());
+
   Node._({required this.location}) : id = _nextId++;
 
   String get errorId {
@@ -5410,7 +5416,7 @@
 class _MiniAstTypeAnalyzer
     with
         TypeAnalyzer<Type, Node, Statement, Expression, Var, Pattern, void,
-            PromotedTypeVariableType, Type, String> {
+            TypeParameter, Type, String> {
   final Harness _harness;
 
   @override
@@ -5595,6 +5601,15 @@
     var methodType = _handlePropertyTargetAndMemberLookup(
         null, target, methodName,
         location: node.location);
+    if (methodType is FunctionType) {
+      if (methodType.namedParameters.isNotEmpty) {
+        throw UnimplementedError('Named parameters are not supported yet');
+      } else if (methodType.requiredPositionalParameterCount !=
+          methodType.positionalParameters.length) {
+        throw UnimplementedError(
+            'Optional positional parameters are not supported yet');
+      }
+    }
     // Recursively analyze each argument.
     var inputKinds = [Kind.expression];
     for (var i = 0; i < arguments.length; i++) {
diff --git a/pkg/_fe_analyzer_shared/test/mini_types.dart b/pkg/_fe_analyzer_shared/test/mini_types.dart
index b6abb1d..0c744e0 100644
--- a/pkg/_fe_analyzer_shared/test/mini_types.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_types.dart
@@ -20,7 +20,8 @@
   static final instance = DynamicType._();
 
   DynamicType._()
-      : super._('dynamic', nullabilitySuffix: NullabilitySuffix.none);
+      : super._(TypeRegistry.dynamic_,
+            nullabilitySuffix: NullabilitySuffix.none);
 
   @override
   Type withNullability(NullabilitySuffix suffix) => this;
@@ -29,18 +30,43 @@
 /// Representation of a function type suitable for unit testing of code in the
 /// `_fe_analyzer_shared` package.
 ///
-/// Optional parameters, named parameters, and type parameters are not (yet)
-/// supported.
-class FunctionType extends Type {
-  /// The return type.
+/// Type parameters are not (yet) supported.
+class FunctionType extends Type
+    implements
+        SharedFunctionTypeStructure<Type, Never, NamedFunctionParameter> {
+  @override
   final Type returnType;
 
   /// A list of the types of positional parameters.
   final List<Type> positionalParameters;
 
+  @override
+  final int requiredPositionalParameterCount;
+
+  /// A list of the named parameters, sorted by name.
+  final List<NamedFunctionParameter> namedParameters;
+
   FunctionType(this.returnType, this.positionalParameters,
-      {super.nullabilitySuffix = NullabilitySuffix.none})
-      : super._();
+      {int? requiredPositionalParameterCount,
+      this.namedParameters = const [],
+      super.nullabilitySuffix = NullabilitySuffix.none})
+      : requiredPositionalParameterCount =
+            requiredPositionalParameterCount ?? positionalParameters.length,
+        super._() {
+    for (var i = 1; i < namedParameters.length; i++) {
+      assert(namedParameters[i - 1].name.compareTo(namedParameters[i].name) < 0,
+          'namedParameters not properly sorted');
+    }
+  }
+
+  @override
+  List<Type> get positionalParameterTypes => positionalParameters;
+
+  @override
+  List<NamedFunctionParameter> get sortedNamedParameters => namedParameters;
+
+  @override
+  List<Never> get typeFormals => const [];
 
   @override
   Type? closureWithRespectToUnknown({required bool covariant}) {
@@ -48,11 +74,17 @@
         returnType.closureWithRespectToUnknown(covariant: covariant);
     List<Type>? newPositionalParameters =
         positionalParameters.closureWithRespectToUnknown(covariant: !covariant);
-    if (newReturnType == null && newPositionalParameters == null) {
+    List<NamedFunctionParameter>? newNamedParameters =
+        namedParameters.closureWithRespectToUnknown(covariant: !covariant);
+    if (newReturnType == null &&
+        newPositionalParameters == null &&
+        newNamedParameters == null) {
       return null;
     }
     return FunctionType(newReturnType ?? returnType,
         newPositionalParameters ?? positionalParameters,
+        requiredPositionalParameterCount: requiredPositionalParameterCount,
+        namedParameters: newNamedParameters ?? namedParameters,
         nullabilitySuffix: nullabilitySuffix);
   }
 
@@ -61,22 +93,43 @@
     Type? newReturnType = returnType.recursivelyDemote(covariant: covariant);
     List<Type>? newPositionalParameters =
         positionalParameters.recursivelyDemote(covariant: !covariant);
-    if (newReturnType == null && newPositionalParameters == null) {
+    List<NamedFunctionParameter>? newNamedParameters =
+        namedParameters.recursivelyDemote(covariant: !covariant);
+    if (newReturnType == null &&
+        newPositionalParameters == null &&
+        newNamedParameters == null) {
       return null;
     }
     return FunctionType(newReturnType ?? returnType,
         newPositionalParameters ?? positionalParameters,
+        requiredPositionalParameterCount: requiredPositionalParameterCount,
+        namedParameters: newNamedParameters ?? namedParameters,
         nullabilitySuffix: nullabilitySuffix);
   }
 
   @override
   Type withNullability(NullabilitySuffix suffix) =>
-      FunctionType(returnType, positionalParameters, nullabilitySuffix: suffix);
+      FunctionType(returnType, positionalParameters,
+          requiredPositionalParameterCount: requiredPositionalParameterCount,
+          namedParameters: namedParameters,
+          nullabilitySuffix: suffix);
 
   @override
-  String _toStringWithoutSuffix({required bool parenthesizeIfComplex}) =>
-      _parenthesizeIf(parenthesizeIfComplex,
-          '$returnType Function(${positionalParameters.join(', ')})');
+  String _toStringWithoutSuffix({required bool parenthesizeIfComplex}) {
+    var parameters = <Object>[
+      ...positionalParameters.sublist(0, requiredPositionalParameterCount)
+    ];
+    if (requiredPositionalParameterCount < positionalParameters.length) {
+      var optionalPositionalParameters =
+          positionalParameters.sublist(requiredPositionalParameterCount);
+      parameters.add('[${optionalPositionalParameters.join(', ')}]');
+    }
+    if (namedParameters.isNotEmpty) {
+      parameters.add('{${namedParameters.join(', ')}}');
+    }
+    return _parenthesizeIf(parenthesizeIfComplex,
+        '$returnType Function(${parameters.join(', ')})');
+  }
 }
 
 /// Representation of the type `FutureOr<T>` suitable for unit testing of code
@@ -84,7 +137,7 @@
 class FutureOrType extends PrimaryType {
   FutureOrType(Type typeArgument,
       {super.nullabilitySuffix = NullabilitySuffix.none})
-      : super._withSpecialName('FutureOr', args: [typeArgument]);
+      : super._special(TypeRegistry.futureOr, args: [typeArgument]);
 
   Type get typeArgument => args.single;
 
@@ -108,18 +161,37 @@
       FutureOrType(typeArgument, nullabilitySuffix: suffix);
 }
 
+/// A type name that represents an ordinary interface type.
+class InterfaceTypeName extends TypeNameInfo {
+  InterfaceTypeName._(super.name);
+}
+
 /// Representation of an invalid type suitable for unit testing of code in the
 /// `_fe_analyzer_shared` package.
 class InvalidType extends _SpecialSimpleType
     implements SharedInvalidTypeStructure<Type> {
   static final instance = InvalidType._();
 
-  InvalidType._() : super._('error', nullabilitySuffix: NullabilitySuffix.none);
+  InvalidType._()
+      : super._(TypeRegistry.error_, nullabilitySuffix: NullabilitySuffix.none);
 
   @override
   Type withNullability(NullabilitySuffix suffix) => this;
 }
 
+/// A named parameter of a function type.
+class NamedFunctionParameter extends NamedType
+    implements SharedNamedFunctionParameterStructure<Type> {
+  @override
+  final bool isRequired;
+
+  NamedFunctionParameter(
+      {required this.isRequired, required super.name, required super.type});
+
+  @override
+  String toString() => [if (isRequired) 'required', type, name].join(' ');
+}
+
 class NamedType implements SharedNamedTypeStructure<Type> {
   @override
   final String name;
@@ -136,7 +208,7 @@
   static final instance = NeverType._();
 
   NeverType._({super.nullabilitySuffix = NullabilitySuffix.none})
-      : super._('Never');
+      : super._(TypeRegistry.never);
 
   @override
   Type withNullability(NullabilitySuffix suffix) =>
@@ -148,7 +220,8 @@
 class NullType extends _SpecialSimpleType {
   static final instance = NullType._();
 
-  NullType._() : super._('Null', nullabilitySuffix: NullabilitySuffix.none);
+  NullType._()
+      : super._(TypeRegistry.null_, nullabilitySuffix: NullabilitySuffix.none);
 
   @override
   Type withNullability(NullabilitySuffix suffix) => this;
@@ -166,52 +239,42 @@
 
 /// Representation of a primary type suitable for unit testing of code in the
 /// `_fe_analyzer_shared` package.  A primary type is either an interface type
-/// with zero or more type parameters (e.g. `double`, or `Map<int, String>`), a
-/// reference to a type parameter, or one of the special types whose name is a
-/// single word (e.g. `dynamic`).
+/// with zero or more type parameters (e.g. `double`, or `Map<int, String>`) or
+/// one of the special types whose name is a single word (e.g. `dynamic`).
 class PrimaryType extends Type {
-  /// Names of primary types not originating from a class, a mixin, or an enum.
-  static const List<String> namedNonInterfaceTypes = [
-    'dynamic',
-    'error',
-    'FutureOr',
-    'Never',
-    'Null',
-    'void'
-  ];
-
-  /// The name of the type.
-  final String name;
+  /// Information about the type name.
+  final TypeNameInfo nameInfo;
 
   /// The type arguments, or `const []` if there are no type arguments.
   final List<Type> args;
 
-  PrimaryType(this.name,
+  PrimaryType(InterfaceTypeName nameInfo,
+      {List<Type> args = const [],
+      NullabilitySuffix nullabilitySuffix = NullabilitySuffix.none})
+      : this._(nameInfo, args: args, nullabilitySuffix: nullabilitySuffix);
+
+  PrimaryType._(this.nameInfo,
       {this.args = const [], super.nullabilitySuffix = NullabilitySuffix.none})
-      : super._() {
-    if (namedNonInterfaceTypes.contains(name)) {
-      throw StateError('Tried to create a PrimaryType with special name $name');
-    }
+      : super._();
+
+  PrimaryType._special(SpecialTypeName nameInfo,
+      {List<Type> args = const [],
+      NullabilitySuffix nullabilitySuffix = NullabilitySuffix.none})
+      : this._(nameInfo, args: args, nullabilitySuffix: nullabilitySuffix);
+
+  bool get isInterfaceType {
+    return nameInfo is InterfaceTypeName;
   }
 
-  PrimaryType._withSpecialName(this.name,
-      {this.args = const [], super.nullabilitySuffix = NullabilitySuffix.none})
-      : super._() {
-    if (!namedNonInterfaceTypes.contains(name)) {
-      throw StateError(
-          'Tried to use PrimaryType._withSpecialName with non-special name '
-          '$name');
-    }
-  }
-
-  bool get isInterfaceType => !namedNonInterfaceTypes.contains(name);
+  /// The name of the type.
+  String get name => nameInfo.name;
 
   @override
   Type? closureWithRespectToUnknown({required bool covariant}) {
     List<Type>? newArgs =
         args.closureWithRespectToUnknown(covariant: covariant);
     if (newArgs == null) return null;
-    return PrimaryType(name,
+    return PrimaryType._(nameInfo,
         args: newArgs, nullabilitySuffix: nullabilitySuffix);
   }
 
@@ -219,59 +282,19 @@
   Type? recursivelyDemote({required bool covariant}) {
     List<Type>? newArgs = args.recursivelyDemote(covariant: covariant);
     if (newArgs == null) return null;
-    return PrimaryType(name,
+    return PrimaryType._(nameInfo,
         args: newArgs, nullabilitySuffix: nullabilitySuffix);
   }
 
   @override
   Type withNullability(NullabilitySuffix suffix) =>
-      PrimaryType(name, args: args, nullabilitySuffix: suffix);
+      PrimaryType._(nameInfo, args: args, nullabilitySuffix: suffix);
 
   @override
   String _toStringWithoutSuffix({required bool parenthesizeIfComplex}) =>
       args.isEmpty ? name : '$name<${args.join(', ')}>';
 }
 
-/// Representation of a promoted type parameter type suitable for unit testing
-/// of code in the `_fe_analyzer_shared` package.  A promoted type parameter is
-/// often written using the syntax `a&b`, where `a` is the type parameter and
-/// `b` is what it's promoted to.  For example, `T&int` represents the type
-/// parameter `T`, promoted to `int`.
-class PromotedTypeVariableType extends Type {
-  final Type innerType;
-
-  final Type promotion;
-
-  PromotedTypeVariableType(this.innerType, this.promotion,
-      {super.nullabilitySuffix = NullabilitySuffix.none})
-      : super._();
-
-  @override
-  Type? closureWithRespectToUnknown({required bool covariant}) {
-    var newPromotion =
-        promotion.closureWithRespectToUnknown(covariant: covariant);
-    if (newPromotion == null) return null;
-    return PromotedTypeVariableType(innerType, newPromotion,
-        nullabilitySuffix: nullabilitySuffix);
-  }
-
-  @override
-  Type? recursivelyDemote({required bool covariant}) =>
-      (covariant ? innerType : NeverType.instance)
-          .withNullability(nullabilitySuffix);
-
-  @override
-  Type withNullability(NullabilitySuffix suffix) =>
-      PromotedTypeVariableType(innerType, promotion, nullabilitySuffix: suffix);
-
-  @override
-  String _toStringWithoutSuffix({required bool parenthesizeIfComplex}) =>
-      _parenthesizeIf(
-          parenthesizeIfComplex,
-          '${innerType.toString(parenthesizeIfComplex: true)}&'
-          '${promotion.toString(parenthesizeIfComplex: true)}');
-}
-
 class RecordType extends Type implements SharedRecordTypeStructure<Type> {
   @override
   final List<Type> positionalTypes;
@@ -283,7 +306,12 @@
     required this.positionalTypes,
     required this.namedTypes,
     super.nullabilitySuffix = NullabilitySuffix.none,
-  }) : super._();
+  }) : super._() {
+    for (var i = 1; i < namedTypes.length; i++) {
+      assert(namedTypes[i - 1].name.compareTo(namedTypes[i].name) < 0,
+          'namedTypes not properly sorted');
+    }
+  }
 
   @override
   Type? closureWithRespectToUnknown({required bool covariant}) {
@@ -383,6 +411,17 @@
   }
 }
 
+/// A type name that represents one of Dart's built-in "special" types, such as:
+/// - `dynamic`
+/// - `error` (to represent an invalid type)
+/// - `FutureOr`
+/// - `Never`
+/// - `Null`
+/// - `void`
+class SpecialTypeName extends TypeNameInfo {
+  SpecialTypeName._(super.name);
+}
+
 /// Representation of a type suitable for unit testing of code in the
 /// `_fe_analyzer_shared` package.
 abstract class Type implements SharedTypeStructure<Type> {
@@ -461,6 +500,222 @@
   String _toStringWithoutSuffix({required bool parenthesizeIfComplex});
 }
 
+/// Information about a single type name recognized by the [Type] parser.
+sealed class TypeNameInfo {
+  final String name;
+
+  TypeNameInfo(this.name);
+}
+
+/// A type name that represents a type variable.
+class TypeParameter extends TypeNameInfo
+    implements SharedTypeParameterStructure<Type> {
+  /// The type variable's bound. Defaults to `Object?`.
+  Type bound;
+
+  TypeParameter._(super.name) : bound = Type('Object?');
+
+  @override
+  String get displayName => name;
+
+  @override
+  String toString() => name;
+}
+
+/// Representation of a type parameter type suitable for unit testing of code in
+/// the `_fe_analyzer_shared` package. A type parameter type might be promoted,
+/// in which case it is often written using the syntax `a&b`, where `a` is the
+/// type parameter and `b` is what it's promoted to.  For example, `T&int`
+/// represents the type parameter `T`, promoted to `int`.
+class TypeParameterType extends Type {
+  /// The type parameter this type is based on.
+  final TypeParameter typeParameter;
+
+  /// If non-null, the promoted type.
+  final Type? promotion;
+
+  TypeParameterType(this.typeParameter,
+      {this.promotion,
+      NullabilitySuffix super.nullabilitySuffix = NullabilitySuffix.none})
+      : super._();
+
+  /// The type parameter's bound.
+  Type get bound => typeParameter.bound;
+
+  @override
+  Type? closureWithRespectToUnknown({required bool covariant}) {
+    var newPromotion =
+        promotion?.closureWithRespectToUnknown(covariant: covariant);
+    if (newPromotion == null) return null;
+    return TypeParameterType(typeParameter,
+        promotion: newPromotion, nullabilitySuffix: nullabilitySuffix);
+  }
+
+  @override
+  Type? recursivelyDemote({required bool covariant}) {
+    if (!covariant) {
+      return NeverType.instance.withNullability(nullabilitySuffix);
+    } else if (promotion == null) {
+      return null;
+    } else {
+      return TypeParameterType(typeParameter,
+          nullabilitySuffix: nullabilitySuffix);
+    }
+  }
+
+  @override
+  Type withNullability(NullabilitySuffix suffix) =>
+      TypeParameterType(typeParameter,
+          promotion: promotion, nullabilitySuffix: suffix);
+
+  @override
+  String _toStringWithoutSuffix({required bool parenthesizeIfComplex}) {
+    if (promotion case var promotion?) {
+      return _parenthesizeIf(
+          parenthesizeIfComplex,
+          '${typeParameter.name}&'
+          '${promotion.toString(parenthesizeIfComplex: true)}');
+    } else {
+      return typeParameter.name;
+    }
+  }
+}
+
+/// Container for static methods that can be used to customize the "mini types"
+/// representation used in `_fe_analyzer_shared` unit tests.
+///
+/// Thanks to Dart's scoping rules, it's possible for a single identifier to
+/// represent an interface type in some contexts, a special type like `Null` in
+/// other contexts, and a type parameter name in other contexts. But allowing a
+/// single name to have multiple meanings isn't useful in `_fe_analyzer_shared`
+/// unit tests, and opens up greater risk of confusion. Therefore, the "mini
+/// types" representation does not permit it; every test must register each type
+/// name it intends to use, specifying its meaning, before using that name in a
+/// call to the [Type] constructor. This registration can happen either within
+/// the test itself or in a callback passed to `setUp`.
+abstract final class TypeRegistry {
+  /// Type names that have been registered using [_add].
+  static Map<String, TypeNameInfo>? _typeNameInfoMap;
+
+  /// The [TypeNameInfo] object representing the special type `dynamic`.
+  static final dynamic_ = SpecialTypeName._('dynamic');
+
+  /// The [TypeNameInfo] object representing the special type `error`.
+  static final error_ = SpecialTypeName._('error');
+
+  /// The [TypeNameInfo] object representing the interface type `Future`.
+  static final future = InterfaceTypeName._('Future');
+
+  /// The [TypeNameInfo] object representing the special type `FutureOr`.
+  static final futureOr = SpecialTypeName._('FutureOr');
+
+  /// The [TypeNameInfo] object representing the interface type `Iterable`.
+  static final iterable = InterfaceTypeName._('Iterable');
+
+  /// The [TypeNameInfo] object representing the interface type `List`.
+  static final list = InterfaceTypeName._('List');
+
+  /// The [TypeNameInfo] object representing the interface type `Map`.
+  static final map = InterfaceTypeName._('Map');
+
+  /// The [TypeNameInfo] object representing the special type `Never`.
+  static final never = SpecialTypeName._('Never');
+
+  /// The [TypeNameInfo] object representing the special type `Null`.
+  static final null_ = SpecialTypeName._('Null');
+
+  /// The [TypeNameInfo] object representing the interface type `Stream`.
+  static final stream = InterfaceTypeName._('Stream');
+
+  /// The [TypeNameInfo] object representing the special type `void`.
+  static final void_ = SpecialTypeName._('void');
+
+  /// Gets [_typeNameInfoMap], throwing an exception if it has not been
+  /// initialized.
+  static Map<String, TypeNameInfo> get _typeNameInfoMapOrThrow =>
+      _typeNameInfoMap ??
+      (throw StateError(
+          'TypeRegistry not initialized (call `TypeRegistry.init` from a test '
+          '`setUp` callback)'));
+
+  factory TypeRegistry._() => throw StateError('Do not construct');
+
+  /// Registers [name] as the name of an ordinary interface type.
+  static InterfaceTypeName addInterfaceTypeName(String name) {
+    var interfaceTypeName = InterfaceTypeName._(name);
+    _add(interfaceTypeName);
+    return interfaceTypeName;
+  }
+
+  /// Registers [name] as the name of a type parameter.
+  static TypeParameter addTypeParameter(String name) {
+    var typeParameter = TypeParameter._(name);
+    _add(typeParameter);
+    return typeParameter;
+  }
+
+  /// Initializes the "mini type" infrastructure.
+  ///
+  /// This method must be called from a `setUp` callback before any unit test
+  /// that makes use of mini types.
+  static void init() {
+    assert(StackTrace.current.toString().contains('runSetUps'),
+        'Should be called from a test `setUp` method');
+    if (_typeNameInfoMap != null) {
+      throw StateError(
+          'init() already called. Did you forget to call uninit() from '
+          '`tearDown`?');
+    }
+    _typeNameInfoMap = {};
+    // Set up some common built-in type names.
+    addInterfaceTypeName('bool');
+    addInterfaceTypeName('double');
+    _add(dynamic_);
+    _add(error_);
+    _add(future);
+    _add(futureOr);
+    addInterfaceTypeName('int');
+    _add(iterable);
+    _add(list);
+    _add(map);
+    _add(never);
+    _add(null_);
+    addInterfaceTypeName('num');
+    addInterfaceTypeName('Object');
+    _add(stream);
+    addInterfaceTypeName('String');
+    _add(void_);
+  }
+
+  /// Retrieves the [TypeNameInfo] corresponding to [name].
+  static TypeNameInfo lookup(String name) =>
+      _typeNameInfoMapOrThrow[name] ??
+      (throw StateError(
+          'Unknown type name $name (use `TypeRegistry.add...` first)'));
+
+  /// Un-does the operation of [init], rendering the "mini type" infrastructure
+  /// unusable.
+  ///
+  /// This method should be called from a `tearDown` callback, complementing the
+  /// call to [init] in a `setUp` callback.
+  static void uninit() {
+    // Note: don't complain if `_typeNameInfoMap` is `null`, because we don't
+    // want to produce confusing failure messages if a test runs into trouble
+    // while trying to initialize itself.
+    _typeNameInfoMap = null;
+  }
+
+  /// Registers [info] as information about a type name.
+  static void _add(TypeNameInfo info) {
+    var name = info.name;
+    var infoMap = _typeNameInfoMapOrThrow;
+    if (infoMap.containsKey(name)) {
+      throw StateError('Type name $name already registered');
+    }
+    infoMap[name] = info;
+  }
+}
+
 class TypeSystem {
   static final Map<String, List<Type> Function(List<Type>)>
       _coreSuperInterfaceTemplates = {
@@ -469,7 +724,8 @@
     'Future': (_) => [Type('Object')],
     'int': (_) => [Type('num'), Type('Object')],
     'Iterable': (_) => [Type('Object')],
-    'List': (args) => [PrimaryType('Iterable', args: args), Type('Object')],
+    'List': (args) =>
+        [PrimaryType(TypeRegistry.iterable, args: args), Type('Object')],
     'Map': (_) => [Type('Object')],
     'Object': (_) => [],
     'num': (_) => [Type('Object')],
@@ -480,8 +736,6 @@
 
   static final _objectType = Type('Object');
 
-  final Map<String, Type> _typeVarBounds = {};
-
   final Map<String, List<Type> Function(List<Type>)> _superInterfaceTemplates =
       Map.of(_coreSuperInterfaceTemplates);
 
@@ -490,10 +744,6 @@
     _superInterfaceTemplates[className] = template;
   }
 
-  void addTypeVariable(String name, {String? bound}) {
-    _typeVarBounds[name] = Type(bound ?? 'Object?');
-  }
-
   Type factor(Type t, Type s) {
     // If T <: S then Never
     if (isSubtype(t, s)) return NeverType.instance;
@@ -525,13 +775,17 @@
     // Else if T is FutureOr<R> and Future<R> <: S then factor(R, S)
     if (t is FutureOrType) {
       var r = t.typeArgument;
-      if (isSubtype(PrimaryType('Future', args: [r]), s)) return factor(r, s);
+      if (isSubtype(PrimaryType(TypeRegistry.future, args: [r]), s)) {
+        return factor(r, s);
+      }
     }
 
     // Else if T is FutureOr<R> and R <: S then factor(Future<R>, S)
     if (t is FutureOrType) {
       var r = t.typeArgument;
-      if (isSubtype(r, s)) return factor(PrimaryType('Future', args: [r]), s);
+      if (isSubtype(r, s)) {
+        return factor(PrimaryType(TypeRegistry.future, args: [r]), s);
+      }
     }
 
     // Else T
@@ -545,14 +799,34 @@
     //   and type variables but not for composite types.  We only check it for
     //   types with a single name and no type arguments (this covers both
     //   primitive types and type variables).
-    if (t0 is PrimaryType &&
-        t0.nullabilitySuffix == NullabilitySuffix.none &&
-        t0.args.isEmpty &&
-        t1 is PrimaryType &&
-        t1.nullabilitySuffix == NullabilitySuffix.none &&
-        t1.args.isEmpty &&
-        t0.name == t1.name) {
-      return true;
+    switch ((t0, t1)) {
+      case (
+            PrimaryType(
+              nameInfo: var t0Info,
+              nullabilitySuffix: NullabilitySuffix.none,
+              args: []
+            ),
+            PrimaryType(
+              nameInfo: var t1Info,
+              nullabilitySuffix: NullabilitySuffix.none,
+              args: []
+            )
+          )
+          when t0Info == t1Info:
+      case (
+            TypeParameterType(
+              typeParameter: var x0,
+              promotion: null,
+              nullabilitySuffix: NullabilitySuffix.none
+            ),
+            TypeParameterType(
+              typeParameter: var x1,
+              promotion: null,
+              nullabilitySuffix: NullabilitySuffix.none
+            )
+          )
+          when x0 == x1:
+        return true;
     }
 
     // Unknown types (note: this is not in the spec, but necessary because there
@@ -581,16 +855,22 @@
         t1.name == 'Object') {
       // - if T0 is an unpromoted type variable with bound B then T0 <: T1 iff
       //   B <: Object
-      if (t0 is PrimaryType &&
-          t0.nullabilitySuffix == NullabilitySuffix.none &&
-          _isTypeVar(t0)) {
-        return isSubtype(_typeVarBound(t0), _objectType);
+      if (t0
+          case TypeParameterType(
+            bound: var b,
+            promotion: null,
+            nullabilitySuffix: NullabilitySuffix.none
+          )) {
+        return isSubtype(b, _objectType);
       }
 
       // - if T0 is a promoted type variable X & S then T0 <: T1 iff S <: Object
-      if (t0 is PromotedTypeVariableType &&
-          t0.nullabilitySuffix == NullabilitySuffix.none) {
-        return isSubtype(t0.promotion, _objectType);
+      if (t0
+          case TypeParameterType(
+            promotion: var s?,
+            nullabilitySuffix: NullabilitySuffix.none
+          )) {
+        return isSubtype(s, _objectType);
       }
 
       // - if T0 is FutureOr<S> for some S, then T0 <: T1 iff S <: Object.
@@ -622,7 +902,10 @@
     // Left Null: if T0 is Null then:
     if (t0 is NullType) {
       // - if T1 is a type variable (promoted or not) the query is false
-      if (_isTypeVar(t1)) return false;
+      if (t1
+          case TypeParameterType(nullabilitySuffix: NullabilitySuffix.none)) {
+        return false;
+      }
 
       // - If T1 is FutureOr<S> for some S, then the query is true iff
       //   Null <: S.
@@ -659,7 +942,7 @@
       var s0 = t0.typeArgument;
 
       // - T0 <: T1 iff Future<S0> <: T1 and S0 <: T1
-      return isSubtype(PrimaryType('Future', args: [s0]), t1) &&
+      return isSubtype(PrimaryType(TypeRegistry.future, args: [s0]), t1) &&
           isSubtype(s0, t1);
     }
 
@@ -672,30 +955,49 @@
 
     // Type Variable Reflexivity 1: if T0 is a type variable X0 or a promoted
     // type variables X0 & S0 and T1 is X0 then:
-    if (_isTypeVar(t0) &&
-        t1 is PrimaryType &&
-        t1.nullabilitySuffix == NullabilitySuffix.none &&
-        t1.args.isEmpty &&
-        _typeVarName(t0) == t1.name) {
+    if ((t0, t1)
+        case (
+          TypeParameterType(
+            typeParameter: var x0,
+            nullabilitySuffix: NullabilitySuffix.none
+          ),
+          TypeParameterType(
+            typeParameter: var x1,
+            promotion: null,
+            nullabilitySuffix: NullabilitySuffix.none
+          )
+        ) when x0 == x1) {
       // - T0 <: T1
       return true;
     }
 
     // Type Variable Reflexivity 2: if T0 is a type variable X0 or a promoted
     // type variables X0 & S0 and T1 is X0 & S1 then:
-    if (_isTypeVar(t0) &&
-        t1 is PromotedTypeVariableType &&
-        t1.nullabilitySuffix == NullabilitySuffix.none &&
-        _typeVarName(t0) == _typeVarName(t1)) {
+    if ((t0, t1)
+        case (
+          TypeParameterType(
+            typeParameter: var x0,
+            nullabilitySuffix: NullabilitySuffix.none
+          ),
+          TypeParameterType(
+            typeParameter: var x1,
+            promotion: var s1?,
+            nullabilitySuffix: NullabilitySuffix.none
+          )
+        ) when x0 == x1) {
       // - T0 <: T1 iff T0 <: S1.
-      return isSubtype(t0, t1.promotion);
+      return isSubtype(t0, s1);
     }
 
     // Right Promoted Variable: if T1 is a promoted type variable X1 & S1 then:
-    if (t1 is PromotedTypeVariableType &&
-        t1.nullabilitySuffix == NullabilitySuffix.none) {
+    if (t1
+        case TypeParameterType(
+          typeParameter: var x1,
+          promotion: var s1?,
+          nullabilitySuffix: NullabilitySuffix.none
+        )) {
       // - T0 <: T1 iff T0 <: X1 and T0 <: S1
-      return isSubtype(t0, t1.innerType) && isSubtype(t0, t1.promotion);
+      return isSubtype(t0, TypeParameterType(x1)) && isSubtype(t0, s1);
     }
 
     // Right FutureOr: if T1 is FutureOr<S1> then:
@@ -703,17 +1005,23 @@
       var s1 = t1.typeArgument;
 
       // - T0 <: T1 iff any of the following hold:
-      return
-          //   - either T0 <: Future<S1>
-          isSubtype(t0, PrimaryType('Future', args: [s1])) ||
-              //   - or T0 <: S1
-              isSubtype(t0, s1) ||
-              //   - or T0 is X0 and X0 has bound S0 and S0 <: T1
-              t0 is PrimaryType &&
-                  _isTypeVar(t0) &&
-                  isSubtype(_typeVarBound(t0), t1) ||
-              //   - or T0 is X0 & S0 and S0 <: T1
-              t0 is PromotedTypeVariableType && isSubtype(t0.promotion, t1);
+      //   - either T0 <: Future<S1>
+      if (isSubtype(t0, PrimaryType(TypeRegistry.future, args: [s1]))) {
+        return true;
+      }
+      //   - or T0 <: S1
+      if (isSubtype(t0, s1)) return true;
+      //   - or T0 is X0 and X0 has bound S0 and S0 <: T1
+      if (t0 case TypeParameterType(bound: var s0, promotion: null)
+          when isSubtype(s0, t1)) {
+        return true;
+      }
+      //   - or T0 is X0 & S0 and S0 <: T1
+      if (t0 case TypeParameterType(promotion: var s0?)
+          when isSubtype(s0, t1)) {
+        return true;
+      }
+      return false;
     }
 
     // Right Nullable: if T1 is S1? then:
@@ -721,29 +1029,33 @@
       var s1 = t1.withNullability(NullabilitySuffix.none);
 
       // - T0 <: T1 iff any of the following hold:
-      return
-          //   - either T0 <: S1
-          isSubtype(t0, s1) ||
-              //   - or T0 <: Null
-              isSubtype(t0, NullType.instance) ||
-              //   - or T0 is X0 and X0 has bound S0 and S0 <: T1
-              t0 is PrimaryType &&
-                  _isTypeVar(t0) &&
-                  isSubtype(_typeVarBound(t0), t1) ||
-              //   - or T0 is X0 & S0 and S0 <: T1
-              t0 is PromotedTypeVariableType && isSubtype(t0.promotion, t1);
+      //   - either T0 <: S1
+      if (isSubtype(t0, s1)) return true;
+      //   - or T0 <: Null
+      if (isSubtype(t0, NullType.instance)) return true;
+      //   - or T0 is X0 and X0 has bound S0 and S0 <: T1
+      if (t0 case TypeParameterType(bound: var s0, promotion: null)
+          when isSubtype(s0, t1)) {
+        return true;
+      }
+      //   - or T0 is X0 & S0 and S0 <: T1
+      if (t0 case TypeParameterType(promotion: var s0?)
+          when isSubtype(s0, t1)) {
+        return true;
+      }
+      return false;
     }
 
     // Left Promoted Variable: T0 is a promoted type variable X0 & S0
-    if (t0 is PromotedTypeVariableType) {
+    if (t0 case TypeParameterType(promotion: var s0?)) {
       // - and S0 <: T1
-      if (isSubtype(t0.promotion, t1)) return true;
+      if (isSubtype(s0, t1)) return true;
     }
 
     // Left Type Variable Bound: T0 is a type variable X0 with bound B0
-    if (t0 is PrimaryType && _isTypeVar(t0)) {
+    if (t0 case TypeParameterType(bound: var b0, promotion: null)) {
       // - and B0 <: T1
-      if (isSubtype(_typeVarBound(t0), t1)) return true;
+      if (isSubtype(b0, t1)) return true;
     }
 
     // Function Type/Function: T0 is a function type and T1 is Function
@@ -784,7 +1096,7 @@
 
     // Super-Interface: T0 is an interface type with super-interfaces S0,...Sn
     bool isSuperInterfaceSubtype() {
-      if (t0 is! PrimaryType || _isTypeVar(t0)) return false;
+      if (t0 is! PrimaryType) return false;
       var superInterfaceTemplate = _superInterfaceTemplates[t0.name];
       if (superInterfaceTemplate == null) {
         assert(false, 'Superinterfaces for $t0 not known');
@@ -804,16 +1116,15 @@
     bool isPositionalFunctionSubtype() {
       // Positional Function Types: T0 is U0 Function<X0 extends B00, ...,
       // Xk extends B0k>(V0 x0, ..., Vn xn, [Vn+1 xn+1, ..., Vm xm])
-      if (t0 is! FunctionType) return false;
-      var n = t0.positionalParameters.length;
-      // (Note: we don't support optional parameters)
-      var m = n;
+      if (t0 is! FunctionType || t0.namedParameters.isNotEmpty) return false;
+      var n = t0.requiredPositionalParameterCount;
+      var m = t0.positionalParameters.length;
 
       // - and T1 is U1 Function<Y0 extends B10, ..., Yk extends B1k>(S0 y0,
       //   ..., Sp yp, [Sp+1 yp+1, ..., Sq yq])
-      if (t1 is! FunctionType) return false;
-      var p = t1.positionalParameters.length;
-      var q = p;
+      if (t1 is! FunctionType || t1.namedParameters.isNotEmpty) return false;
+      var p = t1.requiredPositionalParameterCount;
+      var q = t1.positionalParameters.length;
 
       // - and p >= n
       if (p < n) return false;
@@ -849,24 +1160,78 @@
       // Named Function Types: T0 is U0 Function<X0 extends B00, ..., Xk extends
       // B0k>(V0 x0, ..., Vn xn, {r0n+1 Vn+1 xn+1, ..., r0m Vm xm}) where r0j is
       // empty or required for j in n+1...m
-      //
+      if (t0 is! FunctionType) return false;
+      var n = t0.positionalParameters.length;
+      if (t0.requiredPositionalParameterCount != n) return false;
+
       // - and T1 is U1 Function<Y0 extends B10, ..., Yk extends B1k>(S0 y0,
       //   ..., Sn yn, {r1n+1 Sn+1 yn+1, ..., r1q Sq yq}) where r1j is empty or
       //   required for j in n+1...q
+      if (t1 is! FunctionType ||
+          t1.positionalParameters.length != n ||
+          t1.requiredPositionalParameterCount != n) {
+        return false;
+      }
+
       // - and {yn+1, ... , yq} subsetof {xn+1, ... , xm}
+      var t1IndexToT0Index = <int>[];
+      for (var i = 0, j = 0;
+          i < t0.namedParameters.length || j < t1.namedParameters.length;) {
+        if (i >= t0.namedParameters.length) break;
+        if (j >= t1.namedParameters.length) return false;
+        switch (
+            t0.namedParameters[i].name.compareTo(t1.namedParameters[j].name)) {
+          case < 0:
+            i++;
+          case > 0:
+            return false;
+          default: // == 0
+            t1IndexToT0Index.add(i);
+            i++;
+            j++;
+        }
+      }
+
+      // (Note: no substitution is needed in the code below; we don't support
+      // type arguments on function types)
+
       // - and Si[Z0/Y0, ..., Zk/Yk] <: Vi[Z0/X0, ..., Zk/Xk] for i in 0...n
+      for (var i = 0; i < n; i++) {
+        if (!isSubtype(
+            t1.positionalParameters[i], t0.positionalParameters[i])) {
+          return false;
+        }
+      }
+
       // - and Si[Z0/Y0, ..., Zk/Yk] <: Tj[Z0/X0, ..., Zk/Xk] for i in n+1...q,
       //   yj = xi
+      for (var j = 0; j < t1IndexToT0Index.length; j++) {
+        var i = t1IndexToT0Index[j];
+        if (!isSubtype(
+            t1.namedParameters[j].type, t0.namedParameters[i].type)) {
+          return false;
+        }
+      }
+
       // - and for each j such that r0j is required, then there exists an i in
       //   n+1...q such that xj = yi, and r1i is required
+      for (var j = 0; j < t1IndexToT0Index.length; j++) {
+        var i = t1IndexToT0Index[j];
+        if (t1.namedParameters[j].isRequired &&
+            !t0.namedParameters[i].isRequired) {
+          return false;
+        }
+      }
+
       // - and U0[Z0/X0, ..., Zk/Xk] <: U1[Z0/Y0, ..., Zk/Yk]
+      if (!isSubtype(t0.returnType, t1.returnType)) return false;
+
       // - and B0i[Z0/X0, ..., Zk/Xk] === B1i[Z0/Y0, ..., Zk/Yk] for i in 0...k
       // - where the Zi are fresh type variables with bounds B0i[Z0/X0, ...,
       //   Zk/Xk]
-
-      // Note: nothing to do here; we don't support named arguments on function
-      // types.
-      return false;
+      // (No check needed here since we don't support type arguments on function
+      // types)
+      return true;
     }
 
     if (isNamedFunctionSubtype()) return true;
@@ -908,32 +1273,6 @@
     }
     return false;
   }
-
-  bool _isTypeVar(Type t) {
-    if (t is PromotedTypeVariableType &&
-        t.nullabilitySuffix == NullabilitySuffix.none) {
-      assert(_isTypeVar(t.innerType));
-      return true;
-    } else if (t is PrimaryType &&
-        t.nullabilitySuffix == NullabilitySuffix.none &&
-        t.args.isEmpty) {
-      return _typeVarBounds.containsKey(t.name);
-    } else {
-      return false;
-    }
-  }
-
-  Type _typeVarBound(Type t) => _typeVarBounds[_typeVarName(t)]!;
-
-  String _typeVarName(Type t) {
-    assert(_isTypeVar(t));
-    if (t is PromotedTypeVariableType &&
-        t.nullabilitySuffix == NullabilitySuffix.none) {
-      return _typeVarName(t.innerType);
-    } else {
-      return (t as PrimaryType).name;
-    }
-  }
 }
 
 /// Representation of the unknown type suitable for unit testing of code in the
@@ -963,7 +1302,8 @@
     implements SharedVoidTypeStructure<Type> {
   static final instance = VoidType._();
 
-  VoidType._() : super._('void', nullabilitySuffix: NullabilitySuffix.none);
+  VoidType._()
+      : super._(TypeRegistry.void_, nullabilitySuffix: NullabilitySuffix.none);
 
   @override
   Type withNullability(NullabilitySuffix suffix) => this;
@@ -976,9 +1316,9 @@
 /// that don't need special functionality for the [closureWithRespectToUnknown]
 /// and [recursivelyDemote] methods.
 abstract class _SpecialSimpleType extends PrimaryType {
-  _SpecialSimpleType._(super.name,
+  _SpecialSimpleType._(super.nameInfo,
       {super.nullabilitySuffix = NullabilitySuffix.none})
-      : super._withSpecialName();
+      : super._special();
 
   @override
   Type? closureWithRespectToUnknown({required bool covariant}) => null;
@@ -989,7 +1329,7 @@
 
 class _TypeParser {
   static final _typeTokenizationRegexp =
-      RegExp(_identifierPattern + r'|\(|\)|<|>|,|\?|\*|&|{|}');
+      RegExp(_identifierPattern + r'|\(|\)|<|>|,|\?|\*|&|{|}|\[|\]');
 
   static const _identifierPattern = '[_a-zA-Z][_a-zA-Z0-9]*';
 
@@ -1014,6 +1354,55 @@
         'Error parsing type `$_typeStr` at token $_currentToken: $message');
   }
 
+  List<NamedFunctionParameter> _parseNamedFunctionParameters() {
+    assert(_currentToken == '{');
+    _next();
+    var namedParameters = <NamedFunctionParameter>[];
+    while (true) {
+      var isRequired = _currentToken == 'required';
+      if (isRequired) {
+        _next();
+      }
+      var type = _parseType();
+      var name = _currentToken;
+      if (_identifierRegexp.matchAsPrefix(name) == null) {
+        _parseFailure('Expected an identifier');
+      }
+      namedParameters.add(NamedFunctionParameter(
+          name: name, type: type, isRequired: isRequired));
+      _next();
+      if (_currentToken == ',') {
+        _next();
+        continue;
+      }
+      if (_currentToken == '}') {
+        break;
+      }
+      _parseFailure('Expected `}` or `,`');
+    }
+    _next();
+    namedParameters.sort((a, b) => a.name.compareTo(b.name));
+    return namedParameters;
+  }
+
+  void _parseOptionalFunctionParameters(List<Type> positionalParameterTypes) {
+    assert(_currentToken == '[');
+    _next();
+    while (true) {
+      var type = _parseType();
+      positionalParameterTypes.add(type);
+      if (_currentToken == ',') {
+        _next();
+        continue;
+      }
+      if (_currentToken == ']') {
+        break;
+      }
+      _parseFailure('Expected `]` or `,`');
+    }
+    _next();
+  }
+
   List<NamedType> _parseRecordTypeNamedFields() {
     assert(_currentToken == '{');
     _next();
@@ -1039,6 +1428,7 @@
       _parseFailure('Must have at least one named type between {}');
     }
     _next();
+    namedTypes.sort((a, b) => a.name.compareTo(b.name));
     return namedTypes;
   }
 
@@ -1075,19 +1465,40 @@
       _next();
       return type.withNullability(NullabilitySuffix.star);
     } else if (_currentToken == '&') {
-      _next();
-      var promotion = _parseUnsuffixedType();
-      return PromotedTypeVariableType(type, promotion);
+      if (type case TypeParameterType(promotion: null)) {
+        _next();
+        var promotion = _parseUnsuffixedType();
+        return TypeParameterType(type.typeParameter, promotion: promotion);
+      } else {
+        _parseFailure(
+            'The type to the left of & must be an unpromoted type parameter');
+      }
     } else if (_currentToken == 'Function') {
       _next();
       if (_currentToken != '(') {
         _parseFailure('Expected `(`');
       }
       _next();
-      var parameterTypes = <Type>[];
+      var positionalParameterTypes = <Type>[];
+      List<NamedFunctionParameter>? namedFunctionParameters;
+      int? requiredPositionalParameterCount;
       if (_currentToken != ')') {
         while (true) {
-          parameterTypes.add(_parseType());
+          if (_currentToken == '{') {
+            namedFunctionParameters = _parseNamedFunctionParameters();
+            if (_currentToken != ')') {
+              _parseFailure('Expected `)`');
+            }
+            break;
+          } else if (_currentToken == '[') {
+            requiredPositionalParameterCount = positionalParameterTypes.length;
+            _parseOptionalFunctionParameters(positionalParameterTypes);
+            if (_currentToken != ')') {
+              _parseFailure('Expected `)`');
+            }
+            break;
+          }
+          positionalParameterTypes.add(_parseType());
           if (_currentToken == ')') break;
           if (_currentToken != ',') {
             _parseFailure('Expected `,` or `)`');
@@ -1096,7 +1507,10 @@
         }
       }
       _next();
-      return FunctionType(type, parameterTypes);
+      return FunctionType(type, positionalParameterTypes,
+          requiredPositionalParameterCount: requiredPositionalParameterCount ??
+              positionalParameterTypes.length,
+          namedParameters: namedFunctionParameters ?? const []);
     } else {
       return null;
     }
@@ -1118,9 +1532,15 @@
     //   typeArgs := `<` type (`,` type)* `>`
     //   nullability := (`?` | `*`)?
     //   suffix := `Function` `(` type (`,` type)* `)`
+    //           | `Function` `(` (type `,`)* namedFunctionParameters `)`
+    //           | `Function` `(` (type `,`)* optionalFunctionParameters `)`
     //           | `?`
     //           | `*`
     //           | `&` unsuffixedType
+    //   namedFunctionParameters := `{` namedFunctionParameter
+    //                              (`,` namedFunctionParameter)* `}`
+    //   namedFunctionParameter := `required`? type identifier
+    //   optionalFunctionParameters := `[` type (`,` type)* `]`
     // TODO(paulberry): support more syntax if needed
     var result = _parseUnsuffixedType();
     while (true) {
@@ -1173,38 +1593,49 @@
     } else {
       typeArgs = const [];
     }
-    if (typeName == 'dynamic') {
-      if (typeArgs.isNotEmpty) {
-        throw ParseError('`dynamic` does not accept type arguments');
-      }
-      return DynamicType.instance;
-    } else if (typeName == 'error') {
-      if (typeArgs.isNotEmpty) {
-        throw ParseError('`error` does not accept type arguments');
-      }
-      return InvalidType.instance;
-    } else if (typeName == 'FutureOr') {
-      if (typeArgs.length != 1) {
-        throw ParseError('`FutureOr` requires exactly one type argument');
-      }
-      return FutureOrType(typeArgs.single);
-    } else if (typeName == 'Never') {
-      if (typeArgs.isNotEmpty) {
-        throw ParseError('`Never` does not accept type arguments');
-      }
-      return NeverType.instance;
-    } else if (typeName == 'Null') {
-      if (typeArgs.isNotEmpty) {
-        throw ParseError('`Null` does not accept type arguments');
-      }
-      return NullType.instance;
-    } else if (typeName == 'void') {
-      if (typeArgs.isNotEmpty) {
-        throw ParseError('`void` does not accept type arguments');
-      }
-      return VoidType.instance;
-    } else {
-      return PrimaryType(typeName, args: typeArgs);
+    var nameInfo = TypeRegistry.lookup(typeName);
+    switch (nameInfo) {
+      case TypeParameter():
+        if (typeArgs.isNotEmpty) {
+          throw ParseError('Type parameter types do not accept type arguments');
+        }
+        return TypeParameterType(nameInfo);
+      case InterfaceTypeName():
+        return PrimaryType(nameInfo, args: typeArgs);
+      case SpecialTypeName():
+        if (typeName == 'dynamic') {
+          if (typeArgs.isNotEmpty) {
+            throw ParseError('`dynamic` does not accept type arguments');
+          }
+          return DynamicType.instance;
+        } else if (typeName == 'error') {
+          if (typeArgs.isNotEmpty) {
+            throw ParseError('`error` does not accept type arguments');
+          }
+          return InvalidType.instance;
+        } else if (typeName == 'FutureOr') {
+          if (typeArgs.length != 1) {
+            throw ParseError('`FutureOr` requires exactly one type argument');
+          }
+          return FutureOrType(typeArgs.single);
+        } else if (typeName == 'Never') {
+          if (typeArgs.isNotEmpty) {
+            throw ParseError('`Never` does not accept type arguments');
+          }
+          return NeverType.instance;
+        } else if (typeName == 'Null') {
+          if (typeArgs.isNotEmpty) {
+            throw ParseError('`Null` does not accept type arguments');
+          }
+          return NullType.instance;
+        } else if (typeName == 'void') {
+          if (typeArgs.isNotEmpty) {
+            throw ParseError('`void` does not accept type arguments');
+          }
+          return VoidType.instance;
+        } else {
+          throw UnimplementedError('Unknown special type name: $typeName');
+        }
     }
   }
 
@@ -1240,6 +1671,55 @@
   }
 }
 
+extension on List<NamedFunctionParameter> {
+  /// Calls [Type.closureWithRespectToUnknown] to translate every list member
+  /// into a type that doesn't involve the unknown type (`_`).  If no type would
+  /// be changed by this operation, returns `null`.
+  List<NamedFunctionParameter>? closureWithRespectToUnknown(
+      {required bool covariant}) {
+    List<NamedFunctionParameter>? newList;
+    for (int i = 0; i < length; i++) {
+      NamedFunctionParameter namedFunctionParameter = this[i];
+      Type? newType = namedFunctionParameter.type
+          .closureWithRespectToUnknown(covariant: covariant);
+      if (newList == null) {
+        if (newType == null) continue;
+        newList = sublist(0, i);
+      }
+      newList.add(newType == null
+          ? namedFunctionParameter
+          : NamedFunctionParameter(
+              isRequired: namedFunctionParameter.isRequired,
+              name: namedFunctionParameter.name,
+              type: newType));
+    }
+    return newList;
+  }
+
+  /// Calls [Type.recursivelyDemote] to translate every list member into a type
+  /// that doesn't involve any type promotion.  If no type would be changed by
+  /// this operation, returns `null`.
+  List<NamedFunctionParameter>? recursivelyDemote({required bool covariant}) {
+    List<NamedFunctionParameter>? newList;
+    for (int i = 0; i < length; i++) {
+      NamedFunctionParameter namedFunctionParameter = this[i];
+      Type? newType =
+          namedFunctionParameter.type.recursivelyDemote(covariant: covariant);
+      if (newList == null) {
+        if (newType == null) continue;
+        newList = sublist(0, i);
+      }
+      newList.add(newType == null
+          ? namedFunctionParameter
+          : NamedFunctionParameter(
+              isRequired: namedFunctionParameter.isRequired,
+              name: namedFunctionParameter.name,
+              type: newType));
+    }
+    return newList;
+  }
+}
+
 extension on List<Type> {
   /// Calls [Type.closureWithRespectToUnknown] to translate every list member
   /// into a type that doesn't involve the unknown type (`_`).  If no type would
diff --git a/pkg/_fe_analyzer_shared/test/mini_types_test.dart b/pkg/_fe_analyzer_shared/test/mini_types_test.dart
index 4dc17be..f99ede1 100644
--- a/pkg/_fe_analyzer_shared/test/mini_types_test.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_types_test.dart
@@ -8,19 +8,75 @@
 import 'mini_types.dart';
 
 main() {
+  late TypeParameter t;
+  late TypeParameter u;
+  late TypeParameter v;
+
+  setUp(() {
+    TypeRegistry.init();
+    t = TypeRegistry.addTypeParameter('T');
+    u = TypeRegistry.addTypeParameter('U');
+    v = TypeRegistry.addTypeParameter('V');
+  });
+
+  tearDown(() {
+    TypeRegistry.uninit();
+  });
+
   group('toString:', () {
     group('FunctionType:', () {
-      test('basic', () {
+      group('positional parameters:', () {
+        test('all required', () {
+          expect(
+              FunctionType(TypeParameterType(t),
+                  [TypeParameterType(u), TypeParameterType(v)]).toString(),
+              'T Function(U, V)');
+        });
+
+        test('all optional', () {
+          expect(
+              FunctionType(TypeParameterType(t),
+                      [TypeParameterType(u), TypeParameterType(v)],
+                      requiredPositionalParameterCount: 0)
+                  .toString(),
+              'T Function([U, V])');
+        });
+
+        test('mixed required and optional', () {
+          expect(
+              FunctionType(TypeParameterType(t),
+                      [TypeParameterType(u), TypeParameterType(v)],
+                      requiredPositionalParameterCount: 1)
+                  .toString(),
+              'T Function(U, [V])');
+        });
+      });
+
+      test('named parameters', () {
         expect(
-            FunctionType(PrimaryType('T'), [PrimaryType('U'), PrimaryType('V')])
-                .toString(),
-            'T Function(U, V)');
+            FunctionType(TypeParameterType(t), [], namedParameters: [
+              NamedFunctionParameter(
+                  isRequired: false, type: TypeParameterType(u), name: 'x'),
+              NamedFunctionParameter(
+                  isRequired: true, type: TypeParameterType(v), name: 'y')
+            ]).toString(),
+            'T Function({U x, required V y})');
+      });
+
+      test('positional and named parameters', () {
+        expect(
+            FunctionType(TypeParameterType(t), [
+              TypeParameterType(u)
+            ], namedParameters: [
+              NamedFunctionParameter(
+                  isRequired: false, type: TypeParameterType(v), name: 'y')
+            ]).toString(),
+            'T Function(U, {V y})');
       });
 
       test('needs parentheses', () {
         expect(
-            PromotedTypeVariableType(
-                    PrimaryType('T'), FunctionType(VoidType.instance, []))
+            TypeParameterType(t, promotion: FunctionType(VoidType.instance, []))
                 .toString(),
             'T&(void Function())');
       });
@@ -28,48 +84,36 @@
 
     group('PrimaryType:', () {
       test('simple', () {
-        expect(PrimaryType('T').toString(), 'T');
+        expect(TypeParameterType(t).toString(), 'T');
       });
 
       test('with arguments', () {
         expect(
-            PrimaryType('Map', args: [PrimaryType('T'), PrimaryType('U')])
-                .toString(),
+            PrimaryType(TypeRegistry.map,
+                args: [TypeParameterType(t), TypeParameterType(u)]).toString(),
             'Map<T, U>');
       });
     });
 
     group('PromotedTypeVariableType:', () {
       test('basic', () {
-        expect(
-            PromotedTypeVariableType(PrimaryType('T'), PrimaryType('U'))
-                .toString(),
+        expect(TypeParameterType(t, promotion: TypeParameterType(u)).toString(),
             'T&U');
       });
 
-      test('needs parentheses (left)', () {
-        expect(
-            PromotedTypeVariableType(
-                    PromotedTypeVariableType(
-                        PrimaryType('T'), PrimaryType('U')),
-                    PrimaryType('V'))
-                .toString(),
-            '(T&U)&V');
-      });
-
       test('needs parentheses (right)', () {
         expect(
-            PromotedTypeVariableType(
-                    PrimaryType('T'),
-                    PromotedTypeVariableType(
-                        PrimaryType('U'), PrimaryType('V')))
+            TypeParameterType(t,
+                    promotion:
+                        TypeParameterType(u, promotion: TypeParameterType(v)))
                 .toString(),
             'T&(U&V)');
       });
 
       test('needs parentheses (question)', () {
         expect(
-            PromotedTypeVariableType(PrimaryType('T'), PrimaryType('U'),
+            TypeParameterType(t,
+                    promotion: TypeParameterType(u),
                     nullabilitySuffix: NullabilitySuffix.question)
                 .toString(),
             '(T&U)?');
@@ -77,7 +121,8 @@
 
       test('needs parentheses (star)', () {
         expect(
-            PromotedTypeVariableType(PrimaryType('T'), PrimaryType('U'),
+            TypeParameterType(t,
+                    promotion: TypeParameterType(u),
                     nullabilitySuffix: NullabilitySuffix.star)
                 .toString(),
             '(T&U)*');
@@ -87,16 +132,15 @@
     group('QuestionType:', () {
       test('basic', () {
         expect(
-            PrimaryType('T', nullabilitySuffix: NullabilitySuffix.question)
+            TypeParameterType(t, nullabilitySuffix: NullabilitySuffix.question)
                 .toString(),
             'T?');
       });
 
       test('needs parentheses', () {
         expect(
-            PromotedTypeVariableType(
-                    PrimaryType('T'),
-                    PrimaryType('U',
+            TypeParameterType(t,
+                    promotion: TypeParameterType(u,
                         nullabilitySuffix: NullabilitySuffix.question))
                 .toString(),
             'T&(U?)');
@@ -111,7 +155,7 @@
 
       test('single positional argument', () {
         expect(
-            RecordType(positionalTypes: [PrimaryType('T')], namedTypes: [])
+            RecordType(positionalTypes: [TypeParameterType(t)], namedTypes: [])
                 .toString(),
             '(T,)');
       });
@@ -119,35 +163,35 @@
       test('multiple positional arguments', () {
         expect(
             RecordType(
-                positionalTypes: [PrimaryType('T'), PrimaryType('U')],
+                positionalTypes: [TypeParameterType(t), TypeParameterType(u)],
                 namedTypes: []).toString(),
             '(T, U)');
       });
 
       test('single named argument', () {
         expect(
-            RecordType(
-                    positionalTypes: [],
-                    namedTypes: [NamedType(name: 't', type: PrimaryType('T'))])
-                .toString(),
+            RecordType(positionalTypes: [], namedTypes: [
+              NamedType(name: 't', type: TypeParameterType(t))
+            ]).toString(),
             '({T t})');
       });
 
       test('multiple named arguments', () {
         expect(
             RecordType(positionalTypes: [], namedTypes: [
-              NamedType(name: 't', type: PrimaryType('T')),
-              NamedType(name: 'u', type: PrimaryType('U'))
+              NamedType(name: 't', type: TypeParameterType(t)),
+              NamedType(name: 'u', type: TypeParameterType(u))
             ]).toString(),
             '({T t, U u})');
       });
 
       test('both positional and named arguments', () {
         expect(
-            RecordType(
-                    positionalTypes: [PrimaryType('T')],
-                    namedTypes: [NamedType(name: 'u', type: PrimaryType('U'))])
-                .toString(),
+            RecordType(positionalTypes: [
+              TypeParameterType(t)
+            ], namedTypes: [
+              NamedType(name: 'u', type: TypeParameterType(u))
+            ]).toString(),
             '(T, {U u})');
       });
     });
@@ -155,15 +199,16 @@
     group('StarType:', () {
       test('basic', () {
         expect(
-            PrimaryType('T', nullabilitySuffix: NullabilitySuffix.star)
+            TypeParameterType(t, nullabilitySuffix: NullabilitySuffix.star)
                 .toString(),
             'T*');
       });
 
       test('needs parentheses', () {
         expect(
-            PromotedTypeVariableType(PrimaryType('T'),
-                    PrimaryType('U', nullabilitySuffix: NullabilitySuffix.star))
+            TypeParameterType(t,
+                    promotion: TypeParameterType(u,
+                        nullabilitySuffix: NullabilitySuffix.star))
                 .toString(),
             'T&(U*)');
       });
@@ -179,24 +224,24 @@
 
     group('primary type:', () {
       test('no type args', () {
-        var t = Type('int') as PrimaryType;
-        expect(t.name, 'int');
-        expect(t.args, isEmpty);
+        var type = Type('int') as PrimaryType;
+        expect(type.name, 'int');
+        expect(type.args, isEmpty);
       });
 
       test('type arg', () {
-        var t = Type('List<int>') as PrimaryType;
-        expect(t.name, 'List');
-        expect(t.args, hasLength(1));
-        expect(t.args[0].type, 'int');
+        var type = Type('List<int>') as PrimaryType;
+        expect(type.name, 'List');
+        expect(type.args, hasLength(1));
+        expect(type.args[0].type, 'int');
       });
 
       test('type args', () {
-        var t = Type('Map<int, String>') as PrimaryType;
-        expect(t.name, 'Map');
-        expect(t.args, hasLength(2));
-        expect(t.args[0].type, 'int');
-        expect(t.args[1].type, 'String');
+        var type = Type('Map<int, String>') as PrimaryType;
+        expect(type.name, 'Map');
+        expect(type.args, hasLength(2));
+        expect(type.args[0].type, 'int');
+        expect(type.args[1].type, 'String');
       });
 
       test('invalid type arg separator', () {
@@ -212,8 +257,8 @@
       });
 
       test('FutureOr', () {
-        var t = Type('FutureOr<int>') as FutureOrType;
-        expect(t.typeArgument.type, 'int');
+        var type = Type('FutureOr<int>') as FutureOrType;
+        expect(type.typeArgument.type, 'int');
       });
 
       test('Never', () {
@@ -234,31 +279,31 @@
     });
 
     test('unknown type', () {
-      var t = Type('_');
-      expect(t, TypeMatcher<UnknownType>());
+      var type = Type('_');
+      expect(type, TypeMatcher<UnknownType>());
     });
 
     test('question type', () {
-      var t = Type('int?');
-      expect(t.nullabilitySuffix, NullabilitySuffix.question);
-      expect(t.withNullability(NullabilitySuffix.none).type, 'int');
+      var type = Type('int?');
+      expect(type.nullabilitySuffix, NullabilitySuffix.question);
+      expect(type.withNullability(NullabilitySuffix.none).type, 'int');
     });
 
     test('star type', () {
-      var t = Type('int*');
-      expect(t.nullabilitySuffix, NullabilitySuffix.star);
-      expect(t.withNullability(NullabilitySuffix.none).type, 'int');
+      var type = Type('int*');
+      expect(type.nullabilitySuffix, NullabilitySuffix.star);
+      expect(type.withNullability(NullabilitySuffix.none).type, 'int');
     });
 
     test('promoted type variable', () {
-      var t = Type('T&int') as PromotedTypeVariableType;
-      expect(t.innerType.type, 'T');
-      expect(t.promotion.type, 'int');
+      var type = Type('T&int') as TypeParameterType;
+      expect(type.typeParameter, t);
+      expect(type.promotion!.type, 'int');
     });
 
     test('parenthesized type', () {
-      var t = Type('(int)');
-      expect(t.type, 'int');
+      var type = Type('(int)');
+      expect(type.type, 'int');
     });
 
     test('invalid token terminating parenthesized type', () {
@@ -267,24 +312,101 @@
 
     group('function type:', () {
       test('no parameters', () {
-        var t = Type('int Function()') as FunctionType;
-        expect(t.returnType.type, 'int');
-        expect(t.positionalParameters, isEmpty);
+        var type = Type('int Function()') as FunctionType;
+        expect(type.returnType.type, 'int');
+        expect(type.positionalParameters, isEmpty);
+        expect(type.requiredPositionalParameterCount, 0);
+        expect(type.namedParameters, isEmpty);
       });
 
-      test('positional parameter', () {
-        var t = Type('int Function(String)') as FunctionType;
-        expect(t.returnType.type, 'int');
-        expect(t.positionalParameters, hasLength(1));
-        expect(t.positionalParameters[0].type, 'String');
+      test('required positional parameter', () {
+        var type = Type('int Function(String)') as FunctionType;
+        expect(type.returnType.type, 'int');
+        expect(type.positionalParameters, hasLength(1));
+        expect(type.positionalParameters[0].type, 'String');
+        expect(type.requiredPositionalParameterCount, 1);
+        expect(type.namedParameters, isEmpty);
       });
 
-      test('positional parameters', () {
-        var t = Type('int Function(String, double)') as FunctionType;
-        expect(t.returnType.type, 'int');
-        expect(t.positionalParameters, hasLength(2));
-        expect(t.positionalParameters[0].type, 'String');
-        expect(t.positionalParameters[1].type, 'double');
+      test('required positional parameters', () {
+        var type = Type('int Function(String, double)') as FunctionType;
+        expect(type.returnType.type, 'int');
+        expect(type.positionalParameters, hasLength(2));
+        expect(type.positionalParameters[0].type, 'String');
+        expect(type.positionalParameters[1].type, 'double');
+        expect(type.requiredPositionalParameterCount, 2);
+        expect(type.namedParameters, isEmpty);
+      });
+
+      test('optional positional parameter', () {
+        var type = Type('int Function([String])') as FunctionType;
+        expect(type.returnType.type, 'int');
+        expect(type.positionalParameters, hasLength(1));
+        expect(type.positionalParameters[0].type, 'String');
+        expect(type.requiredPositionalParameterCount, 0);
+        expect(type.namedParameters, isEmpty);
+      });
+
+      test('optional positional parameters', () {
+        var type = Type('int Function([String, double])') as FunctionType;
+        expect(type.returnType.type, 'int');
+        expect(type.positionalParameters, hasLength(2));
+        expect(type.positionalParameters[0].type, 'String');
+        expect(type.positionalParameters[1].type, 'double');
+        expect(type.requiredPositionalParameterCount, 0);
+        expect(type.namedParameters, isEmpty);
+      });
+
+      group('named parameter:', () {
+        test('not required', () {
+          var type = Type('int Function({String x})') as FunctionType;
+          expect(type.returnType.type, 'int');
+          expect(type.positionalParameters, isEmpty);
+          expect(type.requiredPositionalParameterCount, 0);
+          expect(type.namedParameters, hasLength(1));
+          expect(type.namedParameters[0].isRequired, false);
+          expect(type.namedParameters[0].type.type, 'String');
+          expect(type.namedParameters[0].name, 'x');
+        });
+
+        test('required', () {
+          var type = Type('int Function({required String x})') as FunctionType;
+          expect(type.returnType.type, 'int');
+          expect(type.positionalParameters, isEmpty);
+          expect(type.requiredPositionalParameterCount, 0);
+          expect(type.namedParameters, hasLength(1));
+          expect(type.namedParameters[0].isRequired, true);
+          expect(type.namedParameters[0].type.type, 'String');
+          expect(type.namedParameters[0].name, 'x');
+        });
+      });
+
+      test('named parameters', () {
+        var type = Type('int Function({String x, double y})') as FunctionType;
+        expect(type.returnType.type, 'int');
+        expect(type.positionalParameters, isEmpty);
+        expect(type.requiredPositionalParameterCount, 0);
+        expect(type.namedParameters, hasLength(2));
+        expect(type.namedParameters[0].isRequired, false);
+        expect(type.namedParameters[0].type.type, 'String');
+        expect(type.namedParameters[0].name, 'x');
+        expect(type.namedParameters[1].isRequired, false);
+        expect(type.namedParameters[1].type.type, 'double');
+        expect(type.namedParameters[1].name, 'y');
+      });
+
+      test('named parameter sorting', () {
+        var type = Type('int Function({double y, String x})') as FunctionType;
+        expect(type.returnType.type, 'int');
+        expect(type.positionalParameters, isEmpty);
+        expect(type.requiredPositionalParameterCount, 0);
+        expect(type.namedParameters, hasLength(2));
+        expect(type.namedParameters[0].isRequired, false);
+        expect(type.namedParameters[0].type.type, 'String');
+        expect(type.namedParameters[0].name, 'x');
+        expect(type.namedParameters[1].isRequired, false);
+        expect(type.namedParameters[1].type.type, 'double');
+        expect(type.namedParameters[1].name, 'y');
       });
 
       test('invalid parameter separator', () {
@@ -299,25 +421,25 @@
 
     group('record type:', () {
       test('no fields', () {
-        var t = Type('()') as RecordType;
-        expect(t.positionalTypes, isEmpty);
-        expect(t.namedTypes, isEmpty);
+        var type = Type('()') as RecordType;
+        expect(type.positionalTypes, isEmpty);
+        expect(type.namedTypes, isEmpty);
       });
 
       test('named field', () {
-        var t = Type('({int x})') as RecordType;
-        expect(t.positionalTypes, isEmpty);
-        expect(t.namedTypes, hasLength(1));
-        expect(t.namedTypes[0].name, 'x');
-        expect(t.namedTypes[0].type.type, 'int');
+        var type = Type('({int x})') as RecordType;
+        expect(type.positionalTypes, isEmpty);
+        expect(type.namedTypes, hasLength(1));
+        expect(type.namedTypes[0].name, 'x');
+        expect(type.namedTypes[0].type.type, 'int');
       });
 
       test('named field followed by comma', () {
-        var t = Type('({int x,})') as RecordType;
-        expect(t.positionalTypes, isEmpty);
-        expect(t.namedTypes, hasLength(1));
-        expect(t.namedTypes[0].name, 'x');
-        expect(t.namedTypes[0].type.type, 'int');
+        var type = Type('({int x,})') as RecordType;
+        expect(type.positionalTypes, isEmpty);
+        expect(type.namedTypes, hasLength(1));
+        expect(type.namedTypes[0].name, 'x');
+        expect(type.namedTypes[0].type.type, 'int');
       });
 
       test('named field followed by invalid token', () {
@@ -329,13 +451,13 @@
       });
 
       test('named fields', () {
-        var t = Type('({int x, String y})') as RecordType;
-        expect(t.positionalTypes, isEmpty);
-        expect(t.namedTypes, hasLength(2));
-        expect(t.namedTypes[0].name, 'x');
-        expect(t.namedTypes[0].type.type, 'int');
-        expect(t.namedTypes[1].name, 'y');
-        expect(t.namedTypes[1].type.type, 'String');
+        var type = Type('({int x, String y})') as RecordType;
+        expect(type.positionalTypes, isEmpty);
+        expect(type.namedTypes, hasLength(2));
+        expect(type.namedTypes[0].name, 'x');
+        expect(type.namedTypes[0].type.type, 'int');
+        expect(type.namedTypes[1].name, 'y');
+        expect(type.namedTypes[1].type.type, 'String');
       });
 
       test('curly braces followed by invalid token', () {
@@ -347,38 +469,38 @@
       });
 
       test('positional field', () {
-        var t = Type('(int,)') as RecordType;
-        expect(t.namedTypes, isEmpty);
-        expect(t.positionalTypes, hasLength(1));
-        expect(t.positionalTypes[0].type, 'int');
+        var type = Type('(int,)') as RecordType;
+        expect(type.namedTypes, isEmpty);
+        expect(type.positionalTypes, hasLength(1));
+        expect(type.positionalTypes[0].type, 'int');
       });
 
       group('positional fields:', () {
         test('two', () {
-          var t = Type('(int, String)') as RecordType;
-          expect(t.namedTypes, isEmpty);
-          expect(t.positionalTypes, hasLength(2));
-          expect(t.positionalTypes[0].type, 'int');
-          expect(t.positionalTypes[1].type, 'String');
+          var type = Type('(int, String)') as RecordType;
+          expect(type.namedTypes, isEmpty);
+          expect(type.positionalTypes, hasLength(2));
+          expect(type.positionalTypes[0].type, 'int');
+          expect(type.positionalTypes[1].type, 'String');
         });
 
         test('three', () {
-          var t = Type('(int, String, double)') as RecordType;
-          expect(t.namedTypes, isEmpty);
-          expect(t.positionalTypes, hasLength(3));
-          expect(t.positionalTypes[0].type, 'int');
-          expect(t.positionalTypes[1].type, 'String');
-          expect(t.positionalTypes[2].type, 'double');
+          var type = Type('(int, String, double)') as RecordType;
+          expect(type.namedTypes, isEmpty);
+          expect(type.positionalTypes, hasLength(3));
+          expect(type.positionalTypes[0].type, 'int');
+          expect(type.positionalTypes[1].type, 'String');
+          expect(type.positionalTypes[2].type, 'double');
         });
       });
 
       test('named and positional fields', () {
-        var t = Type('(int, {String x})') as RecordType;
-        expect(t.positionalTypes, hasLength(1));
-        expect(t.positionalTypes[0].type, 'int');
-        expect(t.namedTypes, hasLength(1));
-        expect(t.namedTypes[0].name, 'x');
-        expect(t.namedTypes[0].type.type, 'String');
+        var type = Type('(int, {String x})') as RecordType;
+        expect(type.positionalTypes, hasLength(1));
+        expect(type.positionalTypes[0].type, 'int');
+        expect(type.namedTypes, hasLength(1));
+        expect(type.namedTypes[0].name, 'x');
+        expect(type.namedTypes[0].type.type, 'String');
       });
 
       test('terminated by invalid token', () {
@@ -454,6 +576,35 @@
               'void Function(T, String)');
         });
       });
+
+      group('named parameters:', () {
+        test('unchanged', () {
+          expect(
+              Type('void Function({int x, String y})')
+                  .recursivelyDemote(covariant: true),
+              isNull);
+          expect(
+              Type('void Function({int x, String y})')
+                  .recursivelyDemote(covariant: false),
+              isNull);
+        });
+
+        test('covariant', () {
+          expect(
+              Type('void Function({T&int x, String y})')
+                  .recursivelyDemote(covariant: true)!
+                  .type,
+              'void Function({Never x, String y})');
+        });
+
+        test('contravariant', () {
+          expect(
+              Type('void Function({T&int x, String y})')
+                  .recursivelyDemote(covariant: false)!
+                  .type,
+              'void Function({T x, String y})');
+        });
+      });
     });
 
     group('NonFunctionType', () {
@@ -641,6 +792,35 @@
               'void Function(Object?, String)');
         });
       });
+
+      group('named parameters:', () {
+        test('unchanged', () {
+          expect(
+              Type('void Function({int x, String y})')
+                  .closureWithRespectToUnknown(covariant: true),
+              isNull);
+          expect(
+              Type('void Function({int x, String y})')
+                  .closureWithRespectToUnknown(covariant: false),
+              isNull);
+        });
+
+        test('covariant', () {
+          expect(
+              Type('void Function({_ x, String y})')
+                  .closureWithRespectToUnknown(covariant: true)!
+                  .type,
+              'void Function({Never x, String y})');
+        });
+
+        test('contravariant', () {
+          expect(
+              Type('void Function({_ x, String y})')
+                  .closureWithRespectToUnknown(covariant: false)!
+                  .type,
+              'void Function({Object? x, String y})');
+        });
+      });
     });
 
     group('NonFunctionType', () {
diff --git a/pkg/_fe_analyzer_shared/test/scanner_benchmark.dart b/pkg/_fe_analyzer_shared/test/scanner_benchmark.dart
new file mode 100644
index 0000000..6c39cb6
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/scanner_benchmark.dart
@@ -0,0 +1,124 @@
+// Copyright (c) 2024, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io';
+import 'dart:typed_data';
+
+import 'package:_fe_analyzer_shared/src/scanner/scanner.dart';
+
+void main(List<String> args) {
+  if (args.isEmpty || args.length > 2) {
+    throw "Expected 1 or 2 argument: <dart file> and either "
+        "--string or --bytes or --stringtobytes or --count";
+  }
+  File? f;
+  ScanType scanType = ScanType.string;
+  for (String arg in args) {
+    if (arg == "--string") {
+      scanType = ScanType.string;
+    } else if (arg == "--bytes") {
+      scanType = ScanType.bytes;
+    } else if (arg == "--stringtobytes") {
+      scanType = ScanType.stringAsBytes;
+    } else if (arg == "--count") {
+      scanType = ScanType.countLfs;
+    } else if (arg.startsWith("--")) {
+      throw "Unsupported setting: $arg";
+    } else {
+      f = new File(args[0]);
+    }
+  }
+  if (f == null) {
+    throw "No input file given.";
+  }
+  if (!f.existsSync()) {
+    throw "File $f doesn't exist.";
+  }
+  String content = f.readAsStringSync();
+  String contentZeroTerminated = content + '\x00';
+  Uint8List contentBytes = f.readAsBytesSync();
+
+  int numErrors = 0;
+  Stopwatch stopwatch = new Stopwatch()..start();
+  const int iterations = 1000;
+  int lengthProcessed;
+  bool hasErrors = false;
+
+  switch (scanType) {
+    case ScanType.string:
+      lengthProcessed = content.length;
+      for (int i = 0; i < iterations; i++) {
+        hasErrors = scanString(
+          content,
+          configuration: new ScannerConfiguration(
+            enableExtensionMethods: true,
+            enableNonNullable: true,
+            enableTripleShift: true,
+          ),
+          includeComments: true,
+        ).hasErrors;
+      }
+    case ScanType.bytes:
+      lengthProcessed = contentBytes.length;
+      for (int i = 0; i < iterations; i++) {
+        hasErrors = scan(
+          contentBytes,
+          configuration: new ScannerConfiguration(
+            enableExtensionMethods: true,
+            enableNonNullable: true,
+            enableTripleShift: true,
+          ),
+          includeComments: true,
+        ).hasErrors;
+      }
+    case ScanType.stringAsBytes:
+      lengthProcessed = content.length;
+      for (int i = 0; i < iterations; i++) {
+        Uint8List tmp = utf8.encode(contentZeroTerminated);
+        hasErrors = scan(
+          tmp,
+          configuration: new ScannerConfiguration(
+            enableExtensionMethods: true,
+            enableNonNullable: true,
+            enableTripleShift: true,
+          ),
+          includeComments: true,
+        ).hasErrors;
+      }
+    case ScanType.countLfs:
+      lengthProcessed = contentBytes.length;
+      for (int i = 0; i < iterations; i++) {
+        hasErrors = false;
+        int count = 0;
+        for (int i = 0; i < contentBytes.length; i++) {
+          if (contentBytes[i] == 10) count++;
+        }
+        // Make sure the above can't be optimized away.
+        if (count == 42) print("Exactly 42 LFs");
+      }
+      if (hasErrors) {
+        numErrors++;
+      }
+  }
+  stopwatch.stop();
+  print("Scanned $lengthProcessed ${scanType.what} $iterations times "
+      "in ${stopwatch.elapsed}");
+  print("Found errors $numErrors times");
+  double lengthPerMicrosecond =
+      (lengthProcessed * iterations) / stopwatch.elapsedMicroseconds;
+  print("That's $lengthPerMicrosecond ${scanType.what} per microsecond");
+  print("");
+}
+
+enum ScanType {
+  string("string characters"),
+  bytes("bytes"),
+  stringAsBytes("string characters as bytes"),
+  countLfs("bytes");
+
+  final String what;
+
+  const ScanType(this.what);
+}
diff --git a/pkg/_fe_analyzer_shared/test/type_inference/type_constraint_gatherer_test.dart b/pkg/_fe_analyzer_shared/test/type_inference/type_constraint_gatherer_test.dart
new file mode 100644
index 0000000..c860637
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/type_inference/type_constraint_gatherer_test.dart
@@ -0,0 +1,638 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:_fe_analyzer_shared/src/type_inference/nullability_suffix.dart';
+import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart';
+import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
+import 'package:checks/checks.dart';
+import 'package:test/scaffolding.dart';
+
+import '../mini_ast.dart';
+import '../mini_types.dart';
+
+main() {
+  setUp(() {
+    TypeRegistry.init();
+    TypeRegistry.addInterfaceTypeName('Contravariant');
+    TypeRegistry.addInterfaceTypeName('Invariant');
+    TypeRegistry.addInterfaceTypeName('MyListOfInt');
+    TypeRegistry.addInterfaceTypeName('Unrelated');
+  });
+
+  tearDown(() {
+    TypeRegistry.uninit();
+  });
+
+  group('performSubtypeConstraintGenerationForFunctionTypes:', () {
+    test('Matching functions with no parameters', () {
+      var tcg = _TypeConstraintGatherer({});
+      check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+              Type('void Function()'), Type('void Function()'),
+              leftSchema: false, astNodeForTesting: Node.placeholder()))
+          .equals(true);
+      check(tcg._constraints).isEmpty();
+    });
+
+    group('Matching functions with positional parameters:', () {
+      test('None optional', () {
+        var tcg = _TypeConstraintGatherer({'T', 'U'});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('void Function(int, String)'), Type('void Function(T, U)'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(true);
+        check(tcg._constraints).unorderedEquals(['T <: int', 'U <: String']);
+      });
+
+      test('Some optional on LHS', () {
+        var tcg = _TypeConstraintGatherer({'T', 'U'});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('void Function(int, [String])'),
+                Type('void Function(T, U)'),
+                leftSchema: false,
+                astNodeForTesting: Node.placeholder()))
+            .equals(true);
+        check(tcg._constraints).unorderedEquals(['T <: int', 'U <: String']);
+      });
+    });
+
+    group('Non-matching functions with positional parameters:', () {
+      test('Non-matching due to return types', () {
+        var tcg = _TypeConstraintGatherer({});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('int Function(int)'), Type('String Function(int)'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(null);
+        check(tcg._constraints).isEmpty();
+      });
+
+      test('Non-matching due to parameter types', () {
+        var tcg = _TypeConstraintGatherer({});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('void Function(int)'), Type('void Function(String)'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(null);
+        check(tcg._constraints).isEmpty();
+      });
+
+      test('Non-matching due to optional parameters on RHS', () {
+        var tcg = _TypeConstraintGatherer({});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('void Function()'), Type('void Function([int])'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(null);
+        check(tcg._constraints).isEmpty();
+      });
+
+      test('Non-matching due to more parameters being required on LHS', () {
+        var tcg = _TypeConstraintGatherer({});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('void Function(int)'), Type('void Function([int])'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(null);
+        check(tcg._constraints).isEmpty();
+      });
+    });
+
+    group('Matching functions with named parameters:', () {
+      test('None optional', () {
+        var tcg = _TypeConstraintGatherer({'T', 'U'});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('void Function({required int x, required String y})'),
+                Type('void Function({required T x, required U y})'),
+                leftSchema: false,
+                astNodeForTesting: Node.placeholder()))
+            .equals(true);
+        check(tcg._constraints).unorderedEquals(['T <: int', 'U <: String']);
+      });
+
+      test('Some optional on LHS', () {
+        var tcg = _TypeConstraintGatherer({'T', 'U'});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('void Function({required int x, String y})'),
+                Type('void Function({required T x, required U y})'),
+                leftSchema: false,
+                astNodeForTesting: Node.placeholder()))
+            .equals(true);
+        check(tcg._constraints).unorderedEquals(['T <: int', 'U <: String']);
+      });
+
+      test('Optional named parameter on LHS', () {
+        var tcg = _TypeConstraintGatherer({'T'});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('void Function(int, {String x})'),
+                Type('void Function(T)'),
+                leftSchema: false,
+                astNodeForTesting: Node.placeholder()))
+            .equals(true);
+        check(tcg._constraints).unorderedEquals(['T <: int']);
+      });
+
+      test('Extra optional named parameter on LHS', () {
+        var tcg = _TypeConstraintGatherer({'T'});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('void Function({String x, int y})'),
+                Type('void Function({T y})'),
+                leftSchema: false,
+                astNodeForTesting: Node.placeholder()))
+            .equals(true);
+        check(tcg._constraints).unorderedEquals(['T <: int']);
+      });
+    });
+
+    group('Non-matching functions with named parameters:', () {
+      test('Non-matching due to return types', () {
+        var tcg = _TypeConstraintGatherer({});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('int Function({int x})'), Type('String Function({int x})'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(null);
+        check(tcg._constraints).isEmpty();
+      });
+
+      test('Non-matching due to named parameter types', () {
+        var tcg = _TypeConstraintGatherer({});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('void Function({int x})'),
+                Type('void Function({String x})'),
+                leftSchema: false,
+                astNodeForTesting: Node.placeholder()))
+            .equals(null);
+        check(tcg._constraints).isEmpty();
+      });
+
+      test('Non-matching due to required named parameter on LHS', () {
+        var tcg = _TypeConstraintGatherer({});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('void Function({required int x})'),
+                Type('void Function()'),
+                leftSchema: false,
+                astNodeForTesting: Node.placeholder()))
+            .equals(null);
+        check(tcg._constraints).isEmpty();
+      });
+
+      test('Non-matching due to optional named parameter on RHS', () {
+        var tcg = _TypeConstraintGatherer({});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('void Function()'), Type('void Function({int x})'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(null);
+        check(tcg._constraints).isEmpty();
+      });
+
+      test('Non-matching due to named parameter on RHS, with decoys on LHS',
+          () {
+        var tcg = _TypeConstraintGatherer({});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('void Function({int x, int y})'),
+                Type('void Function({int z})'),
+                leftSchema: false,
+                astNodeForTesting: Node.placeholder()))
+            .equals(null);
+        check(tcg._constraints).isEmpty();
+      });
+    });
+
+    test('Matching functions with named and positional parameters', () {
+      var tcg = _TypeConstraintGatherer({'T', 'U'});
+      check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+              Type('void Function(int, {String y})'),
+              Type('void Function(T, {U y})'),
+              leftSchema: false,
+              astNodeForTesting: Node.placeholder()))
+          .equals(true);
+      check(tcg._constraints).unorderedEquals(['T <: int', 'U <: String']);
+    });
+
+    group('Non-matching functions with named and positional parameters:', () {
+      test(
+          'Non-matching due to LHS not accepting optional positional parameter',
+          () {
+        var tcg = _TypeConstraintGatherer({});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('void Function(int, {String x})'),
+                Type('void Function(int, [String])'),
+                leftSchema: false,
+                astNodeForTesting: Node.placeholder()))
+            .equals(null);
+        check(tcg._constraints).isEmpty();
+      });
+
+      test('Non-matching due to positional parameter length mismatch', () {
+        var tcg = _TypeConstraintGatherer({});
+        check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
+                Type('void Function(int, {String x})'),
+                Type('void Function(int, String)'),
+                leftSchema: false,
+                astNodeForTesting: Node.placeholder()))
+            .equals(null);
+        check(tcg._constraints).isEmpty();
+      });
+    });
+  });
+
+  group('performSubtypeConstraintGenerationForFutureOr:', () {
+    test('FutureOr matches FutureOr with constraints based on arguments', () {
+      // `FutureOr<T> <# FutureOr<int>` reduces to `T <# int`
+      var tcg = _TypeConstraintGatherer({'T'});
+      check(tcg.performSubtypeConstraintGenerationForFutureOr(
+              Type('FutureOr<T>'), Type('FutureOr<int>'),
+              leftSchema: false, astNodeForTesting: Node.placeholder()))
+          .isTrue();
+      check(tcg._constraints).deepEquals(['T <: int']);
+    });
+
+    test('FutureOr does not match FutureOr because arguments fail to match',
+        () {
+      // `FutureOr<int> <# FutureOr<String>` reduces to `int <# String`
+      var tcg = _TypeConstraintGatherer({});
+      check(tcg.performSubtypeConstraintGenerationForFutureOr(
+              Type('FutureOr<int>'), Type('FutureOr<String>'),
+              leftSchema: false, astNodeForTesting: Node.placeholder()))
+          .isFalse();
+      check(tcg._constraints).isEmpty();
+    });
+
+    test('Future matches FutureOr favoring Future branch', () {
+      // `Future<int> <# FutureOr<T>` could match in two possible ways:
+      // - `Future<int> <# Future<T>` (taking the "Future" branch of the
+      //   FutureOr), producing `int <: T`
+      // - `Future<int> <# T` (taking the "non-Future" branch of the FutureOr),
+      //   producing `Future<int> <: T`
+      // In cases where both branches produce a constraint, the "Future" branch
+      // is favored.
+      var tcg = _TypeConstraintGatherer({'T'});
+      check(tcg.performSubtypeConstraintGenerationForFutureOr(
+              Type('Future<int>'), Type('FutureOr<T>'),
+              leftSchema: false, astNodeForTesting: Node.placeholder()))
+          .isTrue();
+      check(tcg._constraints).deepEquals(['int <: T']);
+    });
+
+    test('Future matches FutureOr preferring to generate constraints', () {
+      // `Future<_> <# FutureOr<T>` could match in two possible ways:
+      // - `Future<_> <# Future<T>` (taking the "Future" branch of the
+      //   FutureOr), producing no constraints
+      // - `Future<_> <# T` (taking the "non-Future" branch of the FutureOr),
+      //   producing `Future<_> <: T`
+      // In cases where only one branch produces a constraint, that branch is
+      // favored.
+      var tcg = _TypeConstraintGatherer({'T'});
+      check(tcg.performSubtypeConstraintGenerationForFutureOr(
+              Type('Future<_>'), Type('FutureOr<T>'),
+              leftSchema: true, astNodeForTesting: Node.placeholder()))
+          .isTrue();
+      check(tcg._constraints).deepEquals(['Future<_> <: T']);
+    });
+
+    test('Type matches FutureOr favoring the Future branch', () {
+      // `T <# FutureOr<int>` could match in two possible ways:
+      // - `T <# Future<int>` (taking the "Future" branch of the FutureOr),
+      //   producing `T <: Future<int>`
+      // - `T <# int` (taking the "non-Future" branch of the FutureOr),
+      //   producing `T <: int`
+      // In cases where both branches produce a constraint, the "Future" branch
+      // is favored.
+      var tcg = _TypeConstraintGatherer({'T'});
+      check(tcg.performSubtypeConstraintGenerationForFutureOr(
+              Type('T'), Type('FutureOr<int>'),
+              leftSchema: false, astNodeForTesting: Node.placeholder()))
+          .isTrue();
+      check(tcg._constraints).deepEquals(['T <: Future<int>']);
+    });
+
+    test('Future matches FutureOr with no constraints', () {
+      // `Future<int> <# FutureOr<int>` matches (taking the "Future" branch of
+      // the FutureOr) without generating any constraints.
+      var tcg = _TypeConstraintGatherer({});
+      check(tcg.performSubtypeConstraintGenerationForFutureOr(
+              Type('Future<int>'), Type('FutureOr<int>'),
+              leftSchema: false, astNodeForTesting: Node.placeholder()))
+          .isTrue();
+      check(tcg._constraints).isEmpty();
+    });
+
+    test('Type matches FutureOr favoring the branch that matches', () {
+      // `List<T> <# FutureOr<List<int>>` could only match by taking the
+      // "non-Future" branch of the FutureOr, so the constraint `T <: int` is
+      // produced.
+      var tcg = _TypeConstraintGatherer({'T'});
+      check(tcg.performSubtypeConstraintGenerationForFutureOr(
+              Type('List<T>'), Type('FutureOr<List<int>>'),
+              leftSchema: false, astNodeForTesting: Node.placeholder()))
+          .isTrue();
+      check(tcg._constraints).deepEquals(['T <: int']);
+    });
+
+    group('Nullable FutureOr on RHS:', () {
+      test('Does not match, according to spec', () {
+        var tcg = _TypeConstraintGatherer({'T'});
+        check(tcg.performSubtypeConstraintGenerationForFutureOr(
+                Type('FutureOr<T>'), Type('FutureOr<int>?'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .isFalse();
+        check(tcg._constraints).isEmpty();
+      });
+
+      test('Matches, according to CFE discrepancy', () {
+        var tcg = _TypeConstraintGatherer({'T'},
+            enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr: true);
+        check(tcg.performSubtypeConstraintGenerationForFutureOr(
+                Type('FutureOr<T>'), Type('FutureOr<int>?'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .isTrue();
+        check(tcg._constraints).deepEquals(['T <: int']);
+      });
+    });
+
+    group('Nullable FutureOr on LHS:', () {
+      test('Does not match, according to spec', () {
+        var tcg = _TypeConstraintGatherer({'T'});
+        check(tcg.performSubtypeConstraintGenerationForFutureOr(
+                Type('FutureOr<T>?'), Type('FutureOr<int>'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .isFalse();
+        check(tcg._constraints).isEmpty();
+      });
+
+      test('Matches, according to CFE discrepancy', () {
+        var tcg = _TypeConstraintGatherer({'T'},
+            enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr: true);
+        check(tcg.performSubtypeConstraintGenerationForFutureOr(
+                Type('FutureOr<T>?'), Type('FutureOr<int>'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .isTrue();
+        check(tcg._constraints).deepEquals(['T <: int']);
+      });
+    });
+  });
+
+  group('performSubtypeConstraintGenerationForTypeDeclarationTypes', () {
+    group('Same base type on both sides:', () {
+      test('Covariant, matching', () {
+        var tcg = _TypeConstraintGatherer({'T', 'U'});
+        check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
+                Type('Map<T, U>'), Type('Map<int, String>'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(true);
+        check(tcg._constraints).unorderedEquals(['T <: int', 'U <: String']);
+      });
+
+      test('Covariant, not matching', () {
+        var tcg = _TypeConstraintGatherer({'T'});
+        check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
+                Type('Map<T, int>'), Type('Map<int, String>'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(false);
+        check(tcg._constraints).isEmpty();
+      });
+
+      test('Contravariant, matching', () {
+        var tcg = _TypeConstraintGatherer({'T', 'U'});
+        tcg.typeAnalyzerOperations.addVariance(
+            'Contravariant', [Variance.contravariant, Variance.contravariant]);
+        check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
+                Type('Contravariant<T, U>'), Type('Contravariant<int, String>'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(true);
+        check(tcg._constraints).unorderedEquals(['int <: T', 'String <: U']);
+      });
+
+      test('Contravariant, not matching', () {
+        var tcg = _TypeConstraintGatherer({'T'});
+        tcg.typeAnalyzerOperations.addVariance(
+            'Contravariant', [Variance.contravariant, Variance.contravariant]);
+        check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
+                Type('Contravariant<T, int>'),
+                Type('Contravariant<int, String>'),
+                leftSchema: false,
+                astNodeForTesting: Node.placeholder()))
+            .equals(false);
+        check(tcg._constraints).isEmpty();
+      });
+
+      test('Invariant, matching', () {
+        var tcg = _TypeConstraintGatherer({'T', 'U'});
+        tcg.typeAnalyzerOperations
+            .addVariance('Invariant', [Variance.invariant, Variance.invariant]);
+        check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
+                Type('Invariant<T, U>'), Type('Invariant<int, String>'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(true);
+        check(tcg._constraints).unorderedEquals(
+            ['T <: int', 'U <: String', 'int <: T', 'String <: U']);
+      });
+
+      test('Invariant, not matching', () {
+        var tcg = _TypeConstraintGatherer({'T'});
+        tcg.typeAnalyzerOperations
+            .addVariance('Invariant', [Variance.invariant, Variance.invariant]);
+        check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
+                Type('Invariant<T, int>'), Type('Invariant<int, String>'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(false);
+        check(tcg._constraints).isEmpty();
+      });
+
+      test('Unrelated, matchable', () {
+        // When the variance is "unrelated", type inference doesn't even try to
+        // match up the type parameters; they are always considered to match.
+        var tcg = _TypeConstraintGatherer({'T', 'U'});
+        tcg.typeAnalyzerOperations
+            .addVariance('Unrelated', [Variance.unrelated, Variance.unrelated]);
+        check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
+                Type('Unrelated<T, U>'), Type('Unrelated<int, String>'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(true);
+        check(tcg._constraints).isEmpty();
+      });
+
+      test('Unrelated, not matchable', () {
+        // When the variance is "unrelated", type inference doesn't even try to
+        // match up the type parameters; they are always considered to match.
+        var tcg = _TypeConstraintGatherer({'T'});
+        tcg.typeAnalyzerOperations
+            .addVariance('Unrelated', [Variance.unrelated, Variance.unrelated]);
+        check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
+                Type('Unrelated<T, int>'), Type('Unrelated<int, String>'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(true);
+        check(tcg._constraints).isEmpty();
+      });
+    });
+
+    group('Related types on both sides:', () {
+      test('No change in type args', () {
+        var tcg = _TypeConstraintGatherer({'T'});
+        check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
+                Type('List<T>'), Type('Iterable<int>'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(true);
+        check(tcg._constraints).deepEquals(['T <: int']);
+      });
+
+      test('Change in type args', () {
+        var tcg = _TypeConstraintGatherer({'T'});
+        check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
+                Type('MyListOfInt'), Type('List<T>'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(true);
+        check(tcg._constraints).deepEquals(['int <: T']);
+      });
+
+      test('LHS nullable', () {
+        // When the LHS is a nullable type,
+        // performSubtypeConstraintGenerationForTypeDeclarationTypes considers
+        // it not to match (this is handled by other parts of the subtyping
+        // algorithm)
+        var tcg = _TypeConstraintGatherer({'T'});
+        check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
+                Type('List<T>?'), Type('Iterable<int>'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(false);
+        check(tcg._constraints).isEmpty();
+      });
+
+      test('RHS nullable', () {
+        // When the RHS is a nullable type,
+        // performSubtypeConstraintGenerationForTypeDeclarationTypes considers
+        // it not to match (this is handled by other parts of the subtyping
+        // algorithm)
+        var tcg = _TypeConstraintGatherer({'T'});
+        check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
+                Type('List<T>'), Type('Iterable<int>?'),
+                leftSchema: false, astNodeForTesting: Node.placeholder()))
+            .equals(false);
+        check(tcg._constraints).isEmpty();
+      });
+    });
+
+    test('Non-interface type on LHS', () {
+      var tcg = _TypeConstraintGatherer({});
+      check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
+              Type('void Function()'), Type('int'),
+              leftSchema: false, astNodeForTesting: Node.placeholder()))
+          .isNull();
+      check(tcg._constraints).isEmpty();
+    });
+
+    test('Non-interface type on RHS', () {
+      var tcg = _TypeConstraintGatherer({});
+      check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
+              Type('int'), Type('void Function()'),
+              leftSchema: false, astNodeForTesting: Node.placeholder()))
+          .isNull();
+      check(tcg._constraints).isEmpty();
+    });
+  });
+}
+
+class _TypeConstraintGatherer extends TypeConstraintGenerator<Type,
+        NamedFunctionParameter, Var, TypeParameter, Type, String, Node>
+    with
+        TypeConstraintGeneratorMixin<Type, NamedFunctionParameter, Var,
+            TypeParameter, Type, String, Node> {
+  final _typeVariablesBeingConstrained = <TypeParameter>{};
+
+  @override
+  final bool enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr;
+
+  @override
+  final MiniAstOperations typeAnalyzerOperations = MiniAstOperations();
+
+  final _constraints = <String>[];
+
+  _TypeConstraintGatherer(Set<String> typeVariablesBeingConstrained,
+      {this.enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr =
+          false}) {
+    for (var typeVariableName in typeVariablesBeingConstrained) {
+      _typeVariablesBeingConstrained
+          .add(TypeRegistry.addTypeParameter(typeVariableName));
+    }
+  }
+
+  @override
+  TypeConstraintGeneratorState get currentState =>
+      TypeConstraintGeneratorState(_constraints.length);
+
+  @override
+  List<Type>? getTypeArgumentsAsInstanceOf(Type type, String typeDeclaration) {
+    // We just have a few cases hardcoded here to make the tests work.
+    // TODO(paulberry): if this gets too unwieldy, replace it with a more
+    // general implementation.
+    switch ((type, typeDeclaration)) {
+      case (PrimaryType(name: 'List', :var args), 'Iterable'):
+        // List<T> inherits from Iterable<T>
+        return args;
+      case (PrimaryType(name: 'MyListOfInt'), 'List'):
+        // MyListOfInt inherits from List<int>
+        return [Type('int')];
+      case (PrimaryType(name: 'Future'), 'int'):
+      case (PrimaryType(name: 'int'), 'String'):
+      case (PrimaryType(name: 'List'), 'Future'):
+      case (PrimaryType(name: 'String'), 'int'):
+        // Unrelated types
+        return null;
+      default:
+        throw UnimplementedError(
+            'getTypeArgumentsAsInstanceOf($type, $typeDeclaration)');
+    }
+  }
+
+  @override
+  bool performSubtypeConstraintGenerationInternal(Type p, Type q,
+      {required bool leftSchema, required Node? astNodeForTesting}) {
+    // If `P` is `_` then the match holds with no constraints.
+    if (p is SharedUnknownTypeStructure) {
+      return true;
+    }
+
+    // If `Q` is `_` then the match holds with no constraints.
+    if (q is SharedUnknownTypeStructure) {
+      return true;
+    }
+
+    // If T is a type variable being constrained, then `T <# Q` matches,
+    // generating the constraint `T <: Q`.
+    if (typeAnalyzerOperations.matchInferableParameter(SharedTypeView(p))
+        case var typeVar?
+        when p.nullabilitySuffix == NullabilitySuffix.none &&
+            _typeVariablesBeingConstrained.contains(typeVar)) {
+      _constraints.add('$typeVar <: $q');
+      return true;
+    }
+
+    // If T is a type variable being constrained, then `P <# T` matches,
+    // generating the constraint `P <: T`.
+    if (typeAnalyzerOperations.matchInferableParameter(SharedTypeView(q))
+        case var typeVar?
+        when q.nullabilitySuffix == NullabilitySuffix.none &&
+            _typeVariablesBeingConstrained.contains(typeVar)) {
+      _constraints.add('$p <: $typeVar');
+      return true;
+    }
+
+    // If `P` and `Q` are identical types, then the subtype match holds
+    // under no constraints.
+    if (p == q) {
+      return true;
+    }
+
+    bool? result = performSubtypeConstraintGenerationForTypeDeclarationTypes(
+        p, q,
+        leftSchema: leftSchema, astNodeForTesting: astNodeForTesting);
+    if (result != null) {
+      return result;
+    }
+
+    // Assume for the moment that nothing else matches.
+    // TODO(paulberry): expand this as needed.
+    return false;
+  }
+
+  @override
+  void restoreState(TypeConstraintGeneratorState state) {
+    _constraints.length = state.count;
+  }
+}
diff --git a/pkg/_fe_analyzer_shared/test/type_inference/type_inference_test.dart b/pkg/_fe_analyzer_shared/test/type_inference/type_inference_test.dart
index 247b23e..7b6d4d4 100644
--- a/pkg/_fe_analyzer_shared/test/type_inference/type_inference_test.dart
+++ b/pkg/_fe_analyzer_shared/test/type_inference/type_inference_test.dart
@@ -9,11 +9,28 @@
 
 main() {
   late Harness h;
+  late InterfaceTypeName a;
+  late InterfaceTypeName b1;
+  late InterfaceTypeName b2;
 
   setUp(() {
+    TypeRegistry.init();
+    a = TypeRegistry.addInterfaceTypeName('A');
+    TypeRegistry.addInterfaceTypeName('B');
+    b1 = TypeRegistry.addInterfaceTypeName('B1');
+    b2 = TypeRegistry.addInterfaceTypeName('B2');
+    TypeRegistry.addInterfaceTypeName('C');
+    TypeRegistry.addInterfaceTypeName('C1');
+    TypeRegistry.addInterfaceTypeName('C2');
+    TypeRegistry.addInterfaceTypeName('E');
+    TypeRegistry.addInterfaceTypeName('X');
     h = Harness();
   });
 
+  tearDown(() {
+    TypeRegistry.uninit();
+  });
+
   group('Collection elements:', () {
     group('If:', () {
       test('Condition schema', () {
@@ -520,16 +537,16 @@
           h.addSuperInterfaces(
               'C1',
               (args) => [
-                    PrimaryType('B1', args: args),
-                    PrimaryType('B2', args: args),
+                    PrimaryType(b1, args: args),
+                    PrimaryType(b2, args: args),
                     Type('A'),
                     Type('Object')
                   ]);
           h.addSuperInterfaces(
               'C2',
               (args) => [
-                    PrimaryType('B1', args: args),
-                    PrimaryType('B2', args: args),
+                    PrimaryType(b1, args: args),
+                    PrimaryType(b2, args: args),
                     Type('A'),
                     Type('Object')
                   ]);
@@ -1724,7 +1741,7 @@
       });
 
       test('promoted initializer', () {
-        h.addTypeVariable('T');
+        TypeRegistry.addTypeParameter('T');
         var x = Var('x');
         h.run([
           declare(x, initializer: expr('T&int')).checkIR('match(expr(T&int), '
@@ -3144,7 +3161,7 @@
           h.addDownwardInfer(name: 'B', context: 'A<int>', result: 'B<int>');
           h.addMember('B<int>', 'foo', 'int');
           h.addSuperInterfaces(
-              'B', (args) => [PrimaryType('A', args: args), Type('Object')]);
+              'B', (args) => [PrimaryType(a, args: args), Type('Object')]);
           h.addSuperInterfaces('A', (_) => [Type('Object')]);
           h.run([
             ifCase(
diff --git a/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart b/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart
index 7795f9a..405276a 100644
--- a/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart
+++ b/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart
@@ -1082,7 +1082,9 @@
   /// If not an interop extension type or extension member, returns null.
   FunctionType? getFunctionType(Procedure node) {
     if (getExtensionDescriptor(node) == null &&
-        getExtensionTypeDescriptor(node) == null) return null;
+        getExtensionTypeDescriptor(node) == null) {
+      return null;
+    }
 
     final functionType = node.signatureType ??
         node.function.computeFunctionType(Nullability.nonNullable);
diff --git a/pkg/_macros/CHANGELOG.md b/pkg/_macros/CHANGELOG.md
index 58668f7..48fe1f3 100644
--- a/pkg/_macros/CHANGELOG.md
+++ b/pkg/_macros/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.3.3
+
+- Add `isConst` to constructors.
+- Bug fix: Add `const` and `factory` modifiers to constructor augmentations.
+- Add `isField` and `isSuper` to parameters.
+- Bug fix: Add `this.` and `super.` to parameter augmentations when needed.
+
 ## 0.3.2
 
 - Fix bug where augmenting classes with type parameters didn't work.
diff --git a/pkg/_macros/analysis_options.yaml b/pkg/_macros/analysis_options.yaml
index b761641..7378161 100644
--- a/pkg/_macros/analysis_options.yaml
+++ b/pkg/_macros/analysis_options.yaml
@@ -4,6 +4,8 @@
   language:
     strict-casts: true
   errors:
+    # Remove on next publish or protocol refactoring:
+    unintended_html_in_doc_comment: ignore
     # Remove on next publish or protocol refactoring;
     # https://github.com/dart-lang/language/issues/3706.
     unnecessary_library_name: ignore
diff --git a/pkg/_macros/lib/src/api/code.dart b/pkg/_macros/lib/src/api/code.dart
index 84793ec..87fe9a1 100644
--- a/pkg/_macros/lib/src/api/code.dart
+++ b/pkg/_macros/lib/src/api/code.dart
@@ -104,11 +104,21 @@
 /// It is the job of the user to construct and combine these together in a way
 /// that creates valid parameter lists.
 final class ParameterCode implements Code {
+  /// Optional default value for this parameter (not including the ` = `).
   final Code? defaultValue;
+
+  /// Any keywords to put on this parameter (before the type).
   final List<String> keywords;
+
+  /// Optional name of this parameter (can only be omitted for function types).
   final String? name;
+
+  /// Optional type for this parameter.
   final TypeAnnotationCode? type;
 
+  /// The type of parameter this is.
+  final ParameterStyle style;
+
   @override
   CodeKind get kind => CodeKind.parameter;
 
@@ -122,6 +132,10 @@
           type!,
           ' ',
         ],
+        if (style == ParameterStyle.fieldFormal)
+          'this.'
+        else if (style == ParameterStyle.superFormal)
+          'super.',
         if (name != null) name!,
         if (defaultValue != null) ...[
           ' = ',
@@ -133,6 +147,7 @@
     this.defaultValue,
     this.keywords = const [],
     this.name,
+    this.style = ParameterStyle.normal,
     this.type,
   });
 }
diff --git a/pkg/_macros/lib/src/api/introspection.dart b/pkg/_macros/lib/src/api/introspection.dart
index 43d83f6..83b8fec 100644
--- a/pkg/_macros/lib/src/api/introspection.dart
+++ b/pkg/_macros/lib/src/api/introspection.dart
@@ -307,6 +307,9 @@
 
 /// Constructor introspection information.
 abstract interface class ConstructorDeclaration implements MethodDeclaration {
+  /// Whether or not this constructor is const.
+  bool get isConst;
+
   /// Whether or not this is a factory constructor.
   bool get isFactory;
 }
@@ -360,6 +363,9 @@
   /// Specifically, function type parameters may not have a name.
   String? get name;
 
+  /// The style of parameter this is.
+  ParameterStyle get style;
+
   /// A convenience method to get a `code` object equivalent to this parameter.
   ///
   /// Note that the original default value will not be included, as it is not a
@@ -367,8 +373,23 @@
   ParameterCode get code;
 }
 
+/// The different kinds of parameters.
+enum ParameterStyle {
+  /// A standard parameter.
+  normal,
+
+  /// A `this.` style parameter, otherwise known as an initializing formal
+  /// parameter.
+  fieldFormal,
+
+  /// A `super.` style parameter.
+  superFormal,
+}
+
 /// Parameters of normal functions/methods, which always have an identifier, and
 /// declare a new variable in scope.
+///
+/// These may also be `this.` or `super.` parameters.
 abstract interface class FormalParameterDeclaration
     implements FormalParameter, Declaration {
   @override
diff --git a/pkg/_macros/lib/src/executor/builder_impls.dart b/pkg/_macros/lib/src/executor/builder_impls.dart
index 53d2352..2b9a956 100644
--- a/pkg/_macros/lib/src/executor/builder_impls.dart
+++ b/pkg/_macros/lib/src/executor/builder_impls.dart
@@ -682,6 +682,8 @@
     if (declaration is MethodDeclaration) '  ',
     'augment ',
     if (declaration is ConstructorDeclaration) ...[
+      if (declaration.isConst) 'const ',
+      if (declaration.isFactory) 'factory ',
       declaration.definingType.name,
       if (declaration.identifier.name.isNotEmpty) '.',
     ] else ...[
diff --git a/pkg/_macros/lib/src/executor/introspection_impls.dart b/pkg/_macros/lib/src/executor/introspection_impls.dart
index 23ae7a9..efb8e81 100644
--- a/pkg/_macros/lib/src/executor/introspection_impls.dart
+++ b/pkg/_macros/lib/src/executor/introspection_impls.dart
@@ -414,6 +414,9 @@
   final bool isRequired;
 
   @override
+  final ParameterStyle style;
+
+  @override
   RemoteInstanceKind get kind => RemoteInstanceKind.formalParameterDeclaration;
 
   @override
@@ -426,6 +429,7 @@
     required super.metadata,
     required this.isNamed,
     required this.isRequired,
+    required this.style,
     required this.type,
   });
 
@@ -435,6 +439,7 @@
     required super.library,
     required super.metadata,
     required BitMask<ParameterIntrospectionBit> bitMask,
+    required this.style,
     required this.type,
   })  : isNamed = bitMask.has(ParameterIntrospectionBit.isNamed),
         isRequired = bitMask.has(ParameterIntrospectionBit.isRequired);
@@ -451,14 +456,18 @@
     if (isRequired) bitMask.add(ParameterIntrospectionBit.isRequired);
     bitMask.freeze();
     serializer.addInt(bitMask._mask);
+    serializer.addInt(style.index);
     type.serialize(serializer);
   }
 
   @override
-  ParameterCode get code =>
-      ParameterCode(name: identifier.name, type: type.code, keywords: [
-        if (isNamed && isRequired) 'required',
-      ]);
+  ParameterCode get code => ParameterCode(
+          name: identifier.name,
+          style: style,
+          type: type.code,
+          keywords: [
+            if (isNamed && isRequired) 'required',
+          ]);
 }
 
 class FormalParameterImpl extends RemoteInstance implements FormalParameter {
@@ -478,6 +487,9 @@
   final TypeAnnotationImpl type;
 
   @override
+  ParameterStyle get style => ParameterStyle.normal;
+
+  @override
   RemoteInstanceKind get kind => RemoteInstanceKind.formalParameter;
 
   FormalParameterImpl({
@@ -764,6 +776,9 @@
 class ConstructorDeclarationImpl extends MethodDeclarationImpl
     implements ConstructorDeclaration {
   @override
+  final bool isConst;
+
+  @override
   final bool isFactory;
 
   @override
@@ -785,6 +800,7 @@
     // Method fields.
     required super.definingType,
     // Constructor fields.
+    required this.isConst,
     required this.isFactory,
   }) : super(
           isGetter: false,
@@ -807,7 +823,8 @@
     required super.typeParameters,
     // Method fields.
     required super.definingType,
-  })  : isFactory = bitMask.has(FunctionIntrospectionBit.isFactory),
+  })  : isConst = bitMask.has(FunctionIntrospectionBit.isConst),
+        isFactory = bitMask.has(FunctionIntrospectionBit.isFactory),
         super.fromBitMask();
 
   /// If subclasses have their own values to add to [bitMask], they must do so
@@ -816,6 +833,7 @@
   void serializeUncached(Serializer serializer,
       {BitMask<FunctionIntrospectionBit>? bitMask}) {
     bitMask ??= BitMask();
+    if (isConst) bitMask.add(FunctionIntrospectionBit.isConst);
     if (isFactory) bitMask.add(FunctionIntrospectionBit.isFactory);
     super.serializeUncached(serializer, bitMask: bitMask);
   }
@@ -1383,6 +1401,7 @@
   hasBody,
   hasExternal,
   hasStatic,
+  isConst,
   isFactory,
   isGetter,
   isOperator,
@@ -1391,8 +1410,10 @@
 
 /// Defines the bits for the bit mask for all boolean parameter fields.
 enum ParameterIntrospectionBit {
+  isField,
   isNamed,
   isRequired,
+  isSuper,
 }
 
 /// Defines the bits for the bit mask for all boolean variable fields.
diff --git a/pkg/_macros/lib/src/executor/serialization_extensions.dart b/pkg/_macros/lib/src/executor/serialization_extensions.dart
index 7006aa7..ba46537 100644
--- a/pkg/_macros/lib/src/executor/serialization_extensions.dart
+++ b/pkg/_macros/lib/src/executor/serialization_extensions.dart
@@ -171,6 +171,7 @@
         library: RemoteInstance.deserialize(this),
         metadata: (this..moveNext())._expectRemoteInstanceList(),
         bitMask: BitMask((this..moveNext()).expectInt()),
+        style: ParameterStyle.values[(this..moveNext()).expectInt()],
         type: RemoteInstance.deserialize(this),
       );
 
@@ -442,6 +443,7 @@
           defaultValue: (this..moveNext()).expectNullableCode(),
           keywords: _readStringList(),
           name: (this..moveNext()).expectNullableString(),
+          style: ParameterStyle.values[(this..moveNext()).expectInt()],
           type: (this..moveNext()).expectNullableCode()) as T,
       CodeKind.recordField => RecordFieldCode(
           name: (this..moveNext()).expectNullableString(),
@@ -589,6 +591,7 @@
         serializer
           ..endList()
           ..addNullableString(self.name);
+        serializer.addInt(self.style.index);
         self.type.serializeNullable(serializer);
         return;
       case CodeKind.typeParameter:
diff --git a/pkg/_macros/pubspec.yaml b/pkg/_macros/pubspec.yaml
index ac3cbfa..37e6dc5 100644
--- a/pkg/_macros/pubspec.yaml
+++ b/pkg/_macros/pubspec.yaml
@@ -1,5 +1,5 @@
 name: _macros
-version: 0.3.2
+version: 0.3.3
 description: >-
   This is a private SDK vendored package, which is re-exported by the public
   `macros` package, which is a pub package. Every change to this package is
diff --git a/pkg/_macros/test/executor/executor_test.dart b/pkg/_macros/test/executor/executor_test.dart
index 7b86bd9..3e3978e 100644
--- a/pkg/_macros/test/executor/executor_test.dart
+++ b/pkg/_macros/test/executor/executor_test.dart
@@ -800,7 +800,7 @@
                 expect(definitionResult.libraryAugmentations, isEmpty);
               });
 
-              test('on constructors', () async {
+              test('on regular constructors', () async {
                 var definitionResult = await executor.executeDefinitionsPhase(
                     simpleMacroInstanceId,
                     Fixtures.myConstructor,
@@ -819,6 +819,46 @@
                 expect(definitionResult.libraryAugmentations, isEmpty);
               });
 
+              test('on factory constructors', () async {
+                var definitionResult = await executor.executeDefinitionsPhase(
+                    simpleMacroInstanceId,
+                    Fixtures.myFactoryConstructor,
+                    Fixtures.testDefinitionPhaseIntrospector);
+                expect(definitionResult.enumValueAugmentations, isEmpty);
+                expect(definitionResult.interfaceAugmentations, isEmpty);
+                expect(definitionResult.mixinAugmentations, isEmpty);
+                expect(definitionResult.typeAugmentations, hasLength(1));
+                expect(
+                    definitionResult
+                        .typeAugmentations[
+                            Fixtures.myFactoryConstructor.definingType]!
+                        .first
+                        .debugString()
+                        .toString(),
+                    factoryConstructorDefinitionMatcher);
+                expect(definitionResult.libraryAugmentations, isEmpty);
+              });
+
+              test('on const constructors', () async {
+                var definitionResult = await executor.executeDefinitionsPhase(
+                    simpleMacroInstanceId,
+                    Fixtures.myConstConstructor,
+                    Fixtures.testDefinitionPhaseIntrospector);
+                expect(definitionResult.enumValueAugmentations, isEmpty);
+                expect(definitionResult.interfaceAugmentations, isEmpty);
+                expect(definitionResult.mixinAugmentations, isEmpty);
+                expect(definitionResult.typeAugmentations, hasLength(1));
+                expect(
+                    definitionResult
+                        .typeAugmentations[
+                            Fixtures.myConstConstructor.definingType]!
+                        .first
+                        .debugString()
+                        .toString(),
+                    constConstructorDefinitionMatcher);
+                expect(definitionResult.libraryAugmentations, isEmpty);
+              });
+
               test('on getters', () async {
                 var result = await executor.executeDefinitionsPhase(
                     simpleMacroInstanceId,
@@ -928,6 +968,8 @@
                     unorderedEquals([
                       ...methodDefinitionMatchers,
                       constructorDefinitionMatcher,
+                      constConstructorDefinitionMatcher,
+                      factoryConstructorDefinitionMatcher,
                       ...fieldDefinitionMatchers,
                     ]));
               });
@@ -954,8 +996,9 @@
                     typeAugmentationStrings,
                     unorderedEquals([
                       equalsIgnoringWhitespace('''
-                        augment MyEnum.myEnumConstructor(String myField, ) {
+                        augment MyEnum.myEnumConstructor(String this.myField, ) {
                           print('definingClass: MyEnum');
+                          print('isConst: false');
                           print('isFactory: false');
                           print('isExternal: false');
                           print('isGetter: false');
@@ -1123,8 +1166,9 @@
 }
 
 final constructorDefinitionMatcher = equalsIgnoringWhitespace('''
-augment MyClass.myConstructor(/*inferred*/String myField, ) {
+augment MyClass.myConstructor(/*inferred*/String super.myField, ) {
   print('definingClass: MyClass');
+  print('isConst: false');
   print('isFactory: false');
   print('isExternal: false');
   print('isGetter: false');
@@ -1134,6 +1178,32 @@
   return augmented();
 }''');
 
+final constConstructorDefinitionMatcher = equalsIgnoringWhitespace('''
+augment const MyClass.myConstConstructor(/*inferred*/String this.myField, ) {
+  print('definingClass: MyClass');
+  print('isConst: true');
+  print('isFactory: false');
+  print('isExternal: false');
+  print('isGetter: false');
+  print('isSetter: false');
+  print('returnType: MyClass');
+  print('positionalParam: String (inferred) myField');
+  return augmented();
+}''');
+
+final factoryConstructorDefinitionMatcher = equalsIgnoringWhitespace('''
+augment factory MyClass.myFactoryConstructor(/*inferred*/String myField, ) {
+  print('definingClass: MyClass');
+  print('isConst: false');
+  print('isFactory: true');
+  print('isExternal: false');
+  print('isGetter: false');
+  print('isSetter: false');
+  print('returnType: MyClass');
+  print('positionalParam: String (inferred) myField');
+  return augmented();
+}''');
+
 final fieldDefinitionMatchers = [
   equalsIgnoringWhitespace('''
     augment String get myField {
@@ -1179,6 +1249,8 @@
       print('field: myField');
       print('method: myMethod');
       print('constructor: myConstructor');
+      print('constructor: myConstConstructor');
+      print('constructor: myFactoryConstructor');
       return augmented();
     }'''),
 ];
diff --git a/pkg/_macros/test/executor/serialization_test.dart b/pkg/_macros/test/executor/serialization_test.dart
index 74ad991..61862e2 100644
--- a/pkg/_macros/test/executor/serialization_test.dart
+++ b/pkg/_macros/test/executor/serialization_test.dart
@@ -172,6 +172,7 @@
                 IdentifierImpl(id: RemoteInstance.uniqueId, name: 'foo'),
             library: Fixtures.library,
             metadata: [],
+            style: ParameterStyle.values[rand.nextInt(3)],
             type: fooType);
         final fooNamedFunctionTypeParam = FormalParameterImpl(
             id: RemoteInstance.uniqueId,
@@ -189,6 +190,7 @@
                 IdentifierImpl(id: RemoteInstance.uniqueId, name: 'bar'),
             library: Fixtures.library,
             metadata: [],
+            style: ParameterStyle.values[rand.nextInt(3)],
             type: barType);
         final barPositionalFunctionTypeParam = FormalParameterImpl(
             id: RemoteInstance.uniqueId,
@@ -294,6 +296,7 @@
             returnType: fooType,
             typeParameters: [zapTypeParam],
             definingType: fooType.identifier,
+            isConst: rand.nextBool(),
             isFactory: rand.nextBool(),
           );
           expectSerializationEquality<DeclarationImpl>(
@@ -765,7 +768,7 @@
 
 /// Deserializes [serialized] in its own remote instance cache and sends it
 /// back.
-Object? roundTrip<Declaration>(Object? serialized, int zoneId) {
+Object? roundTrip(Object? serialized, int zoneId) {
   return withRemoteInstanceZone(zoneId, () {
     var deserializer = deserializerFactory(serialized);
     var instance = RemoteInstance.deserialize(deserializer) as Serializable;
diff --git a/pkg/_macros/test/executor/simple_macro.dart b/pkg/_macros/test/executor/simple_macro.dart
index c595707..c1f8f2e 100644
--- a/pkg/_macros/test/executor/simple_macro.dart
+++ b/pkg/_macros/test/executor/simple_macro.dart
@@ -766,7 +766,9 @@
     if (function is MethodDeclaration)
       "print('definingClass: ${function.definingType.name}');\n",
     if (function is ConstructorDeclaration)
-      "print('isFactory: ${function.isFactory}');\n",
+      '''
+        print('isConst: ${function.isConst}');
+        print('isFactory: ${function.isFactory}');''',
     '''
       print('isExternal: ${function.hasExternal}');
       print('isGetter: ${function.isGetter}');
diff --git a/pkg/_macros/test/util.dart b/pkg/_macros/test/util.dart
index 76ae2be..6ac7d34 100644
--- a/pkg/_macros/test/util.dart
+++ b/pkg/_macros/test/util.dart
@@ -463,6 +463,7 @@
             metadata: [],
             isNamed: false,
             isRequired: true,
+            style: ParameterStyle.normal,
             type: stringType)
       ],
       returnType: voidType,
@@ -542,11 +543,65 @@
             metadata: [],
             isNamed: false,
             isRequired: true,
+            style: ParameterStyle.superFormal,
             type: TestOmittedTypeAnnotation(myField.type))
       ],
       returnType: myClassType,
       typeParameters: [],
       definingType: myClassType.identifier,
+      isConst: false,
+      isFactory: false);
+  static final myFactoryConstructor = ConstructorDeclarationImpl(
+      id: RemoteInstance.uniqueId,
+      identifier: IdentifierImpl(
+          id: RemoteInstance.uniqueId, name: 'myFactoryConstructor'),
+      library: Fixtures.library,
+      metadata: [],
+      hasBody: false, // we will augment with one
+      hasExternal: false,
+      namedParameters: [],
+      positionalParameters: [
+        FormalParameterDeclarationImpl(
+            id: RemoteInstance.uniqueId,
+            identifier:
+                IdentifierImpl(id: RemoteInstance.uniqueId, name: 'myField'),
+            library: Fixtures.library,
+            metadata: [],
+            isNamed: false,
+            isRequired: true,
+            style: ParameterStyle.normal,
+            type: TestOmittedTypeAnnotation(myField.type))
+      ],
+      returnType: myClassType,
+      typeParameters: [],
+      definingType: myClassType.identifier,
+      isConst: false,
+      isFactory: true);
+  static final myConstConstructor = ConstructorDeclarationImpl(
+      id: RemoteInstance.uniqueId,
+      identifier: IdentifierImpl(
+          id: RemoteInstance.uniqueId, name: 'myConstConstructor'),
+      library: Fixtures.library,
+      metadata: [],
+      hasBody: false, // we will augment with one
+      hasExternal: false,
+      namedParameters: [],
+      positionalParameters: [
+        FormalParameterDeclarationImpl(
+            id: RemoteInstance.uniqueId,
+            identifier:
+                IdentifierImpl(id: RemoteInstance.uniqueId, name: 'myField'),
+            library: Fixtures.library,
+            metadata: [],
+            isNamed: false,
+            isRequired: true,
+            style: ParameterStyle.fieldFormal,
+            type: TestOmittedTypeAnnotation(myField.type))
+      ],
+      returnType: myClassType,
+      typeParameters: [],
+      definingType: myClassType.identifier,
+      isConst: true,
       isFactory: false);
   static final myField = FieldDeclarationImpl(
       id: RemoteInstance.uniqueId,
@@ -680,11 +735,13 @@
             metadata: [],
             isNamed: false,
             isRequired: true,
+            style: ParameterStyle.fieldFormal,
             type: stringType)
       ],
       returnType: myEnumType,
       typeParameters: [],
       definingType: myEnum.identifier,
+      isConst: false,
       isFactory: false);
 
   static final myMixin = MixinDeclarationImpl(
@@ -795,7 +852,7 @@
 
   static final testDeclarationPhaseIntrospector =
       TestDeclarationPhaseIntrospector(constructors: {
-    myClass: [myConstructor],
+    myClass: [myConstructor, myConstConstructor, myFactoryConstructor],
     myEnum: [myEnumConstructor],
     myMixin: [],
   }, enumValues: {
diff --git a/pkg/analysis_server/analysis_options.yaml b/pkg/analysis_server/analysis_options.yaml
index ca6e101..09e91c2 100644
--- a/pkg/analysis_server/analysis_options.yaml
+++ b/pkg/analysis_server/analysis_options.yaml
@@ -24,9 +24,12 @@
     non_constant_identifier_names: ignore
     overridden_fields: ignore
     todo: ignore
+    # Existing violations (361)
+    unintended_html_in_doc_comment: ignore
 
 linter:
   rules:
+    - analyzer_use_new_elements
     - avoid_redundant_argument_values
     - flutter_style_todos
     - library_annotations
diff --git a/pkg/analysis_server/analyzer_use_new_elements.txt b/pkg/analysis_server/analyzer_use_new_elements.txt
new file mode 100644
index 0000000..6e2b200
--- /dev/null
+++ b/pkg/analysis_server/analyzer_use_new_elements.txt
@@ -0,0 +1,1506 @@
+benchmark/benchmarks.dart
+benchmark/integration/driver.dart
+benchmark/integration/input_converter.dart
+benchmark/integration/instrumentation_input_converter.dart
+benchmark/integration/local_runner.dart
+benchmark/integration/log_file_input_converter.dart
+benchmark/integration/main.dart
+benchmark/integration/operation.dart
+benchmark/perf/benchmark_uploader.dart
+benchmark/perf/benchmarks_impl.dart
+benchmark/perf/dart_analyze.dart
+benchmark/perf/flutter_analyze_benchmark.dart
+benchmark/perf/flutter_completion_benchmark.dart
+benchmark/perf/memory_tests.dart
+benchmark/perf/utils.dart
+bin/server.dart
+lib/lsp_protocol/protocol.dart
+lib/plugin/analysis/occurrences/occurrences_core.dart
+lib/plugin/edit/assist/assist_core.dart
+lib/plugin/edit/assist/assist_dart.dart
+lib/protocol/protocol.dart
+lib/protocol/protocol_constants.dart
+lib/protocol/protocol_generated.dart
+lib/src/analytics/active_request_data.dart
+lib/src/analytics/analytics_manager.dart
+lib/src/analytics/context_structure.dart
+lib/src/analytics/notification_data.dart
+lib/src/analytics/percentile_calculator.dart
+lib/src/analytics/plugin_data.dart
+lib/src/analytics/request_data.dart
+lib/src/analytics/session_data.dart
+lib/src/channel/byte_stream_channel.dart
+lib/src/channel/channel.dart
+lib/src/cider/assists.dart
+lib/src/cider/document_symbols.dart
+lib/src/cider/signature_help.dart
+lib/src/collections.dart
+lib/src/computer/computer_closing_labels.dart
+lib/src/computer/computer_color.dart
+lib/src/computer/computer_folding.dart
+lib/src/computer/computer_selection_ranges.dart
+lib/src/context_manager.dart
+lib/src/domain_analysis_flags.dart
+lib/src/domains/analysis/occurrences.dart
+lib/src/domains/completion/available_suggestions.dart
+lib/src/domains/execution/completion.dart
+lib/src/flutter/flutter_notifications.dart
+lib/src/g3/fixes.dart
+lib/src/g3/utilities.dart
+lib/src/handler/legacy/analysis_get_errors.dart
+lib/src/handler/legacy/analysis_get_hover.dart
+lib/src/handler/legacy/analysis_get_imported_elements.dart
+lib/src/handler/legacy/analysis_get_navigation.dart
+lib/src/handler/legacy/analysis_get_signature.dart
+lib/src/handler/legacy/analysis_reanalyze.dart
+lib/src/handler/legacy/analysis_set_analysis_roots.dart
+lib/src/handler/legacy/analysis_set_general_subscriptions.dart
+lib/src/handler/legacy/analysis_set_priority_files.dart
+lib/src/handler/legacy/analysis_set_subscriptions.dart
+lib/src/handler/legacy/analysis_update_content.dart
+lib/src/handler/legacy/analysis_update_options.dart
+lib/src/handler/legacy/analytics_enable.dart
+lib/src/handler/legacy/analytics_is_enabled.dart
+lib/src/handler/legacy/analytics_send_event.dart
+lib/src/handler/legacy/analytics_send_timing.dart
+lib/src/handler/legacy/completion_get_suggestion_details2.dart
+lib/src/handler/legacy/diagnostic_get_diagnostics.dart
+lib/src/handler/legacy/diagnostic_get_server_port.dart
+lib/src/handler/legacy/edit_bulk_fixes.dart
+lib/src/handler/legacy/edit_format.dart
+lib/src/handler/legacy/edit_format_if_enabled.dart
+lib/src/handler/legacy/edit_get_assists.dart
+lib/src/handler/legacy/edit_get_fixes.dart
+lib/src/handler/legacy/edit_get_postfix_completion.dart
+lib/src/handler/legacy/edit_get_refactoring.dart
+lib/src/handler/legacy/edit_get_statement_completion.dart
+lib/src/handler/legacy/edit_import_elements.dart
+lib/src/handler/legacy/edit_is_postfix_completion_applicable.dart
+lib/src/handler/legacy/edit_list_postfix_completion_templates.dart
+lib/src/handler/legacy/edit_organize_directives.dart
+lib/src/handler/legacy/edit_sort_members.dart
+lib/src/handler/legacy/execution_create_context.dart
+lib/src/handler/legacy/execution_delete_context.dart
+lib/src/handler/legacy/execution_get_suggestions.dart
+lib/src/handler/legacy/execution_map_uri.dart
+lib/src/handler/legacy/execution_set_subscriptions.dart
+lib/src/handler/legacy/flutter_get_widget_description.dart
+lib/src/handler/legacy/flutter_set_subscriptions.dart
+lib/src/handler/legacy/flutter_set_widget_property_value.dart
+lib/src/handler/legacy/lsp_over_legacy_handler.dart
+lib/src/handler/legacy/search_find_member_declarations.dart
+lib/src/handler/legacy/search_find_member_references.dart
+lib/src/handler/legacy/search_find_top_level_declarations.dart
+lib/src/handler/legacy/search_get_element_declarations.dart
+lib/src/handler/legacy/server_cancel_request.dart
+lib/src/handler/legacy/server_get_version.dart
+lib/src/handler/legacy/server_set_client_capabilities.dart
+lib/src/handler/legacy/server_set_subscriptions.dart
+lib/src/handler/legacy/server_shutdown.dart
+lib/src/handler/legacy/unsupported_request.dart
+lib/src/legacy_analysis_server.dart
+lib/src/lsp/channel/lsp_byte_stream_channel.dart
+lib/src/lsp/channel/lsp_channel.dart
+lib/src/lsp/client_capabilities.dart
+lib/src/lsp/client_configuration.dart
+lib/src/lsp/constants.dart
+lib/src/lsp/dartdoc.dart
+lib/src/lsp/error_or.dart
+lib/src/lsp/handlers/code_actions/abstract_code_actions_producer.dart
+lib/src/lsp/handlers/code_actions/analysis_options.dart
+lib/src/lsp/handlers/code_actions/plugins.dart
+lib/src/lsp/handlers/code_actions/pubspec.dart
+lib/src/lsp/handlers/commands/fix_all.dart
+lib/src/lsp/handlers/commands/fix_all_in_workspace.dart
+lib/src/lsp/handlers/commands/log_action.dart
+lib/src/lsp/handlers/commands/organize_imports.dart
+lib/src/lsp/handlers/commands/perform_refactor.dart
+lib/src/lsp/handlers/commands/refactor_command_handler.dart
+lib/src/lsp/handlers/commands/send_workspace_edit.dart
+lib/src/lsp/handlers/commands/simple_edit_handler.dart
+lib/src/lsp/handlers/commands/sort_members.dart
+lib/src/lsp/handlers/commands/validate_refactor.dart
+lib/src/lsp/handlers/custom/handler_connect_to_dtd.dart
+lib/src/lsp/handlers/custom/handler_diagnostic_server.dart
+lib/src/lsp/handlers/custom/handler_reanalyze.dart
+lib/src/lsp/handlers/handler_call_hierarchy.dart
+lib/src/lsp/handlers/handler_cancel_request.dart
+lib/src/lsp/handlers/handler_change_workspace_folders.dart
+lib/src/lsp/handlers/handler_code_actions.dart
+lib/src/lsp/handlers/handler_code_lens.dart
+lib/src/lsp/handlers/handler_dart_text_document_content_provider.dart
+lib/src/lsp/handlers/handler_document_color.dart
+lib/src/lsp/handlers/handler_document_highlights.dart
+lib/src/lsp/handlers/handler_document_link.dart
+lib/src/lsp/handlers/handler_document_symbols.dart
+lib/src/lsp/handlers/handler_execute_command.dart
+lib/src/lsp/handlers/handler_exit.dart
+lib/src/lsp/handlers/handler_folding.dart
+lib/src/lsp/handlers/handler_format_on_type.dart
+lib/src/lsp/handlers/handler_format_range.dart
+lib/src/lsp/handlers/handler_formatting.dart
+lib/src/lsp/handlers/handler_hover.dart
+lib/src/lsp/handlers/handler_initialize.dart
+lib/src/lsp/handlers/handler_initialized.dart
+lib/src/lsp/handlers/handler_inlay_hint.dart
+lib/src/lsp/handlers/handler_reject.dart
+lib/src/lsp/handlers/handler_selection_range.dart
+lib/src/lsp/handlers/handler_semantic_tokens.dart
+lib/src/lsp/handlers/handler_shutdown.dart
+lib/src/lsp/handlers/handler_signature_help.dart
+lib/src/lsp/handlers/handler_states.dart
+lib/src/lsp/handlers/handler_text_document_changes.dart
+lib/src/lsp/handlers/handler_will_rename_files.dart
+lib/src/lsp/handlers/handler_workspace_configuration.dart
+lib/src/lsp/handlers/handler_workspace_symbols.dart
+lib/src/lsp/handlers/handlers.dart
+lib/src/lsp/lsp_analysis_server.dart
+lib/src/lsp/lsp_packet_transformer.dart
+lib/src/lsp/lsp_socket_server.dart
+lib/src/lsp/mapping.dart
+lib/src/lsp/notification_manager.dart
+lib/src/lsp/progress.dart
+lib/src/lsp/registration/feature_registration.dart
+lib/src/lsp/semantic_tokens/encoder.dart
+lib/src/lsp/semantic_tokens/legend.dart
+lib/src/lsp/semantic_tokens/mapping.dart
+lib/src/lsp/server_capabilities_computer.dart
+lib/src/lsp/snippets.dart
+lib/src/lsp/temporary_overlay_operation.dart
+lib/src/plugin/notification_manager.dart
+lib/src/plugin/plugin_locator.dart
+lib/src/plugin/plugin_manager.dart
+lib/src/plugin/plugin_watcher.dart
+lib/src/plugin/request_converter.dart
+lib/src/plugin/result_collector.dart
+lib/src/plugin/result_converter.dart
+lib/src/plugin/result_merger.dart
+lib/src/plugin2/generator.dart
+lib/src/protocol/protocol_internal.dart
+lib/src/provisional/completion/completion_core.dart
+lib/src/provisional/completion/dart/completion_dart.dart
+lib/src/request_handler_mixin.dart
+lib/src/server/crash_reporting.dart
+lib/src/server/crash_reporting_attachments.dart
+lib/src/server/debounce_requests.dart
+lib/src/server/detachable_filesystem_manager.dart
+lib/src/server/dev_server.dart
+lib/src/server/diagnostic_server.dart
+lib/src/server/driver.dart
+lib/src/server/error_notifier.dart
+lib/src/server/features.dart
+lib/src/server/http_server.dart
+lib/src/server/isolate_analysis_server.dart
+lib/src/server/lsp_stdio_server.dart
+lib/src/server/message_scheduler.dart
+lib/src/server/performance.dart
+lib/src/server/sdk_configuration.dart
+lib/src/server/stdio_server.dart
+lib/src/services/completion/completion_performance.dart
+lib/src/services/completion/completion_state.dart
+lib/src/services/completion/dart/fuzzy_filter_sort.dart
+lib/src/services/completion/dart/keyword_helper.dart
+lib/src/services/completion/dart/label_helper.dart
+lib/src/services/completion/dart/probability_range.dart
+lib/src/services/completion/dart/relevance_tables.g.dart
+lib/src/services/completion/dart/suggestion_collector.dart
+lib/src/services/completion/dart/uri_helper.dart
+lib/src/services/completion/yaml/analysis_options_generator.dart
+lib/src/services/completion/yaml/fix_data_generator.dart
+lib/src/services/completion/yaml/producer.dart
+lib/src/services/completion/yaml/pubspec_generator.dart
+lib/src/services/completion/yaml/yaml_completion_generator.dart
+lib/src/services/correction/assist.dart
+lib/src/services/correction/assist_internal.dart
+lib/src/services/correction/dart/abstract_producer.dart
+lib/src/services/correction/dart/add_async.dart
+lib/src/services/correction/dart/add_await.dart
+lib/src/services/correction/dart/add_call_super.dart
+lib/src/services/correction/dart/add_class_modifier.dart
+lib/src/services/correction/dart/add_const.dart
+lib/src/services/correction/dart/add_diagnostic_property_reference.dart
+lib/src/services/correction/dart/add_digit_separators.dart
+lib/src/services/correction/dart/add_empty_argument_list.dart
+lib/src/services/correction/dart/add_enum_constant.dart
+lib/src/services/correction/dart/add_eol_at_end_of_file.dart
+lib/src/services/correction/dart/add_explicit_call.dart
+lib/src/services/correction/dart/add_explicit_cast.dart
+lib/src/services/correction/dart/add_field_formal_parameters.dart
+lib/src/services/correction/dart/add_key_to_constructors.dart
+lib/src/services/correction/dart/add_late.dart
+lib/src/services/correction/dart/add_leading_newline_to_string.dart
+lib/src/services/correction/dart/add_missing_enum_like_case_clauses.dart
+lib/src/services/correction/dart/add_missing_parameter.dart
+lib/src/services/correction/dart/add_missing_parameter_named.dart
+lib/src/services/correction/dart/add_missing_required_argument.dart
+lib/src/services/correction/dart/add_ne_null.dart
+lib/src/services/correction/dart/add_null_check.dart
+lib/src/services/correction/dart/add_override.dart
+lib/src/services/correction/dart/add_redeclare.dart
+lib/src/services/correction/dart/add_reopen.dart
+lib/src/services/correction/dart/add_required_keyword.dart
+lib/src/services/correction/dart/add_return_null.dart
+lib/src/services/correction/dart/add_return_type.dart
+lib/src/services/correction/dart/add_static.dart
+lib/src/services/correction/dart/add_super_parameter.dart
+lib/src/services/correction/dart/add_switch_case_break.dart
+lib/src/services/correction/dart/add_trailing_comma.dart
+lib/src/services/correction/dart/add_type_annotation.dart
+lib/src/services/correction/dart/assign_to_local_variable.dart
+lib/src/services/correction/dart/change_argument_name.dart
+lib/src/services/correction/dart/change_to_nearest_precise_value.dart
+lib/src/services/correction/dart/change_type_annotation.dart
+lib/src/services/correction/dart/convert_add_all_to_spread.dart
+lib/src/services/correction/dart/convert_class_to_enum.dart
+lib/src/services/correction/dart/convert_class_to_mixin.dart
+lib/src/services/correction/dart/convert_conditional_expression_to_if_element.dart
+lib/src/services/correction/dart/convert_documentation_into_block.dart
+lib/src/services/correction/dart/convert_documentation_into_line.dart
+lib/src/services/correction/dart/convert_flutter_child.dart
+lib/src/services/correction/dart/convert_flutter_children.dart
+lib/src/services/correction/dart/convert_for_each_to_for_loop.dart
+lib/src/services/correction/dart/convert_into_async_body.dart
+lib/src/services/correction/dart/convert_into_block_body.dart
+lib/src/services/correction/dart/convert_into_final_field.dart
+lib/src/services/correction/dart/convert_into_for_index.dart
+lib/src/services/correction/dart/convert_into_getter.dart
+lib/src/services/correction/dart/convert_into_is_not.dart
+lib/src/services/correction/dart/convert_map_from_iterable_to_for_literal.dart
+lib/src/services/correction/dart/convert_part_of_to_uri.dart
+lib/src/services/correction/dart/convert_quotes.dart
+lib/src/services/correction/dart/convert_to_boolean_expression.dart
+lib/src/services/correction/dart/convert_to_cascade.dart
+lib/src/services/correction/dart/convert_to_constant_pattern.dart
+lib/src/services/correction/dart/convert_to_contains.dart
+lib/src/services/correction/dart/convert_to_expression_function_body.dart
+lib/src/services/correction/dart/convert_to_field_parameter.dart
+lib/src/services/correction/dart/convert_to_flutter_style_todo.dart
+lib/src/services/correction/dart/convert_to_function_declaration.dart
+lib/src/services/correction/dart/convert_to_generic_function_syntax.dart
+lib/src/services/correction/dart/convert_to_if_case_statement_chain.dart
+lib/src/services/correction/dart/convert_to_if_null.dart
+lib/src/services/correction/dart/convert_to_initializing_formal.dart
+lib/src/services/correction/dart/convert_to_int_literal.dart
+lib/src/services/correction/dart/convert_to_map_literal.dart
+lib/src/services/correction/dart/convert_to_multiline_string.dart
+lib/src/services/correction/dart/convert_to_named_arguments.dart
+lib/src/services/correction/dart/convert_to_normal_parameter.dart
+lib/src/services/correction/dart/convert_to_null_aware.dart
+lib/src/services/correction/dart/convert_to_null_aware_spread.dart
+lib/src/services/correction/dart/convert_to_on_type.dart
+lib/src/services/correction/dart/convert_to_raw_string.dart
+lib/src/services/correction/dart/convert_to_set_literal.dart
+lib/src/services/correction/dart/convert_to_super_parameters.dart
+lib/src/services/correction/dart/convert_to_switch_expression.dart
+lib/src/services/correction/dart/convert_to_switch_statement.dart
+lib/src/services/correction/dart/convert_to_where_type.dart
+lib/src/services/correction/dart/convert_to_wildcard_pattern.dart
+lib/src/services/correction/dart/convert_to_wildcard_variable.dart
+lib/src/services/correction/dart/create_class.dart
+lib/src/services/correction/dart/create_constructor.dart
+lib/src/services/correction/dart/create_constructor_for_final_fields.dart
+lib/src/services/correction/dart/create_field.dart
+lib/src/services/correction/dart/create_function.dart
+lib/src/services/correction/dart/create_getter.dart
+lib/src/services/correction/dart/create_local_variable.dart
+lib/src/services/correction/dart/create_method.dart
+lib/src/services/correction/dart/create_method_or_function.dart
+lib/src/services/correction/dart/create_no_such_method.dart
+lib/src/services/correction/dart/create_parameter.dart
+lib/src/services/correction/dart/create_setter.dart
+lib/src/services/correction/dart/data_driven.dart
+lib/src/services/correction/dart/destructure_local_variable_assignment.dart
+lib/src/services/correction/dart/encapsulate_field.dart
+lib/src/services/correction/dart/exchange_operands.dart
+lib/src/services/correction/dart/extend_class_for_mixin.dart
+lib/src/services/correction/dart/extract_local_variable.dart
+lib/src/services/correction/dart/flutter_convert_to_children.dart
+lib/src/services/correction/dart/flutter_move_down.dart
+lib/src/services/correction/dart/flutter_move_up.dart
+lib/src/services/correction/dart/flutter_remove_widget.dart
+lib/src/services/correction/dart/flutter_swap_with_child.dart
+lib/src/services/correction/dart/flutter_swap_with_parent.dart
+lib/src/services/correction/dart/flutter_wrap_generic.dart
+lib/src/services/correction/dart/ignore_diagnostic.dart
+lib/src/services/correction/dart/import_add_show.dart
+lib/src/services/correction/dart/inline_invocation.dart
+lib/src/services/correction/dart/inline_typedef.dart
+lib/src/services/correction/dart/insert_body.dart
+lib/src/services/correction/dart/insert_semicolon.dart
+lib/src/services/correction/dart/invert_conditional_expression.dart
+lib/src/services/correction/dart/invert_if_statement.dart
+lib/src/services/correction/dart/join_if_with_inner.dart
+lib/src/services/correction/dart/join_if_with_outer.dart
+lib/src/services/correction/dart/join_variable_declaration.dart
+lib/src/services/correction/dart/make_class_abstract.dart
+lib/src/services/correction/dart/make_conditional_on_debug_mode.dart
+lib/src/services/correction/dart/make_field_not_final.dart
+lib/src/services/correction/dart/make_field_public.dart
+lib/src/services/correction/dart/make_final.dart
+lib/src/services/correction/dart/make_required_named_parameters_first.dart
+lib/src/services/correction/dart/make_return_type_nullable.dart
+lib/src/services/correction/dart/make_super_invocation_last.dart
+lib/src/services/correction/dart/make_variable_not_final.dart
+lib/src/services/correction/dart/make_variable_nullable.dart
+lib/src/services/correction/dart/move_annotation_to_library_directive.dart
+lib/src/services/correction/dart/move_doc_comment_to_library_directive.dart
+lib/src/services/correction/dart/move_type_arguments_to_class.dart
+lib/src/services/correction/dart/organize_imports.dart
+lib/src/services/correction/dart/qualify_reference.dart
+lib/src/services/correction/dart/remove_abstract.dart
+lib/src/services/correction/dart/remove_annotation.dart
+lib/src/services/correction/dart/remove_argument.dart
+lib/src/services/correction/dart/remove_assertion.dart
+lib/src/services/correction/dart/remove_assignment.dart
+lib/src/services/correction/dart/remove_await.dart
+lib/src/services/correction/dart/remove_break.dart
+lib/src/services/correction/dart/remove_character.dart
+lib/src/services/correction/dart/remove_comma.dart
+lib/src/services/correction/dart/remove_comparison.dart
+lib/src/services/correction/dart/remove_const.dart
+lib/src/services/correction/dart/remove_constructor.dart
+lib/src/services/correction/dart/remove_constructor_name.dart
+lib/src/services/correction/dart/remove_dead_code.dart
+lib/src/services/correction/dart/remove_dead_if_null.dart
+lib/src/services/correction/dart/remove_default_value.dart
+lib/src/services/correction/dart/remove_deprecated_new_in_comment_reference.dart
+lib/src/services/correction/dart/remove_digit_separators.dart
+lib/src/services/correction/dart/remove_duplicate_case.dart
+lib/src/services/correction/dart/remove_empty_catch.dart
+lib/src/services/correction/dart/remove_empty_constructor_body.dart
+lib/src/services/correction/dart/remove_empty_else.dart
+lib/src/services/correction/dart/remove_empty_statement.dart
+lib/src/services/correction/dart/remove_extends_clause.dart
+lib/src/services/correction/dart/remove_if_null_operator.dart
+lib/src/services/correction/dart/remove_initializer.dart
+lib/src/services/correction/dart/remove_interpolation_braces.dart
+lib/src/services/correction/dart/remove_invocation.dart
+lib/src/services/correction/dart/remove_late.dart
+lib/src/services/correction/dart/remove_leading_underscore.dart
+lib/src/services/correction/dart/remove_lexeme.dart
+lib/src/services/correction/dart/remove_library_name.dart
+lib/src/services/correction/dart/remove_method_declaration.dart
+lib/src/services/correction/dart/remove_name_from_combinator.dart
+lib/src/services/correction/dart/remove_name_from_declaration_clause.dart
+lib/src/services/correction/dart/remove_non_null_assertion.dart
+lib/src/services/correction/dart/remove_on_clause.dart
+lib/src/services/correction/dart/remove_operator.dart
+lib/src/services/correction/dart/remove_parameters_in_getter_declaration.dart
+lib/src/services/correction/dart/remove_parentheses_in_getter_invocation.dart
+lib/src/services/correction/dart/remove_print.dart
+lib/src/services/correction/dart/remove_question_mark.dart
+lib/src/services/correction/dart/remove_required.dart
+lib/src/services/correction/dart/remove_returned_value.dart
+lib/src/services/correction/dart/remove_this_expression.dart
+lib/src/services/correction/dart/remove_to_list.dart
+lib/src/services/correction/dart/remove_type_annotation.dart
+lib/src/services/correction/dart/remove_type_arguments.dart
+lib/src/services/correction/dart/remove_unexpected_underscores.dart
+lib/src/services/correction/dart/remove_unnecessary_cast.dart
+lib/src/services/correction/dart/remove_unnecessary_final.dart
+lib/src/services/correction/dart/remove_unnecessary_late.dart
+lib/src/services/correction/dart/remove_unnecessary_library_directive.dart
+lib/src/services/correction/dart/remove_unnecessary_new.dart
+lib/src/services/correction/dart/remove_unnecessary_parentheses.dart
+lib/src/services/correction/dart/remove_unnecessary_raw_string.dart
+lib/src/services/correction/dart/remove_unnecessary_string_escape.dart
+lib/src/services/correction/dart/remove_unnecessary_string_interpolation.dart
+lib/src/services/correction/dart/remove_unnecessary_wildcard_pattern.dart
+lib/src/services/correction/dart/remove_unused_catch_clause.dart
+lib/src/services/correction/dart/remove_unused_catch_stack.dart
+lib/src/services/correction/dart/remove_unused_import.dart
+lib/src/services/correction/dart/remove_unused_label.dart
+lib/src/services/correction/dart/remove_unused_local_variable.dart
+lib/src/services/correction/dart/remove_unused_parameter.dart
+lib/src/services/correction/dart/remove_var.dart
+lib/src/services/correction/dart/remove_var_keyword.dart
+lib/src/services/correction/dart/rename_to_camel_case.dart
+lib/src/services/correction/dart/replace_boolean_with_bool.dart
+lib/src/services/correction/dart/replace_cascade_with_dot.dart
+lib/src/services/correction/dart/replace_colon_with_equals.dart
+lib/src/services/correction/dart/replace_colon_with_in.dart
+lib/src/services/correction/dart/replace_conditional_with_if_else.dart
+lib/src/services/correction/dart/replace_container_with_colored_box.dart
+lib/src/services/correction/dart/replace_container_with_sized_box.dart
+lib/src/services/correction/dart/replace_empty_map_pattern.dart
+lib/src/services/correction/dart/replace_final_with_const.dart
+lib/src/services/correction/dart/replace_final_with_var.dart
+lib/src/services/correction/dart/replace_if_else_with_conditional.dart
+lib/src/services/correction/dart/replace_new_with_const.dart
+lib/src/services/correction/dart/replace_null_check_with_cast.dart
+lib/src/services/correction/dart/replace_null_with_closure.dart
+lib/src/services/correction/dart/replace_null_with_void.dart
+lib/src/services/correction/dart/replace_return_type.dart
+lib/src/services/correction/dart/replace_return_type_future.dart
+lib/src/services/correction/dart/replace_return_type_iterable.dart
+lib/src/services/correction/dart/replace_return_type_stream.dart
+lib/src/services/correction/dart/replace_var_with_dynamic.dart
+lib/src/services/correction/dart/replace_with_arrow.dart
+lib/src/services/correction/dart/replace_with_brackets.dart
+lib/src/services/correction/dart/replace_with_conditional_assignment.dart
+lib/src/services/correction/dart/replace_with_decorated_box.dart
+lib/src/services/correction/dart/replace_with_eight_digit_hex.dart
+lib/src/services/correction/dart/replace_with_extension_name.dart
+lib/src/services/correction/dart/replace_with_identifier.dart
+lib/src/services/correction/dart/replace_with_interpolation.dart
+lib/src/services/correction/dart/replace_with_is_empty.dart
+lib/src/services/correction/dart/replace_with_is_nan.dart
+lib/src/services/correction/dart/replace_with_named_constant.dart
+lib/src/services/correction/dart/replace_with_not_null_aware.dart
+lib/src/services/correction/dart/replace_with_null_aware.dart
+lib/src/services/correction/dart/replace_with_part_of_uri.dart
+lib/src/services/correction/dart/replace_with_tear_off.dart
+lib/src/services/correction/dart/replace_with_unicode_escape.dart
+lib/src/services/correction/dart/replace_with_var.dart
+lib/src/services/correction/dart/replace_with_wildcard.dart
+lib/src/services/correction/dart/shadow_field.dart
+lib/src/services/correction/dart/sort_child_property_last.dart
+lib/src/services/correction/dart/sort_combinators.dart
+lib/src/services/correction/dart/sort_constructor_first.dart
+lib/src/services/correction/dart/sort_unnamed_constructor_first.dart
+lib/src/services/correction/dart/split_and_condition.dart
+lib/src/services/correction/dart/split_multiple_declarations.dart
+lib/src/services/correction/dart/split_variable_declaration.dart
+lib/src/services/correction/dart/surround_with.dart
+lib/src/services/correction/dart/surround_with_parentheses.dart
+lib/src/services/correction/dart/update_sdk_constraints.dart
+lib/src/services/correction/dart/use_curly_braces.dart
+lib/src/services/correction/dart/use_effective_integer_division.dart
+lib/src/services/correction/dart/use_eq_eq_null.dart
+lib/src/services/correction/dart/use_is_not_empty.dart
+lib/src/services/correction/dart/use_not_eq_null.dart
+lib/src/services/correction/dart/use_rethrow.dart
+lib/src/services/correction/dart/wrap_in_text.dart
+lib/src/services/correction/dart/wrap_in_unawaited.dart
+lib/src/services/correction/executable_parameters.dart
+lib/src/services/correction/fix.dart
+lib/src/services/correction/fix/analysis_options/fix_generator.dart
+lib/src/services/correction/fix/data_driven/accessor.dart
+lib/src/services/correction/fix/data_driven/add_type_parameter.dart
+lib/src/services/correction/fix/data_driven/change.dart
+lib/src/services/correction/fix/data_driven/changes_selector.dart
+lib/src/services/correction/fix/data_driven/code_fragment_parser.dart
+lib/src/services/correction/fix/data_driven/code_template.dart
+lib/src/services/correction/fix/data_driven/element_descriptor.dart
+lib/src/services/correction/fix/data_driven/element_kind.dart
+lib/src/services/correction/fix/data_driven/expression.dart
+lib/src/services/correction/fix/data_driven/modify_parameters.dart
+lib/src/services/correction/fix/data_driven/rename.dart
+lib/src/services/correction/fix/data_driven/transform.dart
+lib/src/services/correction/fix/data_driven/transform_set.dart
+lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
+lib/src/services/correction/fix/data_driven/transform_set_manager.dart
+lib/src/services/correction/fix/data_driven/transform_set_parser.dart
+lib/src/services/correction/fix/data_driven/value_generator.dart
+lib/src/services/correction/fix/data_driven/variable_scope.dart
+lib/src/services/correction/fix/pubspec/fix_generator.dart
+lib/src/services/correction/fix/pubspec/fix_kind.dart
+lib/src/services/correction/fix_internal.dart
+lib/src/services/correction/levenshtein.dart
+lib/src/services/correction/name_suggestion.dart
+lib/src/services/correction/organize_imports.dart
+lib/src/services/correction/selection_analyzer.dart
+lib/src/services/correction/sort_members.dart
+lib/src/services/correction/source_buffer.dart
+lib/src/services/correction/statement_analyzer.dart
+lib/src/services/correction/status.dart
+lib/src/services/dart_tooling_daemon/dtd_services.dart
+lib/src/services/execution/execution_context.dart
+lib/src/services/kythe/schema.dart
+lib/src/services/pub/pub_api.dart
+lib/src/services/pub/pub_command.dart
+lib/src/services/pub/pub_package_service.dart
+lib/src/services/refactoring/convert_all_formal_parameters_to_named.dart
+lib/src/services/refactoring/convert_selected_formal_parameters_to_named.dart
+lib/src/services/refactoring/framework/refactoring_context.dart
+lib/src/services/refactoring/framework/refactoring_processor.dart
+lib/src/services/refactoring/framework/refactoring_producer.dart
+lib/src/services/refactoring/framework/write_invocation_arguments.dart
+lib/src/services/refactoring/legacy/naming_conventions.dart
+lib/src/services/refactoring/move_selected_formal_parameters_left.dart
+lib/src/services/snippets/dart/class_declaration.dart
+lib/src/services/snippets/dart/do_statement.dart
+lib/src/services/snippets/dart/for_in_statement.dart
+lib/src/services/snippets/dart/for_statement.dart
+lib/src/services/snippets/dart/function_declaration.dart
+lib/src/services/snippets/dart/if_else_statement.dart
+lib/src/services/snippets/dart/if_statement.dart
+lib/src/services/snippets/dart/main_function.dart
+lib/src/services/snippets/dart/switch_expression.dart
+lib/src/services/snippets/dart/switch_statement.dart
+lib/src/services/snippets/dart/test_definition.dart
+lib/src/services/snippets/dart/test_group_definition.dart
+lib/src/services/snippets/dart/try_catch_statement.dart
+lib/src/services/snippets/dart/while_statement.dart
+lib/src/services/snippets/dart_snippet_request.dart
+lib/src/services/snippets/snippet.dart
+lib/src/services/snippets/snippet_context.dart
+lib/src/services/user_prompts/dart_fix_prompt_manager.dart
+lib/src/services/user_prompts/survey_manager.dart
+lib/src/services/user_prompts/user_prompts.dart
+lib/src/socket_server.dart
+lib/src/status/pages.dart
+lib/src/utilities/change_builder.dart
+lib/src/utilities/extensions/numeric.dart
+lib/src/utilities/extensions/object.dart
+lib/src/utilities/extensions/range_factory.dart
+lib/src/utilities/extensions/string.dart
+lib/src/utilities/extensions/yaml.dart
+lib/src/utilities/file_string_sink.dart
+lib/src/utilities/index_range.dart
+lib/src/utilities/mocks.dart
+lib/src/utilities/null_string_sink.dart
+lib/src/utilities/process.dart
+lib/src/utilities/profiling.dart
+lib/src/utilities/request_statistics.dart
+lib/src/utilities/source_change_merger.dart
+lib/src/utilities/stream.dart
+lib/src/utilities/strings.dart
+lib/src/utilities/tee_string_sink.dart
+lib/src/utilities/timing_byte_store.dart
+lib/src/utilities/usage_tracking/usage_tracking.dart
+lib/src/utilities/yaml_node_locator.dart
+lib/starter.dart
+test/abstract_context.dart
+test/analysis/get_errors_test.dart
+test/analysis/get_hover_test.dart
+test/analysis/get_navigation_test.dart
+test/analysis/get_signature_test.dart
+test/analysis/notification_analysis_options_test.dart
+test/analysis/notification_analyzed_files_test.dart
+test/analysis/notification_closing_labels_test.dart
+test/analysis/notification_errors_test.dart
+test/analysis/notification_folding_test.dart
+test/analysis/notification_highlights2_test.dart
+test/analysis/notification_implemented_test.dart
+test/analysis/notification_navigation_test.dart
+test/analysis/notification_occurrences_test.dart
+test/analysis/notification_outline_test.dart
+test/analysis/notification_overrides_test.dart
+test/analysis/reanalyze_test.dart
+test/analysis/set_priority_files_test.dart
+test/analysis/test_all.dart
+test/analysis/update_content_test.dart
+test/analysis_abstract.dart
+test/analysis_server_base.dart
+test/analysis_server_test.dart
+test/benchmarks_test.dart
+test/channel/byte_stream_channel_test.dart
+test/channel/test_all.dart
+test/client/completion_driver_test.dart
+test/client/impl/completion_driver.dart
+test/client/impl/expect_mixin.dart
+test/client/test_all.dart
+test/completion_test_support.dart
+test/constants.dart
+test/domain_analysis_test.dart
+test/domain_completion_test.dart
+test/domain_completion_util.dart
+test/domain_diagnostic_test.dart
+test/domain_execution_test.dart
+test/domain_server_test.dart
+test/edit/assists_test.dart
+test/edit/bulk_fixes_test.dart
+test/edit/fixes_test.dart
+test/edit/format_if_enabled_test.dart
+test/edit/format_test.dart
+test/edit/organize_directives_test.dart
+test/edit/postfix_completion_test.dart
+test/edit/refactoring_test.dart
+test/edit/sort_members_test.dart
+test/edit/statement_completion_test.dart
+test/edit/test_all.dart
+test/integration/analysis/analysis_options_test.dart
+test/integration/analysis/error_test.dart
+test/integration/analysis/get_errors_non_standard_sdk_test.dart
+test/integration/analysis/get_errors_test.dart
+test/integration/analysis/get_hover_test.dart
+test/integration/analysis/get_imported_elements_test.dart
+test/integration/analysis/get_library_dependencies_test.dart
+test/integration/analysis/get_navigation_test.dart
+test/integration/analysis/get_reachable_sources_test.dart
+test/integration/analysis/highlights_test.dart
+test/integration/analysis/lint_test.dart
+test/integration/analysis/navigation_test.dart
+test/integration/analysis/occurrences_test.dart
+test/integration/analysis/outline_test.dart
+test/integration/analysis/overrides_test.dart
+test/integration/analysis/package_root_test.dart
+test/integration/analysis/reanalyze_concurrent_test.dart
+test/integration/analysis/reanalyze_test.dart
+test/integration/analysis/set_analysis_roots_test.dart
+test/integration/analysis/set_general_subscriptions_test.dart
+test/integration/analysis/set_priority_files_test.dart
+test/integration/analysis/set_subscriptions_test.dart
+test/integration/analysis/test_all.dart
+test/integration/analysis/update_content_list_test.dart
+test/integration/analysis/update_content_test.dart
+test/integration/analysis/update_options_test.dart
+test/integration/completion/get_suggestions_test.dart
+test/integration/completion/test_all.dart
+test/integration/coverage_test.dart
+test/integration/diagnostic/get_diagnostics_test.dart
+test/integration/diagnostic/get_server_port_test.dart
+test/integration/diagnostic/test_all.dart
+test/integration/dtd/dtd_test.dart
+test/integration/dtd/test_all.dart
+test/integration/edit/bulk_fixes_test.dart
+test/integration/edit/format_test.dart
+test/integration/edit/get_assists_test.dart
+test/integration/edit/get_available_refactorings_test.dart
+test/integration/edit/get_fixes_test.dart
+test/integration/edit/get_postfix_completion_test.dart
+test/integration/edit/get_refactoring_test.dart
+test/integration/edit/get_statement_completion_test.dart
+test/integration/edit/import_elements_test.dart
+test/integration/edit/is_postfix_completion_applicable_test.dart
+test/integration/edit/list_postfix_completion_templates_test.dart
+test/integration/edit/organize_directives_test.dart
+test/integration/edit/sort_members_test.dart
+test/integration/edit/test_all.dart
+test/integration/execution/create_context_test.dart
+test/integration/execution/delete_context_test.dart
+test/integration/execution/map_uri_test.dart
+test/integration/execution/set_subscriptions_test.dart
+test/integration/execution/test_all.dart
+test/integration/lsp/abstract_lsp_over_legacy.dart
+test/integration/lsp/handle_test.dart
+test/integration/lsp/notification_test.dart
+test/integration/lsp/test_all.dart
+test/integration/lsp_server/analyzer_status_test.dart
+test/integration/lsp_server/diagnostic_test.dart
+test/integration/lsp_server/dtd_test.dart
+test/integration/lsp_server/initialization_test.dart
+test/integration/lsp_server/integration_tests.dart
+test/integration/lsp_server/server_test.dart
+test/integration/lsp_server/test_all.dart
+test/integration/lsp_server/workspace_symbol_benchmark.dart
+test/integration/search/find_element_references_test.dart
+test/integration/search/find_member_declarations_test.dart
+test/integration/search/find_member_references_test.dart
+test/integration/search/find_top_level_declarations_test.dart
+test/integration/search/get_type_hierarchy_test.dart
+test/integration/search/test_all.dart
+test/integration/server/blaze_changes_test.dart
+test/integration/server/command_line_options_test.dart
+test/integration/server/get_version_test.dart
+test/integration/server/message_scheduler_test.dart
+test/integration/server/set_subscriptions_invalid_service_test.dart
+test/integration/server/set_subscriptions_test.dart
+test/integration/server/shutdown_test.dart
+test/integration/server/status_test.dart
+test/integration/server/test_all.dart
+test/integration/support/dart_tooling_daemon.dart
+test/integration/support/integration_test_methods.dart
+test/integration/support/integration_tests.dart
+test/integration/support/protocol_matchers.dart
+test/integration/support/web_sockets.dart
+test/integration/test_all.dart
+test/lsp/analyzer_status_test.dart
+test/lsp/augmentation_test.dart
+test/lsp/augmented_test.dart
+test/lsp/call_hierarchy_test.dart
+test/lsp/cancel_request_test.dart
+test/lsp/change_verifier.dart
+test/lsp/change_workspace_folders_test.dart
+test/lsp/client_configuration_test.dart
+test/lsp/closing_labels_test.dart
+test/lsp/code_actions_abstract.dart
+test/lsp/code_actions_assists_test.dart
+test/lsp/code_actions_fixes_test.dart
+test/lsp/code_actions_refactor_test.dart
+test/lsp/code_actions_source_test.dart
+test/lsp/code_lens/augmentations_test.dart
+test/lsp/code_lens/test_all.dart
+test/lsp/commands/fix_all_in_workspace_test.dart
+test/lsp/commands/test_all.dart
+test/lsp/completion.dart
+test/lsp/completion_dart_test.dart
+test/lsp/completion_yaml_test.dart
+test/lsp/configuration_test.dart
+test/lsp/dart_text_document_content_provider_test.dart
+test/lsp/definition_test.dart
+test/lsp/diagnostic_test.dart
+test/lsp/document_changes_test.dart
+test/lsp/document_color_test.dart
+test/lsp/document_highlights_test.dart
+test/lsp/document_link_test.dart
+test/lsp/document_symbols_test.dart
+test/lsp/error_or_test.dart
+test/lsp/file_modification_test.dart
+test/lsp/flutter_outline_test.dart
+test/lsp/folding_test.dart
+test/lsp/format_test.dart
+test/lsp/hover_test.dart
+test/lsp/implementation_test.dart
+test/lsp/initialization_test.dart
+test/lsp/inlay_hint_test.dart
+test/lsp/mapping_test.dart
+test/lsp/open_uri_test.dart
+test/lsp/outline_test.dart
+test/lsp/priority_files_test.dart
+test/lsp/pub_package_service_test.dart
+test/lsp/reanalyze_test.dart
+test/lsp/references_test.dart
+test/lsp/rename_test.dart
+test/lsp/request_helpers_mixin.dart
+test/lsp/selection_range_test.dart
+test/lsp/semantic_tokens_test.dart
+test/lsp/server_abstract.dart
+test/lsp/server_test.dart
+test/lsp/signature_help_test.dart
+test/lsp/snippets_test.dart
+test/lsp/source_edits_test.dart
+test/lsp/super_test.dart
+test/lsp/temporary_overlay_operation_test.dart
+test/lsp/test_all.dart
+test/lsp/type_definition_test.dart
+test/lsp/type_hierarchy_test.dart
+test/lsp/will_rename_files_test.dart
+test/lsp/workspace_symbols_test.dart
+test/lsp_over_legacy/abstract_lsp_over_legacy.dart
+test/lsp_over_legacy/call_hierarchy_test.dart
+test/lsp_over_legacy/dart_text_document_content_provider_test.dart
+test/lsp_over_legacy/document_color_test.dart
+test/lsp_over_legacy/document_highlights_test.dart
+test/lsp_over_legacy/document_symbols_test.dart
+test/lsp_over_legacy/format_test.dart
+test/lsp_over_legacy/hover_test.dart
+test/lsp_over_legacy/implementation_test.dart
+test/lsp_over_legacy/signature_help_test.dart
+test/lsp_over_legacy/test_all.dart
+test/lsp_over_legacy/type_definition_test.dart
+test/lsp_over_legacy/type_hierarchy_test.dart
+test/lsp_over_legacy/will_rename_files_test.dart
+test/lsp_over_legacy/workspace_symbols_test.dart
+test/mocks.dart
+test/mocks_lsp.dart
+test/plugin/test_all.dart
+test/protocol_server_test.dart
+test/protocol_test.dart
+test/search/abstract_search_domain.dart
+test/search/declarations_test.dart
+test/search/element_references_test.dart
+test/search/member_declarations_test.dart
+test/search/member_references_test.dart
+test/search/search_result_test.dart
+test/search/test_all.dart
+test/search/top_level_declarations_test.dart
+test/search/type_hierarchy_test.dart
+test/services/completion/dart/completion_check.dart
+test/services/completion/dart/completion_printer.dart
+test/services/completion/dart/completion_test.dart
+test/services/completion/dart/declaration/class_member_test.dart
+test/services/completion/dart/declaration/class_test.dart
+test/services/completion/dart/declaration/closure_test.dart
+test/services/completion/dart/declaration/constructor_test.dart
+test/services/completion/dart/declaration/documentation_test.dart
+test/services/completion/dart/declaration/enum_test.dart
+test/services/completion/dart/declaration/extension_member_test.dart
+test/services/completion/dart/declaration/imported_reference_test.dart
+test/services/completion/dart/declaration/label_test.dart
+test/services/completion/dart/declaration/library_member_test.dart
+test/services/completion/dart/declaration/library_prefix_test.dart
+test/services/completion/dart/declaration/library_test.dart
+test/services/completion/dart/declaration/local_library_test.dart
+test/services/completion/dart/declaration/local_reference_test.dart
+test/services/completion/dart/declaration/pattern_variable_test.dart
+test/services/completion/dart/declaration/record_type_test.dart
+test/services/completion/dart/declaration/test_all.dart
+test/services/completion/dart/declaration/type_member_test.dart
+test/services/completion/dart/declaration/uri_test.dart
+test/services/completion/dart/declaration/variable_name_test.dart
+test/services/completion/dart/declaration/wildcard_variables_test.dart
+test/services/completion/dart/location/argument_list_test.dart
+test/services/completion/dart/location/as_expression_test.dart
+test/services/completion/dart/location/assert_initializer_test.dart
+test/services/completion/dart/location/assert_statement_test.dart
+test/services/completion/dart/location/assignment_expression_test.dart
+test/services/completion/dart/location/block_test.dart
+test/services/completion/dart/location/case_clause_test.dart
+test/services/completion/dart/location/cast_pattern_test.dart
+test/services/completion/dart/location/catch_clause_test.dart
+test/services/completion/dart/location/class_body_test.dart
+test/services/completion/dart/location/class_declaration_test.dart
+test/services/completion/dart/location/compilation_unit_member_test.dart
+test/services/completion/dart/location/compilation_unit_test.dart
+test/services/completion/dart/location/conditional_expression_test.dart
+test/services/completion/dart/location/constructor_declaration_test.dart
+test/services/completion/dart/location/constructor_invocation_test.dart
+test/services/completion/dart/location/directive_uri_test.dart
+test/services/completion/dart/location/enum_constant_test.dart
+test/services/completion/dart/location/enum_declaration_test.dart
+test/services/completion/dart/location/extends_clause_test.dart
+test/services/completion/dart/location/extension_body_test.dart
+test/services/completion/dart/location/extension_declaration_test.dart
+test/services/completion/dart/location/extension_type_declaration_test.dart
+test/services/completion/dart/location/field_declaration_test.dart
+test/services/completion/dart/location/field_formal_parameter_test.dart
+test/services/completion/dart/location/for_element_test.dart
+test/services/completion/dart/location/for_statement_test.dart
+test/services/completion/dart/location/function_declaration_test.dart
+test/services/completion/dart/location/function_expression_test.dart
+test/services/completion/dart/location/function_invocation_test.dart
+test/services/completion/dart/location/if_element_test.dart
+test/services/completion/dart/location/if_statement_test.dart
+test/services/completion/dart/location/implements_clause_test.dart
+test/services/completion/dart/location/import_directive_test.dart
+test/services/completion/dart/location/index_expression_test.dart
+test/services/completion/dart/location/instance_creation_expression_test.dart
+test/services/completion/dart/location/is_expression_test.dart
+test/services/completion/dart/location/library_directive_test.dart
+test/services/completion/dart/location/list_literal_test.dart
+test/services/completion/dart/location/list_pattern_test.dart
+test/services/completion/dart/location/logical_and_pattern_test.dart
+test/services/completion/dart/location/logical_or_pattern_test.dart
+test/services/completion/dart/location/map_literal_test.dart
+test/services/completion/dart/location/map_pattern_test.dart
+test/services/completion/dart/location/method_declaration_test.dart
+test/services/completion/dart/location/method_invocation_test.dart
+test/services/completion/dart/location/mixin_declaration_test.dart
+test/services/completion/dart/location/named_expression_test.dart
+test/services/completion/dart/location/named_type_test.dart
+test/services/completion/dart/location/object_pattern_test.dart
+test/services/completion/dart/location/parameter_list_test.dart
+test/services/completion/dart/location/parenthesized_pattern_test.dart
+test/services/completion/dart/location/pattern_assignment_test.dart
+test/services/completion/dart/location/pattern_variable_declaration_test.dart
+test/services/completion/dart/location/property_access_expression_test.dart
+test/services/completion/dart/location/record_literal_test.dart
+test/services/completion/dart/location/record_pattern_test.dart
+test/services/completion/dart/location/record_type_annotation_test.dart
+test/services/completion/dart/location/redirecting_constructor_invocation_test.dart
+test/services/completion/dart/location/relational_pattern_test.dart
+test/services/completion/dart/location/rest_pattern_test.dart
+test/services/completion/dart/location/return_statement_test.dart
+test/services/completion/dart/location/set_literal_test.dart
+test/services/completion/dart/location/string_literal_test.dart
+test/services/completion/dart/location/super_constructor_invocation_test.dart
+test/services/completion/dart/location/super_formal_parameter_test.dart
+test/services/completion/dart/location/switch_expression_test.dart
+test/services/completion/dart/location/switch_pattern_case_test.dart
+test/services/completion/dart/location/switch_statement_test.dart
+test/services/completion/dart/location/test_all.dart
+test/services/completion/dart/location/try_statement_test.dart
+test/services/completion/dart/location/type_argument_list_test.dart
+test/services/completion/dart/location/type_test_test.dart
+test/services/completion/dart/location/variable_declaration_list_test.dart
+test/services/completion/dart/location/wildcard_pattern_test.dart
+test/services/completion/dart/location/with_clause_test.dart
+test/services/completion/dart/relevance/bool_assignment_test.dart
+test/services/completion/dart/relevance/completion_relevance.dart
+test/services/completion/dart/relevance/deprecated_member_test.dart
+test/services/completion/dart/relevance/instance_member_test.dart
+test/services/completion/dart/relevance/is_no_such_method_test.dart
+test/services/completion/dart/relevance/locality_test.dart
+test/services/completion/dart/relevance/named_argument_test.dart
+test/services/completion/dart/relevance/non_type_member_test.dart
+test/services/completion/dart/relevance/static_member_test.dart
+test/services/completion/dart/relevance/switch_statement_test.dart
+test/services/completion/dart/relevance/test_all.dart
+test/services/completion/dart/shadowing_test.dart
+test/services/completion/dart/test_all.dart
+test/services/completion/dart/text_expectations.dart
+test/services/completion/dart/visibility/test_all.dart
+test/services/completion/dart/visibility/types_test.dart
+test/services/completion/postfix/postfix_completion_test.dart
+test/services/completion/postfix/test_all.dart
+test/services/completion/statement/statement_completion_test.dart
+test/services/completion/statement/test_all.dart
+test/services/completion/test_all.dart
+test/services/correction/change_test.dart
+test/services/correction/levenshtein_test.dart
+test/services/correction/organize_directives_test.dart
+test/services/correction/sort_members_test.dart
+test/services/correction/test_all.dart
+test/services/linter/linter_test.dart
+test/services/linter/test_all.dart
+test/services/refactoring/agnostic/test_all.dart
+test/services/refactoring/legacy/abstract_refactoring.dart
+test/services/refactoring/legacy/extract_local_test.dart
+test/services/refactoring/legacy/extract_widget_test.dart
+test/services/refactoring/legacy/inline_local_test.dart
+test/services/refactoring/legacy/inline_method_test.dart
+test/services/refactoring/legacy/move_file_test.dart
+test/services/refactoring/legacy/naming_conventions_test.dart
+test/services/refactoring/legacy/rename_extension_member_test.dart
+test/services/refactoring/legacy/rename_label_test.dart
+test/services/refactoring/legacy/rename_local_test.dart
+test/services/refactoring/legacy/rename_type_parameter_test.dart
+test/services/refactoring/legacy/rename_unit_member_test.dart
+test/services/refactoring/legacy/test_all.dart
+test/services/refactoring/test_all.dart
+test/services/search/test_all.dart
+test/services/snippets/dart/class_declaration_test.dart
+test/services/snippets/dart/do_statement_test.dart
+test/services/snippets/dart/flutter_stateful_widget_test.dart
+test/services/snippets/dart/flutter_stateful_widget_with_animation_controller_test.dart
+test/services/snippets/dart/flutter_stateless_widget_test.dart
+test/services/snippets/dart/for_in_statement_test.dart
+test/services/snippets/dart/for_statement_test.dart
+test/services/snippets/dart/function_declaration_test.dart
+test/services/snippets/dart/if_else_statement_test.dart
+test/services/snippets/dart/if_statement_test.dart
+test/services/snippets/dart/main_function_test.dart
+test/services/snippets/dart/switch_expression_test.dart
+test/services/snippets/dart/switch_statement_test.dart
+test/services/snippets/dart/test_all.dart
+test/services/snippets/dart/test_definition_test.dart
+test/services/snippets/dart/test_group_definition_test.dart
+test/services/snippets/dart/try_catch_statement_test.dart
+test/services/snippets/dart/while_statement_test.dart
+test/services/snippets/snippet_request_test.dart
+test/services/snippets/test_all.dart
+test/services/test_all.dart
+test/services/user_prompts/dart_fix_prompt_manager_test.dart
+test/services/user_prompts/preferences_test.dart
+test/services/user_prompts/survey_manager_test.dart
+test/services/user_prompts/test_all.dart
+test/shared/shared_dtd_tests.dart
+test/socket_server_test.dart
+test/src/analytics/analytics_manager_test.dart
+test/src/analytics/percentile_calculator_test.dart
+test/src/analytics/test_all.dart
+test/src/cider/assists_test.dart
+test/src/cider/cider_service.dart
+test/src/cider/document_symbols_test.dart
+test/src/cider/fixes_test.dart
+test/src/cider/signature_help_test.dart
+test/src/cider/test_all.dart
+test/src/computer/call_hierarchy_computer_test.dart
+test/src/computer/closing_labels_computer_test.dart
+test/src/computer/color_computer_test.dart
+test/src/computer/folding_computer_test.dart
+test/src/computer/highlights_computer_test.dart
+test/src/computer/import_elements_computer_test.dart
+test/src/computer/imported_elements_computer_test.dart
+test/src/computer/outline_computer_test.dart
+test/src/computer/selection_range_computer_test.dart
+test/src/computer/test_all.dart
+test/src/domains/execution/completion_test.dart
+test/src/domains/execution/test_all.dart
+test/src/domains/flutter/base.dart
+test/src/domains/flutter/get_widget_description_test.dart
+test/src/domains/flutter/set_property_value_test.dart
+test/src/domains/flutter/test_all.dart
+test/src/domains/test_all.dart
+test/src/flutter/flutter_outline_computer_test.dart
+test/src/flutter/flutter_outline_notification_test.dart
+test/src/flutter/test_all.dart
+test/src/g3/fixes_test.dart
+test/src/g3/test_all.dart
+test/src/g3/utilities_test.dart
+test/src/lsp/lsp_packet_transformer_test.dart
+test/src/lsp/test_all.dart
+test/src/plugin/notification_manager_test.dart
+test/src/plugin/plugin_locator_test.dart
+test/src/plugin/plugin_manager_test.dart
+test/src/plugin/plugin_watcher_test.dart
+test/src/plugin/protocol_test_utilities.dart
+test/src/plugin/request_converter_test.dart
+test/src/plugin/result_collector_test.dart
+test/src/plugin/result_converter_test.dart
+test/src/plugin/result_merger_test.dart
+test/src/plugin/test_all.dart
+test/src/plugin2/generator_test.dart
+test/src/plugin2/test_all.dart
+test/src/server/sdk_configuration_test.dart
+test/src/server/test_all.dart
+test/src/services/completion/dart/completion_test.dart
+test/src/services/completion/dart/feature_computer_test.dart
+test/src/services/completion/dart/test_all.dart
+test/src/services/completion/test_all.dart
+test/src/services/completion/yaml/analysis_options_generator_test.dart
+test/src/services/completion/yaml/fix_data_generator_test.dart
+test/src/services/completion/yaml/pubspec_generator_test.dart
+test/src/services/completion/yaml/test_all.dart
+test/src/services/completion/yaml/yaml_generator_test_support.dart
+test/src/services/correction/assist/add_diagnostic_property_reference_test.dart
+test/src/services/correction/assist/add_digit_separators_test.dart
+test/src/services/correction/assist/add_return_type_test.dart
+test/src/services/correction/assist/add_type_annotation_test.dart
+test/src/services/correction/assist/assign_to_local_variable_test.dart
+test/src/services/correction/assist/assist_processor.dart
+test/src/services/correction/assist/convert_class_to_enum_test.dart
+test/src/services/correction/assist/convert_class_to_mixin_test.dart
+test/src/services/correction/assist/convert_documentation_into_block_test.dart
+test/src/services/correction/assist/convert_documentation_into_line_test.dart
+test/src/services/correction/assist/convert_into_async_body_test.dart
+test/src/services/correction/assist/convert_into_block_body_test.dart
+test/src/services/correction/assist/convert_into_expression_body_test.dart
+test/src/services/correction/assist/convert_into_final_field_test.dart
+test/src/services/correction/assist/convert_into_for_index_test.dart
+test/src/services/correction/assist/convert_into_generic_function_syntax_test.dart
+test/src/services/correction/assist/convert_into_getter_test.dart
+test/src/services/correction/assist/convert_into_is_not_empty_test.dart
+test/src/services/correction/assist/convert_into_is_not_test.dart
+test/src/services/correction/assist/convert_part_of_to_uri_test.dart
+test/src/services/correction/assist/convert_to_double_quoted_string_test.dart
+test/src/services/correction/assist/convert_to_field_parameter_test.dart
+test/src/services/correction/assist/convert_to_for_element_test.dart
+test/src/services/correction/assist/convert_to_if_case_statement_chain_test.dart
+test/src/services/correction/assist/convert_to_if_case_statement_test.dart
+test/src/services/correction/assist/convert_to_if_element_test.dart
+test/src/services/correction/assist/convert_to_int_literal_test.dart
+test/src/services/correction/assist/convert_to_map_literal_test.dart
+test/src/services/correction/assist/convert_to_multiline_string_test.dart
+test/src/services/correction/assist/convert_to_normal_parameter_test.dart
+test/src/services/correction/assist/convert_to_null_aware_test.dart
+test/src/services/correction/assist/convert_to_package_import_test.dart
+test/src/services/correction/assist/convert_to_set_literal_test.dart
+test/src/services/correction/assist/convert_to_single_quoted_string_test.dart
+test/src/services/correction/assist/convert_to_spread_test.dart
+test/src/services/correction/assist/convert_to_super_parameters_test.dart
+test/src/services/correction/assist/convert_to_switch_expression_test.dart
+test/src/services/correction/assist/convert_to_switch_statement_test.dart
+test/src/services/correction/assist/destructure_local_variable_assignment_test.dart
+test/src/services/correction/assist/encapsulate_field_test.dart
+test/src/services/correction/assist/exchange_operands_test.dart
+test/src/services/correction/assist/flutter_convert_to_children_test.dart
+test/src/services/correction/assist/flutter_convert_to_stateful_widget_test.dart
+test/src/services/correction/assist/flutter_convert_to_stateless_widget_test.dart
+test/src/services/correction/assist/flutter_move_down_test.dart
+test/src/services/correction/assist/flutter_move_up_test.dart
+test/src/services/correction/assist/flutter_remove_widget_test.dart
+test/src/services/correction/assist/flutter_surround_with_set_state_test.dart
+test/src/services/correction/assist/flutter_swap_with_child_test.dart
+test/src/services/correction/assist/flutter_swap_with_parent_test.dart
+test/src/services/correction/assist/flutter_wrap_builder_test.dart
+test/src/services/correction/assist/flutter_wrap_center_test.dart
+test/src/services/correction/assist/flutter_wrap_column_test.dart
+test/src/services/correction/assist/flutter_wrap_container_test.dart
+test/src/services/correction/assist/flutter_wrap_generic_test.dart
+test/src/services/correction/assist/flutter_wrap_padding_test.dart
+test/src/services/correction/assist/flutter_wrap_row_test.dart
+test/src/services/correction/assist/flutter_wrap_sized_box_test.dart
+test/src/services/correction/assist/flutter_wrap_stream_builder_test.dart
+test/src/services/correction/assist/import_add_show_test.dart
+test/src/services/correction/assist/inline_invocation_test.dart
+test/src/services/correction/assist/invert_conditional_expression_test.dart
+test/src/services/correction/assist/invert_if_statement_test.dart
+test/src/services/correction/assist/join_if_with_inner_test.dart
+test/src/services/correction/assist/join_if_with_outer_test.dart
+test/src/services/correction/assist/join_variable_declaration_test.dart
+test/src/services/correction/assist/remove_digit_separators_test.dart
+test/src/services/correction/assist/remove_type_annotation_test.dart
+test/src/services/correction/assist/replace_conditional_with_if_else_test.dart
+test/src/services/correction/assist/replace_if_else_with_conditional_test.dart
+test/src/services/correction/assist/replace_with_var_test.dart
+test/src/services/correction/assist/shadow_field_test.dart
+test/src/services/correction/assist/sort_child_property_last_test.dart
+test/src/services/correction/assist/split_and_condition_test.dart
+test/src/services/correction/assist/split_variable_declaration_test.dart
+test/src/services/correction/assist/surround_with_block_test.dart
+test/src/services/correction/assist/surround_with_do_while_test.dart
+test/src/services/correction/assist/surround_with_for_in_test.dart
+test/src/services/correction/assist/surround_with_for_test.dart
+test/src/services/correction/assist/surround_with_if_test.dart
+test/src/services/correction/assist/surround_with_try_catch_test.dart
+test/src/services/correction/assist/surround_with_try_finally_test.dart
+test/src/services/correction/assist/surround_with_while_test.dart
+test/src/services/correction/assist/test_all.dart
+test/src/services/correction/assist/use_curly_braces_test.dart
+test/src/services/correction/fix/add_async_test.dart
+test/src/services/correction/fix/add_await_test.dart
+test/src/services/correction/fix/add_call_super_test.dart
+test/src/services/correction/fix/add_class_modifier_test.dart
+test/src/services/correction/fix/add_const_test.dart
+test/src/services/correction/fix/add_curly_braces_test.dart
+test/src/services/correction/fix/add_diagnostic_property_reference_test.dart
+test/src/services/correction/fix/add_empty_argument_list_test.dart
+test/src/services/correction/fix/add_enum_constant_test.dart
+test/src/services/correction/fix/add_eol_at_end_of_file_test.dart
+test/src/services/correction/fix/add_explicit_call_test.dart
+test/src/services/correction/fix/add_explicit_cast_test.dart
+test/src/services/correction/fix/add_extension_override_test.dart
+test/src/services/correction/fix/add_field_formal_parameters_test.dart
+test/src/services/correction/fix/add_key_to_constructors_test.dart
+test/src/services/correction/fix/add_late_test.dart
+test/src/services/correction/fix/add_leading_newline_to_string_test.dart
+test/src/services/correction/fix/add_missing_enum_case_clauses_test.dart
+test/src/services/correction/fix/add_missing_enum_like_case_clauses_test.dart
+test/src/services/correction/fix/add_missing_parameter_named_test.dart
+test/src/services/correction/fix/add_missing_parameter_positional_test.dart
+test/src/services/correction/fix/add_missing_parameter_required_test.dart
+test/src/services/correction/fix/add_missing_required_argument_test.dart
+test/src/services/correction/fix/add_missing_switch_cases_test.dart
+test/src/services/correction/fix/add_ne_null_test.dart
+test/src/services/correction/fix/add_null_check_test.dart
+test/src/services/correction/fix/add_override_test.dart
+test/src/services/correction/fix/add_redeclare_test.dart
+test/src/services/correction/fix/add_reopen_test.dart
+test/src/services/correction/fix/add_required_test.dart
+test/src/services/correction/fix/add_return_null_test.dart
+test/src/services/correction/fix/add_return_type_test.dart
+test/src/services/correction/fix/add_static_test.dart
+test/src/services/correction/fix/add_super_constructor_invocation_test.dart
+test/src/services/correction/fix/add_super_parameter_test.dart
+test/src/services/correction/fix/add_switch_case_break_test.dart
+test/src/services/correction/fix/add_trailing_comma_test.dart
+test/src/services/correction/fix/add_type_annotation_test.dart
+test/src/services/correction/fix/analysis_options/remove_lint_test.dart
+test/src/services/correction/fix/analysis_options/remove_setting_test.dart
+test/src/services/correction/fix/analysis_options/test_all.dart
+test/src/services/correction/fix/analysis_options/test_support.dart
+test/src/services/correction/fix/bulk_fix_processor_test.dart
+test/src/services/correction/fix/change_argument_name_test.dart
+test/src/services/correction/fix/change_to_nearest_precise_value_test.dart
+test/src/services/correction/fix/change_to_static_access_test.dart
+test/src/services/correction/fix/change_to_test.dart
+test/src/services/correction/fix/change_type_annotation_test.dart
+test/src/services/correction/fix/convert_class_to_enum_test.dart
+test/src/services/correction/fix/convert_documentation_into_line_test.dart
+test/src/services/correction/fix/convert_flutter_child_test.dart
+test/src/services/correction/fix/convert_flutter_children_test.dart
+test/src/services/correction/fix/convert_for_each_to_for_loop_test.dart
+test/src/services/correction/fix/convert_into_block_body_test.dart
+test/src/services/correction/fix/convert_into_expression_body_test.dart
+test/src/services/correction/fix/convert_into_is_not_test.dart
+test/src/services/correction/fix/convert_quotes_test.dart
+test/src/services/correction/fix/convert_to_block_function_body_test.dart
+test/src/services/correction/fix/convert_to_boolean_expression_test.dart
+test/src/services/correction/fix/convert_to_cascade_test.dart
+test/src/services/correction/fix/convert_to_constant_pattern_test.dart
+test/src/services/correction/fix/convert_to_contains_test.dart
+test/src/services/correction/fix/convert_to_double_quoted_string_test.dart
+test/src/services/correction/fix/convert_to_flutter_style_todo_test.dart
+test/src/services/correction/fix/convert_to_for_element_test.dart
+test/src/services/correction/fix/convert_to_function_declaration_test.dart
+test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart
+test/src/services/correction/fix/convert_to_if_element_test.dart
+test/src/services/correction/fix/convert_to_if_null_test.dart
+test/src/services/correction/fix/convert_to_initializing_formal_test.dart
+test/src/services/correction/fix/convert_to_int_literal_test.dart
+test/src/services/correction/fix/convert_to_map_literal_test.dart
+test/src/services/correction/fix/convert_to_named_arguments_test.dart
+test/src/services/correction/fix/convert_to_null_aware_spread_test.dart
+test/src/services/correction/fix/convert_to_null_aware_test.dart
+test/src/services/correction/fix/convert_to_on_type_test.dart
+test/src/services/correction/fix/convert_to_package_import_test.dart
+test/src/services/correction/fix/convert_to_raw_string_test.dart
+test/src/services/correction/fix/convert_to_relative_import_test.dart
+test/src/services/correction/fix/convert_to_set_literal_test.dart
+test/src/services/correction/fix/convert_to_single_quoted_string_test.dart
+test/src/services/correction/fix/convert_to_spread_test.dart
+test/src/services/correction/fix/convert_to_super_parameters_test.dart
+test/src/services/correction/fix/convert_to_where_type_test.dart
+test/src/services/correction/fix/convert_to_wildcard_pattern_test.dart
+test/src/services/correction/fix/convert_to_wildcard_variable_test.dart
+test/src/services/correction/fix/create_class_test.dart
+test/src/services/correction/fix/create_constructor_for_final_fields_test.dart
+test/src/services/correction/fix/create_constructor_super_test.dart
+test/src/services/correction/fix/create_constructor_test.dart
+test/src/services/correction/fix/create_extension_member_test.dart
+test/src/services/correction/fix/create_field_test.dart
+test/src/services/correction/fix/create_file_test.dart
+test/src/services/correction/fix/create_function_test.dart
+test/src/services/correction/fix/create_getter_test.dart
+test/src/services/correction/fix/create_local_variable_test.dart
+test/src/services/correction/fix/create_method_test.dart
+test/src/services/correction/fix/create_missing_overrides_test.dart
+test/src/services/correction/fix/create_mixin_test.dart
+test/src/services/correction/fix/create_no_such_method_test.dart
+test/src/services/correction/fix/create_parameter_test.dart
+test/src/services/correction/fix/create_setter_test.dart
+test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
+test/src/services/correction/fix/data_driven/code_fragment_parser_test.dart
+test/src/services/correction/fix/data_driven/code_template_test.dart
+test/src/services/correction/fix/data_driven/collection_use_case_test.dart
+test/src/services/correction/fix/data_driven/data_driven_test.dart
+test/src/services/correction/fix/data_driven/data_driven_test_support.dart
+test/src/services/correction/fix/data_driven/diagnostics/conflicting_key_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/expected_primary_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/incompatible_element_kind_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/invalid_change_for_kind_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/invalid_character_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/invalid_key_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/invalid_parameter_style_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/invalid_required_if_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/invalid_value_one_of_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/invalid_value_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/missing_key_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/missing_one_of_multiple_keys_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/missing_template_end_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/missing_token_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/missing_uri_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/test_all.dart
+test/src/services/correction/fix/data_driven/diagnostics/undefined_variable_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/unexpected_token_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/unknown_accessor_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/unsupported_key_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/unsupported_static_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/unsupported_version_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/wrong_token_test.dart
+test/src/services/correction/fix/data_driven/diagnostics/yaml_syntax_error_test.dart
+test/src/services/correction/fix/data_driven/element_matcher_test.dart
+test/src/services/correction/fix/data_driven/end_to_end_test.dart
+test/src/services/correction/fix/data_driven/flutter_use_case_test.dart
+test/src/services/correction/fix/data_driven/modify_parameters_test.dart
+test/src/services/correction/fix/data_driven/platform_use_case_test.dart
+test/src/services/correction/fix/data_driven/rename_parameter_test.dart
+test/src/services/correction/fix/data_driven/rename_test.dart
+test/src/services/correction/fix/data_driven/replaced_by_test.dart
+test/src/services/correction/fix/data_driven/sdk_fix_test.dart
+test/src/services/correction/fix/data_driven/test_all.dart
+test/src/services/correction/fix/data_driven/test_use_case_test.dart
+test/src/services/correction/fix/data_driven/transform_set_manager_test.dart
+test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
+test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart
+test/src/services/correction/fix/directives_ordering_test.dart
+test/src/services/correction/fix/extend_class_for_mixin_test.dart
+test/src/services/correction/fix/extract_local_variable_test.dart
+test/src/services/correction/fix/fix_in_file_test.dart
+test/src/services/correction/fix/fix_processor.dart
+test/src/services/correction/fix/fix_processor_map_test.dart
+test/src/services/correction/fix/fix_test.dart
+test/src/services/correction/fix/format_file_test.dart
+test/src/services/correction/fix/ignore_diagnostic_test.dart
+test/src/services/correction/fix/import_library_prefix_test.dart
+test/src/services/correction/fix/import_library_project_test.dart
+test/src/services/correction/fix/import_library_sdk_test.dart
+test/src/services/correction/fix/import_library_show_test.dart
+test/src/services/correction/fix/inline_invocation_test.dart
+test/src/services/correction/fix/inline_typedef_test.dart
+test/src/services/correction/fix/insert_body_test.dart
+test/src/services/correction/fix/insert_semicolon_test.dart
+test/src/services/correction/fix/make_class_abstract_test.dart
+test/src/services/correction/fix/make_conditional_on_debug_mode_test.dart
+test/src/services/correction/fix/make_field_not_final_test.dart
+test/src/services/correction/fix/make_field_public_test.dart
+test/src/services/correction/fix/make_final_test.dart
+test/src/services/correction/fix/make_required_named_parameters_first_test.dart
+test/src/services/correction/fix/make_return_type_nullable_test.dart
+test/src/services/correction/fix/make_super_invocation_last_test.dart
+test/src/services/correction/fix/make_variable_not_final_test.dart
+test/src/services/correction/fix/make_variable_nullable_test.dart
+test/src/services/correction/fix/move_annotation_to_library_directive_test.dart
+test/src/services/correction/fix/move_doc_comment_to_library_directive_test.dart
+test/src/services/correction/fix/move_type_arguments_to_class_test.dart
+test/src/services/correction/fix/organize_imports_test.dart
+test/src/services/correction/fix/pubspec/add_dependency_test.dart
+test/src/services/correction/fix/pubspec/missing_name_test.dart
+test/src/services/correction/fix/pubspec/test_all.dart
+test/src/services/correction/fix/pubspec/test_support.dart
+test/src/services/correction/fix/qualify_reference_test.dart
+test/src/services/correction/fix/remove_abstract_test.dart
+test/src/services/correction/fix/remove_annotation_test.dart
+test/src/services/correction/fix/remove_argument_test.dart
+test/src/services/correction/fix/remove_assertion_test.dart
+test/src/services/correction/fix/remove_assignment_test.dart
+test/src/services/correction/fix/remove_await_test.dart
+test/src/services/correction/fix/remove_break_test.dart
+test/src/services/correction/fix/remove_character_test.dart
+test/src/services/correction/fix/remove_comma_test.dart
+test/src/services/correction/fix/remove_comparison_test.dart
+test/src/services/correction/fix/remove_const_test.dart
+test/src/services/correction/fix/remove_constructor_name_test.dart
+test/src/services/correction/fix/remove_constructor_test.dart
+test/src/services/correction/fix/remove_dead_code_test.dart
+test/src/services/correction/fix/remove_default_value_test.dart
+test/src/services/correction/fix/remove_deprecated_new_in_comment_reference_test.dart
+test/src/services/correction/fix/remove_duplicate_case_test.dart
+test/src/services/correction/fix/remove_empty_catch_test.dart
+test/src/services/correction/fix/remove_empty_constructor_body_test.dart
+test/src/services/correction/fix/remove_empty_else_test.dart
+test/src/services/correction/fix/remove_empty_statement_test.dart
+test/src/services/correction/fix/remove_extends_clause_test.dart
+test/src/services/correction/fix/remove_if_null_operator_test.dart
+test/src/services/correction/fix/remove_initializer_test.dart
+test/src/services/correction/fix/remove_interpolation_braces_test.dart
+test/src/services/correction/fix/remove_invocation_test.dart
+test/src/services/correction/fix/remove_late_test.dart
+test/src/services/correction/fix/remove_leading_underscore_test.dart
+test/src/services/correction/fix/remove_lexeme_test.dart
+test/src/services/correction/fix/remove_library_name_test.dart
+test/src/services/correction/fix/remove_method_declaration_test.dart
+test/src/services/correction/fix/remove_name_from_combinator_test.dart
+test/src/services/correction/fix/remove_name_from_declaration_clause_test.dart
+test/src/services/correction/fix/remove_non_null_assertion_test.dart
+test/src/services/correction/fix/remove_on_clause_test.dart
+test/src/services/correction/fix/remove_operator_test.dart
+test/src/services/correction/fix/remove_parameters_in_getter_declaration_test.dart
+test/src/services/correction/fix/remove_parentheses_in_getter_invocation_test.dart
+test/src/services/correction/fix/remove_print_test.dart
+test/src/services/correction/fix/remove_question_mark_test.dart
+test/src/services/correction/fix/remove_required_test.dart
+test/src/services/correction/fix/remove_returned_value_test.dart
+test/src/services/correction/fix/remove_this_expression_test.dart
+test/src/services/correction/fix/remove_type_annotation_test.dart
+test/src/services/correction/fix/remove_type_arguments_test.dart
+test/src/services/correction/fix/remove_unexpected_underscores_test.dart
+test/src/services/correction/fix/remove_unnecessary_cast_test.dart
+test/src/services/correction/fix/remove_unnecessary_const_test.dart
+test/src/services/correction/fix/remove_unnecessary_final_test.dart
+test/src/services/correction/fix/remove_unnecessary_late_test.dart
+test/src/services/correction/fix/remove_unnecessary_library_directive_test.dart
+test/src/services/correction/fix/remove_unnecessary_new_test.dart
+test/src/services/correction/fix/remove_unnecessary_parentheses_test.dart
+test/src/services/correction/fix/remove_unnecessary_raw_string_test.dart
+test/src/services/correction/fix/remove_unnecessary_string_escapes_test.dart
+test/src/services/correction/fix/remove_unnecessary_string_interpolation_test.dart
+test/src/services/correction/fix/remove_unnecessary_to_list_test.dart
+test/src/services/correction/fix/remove_unnecessary_wildcard_pattern_test.dart
+test/src/services/correction/fix/remove_unused_catch_clause_test.dart
+test/src/services/correction/fix/remove_unused_catch_stack_test.dart
+test/src/services/correction/fix/remove_unused_element_test.dart
+test/src/services/correction/fix/remove_unused_field_test.dart
+test/src/services/correction/fix/remove_unused_import_test.dart
+test/src/services/correction/fix/remove_unused_label_test.dart
+test/src/services/correction/fix/remove_unused_local_variable_test.dart
+test/src/services/correction/fix/remove_unused_parameter_test.dart
+test/src/services/correction/fix/remove_var_keyword_test.dart
+test/src/services/correction/fix/remove_var_test.dart
+test/src/services/correction/fix/rename_method_parameter_test.dart
+test/src/services/correction/fix/rename_to_camel_case_test.dart
+test/src/services/correction/fix/replace_boolean_with_bool_test.dart
+test/src/services/correction/fix/replace_cascade_with_dot_test.dart
+test/src/services/correction/fix/replace_colon_with_equals_test.dart
+test/src/services/correction/fix/replace_colon_with_in_test.dart
+test/src/services/correction/fix/replace_container_with_colored_box_test.dart
+test/src/services/correction/fix/replace_container_with_sized_box_test.dart
+test/src/services/correction/fix/replace_empty_amp_pattern_test.dart
+test/src/services/correction/fix/replace_final_with_const_test.dart
+test/src/services/correction/fix/replace_final_with_var_test.dart
+test/src/services/correction/fix/replace_new_with_const_test.dart
+test/src/services/correction/fix/replace_null_check_with_cast_test.dart
+test/src/services/correction/fix/replace_null_with_closure_test.dart
+test/src/services/correction/fix/replace_null_with_void_test.dart
+test/src/services/correction/fix/replace_return_type_future_test.dart
+test/src/services/correction/fix/replace_return_type_iterable_test.dart
+test/src/services/correction/fix/replace_return_type_stream_test.dart
+test/src/services/correction/fix/replace_return_type_test.dart
+test/src/services/correction/fix/replace_var_with_dynamic_test.dart
+test/src/services/correction/fix/replace_with_arrow_test.dart
+test/src/services/correction/fix/replace_with_brackets_test.dart
+test/src/services/correction/fix/replace_with_conditional_assignment_test.dart
+test/src/services/correction/fix/replace_with_decorated_box_test.dart
+test/src/services/correction/fix/replace_with_eight_digit_hex_test.dart
+test/src/services/correction/fix/replace_with_extension_name_test.dart
+test/src/services/correction/fix/replace_with_identifier_test.dart
+test/src/services/correction/fix/replace_with_interpolation_test.dart
+test/src/services/correction/fix/replace_with_is_empty_test.dart
+test/src/services/correction/fix/replace_with_is_nan_test.dart
+test/src/services/correction/fix/replace_with_is_not_empty_test.dart
+test/src/services/correction/fix/replace_with_named_constant_test.dart
+test/src/services/correction/fix/replace_with_not_null_aware_test.dart
+test/src/services/correction/fix/replace_with_null_aware_test.dart
+test/src/services/correction/fix/replace_with_part_of_uri_test.dart
+test/src/services/correction/fix/replace_with_tear_off_test.dart
+test/src/services/correction/fix/replace_with_unicode_escape_test.dart
+test/src/services/correction/fix/replace_with_var_test.dart
+test/src/services/correction/fix/replace_with_wildcard_test.dart
+test/src/services/correction/fix/sort_child_property_last_test.dart
+test/src/services/correction/fix/sort_combinators_test.dart
+test/src/services/correction/fix/sort_constructor_first_test.dart
+test/src/services/correction/fix/sort_unnamed_constructor_first_test.dart
+test/src/services/correction/fix/split_multiple_declarations_test.dart
+test/src/services/correction/fix/surround_with_parentheses_test.dart
+test/src/services/correction/fix/test_all.dart
+test/src/services/correction/fix/update_sdk_constraints_test.dart
+test/src/services/correction/fix/use_curly_braces_test.dart
+test/src/services/correction/fix/use_effective_integer_division_test.dart
+test/src/services/correction/fix/use_eq_eq_null_test.dart
+test/src/services/correction/fix/use_is_not_empty_test.dart
+test/src/services/correction/fix/use_not_eq_null_test.dart
+test/src/services/correction/fix/use_rethrow_test.dart
+test/src/services/correction/fix/wrap_in_text_test.dart
+test/src/services/correction/fix/wrap_in_unawaited_test.dart
+test/src/services/correction/test_all.dart
+test/src/services/flutter/constants.dart
+test/src/services/flutter/container_properties_test.dart
+test/src/services/flutter/test_all.dart
+test/src/services/flutter/widget_description.dart
+test/src/services/flutter/widget_descriptions_test.dart
+test/src/services/refactoring/convert_all_formal_parameters_to_named_test.dart
+test/src/services/refactoring/convert_selected_formal_parameters_to_named_test.dart
+test/src/services/refactoring/move_selected_formal_parameters_left_test.dart
+test/src/services/refactoring/move_top_level_to_file_test.dart
+test/src/services/refactoring/refactoring_test_support.dart
+test/src/services/refactoring/test_all.dart
+test/src/services/test_all.dart
+test/src/test_all.dart
+test/src/utilities/extensions/ast_test.dart
+test/src/utilities/extensions/range_factory_test.dart
+test/src/utilities/extensions/string_test.dart
+test/src/utilities/extensions/test_all.dart
+test/src/utilities/json_test.dart
+test/src/utilities/profiling_test.dart
+test/src/utilities/selection_test.dart
+test/src/utilities/source_change_merger_test.dart
+test/src/utilities/strings_test.dart
+test/src/utilities/test_all.dart
+test/stress/completion/completion.dart
+test/stress/completion/completion_runner.dart
+test/stress/replay/operation.dart
+test/stress/replay/replay.dart
+test/stress/utilities/git.dart
+test/stress/utilities/logger.dart
+test/stress/utilities/server.dart
+test/support/configuration_files.dart
+test/test_all.dart
+test/test_macros.dart
+test/timing/completion/completion_simple.dart
+test/timing/timing_framework.dart
+test/tool/completion_metrics/metrics_util_test.dart
+test/tool/completion_metrics/test_all.dart
+test/tool/lsp_spec/dart_test.dart
+test/tool/lsp_spec/generated_classes_test.dart
+test/tool/lsp_spec/json_test.dart
+test/tool/lsp_spec/matchers.dart
+test/tool/lsp_spec/meta_model_test.dart
+test/tool/lsp_spec/readme_test.dart
+test/tool/lsp_spec/test_all.dart
+test/tool/test_all.dart
+test/utilities/test_all.dart
+test/utilities/usage_tracking/test_all.dart
+test/utilities/usage_tracking/usage_tracking_test.dart
+test/utils/lsp_protocol_extensions.dart
+test/utils/test_code_extensions.dart
+test/utils/test_instrumentation_service.dart
+test/utils/test_support.dart
+test/verify_error_fix_status_test.dart
+test/verify_no_utf8_encode_test.dart
+test/verify_sorted_test.dart
+test/verify_tests_test.dart
+tool/bulk_fix/supported_diagnostics.dart
+tool/bulk_fix/supported_lints.dart
+tool/code_completion/benchmark/flutter.dart
+tool/code_completion/benchmark/sliding_statistics.dart
+tool/code_completion/code_metrics.dart
+tool/code_completion/completion_at.dart
+tool/code_completion/completion_metrics_base.dart
+tool/code_completion/completion_metrics_client.dart
+tool/code_completion/corpus.dart
+tool/code_completion/implicit_type_declarations.dart
+tool/code_completion/metrics_util.dart
+tool/code_completion/output_utilities.dart
+tool/codebase/failing_tests.dart
+tool/generate_testing_package.dart
+tool/instrumentation/log/log.dart
+tool/instrumentation/log_viewer.dart
+tool/instrumentation/page/log_page.dart
+tool/instrumentation/page/page_writer.dart
+tool/instrumentation/page/stats_page.dart
+tool/instrumentation/server.dart
+tool/lsp_spec/codegen_dart.dart
+tool/lsp_spec/generate_all.dart
+tool/lsp_spec/meta_model.dart
+tool/lsp_spec/meta_model_cleaner.dart
+tool/lsp_spec/meta_model_reader.dart
+tool/lsp_test_with_parameters.dart
+tool/presubmit/verify_error_fix_status.dart
+tool/spec/api.dart
+tool/spec/check_all_test.dart
+tool/spec/codegen_analysis_server.dart
+tool/spec/codegen_dart.dart
+tool/spec/codegen_dart_notification_handler.dart
+tool/spec/codegen_dart_protocol.dart
+tool/spec/codegen_inttest_methods.dart
+tool/spec/codegen_java.dart
+tool/spec/codegen_java_types.dart
+tool/spec/codegen_matchers.dart
+tool/spec/codegen_protocol_constants.dart
+tool/spec/from_html.dart
+tool/spec/generate_all.dart
+tool/spec/implied_types.dart
+tool/spec/to_html.dart
diff --git a/pkg/analysis_server/benchmark/perf/memory_tests.dart b/pkg/analysis_server/benchmark/perf/memory_tests.dart
index ecfbb91..fa987b3 100644
--- a/pkg/analysis_server/benchmark/perf/memory_tests.dart
+++ b/pkg/analysis_server/benchmark/perf/memory_tests.dart
@@ -183,7 +183,6 @@
     _test.instrumentationService = InstrumentationLogAdapter(_logger);
     await _test.setUp();
     _test.projectFolderPath = roots.single;
-    _test.projectFolderUri = Uri.file(_test.projectFolderPath);
     await _test.initialize();
   }
 
@@ -218,7 +217,8 @@
       '--enable-vm-service=$_vmServicePort',
       '-DSILENT_OBSERVATORY=true',
       '--disable-service-auth-codes',
-      '--disable-dart-dev'
+      '--disable-dart-dev',
+      '--no-dds',
     ]);
     await super.setUp();
 
diff --git a/pkg/analysis_server/doc/implementation/quick_fix.md b/pkg/analysis_server/doc/implementation/quick_fix.md
index 04df53d..c3d05b5 100644
--- a/pkg/analysis_server/doc/implementation/quick_fix.md
+++ b/pkg/analysis_server/doc/implementation/quick_fix.md
@@ -145,8 +145,8 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:linter/src/lint_names.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'fix_processor.dart';
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 6cb54e1..ebcaec2 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -12,12 +12,14 @@
 import 'package:analysis_server/src/context_manager.dart';
 import 'package:analysis_server/src/domains/completion/available_suggestions.dart';
 import 'package:analysis_server/src/legacy_analysis_server.dart';
-import 'package:analysis_server/src/lsp/client_capabilities.dart';
-import 'package:analysis_server/src/lsp/client_configuration.dart';
+import 'package:analysis_server/src/lsp/client_capabilities.dart' as lsp;
+import 'package:analysis_server/src/lsp/client_configuration.dart' as lsp;
 import 'package:analysis_server/src/lsp/constants.dart' as lsp;
-import 'package:analysis_server/src/lsp/error_or.dart';
-import 'package:analysis_server/src/lsp/handlers/handler_execute_command.dart';
-import 'package:analysis_server/src/lsp/handlers/handler_states.dart';
+import 'package:analysis_server/src/lsp/error_or.dart' as lsp;
+import 'package:analysis_server/src/lsp/handlers/handler_execute_command.dart'
+    as lsp;
+import 'package:analysis_server/src/lsp/handlers/handler_states.dart' as lsp;
+import 'package:analysis_server/src/lsp/handlers/handlers.dart' as lsp;
 import 'package:analysis_server/src/plugin/notification_manager.dart';
 import 'package:analysis_server/src/plugin/plugin_manager.dart';
 import 'package:analysis_server/src/plugin/plugin_watcher.dart';
@@ -26,6 +28,7 @@
 import 'package:analysis_server/src/protocol_server.dart' as server;
 import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
 import 'package:analysis_server/src/server/diagnostic_server.dart';
+import 'package:analysis_server/src/server/message_scheduler.dart';
 import 'package:analysis_server/src/server/performance.dart';
 import 'package:analysis_server/src/services/completion/completion_performance.dart';
 import 'package:analysis_server/src/services/correction/assist_internal.dart';
@@ -46,6 +49,7 @@
 import 'package:analysis_server/src/utilities/process.dart';
 import 'package:analysis_server/src/utilities/request_statistics.dart';
 import 'package:analysis_server/src/utilities/tee_string_sink.dart';
+import 'package:analysis_server/src/utilities/timing_byte_store.dart';
 import 'package:analysis_server_plugin/src/correction/fix_generators.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/analysis/session.dart';
@@ -135,7 +139,7 @@
   ///
   /// This allows the server to call commands itself, such as "Fix All in
   /// Workspace" triggered from the [DartFixPromptManager].
-  ExecuteCommandHandler? executeCommandHandler;
+  lsp.ExecuteCommandHandler? executeCommandHandler;
 
   /// The object used to manage the execution of plugins.
   late PluginManager pluginManager;
@@ -250,6 +254,13 @@
   /// A completer for [lspUninitialized].
   final Completer<void> _lspUninitializedCompleter = Completer<void>();
 
+  /// A scheduler that keeps track of all incoming messages and schedules them
+  /// for processing.
+  final MessageScheduler messageScheduler;
+
+  /// A [TimingByteStore] that records timings for reads from the byte store.
+  TimingByteStore? _timingByteStore;
+
   AnalysisServer(
     this.options,
     this.sdkManager,
@@ -269,7 +280,9 @@
   })  : resourceProvider = OverlayResourceProvider(baseResourceProvider),
         pubApi = PubApi(instrumentationService, httpClient,
             Platform.environment['PUB_HOSTED_URL']),
-        producerGeneratorsForLintRules = AssistProcessor.computeLintRuleMap() {
+        producerGeneratorsForLintRules = AssistProcessor.computeLintRuleMap(),
+        messageScheduler = MessageScheduler() {
+    messageScheduler.setServer(this);
     // Set the default URI converter. This uses the resource providers path
     // context (unlike the initialized value) which allows tests to override it.
     uriConverter = ClientUriConverter.noop(baseResourceProvider.pathContext);
@@ -372,6 +385,10 @@
   Future<void> get analysisContextsRebuilt =>
       analysisContextRebuildCompleter.future;
 
+  /// A list of timings for the byte store, or `null` if timing is not being
+  /// tracked.
+  List<ByteStoreTimings>? get byteStoreTimings => _timingByteStore?.timings;
+
   /// The list of current analysis sessions in all contexts.
   Future<List<AnalysisSessionImpl>> get currentSessions async {
     var sessions = <AnalysisSessionImpl>[];
@@ -386,17 +403,25 @@
   Map<Folder, analysis.AnalysisDriver> get driverMap =>
       contextManager.driverMap;
 
-  /// The capabilities of the LSP client.
+  /// The capabilities of the editor that owns this server.
   ///
-  /// For the legacy server, this set may be a fixed set that is not configured
-  /// by the client.
-  LspClientCapabilities? get lspClientCapabilities;
+  /// Request handlers should be careful to use the correct clients capabilities
+  /// if they are available to non-editor clients (such as over DTD). The
+  /// capabilities of the caller are available in [MessageInfo] and should
+  /// usually be used when computing the results for requests, but if those
+  /// requests additionally trigger requests to the editor, those requests to
+  /// the editor should consider these capabilities.
+  ///
+  /// For the legacy server, this set may be a fixed set that is not actually
+  /// configured by the client, but matches what legacy protocol editors expect
+  /// when using LSP-over-Legacy.
+  lsp.LspClientCapabilities? get editorClientCapabilities;
 
   /// The configuration (user/workspace settings) from the LSP client.
   ///
   /// For the legacy server, this set may be a fixed set that is not controlled
   /// by the client.
-  LspClientConfiguration get lspClientConfiguration;
+  lsp.LspClientConfiguration get lspClientConfiguration;
 
   /// A [Future] that completes when the LSP server moves into the initialized
   /// state and can handle normal LSP requests.
@@ -405,7 +430,7 @@
   ///
   /// When the server leaves the initialized state, [lspUninitialized] will
   /// complete.
-  FutureOr<InitializedStateMessageHandler> get lspInitialized;
+  FutureOr<lsp.InitializedStateMessageHandler> get lspInitialized;
 
   /// A [Future] that completes once the server transitions out of an
   /// initialized state.
@@ -457,6 +482,7 @@
   }
 
   void afterContextsCreated() {
+    _timingByteStore?.newTimings('after contexts created');
     isFirstAnalysisSinceContextsBuilt = true;
     addContextsToDeclarationsTracker();
   }
@@ -502,10 +528,10 @@
   ///
   /// If there is already an active connection to DTD or there is an error
   /// connecting, returns an error, otherwise returns `null`.
-  Future<ErrorOr<Null>> connectToDtd(Uri dtdUri) async {
+  Future<lsp.ErrorOr<Null>> connectToDtd(Uri dtdUri) async {
     switch (dtd?.state) {
       case DtdConnectionState.Connecting || DtdConnectionState.Connected:
-        return error(
+        return lsp.error(
           lsp.ServerErrorCodes.StateError,
           'Server is already connected to DTD',
         );
@@ -513,7 +539,7 @@
         var connectResult = await DtdServices.connect(this, dtdUri);
         return connectResult.mapResultSync((dtd) {
           this.dtd = dtd;
-          return success(null);
+          return lsp.success(null);
         });
     }
   }
@@ -536,8 +562,9 @@
     if (resourceProvider is PhysicalResourceProvider) {
       var stateLocation = resourceProvider.getStateLocation('.analysis-driver');
       if (stateLocation != null) {
-        return MemoryCachingByteStore(
-            EvictingFileByteStore(stateLocation.path, G), memoryCacheSize);
+        var timingByteStore = _timingByteStore =
+            TimingByteStore(EvictingFileByteStore(stateLocation.path, G));
+        return MemoryCachingByteStore(timingByteStore, memoryCacheSize);
       }
     }
 
@@ -775,11 +802,34 @@
   @mustCallSuper
   FutureOr<void> handleAnalysisStatusChange(analysis.AnalysisStatus status) {
     if (isFirstAnalysisSinceContextsBuilt && !status.isWorking) {
+      _timingByteStore?.newTimings('initial analysis completed');
       isFirstAnalysisSinceContextsBuilt = false;
       _dartFixPrompt.triggerCheck();
     }
   }
 
+  /// Immediately handles an LSP message by delegating to the
+  /// [lsp.InitializedStateMessageHandler]. This method does not schedule the
+  /// message and is intended to be used by the scheduler (or LSP-over-Legacy
+  /// where the original legacy wrapper was already scheduled).
+  ///
+  /// If the LSP server/support is not yet initialized, will wait until it is.
+  FutureOr<lsp.ErrorOr<Object?>> immediatelyHandleLspMessage(
+    lsp.IncomingMessage message,
+    lsp.MessageInfo messageInfo, {
+    lsp.CancellationToken? cancellationToken,
+  }) async {
+    // This is FutureOr<> because for the legacy server it's never a future, so
+    // we can skip the await.
+    var initializedLspHandler = lspInitialized;
+    var handler = initializedLspHandler is lsp.InitializedStateMessageHandler
+        ? initializedLspHandler
+        : await initializedLspHandler;
+
+    return handler.handleMessage(message, messageInfo,
+        cancellationToken: cancellationToken);
+  }
+
   /// Return `true` if the file or directory with the given [path] will be
   /// analyzed in one of the analysis contexts.
   bool isAnalyzed(String path) {
diff --git a/pkg/analysis_server/lib/src/cider/completion.dart b/pkg/analysis_server/lib/src/cider/completion.dart
index d88d035..ce0fd14 100644
--- a/pkg/analysis_server/lib/src/cider/completion.dart
+++ b/pkg/analysis_server/lib/src/cider/completion.dart
@@ -7,11 +7,13 @@
 import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
 import 'package:analysis_server/src/services/completion/dart/fuzzy_filter_sort.dart';
 import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
-import 'package:analyzer/dart/element/element.dart' show LibraryElement;
+import 'package:analyzer/dart/element/element.dart'
+    show CompilationUnitElement, LibraryElement;
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
 import 'package:analyzer/src/dart/analysis/results.dart';
 import 'package:analyzer/src/dart/micro/resolve_file.dart';
 import 'package:analyzer/src/util/performance/operation_performance.dart';
+import 'package:analyzer/src/utilities/extensions/element.dart';
 import 'package:meta/meta.dart';
 
 /// The cache that can be reuse for across multiple completion request.
@@ -117,7 +119,7 @@
           _logger.run('Add imported suggestions', () {
             suggestions.addAll(
               _importedLibrariesSuggestions(
-                target: resolvedUnit.libraryElement,
+                target: resolvedUnit.unitElement,
                 performance: performance,
               ),
             );
@@ -166,11 +168,16 @@
   // TODO(scheglov): Implement show / hide combinators.
   // TODO(scheglov): Implement prefixes.
   List<CompletionSuggestionBuilder> _importedLibrariesSuggestions({
-    required LibraryElement target,
+    required CompilationUnitElement target,
     required OperationPerformanceImpl performance,
   }) {
     var suggestionBuilders = <CompletionSuggestionBuilder>[];
-    for (var importedLibrary in target.importedLibraries) {
+    var importedLibraries = target.withEnclosing
+        .expand((fragment) => fragment.libraryImports)
+        .map((import) => import.importedLibrary)
+        .nonNulls
+        .toSet();
+    for (var importedLibrary in importedLibraries) {
       var importedSuggestions = _importedLibrarySuggestions(
         element: importedLibrary,
         performance: performance,
diff --git a/pkg/analysis_server/lib/src/cider/rename.dart b/pkg/analysis_server/lib/src/cider/rename.dart
index 4da587a..e44230e 100644
--- a/pkg/analysis_server/lib/src/cider/rename.dart
+++ b/pkg/analysis_server/lib/src/cider/rename.dart
@@ -217,7 +217,7 @@
       }
     } else if (element is LibraryImportElement) {
       var unit = (await canRename._fileResolver.resolve(path: sourcePath)).unit;
-      var index = element.library.libraryImports.indexOf(element);
+      var index = element.enclosingElement3.libraryImports.indexOf(element);
       var node = unit.directives.whereType<ImportDirective>().elementAt(index);
       var prefixNode = node.prefix;
       if (newName.isEmpty) {
diff --git a/pkg/analysis_server/lib/src/computer/computer_color.dart b/pkg/analysis_server/lib/src/computer/computer_color.dart
index 5d78069..7dacc23 100644
--- a/pkg/analysis_server/lib/src/computer/computer_color.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_color.dart
@@ -7,7 +7,7 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/constant/value.dart';
-import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/element2.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/constant/value.dart' show GenericState;
 import 'package:analyzer/src/lint/linter.dart';
@@ -58,7 +58,7 @@
     if (memberName != null) {
       colorConst = _getMember(colorConst, memberName);
     } else if (index != null) {
-      colorConst = _getSwatchValue(colorConst, index);
+      colorConst = _getSwatchColor(colorConst, index);
     }
 
     return _tryRecordColor(expression, colorConst);
@@ -73,41 +73,60 @@
     if (!expression.staticType.isColor) return false;
 
     var constructor = expression.constructorName;
-    var staticElement = constructor.staticElement;
-    var classElement = staticElement?.enclosingElement3;
+    var staticElement = constructor.element;
+    var classElement = staticElement?.enclosingElement2;
     var className = classElement?.name;
     var constructorName = constructor.name?.name;
-    var constructorArgs = expression.argumentList.arguments
-        .map((e) => e is Literal ? e : null)
-        .toList();
+    var constructorArgs = expression.argumentList.arguments.toList();
 
-    int? colorValue;
+    ColorInformation? color;
     if (_isDartUi(classElement) && className == 'Color') {
-      colorValue = _getDartUiColorValue(constructorName, constructorArgs);
+      color = _getDartUiColor(constructorName, constructorArgs);
     } else if (_isFlutterPainting(classElement) && className == 'ColorSwatch') {
-      colorValue =
-          _getFlutterSwatchColorValue(constructorName, constructorArgs);
+      color = _getFlutterSwatchColor(constructorName, constructorArgs);
     } else if (_isFlutterMaterial(classElement) &&
         className == 'MaterialAccentColor') {
-      colorValue =
-          _getFlutterMaterialAccentColorValue(constructorName, constructorArgs);
+      color = _getFlutterMaterialAccentColor(constructorName, constructorArgs);
     }
 
-    return _tryRecordColorValue(expression, colorValue);
+    return _tryRecordColorInformation(expression, color);
   }
 
-  /// Converts ARGB values into a single int value as 0xAARRGGBB as used by
-  /// the dart:ui Color class.
-  int _colorValueForComponents(int alpha, int red, int green, int blue) {
-    return (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
-  }
-
-  /// Extracts the color value from dart:ui Color constructor args.
-  int? _getDartUiColorValue(String? name, List<Literal?> args) {
+  /// Extracts the color information from dart:ui Color constructor args.
+  ColorInformation? _getDartUiColor(String? name, List<Expression> args) {
     if (name == null && args.length == 1) {
+      // Color(0xFF000000).
       var arg0 = args[0];
-      return arg0 is IntegerLiteral ? arg0.value : null;
+      return arg0 is IntegerLiteral ? getColorForInt(arg0.value) : null;
+    } else if (name == 'from') {
+      // Color.from(alpha: 1, red: 1, green: 1, blue: 1).
+      double? alpha, red, green, blue;
+      for (var arg in args.whereType<NamedExpression>()) {
+        var expression = arg.expression;
+        var value = expression is DoubleLiteral
+            ? expression.value
+            : expression is IntegerLiteral
+                ? expression.value?.toDouble()
+                : null;
+        switch (arg.name.label.name) {
+          case 'alpha':
+            alpha = value;
+          case 'red':
+            red = value;
+          case 'green':
+            green = value;
+          case 'blue':
+            blue = value;
+        }
+      }
+      return getColorForDoubles(
+        alpha: alpha,
+        red: red,
+        green: green,
+        blue: blue,
+      );
     } else if (name == 'fromARGB' && args.length == 4) {
+      // Color.fromARGB(255, 255, 255, 255).
       var arg0 = args[0];
       var arg1 = args[1];
       var arg2 = args[2];
@@ -119,9 +138,10 @@
       var blue = arg3 is IntegerLiteral ? arg3.value : null;
 
       return alpha != null && red != null && green != null && blue != null
-          ? _colorValueForComponents(alpha, red, green, blue)
+          ? ColorInformation(alpha, red, green, blue)
           : null;
     } else if (name == 'fromRGBO' && args.length == 4) {
+      // Color.fromRGBO(255, 255, 255, 1.0).
       var arg0 = args[0];
       var arg1 = args[1];
       var arg2 = args[2];
@@ -138,24 +158,26 @@
       var alpha = opacity != null ? (opacity * 255).toInt() : null;
 
       return alpha != null && red != null && green != null && blue != null
-          ? _colorValueForComponents(alpha, red, green, blue)
+          ? ColorInformation(alpha, red, green, blue)
           : null;
     } else {
       return null;
     }
   }
 
-  /// Extracts the color value from Flutter MaterialAccentColor constructor args.
-  int? _getFlutterMaterialAccentColorValue(String? name, List<Literal?> args) =>
+  /// Extracts the color from Flutter MaterialAccentColor constructor args.
+  ColorInformation? _getFlutterMaterialAccentColor(
+          String? name, List<Expression> args) =>
       // MaterialAccentColor is a subclass of SwatchColor and has the same
       // constructor.
-      _getFlutterSwatchColorValue(name, args);
+      _getFlutterSwatchColor(name, args);
 
-  /// Extracts the color value from Flutter ColorSwatch constructor args.
-  int? _getFlutterSwatchColorValue(String? name, List<Literal?> args) {
+  /// Extracts the color information from Flutter ColorSwatch constructor args.
+  ColorInformation? _getFlutterSwatchColor(
+      String? name, List<Expression> args) {
     if (name == null && args.isNotEmpty) {
       var arg0 = args[0];
-      return arg0 is IntegerLiteral ? arg0.value : null;
+      return arg0 is IntegerLiteral ? getColorForInt(arg0.value) : null;
     } else {
       return null;
     }
@@ -166,17 +188,17 @@
   /// Well-known getters like `shade500` will be mapped onto the swatch value
   /// with a matching index.
   DartObject? _getMember(DartObject target, String memberName) {
-    var colorValue = target.getFieldFromHierarchy(memberName);
-    if (colorValue != null) {
-      return colorValue;
+    var color = target.getFieldFromHierarchy(memberName);
+    if (color != null) {
+      return color;
     }
 
-    // If we didn't get a value but it's a getter we know how to read from a
+    // If we didn't get a color but it's a getter we know how to read from a
     // swatch, try that.
     if (memberName.startsWith('shade')) {
       var shadeNumber = int.tryParse(memberName.substring(5));
       if (shadeNumber != null) {
-        return _getSwatchValue(target, shadeNumber);
+        return _getSwatchColor(target, shadeNumber);
       }
     }
 
@@ -184,7 +206,7 @@
   }
 
   /// Extracts a specific shade index from a Flutter SwatchColor.
-  DartObject? _getSwatchValue(DartObject target, int swatchValue) {
+  DartObject? _getSwatchColor(DartObject target, int swatchValue) {
     var swatch = target.getFieldFromHierarchy('_swatch')?.toMapValue();
     if (swatch == null) return null;
 
@@ -197,78 +219,102 @@
   }
 
   /// Checks whether this elements library is dart:ui.
-  bool _isDartUi(Element? element) => element?.library?.name == 'dart.ui';
+  bool _isDartUi(Element2? element) => element?.library2?.name == 'dart.ui';
 
   /// Checks whether this elements library is Flutter Material colors.
-  bool _isFlutterMaterial(Element? element) =>
-      element?.library?.identifier ==
+  bool _isFlutterMaterial(Element2? element) =>
+      element?.library2?.identifier ==
       'package:flutter/src/material/colors.dart';
 
   /// Checks whether this elements library is Flutter Painting colors.
-  bool _isFlutterPainting(Element? element) =>
-      element?.library?.identifier ==
+  bool _isFlutterPainting(Element2? element) =>
+      element?.library2?.identifier ==
       'package:flutter/src/painting/colors.dart';
 
-  /// Tries to record a color value from [colorConst] for [expression].
+  /// Tries to record a color from [colorConst] for [expression].
   ///
   /// Returns whether a valid color was found and recorded.
   bool _tryRecordColor(Expression expression, DartObject? colorConst) =>
-      _tryRecordColorValue(expression, _colorValueForColorConst(colorConst));
+      _tryRecordColorInformation(expression, getColorForObject(colorConst));
 
-  /// Tries to record the [colorValue] for [expression].
+  /// Tries to record the [color] for [expression].
   ///
   /// Returns whether a valid color was found and recorded.
-  bool _tryRecordColorValue(Expression expression, int? colorValue) {
-    if (colorValue == null) return false;
-
-    // Build color information from the Color value.
-    var color = _colorInformationForColorValue(colorValue);
+  bool _tryRecordColorInformation(
+      Expression expression, ColorInformation? color) {
+    if (color == null) return false;
 
     // Record the color against the original entire expression.
     _colors.add(ColorReference(expression.offset, expression.length, color));
     return true;
   }
 
-  static ColorInformation? getColorForValue(DartObject object) {
-    if (object.type.isColor) {
-      var colorValue = _colorValueForColorConst(object);
-      if (colorValue != null) {
-        return _colorInformationForColorValue(colorValue);
-      }
-    }
-    return null;
+  /// Gets [ColorInformation] from a set of doubles that are stored internally
+  /// in a dart:ui Color object.
+  static ColorInformation? getColorForDoubles({
+    required double? alpha,
+    required double? red,
+    required double? green,
+    required double? blue,
+  }) {
+    return alpha != null && red != null && green != null && blue != null
+        ? ColorInformation(
+            (alpha * 255.0).round() & 0xff,
+            (red * 255.0).round() & 0xff,
+            (green * 255.0).round() & 0xff,
+            (blue * 255.0).round() & 0xff,
+          )
+        : null;
   }
 
-  /// Creates a [ColorInformation] by extracting the argb values from
-  /// [value] encoded as 0xAARRGGBB as in the dart:ui Color class.
-  static ColorInformation _colorInformationForColorValue(int value) {
-    // Extract color information according to dart:ui Color values.
-    var alpha = (0xff000000 & value) >> 24;
-    var red = (0x00ff0000 & value) >> 16;
-    var blue = (0x000000ff & value) >> 0;
-    var green = (0x0000ff00 & value) >> 8;
-
-    return ColorInformation(alpha, red, green, blue);
+  /// Gets [ColorInformation] from a value like `0xFFFF9000` which is used in
+  /// the default `Color()` constructor.
+  static ColorInformation? getColorForInt(int? value) {
+    return value != null
+        ? ColorInformation(
+            (value >> 24) & 0xff,
+            (value >> 16) & 0xff,
+            (value >> 8) & 0xff,
+            value & 0xff,
+          )
+        : null;
   }
 
-  /// Extracts the integer color value from the dart:ui Color constant [color].
-  static int? _colorValueForColorConst(DartObject? color) {
-    if (color == null || color.isNull) return null;
+  /// Gets [ColorInformation] from the dart:ui Color object [color].
+  static ColorInformation? getColorForObject(DartObject? color) {
+    if (color == null || color.isNull || !color.type.isColor) return null;
 
     // If the object has a "color" field, walk down to that, because some colors
     // like CupertinoColors have a "value=0" with an overridden getter that
     // would always result in a value representing black.
     color = color.getFieldFromHierarchy('color') ?? color;
 
-    return color.getFieldFromHierarchy('value')?.toIntValue();
+    var alpha = color.getFieldFromHierarchy('a')?.toDoubleValue();
+    var red = color.getFieldFromHierarchy('r')?.toDoubleValue();
+    var green = color.getFieldFromHierarchy('g')?.toDoubleValue();
+    var blue = color.getFieldFromHierarchy('b')?.toDoubleValue();
+
+    return getColorForDoubles(
+      alpha: alpha,
+      red: red,
+      green: green,
+      blue: blue,
+    );
   }
 }
 
 /// Information about a color that is present in a document.
 class ColorInformation {
+  /// Alpha as a value from 0 to 255.
   final int alpha;
+
+  /// Red as a value from 0 to 255.
   final int red;
+
+  /// Green as a value from 0 to 255.
   final int green;
+
+  /// Blue as a value from 0 to 255.
   final int blue;
 
   ColorInformation(this.alpha, this.red, this.green, this.blue);
@@ -340,8 +386,8 @@
 
   @override
   void visitPropertyAccess(PropertyAccess node) {
-    // Handle things like CupterinoColors.activeBlue.darkColor where we can't
-    // evaluate the whole expression, but can evaluate CupterinoColors.activeBlue
+    // Handle things like CupertinoColors.activeBlue.darkColor where we can't
+    // evaluate the whole expression, but can evaluate CupertinoColors.activeBlue
     // and read the darkColor.
     if (computer.tryAddColor(
       node,
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights.dart b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
index 7ba7268..6bedb81 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
@@ -198,18 +198,13 @@
       }
     }
 
-    if (_isAnnotationIdentifier(parent)) {
-      semanticModifiers ??= {};
-      semanticModifiers.add(CustomSemanticTokenModifiers.annotation);
-    }
-
     // add region
-    return _addRegion_token(
-      nameToken,
-      type,
-      semanticTokenType: semanticType,
-      semanticTokenModifiers: semanticModifiers,
-    );
+    return _addRegion_token(nameToken, type,
+        semanticTokenType: semanticType,
+        semanticTokenModifiers: semanticModifiers,
+        additionalSemanticTokenModifiers: _isAnnotationIdentifier(parent)
+            ? {CustomSemanticTokenModifiers.annotation}
+            : null);
   }
 
   bool _addIdentifierRegion_constructor(
@@ -307,7 +302,7 @@
       var staticType = parent.realTarget.staticType;
       if (staticType is RecordType) {
         type = staticType.fieldByName(nameToken.lexeme) != null
-            ? HighlightRegionType.INSTANCE_FIELD_REFERENCE
+            ? HighlightRegionType.INSTANCE_GETTER_REFERENCE
             : HighlightRegionType.UNRESOLVED_INSTANCE_MEMBER_REFERENCE;
       }
     }
@@ -316,7 +311,7 @@
       return _addRegion_token(
         nameToken,
         type,
-        semanticTokenModifiers: _isAnnotationIdentifier(parent)
+        additionalSemanticTokenModifiers: _isAnnotationIdentifier(parent)
             ? {CustomSemanticTokenModifiers.annotation}
             : null,
       );
@@ -461,7 +456,11 @@
     if (element is! TypeParameterElement) {
       return false;
     }
-    return _addRegion_token(nameToken, HighlightRegionType.TYPE_PARAMETER);
+    return _addRegion_token(
+      nameToken,
+      HighlightRegionType.TYPE_PARAMETER,
+      additionalSemanticTokenModifiers: _additionalModifiersForElement(element),
+    );
   }
 
   bool _addIdentifierRegion_unresolvedInstanceMemberReference(
@@ -496,11 +495,22 @@
     return false;
   }
 
+  /// Returns a set of additional semantic token modifiers that apply to
+  /// [element].
+  Set<SemanticTokenModifiers>? _additionalModifiersForElement(
+      Element? element) {
+    return (element?.isWildcardVariable ?? false)
+        ? {CustomSemanticTokenModifiers.wildcard}
+        : null;
+  }
+
   /// Adds a highlight region/semantic token for the given [offset]/[length].
   ///
   /// If [semanticTokenType] or [semanticTokenModifiers] are not provided, the
   /// values from the default LSP mapping for [type] (also used for plugins)
-  /// will be used instead.
+  /// will be used instead. If [additionalSemanticTokenModifiers] are provided,
+  /// they will always be added in addition to [semanticTokenModifiers]/the
+  /// defaults.
   ///
   /// If the computer has a [range] set, tokens that fall outside of that range
   /// will not be recorded.
@@ -510,6 +520,7 @@
     HighlightRegionType type, {
     SemanticTokenTypes? semanticTokenType,
     Set<SemanticTokenModifiers>? semanticTokenModifiers,
+    Set<SemanticTokenModifiers>? additionalSemanticTokenModifiers,
   }) {
     var range = this.range;
     if (range != null) {
@@ -526,6 +537,14 @@
       // Use default mappings if an overridden type/modifiers were not supplied.
       semanticTokenType ??= highlightRegionTokenTypes[type];
       semanticTokenModifiers ??= highlightRegionTokenModifiers[type];
+
+      if (additionalSemanticTokenModifiers != null &&
+          additionalSemanticTokenModifiers.isNotEmpty) {
+        semanticTokenModifiers = {
+          ...?semanticTokenModifiers,
+          ...additionalSemanticTokenModifiers
+        };
+      }
       if (semanticTokenType != null) {
         _semanticTokens.add(SemanticTokenInfo(
             offset, length, semanticTokenType, semanticTokenModifiers));
@@ -563,13 +582,19 @@
     HighlightRegionType type, {
     SemanticTokenTypes? semanticTokenType,
     Set<SemanticTokenModifiers>? semanticTokenModifiers,
+    Set<SemanticTokenModifiers>? additionalSemanticTokenModifiers,
   }) {
     if (token != null) {
       var offset = token.offset;
       var length = token.length;
-      _addRegion(offset, length, type,
-          semanticTokenType: semanticTokenType,
-          semanticTokenModifiers: semanticTokenModifiers);
+      _addRegion(
+        offset,
+        length,
+        type,
+        semanticTokenType: semanticTokenType,
+        semanticTokenModifiers: semanticTokenModifiers,
+        additionalSemanticTokenModifiers: additionalSemanticTokenModifiers,
+      );
     }
     return true;
   }
@@ -638,15 +663,6 @@
   }
 
   @override
-  void visitAugmentationImportDirective(AugmentationImportDirective node) {
-    computer._addRegion_node(node, HighlightRegionType.DIRECTIVE);
-    computer._addRegion_token(node.importKeyword, HighlightRegionType.BUILT_IN);
-    computer._addRegion_token(
-        node.augmentKeyword, HighlightRegionType.BUILT_IN);
-    super.visitAugmentationImportDirective(node);
-  }
-
-  @override
   void visitAugmentedExpression(AugmentedExpression node) {
     computer._addRegion_token(
         node.augmentedKeyword, HighlightRegionType.KEYWORD);
@@ -709,13 +725,21 @@
 
     var exceptionParameter = node.exceptionParameter;
     if (exceptionParameter != null) {
-      computer._addRegion_token(exceptionParameter.name,
-          HighlightRegionType.LOCAL_VARIABLE_DECLARATION);
+      computer._addRegion_token(
+        exceptionParameter.name,
+        HighlightRegionType.LOCAL_VARIABLE_DECLARATION,
+        additionalSemanticTokenModifiers:
+            _additionalModifiersForElement(exceptionParameter.declaredElement),
+      );
     }
     var stackTraceParameter = node.stackTraceParameter;
     if (stackTraceParameter != null) {
-      computer._addRegion_token(stackTraceParameter.name,
-          HighlightRegionType.LOCAL_VARIABLE_DECLARATION);
+      computer._addRegion_token(
+        stackTraceParameter.name,
+        HighlightRegionType.LOCAL_VARIABLE_DECLARATION,
+        additionalSemanticTokenModifiers:
+            _additionalModifiersForElement(stackTraceParameter.declaredElement),
+      );
     }
 
     super.visitCatchClause(node);
@@ -818,6 +842,8 @@
     computer._addRegion_token(
       node.name,
       HighlightRegionType.LOCAL_VARIABLE_DECLARATION,
+      additionalSemanticTokenModifiers:
+          _additionalModifiersForElement(node.declaredElement),
     );
 
     super.visitDeclaredIdentifier(node);
@@ -971,16 +997,12 @@
       HighlightRegionType.KEYWORD,
     );
 
-    var element = node.declaredElement;
-    if (element is FieldFormalParameterElement) {
-      var field = element.field;
-      if (field != null) {
-        computer._addRegion_token(
-          node.name,
-          HighlightRegionType.INSTANCE_FIELD_REFERENCE,
-        );
-      }
-    }
+    computer._addRegion_token(
+      node.name,
+      HighlightRegionType.INSTANCE_FIELD_REFERENCE,
+      additionalSemanticTokenModifiers:
+          _additionalModifiersForElement(node.declaredElement),
+    );
 
     super.visitFieldFormalParameter(node);
   }
@@ -1190,16 +1212,6 @@
   }
 
   @override
-  void visitLibraryAugmentationDirective(LibraryAugmentationDirective node) {
-    computer._addRegion_node(node, HighlightRegionType.DIRECTIVE);
-    computer._addRegion_token(
-        node.libraryKeyword, HighlightRegionType.BUILT_IN);
-    computer._addRegion_token(
-        node.augmentKeyword, HighlightRegionType.BUILT_IN);
-    super.visitLibraryAugmentationDirective(node);
-  }
-
-  @override
   void visitLibraryDirective(LibraryDirective node) {
     computer._addRegion_node(node, HighlightRegionType.DIRECTIVE);
     computer._addRegion_token(
@@ -1398,7 +1410,6 @@
     computer._addRegion_token(
       node.fieldName,
       HighlightRegionType.INSTANCE_FIELD_DECLARATION,
-      semanticTokenModifiers: {SemanticTokenModifiers.declaration},
     );
 
     super.visitRepresentationDeclaration(node);
@@ -1443,11 +1454,14 @@
     computer._addRegion_token(
         node.requiredKeyword, HighlightRegionType.KEYWORD);
 
+    var declaredElement = node.declaredElement!;
     computer._addRegion_token(
       node.name,
-      node.declaredElement!.type is DynamicType
+      declaredElement.type is DynamicType
           ? HighlightRegionType.DYNAMIC_PARAMETER_DECLARATION
           : HighlightRegionType.PARAMETER_DECLARATION,
+      additionalSemanticTokenModifiers:
+          _additionalModifiersForElement(declaredElement),
     );
 
     super.visitSimpleFormalParameter(node);
@@ -1501,12 +1515,12 @@
 
     computer._addRegion_token(
       node.name,
-      HighlightRegionType.PARAMETER_DECLARATION,
+      node.declaredElement!.type is DynamicType
+          ? HighlightRegionType.DYNAMIC_PARAMETER_DECLARATION
+          : HighlightRegionType.PARAMETER_DECLARATION,
     );
 
-    node.type?.accept(this);
-    node.typeParameters?.accept(this);
-    node.parameters?.accept(this);
+    super.visitSuperFormalParameter(node);
   }
 
   @override
@@ -1577,7 +1591,12 @@
 
   @override
   void visitTypeParameter(TypeParameter node) {
-    computer._addRegion_token(node.name, HighlightRegionType.TYPE_PARAMETER);
+    computer._addRegion_token(
+      node.name,
+      HighlightRegionType.TYPE_PARAMETER,
+      additionalSemanticTokenModifiers:
+          _additionalModifiersForElement(node.declaredElement),
+    );
     super.visitTypeParameter(node);
   }
 
@@ -1597,6 +1616,8 @@
         element.type is DynamicType
             ? HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_DECLARATION
             : HighlightRegionType.LOCAL_VARIABLE_DECLARATION,
+        additionalSemanticTokenModifiers:
+            _additionalModifiersForElement(element),
       );
     } else if (element is TopLevelVariableElement) {
       computer._addRegion_token(
@@ -1632,6 +1653,16 @@
   @override
   void visitWildcardPattern(WildcardPattern node) {
     computer._addRegion_token(node.keyword, HighlightRegionType.KEYWORD);
+
+    // For consistency, wildcard patterns are treated like wildcard variable
+    // declarations.
+    // https://github.com/dart-lang/sdk/issues/56567
+    computer._addRegion_token(
+      node.name,
+      HighlightRegionType.LOCAL_VARIABLE_DECLARATION,
+      additionalSemanticTokenModifiers: {CustomSemanticTokenModifiers.wildcard},
+    );
+
     super.visitWildcardPattern(node);
   }
 
@@ -1652,6 +1683,13 @@
     super.visitYieldStatement(node);
   }
 
+  /// Returns a set of additional semantic token modifiers that apply to
+  /// [element].
+  Set<SemanticTokenModifiers>? _additionalModifiersForElement(
+      Element? element) {
+    return computer._additionalModifiersForElement(element);
+  }
+
   void _addRegions_configurations(List<Configuration> configurations) {
     for (var configuration in configurations) {
       computer._addRegion_token(
diff --git a/pkg/analysis_server/lib/src/computer/import_elements_computer.dart b/pkg/analysis_server/lib/src/computer/import_elements_computer.dart
index f6f71c7..378e255 100644
--- a/pkg/analysis_server/lib/src/computer/import_elements_computer.dart
+++ b/pkg/analysis_server/lib/src/computer/import_elements_computer.dart
@@ -325,7 +325,7 @@
   }
 
   bool _hasElement(String prefix, String name) {
-    var scope = libraryResult.libraryElement.scope;
+    var scope = libraryResult.libraryElement.definingCompilationUnit.scope;
 
     if (prefix.isNotEmpty) {
       var prefixElement = scope.lookup(prefix).getter;
diff --git a/pkg/analysis_server/lib/src/g3/utilities.dart b/pkg/analysis_server/lib/src/g3/utilities.dart
index 809db1f..eff68a6 100644
--- a/pkg/analysis_server/lib/src/g3/utilities.dart
+++ b/pkg/analysis_server/lib/src/g3/utilities.dart
@@ -16,12 +16,14 @@
 import 'package:analyzer/src/generated/parser.dart' as p;
 import 'package:analyzer/src/string_source.dart';
 import 'package:dart_style/dart_style.dart';
+import 'package:pub_semver/pub_semver.dart';
 
 /// Return a formatted string if successful, throws a [FormatterException] if
-/// unable to format. Takes a string as input.
-String format(String content) {
+/// unable to format. Takes a string as input and an optional [languageVersion].
+String format(String content, {Version? languageVersion}) {
   var code = SourceCode(content);
-  var formatter = DartFormatter();
+  var formatter = DartFormatter(
+      languageVersion: languageVersion ?? DartFormatter.latestLanguageVersion);
   SourceCode formattedResult;
   formattedResult = formatter.formatSource(code);
   return formattedResult.text;
diff --git a/pkg/analysis_server/lib/src/handler/legacy/edit_format.dart b/pkg/analysis_server/lib/src/handler/legacy/edit_format.dart
index da48426..4a5ceaf 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/edit_format.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/edit_format.dart
@@ -48,7 +48,12 @@
       selectionStart: start,
       selectionLength: length,
     );
-    var formatter = DartFormatter(pageWidth: params.lineLength);
+
+    var driver = server.getAnalysisDriver(file);
+    var library = await driver?.getResolvedLibrary(file);
+    var formatter = DartFormatter(
+        pageWidth: params.lineLength,
+        languageVersion: library.effectiveLanguageVersion);
     SourceCode formattedResult;
     try {
       formattedResult = formatter.formatSource(code);
diff --git a/pkg/analysis_server/lib/src/handler/legacy/edit_format_if_enabled.dart b/pkg/analysis_server/lib/src/handler/legacy/edit_format_if_enabled.dart
index 3a208d9..3a3c9ee 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/edit_format_if_enabled.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/edit_format_if_enabled.dart
@@ -13,6 +13,7 @@
 import 'package:dart_style/src/dart_formatter.dart';
 import 'package:dart_style/src/exceptions.dart';
 import 'package:dart_style/src/source_code.dart';
+import 'package:pub_semver/pub_semver.dart';
 
 /// The handler for the `edit.formatIfEnabled` request.
 class EditFormatIfEnabledHandler extends LegacyHandler {
@@ -21,17 +22,20 @@
   EditFormatIfEnabledHandler(
       super.server, super.request, super.cancellationToken, super.performance);
 
-  /// Format the given [file].
+  /// Format the given [file] with the given [languageVersion].
   ///
   /// Throws a [FileSystemException] if the file doesn't exist or can't be read.
   /// Throws a [FormatterException] if the code could not be formatted.
-  List<SourceEdit> formatFile(File file) {
+  List<SourceEdit> formatFile(File file, {Version? languageVersion}) {
     // TODO(brianwilkerson): Move this to a superclass when `edit.format` is
     //  implemented by a handler class so the code can be shared.
     var originalContent = file.readAsStringSync();
     var code = SourceCode(originalContent);
 
-    var formatter = DartFormatter();
+    var formatter = DartFormatter(
+        languageVersion:
+            languageVersion ?? DartFormatter.latestLanguageVersion);
+
     var formatResult = formatter.formatSource(code);
     var formattedContent = formatResult.text;
 
@@ -56,7 +60,7 @@
     );
     var sourceFileEdits = <SourceFileEdit>[];
     for (var context in collection.contexts) {
-      _formatInContext(context, sourceFileEdits);
+      await _formatInContext(context, sourceFileEdits);
     }
     sendResult(EditFormatIfEnabledResult(sourceFileEdits));
   }
@@ -64,8 +68,8 @@
   /// Format all of the Dart files in the given [context] whose associated
   /// `codeStyleOptions` enable formatting, adding the edits to the list of
   /// [sourceFileEdits].
-  void _formatInContext(DriverBasedAnalysisContext context,
-      List<SourceFileEdit> sourceFileEdits) {
+  Future<void> _formatInContext(DriverBasedAnalysisContext context,
+      List<SourceFileEdit> sourceFileEdits) async {
     var pathContext = context.resourceProvider.pathContext;
     for (var filePath in context.contextRoot.analyzedFiles()) {
       // Skip anything but .dart files.
@@ -80,7 +84,10 @@
       var options = context.getAnalysisOptionsForFile(resource);
       if (options.codeStyleOptions.useFormatter) {
         try {
-          var sourceEdits = formatFile(resource);
+          var library = await context.driver.getResolvedLibrary(filePath);
+          var languageVersion = library.effectiveLanguageVersion;
+          var sourceEdits =
+              formatFile(resource, languageVersion: languageVersion);
           if (sourceEdits.isNotEmpty) {
             sourceFileEdits
                 .add(SourceFileEdit(filePath, 0, edits: sourceEdits));
diff --git a/pkg/analysis_server/lib/src/handler/legacy/edit_get_fixes.dart b/pkg/analysis_server/lib/src/handler/legacy/edit_get_fixes.dart
index 4fe02d5..e3c45d9 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/edit_get_fixes.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/edit_get_fixes.dart
@@ -146,9 +146,8 @@
           content: content,
           uri: optionsFile.toUri(),
           lineInfo: lineInfo,
-          isAugmentation: false,
           isLibrary: true,
-          isMacroAugmentation: false,
+          isMacroPart: false,
           isPart: false,
           errors: errors,
           analysisOptions: analysisOptions,
@@ -274,9 +273,8 @@
           content: content,
           uri: pubspecFile.toUri(),
           lineInfo: lineInfo,
-          isAugmentation: false,
           isLibrary: true,
-          isMacroAugmentation: false,
+          isMacroPart: false,
           isPart: false,
           errors: errors,
           analysisOptions: analysisOptions,
diff --git a/pkg/analysis_server/lib/src/handler/legacy/edit_import_elements.dart b/pkg/analysis_server/lib/src/handler/legacy/edit_import_elements.dart
index f87f15f..996b514 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/edit_import_elements.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/edit_import_elements.dart
@@ -34,8 +34,8 @@
       sendResponse(Response.importElementsInvalidFile(request));
       return;
     }
-    var libraryUnit = result.libraryElement.definingCompilationUnit;
-    if (libraryUnit != result.unit.declaredElement) {
+    var libraryUnit = result.libraryElement2.firstFragment;
+    if (libraryUnit != result.libraryFragment) {
       // The file in the request is a part of a library. We need to pass the
       // defining compilation unit to the computer, not the part.
       result = await server.getResolvedUnit(libraryUnit.source.fullName);
diff --git a/pkg/analysis_server/lib/src/handler/legacy/legacy_handler.dart b/pkg/analysis_server/lib/src/handler/legacy/legacy_handler.dart
index 3a92f28..6d006e9 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/legacy_handler.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/legacy_handler.dart
@@ -9,10 +9,13 @@
 import 'package:analysis_server/protocol/protocol_generated.dart';
 import 'package:analysis_server/src/legacy_analysis_server.dart';
 import 'package:analysis_server/src/protocol/protocol_internal.dart';
+import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/src/dart/error/syntactic_errors.g.dart';
 import 'package:analyzer/src/util/performance/operation_performance.dart';
 import 'package:analyzer/src/utilities/cancellation.dart';
+import 'package:dart_style/dart_style.dart';
+import 'package:pub_semver/pub_semver.dart';
 
 /// A request handler for the completion domain.
 abstract class CompletionHandler extends LegacyHandler {
@@ -96,3 +99,13 @@
         params.toNotification(clientUriConverter: server.uriConverter));
   }
 }
+
+extension SomeResolvedLibraryResultExtension on SomeResolvedLibraryResult? {
+  Version get effectiveLanguageVersion {
+    var self = this;
+    if (self is ResolvedLibraryResult) {
+      return self.element.languageVersion.effective;
+    }
+    return DartFormatter.latestLanguageVersion;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/handler/legacy/lsp_over_legacy_handler.dart b/pkg/analysis_server/lib/src/handler/legacy/lsp_over_legacy_handler.dart
index 34f41fe..f5f1c8b 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/lsp_over_legacy_handler.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/lsp_over_legacy_handler.dart
@@ -9,7 +9,6 @@
 import 'package:analysis_server/src/handler/legacy/legacy_handler.dart';
 import 'package:analysis_server/src/lsp/constants.dart';
 import 'package:analysis_server/src/lsp/error_or.dart';
-import 'package:analysis_server/src/lsp/handlers/handler_states.dart';
 import 'package:analysis_server/src/lsp/handlers/handlers.dart' as lsp;
 import 'package:analyzer/dart/analysis/session.dart';
 import 'package:language_server_protocol/json_parsing.dart';
@@ -43,20 +42,10 @@
           })
         : null;
 
-    // Get the handler for LSP requests from the server.
-    // The value is a `FutureOr<>` because for the real LSP server it can be
-    // delayed (the client influences when we're in the initialized state) but
-    // since it's never a `Future` for the legacy server and we want to maintain
-    // request order here, skip the `await`.
-    var initializedLspHandler = server.lspInitialized;
-    var handler = initializedLspHandler is InitializedStateMessageHandler
-        ? initializedLspHandler
-        : await server.lspInitialized;
-
     if (lspMessage != null) {
       server.analyticsManager.startedRequestMessage(
           request: lspMessage, startTime: DateTime.now());
-      await handleRequest(handler, lspMessage);
+      await handleRequest(lspMessage);
     } else {
       var message = "The 'lspMessage' parameter was not a valid LSP request:\n"
           "${reporter.errors.join('\n')}";
@@ -65,18 +54,18 @@
     }
   }
 
-  Future<void> handleRequest(
-    InitializedStateMessageHandler handler,
-    RequestMessage message,
-  ) async {
+  Future<void> handleRequest(RequestMessage message) async {
     var messageInfo = lsp.MessageInfo(
       performance: performance,
+      clientCapabilities: server.editorClientCapabilities,
       timeSinceRequest: request.timeSinceRequest,
     );
 
     ErrorOr<Object?> result;
     try {
-      result = await handler.handleMessage(message, messageInfo,
+      // Since this (legacy) request was already scheduled, we immediately
+      // execute the wrapped LSP request without additional scheduling.
+      result = await server.immediatelyHandleLspMessage(message, messageInfo,
           cancellationToken: cancellationToken);
     } on InconsistentAnalysisException {
       result = error(
diff --git a/pkg/analysis_server/lib/src/legacy_analysis_server.dart b/pkg/analysis_server/lib/src/legacy_analysis_server.dart
index 8a14aa5..1b7daf5 100644
--- a/pkg/analysis_server/lib/src/legacy_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/legacy_analysis_server.dart
@@ -86,6 +86,7 @@
 import 'package:analysis_server/src/server/diagnostic_server.dart';
 import 'package:analysis_server/src/server/error_notifier.dart';
 import 'package:analysis_server/src/server/features.dart';
+import 'package:analysis_server/src/server/message_scheduler.dart';
 import 'package:analysis_server/src/server/performance.dart';
 import 'package:analysis_server/src/server/sdk_configuration.dart';
 import 'package:analysis_server/src/services/completion/completion_state.dart';
@@ -290,22 +291,7 @@
       ServerSetClientCapabilitiesParams([]);
 
   @override
-  final lspClientCapabilities = lsp.LspClientCapabilities(
-    lsp.ClientCapabilities(
-      textDocument: lsp.TextDocumentClientCapabilities(
-        hover: lsp.HoverClientCapabilities(
-          contentFormat: [
-            lsp.MarkupKind.Markdown,
-          ],
-        ),
-      ),
-      workspace: lsp.WorkspaceClientCapabilities(
-        workspaceEdit: lsp.WorkspaceEditClientCapabilities(
-          documentChanges: true,
-        ),
-      ),
-    ),
-  );
+  final editorClientCapabilities = lsp.fixedBasicLspClientCapabilities;
 
   @override
   final lsp.LspClientConfiguration lspClientConfiguration;
@@ -621,7 +607,8 @@
   /// Handle a [request] that was read from the communication channel.
   void handleRequestOrResponse(RequestOrResponse requestOrResponse) {
     if (requestOrResponse is Request) {
-      handleRequest(requestOrResponse);
+      messageScheduler.add(LegacyMessage(request: requestOrResponse));
+      messageScheduler.notify();
     } else if (requestOrResponse is Response) {
       handleResponse(requestOrResponse);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/client_capabilities.dart b/pkg/analysis_server/lib/src/lsp/client_capabilities.dart
index 0099175..f86a8b5 100644
--- a/pkg/analysis_server/lib/src/lsp/client_capabilities.dart
+++ b/pkg/analysis_server/lib/src/lsp/client_capabilities.dart
@@ -24,6 +24,29 @@
     // TODO(dantup): Remove this after the next beta branch.
     'supportsDartTextDocumentContentProviderEXP1';
 
+/// A fixed set of ClientCapabilities used for clients that may execute LSP
+/// requests without performing standard LSP initialization (such as a DTD
+/// client or LSP-over-Legacy).
+///
+/// These capabilities may affect the behaviour and format of responses so
+/// should be as stable as possible to avoid affecting existing callers.
+final fixedBasicLspClientCapabilities = LspClientCapabilities(
+  ClientCapabilities(
+    textDocument: TextDocumentClientCapabilities(
+      hover: HoverClientCapabilities(
+        contentFormat: [
+          MarkupKind.Markdown,
+        ],
+      ),
+    ),
+    workspace: WorkspaceClientCapabilities(
+      workspaceEdit: WorkspaceEditClientCapabilities(
+        documentChanges: true,
+      ),
+    ),
+  ),
+);
+
 /// Wraps the client (editor) capabilities to improve performance.
 ///
 /// Sets transferred as arrays in JSON will be converted to Sets for faster
diff --git a/pkg/analysis_server/lib/src/lsp/constants.dart b/pkg/analysis_server/lib/src/lsp/constants.dart
index 0b49cd7..399e8a4 100644
--- a/pkg/analysis_server/lib/src/lsp/constants.dart
+++ b/pkg/analysis_server/lib/src/lsp/constants.dart
@@ -181,6 +181,9 @@
   /// to class names that are not constructors.
   static const constructor = SemanticTokenModifiers('constructor');
 
+  /// A modifier applied to wildcards.
+  static const wildcard = SemanticTokenModifiers('wildcard');
+
   /// A modifier applied to escape characters within a string to allow coloring
   /// them differently.
   static const escape = SemanticTokenModifiers('escape');
@@ -221,6 +224,7 @@
     escape,
     interpolation,
     void_,
+    wildcard,
   ];
 }
 
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/abstract_code_actions_producer.dart b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/abstract_code_actions_producer.dart
index f73ecc1..be3405f 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/abstract_code_actions_producer.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/abstract_code_actions_producer.dart
@@ -77,7 +77,7 @@
       kind: toCodeActionKind(change.id, CodeActionKind.Refactor),
       diagnostics: const [],
       command: createLogActionCommand(change.id),
-      edit: createWorkspaceEdit(server, change,
+      edit: createWorkspaceEdit(server, capabilities, change,
           allowSnippets: true, filePath: path, lineInfo: lineInfo),
     );
   }
@@ -107,7 +107,7 @@
       kind: toCodeActionKind(change.id, CodeActionKind.QuickFix),
       diagnostics: [diagnostic],
       command: createLogActionCommand(change.id),
-      edit: createWorkspaceEdit(server, change,
+      edit: createWorkspaceEdit(server, capabilities, change,
           allowSnippets: true, filePath: path, lineInfo: lineInfo),
     );
   }
@@ -140,9 +140,8 @@
       content: file.readAsStringSync(),
       uri: server.uriConverter.toClientUri(path),
       lineInfo: lineInfo,
-      isAugmentation: false,
       isLibrary: true,
-      isMacroAugmentation: false,
+      isMacroPart: false,
       isPart: false,
       errors: errors,
       analysisOptions: analysisOptions,
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/dart.dart b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/dart.dart
index 4acd641..41b8ed7 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/dart.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/dart.dart
@@ -220,6 +220,7 @@
         startSessions: await server.currentSessions,
         resolvedLibraryResult: library,
         resolvedUnitResult: unit,
+        clientCapabilities: capabilities,
         selectionOffset: offset,
         selectionLength: length,
         includeExperimental:
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/code_lens/abstract_code_lens_provider.dart b/pkg/analysis_server/lib/src/lsp/handlers/code_lens/abstract_code_lens_provider.dart
index d862154..467690a 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/code_lens/abstract_code_lens_provider.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/code_lens/abstract_code_lens_provider.dart
@@ -5,6 +5,7 @@
 import 'package:analysis_server/lsp_protocol/protocol.dart'
     hide Declaration, Element;
 import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/lsp/client_capabilities.dart';
 import 'package:analysis_server/src/lsp/constants.dart';
 import 'package:analysis_server/src/lsp/error_or.dart';
 import 'package:analysis_server/src/lsp/handlers/handlers.dart';
@@ -16,7 +17,8 @@
 ///
 /// The LSP CodeLens handler will call all registered CodeLens providers and
 /// merge the results before responding to the client.
-abstract class AbstractCodeLensProvider with HandlerHelperMixin {
+abstract class AbstractCodeLensProvider
+    with HandlerHelperMixin, Handler<List<CodeLens>> {
   @override
   final AnalysisServer server;
 
@@ -24,10 +26,8 @@
 
   /// Whether the client supports the `dart.goToLocation` command, as produced
   /// by [getNavigationCommand].
-  bool get clientSupportsGoToLocationCommand =>
-      server.lspClientCapabilities?.supportedCommands
-          .contains(ClientCommands.goToLocation) ??
-      false;
+  bool clientSupportsGoToLocationCommand(LspClientCapabilities capabilities) =>
+      capabilities.supportedCommands.contains(ClientCommands.goToLocation);
 
   /// Attempt to compute a [Location] to the declaration of [element].
   ///
@@ -62,11 +62,12 @@
   ///
   /// If for any reason the location cannot be computed, returns `null`.
   Command? getNavigationCommand(
+    LspClientCapabilities clientCapabilities,
     String title,
     Element element,
     Map<String, LineInfo?> lineInfoCache,
   ) {
-    assert(clientSupportsGoToLocationCommand);
+    assert(clientSupportsGoToLocationCommand(clientCapabilities));
 
     var location = getLocation(element, lineInfoCache);
     if (location == null) {
@@ -87,5 +88,8 @@
     Map<String, LineInfo?> lineInfoCache,
   );
 
-  bool isAvailable(CodeLensParams params);
+  bool isAvailable(
+    LspClientCapabilities clientCapabilities,
+    CodeLensParams params,
+  );
 }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/code_lens/augmentations.dart b/pkg/analysis_server/lib/src/lsp/handlers/code_lens/augmentations.dart
index 55f0108..a29a256 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/code_lens/augmentations.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/code_lens/augmentations.dart
@@ -4,6 +4,7 @@
 
 import 'package:analysis_server/lsp_protocol/protocol.dart'
     hide Declaration, Element;
+import 'package:analysis_server/src/lsp/client_capabilities.dart';
 import 'package:analysis_server/src/lsp/client_configuration.dart';
 import 'package:analysis_server/src/lsp/error_or.dart';
 import 'package:analysis_server/src/lsp/handlers/code_lens/abstract_code_lens_provider.dart';
@@ -29,6 +30,11 @@
     CancellationToken token,
     Map<String, LineInfo?> lineInfoCache,
   ) async {
+    var clientCapabilities = message.clientCapabilities;
+    if (clientCapabilities == null) {
+      return serverNotInitializedError;
+    }
+
     var performance = message.performance;
     var path = pathOfDoc(params.textDocument);
     var unit = await performance.runAsync(
@@ -38,21 +44,23 @@
     return await unit.mapResult((result) {
       return performance.runAsync(
         '_getCodeLenses',
-        (performance) =>
-            _getCodeLenses(result, token, performance, lineInfoCache),
+        (performance) => _getCodeLenses(
+            clientCapabilities, result, token, performance, lineInfoCache),
       );
     });
   }
 
   @override
-  bool isAvailable(CodeLensParams params) {
+  bool isAvailable(
+      LspClientCapabilities clientCapabilities, CodeLensParams params) {
     return isDartDocument(params.textDocument) &&
         // We need to run if either of these are enabled.
         (codeLens.augmentation || codeLens.augmented) &&
-        clientSupportsGoToLocationCommand;
+        clientSupportsGoToLocationCommand(clientCapabilities);
   }
 
   Future<ErrorOr<List<CodeLens>>> _getCodeLenses(
+    LspClientCapabilities clientCapabilities,
     ResolvedUnitResult result,
     CancellationToken token,
     OperationPerformanceImpl performance,
@@ -63,7 +71,8 @@
 
     /// Helper to add a CodeLens at [declaration] to [target] for [title].
     void addCodeLens(String title, Element declaration, Element target) {
-      var command = getNavigationCommand(title, target, lineInfoCache);
+      var command = getNavigationCommand(
+          clientCapabilities, title, target, lineInfoCache);
       if (command != null && declaration.nameOffset != -1) {
         var range = toRange(
           lineInfo,
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/abstract_refactor.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/abstract_refactor.dart
index ac84905..6cf2fea 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/abstract_refactor.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/abstract_refactor.dart
@@ -5,6 +5,7 @@
 import 'dart:async';
 
 import 'package:analysis_server/lsp_protocol/protocol.dart';
+import 'package:analysis_server/src/lsp/client_capabilities.dart';
 import 'package:analysis_server/src/lsp/constants.dart';
 import 'package:analysis_server/src/lsp/error_or.dart';
 import 'package:analysis_server/src/lsp/handlers/commands/simple_edit_handler.dart';
@@ -35,6 +36,7 @@
       int offset,
       int length,
       Map<String, Object?>? options,
+      LspClientCapabilities clientCapabilities,
       CancellationToken cancellationToken,
       ProgressReporter reporter,
       int? docVersion);
@@ -146,6 +148,11 @@
     ProgressReporter progress,
     CancellationToken cancellationToken,
   ) async {
+    var clientCapabilities = message.clientCapabilities;
+    if (clientCapabilities == null) {
+      return serverNotInitializedError;
+    }
+
     if (parameters['kind'] is! String ||
         parameters['path'] is! String ||
         (parameters['docVersion'] is! int?) ||
@@ -171,8 +178,17 @@
     var length = parameters['length'] as int;
     var options = parameters['options'] as Map<String, Object?>?;
 
-    return execute(path, kind, offset, length, options, cancellationToken,
-        progress, docVersion);
+    return execute(
+      path,
+      kind,
+      offset,
+      length,
+      options,
+      clientCapabilities,
+      cancellationToken,
+      progress,
+      docVersion,
+    );
   }
 
   /// Parses "legacy" arguments passed a list, rather than in a map as a single
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/fix_all.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/fix_all.dart
index 6fc273b..1f799d7 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/fix_all.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/fix_all.dart
@@ -144,7 +144,8 @@
     // LineInfos to reflect the original state while mapping to LSP.
     await revertOverlays();
 
-    var edit = createPlainWorkspaceEdit(server, changes);
+    var edit = createPlainWorkspaceEdit(
+        server, server.editorClientCapabilities!, changes);
 
     return success(edit);
   }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/fix_all_in_workspace.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/fix_all_in_workspace.dart
index dc19e9b..f03d40b 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/fix_all_in_workspace.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/fix_all_in_workspace.dart
@@ -30,14 +30,21 @@
     ProgressReporter progress,
     CancellationToken cancellationToken,
   ) async {
-    if (!(server.lspClientCapabilities?.applyEdit ?? false)) {
+    // Use the editor capabilities, since we're building edits to send to the
+    // editor regardless of who called us.
+    var clientCapabilities = server.editorClientCapabilities;
+    if (clientCapabilities == null) {
+      return serverNotInitializedError;
+    }
+
+    if (!clientCapabilities.applyEdit) {
       return error(
         ServerErrorCodes.FeatureDisabled,
         '"$commandName" is only available for clients that support workspace/applyEdit',
       );
     }
 
-    if (!(server.lspClientCapabilities?.changeAnnotations ?? false)) {
+    if (!clientCapabilities.changeAnnotations) {
       return error(
         ServerErrorCodes.FeatureDisabled,
         '"$commandName" is only available for clients that support change annotations',
@@ -64,6 +71,7 @@
 
     var edit = createWorkspaceEdit(
       server,
+      clientCapabilities,
       change,
       annotateChanges: requireConfirmation
           ? ChangeAnnotations.requireConfirmation
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
index fe90dfe..14b3b1c 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
@@ -5,6 +5,7 @@
 import 'dart:async';
 
 import 'package:analysis_server/lsp_protocol/protocol.dart';
+import 'package:analysis_server/src/lsp/client_capabilities.dart';
 import 'package:analysis_server/src/lsp/error_or.dart';
 import 'package:analysis_server/src/lsp/handlers/commands/abstract_refactor.dart';
 import 'package:analysis_server/src/lsp/handlers/handlers.dart';
@@ -35,6 +36,7 @@
     int offset,
     int length,
     Map<String, Object?>? options,
+    LspClientCapabilities clientCapabilities,
     CancellationToken cancellationToken,
     ProgressReporter reporter,
     int? docVersion,
@@ -93,7 +95,7 @@
             return fileModifiedError;
           }
 
-          var edit = createWorkspaceEdit(server, change);
+          var edit = createWorkspaceEdit(server, clientCapabilities, change);
           return await sendWorkspaceEditToClient(edit);
         } finally {
           manager.end(cancelableToken);
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/refactor_command_handler.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/refactor_command_handler.dart
index 088bf32..702a24f 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/refactor_command_handler.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/refactor_command_handler.dart
@@ -49,7 +49,9 @@
               'arguments: List'));
     }
 
-    var clientCapabilities = server.lspClientCapabilities;
+    // Use the editor capabilities, since we're building edits to send to the
+    // editor regardless of who called us.
+    var clientCapabilities = server.editorClientCapabilities;
     if (clientCapabilities == null) {
       // This should not happen unless a client misbehaves.
       return serverNotInitializedError;
@@ -67,6 +69,7 @@
         startSessions: await server.currentSessions,
         resolvedLibraryResult: library,
         resolvedUnitResult: unit,
+        clientCapabilities: clientCapabilities,
         selectionOffset: offset,
         selectionLength: length,
         includeExperimental:
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart
index 88e803d..44c6e9c 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart
@@ -27,18 +27,20 @@
   }
 
   Future<ErrorOr<void>> sendSourceEditsToClient(
-      OptionalVersionedTextDocumentIdentifier docIdentifier,
-      CompilationUnit unit,
-      List<SourceEdit> edits) async {
+    OptionalVersionedTextDocumentIdentifier docIdentifier,
+    CompilationUnit unit,
+    List<SourceEdit> edits,
+  ) async {
     // If there are no edits to apply, just complete the command without going
     // back to the client.
     if (edits.isEmpty) {
       return success(null);
     }
 
-    var clientCapabilities = server.lspClientCapabilities;
+    // Use the editor capabilities, since we're building edits to send to the
+    // editor regardless of who called us.
+    var clientCapabilities = server.editorClientCapabilities;
     if (clientCapabilities == null) {
-      // This should not happen unless a client misbehaves.
       return serverNotInitializedError;
     }
 
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/validate_refactor.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/validate_refactor.dart
index 3369fa9..49638dc 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/validate_refactor.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/validate_refactor.dart
@@ -5,6 +5,7 @@
 import 'dart:async';
 
 import 'package:analysis_server/lsp_protocol/protocol.dart';
+import 'package:analysis_server/src/lsp/client_capabilities.dart';
 import 'package:analysis_server/src/lsp/error_or.dart';
 import 'package:analysis_server/src/lsp/handlers/commands/abstract_refactor.dart';
 import 'package:analysis_server/src/lsp/handlers/handlers.dart';
@@ -28,6 +29,7 @@
     int offset,
     int length,
     Map<String, Object?>? options,
+    LspClientCapabilities clientCapabilities,
     CancellationToken cancellationToken,
     ProgressReporter reporter,
     int? docVersion,
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_call_hierarchy.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_call_hierarchy.dart
index d644a5c..bb4d5ae 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_call_hierarchy.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_call_hierarchy.dart
@@ -8,6 +8,7 @@
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/computer/computer_call_hierarchy.dart'
     as call_hierarchy;
+import 'package:analysis_server/src/lsp/client_capabilities.dart';
 import 'package:analysis_server/src/lsp/error_or.dart';
 import 'package:analysis_server/src/lsp/handlers/handlers.dart';
 import 'package:analysis_server/src/lsp/mapping.dart';
@@ -70,10 +71,16 @@
   /// in the superclass.
   @override
   Future<ErrorOr<CallHierarchyIncomingCallsResult>> handle(
-          CallHierarchyIncomingCallsParams params,
-          MessageInfo message,
-          CancellationToken token) =>
-      handleCalls(params.item);
+      CallHierarchyIncomingCallsParams params,
+      MessageInfo message,
+      CancellationToken token) async {
+    var clientCapabilities = message.clientCapabilities;
+    if (clientCapabilities == null) {
+      return failure(serverNotInitializedError);
+    }
+
+    return handleCalls(clientCapabilities, params.item);
+  }
 
   /// Converts a server [call_hierarchy.CallHierarchyCalls] into the correct LSP
   /// type for incoming calls.
@@ -132,10 +139,16 @@
   /// in the superclass.
   @override
   Future<ErrorOr<CallHierarchyOutgoingCallsResult>> handle(
-          CallHierarchyOutgoingCallsParams params,
-          MessageInfo message,
-          CancellationToken token) =>
-      handleCalls(params.item);
+      CallHierarchyOutgoingCallsParams params,
+      MessageInfo message,
+      CancellationToken token) async {
+    var clientCapabilities = message.clientCapabilities;
+    if (clientCapabilities == null) {
+      return failure(serverNotInitializedError);
+    }
+
+    return handleCalls(clientCapabilities, params.item);
+  }
 
   /// Converts a server [call_hierarchy.CallHierarchyCalls] into the correct LSP
   /// type for outgoing calls.
@@ -195,7 +208,7 @@
       return success(const []);
     }
 
-    var clientCapabilities = server.lspClientCapabilities;
+    var clientCapabilities = message.clientCapabilities;
     if (clientCapabilities == null) {
       // This should not happen unless a client misbehaves.
       return serverNotInitializedError;
@@ -264,17 +277,12 @@
   /// Handles a request for incoming or outgoing calls (handled by the concrete
   /// implementation) by delegating fetching and converting calls to the
   /// subclass.
-  Future<ErrorOr<List<C>?>> handleCalls(CallHierarchyItem item) async {
+  Future<ErrorOr<List<C>?>> handleCalls(
+      LspClientCapabilities clientCapabilities, CallHierarchyItem item) async {
     if (!isDartUri(item.uri)) {
       return success(const []);
     }
 
-    var clientCapabilities = server.lspClientCapabilities;
-    if (clientCapabilities == null) {
-      // This should not happen unless a client misbehaves.
-      return failure(serverNotInitializedError);
-    }
-
     var path = pathOfUri(item.uri);
     var unit = await path.mapResult(requireResolvedUnit);
     return unit.mapResult((unit) async {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index 88bd0f4..e214cbc 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -47,7 +47,7 @@
         return success(const []);
       }
 
-      var capabilities = server.lspClientCapabilities;
+      var capabilities = message.clientCapabilities;
       if (capabilities == null) {
         // This should not happen unless a client misbehaves.
         return serverNotInitializedError;
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_lens.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_lens.dart
index ebb5f7d..9bba424 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_lens.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_lens.dart
@@ -34,11 +34,18 @@
     MessageInfo message,
     CancellationToken token,
   ) async {
+    var clientCapabilities = message.clientCapabilities;
+    if (clientCapabilities == null) {
+      return serverNotInitializedError;
+    }
+
     // Ask all providers to compute their CodeLenses.
     var lineInfoCache = <String, LineInfo?>{};
     var providerResults = await Future.wait(
-      codeLensProviders.where((provider) => provider.isAvailable(params)).map(
-          (provider) => provider.handle(params, message, token, lineInfoCache)),
+      codeLensProviders
+          .where((provider) => provider.isAvailable(clientCapabilities, params))
+          .map((provider) =>
+              provider.handle(params, message, token, lineInfoCache)),
     );
 
     // Merge the results, but if any errors, propogate the first error.
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index e894785..1afff6b 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -85,7 +85,7 @@
   @override
   Future<ErrorOr<CompletionList>> handle(CompletionParams params,
       MessageInfo message, CancellationToken token) async {
-    var clientCapabilities = server.lspClientCapabilities;
+    var clientCapabilities = message.clientCapabilities;
     if (clientCapabilities == null) {
       // This should not happen unless a client misbehaves.
       return serverNotInitializedError;
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
index d7404b9..0b6904e 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
@@ -4,6 +4,7 @@
 
 import 'package:analysis_server/lsp_protocol/protocol.dart' hide Element;
 import 'package:analysis_server/src/computer/computer_hover.dart';
+import 'package:analysis_server/src/lsp/client_capabilities.dart';
 import 'package:analysis_server/src/lsp/constants.dart';
 import 'package:analysis_server/src/lsp/error_or.dart';
 import 'package:analysis_server/src/lsp/handlers/handlers.dart';
@@ -37,10 +38,15 @@
     MessageInfo message,
     CancellationToken token,
   ) async {
+    var capabilities = message.clientCapabilities;
+    if (capabilities == null) {
+      return serverNotInitializedError;
+    }
+
     var resolutionInfo = params.data;
 
     if (resolutionInfo is DartCompletionResolutionInfo) {
-      return resolveDartCompletion(params, resolutionInfo, token);
+      return resolveDartCompletion(capabilities, params, resolutionInfo, token);
     } else if (resolutionInfo is PubPackageCompletionItemResolutionInfo) {
       return resolvePubPackageCompletion(params, resolutionInfo, token);
     } else {
@@ -49,17 +55,11 @@
   }
 
   Future<ErrorOr<CompletionItem>> resolveDartCompletion(
+    LspClientCapabilities clientCapabilities,
     CompletionItem item,
     DartCompletionResolutionInfo data,
     CancellationToken token,
   ) async {
-    var clientCapabilities = server.lspClientCapabilities;
-    if (clientCapabilities == null) {
-      // This should not happen unless a client misbehaves.
-      return error(ErrorCodes.ServerNotInitialized,
-          'Requests not before server is initialized');
-    }
-
     var file = data.file;
     var importUris = data.importUris.map(Uri.parse).toList();
     var elementLocationReference = data.ref;
@@ -111,8 +111,8 @@
         // a command that the client will call to apply those edits later.
         Command? command;
         if (otherFilesChanges.isNotEmpty) {
-          var workspaceEdit =
-              createPlainWorkspaceEdit(server, otherFilesChanges);
+          var workspaceEdit = createPlainWorkspaceEdit(
+              server, clientCapabilities, otherFilesChanges);
           command = Command(
               title: 'Add import',
               command: Commands.sendWorkspaceEdit,
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
index ef58e23..c6549d1 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
@@ -71,7 +71,7 @@
       TextDocumentPositionParams params,
       MessageInfo message,
       CancellationToken token) async {
-    var clientCapabilities = server.lspClientCapabilities;
+    var clientCapabilities = message.clientCapabilities;
     if (clientCapabilities == null) {
       // This should not happen unless a client misbehaves.
       return serverNotInitializedError;
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_color_presentation.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_color_presentation.dart
index 2ec92a7..3dd4768 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_color_presentation.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_color_presentation.dart
@@ -23,7 +23,12 @@
 /// into the source file.
 class DocumentColorPresentationHandler extends SharedMessageHandler<
     ColorPresentationParams, List<ColorPresentation>> {