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>> {