diff --git a/.gitmodules b/.gitmodules index a524098845a48..cca60e337d2d8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -38,9 +38,6 @@ [submodule "src/doc/embedded-book"] path = src/doc/embedded-book url = https://github.com/rust-embedded/book.git -[submodule "src/tools/rust-analyzer"] - path = src/tools/rust-analyzer - url = https://github.com/rust-analyzer/rust-analyzer.git [submodule "library/backtrace"] path = library/backtrace url = https://github.com/rust-lang/backtrace-rs.git diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 575cbc3beb2e7..8876f70c8c61c 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -621,6 +621,7 @@ impl<'a> Builder<'a> { check::Clippy, check::Miri, check::Rls, + check::RustAnalyzer, check::Rustfmt, check::Bootstrap ), @@ -648,6 +649,7 @@ impl<'a> Builder<'a> { test::Cargotest, test::Cargo, test::Rls, + test::RustAnalyzer, test::ErrorIndex, test::Distcheck, test::RunMakeFullDeps, @@ -1551,7 +1553,7 @@ impl<'a> Builder<'a> { Mode::ToolStd => { // Right now this is just compiletest and a few other tools that build on stable. // Allow them to use `feature(test)`, but nothing else. - rustflags.arg("-Zallow-features=binary-dep-depinfo,test,backtrace"); + rustflags.arg("-Zallow-features=binary-dep-depinfo,test,backtrace,proc_macro_internals,proc_macro_diagnostic,proc_macro_span"); } Mode::Std | Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {} } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 9196b78c513fe..394bd8b4e2825 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -301,6 +301,68 @@ impl Step for CodegenBackend { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct RustAnalyzer { + pub target: TargetSelection, +} + +impl Step for RustAnalyzer { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/rust-analyzer") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(RustAnalyzer { target: run.target }); + } + + fn run(self, builder: &Builder<'_>) { + let compiler = builder.compiler(builder.top_stage, builder.config.build); + let target = self.target; + + builder.ensure(Std { target }); + + let mut cargo = prepare_tool_cargo( + builder, + compiler, + Mode::ToolStd, + target, + cargo_subcommand(builder.kind), + "src/tools/rust-analyzer", + SourceType::InTree, + &["rust-analyzer/in-rust-tree".to_owned()], + ); + + cargo.rustflag( + "-Zallow-features=proc_macro_internals,proc_macro_diagnostic,proc_macro_span", + ); + + // For ./x.py clippy, don't check those targets because + // linting tests and benchmarks can produce very noisy results + if builder.kind != Kind::Clippy { + // can't use `--all-targets` because `--examples` doesn't work well + cargo.arg("--bins"); + cargo.arg("--tests"); + cargo.arg("--benches"); + } + + builder.info(&format!( + "Checking stage{} {} artifacts ({} -> {})", + compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple + )); + run_cargo(builder, cargo, args(builder), &stamp(builder, compiler, target), vec![], true); + + /// Cargo's output path in a given stage, compiled by a particular + /// compiler for the specified target. + fn stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf { + builder.cargo_out(compiler, Mode::ToolStd, target).join(".rust-analyzer-check.stamp") + } + } +} + macro_rules! tool_check_step { ($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index cba013b5bb689..95655c0ee3598 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1058,7 +1058,7 @@ impl Step for RustAnalyzer { } let rust_analyzer = builder - .ensure(tool::RustAnalyzer { compiler, target, extra_features: Vec::new() }) + .ensure(tool::RustAnalyzer { compiler, target }) .expect("rust-analyzer always builds"); let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 078207d85fe46..fd583da908255 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -352,6 +352,64 @@ impl Step for Rls { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct RustAnalyzer { + stage: u32, + host: TargetSelection, +} + +impl Step for RustAnalyzer { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/rust-analyzer") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Self { stage: run.builder.top_stage, host: run.target }); + } + + /// Runs `cargo test` for rust-analyzer + fn run(self, builder: &Builder<'_>) { + let stage = self.stage; + let host = self.host; + let compiler = builder.compiler(stage, host); + + builder.ensure(tool::RustAnalyzer { compiler, target: self.host }).expect("in-tree tool"); + + let workspace_path = "src/tools/rust-analyzer"; + // until the whole RA test suite runs on `i686`, we only run + // `proc-macro-srv` tests + let crate_path = "src/tools/rust-analyzer/crates/proc-macro-srv"; + let mut cargo = tool::prepare_tool_cargo( + builder, + compiler, + Mode::ToolStd, + host, + "test", + crate_path, + SourceType::InTree, + &["sysroot-abi".to_owned()], + ); + + let dir = builder.src.join(workspace_path); + // needed by rust-analyzer to find its own text fixtures, cf. + // https://github.com/rust-analyzer/expect-test/issues/33 + cargo.env("CARGO_WORKSPACE_DIR", &dir); + + // RA's test suite tries to write to the source directory, that can't + // work in Rust CI + cargo.env("SKIP_SLOW_TESTS", "1"); + + cargo.add_rustc_lib_path(builder, compiler); + cargo.arg("--").args(builder.config.cmd.test_args()); + + builder.run(&mut cargo.into()); + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Rustfmt { stage: u32, diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index f659ccbe2507f..7c37621d417c9 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use std::env; use std::fs; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::process::Command; use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; @@ -683,6 +683,50 @@ impl Step for LldWrapper { } } +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct RustAnalyzer { + pub compiler: Compiler, + pub target: TargetSelection, +} + +impl Step for RustAnalyzer { + type Output = Option; + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = false; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + let builder = run.builder; + run.path("src/tools/rust-analyzer").default_condition( + builder.config.extended + && builder + .config + .tools + .as_ref() + .map_or(true, |tools| tools.iter().any(|tool| tool == "rust-analyzer")), + ) + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(RustAnalyzer { + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + target: run.target, + }); + } + + fn run(self, builder: &Builder<'_>) -> Option { + builder.ensure(ToolBuild { + compiler: self.compiler, + target: self.target, + tool: "rust-analyzer", + mode: Mode::ToolStd, + path: "src/tools/rust-analyzer", + extra_features: vec!["rust-analyzer/in-rust-tree".to_owned()], + is_optional_tool: false, + source_type: SourceType::InTree, + }) + } +} + macro_rules! tool_extended { (($sel:ident, $builder:ident), $($name:ident, @@ -780,7 +824,6 @@ tool_extended!((self, builder), // and this is close enough for now. RustDemangler, rust_demangler, "src/tools/rust-demangler", "rust-demangler", stable=false, in_tree=true, tool_std=true, {}; Rustfmt, rustfmt, "src/tools/rustfmt", "rustfmt", stable=true, in_tree=true, {}; - RustAnalyzer, rust_analyzer, "src/tools/rust-analyzer/crates/rust-analyzer", "rust-analyzer", stable=true, submodule="rust-analyzer", {}; ); impl<'a> Builder<'a> { diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer deleted file mode 160000 index 897a7ec4b826f..0000000000000 --- a/src/tools/rust-analyzer +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 897a7ec4b826f85ec1626870e734490701138097 diff --git a/src/tools/rust-analyzer/.cargo/config.toml b/src/tools/rust-analyzer/.cargo/config.toml new file mode 100644 index 0000000000000..24745d1c806fe --- /dev/null +++ b/src/tools/rust-analyzer/.cargo/config.toml @@ -0,0 +1,11 @@ +[alias] +xtask = "run --package xtask --bin xtask --" +tq = "test -- -q" +qt = "tq" +lint = "clippy --all-targets -- -Aclippy::collapsible_if -Aclippy::needless_pass_by_value -Aclippy::nonminimal_bool -Aclippy::redundant_pattern_matching --cap-lints warn" + +[target.x86_64-pc-windows-msvc] +linker = "rust-lld" + +[env] +CARGO_WORKSPACE_DIR = { value = "", relative = true } \ No newline at end of file diff --git a/src/tools/rust-analyzer/.editorconfig b/src/tools/rust-analyzer/.editorconfig new file mode 100644 index 0000000000000..314f79d3f901c --- /dev/null +++ b/src/tools/rust-analyzer/.editorconfig @@ -0,0 +1,19 @@ +# https://EditorConfig.org +root = true + +[*] +charset = utf-8 +trim_trailing_whitespace = true +end_of_line = lf +insert_final_newline = true +indent_style = space + +[*.{rs,toml}] +indent_size = 4 + +[*.ts] +indent_size = 4 +[*.js] +indent_size = 4 +[*.json] +indent_size = 4 diff --git a/src/tools/rust-analyzer/.git-blame-ignore-revs b/src/tools/rust-analyzer/.git-blame-ignore-revs new file mode 100644 index 0000000000000..a302e23781ae9 --- /dev/null +++ b/src/tools/rust-analyzer/.git-blame-ignore-revs @@ -0,0 +1,8 @@ +# for this file to take effect make sure you use git ^2.23 and +# add ignoreFile to your git configuration: +# ``` +# git config --global blame.ignoreRevsFile .git-blame-ignore-revs +# ``` + +# prettier format +f247090558c9ba3c551566eae5882b7ca865225f diff --git a/src/tools/rust-analyzer/.gitattributes b/src/tools/rust-analyzer/.gitattributes new file mode 100644 index 0000000000000..cb87b5d01385a --- /dev/null +++ b/src/tools/rust-analyzer/.gitattributes @@ -0,0 +1,9 @@ +* text=auto eol=lf + +# git grep shouldn't match entries in this benchmark data +bench_data/** binary + +# Older git versions try to fix line endings on images, this prevents it. +*.png binary +*.jpg binary +*.ico binary diff --git a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/blank_issue.md b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/blank_issue.md new file mode 100644 index 0000000000000..a08ad07cbf8d3 --- /dev/null +++ b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/blank_issue.md @@ -0,0 +1,10 @@ +--- +name: Blank Issue +about: Create a blank issue. +title: '' +labels: '' +assignees: '' + +--- + + diff --git a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/bug_report.md b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000000..7ba06356a37ce --- /dev/null +++ b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,26 @@ +--- +name: Bug report +about: Create a bug report for rust-analyzer. +title: '' +labels: '' +assignees: '' + +--- + + + +**rust-analyzer version**: (eg. output of "Rust Analyzer: Show RA Version" command) + +**rustc version**: (eg. output of `rustc -V`) + +**relevant settings**: (eg. client settings, or environment variables like `CARGO`, `RUSTUP_HOME` or `CARGO_HOME`) diff --git a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md new file mode 100644 index 0000000000000..a0b1627d7e2ef --- /dev/null +++ b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md @@ -0,0 +1,17 @@ +--- +name: Critical Nightly Regression +about: You are using nightly rust-analyzer and the latest version is unusable. +title: '' +labels: '' +assignees: 'matklad' + +--- + + + +This is a serious regression in nightly and it's important to fix it before the next release. +@matklad, please take a look. diff --git a/src/tools/rust-analyzer/.github/actions/github-release/Dockerfile b/src/tools/rust-analyzer/.github/actions/github-release/Dockerfile new file mode 100644 index 0000000000000..5849eac7d246a --- /dev/null +++ b/src/tools/rust-analyzer/.github/actions/github-release/Dockerfile @@ -0,0 +1,8 @@ +FROM node:slim + +COPY . /action +WORKDIR /action + +RUN npm install --production + +ENTRYPOINT ["node", "/action/main.js"] diff --git a/src/tools/rust-analyzer/.github/actions/github-release/README.md b/src/tools/rust-analyzer/.github/actions/github-release/README.md new file mode 100644 index 0000000000000..7b50d002001ee --- /dev/null +++ b/src/tools/rust-analyzer/.github/actions/github-release/README.md @@ -0,0 +1,21 @@ +# github-release + +Copy-pasted from +https://github.com/bytecodealliance/wasmtime/tree/8acfdbdd8aa550d1b84e0ce1e6222a6605d14e38/.github/actions/github-release + +An action used to publish GitHub releases for `wasmtime`. + +As of the time of this writing there's a few actions floating around which +perform github releases but they all tend to have their set of drawbacks. +Additionally nothing handles deleting releases which we need for our rolling +`dev` release. + +To handle all this this action rolls-its-own implementation using the +actions/toolkit repository and packages published there. These run in a Docker +container and take various inputs to orchestrate the release from the build. + +More comments can be found in `main.js`. + +Testing this is really hard. If you want to try though run `npm install` and +then `node main.js`. You'll have to configure a bunch of env vars though to get +anything reasonably working. diff --git a/src/tools/rust-analyzer/.github/actions/github-release/action.yml b/src/tools/rust-analyzer/.github/actions/github-release/action.yml new file mode 100644 index 0000000000000..51a074adfaa88 --- /dev/null +++ b/src/tools/rust-analyzer/.github/actions/github-release/action.yml @@ -0,0 +1,15 @@ +name: 'wasmtime github releases' +description: 'wasmtime github releases' +inputs: + token: + description: '' + required: true + name: + description: '' + required: true + files: + description: '' + required: true +runs: + using: 'docker' + image: 'Dockerfile' diff --git a/src/tools/rust-analyzer/.github/actions/github-release/main.js b/src/tools/rust-analyzer/.github/actions/github-release/main.js new file mode 100644 index 0000000000000..e8dba398733c1 --- /dev/null +++ b/src/tools/rust-analyzer/.github/actions/github-release/main.js @@ -0,0 +1,144 @@ +const core = require('@actions/core'); +const path = require("path"); +const fs = require("fs"); +const github = require('@actions/github'); +const glob = require('glob'); + +function sleep(milliseconds) { + return new Promise(resolve => setTimeout(resolve, milliseconds)); +} + +async function runOnce() { + // Load all our inputs and env vars. Note that `getInput` reads from `INPUT_*` + const files = core.getInput('files'); + const name = core.getInput('name'); + const token = core.getInput('token'); + const slug = process.env.GITHUB_REPOSITORY; + const owner = slug.split('/')[0]; + const repo = slug.split('/')[1]; + const sha = process.env.HEAD_SHA; + + core.info(`files: ${files}`); + core.info(`name: ${name}`); + + const options = { + request: { + timeout: 30000, + } + }; + const octokit = github.getOctokit(token, options); + + // Delete the previous release since we can't overwrite one. This may happen + // due to retrying an upload or it may happen because we're doing the dev + // release. + const releases = await octokit.paginate("GET /repos/:owner/:repo/releases", { owner, repo }); + for (const release of releases) { + if (release.tag_name !== name) { + continue; + } + const release_id = release.id; + core.info(`deleting release ${release_id}`); + await octokit.rest.repos.deleteRelease({ owner, repo, release_id }); + } + + // We also need to update the `dev` tag while we're at it on the `dev` branch. + if (name == 'nightly') { + try { + core.info(`updating nightly tag`); + await octokit.rest.git.updateRef({ + owner, + repo, + ref: 'tags/nightly', + sha, + force: true, + }); + } catch (e) { + core.error(e); + core.info(`creating nightly tag`); + await octokit.rest.git.createTag({ + owner, + repo, + tag: 'nightly', + message: 'nightly release', + object: sha, + type: 'commit', + }); + } + } + + // Creates an official GitHub release for this `tag`, and if this is `dev` + // then we know that from the previous block this should be a fresh release. + core.info(`creating a release`); + const release = await octokit.rest.repos.createRelease({ + owner, + repo, + name, + tag_name: name, + target_commitish: sha, + prerelease: name === 'nightly', + }); + const release_id = release.data.id; + + // Upload all the relevant assets for this release as just general blobs. + for (const file of glob.sync(files)) { + const size = fs.statSync(file).size; + const name = path.basename(file); + + await runWithRetry(async function () { + // We can't overwrite assets, so remove existing ones from a previous try. + let assets = await octokit.rest.repos.listReleaseAssets({ + owner, + repo, + release_id + }); + for (const asset of assets.data) { + if (asset.name === name) { + core.info(`delete asset ${name}`); + const asset_id = asset.id; + await octokit.rest.repos.deleteReleaseAsset({ owner, repo, asset_id }); + } + } + + core.info(`upload ${file}`); + const headers = { 'content-length': size, 'content-type': 'application/octet-stream' }; + const data = fs.createReadStream(file); + await octokit.rest.repos.uploadReleaseAsset({ + data, + headers, + name, + url: release.data.upload_url, + }); + }); + } +} + +async function runWithRetry(f) { + const retries = 10; + const maxDelay = 4000; + let delay = 1000; + + for (let i = 0; i < retries; i++) { + try { + await f(); + break; + } catch (e) { + if (i === retries - 1) + throw e; + + core.error(e); + const currentDelay = Math.round(Math.random() * delay); + core.info(`sleeping ${currentDelay} ms`); + await sleep(currentDelay); + delay = Math.min(delay * 2, maxDelay); + } + } +} + +async function run() { + await runWithRetry(runOnce); +} + +run().catch(err => { + core.error(err); + core.setFailed(err.message); +}); diff --git a/src/tools/rust-analyzer/.github/actions/github-release/package.json b/src/tools/rust-analyzer/.github/actions/github-release/package.json new file mode 100644 index 0000000000000..af4bf074d2d03 --- /dev/null +++ b/src/tools/rust-analyzer/.github/actions/github-release/package.json @@ -0,0 +1,10 @@ +{ + "name": "wasmtime-github-release", + "version": "0.0.0", + "main": "main.js", + "dependencies": { + "@actions/core": "^1.6", + "@actions/github": "^5.0", + "glob": "^7.1.5" + } +} diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml new file mode 100644 index 0000000000000..0c81ff0789fbb --- /dev/null +++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml @@ -0,0 +1,156 @@ +# Please make sure that the `needs` fields for both `end-success` and `end-failure` +# are updated when adding new jobs! + +name: CI +on: + pull_request: + push: + branches: + - auto + - try + +env: + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + CI: 1 + RUST_BACKTRACE: short + RUSTFLAGS: "-D warnings -W unreachable-pub -W rust-2021-compatibility" + RUSTUP_MAX_RETRIES: 10 + +jobs: + rust: + if: github.repository == 'rust-lang/rust-analyzer' + name: Rust + runs-on: ${{ matrix.os }} + env: + CC: deny_c + + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 20 + + - name: Install Rust toolchain + run: | + rustup update --no-self-update stable + rustup component add rustfmt rust-src + + - name: Cache Dependencies + uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72 + + - name: Compile + run: cargo test --no-run --locked + + - name: Test + run: cargo test -- --nocapture --quiet + + # Weird targets to catch non-portable code + rust-cross: + if: github.repository == 'rust-lang/rust-analyzer' + name: Rust Cross + runs-on: ubuntu-latest + + env: + targets: "powerpc-unknown-linux-gnu x86_64-unknown-linux-musl" + # The rust-analyzer binary is not expected to compile on WASM, but the IDE + # crate should + targets_ide: "wasm32-unknown-unknown" + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install Rust toolchain + run: | + rustup update --no-self-update stable + rustup target add ${{ env.targets }} ${{ env.targets_ide }} + + - name: Cache Dependencies + uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72 + + - name: Check + run: | + for target in ${{ env.targets }}; do + cargo check --target=$target --all-targets + done + for target in ${{ env.targets_ide }}; do + cargo check -p ide --target=$target --all-targets + done + + typescript: + if: github.repository == 'rust-lang/rust-analyzer' + name: TypeScript + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install Nodejs + uses: actions/setup-node@v1 + with: + node-version: 14.x + + - name: Install xvfb + if: matrix.os == 'ubuntu-latest' + run: sudo apt-get install -y xvfb + + - run: npm ci + working-directory: ./editors/code + +# - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; } +# if: runner.os == 'Linux' +# working-directory: ./editors/code + + - run: npm run lint + working-directory: ./editors/code + + - name: Run VS Code tests (Linux) + if: matrix.os == 'ubuntu-latest' + env: + VSCODE_CLI: 1 + run: xvfb-run npm test + working-directory: ./editors/code + + - name: Run VS Code tests (Windows) + if: matrix.os == 'windows-latest' + env: + VSCODE_CLI: 1 + run: npm test + working-directory: ./editors/code + + - run: npm run pretest + working-directory: ./editors/code + + - run: npm run package --scripts-prepend-node-path + working-directory: ./editors/code + + end-success: + name: bors build finished + if: github.event.pusher.name == 'bors' && success() + runs-on: ubuntu-latest + needs: [rust, rust-cross, typescript] + steps: + - name: Mark the job as successful + run: exit 0 + + end-failure: + name: bors build finished + if: github.event.pusher.name == 'bors' && (failure() || cancelled()) + runs-on: ubuntu-latest + needs: [rust, rust-cross, typescript] + steps: + - name: Mark the job as a failure + run: exit 1 diff --git a/src/tools/rust-analyzer/.github/workflows/metrics.yaml b/src/tools/rust-analyzer/.github/workflows/metrics.yaml new file mode 100644 index 0000000000000..3fe2fc917a39a --- /dev/null +++ b/src/tools/rust-analyzer/.github/workflows/metrics.yaml @@ -0,0 +1,30 @@ +name: metrics +on: + push: + branches: + - master + +env: + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + RUSTFLAGS: "-D warnings -W unreachable-pub" + RUSTUP_MAX_RETRIES: 10 + +jobs: + metrics: + if: github.repository == 'rust-lang/rust-analyzer' + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install Rust toolchain + run: | + rustup update --no-self-update stable + rustup component add rustfmt rust-src + + - name: Collect metrics + run: cargo xtask metrics + env: + METRICS_TOKEN: ${{ secrets.METRICS_TOKEN }} diff --git a/src/tools/rust-analyzer/.github/workflows/publish.yml b/src/tools/rust-analyzer/.github/workflows/publish.yml new file mode 100644 index 0000000000000..927996c1bef21 --- /dev/null +++ b/src/tools/rust-analyzer/.github/workflows/publish.yml @@ -0,0 +1,41 @@ +name: publish +on: + workflow_dispatch: # We can add version input when 1.0 is released and scheduled releases are removed + +# schedule: +# - cron: "0 0 * * *" # midnight UTC + + push: + branches: + - release + +jobs: + publish: + name: publish + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Install Rust toolchain + run: rustup update --no-self-update stable + + - name: Install cargo-workspaces + run: cargo install cargo-workspaces + + - name: Release + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + PATCH: ${{ github.run_number }} + shell: bash + run: | + git config --global user.email "runner@gha.local" + git config --global user.name "Github Action" + rm Cargo.lock + cargo workspaces rename ra_ap_%n + find crates/rust-analyzer -type f -name '*.rs' -exec sed -i 's/rust_analyzer/ra_ap_rust_analyzer/g' {} + + # Fix names for crates that were published before switch to kebab-case. + find crates -name 'Cargo.toml' -exec sed -i "s/ra_ap_base-db/ra_ap_base_db/g; s/ra_ap_hir-def/ra_ap_hir_def/g; s/ra_ap_hir-expand/ra_ap_hir_expand/g; s/ra_ap_hir-ty/ra_ap_hir_ty/g; s/ra_ap_ide-assists/ra_ap_ide_assists/g; s/ra_ap_ide-completion/ra_ap_ide_completion/g; s/ra_ap_ide-db/ra_ap_ide_db/g; s/ra_ap_ide-diagnostics/ra_ap_ide_diagnostics/g; s/ra_ap_ide-ssr/ra_ap_ide_ssr/g; s/ra_ap_proc-macro-api/ra_ap_proc_macro_api/g; s/ra_ap_proc-macro-srv/ra_ap_proc_macro_srv/g; s/ra_ap_project-model/ra_ap_project_model/g; s/ra_ap_test-utils/ra_ap_test_utils/g; s/ra_ap_text-edit/ra_ap_text_edit/g" {} + + cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$PATCH diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml new file mode 100644 index 0000000000000..4e62f2cde2799 --- /dev/null +++ b/src/tools/rust-analyzer/.github/workflows/release.yaml @@ -0,0 +1,249 @@ +name: release +on: + schedule: + - cron: "0 0 * * *" # midnight UTC + + workflow_dispatch: + + push: + branches: + - release + - trigger-nightly + +env: + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + RUSTFLAGS: "-D warnings -W unreachable-pub" + RUSTUP_MAX_RETRIES: 10 + FETCH_DEPTH: 0 # pull in the tags for the version string + MACOSX_DEPLOYMENT_TARGET: 10.15 + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc + +jobs: + dist: + strategy: + matrix: + include: + - os: windows-latest + target: x86_64-pc-windows-msvc + code-target: win32-x64 + - os: windows-latest + target: aarch64-pc-windows-msvc + code-target: win32-arm64 + - os: ubuntu-18.04 + target: x86_64-unknown-linux-gnu + code-target: linux-x64 + - os: ubuntu-18.04 + target: aarch64-unknown-linux-gnu + code-target: linux-arm64 + - os: macos-11 + target: x86_64-apple-darwin + code-target: darwin-x64 + - os: macos-11 + target: aarch64-apple-darwin + code-target: darwin-arm64 + + name: dist (${{ matrix.target }}) + runs-on: ${{ matrix.os }} + + env: + RA_TARGET: ${{ matrix.target }} + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: ${{ env.FETCH_DEPTH }} + + - name: Install Rust toolchain + run: | + rustup update --no-self-update stable + rustup target add ${{ matrix.target }} + rustup component add rust-src + + - name: Install Node.js + uses: actions/setup-node@v1 + with: + node-version: 14.x + + - name: Update apt repositories + if: matrix.target == 'aarch64-unknown-linux-gnu' + run: sudo apt-get update + + - name: Install target toolchain + if: matrix.target == 'aarch64-unknown-linux-gnu' + run: sudo apt-get install gcc-aarch64-linux-gnu + + - name: Dist + run: cargo xtask dist --client-patch-version ${{ github.run_number }} + + - run: npm ci + working-directory: editors/code + + - name: Package Extension (release) + if: github.ref == 'refs/heads/release' + run: npx vsce package -o "../../dist/rust-analyzer-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} + working-directory: editors/code + + - name: Package Extension (nightly) + if: github.ref != 'refs/heads/release' + run: npx vsce package -o "../../dist/rust-analyzer-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} --pre-release + working-directory: editors/code + + - if: matrix.target == 'x86_64-unknown-linux-gnu' + run: rm -rf editors/code/server + + - if: matrix.target == 'x86_64-unknown-linux-gnu' && github.ref == 'refs/heads/release' + run: npx vsce package -o ../../dist/rust-analyzer-no-server.vsix + working-directory: editors/code + + - if: matrix.target == 'x86_64-unknown-linux-gnu' && github.ref != 'refs/heads/release' + run: npx vsce package -o ../../dist/rust-analyzer-no-server.vsix --pre-release + working-directory: editors/code + + - name: Run analysis-stats on rust-analyzer + if: matrix.target == 'x86_64-unknown-linux-gnu' + run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats . + + - name: Run analysis-stats on rust std library + if: matrix.target == 'x86_64-unknown-linux-gnu' + run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std + + - name: Upload artifacts + uses: actions/upload-artifact@v1 + with: + name: dist-${{ matrix.target }} + path: ./dist + + dist-x86_64-unknown-linux-musl: + name: dist (x86_64-unknown-linux-musl) + runs-on: ubuntu-latest + env: + RA_TARGET: x86_64-unknown-linux-musl + # For some reason `-crt-static` is not working for clang without lld + RUSTFLAGS: "-C link-arg=-fuse-ld=lld -C target-feature=-crt-static" + container: + image: rust:alpine + volumes: + - /usr/local/cargo/registry + + steps: + - name: Install dependencies + run: apk add --no-cache git clang lld musl-dev nodejs npm + + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: ${{ env.FETCH_DEPTH }} + + - name: Dist + run: cargo xtask dist --client-patch-version ${{ github.run_number }} + + - run: npm ci + working-directory: editors/code + + - name: Package Extension (release) + if: github.ref == 'refs/heads/release' + run: npx vsce package -o "../../dist/rust-analyzer-alpine-x64.vsix" --target alpine-x64 + working-directory: editors/code + + - name: Package Extension (nightly) + if: github.ref != 'refs/heads/release' + run: npx vsce package -o "../../dist/rust-analyzer-alpine-x64.vsix" --target alpine-x64 --pre-release + working-directory: editors/code + + - run: rm -rf editors/code/server + + - name: Upload artifacts + uses: actions/upload-artifact@v1 + with: + name: dist-x86_64-unknown-linux-musl + path: ./dist + + publish: + name: publish + runs-on: ubuntu-latest + needs: ["dist", "dist-x86_64-unknown-linux-musl"] + steps: + - name: Install Nodejs + uses: actions/setup-node@v1 + with: + node-version: 14.x + + - run: echo "TAG=$(date --iso -u)" >> $GITHUB_ENV + if: github.ref == 'refs/heads/release' + - run: echo "TAG=nightly" >> $GITHUB_ENV + if: github.ref != 'refs/heads/release' + - run: 'echo "TAG: $TAG"' + + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: ${{ env.FETCH_DEPTH }} + + - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV + - run: 'echo "HEAD_SHA: $HEAD_SHA"' + + - uses: actions/download-artifact@v1 + with: + name: dist-aarch64-apple-darwin + path: dist + - uses: actions/download-artifact@v1 + with: + name: dist-x86_64-apple-darwin + path: dist + - uses: actions/download-artifact@v1 + with: + name: dist-x86_64-unknown-linux-gnu + path: dist + - uses: actions/download-artifact@v1 + with: + name: dist-x86_64-unknown-linux-musl + path: dist + - uses: actions/download-artifact@v1 + with: + name: dist-aarch64-unknown-linux-gnu + path: dist + - uses: actions/download-artifact@v1 + with: + name: dist-x86_64-pc-windows-msvc + path: dist + - uses: actions/download-artifact@v1 + with: + name: dist-aarch64-pc-windows-msvc + path: dist + - run: ls -al ./dist + + - name: Publish Release + uses: ./.github/actions/github-release + with: + files: "dist/*" + name: ${{ env.TAG }} + token: ${{ secrets.GITHUB_TOKEN }} + + - run: rm dist/rust-analyzer-no-server.vsix + + - run: npm ci + working-directory: ./editors/code + + - name: Publish Extension (Code Marketplace, release) + if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer') + working-directory: ./editors/code + # token from https://dev.azure.com/rust-analyzer/ + run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix + + - name: Publish Extension (OpenVSX, release) + if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer') + working-directory: ./editors/code + # token from https://dev.azure.com/rust-analyzer/ + run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix + + - name: Publish Extension (Code Marketplace, nightly) + if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer') + working-directory: ./editors/code + run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix --pre-release + + - name: Publish Extension (OpenVSX, nightly) + if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer') + working-directory: ./editors/code + run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix --pre-release diff --git a/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml b/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml new file mode 100644 index 0000000000000..05f3e254e5f5a --- /dev/null +++ b/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml @@ -0,0 +1,34 @@ +name: rustdoc +on: + push: + branches: + - master + +env: + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + RUSTFLAGS: "-D warnings -W unreachable-pub" + RUSTUP_MAX_RETRIES: 10 + +jobs: + rustdoc: + if: github.repository == 'rust-lang/rust-analyzer' + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install Rust toolchain + run: rustup update --no-self-update stable + + - name: Build Documentation + run: cargo doc --all --no-deps + + - name: Deploy Docs + uses: peaceiris/actions-gh-pages@364c31d33bb99327c77b3a5438a83a357a6729ad # v3.4.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_branch: gh-pages + publish_dir: ./target/doc + force_orphan: true diff --git a/src/tools/rust-analyzer/.gitignore b/src/tools/rust-analyzer/.gitignore new file mode 100644 index 0000000000000..68c87a6b1ed41 --- /dev/null +++ b/src/tools/rust-analyzer/.gitignore @@ -0,0 +1,16 @@ +/target/ +/dist/ +crates/*/target +**/*.rs.bk +**/*.rs.pending-snap +.idea/* +*.log +*.iml +.vscode/settings.json +generated_assists.adoc +generated_features.adoc +generated_diagnostic.adoc +.DS_Store +/out/ +/dump.lsif +.envrc diff --git a/src/tools/rust-analyzer/.vscode/extensions.json b/src/tools/rust-analyzer/.vscode/extensions.json new file mode 100644 index 0000000000000..027eeabc4c3e5 --- /dev/null +++ b/src/tools/rust-analyzer/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": ["vadimcn.vscode-lldb"], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [] +} diff --git a/src/tools/rust-analyzer/.vscode/launch.json b/src/tools/rust-analyzer/.vscode/launch.json new file mode 100644 index 0000000000000..021b8f048cf2c --- /dev/null +++ b/src/tools/rust-analyzer/.vscode/launch.json @@ -0,0 +1,131 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + + // NOTE: --disable-extensions + // Disable all installed extensions to increase performance of the debug instance + // and prevent potential conflicts with other installed extensions. + + "version": "0.2.0", + "configurations": [ + { + // Used for testing the extension with the installed LSP server. + "name": "Run Installed Extension", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + // "--user-data-dir=${workspaceFolder}/target/code", + "--disable-extensions", + "--extensionDevelopmentPath=${workspaceFolder}/editors/code" + ], + "outFiles": [ + "${workspaceFolder}/editors/code/out/**/*.js" + ], + "preLaunchTask": "Build Extension", + "skipFiles": [ + "/**/*.js" + ] + }, + { + // Used for testing the extension with a local build of the LSP server (in `target/debug`). + "name": "Run Extension (Debug Build)", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--disable-extensions", + "--extensionDevelopmentPath=${workspaceFolder}/editors/code" + ], + "outFiles": [ + "${workspaceFolder}/editors/code/out/**/*.js" + ], + "preLaunchTask": "Build Server and Extension", + "skipFiles": [ + "/**/*.js" + ], + "env": { + "__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/debug/rust-analyzer" + } + }, + { + // Used for testing the extension with a local build of the LSP server (in `target/release`). + "name": "Run Extension (Release Build)", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--disable-extensions", + "--extensionDevelopmentPath=${workspaceFolder}/editors/code" + ], + "outFiles": [ + "${workspaceFolder}/editors/code/out/**/*.js" + ], + "preLaunchTask": "Build Server (Release) and Extension", + "skipFiles": [ + "/**/*.js" + ], + "env": { + "__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/release/rust-analyzer" + } + }, + { + // Used for testing the extension with a local build of the LSP server (in `target/release`) + // with all other extendions loaded. + "name": "Run With Extensions", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--disable-extension", "matklad.rust-analyzer", + "--extensionDevelopmentPath=${workspaceFolder}/editors/code" + ], + "outFiles": [ + "${workspaceFolder}/editors/code/out/**/*.js" + ], + "preLaunchTask": "Build Server (Release) and Extension", + "skipFiles": [ + "/**/*.js" + ], + "env": { + "__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/release/rust-analyzer" + } + }, + { + // Used to attach LLDB to a running LSP server. + // NOTE: Might require root permissions. For this run: + // + // `echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope` + // + // Don't forget to set `debug = 2` in `Cargo.toml` before building the server + + "name": "Attach To Server", + "type": "lldb", + "request": "attach", + "program": "${workspaceFolder}/target/debug/rust-analyzer", + "pid": "${command:pickMyProcess}", + "sourceLanguages": [ + "rust" + ] + }, + { + "name": "Run Unit Tests", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}/editors/code", + "--extensionTestsPath=${workspaceFolder}/editors/code/out/tests/unit" ], + "sourceMaps": true, + "outFiles": [ "${workspaceFolder}/editors/code/out/tests/unit/**/*.js" ], + "preLaunchTask": "Pretest" + }, + { + "name": "Win Attach to Server", + "type": "cppvsdbg", + "processId":"${command:pickProcess}", + "request": "attach" + } + ] +} diff --git a/src/tools/rust-analyzer/.vscode/tasks.json b/src/tools/rust-analyzer/.vscode/tasks.json new file mode 100644 index 0000000000000..a25dff19e4155 --- /dev/null +++ b/src/tools/rust-analyzer/.vscode/tasks.json @@ -0,0 +1,67 @@ +// See https://go.microsoft.com/fwlink/?LinkId=733558 +// for the documentation about the tasks.json format +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build Extension in Background", + "group": "build", + "type": "npm", + "script": "watch", + "path": "editors/code/", + "problemMatcher": { + "base": "$tsc-watch", + "fileLocation": ["relative", "${workspaceFolder}/editors/code/"] + }, + "isBackground": true, + }, + { + "label": "Build Extension", + "group": "build", + "type": "npm", + "script": "build", + "path": "editors/code/", + "problemMatcher": { + "base": "$tsc", + "fileLocation": ["relative", "${workspaceFolder}/editors/code/"] + }, + }, + { + "label": "Build Server", + "group": "build", + "type": "shell", + "command": "cargo build --package rust-analyzer", + "problemMatcher": "$rustc" + }, + { + "label": "Build Server (Release)", + "group": "build", + "type": "shell", + "command": "cargo build --release --package rust-analyzer", + "problemMatcher": "$rustc" + }, + { + "label": "Pretest", + "group": "build", + "isBackground": false, + "type": "npm", + "script": "pretest", + "path": "editors/code/", + "problemMatcher": { + "base": "$tsc", + "fileLocation": ["relative", "${workspaceFolder}/editors/code/"] + } + }, + + { + "label": "Build Server and Extension", + "dependsOn": ["Build Server", "Build Extension"], + "problemMatcher": "$rustc" + }, + { + "label": "Build Server (Release) and Extension", + "dependsOn": ["Build Server (Release)", "Build Extension"], + "problemMatcher": "$rustc" + } + ] +} diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock new file mode 100644 index 0000000000000..4c830006832c9 --- /dev/null +++ b/src/tools/rust-analyzer/Cargo.lock @@ -0,0 +1,2094 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "always-assert" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf688625d06217d5b1bb0ea9d9c44a1635fd0ee3534466388d18203174f4d11" +dependencies = [ + "log", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" + +[[package]] +name = "anymap" +version = "1.0.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1f8f5a6f3d50d89e3797d7593a50f96bb2aaa20ca0cc7be1fb673232c91d72" + +[[package]] +name = "arbitrary" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a7924531f38b1970ff630f03eb20a2fde69db5c590c93b0f3482e95dcc5fd60" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object 0.28.4", + "rustc-demangle", +] + +[[package]] +name = "base-db" +version = "0.0.0" +dependencies = [ + "cfg", + "profile", + "rustc-hash", + "salsa", + "stdx", + "syntax", + "test-utils", + "tt", + "vfs", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "camino" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg" +version = "0.0.0" +dependencies = [ + "arbitrary", + "derive_arbitrary", + "expect-test", + "mbe", + "oorandom", + "rustc-hash", + "syntax", + "tt", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chalk-derive" +version = "0.83.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83553c2ef7717e58aecdf42dd9e3c876229f5a1f35a16435b5ddc4addef81827" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "chalk-ir" +version = "0.83.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dd42107d579d8ec2a5af20a8de62a37524a67bf6a4c0ff08a950068f0bfea91" +dependencies = [ + "bitflags", + "chalk-derive", + "lazy_static", +] + +[[package]] +name = "chalk-recursive" +version = "0.83.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c444031541a76c13c145e76d91f1548e9feb2240e7f0c3e77879ceb694994f2d" +dependencies = [ + "chalk-derive", + "chalk-ir", + "chalk-solve", + "rustc-hash", + "tracing", +] + +[[package]] +name = "chalk-solve" +version = "0.83.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c76f2db19c5e8a3d42340cf5b4d90b8c218750536fca35e2bb285ab6653c0bc8" +dependencies = [ + "chalk-derive", + "chalk-ir", + "ena", + "indexmap", + "itertools", + "petgraph", + "rustc-hash", + "tracing", +] + +[[package]] +name = "countme" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" +dependencies = [ + "dashmap", + "once_cell", + "rustc-hash", +] + +[[package]] +name = "cov-mark" +version = "2.0.0-pre.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d48d8f76bd9331f19fe2aaf3821a9f9fb32c3963e1e3d6ce82a8c09cef7444a" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "once_cell", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "dashmap" +version = "5.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3495912c9c1ccf2e18976439f4443f3fee0fd61f424ff99fde6a66b15ecb448f" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "parking_lot_core 0.9.3", +] + +[[package]] +name = "derive_arbitrary" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a577516173adb681466d517d39bd468293bc2c2a16439375ef0f35bba45f3d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dissimilar" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c97b9233581d84b8e1e689cdd3a47b6f69770084fc246e86a7f78b0d9c1d4a5" + +[[package]] +name = "dot" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a74b6c4d4a1cff5f454164363c16b72fa12463ca6b31f4b5f2035a65fa3d5906" + +[[package]] +name = "drop_bomb" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" + +[[package]] +name = "either" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" + +[[package]] +name = "ena" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" +dependencies = [ + "log", +] + +[[package]] +name = "expect-test" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d4661aca38d826eb7c72fe128e4238220616de4c0cc00db7bfc38e2e1364dd3" +dependencies = [ + "dissimilar", + "once_cell", +] + +[[package]] +name = "filetime" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys 0.36.1", +] + +[[package]] +name = "fixedbitset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" + +[[package]] +name = "flate2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flycheck" +version = "0.0.0" +dependencies = [ + "cargo_metadata", + "crossbeam-channel", + "jod-thread", + "paths", + "serde", + "serde_json", + "stdx", + "toolchain", + "tracing", +] + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" + +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + +[[package]] +name = "fst" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" + +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + +[[package]] +name = "hashbrown" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hir" +version = "0.0.0" +dependencies = [ + "arrayvec", + "base-db", + "cfg", + "either", + "hir-def", + "hir-expand", + "hir-ty", + "itertools", + "once_cell", + "profile", + "rustc-hash", + "smallvec", + "stdx", + "syntax", + "tt", +] + +[[package]] +name = "hir-def" +version = "0.0.0" +dependencies = [ + "anymap", + "arrayvec", + "base-db", + "bitflags", + "cfg", + "cov-mark", + "dashmap", + "drop_bomb", + "either", + "expect-test", + "fst", + "hashbrown", + "hir-expand", + "indexmap", + "itertools", + "la-arena", + "limit", + "mbe", + "once_cell", + "profile", + "rustc-hash", + "smallvec", + "stdx", + "syntax", + "test-utils", + "tracing", + "tt", +] + +[[package]] +name = "hir-expand" +version = "0.0.0" +dependencies = [ + "base-db", + "cfg", + "cov-mark", + "either", + "expect-test", + "hashbrown", + "itertools", + "la-arena", + "limit", + "mbe", + "profile", + "rustc-hash", + "smallvec", + "stdx", + "syntax", + "tracing", + "tt", +] + +[[package]] +name = "hir-ty" +version = "0.0.0" +dependencies = [ + "arrayvec", + "base-db", + "chalk-ir", + "chalk-recursive", + "chalk-solve", + "cov-mark", + "ena", + "expect-test", + "hir-def", + "hir-expand", + "itertools", + "la-arena", + "limit", + "once_cell", + "profile", + "rustc-hash", + "scoped-tls", + "smallvec", + "stdx", + "syntax", + "test-utils", + "tracing", + "tracing-subscriber", + "tracing-tree", + "typed-arena", +] + +[[package]] +name = "home" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" +dependencies = [ + "winapi", +] + +[[package]] +name = "ide" +version = "0.0.0" +dependencies = [ + "cfg", + "cov-mark", + "crossbeam-channel", + "dot", + "either", + "expect-test", + "hir", + "ide-assists", + "ide-completion", + "ide-db", + "ide-diagnostics", + "ide-ssr", + "itertools", + "oorandom", + "profile", + "pulldown-cmark", + "pulldown-cmark-to-cmark", + "stdx", + "syntax", + "test-utils", + "text-edit", + "toolchain", + "tracing", + "url", +] + +[[package]] +name = "ide-assists" +version = "0.0.0" +dependencies = [ + "cov-mark", + "either", + "expect-test", + "hir", + "ide-db", + "itertools", + "profile", + "sourcegen", + "stdx", + "syntax", + "test-utils", + "text-edit", +] + +[[package]] +name = "ide-completion" +version = "0.0.0" +dependencies = [ + "base-db", + "cov-mark", + "expect-test", + "hir", + "ide-db", + "itertools", + "once_cell", + "profile", + "smallvec", + "stdx", + "syntax", + "test-utils", + "text-edit", +] + +[[package]] +name = "ide-db" +version = "0.0.0" +dependencies = [ + "arrayvec", + "base-db", + "cov-mark", + "either", + "expect-test", + "fst", + "hir", + "indexmap", + "itertools", + "limit", + "once_cell", + "parser", + "profile", + "rayon", + "rustc-hash", + "sourcegen", + "stdx", + "syntax", + "test-utils", + "text-edit", + "tracing", + "xshell", +] + +[[package]] +name = "ide-diagnostics" +version = "0.0.0" +dependencies = [ + "cfg", + "cov-mark", + "either", + "expect-test", + "hir", + "ide-db", + "itertools", + "profile", + "sourcegen", + "stdx", + "syntax", + "test-utils", + "text-edit", +] + +[[package]] +name = "ide-ssr" +version = "0.0.0" +dependencies = [ + "cov-mark", + "expect-test", + "hir", + "ide-db", + "itertools", + "parser", + "syntax", + "test-utils", + "text-edit", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "jod-thread" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae" + +[[package]] +name = "kqueue" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6112e8f37b59803ac47a42d14f1f3a59bbf72fc6857ffc5be455e28a691f8e" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587" +dependencies = [ + "bitflags", + "libc", +] + +[[package]] +name = "la-arena" +version = "0.3.0" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "libloading" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libmimalloc-sys" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ca136052550448f55df7898c6dbe651c6b574fe38a0d9ea687a9f8088a2e2c" +dependencies = [ + "cc", +] + +[[package]] +name = "limit" +version = "0.0.0" + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "lsp-server" +version = "0.6.0" +dependencies = [ + "crossbeam-channel", + "log", + "lsp-types", + "serde", + "serde_json", +] + +[[package]] +name = "lsp-types" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70c74e2173b2b31f8655d33724b4b45ac13f439386f66290f539c22b144c2212" +dependencies = [ + "bitflags", + "serde", + "serde_json", + "serde_repr", + "url", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "mbe" +version = "0.0.0" +dependencies = [ + "cov-mark", + "parser", + "rustc-hash", + "smallvec", + "stdx", + "syntax", + "test-utils", + "tracing", + "tt", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap2" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5172b50c23043ff43dd53e51392f36519d9b35a8f3a410d30ece5d1aedd58ae" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mimalloc" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f64ad83c969af2e732e907564deb0d0ed393cec4af80776f77dd77a1a427698" +dependencies = [ + "libmimalloc-sys", +] + +[[package]] +name = "miniz_oxide" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.36.1", +] + +[[package]] +name = "miow" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7377f7792b3afb6a3cba68daa54ca23c032137010460d667fda53a8d66be00e" +dependencies = [ + "windows-sys 0.28.0", +] + +[[package]] +name = "notify" +version = "5.0.0-pre.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "553f9844ad0b0824605c20fb55a661679782680410abfb1a8144c2e7e437e7a7" +dependencies = [ + "bitflags", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "mio", + "walkdir", + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +dependencies = [ + "memchr", +] + +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.5", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.3", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys 0.36.1", +] + +[[package]] +name = "parser" +version = "0.0.0" +dependencies = [ + "drop_bomb", + "expect-test", + "limit", + "rustc-ap-rustc_lexer", + "sourcegen", +] + +[[package]] +name = "paste" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" + +[[package]] +name = "paths" +version = "0.0.0" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "perf-event" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5396562cd2eaa828445d6d34258ae21ee1eb9d40fe626ca7f51c8dccb4af9d66" +dependencies = [ + "libc", + "perf-event-open-sys", +] + +[[package]] +name = "perf-event-open-sys" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce9bedf5da2c234fdf2391ede2b90fabf585355f33100689bc364a3ea558561a" +dependencies = [ + "libc", +] + +[[package]] +name = "petgraph" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "proc-macro-api" +version = "0.0.0" +dependencies = [ + "memmap2", + "object 0.29.0", + "paths", + "profile", + "serde", + "serde_json", + "snap", + "stdx", + "tracing", + "tt", +] + +[[package]] +name = "proc-macro-srv" +version = "0.0.0" +dependencies = [ + "crossbeam", + "expect-test", + "libloading", + "mbe", + "memmap2", + "object 0.29.0", + "paths", + "proc-macro-api", + "proc-macro-test", + "tt", +] + +[[package]] +name = "proc-macro-test" +version = "0.0.0" +dependencies = [ + "cargo_metadata", + "proc-macro-test-impl", + "toolchain", +] + +[[package]] +name = "proc-macro-test-impl" +version = "0.0.0" + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profile" +version = "0.0.0" +dependencies = [ + "cfg-if", + "countme", + "la-arena", + "libc", + "once_cell", + "perf-event", + "tikv-jemalloc-ctl", + "winapi", +] + +[[package]] +name = "project-model" +version = "0.0.0" +dependencies = [ + "anyhow", + "base-db", + "cargo_metadata", + "cfg", + "expect-test", + "la-arena", + "paths", + "profile", + "rustc-hash", + "semver", + "serde", + "serde_json", + "stdx", + "toolchain", + "tracing", +] + +[[package]] +name = "pulldown-cmark" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + +[[package]] +name = "pulldown-cmark-to-cmark" +version = "10.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1353ac408192fa925228d3e60ff746167d03f4f7e54835d78ef79e08225d913" +dependencies = [ + "pulldown-cmark", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" + +[[package]] +name = "rowan" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88acf7b001007e9e8c989fe7449f6601d909e5dd2c56399fc158977ad6c56e8" +dependencies = [ + "countme", + "hashbrown", + "memoffset", + "rustc-hash", + "text-size", +] + +[[package]] +name = "rust-analyzer" +version = "0.0.0" +dependencies = [ + "always-assert", + "anyhow", + "cfg", + "crossbeam-channel", + "dissimilar", + "expect-test", + "flycheck", + "hir", + "hir-def", + "hir-ty", + "ide", + "ide-db", + "ide-ssr", + "itertools", + "jod-thread", + "lsp-server", + "lsp-types", + "mbe", + "mimalloc", + "num_cpus", + "oorandom", + "parking_lot 0.12.1", + "proc-macro-api", + "proc-macro-srv", + "profile", + "project-model", + "rayon", + "rustc-hash", + "serde", + "serde_json", + "sourcegen", + "stdx", + "syntax", + "test-utils", + "threadpool", + "tikv-jemallocator", + "toolchain", + "tracing", + "tracing-log", + "tracing-subscriber", + "tracing-tree", + "tt", + "vfs", + "vfs-notify", + "winapi", + "xflags", + "xshell", +] + +[[package]] +name = "rustc-ap-rustc_lexer" +version = "725.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950742ef8a203aa7661aad3ab880438ddeb7f95d4b837c30d65db1a2c5df68e" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "salsa" +version = "0.17.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b223dccb46c32753144d0b51290da7230bb4aedcd8379d6b4c9a474c18bf17a" +dependencies = [ + "crossbeam-utils", + "indexmap", + "lock_api", + "log", + "oorandom", + "parking_lot 0.11.2", + "rustc-hash", + "salsa-macros", + "smallvec", +] + +[[package]] +name = "salsa-macros" +version = "0.17.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac6c2e352df550bf019da7b16164ed2f7fa107c39653d1311d1bba42d1582ff7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "smol_str" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7475118a28b7e3a2e157ce0131ba8c5526ea96e90ee601d9f6bb2e286a35ab44" +dependencies = [ + "serde", +] + +[[package]] +name = "snap" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45456094d1983e2ee2a18fdfebce3189fa451699d0502cb8e3b49dba5ba41451" + +[[package]] +name = "sourcegen" +version = "0.0.0" +dependencies = [ + "xshell", +] + +[[package]] +name = "stdx" +version = "0.0.0" +dependencies = [ + "always-assert", + "backtrace", + "libc", + "miow", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "syntax" +version = "0.0.0" +dependencies = [ + "cov-mark", + "expect-test", + "indexmap", + "itertools", + "once_cell", + "parser", + "proc-macro2", + "profile", + "quote", + "rayon", + "rowan", + "rustc-ap-rustc_lexer", + "rustc-hash", + "smol_str", + "sourcegen", + "stdx", + "test-utils", + "text-edit", + "ungrammar", +] + +[[package]] +name = "test-utils" +version = "0.0.0" +dependencies = [ + "dissimilar", + "profile", + "rustc-hash", + "stdx", + "text-size", +] + +[[package]] +name = "text-edit" +version = "0.0.0" +dependencies = [ + "itertools", + "text-size", +] + +[[package]] +name = "text-size" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a" + +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tikv-jemalloc-ctl" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37706572f4b151dff7a0146e040804e9c26fe3a3118591112f05cf12a4216c1" +dependencies = [ + "libc", + "paste", + "tikv-jemalloc-sys", +] + +[[package]] +name = "tikv-jemalloc-sys" +version = "0.5.1+5.3.0-patched" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "931e876f91fed0827f863a2d153897790da0b24d882c721a79cb3beb0b903261" +dependencies = [ + "cc", + "fs_extra", + "libc", +] + +[[package]] +name = "tikv-jemallocator" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20612db8a13a6c06d57ec83953694185a367e16945f66565e8028d2c0bd76979" +dependencies = [ + "libc", + "tikv-jemalloc-sys", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "toolchain" +version = "0.0.0" +dependencies = [ + "home", +] + +[[package]] +name = "tracing" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59" +dependencies = [ + "matchers", + "once_cell", + "regex", + "sharded-slab", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "tracing-tree" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07e90b329c621ade432823988574e820212648aa40e7a2497777d58de0fb453" +dependencies = [ + "ansi_term", + "atty", + "tracing-core", + "tracing-log", + "tracing-subscriber", +] + +[[package]] +name = "tt" +version = "0.0.0" +dependencies = [ + "smol_str", + "stdx", +] + +[[package]] +name = "typed-arena" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae" + +[[package]] +name = "ungrammar" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e5df347f0bf3ec1d670aad6ca5c6a1859cd9ea61d2113125794654ccced68f" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "unicode-normalization" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" + +[[package]] +name = "unicode-xid" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", + "serde", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vfs" +version = "0.0.0" +dependencies = [ + "fst", + "indexmap", + "paths", + "rustc-hash", +] + +[[package]] +name = "vfs-notify" +version = "0.0.0" +dependencies = [ + "crossbeam-channel", + "jod-thread", + "notify", + "paths", + "tracing", + "vfs", + "walkdir", +] + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82ca39602d5cbfa692c4b67e3bcbb2751477355141c1ed434c94da4186836ff6" +dependencies = [ + "windows_aarch64_msvc 0.28.0", + "windows_i686_gnu 0.28.0", + "windows_i686_msvc 0.28.0", + "windows_x86_64_gnu 0.28.0", + "windows_x86_64_msvc 0.28.0", +] + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "write-json" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06069a848f95fceae3e5e03c0ddc8cb78452b56654ee0c8e68f938cf790fb9e3" + +[[package]] +name = "xflags" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f14fe1ed41a5a2b5ef3f565586c4a8a559ee55d3953faab360a771135bdee00" +dependencies = [ + "xflags-macros", +] + +[[package]] +name = "xflags-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45d11d5fc2a97287eded8b170ca80533b3c42646dd7fa386a5eb045817921022" + +[[package]] +name = "xshell" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d47097dc5c85234b1e41851b3422dd6d19b3befdd35b4ae5ce386724aeca981" +dependencies = [ + "xshell-macros", +] + +[[package]] +name = "xshell-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88301b56c26dd9bf5c43d858538f82d6f3f7764767defbc5d34e59459901c41a" + +[[package]] +name = "xtask" +version = "0.1.0" +dependencies = [ + "anyhow", + "flate2", + "write-json", + "xflags", + "xshell", +] diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml new file mode 100644 index 0000000000000..6b68ca823894f --- /dev/null +++ b/src/tools/rust-analyzer/Cargo.toml @@ -0,0 +1,33 @@ +[workspace] +members = ["xtask/", "lib/*", "crates/*"] +exclude = ["crates/proc-macro-test/imp"] + +[profile.dev] +# Disabling debug info speeds up builds a bunch, +# and we don't rely on it for debugging that much. +debug = 0 + +[profile.dev.package] +# These speed up local tests. +rowan.opt-level = 3 +rustc-hash.opt-level = 3 +smol_str.opt-level = 3 +text-size.opt-level = 3 +# This speeds up `cargo xtask dist`. +miniz_oxide.opt-level = 3 + +[profile.release] +incremental = true +# Set this to 1 or 2 to get more useful backtraces in debugger. +debug = 0 + +[patch.'crates-io'] +# rowan = { path = "../rowan" } + +# chalk-solve = { path = "../chalk/chalk-solve" } +# chalk-ir = { path = "../chalk/chalk-ir" } +# chalk-recursive = { path = "../chalk/chalk-recursive" } + +# ungrammar = { path = "../ungrammar" } + +# salsa = { path = "../salsa" } diff --git a/src/tools/rust-analyzer/LICENSE-APACHE b/src/tools/rust-analyzer/LICENSE-APACHE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/src/tools/rust-analyzer/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/tools/rust-analyzer/LICENSE-MIT b/src/tools/rust-analyzer/LICENSE-MIT new file mode 100644 index 0000000000000..31aa79387f27e --- /dev/null +++ b/src/tools/rust-analyzer/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/tools/rust-analyzer/PRIVACY.md b/src/tools/rust-analyzer/PRIVACY.md new file mode 100644 index 0000000000000..89e252be731d0 --- /dev/null +++ b/src/tools/rust-analyzer/PRIVACY.md @@ -0,0 +1 @@ +See the [Privacy](https://rust-analyzer.github.io/manual.html#privacy) section of the user manual. diff --git a/src/tools/rust-analyzer/README.md b/src/tools/rust-analyzer/README.md new file mode 100644 index 0000000000000..8bb0517ed5abb --- /dev/null +++ b/src/tools/rust-analyzer/README.md @@ -0,0 +1,49 @@ +

+ rust-analyzer logo +

+ +rust-analyzer is a modular compiler frontend for the Rust language. +It is a part of a larger rls-2.0 effort to create excellent IDE support for Rust. + +## Quick Start + +https://rust-analyzer.github.io/manual.html#installation + +## Documentation + +If you want to **contribute** to rust-analyzer or are just curious about how +things work under the hood, check the [./docs/dev](./docs/dev) folder. + +If you want to **use** rust-analyzer's language server with your editor of +choice, check [the manual](https://rust-analyzer.github.io/manual.html) folder. +It also contains some tips & tricks to help you be more productive when using rust-analyzer. + +## Security and Privacy + +See the corresponding sections of [the manual](https://rust-analyzer.github.io/manual.html#security). + +## Communication + +For usage and troubleshooting requests, please use "IDEs and Editors" category of the Rust forum: + +https://users.rust-lang.org/c/ide/14 + +For questions about development and implementation, join rust-analyzer working group on Zulip: + +https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer + +## Quick Links + +* Website: https://rust-analyzer.github.io/ +* Metrics: https://rust-analyzer.github.io/metrics/ +* API docs: https://rust-lang.github.io/rust-analyzer/ide/ +* Changelog: https://rust-analyzer.github.io/thisweek + +## License + +Rust analyzer is primarily distributed under the terms of both the MIT +license and the Apache License (Version 2.0). + +See LICENSE-APACHE and LICENSE-MIT for details. diff --git a/src/tools/rust-analyzer/assets/logo-square.svg b/src/tools/rust-analyzer/assets/logo-square.svg new file mode 100644 index 0000000000000..fe1c1fa02271b --- /dev/null +++ b/src/tools/rust-analyzer/assets/logo-square.svg @@ -0,0 +1,88 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/tools/rust-analyzer/assets/logo-wide.svg b/src/tools/rust-analyzer/assets/logo-wide.svg new file mode 100644 index 0000000000000..c5fb55b36a899 --- /dev/null +++ b/src/tools/rust-analyzer/assets/logo-wide.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/tools/rust-analyzer/bench_data/glorious_old_parser b/src/tools/rust-analyzer/bench_data/glorious_old_parser new file mode 100644 index 0000000000000..7e900dfeb1eeb --- /dev/null +++ b/src/tools/rust-analyzer/bench_data/glorious_old_parser @@ -0,0 +1,8562 @@ +use crate::ast::{AngleBracketedArgs, ParenthesizedArgs, AttrStyle, BareFnTy}; +use crate::ast::{GenericBound, TraitBoundModifier}; +use crate::ast::Unsafety; +use crate::ast::{Mod, AnonConst, Arg, Arm, Guard, Attribute, BindingMode, TraitItemKind}; +use crate::ast::Block; +use crate::ast::{BlockCheckMode, CaptureBy, Movability}; +use crate::ast::{Constness, Crate}; +use crate::ast::Defaultness; +use crate::ast::EnumDef; +use crate::ast::{Expr, ExprKind, RangeLimits}; +use crate::ast::{Field, FnDecl, FnHeader}; +use crate::ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; +use crate::ast::{GenericParam, GenericParamKind}; +use crate::ast::GenericArg; +use crate::ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind}; +use crate::ast::{Label, Lifetime, Lit, LitKind}; +use crate::ast::Local; +use crate::ast::MacStmtStyle; +use crate::ast::{Mac, Mac_, MacDelimiter}; +use crate::ast::{MutTy, Mutability}; +use crate::ast::{Pat, PatKind, PathSegment}; +use crate::ast::{PolyTraitRef, QSelf}; +use crate::ast::{Stmt, StmtKind}; +use crate::ast::{VariantData, StructField}; +use crate::ast::StrStyle; +use crate::ast::SelfKind; +use crate::ast::{TraitItem, TraitRef, TraitObjectSyntax}; +use crate::ast::{Ty, TyKind, TypeBinding, GenericBounds}; +use crate::ast::{Visibility, VisibilityKind, WhereClause, CrateSugar}; +use crate::ast::{UseTree, UseTreeKind}; +use crate::ast::{BinOpKind, UnOp}; +use crate::ast::{RangeEnd, RangeSyntax}; +use crate::{ast, attr}; +use crate::ext::base::DummyResult; +use crate::source_map::{self, SourceMap, Spanned, respan}; +use crate::parse::{self, SeqSep, classify, token}; +use crate::parse::lexer::{TokenAndSpan, UnmatchedBrace}; +use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; +use crate::parse::token::DelimToken; +use crate::parse::{new_sub_parser_from_file, ParseSess, Directory, DirectoryOwnership}; +use crate::util::parser::{AssocOp, Fixity}; +use crate::print::pprust; +use crate::ptr::P; +use crate::parse::PResult; +use crate::ThinVec; +use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; +use crate::symbol::{Symbol, keywords}; + +use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use rustc_target::spec::abi::{self, Abi}; +use syntax_pos::{Span, MultiSpan, BytePos, FileName}; +use log::{debug, trace}; + +use std::borrow::Cow; +use std::cmp; +use std::mem; +use std::path::{self, Path, PathBuf}; +use std::slice; + +#[derive(Debug)] +/// Whether the type alias or associated type is a concrete type or an existential type +pub enum AliasKind { + /// Just a new name for the same type + Weak(P), + /// Only trait impls of the type will be usable, not the actual type itself + Existential(GenericBounds), +} + +bitflags::bitflags! { + struct Restrictions: u8 { + const STMT_EXPR = 1 << 0; + const NO_STRUCT_LITERAL = 1 << 1; + } +} + +type ItemInfo = (Ident, ItemKind, Option>); + +/// Specifies how to parse a path. +#[derive(Copy, Clone, PartialEq)] +pub enum PathStyle { + /// In some contexts, notably in expressions, paths with generic arguments are ambiguous + /// with something else. For example, in expressions `segment < ....` can be interpreted + /// as a comparison and `segment ( ....` can be interpreted as a function call. + /// In all such contexts the non-path interpretation is preferred by default for practical + /// reasons, but the path interpretation can be forced by the disambiguator `::`, e.g. + /// `x` - comparisons, `x::` - unambiguously a path. + Expr, + /// In other contexts, notably in types, no ambiguity exists and paths can be written + /// without the disambiguator, e.g., `x` - unambiguously a path. + /// Paths with disambiguators are still accepted, `x::` - unambiguously a path too. + Type, + /// A path with generic arguments disallowed, e.g., `foo::bar::Baz`, used in imports, + /// visibilities or attributes. + /// Technically, this variant is unnecessary and e.g., `Expr` can be used instead + /// (paths in "mod" contexts have to be checked later for absence of generic arguments + /// anyway, due to macros), but it is used to avoid weird suggestions about expected + /// tokens when something goes wrong. + Mod, +} + +#[derive(Clone, Copy, PartialEq, Debug)] +enum SemiColonMode { + Break, + Ignore, + Comma, +} + +#[derive(Clone, Copy, PartialEq, Debug)] +enum BlockMode { + Break, + Ignore, +} + +/// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression +/// dropped into the token stream, which happens while parsing the result of +/// macro expansion). Placement of these is not as complex as I feared it would +/// be. The important thing is to make sure that lookahead doesn't balk at +/// `token::Interpolated` tokens. +macro_rules! maybe_whole_expr { + ($p:expr) => { + if let token::Interpolated(nt) = $p.token.clone() { + match *nt { + token::NtExpr(ref e) | token::NtLiteral(ref e) => { + $p.bump(); + return Ok((*e).clone()); + } + token::NtPath(ref path) => { + $p.bump(); + let span = $p.span; + let kind = ExprKind::Path(None, (*path).clone()); + return Ok($p.mk_expr(span, kind, ThinVec::new())); + } + token::NtBlock(ref block) => { + $p.bump(); + let span = $p.span; + let kind = ExprKind::Block((*block).clone(), None); + return Ok($p.mk_expr(span, kind, ThinVec::new())); + } + _ => {}, + }; + } + } +} + +/// As maybe_whole_expr, but for things other than expressions +macro_rules! maybe_whole { + ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { + if let token::Interpolated(nt) = $p.token.clone() { + if let token::$constructor($x) = (*nt).clone() { + $p.bump(); + return Ok($e); + } + } + }; +} + +fn maybe_append(mut lhs: Vec, mut rhs: Option>) -> Vec { + if let Some(ref mut rhs) = rhs { + lhs.append(rhs); + } + lhs +} + +#[derive(Debug, Clone, Copy, PartialEq)] +enum PrevTokenKind { + DocComment, + Comma, + Plus, + Interpolated, + Eof, + Ident, + Other, +} + +trait RecoverQPath: Sized { + const PATH_STYLE: PathStyle = PathStyle::Expr; + fn to_ty(&self) -> Option>; + fn to_recovered(&self, qself: Option, path: ast::Path) -> Self; + fn to_string(&self) -> String; +} + +impl RecoverQPath for Ty { + const PATH_STYLE: PathStyle = PathStyle::Type; + fn to_ty(&self) -> Option> { + Some(P(self.clone())) + } + fn to_recovered(&self, qself: Option, path: ast::Path) -> Self { + Self { span: path.span, node: TyKind::Path(qself, path), id: self.id } + } + fn to_string(&self) -> String { + pprust::ty_to_string(self) + } +} + +impl RecoverQPath for Pat { + fn to_ty(&self) -> Option> { + self.to_ty() + } + fn to_recovered(&self, qself: Option, path: ast::Path) -> Self { + Self { span: path.span, node: PatKind::Path(qself, path), id: self.id } + } + fn to_string(&self) -> String { + pprust::pat_to_string(self) + } +} + +impl RecoverQPath for Expr { + fn to_ty(&self) -> Option> { + self.to_ty() + } + fn to_recovered(&self, qself: Option, path: ast::Path) -> Self { + Self { span: path.span, node: ExprKind::Path(qself, path), + id: self.id, attrs: self.attrs.clone() } + } + fn to_string(&self) -> String { + pprust::expr_to_string(self) + } +} + +/* ident is handled by common.rs */ + +#[derive(Clone)] +pub struct Parser<'a> { + pub sess: &'a ParseSess, + /// the current token: + pub token: token::Token, + /// the span of the current token: + pub span: Span, + /// the span of the previous token: + meta_var_span: Option, + pub prev_span: Span, + /// the previous token kind + prev_token_kind: PrevTokenKind, + restrictions: Restrictions, + /// Used to determine the path to externally loaded source files + crate directory: Directory<'a>, + /// Whether to parse sub-modules in other files. + pub recurse_into_file_modules: bool, + /// Name of the root module this parser originated from. If `None`, then the + /// name is not known. This does not change while the parser is descending + /// into modules, and sub-parsers have new values for this name. + pub root_module_name: Option, + crate expected_tokens: Vec, + token_cursor: TokenCursor, + desugar_doc_comments: bool, + /// Whether we should configure out of line modules as we parse. + pub cfg_mods: bool, + /// This field is used to keep track of how many left angle brackets we have seen. This is + /// required in order to detect extra leading left angle brackets (`<` characters) and error + /// appropriately. + /// + /// See the comments in the `parse_path_segment` function for more details. + crate unmatched_angle_bracket_count: u32, + crate max_angle_bracket_count: u32, + /// List of all unclosed delimiters found by the lexer. If an entry is used for error recovery + /// it gets removed from here. Every entry left at the end gets emitted as an independent + /// error. + crate unclosed_delims: Vec, +} + + +#[derive(Clone)] +struct TokenCursor { + frame: TokenCursorFrame, + stack: Vec, +} + +#[derive(Clone)] +struct TokenCursorFrame { + delim: token::DelimToken, + span: DelimSpan, + open_delim: bool, + tree_cursor: tokenstream::Cursor, + close_delim: bool, + last_token: LastToken, +} + +/// This is used in `TokenCursorFrame` above to track tokens that are consumed +/// by the parser, and then that's transitively used to record the tokens that +/// each parse AST item is created with. +/// +/// Right now this has two states, either collecting tokens or not collecting +/// tokens. If we're collecting tokens we just save everything off into a local +/// `Vec`. This should eventually though likely save tokens from the original +/// token stream and just use slicing of token streams to avoid creation of a +/// whole new vector. +/// +/// The second state is where we're passively not recording tokens, but the last +/// token is still tracked for when we want to start recording tokens. This +/// "last token" means that when we start recording tokens we'll want to ensure +/// that this, the first token, is included in the output. +/// +/// You can find some more example usage of this in the `collect_tokens` method +/// on the parser. +#[derive(Clone)] +enum LastToken { + Collecting(Vec), + Was(Option), +} + +impl TokenCursorFrame { + fn new(sp: DelimSpan, delim: DelimToken, tts: &TokenStream) -> Self { + TokenCursorFrame { + delim: delim, + span: sp, + open_delim: delim == token::NoDelim, + tree_cursor: tts.clone().into_trees(), + close_delim: delim == token::NoDelim, + last_token: LastToken::Was(None), + } + } +} + +impl TokenCursor { + fn next(&mut self) -> TokenAndSpan { + loop { + let tree = if !self.frame.open_delim { + self.frame.open_delim = true; + TokenTree::open_tt(self.frame.span.open, self.frame.delim) + } else if let Some(tree) = self.frame.tree_cursor.next() { + tree + } else if !self.frame.close_delim { + self.frame.close_delim = true; + TokenTree::close_tt(self.frame.span.close, self.frame.delim) + } else if let Some(frame) = self.stack.pop() { + self.frame = frame; + continue + } else { + return TokenAndSpan { tok: token::Eof, sp: syntax_pos::DUMMY_SP } + }; + + match self.frame.last_token { + LastToken::Collecting(ref mut v) => v.push(tree.clone().into()), + LastToken::Was(ref mut t) => *t = Some(tree.clone().into()), + } + + match tree { + TokenTree::Token(sp, tok) => return TokenAndSpan { tok: tok, sp: sp }, + TokenTree::Delimited(sp, delim, tts) => { + let frame = TokenCursorFrame::new(sp, delim, &tts); + self.stack.push(mem::replace(&mut self.frame, frame)); + } + } + } + } + + fn next_desugared(&mut self) -> TokenAndSpan { + let (sp, name) = match self.next() { + TokenAndSpan { sp, tok: token::DocComment(name) } => (sp, name), + tok => return tok, + }; + + let stripped = strip_doc_comment_decoration(&name.as_str()); + + // Searches for the occurrences of `"#*` and returns the minimum number of `#`s + // required to wrap the text. + let mut num_of_hashes = 0; + let mut count = 0; + for ch in stripped.chars() { + count = match ch { + '"' => 1, + '#' if count > 0 => count + 1, + _ => 0, + }; + num_of_hashes = cmp::max(num_of_hashes, count); + } + + let delim_span = DelimSpan::from_single(sp); + let body = TokenTree::Delimited( + delim_span, + token::Bracket, + [TokenTree::Token(sp, token::Ident(ast::Ident::from_str("doc"), false)), + TokenTree::Token(sp, token::Eq), + TokenTree::Token(sp, token::Literal( + token::StrRaw(Symbol::intern(&stripped), num_of_hashes), None)) + ] + .iter().cloned().collect::().into(), + ); + + self.stack.push(mem::replace(&mut self.frame, TokenCursorFrame::new( + delim_span, + token::NoDelim, + &if doc_comment_style(&name.as_str()) == AttrStyle::Inner { + [TokenTree::Token(sp, token::Pound), TokenTree::Token(sp, token::Not), body] + .iter().cloned().collect::().into() + } else { + [TokenTree::Token(sp, token::Pound), body] + .iter().cloned().collect::().into() + }, + ))); + + self.next() + } +} + +#[derive(Clone, PartialEq)] +crate enum TokenType { + Token(token::Token), + Keyword(keywords::Keyword), + Operator, + Lifetime, + Ident, + Path, + Type, + Const, +} + +impl TokenType { + fn to_string(&self) -> String { + match *self { + TokenType::Token(ref t) => format!("`{}`", pprust::token_to_string(t)), + TokenType::Keyword(kw) => format!("`{}`", kw.name()), + TokenType::Operator => "an operator".to_string(), + TokenType::Lifetime => "lifetime".to_string(), + TokenType::Ident => "identifier".to_string(), + TokenType::Path => "path".to_string(), + TokenType::Type => "type".to_string(), + TokenType::Const => "const".to_string(), + } + } +} + +/// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT`, +/// `IDENT<::AssocTy>`. +/// +/// Types can also be of the form `IDENT(u8, u8) -> u8`, however this assumes +/// that `IDENT` is not the ident of a fn trait. +fn can_continue_type_after_non_fn_ident(t: &token::Token) -> bool { + t == &token::ModSep || t == &token::Lt || + t == &token::BinOp(token::Shl) +} + +/// Information about the path to a module. +pub struct ModulePath { + name: String, + path_exists: bool, + pub result: Result, +} + +pub struct ModulePathSuccess { + pub path: PathBuf, + pub directory_ownership: DirectoryOwnership, + warn: bool, +} + +pub enum Error { + FileNotFoundForModule { + mod_name: String, + default_path: String, + secondary_path: String, + dir_path: String, + }, + DuplicatePaths { + mod_name: String, + default_path: String, + secondary_path: String, + }, + UselessDocComment, + InclusiveRangeWithNoEnd, +} + +impl Error { + fn span_err>(self, + sp: S, + handler: &errors::Handler) -> DiagnosticBuilder<'_> { + match self { + Error::FileNotFoundForModule { ref mod_name, + ref default_path, + ref secondary_path, + ref dir_path } => { + let mut err = struct_span_err!(handler, sp, E0583, + "file not found for module `{}`", mod_name); + err.help(&format!("name the file either {} or {} inside the directory \"{}\"", + default_path, + secondary_path, + dir_path)); + err + } + Error::DuplicatePaths { ref mod_name, ref default_path, ref secondary_path } => { + let mut err = struct_span_err!(handler, sp, E0584, + "file for module `{}` found at both {} and {}", + mod_name, + default_path, + secondary_path); + err.help("delete or rename one of them to remove the ambiguity"); + err + } + Error::UselessDocComment => { + let mut err = struct_span_err!(handler, sp, E0585, + "found a documentation comment that doesn't document anything"); + err.help("doc comments must come before what they document, maybe a comment was \ + intended with `//`?"); + err + } + Error::InclusiveRangeWithNoEnd => { + let mut err = struct_span_err!(handler, sp, E0586, + "inclusive range with no end"); + err.help("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)"); + err + } + } + } +} + +#[derive(Debug)] +enum LhsExpr { + NotYetParsed, + AttributesParsed(ThinVec), + AlreadyParsed(P), +} + +impl From>> for LhsExpr { + fn from(o: Option>) -> Self { + if let Some(attrs) = o { + LhsExpr::AttributesParsed(attrs) + } else { + LhsExpr::NotYetParsed + } + } +} + +impl From> for LhsExpr { + fn from(expr: P) -> Self { + LhsExpr::AlreadyParsed(expr) + } +} + +/// Creates a placeholder argument. +fn dummy_arg(span: Span) -> Arg { + let ident = Ident::new(keywords::Invalid.name(), span); + let pat = P(Pat { + id: ast::DUMMY_NODE_ID, + node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None), + span, + }); + let ty = Ty { + node: TyKind::Err, + span, + id: ast::DUMMY_NODE_ID + }; + Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID } +} + +#[derive(Copy, Clone, Debug)] +enum TokenExpectType { + Expect, + NoExpect, +} + +impl<'a> Parser<'a> { + pub fn new(sess: &'a ParseSess, + tokens: TokenStream, + directory: Option>, + recurse_into_file_modules: bool, + desugar_doc_comments: bool) + -> Self { + let mut parser = Parser { + sess, + token: token::Whitespace, + span: syntax_pos::DUMMY_SP, + prev_span: syntax_pos::DUMMY_SP, + meta_var_span: None, + prev_token_kind: PrevTokenKind::Other, + restrictions: Restrictions::empty(), + recurse_into_file_modules, + directory: Directory { + path: Cow::from(PathBuf::new()), + ownership: DirectoryOwnership::Owned { relative: None } + }, + root_module_name: None, + expected_tokens: Vec::new(), + token_cursor: TokenCursor { + frame: TokenCursorFrame::new( + DelimSpan::dummy(), + token::NoDelim, + &tokens.into(), + ), + stack: Vec::new(), + }, + desugar_doc_comments, + cfg_mods: true, + unmatched_angle_bracket_count: 0, + max_angle_bracket_count: 0, + unclosed_delims: Vec::new(), + }; + + let tok = parser.next_tok(); + parser.token = tok.tok; + parser.span = tok.sp; + + if let Some(directory) = directory { + parser.directory = directory; + } else if !parser.span.is_dummy() { + if let FileName::Real(mut path) = sess.source_map().span_to_unmapped_path(parser.span) { + path.pop(); + parser.directory.path = Cow::from(path); + } + } + + parser.process_potential_macro_variable(); + parser + } + + fn next_tok(&mut self) -> TokenAndSpan { + let mut next = if self.desugar_doc_comments { + self.token_cursor.next_desugared() + } else { + self.token_cursor.next() + }; + if next.sp.is_dummy() { + // Tweak the location for better diagnostics, but keep syntactic context intact. + next.sp = self.prev_span.with_ctxt(next.sp.ctxt()); + } + next + } + + /// Converts the current token to a string using `self`'s reader. + pub fn this_token_to_string(&self) -> String { + pprust::token_to_string(&self.token) + } + + fn token_descr(&self) -> Option<&'static str> { + Some(match &self.token { + t if t.is_special_ident() => "reserved identifier", + t if t.is_used_keyword() => "keyword", + t if t.is_unused_keyword() => "reserved keyword", + token::DocComment(..) => "doc comment", + _ => return None, + }) + } + + fn this_token_descr(&self) -> String { + if let Some(prefix) = self.token_descr() { + format!("{} `{}`", prefix, self.this_token_to_string()) + } else { + format!("`{}`", self.this_token_to_string()) + } + } + + fn unexpected_last(&self, t: &token::Token) -> PResult<'a, T> { + let token_str = pprust::token_to_string(t); + Err(self.span_fatal(self.prev_span, &format!("unexpected token: `{}`", token_str))) + } + + crate fn unexpected(&mut self) -> PResult<'a, T> { + match self.expect_one_of(&[], &[]) { + Err(e) => Err(e), + Ok(_) => unreachable!(), + } + } + + /// Expects and consumes the token `t`. Signals an error if the next token is not `t`. + pub fn expect(&mut self, t: &token::Token) -> PResult<'a, bool /* recovered */> { + if self.expected_tokens.is_empty() { + if self.token == *t { + self.bump(); + Ok(false) + } else { + let token_str = pprust::token_to_string(t); + let this_token_str = self.this_token_descr(); + let mut err = self.fatal(&format!("expected `{}`, found {}", + token_str, + this_token_str)); + + let sp = if self.token == token::Token::Eof { + // EOF, don't want to point at the following char, but rather the last token + self.prev_span + } else { + self.sess.source_map().next_point(self.prev_span) + }; + let label_exp = format!("expected `{}`", token_str); + match self.recover_closing_delimiter(&[t.clone()], err) { + Err(e) => err = e, + Ok(recovered) => { + return Ok(recovered); + } + } + let cm = self.sess.source_map(); + match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) { + (Ok(ref a), Ok(ref b)) if a.line == b.line => { + // When the spans are in the same line, it means that the only content + // between them is whitespace, point only at the found token. + err.span_label(self.span, label_exp); + } + _ => { + err.span_label(sp, label_exp); + err.span_label(self.span, "unexpected token"); + } + } + Err(err) + } + } else { + self.expect_one_of(slice::from_ref(t), &[]) + } + } + + fn recover_closing_delimiter( + &mut self, + tokens: &[token::Token], + mut err: DiagnosticBuilder<'a>, + ) -> PResult<'a, bool> { + let mut pos = None; + // we want to use the last closing delim that would apply + for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() { + if tokens.contains(&token::CloseDelim(unmatched.expected_delim)) + && Some(self.span) > unmatched.unclosed_span + { + pos = Some(i); + } + } + match pos { + Some(pos) => { + // Recover and assume that the detected unclosed delimiter was meant for + // this location. Emit the diagnostic and act as if the delimiter was + // present for the parser's sake. + + // Don't attempt to recover from this unclosed delimiter more than once. + let unmatched = self.unclosed_delims.remove(pos); + let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim)); + + // We want to suggest the inclusion of the closing delimiter where it makes + // the most sense, which is immediately after the last token: + // + // {foo(bar {}} + // - ^ + // | | + // | help: `)` may belong here (FIXME: #58270) + // | + // unclosed delimiter + if let Some(sp) = unmatched.unclosed_span { + err.span_label(sp, "unclosed delimiter"); + } + err.span_suggestion_short( + self.sess.source_map().next_point(self.prev_span), + &format!("{} may belong here", delim.to_string()), + delim.to_string(), + Applicability::MaybeIncorrect, + ); + err.emit(); + self.expected_tokens.clear(); // reduce errors + Ok(true) + } + _ => Err(err), + } + } + + /// Expect next token to be edible or inedible token. If edible, + /// then consume it; if inedible, then return without consuming + /// anything. Signal a fatal error if next token is unexpected. + pub fn expect_one_of( + &mut self, + edible: &[token::Token], + inedible: &[token::Token], + ) -> PResult<'a, bool /* recovered */> { + fn tokens_to_string(tokens: &[TokenType]) -> String { + let mut i = tokens.iter(); + // This might be a sign we need a connect method on Iterator. + let b = i.next() + .map_or(String::new(), |t| t.to_string()); + i.enumerate().fold(b, |mut b, (i, a)| { + if tokens.len() > 2 && i == tokens.len() - 2 { + b.push_str(", or "); + } else if tokens.len() == 2 && i == tokens.len() - 2 { + b.push_str(" or "); + } else { + b.push_str(", "); + } + b.push_str(&a.to_string()); + b + }) + } + if edible.contains(&self.token) { + self.bump(); + Ok(false) + } else if inedible.contains(&self.token) { + // leave it in the input + Ok(false) + } else { + let mut expected = edible.iter() + .map(|x| TokenType::Token(x.clone())) + .chain(inedible.iter().map(|x| TokenType::Token(x.clone()))) + .chain(self.expected_tokens.iter().cloned()) + .collect::>(); + expected.sort_by_cached_key(|x| x.to_string()); + expected.dedup(); + let expect = tokens_to_string(&expected[..]); + let actual = self.this_token_to_string(); + let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { + let short_expect = if expected.len() > 6 { + format!("{} possible tokens", expected.len()) + } else { + expect.clone() + }; + (format!("expected one of {}, found `{}`", expect, actual), + (self.sess.source_map().next_point(self.prev_span), + format!("expected one of {} here", short_expect))) + } else if expected.is_empty() { + (format!("unexpected token: `{}`", actual), + (self.prev_span, "unexpected token after this".to_string())) + } else { + (format!("expected {}, found `{}`", expect, actual), + (self.sess.source_map().next_point(self.prev_span), + format!("expected {} here", expect))) + }; + let mut err = self.fatal(&msg_exp); + if self.token.is_ident_named("and") { + err.span_suggestion_short( + self.span, + "use `&&` instead of `and` for the boolean operator", + "&&".to_string(), + Applicability::MaybeIncorrect, + ); + } + if self.token.is_ident_named("or") { + err.span_suggestion_short( + self.span, + "use `||` instead of `or` for the boolean operator", + "||".to_string(), + Applicability::MaybeIncorrect, + ); + } + let sp = if self.token == token::Token::Eof { + // This is EOF, don't want to point at the following char, but rather the last token + self.prev_span + } else { + label_sp + }; + match self.recover_closing_delimiter(&expected.iter().filter_map(|tt| match tt { + TokenType::Token(t) => Some(t.clone()), + _ => None, + }).collect::>(), err) { + Err(e) => err = e, + Ok(recovered) => { + return Ok(recovered); + } + } + + let cm = self.sess.source_map(); + match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) { + (Ok(ref a), Ok(ref b)) if a.line == b.line => { + // When the spans are in the same line, it means that the only content between + // them is whitespace, point at the found token in that case: + // + // X | () => { syntax error }; + // | ^^^^^ expected one of 8 possible tokens here + // + // instead of having: + // + // X | () => { syntax error }; + // | -^^^^^ unexpected token + // | | + // | expected one of 8 possible tokens here + err.span_label(self.span, label_exp); + } + _ if self.prev_span == syntax_pos::DUMMY_SP => { + // Account for macro context where the previous span might not be + // available to avoid incorrect output (#54841). + err.span_label(self.span, "unexpected token"); + } + _ => { + err.span_label(sp, label_exp); + err.span_label(self.span, "unexpected token"); + } + } + Err(err) + } + } + + /// Returns the span of expr, if it was not interpolated or the span of the interpolated token. + fn interpolated_or_expr_span(&self, + expr: PResult<'a, P>) + -> PResult<'a, (Span, P)> { + expr.map(|e| { + if self.prev_token_kind == PrevTokenKind::Interpolated { + (self.prev_span, e) + } else { + (e.span, e) + } + }) + } + + fn expected_ident_found(&self) -> DiagnosticBuilder<'a> { + let mut err = self.struct_span_err(self.span, + &format!("expected identifier, found {}", + self.this_token_descr())); + if let token::Ident(ident, false) = &self.token { + if ident.is_reserved() && !ident.is_path_segment_keyword() && + ident.name != keywords::Underscore.name() + { + err.span_suggestion( + self.span, + "you can escape reserved keywords to use them as identifiers", + format!("r#{}", ident), + Applicability::MaybeIncorrect, + ); + } + } + if let Some(token_descr) = self.token_descr() { + err.span_label(self.span, format!("expected identifier, found {}", token_descr)); + } else { + err.span_label(self.span, "expected identifier"); + if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { + err.span_suggestion( + self.span, + "remove this comma", + String::new(), + Applicability::MachineApplicable, + ); + } + } + err + } + + pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { + self.parse_ident_common(true) + } + + fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> { + match self.token { + token::Ident(ident, _) => { + if self.token.is_reserved_ident() { + let mut err = self.expected_ident_found(); + if recover { + err.emit(); + } else { + return Err(err); + } + } + let span = self.span; + self.bump(); + Ok(Ident::new(ident.name, span)) + } + _ => { + Err(if self.prev_token_kind == PrevTokenKind::DocComment { + self.span_fatal_err(self.prev_span, Error::UselessDocComment) + } else { + self.expected_ident_found() + }) + } + } + } + + /// Checks if the next token is `tok`, and returns `true` if so. + /// + /// This method will automatically add `tok` to `expected_tokens` if `tok` is not + /// encountered. + crate fn check(&mut self, tok: &token::Token) -> bool { + let is_present = self.token == *tok; + if !is_present { self.expected_tokens.push(TokenType::Token(tok.clone())); } + is_present + } + + /// Consumes a token 'tok' if it exists. Returns whether the given token was present. + pub fn eat(&mut self, tok: &token::Token) -> bool { + let is_present = self.check(tok); + if is_present { self.bump() } + is_present + } + + fn check_keyword(&mut self, kw: keywords::Keyword) -> bool { + self.expected_tokens.push(TokenType::Keyword(kw)); + self.token.is_keyword(kw) + } + + /// If the next token is the given keyword, eats it and returns + /// `true`. Otherwise, returns `false`. + pub fn eat_keyword(&mut self, kw: keywords::Keyword) -> bool { + if self.check_keyword(kw) { + self.bump(); + true + } else { + false + } + } + + fn eat_keyword_noexpect(&mut self, kw: keywords::Keyword) -> bool { + if self.token.is_keyword(kw) { + self.bump(); + true + } else { + false + } + } + + /// If the given word is not a keyword, signals an error. + /// If the next token is not the given word, signals an error. + /// Otherwise, eats it. + fn expect_keyword(&mut self, kw: keywords::Keyword) -> PResult<'a, ()> { + if !self.eat_keyword(kw) { + self.unexpected() + } else { + Ok(()) + } + } + + fn check_ident(&mut self) -> bool { + if self.token.is_ident() { + true + } else { + self.expected_tokens.push(TokenType::Ident); + false + } + } + + fn check_path(&mut self) -> bool { + if self.token.is_path_start() { + true + } else { + self.expected_tokens.push(TokenType::Path); + false + } + } + + fn check_type(&mut self) -> bool { + if self.token.can_begin_type() { + true + } else { + self.expected_tokens.push(TokenType::Type); + false + } + } + + fn check_const_arg(&mut self) -> bool { + if self.token.can_begin_const_arg() { + true + } else { + self.expected_tokens.push(TokenType::Const); + false + } + } + + /// Expects and consumes a `+`. if `+=` is seen, replaces it with a `=` + /// and continues. If a `+` is not seen, returns `false`. + /// + /// This is used when token-splitting `+=` into `+`. + /// See issue #47856 for an example of when this may occur. + fn eat_plus(&mut self) -> bool { + self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); + match self.token { + token::BinOp(token::Plus) => { + self.bump(); + true + } + token::BinOpEq(token::Plus) => { + let span = self.span.with_lo(self.span.lo() + BytePos(1)); + self.bump_with(token::Eq, span); + true + } + _ => false, + } + } + + + /// Checks to see if the next token is either `+` or `+=`. + /// Otherwise returns `false`. + fn check_plus(&mut self) -> bool { + if self.token.is_like_plus() { + true + } + else { + self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); + false + } + } + + /// Expects and consumes an `&`. If `&&` is seen, replaces it with a single + /// `&` and continues. If an `&` is not seen, signals an error. + fn expect_and(&mut self) -> PResult<'a, ()> { + self.expected_tokens.push(TokenType::Token(token::BinOp(token::And))); + match self.token { + token::BinOp(token::And) => { + self.bump(); + Ok(()) + } + token::AndAnd => { + let span = self.span.with_lo(self.span.lo() + BytePos(1)); + Ok(self.bump_with(token::BinOp(token::And), span)) + } + _ => self.unexpected() + } + } + + /// Expects and consumes an `|`. If `||` is seen, replaces it with a single + /// `|` and continues. If an `|` is not seen, signals an error. + fn expect_or(&mut self) -> PResult<'a, ()> { + self.expected_tokens.push(TokenType::Token(token::BinOp(token::Or))); + match self.token { + token::BinOp(token::Or) => { + self.bump(); + Ok(()) + } + token::OrOr => { + let span = self.span.with_lo(self.span.lo() + BytePos(1)); + Ok(self.bump_with(token::BinOp(token::Or), span)) + } + _ => self.unexpected() + } + } + + fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option) { + match suffix { + None => {/* everything ok */} + Some(suf) => { + let text = suf.as_str(); + if text.is_empty() { + self.span_bug(sp, "found empty literal suffix in Some") + } + let msg = format!("{} with a suffix is invalid", kind); + self.struct_span_err(sp, &msg) + .span_label(sp, msg) + .emit(); + } + } + } + + /// Attempts to consume a `<`. If `<<` is seen, replaces it with a single + /// `<` and continue. If `<-` is seen, replaces it with a single `<` + /// and continue. If a `<` is not seen, returns false. + /// + /// This is meant to be used when parsing generics on a path to get the + /// starting token. + fn eat_lt(&mut self) -> bool { + self.expected_tokens.push(TokenType::Token(token::Lt)); + let ate = match self.token { + token::Lt => { + self.bump(); + true + } + token::BinOp(token::Shl) => { + let span = self.span.with_lo(self.span.lo() + BytePos(1)); + self.bump_with(token::Lt, span); + true + } + token::LArrow => { + let span = self.span.with_lo(self.span.lo() + BytePos(1)); + self.bump_with(token::BinOp(token::Minus), span); + true + } + _ => false, + }; + + if ate { + // See doc comment for `unmatched_angle_bracket_count`. + self.unmatched_angle_bracket_count += 1; + self.max_angle_bracket_count += 1; + debug!("eat_lt: (increment) count={:?}", self.unmatched_angle_bracket_count); + } + + ate + } + + fn expect_lt(&mut self) -> PResult<'a, ()> { + if !self.eat_lt() { + self.unexpected() + } else { + Ok(()) + } + } + + /// Expects and consumes a single `>` token. if a `>>` is seen, replaces it + /// with a single `>` and continues. If a `>` is not seen, signals an error. + fn expect_gt(&mut self) -> PResult<'a, ()> { + self.expected_tokens.push(TokenType::Token(token::Gt)); + let ate = match self.token { + token::Gt => { + self.bump(); + Some(()) + } + token::BinOp(token::Shr) => { + let span = self.span.with_lo(self.span.lo() + BytePos(1)); + Some(self.bump_with(token::Gt, span)) + } + token::BinOpEq(token::Shr) => { + let span = self.span.with_lo(self.span.lo() + BytePos(1)); + Some(self.bump_with(token::Ge, span)) + } + token::Ge => { + let span = self.span.with_lo(self.span.lo() + BytePos(1)); + Some(self.bump_with(token::Eq, span)) + } + _ => None, + }; + + match ate { + Some(_) => { + // See doc comment for `unmatched_angle_bracket_count`. + if self.unmatched_angle_bracket_count > 0 { + self.unmatched_angle_bracket_count -= 1; + debug!("expect_gt: (decrement) count={:?}", self.unmatched_angle_bracket_count); + } + + Ok(()) + }, + None => self.unexpected(), + } + } + + /// Eats and discards tokens until one of `kets` is encountered. Respects token trees, + /// passes through any errors encountered. Used for error recovery. + fn eat_to_tokens(&mut self, kets: &[&token::Token]) { + let handler = self.diagnostic(); + + if let Err(ref mut err) = self.parse_seq_to_before_tokens(kets, + SeqSep::none(), + TokenExpectType::Expect, + |p| Ok(p.parse_token_tree())) { + handler.cancel(err); + } + } + + /// Parses a sequence, including the closing delimiter. The function + /// `f` must consume tokens until reaching the next separator or + /// closing bracket. + pub fn parse_seq_to_end(&mut self, + ket: &token::Token, + sep: SeqSep, + f: F) + -> PResult<'a, Vec> where + F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, + { + let (val, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; + if !recovered { + self.bump(); + } + Ok(val) + } + + /// Parses a sequence, not including the closing delimiter. The function + /// `f` must consume tokens until reaching the next separator or + /// closing bracket. + pub fn parse_seq_to_before_end( + &mut self, + ket: &token::Token, + sep: SeqSep, + f: F, + ) -> PResult<'a, (Vec, bool)> + where F: FnMut(&mut Parser<'a>) -> PResult<'a, T> + { + self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f) + } + + fn parse_seq_to_before_tokens( + &mut self, + kets: &[&token::Token], + sep: SeqSep, + expect: TokenExpectType, + mut f: F, + ) -> PResult<'a, (Vec, bool /* recovered */)> + where F: FnMut(&mut Parser<'a>) -> PResult<'a, T> + { + let mut first = true; + let mut recovered = false; + let mut v = vec![]; + while !kets.iter().any(|k| { + match expect { + TokenExpectType::Expect => self.check(k), + TokenExpectType::NoExpect => self.token == **k, + } + }) { + match self.token { + token::CloseDelim(..) | token::Eof => break, + _ => {} + }; + if let Some(ref t) = sep.sep { + if first { + first = false; + } else { + match self.expect(t) { + Ok(false) => {} + Ok(true) => { + recovered = true; + break; + } + Err(mut e) => { + // Attempt to keep parsing if it was a similar separator + if let Some(ref tokens) = t.similar_tokens() { + if tokens.contains(&self.token) { + self.bump(); + } + } + e.emit(); + // Attempt to keep parsing if it was an omitted separator + match f(self) { + Ok(t) => { + v.push(t); + continue; + }, + Err(mut e) => { + e.cancel(); + break; + } + } + } + } + } + } + if sep.trailing_sep_allowed && kets.iter().any(|k| { + match expect { + TokenExpectType::Expect => self.check(k), + TokenExpectType::NoExpect => self.token == **k, + } + }) { + break; + } + + let t = f(self)?; + v.push(t); + } + + Ok((v, recovered)) + } + + /// Parses a sequence, including the closing delimiter. The function + /// `f` must consume tokens until reaching the next separator or + /// closing bracket. + fn parse_unspanned_seq( + &mut self, + bra: &token::Token, + ket: &token::Token, + sep: SeqSep, + f: F, + ) -> PResult<'a, Vec> where + F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, + { + self.expect(bra)?; + let (result, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; + if !recovered { + self.eat(ket); + } + Ok(result) + } + + /// Advance the parser by one token + pub fn bump(&mut self) { + if self.prev_token_kind == PrevTokenKind::Eof { + // Bumping after EOF is a bad sign, usually an infinite loop. + self.bug("attempted to bump the parser past EOF (may be stuck in a loop)"); + } + + self.prev_span = self.meta_var_span.take().unwrap_or(self.span); + + // Record last token kind for possible error recovery. + self.prev_token_kind = match self.token { + token::DocComment(..) => PrevTokenKind::DocComment, + token::Comma => PrevTokenKind::Comma, + token::BinOp(token::Plus) => PrevTokenKind::Plus, + token::Interpolated(..) => PrevTokenKind::Interpolated, + token::Eof => PrevTokenKind::Eof, + token::Ident(..) => PrevTokenKind::Ident, + _ => PrevTokenKind::Other, + }; + + let next = self.next_tok(); + self.span = next.sp; + self.token = next.tok; + self.expected_tokens.clear(); + // check after each token + self.process_potential_macro_variable(); + } + + /// Advance the parser using provided token as a next one. Use this when + /// consuming a part of a token. For example a single `<` from `<<`. + fn bump_with(&mut self, next: token::Token, span: Span) { + self.prev_span = self.span.with_hi(span.lo()); + // It would be incorrect to record the kind of the current token, but + // fortunately for tokens currently using `bump_with`, the + // prev_token_kind will be of no use anyway. + self.prev_token_kind = PrevTokenKind::Other; + self.span = span; + self.token = next; + self.expected_tokens.clear(); + } + + pub fn look_ahead(&self, dist: usize, f: F) -> R where + F: FnOnce(&token::Token) -> R, + { + if dist == 0 { + return f(&self.token) + } + + f(&match self.token_cursor.frame.tree_cursor.look_ahead(dist - 1) { + Some(tree) => match tree { + TokenTree::Token(_, tok) => tok, + TokenTree::Delimited(_, delim, _) => token::OpenDelim(delim), + }, + None => token::CloseDelim(self.token_cursor.frame.delim), + }) + } + + fn look_ahead_span(&self, dist: usize) -> Span { + if dist == 0 { + return self.span + } + + match self.token_cursor.frame.tree_cursor.look_ahead(dist - 1) { + Some(TokenTree::Token(span, _)) => span, + Some(TokenTree::Delimited(span, ..)) => span.entire(), + None => self.look_ahead_span(dist - 1), + } + } + pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> { + self.sess.span_diagnostic.struct_span_fatal(self.span, m) + } + pub fn span_fatal>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { + self.sess.span_diagnostic.struct_span_fatal(sp, m) + } + fn span_fatal_err>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> { + err.span_err(sp, self.diagnostic()) + } + fn bug(&self, m: &str) -> ! { + self.sess.span_diagnostic.span_bug(self.span, m) + } + fn span_err>(&self, sp: S, m: &str) { + self.sess.span_diagnostic.span_err(sp, m) + } + fn struct_span_err>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { + self.sess.span_diagnostic.struct_span_err(sp, m) + } + crate fn span_bug>(&self, sp: S, m: &str) -> ! { + self.sess.span_diagnostic.span_bug(sp, m) + } + + fn cancel(&self, err: &mut DiagnosticBuilder<'_>) { + self.sess.span_diagnostic.cancel(err) + } + + crate fn diagnostic(&self) -> &'a errors::Handler { + &self.sess.span_diagnostic + } + + /// Is the current token one of the keywords that signals a bare function type? + fn token_is_bare_fn_keyword(&mut self) -> bool { + self.check_keyword(keywords::Fn) || + self.check_keyword(keywords::Unsafe) || + self.check_keyword(keywords::Extern) + } + + /// Parses a `TyKind::BareFn` type. + fn parse_ty_bare_fn(&mut self, generic_params: Vec) -> PResult<'a, TyKind> { + /* + + [unsafe] [extern "ABI"] fn (S) -> T + ^~~~^ ^~~~^ ^~^ ^ + | | | | + | | | Return type + | | Argument types + | | + | ABI + Function Style + */ + + let unsafety = self.parse_unsafety(); + let abi = if self.eat_keyword(keywords::Extern) { + self.parse_opt_abi()?.unwrap_or(Abi::C) + } else { + Abi::Rust + }; + + self.expect_keyword(keywords::Fn)?; + let (inputs, variadic) = self.parse_fn_args(false, true)?; + let ret_ty = self.parse_ret_ty(false)?; + let decl = P(FnDecl { + inputs, + output: ret_ty, + variadic, + }); + Ok(TyKind::BareFn(P(BareFnTy { + abi, + unsafety, + generic_params, + decl, + }))) + } + + /// Parses asyncness: `async` or nothing. + fn parse_asyncness(&mut self) -> IsAsync { + if self.eat_keyword(keywords::Async) { + IsAsync::Async { + closure_id: ast::DUMMY_NODE_ID, + return_impl_trait_id: ast::DUMMY_NODE_ID, + } + } else { + IsAsync::NotAsync + } + } + + /// Parses unsafety: `unsafe` or nothing. + fn parse_unsafety(&mut self) -> Unsafety { + if self.eat_keyword(keywords::Unsafe) { + Unsafety::Unsafe + } else { + Unsafety::Normal + } + } + + /// Parses the items in a trait declaration. + pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> { + maybe_whole!(self, NtTraitItem, |x| x); + let attrs = self.parse_outer_attributes()?; + let (mut item, tokens) = self.collect_tokens(|this| { + this.parse_trait_item_(at_end, attrs) + })?; + // See `parse_item` for why this clause is here. + if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { + item.tokens = Some(tokens); + } + Ok(item) + } + + fn parse_trait_item_(&mut self, + at_end: &mut bool, + mut attrs: Vec) -> PResult<'a, TraitItem> { + let lo = self.span; + + let (name, node, generics) = if self.eat_keyword(keywords::Type) { + self.parse_trait_item_assoc_ty()? + } else if self.is_const_item() { + self.expect_keyword(keywords::Const)?; + let ident = self.parse_ident()?; + self.expect(&token::Colon)?; + let ty = self.parse_ty()?; + let default = if self.eat(&token::Eq) { + let expr = self.parse_expr()?; + self.expect(&token::Semi)?; + Some(expr) + } else { + self.expect(&token::Semi)?; + None + }; + (ident, TraitItemKind::Const(ty, default), ast::Generics::default()) + } else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? { + // trait item macro. + (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default()) + } else { + let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; + + let ident = self.parse_ident()?; + let mut generics = self.parse_generics()?; + + let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| { + // This is somewhat dubious; We don't want to allow + // argument names to be left off if there is a + // definition... + + // We don't allow argument names to be left off in edition 2018. + p.parse_arg_general(p.span.rust_2018(), true) + })?; + generics.where_clause = self.parse_where_clause()?; + + let sig = ast::MethodSig { + header: FnHeader { + unsafety, + constness, + abi, + asyncness, + }, + decl: d, + }; + + let body = match self.token { + token::Semi => { + self.bump(); + *at_end = true; + debug!("parse_trait_methods(): parsing required method"); + None + } + token::OpenDelim(token::Brace) => { + debug!("parse_trait_methods(): parsing provided method"); + *at_end = true; + let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(inner_attrs.iter().cloned()); + Some(body) + } + token::Interpolated(ref nt) => { + match **nt { + token::NtBlock(..) => { + *at_end = true; + let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(inner_attrs.iter().cloned()); + Some(body) + } + _ => { + let token_str = self.this_token_descr(); + let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", + token_str)); + err.span_label(self.span, "expected `;` or `{`"); + return Err(err); + } + } + } + _ => { + let token_str = self.this_token_descr(); + let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", + token_str)); + err.span_label(self.span, "expected `;` or `{`"); + return Err(err); + } + }; + (ident, ast::TraitItemKind::Method(sig, body), generics) + }; + + Ok(TraitItem { + id: ast::DUMMY_NODE_ID, + ident: name, + attrs, + generics, + node, + span: lo.to(self.prev_span), + tokens: None, + }) + } + + /// Parses an optional return type `[ -> TY ]` in a function declaration. + fn parse_ret_ty(&mut self, allow_plus: bool) -> PResult<'a, FunctionRetTy> { + if self.eat(&token::RArrow) { + Ok(FunctionRetTy::Ty(self.parse_ty_common(allow_plus, true)?)) + } else { + Ok(FunctionRetTy::Default(self.span.shrink_to_lo())) + } + } + + /// Parses a type. + pub fn parse_ty(&mut self) -> PResult<'a, P> { + self.parse_ty_common(true, true) + } + + /// Parses a type in restricted contexts where `+` is not permitted. + /// + /// Example 1: `&'a TYPE` + /// `+` is prohibited to maintain operator priority (P(+) < P(&)). + /// Example 2: `value1 as TYPE + value2` + /// `+` is prohibited to avoid interactions with expression grammar. + fn parse_ty_no_plus(&mut self) -> PResult<'a, P> { + self.parse_ty_common(false, true) + } + + fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool) + -> PResult<'a, P> { + maybe_whole!(self, NtTy, |x| x); + + let lo = self.span; + let mut impl_dyn_multi = false; + let node = if self.eat(&token::OpenDelim(token::Paren)) { + // `(TYPE)` is a parenthesized type. + // `(TYPE,)` is a tuple with a single field of type TYPE. + let mut ts = vec![]; + let mut last_comma = false; + while self.token != token::CloseDelim(token::Paren) { + ts.push(self.parse_ty()?); + if self.eat(&token::Comma) { + last_comma = true; + } else { + last_comma = false; + break; + } + } + let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus; + self.expect(&token::CloseDelim(token::Paren))?; + + if ts.len() == 1 && !last_comma { + let ty = ts.into_iter().nth(0).unwrap().into_inner(); + let maybe_bounds = allow_plus && self.token.is_like_plus(); + match ty.node { + // `(TY_BOUND_NOPAREN) + BOUND + ...`. + TyKind::Path(None, ref path) if maybe_bounds => { + self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)? + } + TyKind::TraitObject(ref bounds, TraitObjectSyntax::None) + if maybe_bounds && bounds.len() == 1 && !trailing_plus => { + let path = match bounds[0] { + GenericBound::Trait(ref pt, ..) => pt.trait_ref.path.clone(), + GenericBound::Outlives(..) => self.bug("unexpected lifetime bound"), + }; + self.parse_remaining_bounds(Vec::new(), path, lo, true)? + } + // `(TYPE)` + _ => TyKind::Paren(P(ty)) + } + } else { + TyKind::Tup(ts) + } + } else if self.eat(&token::Not) { + // Never type `!` + TyKind::Never + } else if self.eat(&token::BinOp(token::Star)) { + // Raw pointer + TyKind::Ptr(self.parse_ptr()?) + } else if self.eat(&token::OpenDelim(token::Bracket)) { + // Array or slice + let t = self.parse_ty()?; + // Parse optional `; EXPR` in `[TYPE; EXPR]` + let t = match self.maybe_parse_fixed_length_of_vec()? { + None => TyKind::Slice(t), + Some(length) => TyKind::Array(t, AnonConst { + id: ast::DUMMY_NODE_ID, + value: length, + }), + }; + self.expect(&token::CloseDelim(token::Bracket))?; + t + } else if self.check(&token::BinOp(token::And)) || self.check(&token::AndAnd) { + // Reference + self.expect_and()?; + self.parse_borrowed_pointee()? + } else if self.eat_keyword_noexpect(keywords::Typeof) { + // `typeof(EXPR)` + // In order to not be ambiguous, the type must be surrounded by parens. + self.expect(&token::OpenDelim(token::Paren))?; + let e = AnonConst { + id: ast::DUMMY_NODE_ID, + value: self.parse_expr()?, + }; + self.expect(&token::CloseDelim(token::Paren))?; + TyKind::Typeof(e) + } else if self.eat_keyword(keywords::Underscore) { + // A type to be inferred `_` + TyKind::Infer + } else if self.token_is_bare_fn_keyword() { + // Function pointer type + self.parse_ty_bare_fn(Vec::new())? + } else if self.check_keyword(keywords::For) { + // Function pointer type or bound list (trait object type) starting with a poly-trait. + // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` + // `for<'lt> Trait1<'lt> + Trait2 + 'a` + let lo = self.span; + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + if self.token_is_bare_fn_keyword() { + self.parse_ty_bare_fn(lifetime_defs)? + } else { + let path = self.parse_path(PathStyle::Type)?; + let parse_plus = allow_plus && self.check_plus(); + self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? + } + } else if self.eat_keyword(keywords::Impl) { + // Always parse bounds greedily for better error recovery. + let bounds = self.parse_generic_bounds(None)?; + impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; + TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds) + } else if self.check_keyword(keywords::Dyn) && + (self.span.rust_2018() || + self.look_ahead(1, |t| t.can_begin_bound() && + !can_continue_type_after_non_fn_ident(t))) { + self.bump(); // `dyn` + // Always parse bounds greedily for better error recovery. + let bounds = self.parse_generic_bounds(None)?; + impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; + TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn) + } else if self.check(&token::Question) || + self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus()) { + // Bound list (trait object type) + TyKind::TraitObject(self.parse_generic_bounds_common(allow_plus, None)?, + TraitObjectSyntax::None) + } else if self.eat_lt() { + // Qualified path + let (qself, path) = self.parse_qpath(PathStyle::Type)?; + TyKind::Path(Some(qself), path) + } else if self.token.is_path_start() { + // Simple path + let path = self.parse_path(PathStyle::Type)?; + if self.eat(&token::Not) { + // Macro invocation in type position + let (delim, tts) = self.expect_delimited_token_tree()?; + let node = Mac_ { path, tts, delim }; + TyKind::Mac(respan(lo.to(self.prev_span), node)) + } else { + // Just a type path or bound list (trait object type) starting with a trait. + // `Type` + // `Trait1 + Trait2 + 'a` + if allow_plus && self.check_plus() { + self.parse_remaining_bounds(Vec::new(), path, lo, true)? + } else { + TyKind::Path(None, path) + } + } + } else { + let msg = format!("expected type, found {}", self.this_token_descr()); + return Err(self.fatal(&msg)); + }; + + let span = lo.to(self.prev_span); + let ty = Ty { node, span, id: ast::DUMMY_NODE_ID }; + + // Try to recover from use of `+` with incorrect priority. + self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty); + self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?; + let ty = self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)?; + + Ok(P(ty)) + } + + fn parse_remaining_bounds(&mut self, generic_params: Vec, path: ast::Path, + lo: Span, parse_plus: bool) -> PResult<'a, TyKind> { + let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span)); + let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)]; + if parse_plus { + self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded + bounds.append(&mut self.parse_generic_bounds(None)?); + } + Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) + } + + fn maybe_report_ambiguous_plus(&mut self, allow_plus: bool, impl_dyn_multi: bool, ty: &Ty) { + if !allow_plus && impl_dyn_multi { + let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); + self.struct_span_err(ty.span, "ambiguous `+` in a type") + .span_suggestion( + ty.span, + "use parentheses to disambiguate", + sum_with_parens, + Applicability::MachineApplicable + ).emit(); + } + } + + fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> { + // Do not add `+` to expected tokens. + if !allow_plus || !self.token.is_like_plus() { + return Ok(()) + } + + self.bump(); // `+` + let bounds = self.parse_generic_bounds(None)?; + let sum_span = ty.span.to(self.prev_span); + + let mut err = struct_span_err!(self.sess.span_diagnostic, sum_span, E0178, + "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(ty)); + + match ty.node { + TyKind::Rptr(ref lifetime, ref mut_ty) => { + let sum_with_parens = pprust::to_string(|s| { + use crate::print::pprust::PrintState; + + s.s.word("&")?; + s.print_opt_lifetime(lifetime)?; + s.print_mutability(mut_ty.mutbl)?; + s.popen()?; + s.print_type(&mut_ty.ty)?; + s.print_type_bounds(" +", &bounds)?; + s.pclose() + }); + err.span_suggestion( + sum_span, + "try adding parentheses", + sum_with_parens, + Applicability::MachineApplicable + ); + } + TyKind::Ptr(..) | TyKind::BareFn(..) => { + err.span_label(sum_span, "perhaps you forgot parentheses?"); + } + _ => { + err.span_label(sum_span, "expected a path"); + }, + } + err.emit(); + Ok(()) + } + + // Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`. + fn maybe_recover_from_bad_qpath(&mut self, base: T, allow_recovery: bool) + -> PResult<'a, T> { + // Do not add `::` to expected tokens. + if !allow_recovery || self.token != token::ModSep { + return Ok(base); + } + let ty = match base.to_ty() { + Some(ty) => ty, + None => return Ok(base), + }; + + self.bump(); // `::` + let mut segments = Vec::new(); + self.parse_path_segments(&mut segments, T::PATH_STYLE, true)?; + + let span = ty.span.to(self.prev_span); + let path_span = span.to(span); // use an empty path since `position` == 0 + let recovered = base.to_recovered( + Some(QSelf { ty, path_span, position: 0 }), + ast::Path { segments, span }, + ); + + self.diagnostic() + .struct_span_err(span, "missing angle brackets in associated item path") + .span_suggestion( // this is a best-effort recovery + span, "try", recovered.to_string(), Applicability::MaybeIncorrect + ).emit(); + + Ok(recovered) + } + + fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { + let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; + let mutbl = self.parse_mutability(); + let ty = self.parse_ty_no_plus()?; + return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty: ty, mutbl: mutbl })); + } + + fn parse_ptr(&mut self) -> PResult<'a, MutTy> { + let mutbl = if self.eat_keyword(keywords::Mut) { + Mutability::Mutable + } else if self.eat_keyword(keywords::Const) { + Mutability::Immutable + } else { + let span = self.prev_span; + let msg = "expected mut or const in raw pointer type"; + self.struct_span_err(span, msg) + .span_label(span, msg) + .help("use `*mut T` or `*const T` as appropriate") + .emit(); + Mutability::Immutable + }; + let t = self.parse_ty_no_plus()?; + Ok(MutTy { ty: t, mutbl: mutbl }) + } + + fn is_named_argument(&mut self) -> bool { + let offset = match self.token { + token::Interpolated(ref nt) => match **nt { + token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), + _ => 0, + } + token::BinOp(token::And) | token::AndAnd => 1, + _ if self.token.is_keyword(keywords::Mut) => 1, + _ => 0, + }; + + self.look_ahead(offset, |t| t.is_ident()) && + self.look_ahead(offset + 1, |t| t == &token::Colon) + } + + /// Skips unexpected attributes and doc comments in this position and emits an appropriate + /// error. + fn eat_incorrect_doc_comment(&mut self, applied_to: &str) { + if let token::DocComment(_) = self.token { + let mut err = self.diagnostic().struct_span_err( + self.span, + &format!("documentation comments cannot be applied to {}", applied_to), + ); + err.span_label(self.span, "doc comments are not allowed here"); + err.emit(); + self.bump(); + } else if self.token == token::Pound && self.look_ahead(1, |t| { + *t == token::OpenDelim(token::Bracket) + }) { + let lo = self.span; + // Skip every token until next possible arg. + while self.token != token::CloseDelim(token::Bracket) { + self.bump(); + } + let sp = lo.to(self.span); + self.bump(); + let mut err = self.diagnostic().struct_span_err( + sp, + &format!("attributes cannot be applied to {}", applied_to), + ); + err.span_label(sp, "attributes are not allowed here"); + err.emit(); + } + } + + /// This version of parse arg doesn't necessarily require identifier names. + fn parse_arg_general(&mut self, require_name: bool, is_trait_item: bool) -> PResult<'a, Arg> { + maybe_whole!(self, NtArg, |x| x); + + if let Ok(Some(_)) = self.parse_self_arg() { + let mut err = self.struct_span_err(self.prev_span, + "unexpected `self` argument in function"); + err.span_label(self.prev_span, + "`self` is only valid as the first argument of an associated function"); + return Err(err); + } + + let (pat, ty) = if require_name || self.is_named_argument() { + debug!("parse_arg_general parse_pat (require_name:{})", + require_name); + self.eat_incorrect_doc_comment("method arguments"); + let pat = self.parse_pat(Some("argument name"))?; + + if let Err(mut err) = self.expect(&token::Colon) { + // If we find a pattern followed by an identifier, it could be an (incorrect) + // C-style parameter declaration. + if self.check_ident() && self.look_ahead(1, |t| { + *t == token::Comma || *t == token::CloseDelim(token::Paren) + }) { + let ident = self.parse_ident().unwrap(); + let span = pat.span.with_hi(ident.span.hi()); + + err.span_suggestion( + span, + "declare the type after the parameter binding", + String::from(": "), + Applicability::HasPlaceholders, + ); + } else if require_name && is_trait_item { + if let PatKind::Ident(_, ident, _) = pat.node { + err.span_suggestion( + pat.span, + "explicitly ignore parameter", + format!("_: {}", ident), + Applicability::MachineApplicable, + ); + } + + err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)"); + } + + return Err(err); + } + + self.eat_incorrect_doc_comment("a method argument's type"); + (pat, self.parse_ty()?) + } else { + debug!("parse_arg_general ident_to_pat"); + let parser_snapshot_before_ty = self.clone(); + self.eat_incorrect_doc_comment("a method argument's type"); + let mut ty = self.parse_ty(); + if ty.is_ok() && self.token != token::Comma && + self.token != token::CloseDelim(token::Paren) { + // This wasn't actually a type, but a pattern looking like a type, + // so we are going to rollback and re-parse for recovery. + ty = self.unexpected(); + } + match ty { + Ok(ty) => { + let ident = Ident::new(keywords::Invalid.name(), self.prev_span); + let pat = P(Pat { + id: ast::DUMMY_NODE_ID, + node: PatKind::Ident( + BindingMode::ByValue(Mutability::Immutable), ident, None), + span: ty.span, + }); + (pat, ty) + } + Err(mut err) => { + // Recover from attempting to parse the argument as a type without pattern. + err.cancel(); + mem::replace(self, parser_snapshot_before_ty); + let pat = self.parse_pat(Some("argument name"))?; + self.expect(&token::Colon)?; + let ty = self.parse_ty()?; + + let mut err = self.diagnostic().struct_span_err_with_code( + pat.span, + "patterns aren't allowed in methods without bodies", + DiagnosticId::Error("E0642".into()), + ); + err.span_suggestion_short( + pat.span, + "give this argument a name or use an underscore to ignore it", + "_".to_owned(), + Applicability::MachineApplicable, + ); + err.emit(); + + // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. + let pat = P(Pat { + node: PatKind::Wild, + span: pat.span, + id: ast::DUMMY_NODE_ID + }); + (pat, ty) + } + } + }; + + Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID }) + } + + /// Parses a single function argument. + crate fn parse_arg(&mut self) -> PResult<'a, Arg> { + self.parse_arg_general(true, false) + } + + /// Parses an argument in a lambda header (e.g., `|arg, arg|`). + fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> { + let pat = self.parse_pat(Some("argument name"))?; + let t = if self.eat(&token::Colon) { + self.parse_ty()? + } else { + P(Ty { + id: ast::DUMMY_NODE_ID, + node: TyKind::Infer, + span: self.prev_span, + }) + }; + Ok(Arg { + ty: t, + pat, + id: ast::DUMMY_NODE_ID + }) + } + + fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option>> { + if self.eat(&token::Semi) { + Ok(Some(self.parse_expr()?)) + } else { + Ok(None) + } + } + + /// Matches `token_lit = LIT_INTEGER | ...`. + fn parse_lit_token(&mut self) -> PResult<'a, LitKind> { + let out = match self.token { + token::Interpolated(ref nt) => match **nt { + token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node { + ExprKind::Lit(ref lit) => { lit.node.clone() } + _ => { return self.unexpected_last(&self.token); } + }, + _ => { return self.unexpected_last(&self.token); } + }, + token::Literal(lit, suf) => { + let diag = Some((self.span, &self.sess.span_diagnostic)); + let (suffix_illegal, result) = parse::lit_token(lit, suf, diag); + + if suffix_illegal { + let sp = self.span; + self.expect_no_suffix(sp, lit.literal_name(), suf) + } + + result.unwrap() + } + token::Dot if self.look_ahead(1, |t| match t { + token::Literal(parse::token::Lit::Integer(_) , _) => true, + _ => false, + }) => { // recover from `let x = .4;` + let lo = self.span; + self.bump(); + if let token::Literal( + parse::token::Lit::Integer(val), + suffix, + ) = self.token { + let suffix = suffix.and_then(|s| { + let s = s.as_str().get(); + if ["f32", "f64"].contains(&s) { + Some(s) + } else { + None + } + }).unwrap_or(""); + self.bump(); + let sp = lo.to(self.prev_span); + let mut err = self.diagnostic() + .struct_span_err(sp, "float literals must have an integer part"); + err.span_suggestion( + sp, + "must have an integer part", + format!("0.{}{}", val, suffix), + Applicability::MachineApplicable, + ); + err.emit(); + return Ok(match suffix { + "f32" => ast::LitKind::Float(val, ast::FloatTy::F32), + "f64" => ast::LitKind::Float(val, ast::FloatTy::F64), + _ => ast::LitKind::FloatUnsuffixed(val), + }); + } else { + unreachable!(); + }; + } + _ => { return self.unexpected_last(&self.token); } + }; + + self.bump(); + Ok(out) + } + + /// Matches `lit = true | false | token_lit`. + crate fn parse_lit(&mut self) -> PResult<'a, Lit> { + let lo = self.span; + let lit = if self.eat_keyword(keywords::True) { + LitKind::Bool(true) + } else if self.eat_keyword(keywords::False) { + LitKind::Bool(false) + } else { + let lit = self.parse_lit_token()?; + lit + }; + Ok(source_map::Spanned { node: lit, span: lo.to(self.prev_span) }) + } + + /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). + crate fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P> { + maybe_whole_expr!(self); + + let minus_lo = self.span; + let minus_present = self.eat(&token::BinOp(token::Minus)); + let lo = self.span; + let literal = self.parse_lit()?; + let hi = self.prev_span; + let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new()); + + if minus_present { + let minus_hi = self.prev_span; + let unary = self.mk_unary(UnOp::Neg, expr); + Ok(self.mk_expr(minus_lo.to(minus_hi), unary, ThinVec::new())) + } else { + Ok(expr) + } + } + + fn parse_path_segment_ident(&mut self) -> PResult<'a, ast::Ident> { + match self.token { + token::Ident(ident, _) if self.token.is_path_segment_keyword() => { + let span = self.span; + self.bump(); + Ok(Ident::new(ident.name, span)) + } + _ => self.parse_ident(), + } + } + + fn parse_ident_or_underscore(&mut self) -> PResult<'a, ast::Ident> { + match self.token { + token::Ident(ident, false) if ident.name == keywords::Underscore.name() => { + let span = self.span; + self.bump(); + Ok(Ident::new(ident.name, span)) + } + _ => self.parse_ident(), + } + } + + /// Parses a qualified path. + /// Assumes that the leading `<` has been parsed already. + /// + /// `qualified_path = ::path` + /// + /// # Examples + /// `::default` + /// `::a` + /// `::F::a` (without disambiguator) + /// `::F::a::` (with disambiguator) + fn parse_qpath(&mut self, style: PathStyle) -> PResult<'a, (QSelf, ast::Path)> { + let lo = self.prev_span; + let ty = self.parse_ty()?; + + // `path` will contain the prefix of the path up to the `>`, + // if any (e.g., `U` in the `::*` examples + // above). `path_span` has the span of that path, or an empty + // span in the case of something like `::Bar`. + let (mut path, path_span); + if self.eat_keyword(keywords::As) { + let path_lo = self.span; + path = self.parse_path(PathStyle::Type)?; + path_span = path_lo.to(self.prev_span); + } else { + path = ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP }; + path_span = self.span.to(self.span); + } + + // See doc comment for `unmatched_angle_bracket_count`. + self.expect(&token::Gt)?; + if self.unmatched_angle_bracket_count > 0 { + self.unmatched_angle_bracket_count -= 1; + debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count); + } + + self.expect(&token::ModSep)?; + + let qself = QSelf { ty, path_span, position: path.segments.len() }; + self.parse_path_segments(&mut path.segments, style, true)?; + + Ok((qself, ast::Path { segments: path.segments, span: lo.to(self.prev_span) })) + } + + /// Parses simple paths. + /// + /// `path = [::] segment+` + /// `segment = ident | ident[::] | ident[::](args) [-> type]` + /// + /// # Examples + /// `a::b::C` (without disambiguator) + /// `a::b::C::` (with disambiguator) + /// `Fn(Args)` (without disambiguator) + /// `Fn::(Args)` (with disambiguator) + pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, ast::Path> { + self.parse_path_common(style, true) + } + + crate fn parse_path_common(&mut self, style: PathStyle, enable_warning: bool) + -> PResult<'a, ast::Path> { + maybe_whole!(self, NtPath, |path| { + if style == PathStyle::Mod && + path.segments.iter().any(|segment| segment.args.is_some()) { + self.diagnostic().span_err(path.span, "unexpected generic arguments in path"); + } + path + }); + + let lo = self.meta_var_span.unwrap_or(self.span); + let mut segments = Vec::new(); + let mod_sep_ctxt = self.span.ctxt(); + if self.eat(&token::ModSep) { + segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt))); + } + self.parse_path_segments(&mut segments, style, enable_warning)?; + + Ok(ast::Path { segments, span: lo.to(self.prev_span) }) + } + + /// Like `parse_path`, but also supports parsing `Word` meta items into paths for + /// backwards-compatibility. This is used when parsing derive macro paths in `#[derive]` + /// attributes. + pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, ast::Path> { + let meta_ident = match self.token { + token::Interpolated(ref nt) => match **nt { + token::NtMeta(ref meta) => match meta.node { + ast::MetaItemKind::Word => Some(meta.ident.clone()), + _ => None, + }, + _ => None, + }, + _ => None, + }; + if let Some(path) = meta_ident { + self.bump(); + return Ok(path); + } + self.parse_path(style) + } + + fn parse_path_segments(&mut self, + segments: &mut Vec, + style: PathStyle, + enable_warning: bool) + -> PResult<'a, ()> { + loop { + let segment = self.parse_path_segment(style, enable_warning)?; + if style == PathStyle::Expr { + // In order to check for trailing angle brackets, we must have finished + // recursing (`parse_path_segment` can indirectly call this function), + // that is, the next token must be the highlighted part of the below example: + // + // `Foo::>::Qux` + // ^ here + // + // As opposed to the below highlight (if we had only finished the first + // recursion): + // + // `Foo::>::Qux` + // ^ here + // + // `PathStyle::Expr` is only provided at the root invocation and never in + // `parse_path_segment` to recurse and therefore can be checked to maintain + // this invariant. + self.check_trailing_angle_brackets(&segment, token::ModSep); + } + segments.push(segment); + + if self.is_import_coupler() || !self.eat(&token::ModSep) { + return Ok(()); + } + } + } + + fn parse_path_segment(&mut self, style: PathStyle, enable_warning: bool) + -> PResult<'a, PathSegment> { + let ident = self.parse_path_segment_ident()?; + + let is_args_start = |token: &token::Token| match *token { + token::Lt | token::BinOp(token::Shl) | token::OpenDelim(token::Paren) => true, + _ => false, + }; + let check_args_start = |this: &mut Self| { + this.expected_tokens.extend_from_slice( + &[TokenType::Token(token::Lt), TokenType::Token(token::OpenDelim(token::Paren))] + ); + is_args_start(&this.token) + }; + + Ok(if style == PathStyle::Type && check_args_start(self) || + style != PathStyle::Mod && self.check(&token::ModSep) + && self.look_ahead(1, |t| is_args_start(t)) { + // Generic arguments are found - `<`, `(`, `::<` or `::(`. + if self.eat(&token::ModSep) && style == PathStyle::Type && enable_warning { + self.diagnostic().struct_span_warn(self.prev_span, "unnecessary path disambiguator") + .span_label(self.prev_span, "try removing `::`").emit(); + } + let lo = self.span; + + // We use `style == PathStyle::Expr` to check if this is in a recursion or not. If + // it isn't, then we reset the unmatched angle bracket count as we're about to start + // parsing a new path. + if style == PathStyle::Expr { + self.unmatched_angle_bracket_count = 0; + self.max_angle_bracket_count = 0; + } + + let args = if self.eat_lt() { + // `<'a, T, A = U>` + let (args, bindings) = + self.parse_generic_args_with_leaning_angle_bracket_recovery(style, lo)?; + self.expect_gt()?; + let span = lo.to(self.prev_span); + AngleBracketedArgs { args, bindings, span }.into() + } else { + // `(T, U) -> R` + self.bump(); // `(` + let (inputs, recovered) = self.parse_seq_to_before_tokens( + &[&token::CloseDelim(token::Paren)], + SeqSep::trailing_allowed(token::Comma), + TokenExpectType::Expect, + |p| p.parse_ty())?; + if !recovered { + self.bump(); // `)` + } + let span = lo.to(self.prev_span); + let output = if self.eat(&token::RArrow) { + Some(self.parse_ty_common(false, false)?) + } else { + None + }; + ParenthesizedArgs { inputs, output, span }.into() + }; + + PathSegment { ident, args, id: ast::DUMMY_NODE_ID } + } else { + // Generic arguments are not found. + PathSegment::from_ident(ident) + }) + } + + crate fn check_lifetime(&mut self) -> bool { + self.expected_tokens.push(TokenType::Lifetime); + self.token.is_lifetime() + } + + /// Parses a single lifetime `'a` or panics. + crate fn expect_lifetime(&mut self) -> Lifetime { + if let Some(ident) = self.token.lifetime() { + let span = self.span; + self.bump(); + Lifetime { ident: Ident::new(ident.name, span), id: ast::DUMMY_NODE_ID } + } else { + self.span_bug(self.span, "not a lifetime") + } + } + + fn eat_label(&mut self) -> Option