]> git.lizzy.rs Git - rust.git/commitdiff
:arrow_up: rust-analyzer
authorLaurențiu Nicola <lnicola@dend.ro>
Wed, 26 Oct 2022 14:40:41 +0000 (17:40 +0300)
committerLaurențiu Nicola <lnicola@dend.ro>
Wed, 26 Oct 2022 14:40:41 +0000 (17:40 +0300)
62 files changed:
1  2 
src/tools/rust-analyzer/.github/workflows/publish.yml
src/tools/rust-analyzer/crates/flycheck/src/lib.rs
src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
src/tools/rust-analyzer/crates/hir-expand/src/name.rs
src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
src/tools/rust-analyzer/crates/hir/src/lib.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_constant.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_setter.rs
src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
src/tools/rust-analyzer/crates/ide/src/lib.rs
src/tools/rust-analyzer/crates/ide/src/parent_module.rs
src/tools/rust-analyzer/crates/ide/src/static_index.rs
src/tools/rust-analyzer/crates/ide/src/status.rs
src/tools/rust-analyzer/crates/project-model/Cargo.toml
src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
src/tools/rust-analyzer/crates/project-model/src/lib.rs
src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
src/tools/rust-analyzer/crates/project-model/src/workspace.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
src/tools/rust-analyzer/crates/syntax/src/lib.rs
src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
src/tools/rust-analyzer/docs/user/generated_config.adoc
src/tools/rust-analyzer/editors/code/package-lock.json
src/tools/rust-analyzer/editors/code/package.json
src/tools/rust-analyzer/editors/code/src/ast_inspector.ts
src/tools/rust-analyzer/editors/code/src/bootstrap.ts
src/tools/rust-analyzer/editors/code/src/client.ts
src/tools/rust-analyzer/editors/code/src/commands.ts
src/tools/rust-analyzer/editors/code/src/config.ts
src/tools/rust-analyzer/editors/code/src/ctx.ts
src/tools/rust-analyzer/editors/code/src/main.ts
src/tools/rust-analyzer/editors/code/src/run.ts

index a4497f49e3c2f8c5193aea300b044251ec262463,0000000000000000000000000000000000000000..73e62ab32c6c5d1f310e5cc5734a1496a8409b29
mode 100644,000000..100644
--- /dev/null
@@@ -1,54 -1,0 +1,56 @@@
- #   schedule:
- #     - cron: "0 0 * * *" # midnight UTC
 +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
 +          # Fix names for crates that were published before switch to kebab-case.
 +          cargo workspaces rename --from base-db base_db
 +          cargo workspaces rename --from hir-def hir_def
 +          cargo workspaces rename --from hir-expand hir_expand
 +          cargo workspaces rename --from hir-ty hir_ty
 +          cargo workspaces rename --from ide-assists ide_assists
 +          cargo workspaces rename --from ide-completion ide_completion
 +          cargo workspaces rename --from ide-db ide_db
 +          cargo workspaces rename --from ide-diagnostics ide_diagnostics
 +          cargo workspaces rename --from ide-ssr ide_ssr
 +          cargo workspaces rename --from proc-macro-api proc_macro_api
 +          cargo workspaces rename --from proc-macro-srv proc_macro_srv
 +          cargo workspaces rename --from project-model project_model
 +          cargo workspaces rename --from test-utils test_utils
 +          cargo workspaces rename --from text-edit text_edit
 +          cargo workspaces rename ra_ap_%n
++          # Remove library crates from the workspaces so we don't auto-publish them as well
++          sed -i 's/ "lib\/\*",//' ./Cargo.toml
 +          find crates/rust-analyzer -type f -name '*.rs' -exec sed -i 's/rust_analyzer/ra_ap_rust_analyzer/g' {} +
 +          cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$PATCH
index e8c63d410aa754dd428aee664c771253caa30806,0000000000000000000000000000000000000000..73c3a48b4c5a3fd5fe017031a7e15ba0177b5ad1
mode 100644,000000..100644
--- /dev/null
@@@ -1,436 -1,0 +1,480 @@@
-     workspace_root: AbsPathBuf,
 +//! Flycheck provides the functionality needed to run `cargo check` or
 +//! another compatible command (f.x. clippy) in a background thread and provide
 +//! LSP diagnostics based on the output of the command.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +use std::{
 +    fmt, io,
 +    process::{ChildStderr, ChildStdout, Command, Stdio},
 +    time::Duration,
 +};
 +
 +use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
 +use paths::AbsPathBuf;
 +use rustc_hash::FxHashMap;
 +use serde::Deserialize;
 +use stdx::{process::streaming_output, JodChild};
 +
 +pub use cargo_metadata::diagnostic::{
 +    Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan,
 +    DiagnosticSpanMacroExpansion,
 +};
 +
++#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
++pub enum InvocationStrategy {
++    Once,
++    #[default]
++    PerWorkspace,
++}
++
++#[derive(Clone, Debug, Default, PartialEq, Eq)]
++pub enum InvocationLocation {
++    Root(AbsPathBuf),
++    #[default]
++    Workspace,
++}
++
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum FlycheckConfig {
 +    CargoCommand {
 +        command: String,
 +        target_triple: Option<String>,
 +        all_targets: bool,
 +        no_default_features: bool,
 +        all_features: bool,
 +        features: Vec<String>,
 +        extra_args: Vec<String>,
 +        extra_env: FxHashMap<String, String>,
 +    },
 +    CustomCommand {
 +        command: String,
 +        args: Vec<String>,
 +        extra_env: FxHashMap<String, String>,
++        invocation_strategy: InvocationStrategy,
++        invocation_location: InvocationLocation,
 +    },
 +}
 +
 +impl fmt::Display for FlycheckConfig {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match self {
 +            FlycheckConfig::CargoCommand { command, .. } => write!(f, "cargo {}", command),
 +            FlycheckConfig::CustomCommand { command, args, .. } => {
 +                write!(f, "{} {}", command, args.join(" "))
 +            }
 +        }
 +    }
 +}
 +
 +/// Flycheck wraps the shared state and communication machinery used for
 +/// running `cargo check` (or other compatible command) and providing
 +/// diagnostics based on the output.
 +/// The spawned thread is shut down when this struct is dropped.
 +#[derive(Debug)]
 +pub struct FlycheckHandle {
 +    // XXX: drop order is significant
 +    sender: Sender<Restart>,
 +    _thread: jod_thread::JoinHandle,
 +    id: usize,
 +}
 +
 +impl FlycheckHandle {
 +    pub fn spawn(
 +        id: usize,
 +        sender: Box<dyn Fn(Message) + Send>,
 +        config: FlycheckConfig,
 +        workspace_root: AbsPathBuf,
 +    ) -> FlycheckHandle {
 +        let actor = FlycheckActor::new(id, sender, config, workspace_root);
 +        let (sender, receiver) = unbounded::<Restart>();
 +        let thread = jod_thread::Builder::new()
 +            .name("Flycheck".to_owned())
 +            .spawn(move || actor.run(receiver))
 +            .expect("failed to spawn thread");
 +        FlycheckHandle { id, sender, _thread: thread }
 +    }
 +
 +    /// Schedule a re-start of the cargo check worker.
 +    pub fn restart(&self) {
 +        self.sender.send(Restart::Yes).unwrap();
 +    }
 +
 +    /// Stop this cargo check worker.
 +    pub fn cancel(&self) {
 +        self.sender.send(Restart::No).unwrap();
 +    }
 +
 +    pub fn id(&self) -> usize {
 +        self.id
 +    }
 +}
 +
 +pub enum Message {
 +    /// Request adding a diagnostic with fixes included to a file
 +    AddDiagnostic { id: usize, workspace_root: AbsPathBuf, diagnostic: Diagnostic },
 +
 +    /// Request check progress notification to client
 +    Progress {
 +        /// Flycheck instance ID
 +        id: usize,
 +        progress: Progress,
 +    },
 +}
 +
 +impl fmt::Debug for Message {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match self {
 +            Message::AddDiagnostic { id, workspace_root, diagnostic } => f
 +                .debug_struct("AddDiagnostic")
 +                .field("id", id)
 +                .field("workspace_root", workspace_root)
 +                .field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code))
 +                .finish(),
 +            Message::Progress { id, progress } => {
 +                f.debug_struct("Progress").field("id", id).field("progress", progress).finish()
 +            }
 +        }
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub enum Progress {
 +    DidStart,
 +    DidCheckCrate(String),
 +    DidFinish(io::Result<()>),
 +    DidCancel,
 +    DidFailToRestart(String),
 +}
 +
 +enum Restart {
 +    Yes,
 +    No,
 +}
 +
++/// A [`FlycheckActor`] is a single check instance of a workspace.
 +struct FlycheckActor {
++    /// The workspace id of this flycheck instance.
 +    id: usize,
 +    sender: Box<dyn Fn(Message) + Send>,
 +    config: FlycheckConfig,
-         FlycheckActor { id, sender, config, workspace_root, cargo_handle: None }
++    /// Either the workspace root of the workspace we are flychecking,
++    /// or the project root of the project.
++    root: AbsPathBuf,
 +    /// CargoHandle exists to wrap around the communication needed to be able to
 +    /// run `cargo check` without blocking. Currently the Rust standard library
 +    /// doesn't provide a way to read sub-process output without blocking, so we
 +    /// have to wrap sub-processes output handling in a thread and pass messages
 +    /// back over a channel.
 +    cargo_handle: Option<CargoHandle>,
 +}
 +
 +enum Event {
 +    Restart(Restart),
 +    CheckEvent(Option<CargoMessage>),
 +}
 +
 +impl FlycheckActor {
 +    fn new(
 +        id: usize,
 +        sender: Box<dyn Fn(Message) + Send>,
 +        config: FlycheckConfig,
 +        workspace_root: AbsPathBuf,
 +    ) -> FlycheckActor {
 +        tracing::info!(%id, ?workspace_root, "Spawning flycheck");
-     fn progress(&self, progress: Progress) {
++        FlycheckActor { id, sender, config, root: workspace_root, cargo_handle: None }
 +    }
-                             self.progress(Progress::DidStart);
++
++    fn report_progress(&self, progress: Progress) {
 +        self.send(Message::Progress { id: self.id, progress });
 +    }
++
 +    fn next_event(&self, inbox: &Receiver<Restart>) -> Option<Event> {
 +        let check_chan = self.cargo_handle.as_ref().map(|cargo| &cargo.receiver);
 +        if let Ok(msg) = inbox.try_recv() {
 +            // give restarts a preference so check outputs don't block a restart or stop
 +            return Some(Event::Restart(msg));
 +        }
 +        select! {
 +            recv(inbox) -> msg => msg.ok().map(Event::Restart),
 +            recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())),
 +        }
 +    }
++
 +    fn run(mut self, inbox: Receiver<Restart>) {
 +        'event: while let Some(event) = self.next_event(&inbox) {
 +            match event {
 +                Event::Restart(Restart::No) => {
 +                    self.cancel_check_process();
 +                }
 +                Event::Restart(Restart::Yes) => {
 +                    // Cancel the previously spawned process
 +                    self.cancel_check_process();
 +                    while let Ok(restart) = inbox.recv_timeout(Duration::from_millis(50)) {
 +                        // restart chained with a stop, so just cancel
 +                        if let Restart::No = restart {
 +                            continue 'event;
 +                        }
 +                    }
 +
 +                    let command = self.check_command();
 +                    tracing::debug!(?command, "will restart flycheck");
 +                    match CargoHandle::spawn(command) {
 +                        Ok(cargo_handle) => {
 +                            tracing::debug!(
 +                                command = ?self.check_command(),
 +                                "did  restart flycheck"
 +                            );
 +                            self.cargo_handle = Some(cargo_handle);
-                             self.progress(Progress::DidFailToRestart(format!(
++                            self.report_progress(Progress::DidStart);
 +                        }
 +                        Err(error) => {
-                     self.progress(Progress::DidFinish(res));
++                            self.report_progress(Progress::DidFailToRestart(format!(
 +                                "Failed to run the following command: {:?} error={}",
 +                                self.check_command(),
 +                                error
 +                            )));
 +                        }
 +                    }
 +                }
 +                Event::CheckEvent(None) => {
 +                    tracing::debug!(flycheck_id = self.id, "flycheck finished");
 +
 +                    // Watcher finished
 +                    let cargo_handle = self.cargo_handle.take().unwrap();
 +                    let res = cargo_handle.join();
 +                    if res.is_err() {
 +                        tracing::error!(
 +                            "Flycheck failed to run the following command: {:?}",
 +                            self.check_command()
 +                        );
 +                    }
-                         self.progress(Progress::DidCheckCrate(msg.target.name));
++                    self.report_progress(Progress::DidFinish(res));
 +                }
 +                Event::CheckEvent(Some(message)) => match message {
 +                    CargoMessage::CompilerArtifact(msg) => {
-                             workspace_root: self.workspace_root.clone(),
++                        self.report_progress(Progress::DidCheckCrate(msg.target.name));
 +                    }
 +
 +                    CargoMessage::Diagnostic(msg) => {
 +                        self.send(Message::AddDiagnostic {
 +                            id: self.id,
-             self.progress(Progress::DidCancel);
++                            workspace_root: self.root.clone(),
 +                            diagnostic: msg,
 +                        });
 +                    }
 +                },
 +            }
 +        }
 +        // If we rerun the thread, we need to discard the previous check results first
 +        self.cancel_check_process();
 +    }
 +
 +    fn cancel_check_process(&mut self) {
 +        if let Some(cargo_handle) = self.cargo_handle.take() {
 +            tracing::debug!(
 +                command = ?self.check_command(),
 +                "did  cancel flycheck"
 +            );
 +            cargo_handle.cancel();
-         let mut cmd = match &self.config {
++            self.report_progress(Progress::DidCancel);
 +        }
 +    }
 +
 +    fn check_command(&self) -> Command {
-                 cmd.current_dir(&self.workspace_root);
-                 cmd.args(&["--workspace", "--message-format=json", "--manifest-path"])
-                     .arg(self.workspace_root.join("Cargo.toml").as_os_str());
++        let (mut cmd, args) = match &self.config {
 +            FlycheckConfig::CargoCommand {
 +                command,
 +                target_triple,
 +                no_default_features,
 +                all_targets,
 +                all_features,
 +                extra_args,
 +                features,
 +                extra_env,
 +            } => {
 +                let mut cmd = Command::new(toolchain::cargo());
 +                cmd.arg(command);
-                 cmd.args(extra_args);
++                cmd.args(&["--workspace", "--message-format=json"]);
 +
 +                if let Some(target) = target_triple {
 +                    cmd.args(&["--target", target.as_str()]);
 +                }
 +                if *all_targets {
 +                    cmd.arg("--all-targets");
 +                }
 +                if *all_features {
 +                    cmd.arg("--all-features");
 +                } else {
 +                    if *no_default_features {
 +                        cmd.arg("--no-default-features");
 +                    }
 +                    if !features.is_empty() {
 +                        cmd.arg("--features");
 +                        cmd.arg(features.join(" "));
 +                    }
 +                }
-                 cmd
 +                cmd.envs(extra_env);
-             FlycheckConfig::CustomCommand { command, args, extra_env } => {
++                (cmd, extra_args)
 +            }
-                 cmd.args(args);
++            FlycheckConfig::CustomCommand {
++                command,
++                args,
++                extra_env,
++                invocation_strategy,
++                invocation_location,
++            } => {
 +                let mut cmd = Command::new(command);
-                 cmd
 +                cmd.envs(extra_env);
-         cmd.current_dir(&self.workspace_root);
++
++                match invocation_location {
++                    InvocationLocation::Workspace => {
++                        match invocation_strategy {
++                            InvocationStrategy::Once => {
++                                cmd.current_dir(&self.root);
++                            }
++                            InvocationStrategy::PerWorkspace => {
++                                // FIXME: cmd.current_dir(&affected_workspace);
++                                cmd.current_dir(&self.root);
++                            }
++                        }
++                    }
++                    InvocationLocation::Root(root) => {
++                        cmd.current_dir(root);
++                    }
++                }
++
++                (cmd, args)
 +            }
 +        };
++
++        cmd.args(args);
 +        cmd
 +    }
 +
 +    fn send(&self, check_task: Message) {
 +        (self.sender)(check_task);
 +    }
 +}
 +
 +/// A handle to a cargo process used for fly-checking.
 +struct CargoHandle {
 +    /// The handle to the actual cargo process. As we cannot cancel directly from with
 +    /// a read syscall dropping and therefor terminating the process is our best option.
 +    child: JodChild,
 +    thread: jod_thread::JoinHandle<io::Result<(bool, String)>>,
 +    receiver: Receiver<CargoMessage>,
 +}
 +
 +impl CargoHandle {
 +    fn spawn(mut command: Command) -> std::io::Result<CargoHandle> {
 +        command.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null());
 +        let mut child = JodChild::spawn(command)?;
 +
 +        let stdout = child.stdout.take().unwrap();
 +        let stderr = child.stderr.take().unwrap();
 +
 +        let (sender, receiver) = unbounded();
 +        let actor = CargoActor::new(sender, stdout, stderr);
 +        let thread = jod_thread::Builder::new()
 +            .name("CargoHandle".to_owned())
 +            .spawn(move || actor.run())
 +            .expect("failed to spawn thread");
 +        Ok(CargoHandle { child, thread, receiver })
 +    }
 +
 +    fn cancel(mut self) {
 +        let _ = self.child.kill();
 +        let _ = self.child.wait();
 +    }
 +
 +    fn join(mut self) -> io::Result<()> {
 +        let _ = self.child.kill();
 +        let exit_status = self.child.wait()?;
 +        let (read_at_least_one_message, error) = self.thread.join()?;
 +        if read_at_least_one_message || exit_status.success() {
 +            Ok(())
 +        } else {
 +            Err(io::Error::new(io::ErrorKind::Other, format!(
 +                "Cargo watcher failed, the command produced no valid metadata (exit code: {:?}):\n{}",
 +                exit_status, error
 +            )))
 +        }
 +    }
 +}
 +
 +struct CargoActor {
 +    sender: Sender<CargoMessage>,
 +    stdout: ChildStdout,
 +    stderr: ChildStderr,
 +}
 +
 +impl CargoActor {
 +    fn new(sender: Sender<CargoMessage>, stdout: ChildStdout, stderr: ChildStderr) -> CargoActor {
 +        CargoActor { sender, stdout, stderr }
 +    }
 +
 +    fn run(self) -> io::Result<(bool, String)> {
 +        // We manually read a line at a time, instead of using serde's
 +        // stream deserializers, because the deserializer cannot recover
 +        // from an error, resulting in it getting stuck, because we try to
 +        // be resilient against failures.
 +        //
 +        // Because cargo only outputs one JSON object per line, we can
 +        // simply skip a line if it doesn't parse, which just ignores any
 +        // erroneous output.
 +
 +        let mut error = String::new();
 +        let mut read_at_least_one_message = false;
 +        let output = streaming_output(
 +            self.stdout,
 +            self.stderr,
 +            &mut |line| {
 +                read_at_least_one_message = true;
 +
 +                // Try to deserialize a message from Cargo or Rustc.
 +                let mut deserializer = serde_json::Deserializer::from_str(line);
 +                deserializer.disable_recursion_limit();
 +                if let Ok(message) = JsonMessage::deserialize(&mut deserializer) {
 +                    match message {
 +                        // Skip certain kinds of messages to only spend time on what's useful
 +                        JsonMessage::Cargo(message) => match message {
 +                            cargo_metadata::Message::CompilerArtifact(artifact)
 +                                if !artifact.fresh =>
 +                            {
 +                                self.sender.send(CargoMessage::CompilerArtifact(artifact)).unwrap();
 +                            }
 +                            cargo_metadata::Message::CompilerMessage(msg) => {
 +                                self.sender.send(CargoMessage::Diagnostic(msg.message)).unwrap();
 +                            }
 +                            _ => (),
 +                        },
 +                        JsonMessage::Rustc(message) => {
 +                            self.sender.send(CargoMessage::Diagnostic(message)).unwrap();
 +                        }
 +                    }
 +                }
 +            },
 +            &mut |line| {
 +                error.push_str(line);
 +                error.push('\n');
 +            },
 +        );
 +        match output {
 +            Ok(_) => Ok((read_at_least_one_message, error)),
 +            Err(e) => Err(io::Error::new(e.kind(), format!("{:?}: {}", e, error))),
 +        }
 +    }
 +}
 +
 +enum CargoMessage {
 +    CompilerArtifact(cargo_metadata::Artifact),
 +    Diagnostic(Diagnostic),
 +}
 +
 +#[derive(Deserialize)]
 +#[serde(untagged)]
 +enum JsonMessage {
 +    Cargo(cargo_metadata::Message),
 +    Rustc(Diagnostic),
 +}
index 6819e9114a02476129260eb553f695b9407a729f,0000000000000000000000000000000000000000..fafcde25ae708549241644a6e50803b98c358ce7
mode 100644,000000..100644
--- /dev/null
@@@ -1,95 -1,0 +1,111 @@@
-         expect![[r##"
 +//! Tests for `builtin_derive_macro.rs` from `hir_expand`.
 +
 +use expect_test::expect;
 +
 +use crate::macro_expansion_tests::check;
 +
 +#[test]
 +fn test_copy_expand_simple() {
 +    check(
 +        r#"
 +//- minicore: derive, copy
 +#[derive(Copy)]
 +struct Foo;
 +"#,
- impl < > core::marker::Copy for Foo< > {}"##]],
++        expect![[r#"
 +#[derive(Copy)]
 +struct Foo;
 +
-         expect![[r##"
++impl < > core::marker::Copy for Foo< > {}"#]],
 +    );
 +}
 +
 +#[test]
 +fn test_copy_expand_in_core() {
 +    cov_mark::check!(test_copy_expand_in_core);
 +    check(
 +        r#"
 +//- /lib.rs crate:core
 +#[rustc_builtin_macro]
 +macro derive {}
 +#[rustc_builtin_macro]
 +macro Copy {}
 +#[derive(Copy)]
 +struct Foo;
 +"#,
- impl < > crate ::marker::Copy for Foo< > {}"##]],
++        expect![[r#"
 +#[rustc_builtin_macro]
 +macro derive {}
 +#[rustc_builtin_macro]
 +macro Copy {}
 +#[derive(Copy)]
 +struct Foo;
 +
-         expect![[r##"
++impl < > crate ::marker::Copy for Foo< > {}"#]],
 +    );
 +}
 +
 +#[test]
 +fn test_copy_expand_with_type_params() {
 +    check(
 +        r#"
 +//- minicore: derive, copy
 +#[derive(Copy)]
 +struct Foo<A, B>;
 +"#,
- impl <T0: core::marker::Copy, T1: core::marker::Copy> core::marker::Copy for Foo<T0, T1> {}"##]],
++        expect![[r#"
 +#[derive(Copy)]
 +struct Foo<A, B>;
 +
-         expect![[r##"
++impl <T0: core::marker::Copy, T1: core::marker::Copy, > core::marker::Copy for Foo<T0, T1, > {}"#]],
 +    );
 +}
 +
 +#[test]
 +fn test_copy_expand_with_lifetimes() {
 +    // We currently just ignore lifetimes
 +    check(
 +        r#"
 +//- minicore: derive, copy
 +#[derive(Copy)]
 +struct Foo<A, B, 'a, 'b>;
 +"#,
- impl <T0: core::marker::Copy, T1: core::marker::Copy> core::marker::Copy for Foo<T0, T1> {}"##]],
++        expect![[r#"
 +#[derive(Copy)]
 +struct Foo<A, B, 'a, 'b>;
 +
-         expect![[r##"
++impl <T0: core::marker::Copy, T1: core::marker::Copy, > core::marker::Copy for Foo<T0, T1, > {}"#]],
 +    );
 +}
 +
 +#[test]
 +fn test_clone_expand() {
 +    check(
 +        r#"
 +//- minicore: derive, clone
 +#[derive(Clone)]
 +struct Foo<A, B>;
 +"#,
- impl <T0: core::clone::Clone, T1: core::clone::Clone> core::clone::Clone for Foo<T0, T1> {}"##]],
++        expect![[r#"
 +#[derive(Clone)]
 +struct Foo<A, B>;
 +
++impl <T0: core::clone::Clone, T1: core::clone::Clone, > core::clone::Clone for Foo<T0, T1, > {}"#]],
++    );
++}
++
++#[test]
++fn test_clone_expand_with_const_generics() {
++    check(
++        r#"
++//- minicore: derive, clone
++#[derive(Clone)]
++struct Foo<const X: usize, T>(u32);
++"#,
++        expect![[r#"
++#[derive(Clone)]
++struct Foo<const X: usize, T>(u32);
++
++impl <const T0: usize, T1: core::clone::Clone, > core::clone::Clone for Foo<T0, T1, > {}"#]],
 +    );
 +}
index 79989bc2e38b601339085934488c44cf09217f7c,0000000000000000000000000000000000000000..8966047c9b259d932bc8b618f11497fa5b28f205
mode 100644,000000..100644
--- /dev/null
@@@ -1,249 -1,0 +1,235 @@@
-     type_or_const_params: usize,
 +//! Builtin derives.
 +
 +use base_db::{CrateOrigin, LangCrateOrigin};
 +use tracing::debug;
 +
 +use syntax::{
 +    ast::{self, AstNode, HasGenericParams, HasModuleItem, HasName},
 +    match_ast,
 +};
 +use tt::TokenId;
 +
 +use crate::{db::AstDatabase, name, quote, ExpandError, ExpandResult, MacroCallId};
 +
 +macro_rules! register_builtin {
 +    ( $($trait:ident => $expand:ident),* ) => {
 +        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +        pub enum BuiltinDeriveExpander {
 +            $($trait),*
 +        }
 +
 +        impl BuiltinDeriveExpander {
 +            pub fn expand(
 +                &self,
 +                db: &dyn AstDatabase,
 +                id: MacroCallId,
 +                tt: &tt::Subtree,
 +            ) -> ExpandResult<tt::Subtree> {
 +                let expander = match *self {
 +                    $( BuiltinDeriveExpander::$trait => $expand, )*
 +                };
 +                expander(db, id, tt)
 +            }
 +
 +            fn find_by_name(name: &name::Name) -> Option<Self> {
 +                match name {
 +                    $( id if id == &name::name![$trait] => Some(BuiltinDeriveExpander::$trait), )*
 +                     _ => None,
 +                }
 +            }
 +        }
 +
 +    };
 +}
 +
 +register_builtin! {
 +    Copy => copy_expand,
 +    Clone => clone_expand,
 +    Default => default_expand,
 +    Debug => debug_expand,
 +    Hash => hash_expand,
 +    Ord => ord_expand,
 +    PartialOrd => partial_ord_expand,
 +    Eq => eq_expand,
 +    PartialEq => partial_eq_expand
 +}
 +
 +pub fn find_builtin_derive(ident: &name::Name) -> Option<BuiltinDeriveExpander> {
 +    BuiltinDeriveExpander::find_by_name(ident)
 +}
 +
 +struct BasicAdtInfo {
 +    name: tt::Ident,
-     let type_or_const_params =
-         params.map_or(0, |type_param_list| type_param_list.type_or_const_params().count());
-     Ok(BasicAdtInfo { name: name_token, type_or_const_params })
- }
- fn make_type_args(n: usize, bound: Vec<tt::TokenTree>) -> Vec<tt::TokenTree> {
-     let mut result = Vec::<tt::TokenTree>::with_capacity(n * 2);
-     result.push(
-         tt::Leaf::Punct(tt::Punct {
-             char: '<',
-             spacing: tt::Spacing::Alone,
-             id: tt::TokenId::unspecified(),
-         })
-         .into(),
-     );
-     for i in 0..n {
-         if i > 0 {
-             result.push(
-                 tt::Leaf::Punct(tt::Punct {
-                     char: ',',
-                     spacing: tt::Spacing::Alone,
-                     id: tt::TokenId::unspecified(),
-                 })
-                 .into(),
-             );
-         }
-         result.push(
-             tt::Leaf::Ident(tt::Ident {
-                 id: tt::TokenId::unspecified(),
-                 text: format!("T{}", i).into(),
-             })
-             .into(),
-         );
-         result.extend(bound.iter().cloned());
-     }
-     result.push(
-         tt::Leaf::Punct(tt::Punct {
-             char: '>',
-             spacing: tt::Spacing::Alone,
-             id: tt::TokenId::unspecified(),
++    /// `Some(ty)` if it's a const param of type `ty`, `None` if it's a type param.
++    param_types: Vec<Option<tt::Subtree>>,
 +}
 +
 +fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
 +    let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MacroItems);
 +    let macro_items = ast::MacroItems::cast(parsed.syntax_node()).ok_or_else(|| {
 +        debug!("derive node didn't parse");
 +        ExpandError::Other("invalid item definition".into())
 +    })?;
 +    let item = macro_items.items().next().ok_or_else(|| {
 +        debug!("no module item parsed");
 +        ExpandError::Other("no item found".into())
 +    })?;
 +    let node = item.syntax();
 +    let (name, params) = match_ast! {
 +        match node {
 +            ast::Struct(it) => (it.name(), it.generic_param_list()),
 +            ast::Enum(it) => (it.name(), it.generic_param_list()),
 +            ast::Union(it) => (it.name(), it.generic_param_list()),
 +            _ => {
 +                debug!("unexpected node is {:?}", node);
 +                return Err(ExpandError::Other("expected struct, enum or union".into()))
 +            },
 +        }
 +    };
 +    let name = name.ok_or_else(|| {
 +        debug!("parsed item has no name");
 +        ExpandError::Other("missing name".into())
 +    })?;
 +    let name_token_id =
 +        token_map.token_by_range(name.syntax().text_range()).unwrap_or_else(TokenId::unspecified);
 +    let name_token = tt::Ident { id: name_token_id, text: name.text().into() };
-         .into(),
-     );
-     result
++    let param_types = params
++        .into_iter()
++        .flat_map(|param_list| param_list.type_or_const_params())
++        .map(|param| {
++            if let ast::TypeOrConstParam::Const(param) = param {
++                let ty = param
++                    .ty()
++                    .map(|ty| mbe::syntax_node_to_token_tree(ty.syntax()).0)
++                    .unwrap_or_default();
++                Some(ty)
++            } else {
++                None
++            }
 +        })
-     let trait_path_clone = trait_path.token_trees.clone();
-     let bound = (quote! { : ##trait_path_clone }).token_trees;
-     let type_params = make_type_args(info.type_or_const_params, bound);
-     let type_args = make_type_args(info.type_or_const_params, Vec::new());
-     let trait_path = trait_path.token_trees;
++        .collect();
++    Ok(BasicAdtInfo { name: name_token, param_types })
 +}
 +
 +fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResult<tt::Subtree> {
 +    let info = match parse_adt(tt) {
 +        Ok(info) => info,
 +        Err(e) => return ExpandResult::only_err(e),
 +    };
++    let (params, args): (Vec<_>, Vec<_>) = info
++        .param_types
++        .into_iter()
++        .enumerate()
++        .map(|(idx, param_ty)| {
++            let ident = tt::Leaf::Ident(tt::Ident {
++                id: tt::TokenId::unspecified(),
++                text: format!("T{idx}").into(),
++            });
++            let ident_ = ident.clone();
++            if let Some(ty) = param_ty {
++                (quote! { const #ident : #ty , }, quote! { #ident_ , })
++            } else {
++                let bound = trait_path.clone();
++                (quote! { #ident : #bound , }, quote! { #ident_ , })
++            }
++        })
++        .unzip();
 +    let name = info.name;
-         impl ##type_params ##trait_path for #name ##type_args {}
 +    let expanded = quote! {
++        impl < ##params > #trait_path for #name < ##args > {}
 +    };
 +    ExpandResult::ok(expanded)
 +}
 +
 +fn find_builtin_crate(db: &dyn AstDatabase, id: MacroCallId) -> tt::TokenTree {
 +    // FIXME: make hygiene works for builtin derive macro
 +    // such that $crate can be used here.
 +    let cg = db.crate_graph();
 +    let krate = db.lookup_intern_macro_call(id).krate;
 +
 +    let tt = if matches!(cg[krate].origin, CrateOrigin::Lang(LangCrateOrigin::Core)) {
 +        cov_mark::hit!(test_copy_expand_in_core);
 +        quote! { crate }
 +    } else {
 +        quote! { core }
 +    };
 +
 +    tt.token_trees[0].clone()
 +}
 +
 +fn copy_expand(
 +    db: &dyn AstDatabase,
 +    id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    let krate = find_builtin_crate(db, id);
 +    expand_simple_derive(tt, quote! { #krate::marker::Copy })
 +}
 +
 +fn clone_expand(
 +    db: &dyn AstDatabase,
 +    id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    let krate = find_builtin_crate(db, id);
 +    expand_simple_derive(tt, quote! { #krate::clone::Clone })
 +}
 +
 +fn default_expand(
 +    db: &dyn AstDatabase,
 +    id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    let krate = find_builtin_crate(db, id);
 +    expand_simple_derive(tt, quote! { #krate::default::Default })
 +}
 +
 +fn debug_expand(
 +    db: &dyn AstDatabase,
 +    id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    let krate = find_builtin_crate(db, id);
 +    expand_simple_derive(tt, quote! { #krate::fmt::Debug })
 +}
 +
 +fn hash_expand(
 +    db: &dyn AstDatabase,
 +    id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    let krate = find_builtin_crate(db, id);
 +    expand_simple_derive(tt, quote! { #krate::hash::Hash })
 +}
 +
 +fn eq_expand(db: &dyn AstDatabase, id: MacroCallId, tt: &tt::Subtree) -> ExpandResult<tt::Subtree> {
 +    let krate = find_builtin_crate(db, id);
 +    expand_simple_derive(tt, quote! { #krate::cmp::Eq })
 +}
 +
 +fn partial_eq_expand(
 +    db: &dyn AstDatabase,
 +    id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    let krate = find_builtin_crate(db, id);
 +    expand_simple_derive(tt, quote! { #krate::cmp::PartialEq })
 +}
 +
 +fn ord_expand(
 +    db: &dyn AstDatabase,
 +    id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    let krate = find_builtin_crate(db, id);
 +    expand_simple_derive(tt, quote! { #krate::cmp::Ord })
 +}
 +
 +fn partial_ord_expand(
 +    db: &dyn AstDatabase,
 +    id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    let krate = find_builtin_crate(db, id);
 +    expand_simple_derive(tt, quote! { #krate::cmp::PartialOrd })
 +}
index 68413df420c7d7053c1f707f31fb5cc21d7affa0,0000000000000000000000000000000000000000..d7586d129b768b1e639b915df81f51aa4a5c89b5
mode 100644,000000..100644
--- /dev/null
@@@ -1,278 -1,0 +1,277 @@@
-     (core::ops::FromResidual) => {};
 +//! A lowering for `use`-paths (more generally, paths without angle-bracketed segments).
 +
 +use std::{
 +    fmt::{self, Display},
 +    iter,
 +};
 +
 +use crate::{
 +    db::AstDatabase,
 +    hygiene::Hygiene,
 +    name::{known, Name},
 +};
 +use base_db::CrateId;
 +use either::Either;
 +use smallvec::SmallVec;
 +use syntax::{ast, AstNode};
 +
 +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 +pub struct ModPath {
 +    pub kind: PathKind,
 +    segments: SmallVec<[Name; 1]>,
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 +pub struct UnescapedModPath<'a>(&'a ModPath);
 +
 +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 +pub enum PathKind {
 +    Plain,
 +    /// `self::` is `Super(0)`
 +    Super(u8),
 +    Crate,
 +    /// Absolute path (::foo)
 +    Abs,
 +    /// `$crate` from macro expansion
 +    DollarCrate(CrateId),
 +}
 +
 +impl ModPath {
 +    pub fn from_src(db: &dyn AstDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
 +        convert_path(db, None, path, hygiene)
 +    }
 +
 +    pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath {
 +        let segments = segments.into_iter().collect();
 +        ModPath { kind, segments }
 +    }
 +
 +    /// Creates a `ModPath` from a `PathKind`, with no extra path segments.
 +    pub const fn from_kind(kind: PathKind) -> ModPath {
 +        ModPath { kind, segments: SmallVec::new_const() }
 +    }
 +
 +    pub fn segments(&self) -> &[Name] {
 +        &self.segments
 +    }
 +
 +    pub fn push_segment(&mut self, segment: Name) {
 +        self.segments.push(segment);
 +    }
 +
 +    pub fn pop_segment(&mut self) -> Option<Name> {
 +        self.segments.pop()
 +    }
 +
 +    /// Returns the number of segments in the path (counting special segments like `$crate` and
 +    /// `super`).
 +    pub fn len(&self) -> usize {
 +        self.segments.len()
 +            + match self.kind {
 +                PathKind::Plain => 0,
 +                PathKind::Super(i) => i as usize,
 +                PathKind::Crate => 1,
 +                PathKind::Abs => 0,
 +                PathKind::DollarCrate(_) => 1,
 +            }
 +    }
 +
 +    pub fn is_ident(&self) -> bool {
 +        self.as_ident().is_some()
 +    }
 +
 +    pub fn is_self(&self) -> bool {
 +        self.kind == PathKind::Super(0) && self.segments.is_empty()
 +    }
 +
 +    #[allow(non_snake_case)]
 +    pub fn is_Self(&self) -> bool {
 +        self.kind == PathKind::Plain
 +            && matches!(&*self.segments, [name] if *name == known::SELF_TYPE)
 +    }
 +
 +    /// If this path is a single identifier, like `foo`, return its name.
 +    pub fn as_ident(&self) -> Option<&Name> {
 +        if self.kind != PathKind::Plain {
 +            return None;
 +        }
 +
 +        match &*self.segments {
 +            [name] => Some(name),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn unescaped(&self) -> UnescapedModPath<'_> {
 +        UnescapedModPath(self)
 +    }
 +
 +    fn _fmt(&self, f: &mut fmt::Formatter<'_>, escaped: bool) -> fmt::Result {
 +        let mut first_segment = true;
 +        let mut add_segment = |s| -> fmt::Result {
 +            if !first_segment {
 +                f.write_str("::")?;
 +            }
 +            first_segment = false;
 +            f.write_str(s)?;
 +            Ok(())
 +        };
 +        match self.kind {
 +            PathKind::Plain => {}
 +            PathKind::Super(0) => add_segment("self")?,
 +            PathKind::Super(n) => {
 +                for _ in 0..n {
 +                    add_segment("super")?;
 +                }
 +            }
 +            PathKind::Crate => add_segment("crate")?,
 +            PathKind::Abs => add_segment("")?,
 +            PathKind::DollarCrate(_) => add_segment("$crate")?,
 +        }
 +        for segment in &self.segments {
 +            if !first_segment {
 +                f.write_str("::")?;
 +            }
 +            first_segment = false;
 +            if escaped {
 +                segment.fmt(f)?
 +            } else {
 +                segment.unescaped().fmt(f)?
 +            };
 +        }
 +        Ok(())
 +    }
 +}
 +
 +impl Display for ModPath {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        self._fmt(f, true)
 +    }
 +}
 +
 +impl<'a> Display for UnescapedModPath<'a> {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        self.0._fmt(f, false)
 +    }
 +}
 +
 +impl From<Name> for ModPath {
 +    fn from(name: Name) -> ModPath {
 +        ModPath::from_segments(PathKind::Plain, iter::once(name))
 +    }
 +}
 +
 +fn convert_path(
 +    db: &dyn AstDatabase,
 +    prefix: Option<ModPath>,
 +    path: ast::Path,
 +    hygiene: &Hygiene,
 +) -> Option<ModPath> {
 +    let prefix = match path.qualifier() {
 +        Some(qual) => Some(convert_path(db, prefix, qual, hygiene)?),
 +        None => prefix,
 +    };
 +
 +    let segment = path.segment()?;
 +    let mut mod_path = match segment.kind()? {
 +        ast::PathSegmentKind::Name(name_ref) => {
 +            match hygiene.name_ref_to_name(db, name_ref) {
 +                Either::Left(name) => {
 +                    // no type args in use
 +                    let mut res = prefix.unwrap_or_else(|| {
 +                        ModPath::from_kind(
 +                            segment.coloncolon_token().map_or(PathKind::Plain, |_| PathKind::Abs),
 +                        )
 +                    });
 +                    res.segments.push(name);
 +                    res
 +                }
 +                Either::Right(crate_id) => {
 +                    return Some(ModPath::from_segments(
 +                        PathKind::DollarCrate(crate_id),
 +                        iter::empty(),
 +                    ))
 +                }
 +            }
 +        }
 +        ast::PathSegmentKind::SelfTypeKw => {
 +            if prefix.is_some() {
 +                return None;
 +            }
 +            ModPath::from_segments(PathKind::Plain, Some(known::SELF_TYPE))
 +        }
 +        ast::PathSegmentKind::CrateKw => {
 +            if prefix.is_some() {
 +                return None;
 +            }
 +            ModPath::from_segments(PathKind::Crate, iter::empty())
 +        }
 +        ast::PathSegmentKind::SelfKw => {
 +            if prefix.is_some() {
 +                return None;
 +            }
 +            ModPath::from_segments(PathKind::Super(0), iter::empty())
 +        }
 +        ast::PathSegmentKind::SuperKw => {
 +            let nested_super_count = match prefix.map(|p| p.kind) {
 +                Some(PathKind::Super(n)) => n,
 +                Some(_) => return None,
 +                None => 0,
 +            };
 +
 +            ModPath::from_segments(PathKind::Super(nested_super_count + 1), iter::empty())
 +        }
 +        ast::PathSegmentKind::Type { .. } => {
 +            // not allowed in imports
 +            return None;
 +        }
 +    };
 +
 +    // handle local_inner_macros :
 +    // Basically, even in rustc it is quite hacky:
 +    // https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456
 +    // We follow what it did anyway :)
 +    if mod_path.segments.len() == 1 && mod_path.kind == PathKind::Plain {
 +        if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
 +            if let Some(crate_id) = hygiene.local_inner_macros(db, path) {
 +                mod_path.kind = PathKind::DollarCrate(crate_id);
 +            }
 +        }
 +    }
 +
 +    Some(mod_path)
 +}
 +
 +pub use crate::name as __name;
 +
 +#[macro_export]
 +macro_rules! __known_path {
 +    (core::iter::IntoIterator) => {};
 +    (core::iter::Iterator) => {};
 +    (core::result::Result) => {};
 +    (core::option::Option) => {};
 +    (core::ops::Range) => {};
 +    (core::ops::RangeFrom) => {};
 +    (core::ops::RangeFull) => {};
 +    (core::ops::RangeTo) => {};
 +    (core::ops::RangeToInclusive) => {};
 +    (core::ops::RangeInclusive) => {};
 +    (core::future::Future) => {};
 +    (core::future::IntoFuture) => {};
 +    (core::ops::Try) => {};
 +    ($path:path) => {
 +        compile_error!("Please register your known path in the path module")
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! __path {
 +    ($start:ident $(:: $seg:ident)*) => ({
 +        $crate::__known_path!($start $(:: $seg)*);
 +        $crate::mod_path::ModPath::from_segments($crate::mod_path::PathKind::Abs, vec![
 +            $crate::mod_path::__name![$start], $($crate::mod_path::__name![$seg],)*
 +        ])
 +    });
 +}
 +
 +pub use crate::__path as path;
index 8a735b965ab8460a49003399a12b25e13cb9830b,0000000000000000000000000000000000000000..2679a1c3602671c35fcae81ba8f9fdef4eb90042
mode 100644,000000..100644
--- /dev/null
@@@ -1,449 -1,0 +1,447 @@@
-         Residual,
-         FromResidual,
 +//! See [`Name`].
 +
 +use std::fmt;
 +
 +use syntax::{ast, SmolStr, SyntaxKind};
 +
 +/// `Name` is a wrapper around string, which is used in hir for both references
 +/// and declarations. In theory, names should also carry hygiene info, but we are
 +/// not there yet!
 +///
 +/// Note that `Name` holds and prints escaped name i.e. prefixed with "r#" when it
 +/// is a raw identifier. Use [`unescaped()`][Name::unescaped] when you need the
 +/// name without "r#".
 +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub struct Name(Repr);
 +
 +/// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
 +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub struct UnescapedName<'a>(&'a Name);
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +enum Repr {
 +    Text(SmolStr),
 +    TupleField(usize),
 +}
 +
 +impl fmt::Display for Name {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match &self.0 {
 +            Repr::Text(text) => fmt::Display::fmt(&text, f),
 +            Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
 +        }
 +    }
 +}
 +
 +fn is_raw_identifier(name: &str) -> bool {
 +    let is_keyword = SyntaxKind::from_keyword(name).is_some();
 +    is_keyword && !matches!(name, "self" | "crate" | "super" | "Self")
 +}
 +
 +impl<'a> fmt::Display for UnescapedName<'a> {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match &self.0 .0 {
 +            Repr::Text(text) => {
 +                let text = text.strip_prefix("r#").unwrap_or(text);
 +                fmt::Display::fmt(&text, f)
 +            }
 +            Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
 +        }
 +    }
 +}
 +
 +impl<'a> UnescapedName<'a> {
 +    /// Returns the textual representation of this name as a [`SmolStr`]. Prefer using this over
 +    /// [`ToString::to_string`] if possible as this conversion is cheaper in the general case.
 +    pub fn to_smol_str(&self) -> SmolStr {
 +        match &self.0 .0 {
 +            Repr::Text(it) => {
 +                if let Some(stripped) = it.strip_prefix("r#") {
 +                    SmolStr::new(stripped)
 +                } else {
 +                    it.clone()
 +                }
 +            }
 +            Repr::TupleField(it) => SmolStr::new(&it.to_string()),
 +        }
 +    }
 +}
 +
 +impl Name {
 +    /// Note: this is private to make creating name from random string hard.
 +    /// Hopefully, this should allow us to integrate hygiene cleaner in the
 +    /// future, and to switch to interned representation of names.
 +    const fn new_text(text: SmolStr) -> Name {
 +        Name(Repr::Text(text))
 +    }
 +
 +    pub fn new_tuple_field(idx: usize) -> Name {
 +        Name(Repr::TupleField(idx))
 +    }
 +
 +    pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
 +        Self::new_text(lt.text().into())
 +    }
 +
 +    /// Shortcut to create inline plain text name
 +    const fn new_inline(text: &str) -> Name {
 +        Name::new_text(SmolStr::new_inline(text))
 +    }
 +
 +    /// Resolve a name from the text of token.
 +    fn resolve(raw_text: &str) -> Name {
 +        match raw_text.strip_prefix("r#") {
 +            // When `raw_text` starts with "r#" but the name does not coincide with any
 +            // keyword, we never need the prefix so we strip it.
 +            Some(text) if !is_raw_identifier(text) => Name::new_text(SmolStr::new(text)),
 +            // Keywords (in the current edition) *can* be used as a name in earlier editions of
 +            // Rust, e.g. "try" in Rust 2015. Even in such cases, we keep track of them in their
 +            // escaped form.
 +            None if is_raw_identifier(raw_text) => {
 +                Name::new_text(SmolStr::from_iter(["r#", raw_text]))
 +            }
 +            _ => Name::new_text(raw_text.into()),
 +        }
 +    }
 +
 +    /// A fake name for things missing in the source code.
 +    ///
 +    /// For example, `impl Foo for {}` should be treated as a trait impl for a
 +    /// type with a missing name. Similarly, `struct S { : u32 }` should have a
 +    /// single field with a missing name.
 +    ///
 +    /// Ideally, we want a `gensym` semantics for missing names -- each missing
 +    /// name is equal only to itself. It's not clear how to implement this in
 +    /// salsa though, so we punt on that bit for a moment.
 +    pub const fn missing() -> Name {
 +        Name::new_inline("[missing name]")
 +    }
 +
 +    /// Returns the tuple index this name represents if it is a tuple field.
 +    pub fn as_tuple_index(&self) -> Option<usize> {
 +        match self.0 {
 +            Repr::TupleField(idx) => Some(idx),
 +            _ => None,
 +        }
 +    }
 +
 +    /// Returns the text this name represents if it isn't a tuple field.
 +    pub fn as_text(&self) -> Option<SmolStr> {
 +        match &self.0 {
 +            Repr::Text(it) => Some(it.clone()),
 +            _ => None,
 +        }
 +    }
 +
 +    /// Returns the textual representation of this name as a [`SmolStr`].
 +    /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in
 +    /// the general case.
 +    pub fn to_smol_str(&self) -> SmolStr {
 +        match &self.0 {
 +            Repr::Text(it) => it.clone(),
 +            Repr::TupleField(it) => SmolStr::new(&it.to_string()),
 +        }
 +    }
 +
 +    pub fn unescaped(&self) -> UnescapedName<'_> {
 +        UnescapedName(self)
 +    }
 +
 +    pub fn is_escaped(&self) -> bool {
 +        match &self.0 {
 +            Repr::Text(it) => it.starts_with("r#"),
 +            Repr::TupleField(_) => false,
 +        }
 +    }
 +}
 +
 +pub trait AsName {
 +    fn as_name(&self) -> Name;
 +}
 +
 +impl AsName for ast::NameRef {
 +    fn as_name(&self) -> Name {
 +        match self.as_tuple_field() {
 +            Some(idx) => Name::new_tuple_field(idx),
 +            None => Name::resolve(&self.text()),
 +        }
 +    }
 +}
 +
 +impl AsName for ast::Name {
 +    fn as_name(&self) -> Name {
 +        Name::resolve(&self.text())
 +    }
 +}
 +
 +impl AsName for ast::NameOrNameRef {
 +    fn as_name(&self) -> Name {
 +        match self {
 +            ast::NameOrNameRef::Name(it) => it.as_name(),
 +            ast::NameOrNameRef::NameRef(it) => it.as_name(),
 +        }
 +    }
 +}
 +
 +impl AsName for tt::Ident {
 +    fn as_name(&self) -> Name {
 +        Name::resolve(&self.text)
 +    }
 +}
 +
 +impl AsName for ast::FieldKind {
 +    fn as_name(&self) -> Name {
 +        match self {
 +            ast::FieldKind::Name(nr) => nr.as_name(),
 +            ast::FieldKind::Index(idx) => {
 +                let idx = idx.text().parse::<usize>().unwrap_or(0);
 +                Name::new_tuple_field(idx)
 +            }
 +        }
 +    }
 +}
 +
 +impl AsName for base_db::Dependency {
 +    fn as_name(&self) -> Name {
 +        Name::new_text(SmolStr::new(&*self.name))
 +    }
 +}
 +
 +pub mod known {
 +    macro_rules! known_names {
 +        ($($ident:ident),* $(,)?) => {
 +            $(
 +                #[allow(bad_style)]
 +                pub const $ident: super::Name =
 +                    super::Name::new_inline(stringify!($ident));
 +            )*
 +        };
 +    }
 +
 +    known_names!(
 +        // Primitives
 +        isize,
 +        i8,
 +        i16,
 +        i32,
 +        i64,
 +        i128,
 +        usize,
 +        u8,
 +        u16,
 +        u32,
 +        u64,
 +        u128,
 +        f32,
 +        f64,
 +        bool,
 +        char,
 +        str,
 +        // Special names
 +        macro_rules,
 +        doc,
 +        cfg,
 +        cfg_attr,
 +        register_attr,
 +        register_tool,
 +        // Components of known path (value or mod name)
 +        std,
 +        core,
 +        alloc,
 +        iter,
 +        ops,
 +        future,
 +        result,
 +        boxed,
 +        option,
 +        prelude,
 +        rust_2015,
 +        rust_2018,
 +        rust_2021,
 +        v1,
 +        // Components of known path (type name)
 +        Iterator,
 +        IntoIterator,
 +        Item,
 +        IntoIter,
 +        Try,
 +        Ok,
 +        Future,
 +        IntoFuture,
 +        Result,
 +        Option,
 +        Output,
 +        Target,
 +        Box,
 +        RangeFrom,
 +        RangeFull,
 +        RangeInclusive,
 +        RangeToInclusive,
 +        RangeTo,
 +        Range,
 +        Neg,
 +        Not,
 +        None,
 +        Index,
 +        // Components of known path (function name)
 +        filter_map,
 +        next,
 +        iter_mut,
 +        len,
 +        is_empty,
 +        new,
 +        // Builtin macros
 +        asm,
 +        assert,
 +        column,
 +        compile_error,
 +        concat_idents,
 +        concat_bytes,
 +        concat,
 +        const_format_args,
 +        core_panic,
 +        env,
 +        file,
 +        format_args_nl,
 +        format_args,
 +        global_asm,
 +        include_bytes,
 +        include_str,
 +        include,
 +        line,
 +        llvm_asm,
 +        log_syntax,
 +        module_path,
 +        option_env,
 +        std_panic,
 +        stringify,
 +        trace_macros,
 +        unreachable,
 +        // Builtin derives
 +        Copy,
 +        Clone,
 +        Default,
 +        Debug,
 +        Hash,
 +        Ord,
 +        PartialOrd,
 +        Eq,
 +        PartialEq,
 +        // Builtin attributes
 +        bench,
 +        cfg_accessible,
 +        cfg_eval,
 +        crate_type,
 +        derive,
 +        global_allocator,
 +        test,
 +        test_case,
 +        recursion_limit,
 +        feature,
 +        // Safe intrinsics
 +        abort,
 +        add_with_overflow,
 +        black_box,
 +        bitreverse,
 +        bswap,
 +        caller_location,
 +        ctlz,
 +        ctpop,
 +        cttz,
 +        discriminant_value,
 +        forget,
 +        likely,
 +        maxnumf32,
 +        maxnumf64,
 +        min_align_of_val,
 +        min_align_of,
 +        minnumf32,
 +        minnumf64,
 +        mul_with_overflow,
 +        needs_drop,
 +        ptr_guaranteed_eq,
 +        ptr_guaranteed_ne,
 +        rotate_left,
 +        rotate_right,
 +        rustc_peek,
 +        saturating_add,
 +        saturating_sub,
 +        size_of_val,
 +        size_of,
 +        sub_with_overflow,
 +        type_id,
 +        type_name,
 +        unlikely,
 +        variant_count,
 +        wrapping_add,
 +        wrapping_mul,
 +        wrapping_sub,
 +        // known methods of lang items
 +        eq,
 +        ne,
 +        ge,
 +        gt,
 +        le,
 +        lt,
 +        // lang items
 +        add_assign,
 +        add,
 +        bitand_assign,
 +        bitand,
 +        bitor_assign,
 +        bitor,
 +        bitxor_assign,
 +        bitxor,
 +        branch,
 +        deref_mut,
 +        deref,
 +        div_assign,
 +        div,
 +        fn_mut,
 +        fn_once,
 +        future_trait,
 +        index,
 +        index_mut,
 +        into_future,
 +        mul_assign,
 +        mul,
 +        neg,
 +        not,
 +        owned_box,
 +        partial_ord,
 +        poll,
 +        r#fn,
 +        rem_assign,
 +        rem,
 +        shl_assign,
 +        shl,
 +        shr_assign,
 +        shr,
 +        sub_assign,
 +        sub,
 +    );
 +
 +    // self/Self cannot be used as an identifier
 +    pub const SELF_PARAM: super::Name = super::Name::new_inline("self");
 +    pub const SELF_TYPE: super::Name = super::Name::new_inline("Self");
 +
 +    pub const STATIC_LIFETIME: super::Name = super::Name::new_inline("'static");
 +
 +    #[macro_export]
 +    macro_rules! name {
 +        (self) => {
 +            $crate::name::known::SELF_PARAM
 +        };
 +        (Self) => {
 +            $crate::name::known::SELF_TYPE
 +        };
 +        ('static) => {
 +            $crate::name::known::STATIC_LIFETIME
 +        };
 +        ($ident:ident) => {
 +            $crate::name::known::$ident
 +        };
 +    }
 +}
 +
 +pub use crate::name;
index 6a5c4966f7ba5ee423b0b62273fa046ba1cbb37b,0000000000000000000000000000000000000000..0efff651cc174f91fcdcd5af56d4ab6c10ec07ae
mode 100644,000000..100644
--- /dev/null
@@@ -1,1134 -1,0 +1,1143 @@@
-     IncorrectTryTarget { expr: ExprId },
 +//! Type inference, i.e. the process of walking through the code and determining
 +//! the type of each expression and pattern.
 +//!
 +//! For type inference, compare the implementations in rustc (the various
 +//! check_* methods in rustc_hir_analysis/check/mod.rs are a good entry point) and
 +//! IntelliJ-Rust (org.rust.lang.core.types.infer). Our entry point for
 +//! inference here is the `infer` function, which infers the types of all
 +//! expressions in a given function.
 +//!
 +//! During inference, types (i.e. the `Ty` struct) can contain type 'variables'
 +//! which represent currently unknown types; as we walk through the expressions,
 +//! we might determine that certain variables need to be equal to each other, or
 +//! to certain types. To record this, we use the union-find implementation from
 +//! the `ena` crate, which is extracted from rustc.
 +
 +use std::ops::Index;
 +use std::sync::Arc;
 +
 +use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
 +use hir_def::{
 +    body::Body,
 +    builtin_type::BuiltinType,
 +    data::{ConstData, StaticData},
 +    expr::{BindingAnnotation, ExprId, PatId},
 +    lang_item::LangItemTarget,
 +    path::{path, Path},
 +    resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
 +    type_ref::TypeRef,
 +    AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule,
 +    ItemContainerId, Lookup, TraitId, TypeAliasId, VariantId,
 +};
 +use hir_expand::name::{name, Name};
 +use itertools::Either;
 +use la_arena::ArenaMap;
 +use rustc_hash::FxHashMap;
 +use stdx::{always, impl_from};
 +
 +use crate::{
 +    db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany,
 +    lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal,
 +    GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, Substitution,
 +    TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
 +};
 +
 +// This lint has a false positive here. See the link below for details.
 +//
 +// https://github.com/rust-lang/rust/issues/57411
 +#[allow(unreachable_pub)]
 +pub use coerce::could_coerce;
 +#[allow(unreachable_pub)]
 +pub use unify::could_unify;
 +
 +pub(crate) mod unify;
 +mod path;
 +mod expr;
 +mod pat;
 +mod coerce;
 +mod closure;
 +
 +/// The entry point of type inference.
 +pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
 +    let _p = profile::span("infer_query");
 +    let resolver = def.resolver(db.upcast());
 +    let body = db.body(def);
 +    let mut ctx = InferenceContext::new(db, def, &body, resolver);
 +
 +    match def {
 +        DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
 +        DefWithBodyId::FunctionId(f) => ctx.collect_fn(f),
 +        DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
 +        DefWithBodyId::VariantId(v) => {
 +            ctx.return_ty = TyBuilder::builtin(match db.enum_data(v.parent).variant_body_type() {
 +                Either::Left(builtin) => BuiltinType::Int(builtin),
 +                Either::Right(builtin) => BuiltinType::Uint(builtin),
 +            });
 +        }
 +    }
 +
 +    ctx.infer_body();
 +
 +    Arc::new(ctx.resolve_all())
 +}
 +
 +/// Fully normalize all the types found within `ty` in context of `owner` body definition.
 +///
 +/// This is appropriate to use only after type-check: it assumes
 +/// that normalization will succeed, for example.
 +pub(crate) fn normalize(db: &dyn HirDatabase, owner: DefWithBodyId, ty: Ty) -> Ty {
 +    if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION) {
 +        return ty;
 +    }
 +    let krate = owner.module(db.upcast()).krate();
 +    let trait_env = owner
 +        .as_generic_def_id()
 +        .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
 +    let mut table = unify::InferenceTable::new(db, trait_env);
 +
 +    let ty_with_vars = table.normalize_associated_types_in(ty);
 +    table.resolve_obligations_as_possible();
 +    table.propagate_diverging_flag();
 +    table.resolve_completely(ty_with_vars)
 +}
 +
 +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 +enum ExprOrPatId {
 +    ExprId(ExprId),
 +    PatId(PatId),
 +}
 +impl_from!(ExprId, PatId for ExprOrPatId);
 +
 +/// Binding modes inferred for patterns.
 +/// <https://doc.rust-lang.org/reference/patterns.html#binding-modes>
 +#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 +pub enum BindingMode {
 +    Move,
 +    Ref(Mutability),
 +}
 +
 +impl BindingMode {
 +    fn convert(annotation: BindingAnnotation) -> BindingMode {
 +        match annotation {
 +            BindingAnnotation::Unannotated | BindingAnnotation::Mutable => BindingMode::Move,
 +            BindingAnnotation::Ref => BindingMode::Ref(Mutability::Not),
 +            BindingAnnotation::RefMut => BindingMode::Ref(Mutability::Mut),
 +        }
 +    }
 +}
 +
 +impl Default for BindingMode {
 +    fn default() -> Self {
 +        BindingMode::Move
 +    }
 +}
 +
 +/// Used to generalize patterns and assignee expressions.
 +trait PatLike: Into<ExprOrPatId> + Copy {
 +    type BindingMode: Copy;
 +
 +    fn infer(
 +        this: &mut InferenceContext<'_>,
 +        id: Self,
 +        expected_ty: &Ty,
 +        default_bm: Self::BindingMode,
 +    ) -> Ty;
 +}
 +
 +impl PatLike for ExprId {
 +    type BindingMode = ();
 +
 +    fn infer(
 +        this: &mut InferenceContext<'_>,
 +        id: Self,
 +        expected_ty: &Ty,
 +        _: Self::BindingMode,
 +    ) -> Ty {
 +        this.infer_assignee_expr(id, expected_ty)
 +    }
 +}
 +
 +impl PatLike for PatId {
 +    type BindingMode = BindingMode;
 +
 +    fn infer(
 +        this: &mut InferenceContext<'_>,
 +        id: Self,
 +        expected_ty: &Ty,
 +        default_bm: Self::BindingMode,
 +    ) -> Ty {
 +        this.infer_pat(id, expected_ty, default_bm)
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub(crate) struct InferOk<T> {
 +    value: T,
 +    goals: Vec<InEnvironment<Goal>>,
 +}
 +
 +impl<T> InferOk<T> {
 +    fn map<U>(self, f: impl FnOnce(T) -> U) -> InferOk<U> {
 +        InferOk { value: f(self.value), goals: self.goals }
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub(crate) struct TypeError;
 +pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
 +
 +#[derive(Debug, PartialEq, Eq, Clone)]
 +pub enum InferenceDiagnostic {
 +    NoSuchField { expr: ExprId },
 +    BreakOutsideOfLoop { expr: ExprId, is_break: bool },
-     DoesNotImplement { expr: ExprId, trait_: TraitId, ty: Ty },
 +    MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
 +}
 +
 +/// A mismatch between an expected and an inferred type.
 +#[derive(Clone, PartialEq, Eq, Debug, Hash)]
 +pub struct TypeMismatch {
 +    pub expected: Ty,
 +    pub actual: Ty,
 +}
 +
 +#[derive(Clone, PartialEq, Eq, Debug)]
 +struct InternedStandardTypes {
 +    unknown: Ty,
 +    bool_: Ty,
 +    unit: Ty,
 +}
 +
 +impl Default for InternedStandardTypes {
 +    fn default() -> Self {
 +        InternedStandardTypes {
 +            unknown: TyKind::Error.intern(Interner),
 +            bool_: TyKind::Scalar(Scalar::Bool).intern(Interner),
 +            unit: TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner),
 +        }
 +    }
 +}
 +/// Represents coercing a value to a different type of value.
 +///
 +/// We transform values by following a number of `Adjust` steps in order.
 +/// See the documentation on variants of `Adjust` for more details.
 +///
 +/// Here are some common scenarios:
 +///
 +/// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
 +///    Here the pointer will be dereferenced N times (where a dereference can
 +///    happen to raw or borrowed pointers or any smart pointer which implements
 +///    Deref, including Box<_>). The types of dereferences is given by
 +///    `autoderefs`. It can then be auto-referenced zero or one times, indicated
 +///    by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
 +///    `false`.
 +///
 +/// 2. A thin-to-fat coercion involves unsizing the underlying data. We start
 +///    with a thin pointer, deref a number of times, unsize the underlying data,
 +///    then autoref. The 'unsize' phase may change a fixed length array to a
 +///    dynamically sized one, a concrete object to a trait object, or statically
 +///    sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is
 +///    represented by:
 +///
 +///    ```
 +///    Deref(None) -> [i32; 4],
 +///    Borrow(AutoBorrow::Ref) -> &[i32; 4],
 +///    Unsize -> &[i32],
 +///    ```
 +///
 +///    Note that for a struct, the 'deep' unsizing of the struct is not recorded.
 +///    E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
 +///    The autoderef and -ref are the same as in the above example, but the type
 +///    stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
 +///    the underlying conversions from `[i32; 4]` to `[i32]`.
 +///
 +/// 3. Coercing a `Box<T>` to `Box<dyn Trait>` is an interesting special case. In
 +///    that case, we have the pointer we need coming in, so there are no
 +///    autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
 +///    At some point, of course, `Box` should move out of the compiler, in which
 +///    case this is analogous to transforming a struct. E.g., Box<[i32; 4]> ->
 +///    Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`.
 +#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 +pub struct Adjustment {
 +    pub kind: Adjust,
 +    pub target: Ty,
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum Adjust {
 +    /// Go from ! to any type.
 +    NeverToAny,
 +    /// Dereference once, producing a place.
 +    Deref(Option<OverloadedDeref>),
 +    /// Take the address and produce either a `&` or `*` pointer.
 +    Borrow(AutoBorrow),
 +    Pointer(PointerCast),
 +}
 +
 +/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
 +/// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`.
 +/// The target type is `U` in both cases, with the region and mutability
 +/// being those shared by both the receiver and the returned reference.
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct OverloadedDeref(pub Mutability);
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum AutoBorrow {
 +    /// Converts from T to &T.
 +    Ref(Mutability),
 +    /// Converts from T to *T.
 +    RawPtr(Mutability),
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum PointerCast {
 +    /// Go from a fn-item type to a fn-pointer type.
 +    ReifyFnPointer,
 +
 +    /// Go from a safe fn pointer to an unsafe fn pointer.
 +    UnsafeFnPointer,
 +
 +    /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
 +    /// It cannot convert a closure that requires unsafe.
 +    ClosureFnPointer(Safety),
 +
 +    /// Go from a mut raw pointer to a const raw pointer.
 +    MutToConstPointer,
 +
 +    #[allow(dead_code)]
 +    /// Go from `*const [T; N]` to `*const T`
 +    ArrayToPointer,
 +
 +    /// Unsize a pointer/reference value, e.g., `&[T; n]` to
 +    /// `&[T]`. Note that the source could be a thin or fat pointer.
 +    /// This will do things like convert thin pointers to fat
 +    /// pointers, or convert structs containing thin pointers to
 +    /// structs containing fat pointers, or convert between fat
 +    /// pointers. We don't store the details of how the transform is
 +    /// done (in fact, we don't know that, because it might depend on
 +    /// the precise type parameters). We just store the target
 +    /// type. Codegen backends and miri figure out what has to be done
 +    /// based on the precise source/target type at hand.
 +    Unsize,
 +}
 +
 +/// The result of type inference: A mapping from expressions and patterns to types.
 +#[derive(Clone, PartialEq, Eq, Debug, Default)]
 +pub struct InferenceResult {
 +    /// For each method call expr, records the function it resolves to.
 +    method_resolutions: FxHashMap<ExprId, (FunctionId, Substitution)>,
 +    /// For each field access expr, records the field it resolves to.
 +    field_resolutions: FxHashMap<ExprId, FieldId>,
 +    /// For each struct literal or pattern, records the variant it resolves to.
 +    variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
 +    /// For each associated item record what it resolves to
 +    assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
 +    pub diagnostics: Vec<InferenceDiagnostic>,
 +    pub type_of_expr: ArenaMap<ExprId, Ty>,
 +    /// For each pattern record the type it resolves to.
 +    ///
 +    /// **Note**: When a pattern type is resolved it may still contain
 +    /// unresolved or missing subpatterns or subpatterns of mismatched types.
 +    pub type_of_pat: ArenaMap<PatId, Ty>,
 +    type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
 +    /// Interned common types to return references to.
 +    standard_types: InternedStandardTypes,
 +    /// Stores the types which were implicitly dereferenced in pattern binding modes.
 +    pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
 +    pub pat_binding_modes: FxHashMap<PatId, BindingMode>,
 +    pub expr_adjustments: FxHashMap<ExprId, Vec<Adjustment>>,
 +}
 +
 +impl InferenceResult {
 +    pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> {
 +        self.method_resolutions.get(&expr).cloned()
 +    }
 +    pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> {
 +        self.field_resolutions.get(&expr).copied()
 +    }
 +    pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> {
 +        self.variant_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
 +        self.variant_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<AssocItemId> {
 +        self.assoc_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<AssocItemId> {
 +        self.assoc_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
 +        self.type_mismatches.get(&expr.into())
 +    }
 +    pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch> {
 +        self.type_mismatches.get(&pat.into())
 +    }
 +    pub fn expr_type_mismatches(&self) -> impl Iterator<Item = (ExprId, &TypeMismatch)> {
 +        self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat {
 +            ExprOrPatId::ExprId(expr) => Some((expr, mismatch)),
 +            _ => None,
 +        })
 +    }
 +    pub fn pat_type_mismatches(&self) -> impl Iterator<Item = (PatId, &TypeMismatch)> {
 +        self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat {
 +            ExprOrPatId::PatId(pat) => Some((pat, mismatch)),
 +            _ => None,
 +        })
 +    }
 +}
 +
 +impl Index<ExprId> for InferenceResult {
 +    type Output = Ty;
 +
 +    fn index(&self, expr: ExprId) -> &Ty {
 +        self.type_of_expr.get(expr).unwrap_or(&self.standard_types.unknown)
 +    }
 +}
 +
 +impl Index<PatId> for InferenceResult {
 +    type Output = Ty;
 +
 +    fn index(&self, pat: PatId) -> &Ty {
 +        self.type_of_pat.get(pat).unwrap_or(&self.standard_types.unknown)
 +    }
 +}
 +
 +/// The inference context contains all information needed during type inference.
 +#[derive(Clone, Debug)]
 +pub(crate) struct InferenceContext<'a> {
 +    pub(crate) db: &'a dyn HirDatabase,
 +    pub(crate) owner: DefWithBodyId,
 +    pub(crate) body: &'a Body,
 +    pub(crate) resolver: Resolver,
 +    table: unify::InferenceTable<'a>,
 +    trait_env: Arc<TraitEnvironment>,
 +    pub(crate) result: InferenceResult,
 +    /// The return type of the function being inferred, the closure or async block if we're
 +    /// currently within one.
 +    ///
 +    /// We might consider using a nested inference context for checking
 +    /// closures, but currently this is the only field that will change there,
 +    /// so it doesn't make sense.
 +    return_ty: Ty,
 +    /// The resume type and the yield type, respectively, of the generator being inferred.
 +    resume_yield_tys: Option<(Ty, Ty)>,
 +    diverges: Diverges,
 +    breakables: Vec<BreakableContext>,
 +}
 +
 +#[derive(Clone, Debug)]
 +struct BreakableContext {
 +    /// Whether this context contains at least one break expression.
 +    may_break: bool,
 +    /// The coercion target of the context.
 +    coerce: CoerceMany,
 +    /// The optional label of the context.
 +    label: Option<name::Name>,
 +    kind: BreakableKind,
 +}
 +
 +#[derive(Clone, Debug)]
 +enum BreakableKind {
 +    Block,
 +    Loop,
 +    /// A border is something like an async block, closure etc. Anything that prevents
 +    /// breaking/continuing through
 +    Border,
 +}
 +
 +fn find_breakable<'c>(
 +    ctxs: &'c mut [BreakableContext],
 +    label: Option<&name::Name>,
 +) -> Option<&'c mut BreakableContext> {
 +    let mut ctxs = ctxs
 +        .iter_mut()
 +        .rev()
 +        .take_while(|it| matches!(it.kind, BreakableKind::Block | BreakableKind::Loop));
 +    match label {
 +        Some(_) => ctxs.find(|ctx| ctx.label.as_ref() == label),
 +        None => ctxs.find(|ctx| matches!(ctx.kind, BreakableKind::Loop)),
 +    }
 +}
 +
 +fn find_continuable<'c>(
 +    ctxs: &'c mut [BreakableContext],
 +    label: Option<&name::Name>,
 +) -> Option<&'c mut BreakableContext> {
 +    match label {
 +        Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)),
 +        None => find_breakable(ctxs, label),
 +    }
 +}
 +
 +impl<'a> InferenceContext<'a> {
 +    fn new(
 +        db: &'a dyn HirDatabase,
 +        owner: DefWithBodyId,
 +        body: &'a Body,
 +        resolver: Resolver,
 +    ) -> Self {
 +        let krate = owner.module(db.upcast()).krate();
 +        let trait_env = owner
 +            .as_generic_def_id()
 +            .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
 +        InferenceContext {
 +            result: InferenceResult::default(),
 +            table: unify::InferenceTable::new(db, trait_env.clone()),
 +            trait_env,
 +            return_ty: TyKind::Error.intern(Interner), // set in collect_fn_signature
 +            resume_yield_tys: None,
 +            db,
 +            owner,
 +            body,
 +            resolver,
 +            diverges: Diverges::Maybe,
 +            breakables: Vec::new(),
 +        }
 +    }
 +
 +    fn resolve_all(self) -> InferenceResult {
 +        let InferenceContext { mut table, mut result, .. } = self;
 +
 +        // FIXME resolve obligations as well (use Guidance if necessary)
 +        table.resolve_obligations_as_possible();
 +
 +        // make sure diverging type variables are marked as such
 +        table.propagate_diverging_flag();
 +        for ty in result.type_of_expr.values_mut() {
 +            *ty = table.resolve_completely(ty.clone());
 +        }
 +        for ty in result.type_of_pat.values_mut() {
 +            *ty = table.resolve_completely(ty.clone());
 +        }
 +        for mismatch in result.type_mismatches.values_mut() {
 +            mismatch.expected = table.resolve_completely(mismatch.expected.clone());
 +            mismatch.actual = table.resolve_completely(mismatch.actual.clone());
 +        }
 +        for (_, subst) in result.method_resolutions.values_mut() {
 +            *subst = table.resolve_completely(subst.clone());
 +        }
 +        for adjustment in result.expr_adjustments.values_mut().flatten() {
 +            adjustment.target = table.resolve_completely(adjustment.target.clone());
 +        }
 +        for adjustment in result.pat_adjustments.values_mut().flatten() {
 +            *adjustment = table.resolve_completely(adjustment.clone());
 +        }
 +        result
 +    }
 +
 +    fn collect_const(&mut self, data: &ConstData) {
 +        self.return_ty = self.make_ty(&data.type_ref);
 +    }
 +
 +    fn collect_static(&mut self, data: &StaticData) {
 +        self.return_ty = self.make_ty(&data.type_ref);
 +    }
 +
 +    fn collect_fn(&mut self, func: FunctionId) {
 +        let data = self.db.function_data(func);
 +        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
 +            .with_impl_trait_mode(ImplTraitLoweringMode::Param);
 +        let param_tys =
 +            data.params.iter().map(|(_, type_ref)| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
 +        for (ty, pat) in param_tys.into_iter().zip(self.body.params.iter()) {
 +            let ty = self.insert_type_vars(ty);
 +            let ty = self.normalize_associated_types_in(ty);
 +
 +            self.infer_pat(*pat, &ty, BindingMode::default());
 +        }
 +        let error_ty = &TypeRef::Error;
 +        let return_ty = if data.has_async_kw() {
 +            data.async_ret_type.as_deref().unwrap_or(error_ty)
 +        } else {
 +            &*data.ret_type
 +        };
 +        let return_ty = self.make_ty_with_mode(return_ty, ImplTraitLoweringMode::Opaque);
 +        self.return_ty = return_ty;
 +
 +        if let Some(rpits) = self.db.return_type_impl_traits(func) {
 +            // RPIT opaque types use substitution of their parent function.
 +            let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
 +            self.return_ty = fold_tys(
 +                self.return_ty.clone(),
 +                |ty, _| {
 +                    let opaque_ty_id = match ty.kind(Interner) {
 +                        TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id,
 +                        _ => return ty,
 +                    };
 +                    let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
 +                        ImplTraitId::ReturnTypeImplTrait(_, idx) => idx,
 +                        _ => unreachable!(),
 +                    };
 +                    let bounds = (*rpits).map_ref(|rpits| {
 +                        rpits.impl_traits[idx as usize].bounds.map_ref(|it| it.into_iter())
 +                    });
 +                    let var = self.table.new_type_var();
 +                    let var_subst = Substitution::from1(Interner, var.clone());
 +                    for bound in bounds {
 +                        let predicate =
 +                            bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders);
 +                        let (var_predicate, binders) = predicate
 +                            .substitute(Interner, &var_subst)
 +                            .into_value_and_skipped_binders();
 +                        always!(binders.len(Interner) == 0); // quantified where clauses not yet handled
 +                        self.push_obligation(var_predicate.cast(Interner));
 +                    }
 +                    var
 +                },
 +                DebruijnIndex::INNERMOST,
 +            );
 +        }
 +    }
 +
 +    fn infer_body(&mut self) {
 +        self.infer_expr_coerce(self.body.body_expr, &Expectation::has_type(self.return_ty.clone()));
 +    }
 +
 +    fn write_expr_ty(&mut self, expr: ExprId, ty: Ty) {
 +        self.result.type_of_expr.insert(expr, ty);
 +    }
 +
 +    fn write_expr_adj(&mut self, expr: ExprId, adjustments: Vec<Adjustment>) {
 +        self.result.expr_adjustments.insert(expr, adjustments);
 +    }
 +
 +    fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) {
 +        self.result.method_resolutions.insert(expr, (func, subst));
 +    }
 +
 +    fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantId) {
 +        self.result.variant_resolutions.insert(id, variant);
 +    }
 +
 +    fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId) {
 +        self.result.assoc_resolutions.insert(id, item);
 +    }
 +
 +    fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
 +        self.result.type_of_pat.insert(pat, ty);
 +    }
 +
 +    fn push_diagnostic(&mut self, diagnostic: InferenceDiagnostic) {
 +        self.result.diagnostics.push(diagnostic);
 +    }
 +
 +    fn make_ty_with_mode(
 +        &mut self,
 +        type_ref: &TypeRef,
 +        impl_trait_mode: ImplTraitLoweringMode,
 +    ) -> Ty {
 +        // FIXME use right resolver for block
 +        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
 +            .with_impl_trait_mode(impl_trait_mode);
 +        let ty = ctx.lower_ty(type_ref);
 +        let ty = self.insert_type_vars(ty);
 +        self.normalize_associated_types_in(ty)
 +    }
 +
 +    fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
 +        self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed)
 +    }
 +
 +    fn err_ty(&self) -> Ty {
 +        self.result.standard_types.unknown.clone()
 +    }
 +
 +    /// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it.
 +    fn insert_const_vars_shallow(&mut self, c: Const) -> Const {
 +        let data = c.data(Interner);
 +        match data.value {
 +            ConstValue::Concrete(cc) => match cc.interned {
 +                hir_def::type_ref::ConstScalar::Unknown => {
 +                    self.table.new_const_var(data.ty.clone())
 +                }
 +                _ => c,
 +            },
 +            _ => c,
 +        }
 +    }
 +
 +    /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
 +    fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
 +        match ty.kind(Interner) {
 +            TyKind::Error => self.table.new_type_var(),
 +            TyKind::InferenceVar(..) => {
 +                let ty_resolved = self.resolve_ty_shallow(&ty);
 +                if ty_resolved.is_unknown() {
 +                    self.table.new_type_var()
 +                } else {
 +                    ty
 +                }
 +            }
 +            _ => ty,
 +        }
 +    }
 +
 +    fn insert_type_vars(&mut self, ty: Ty) -> Ty {
 +        fold_tys_and_consts(
 +            ty,
 +            |x, _| match x {
 +                Either::Left(ty) => Either::Left(self.insert_type_vars_shallow(ty)),
 +                Either::Right(c) => Either::Right(self.insert_const_vars_shallow(c)),
 +            },
 +            DebruijnIndex::INNERMOST,
 +        )
 +    }
 +
 +    fn push_obligation(&mut self, o: DomainGoal) {
 +        self.table.register_obligation(o.cast(Interner));
 +    }
 +
 +    fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
 +        self.table.unify(ty1, ty2)
 +    }
 +
 +    /// Recurses through the given type, normalizing associated types mentioned
 +    /// in it by replacing them by type variables and registering obligations to
 +    /// resolve later. This should be done once for every type we get from some
 +    /// type annotation (e.g. from a let type annotation, field type or function
 +    /// call). `make_ty` handles this already, but e.g. for field types we need
 +    /// to do it as well.
 +    fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
 +        self.table.normalize_associated_types_in(ty)
 +    }
 +
 +    fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
 +        self.table.resolve_ty_shallow(ty)
 +    }
 +
 +    fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty {
 +        self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[])
 +    }
 +
 +    fn resolve_associated_type_with_params(
 +        &mut self,
 +        inner_ty: Ty,
 +        assoc_ty: Option<TypeAliasId>,
 +        // FIXME(GATs): these are args for the trait ref, args for assoc type itself should be
 +        // handled when we support them.
 +        params: &[GenericArg],
 +    ) -> Ty {
 +        match assoc_ty {
 +            Some(res_assoc_ty) => {
 +                let trait_ = match res_assoc_ty.lookup(self.db.upcast()).container {
 +                    hir_def::ItemContainerId::TraitId(trait_) => trait_,
 +                    _ => panic!("resolve_associated_type called with non-associated type"),
 +                };
 +                let ty = self.table.new_type_var();
 +                let mut param_iter = params.iter().cloned();
 +                let trait_ref = TyBuilder::trait_ref(self.db, trait_)
 +                    .push(inner_ty)
 +                    .fill(|_| param_iter.next().unwrap())
 +                    .build();
 +                let alias_eq = AliasEq {
 +                    alias: AliasTy::Projection(ProjectionTy {
 +                        associated_ty_id: to_assoc_type_id(res_assoc_ty),
 +                        substitution: trait_ref.substitution.clone(),
 +                    }),
 +                    ty: ty.clone(),
 +                };
 +                self.push_obligation(trait_ref.cast(Interner));
 +                self.push_obligation(alias_eq.cast(Interner));
 +                ty
 +            }
 +            None => self.err_ty(),
 +        }
 +    }
 +
 +    fn resolve_variant(&mut self, path: Option<&Path>, value_ns: bool) -> (Ty, Option<VariantId>) {
 +        let path = match path {
 +            Some(path) => path,
 +            None => return (self.err_ty(), None),
 +        };
 +        let resolver = &self.resolver;
 +        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
 +        // FIXME: this should resolve assoc items as well, see this example:
 +        // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
 +        let (resolution, unresolved) = if value_ns {
 +            match resolver.resolve_path_in_value_ns(self.db.upcast(), path.mod_path()) {
 +                Some(ResolveValueResult::ValueNs(value)) => match value {
 +                    ValueNs::EnumVariantId(var) => {
 +                        let substs = ctx.substs_from_path(path, var.into(), true);
 +                        let ty = self.db.ty(var.parent.into());
 +                        let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                        return (ty, Some(var.into()));
 +                    }
 +                    ValueNs::StructId(strukt) => {
 +                        let substs = ctx.substs_from_path(path, strukt.into(), true);
 +                        let ty = self.db.ty(strukt.into());
 +                        let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                        return (ty, Some(strukt.into()));
 +                    }
 +                    ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
 +                    _ => return (self.err_ty(), None),
 +                },
 +                Some(ResolveValueResult::Partial(typens, unresolved)) => (typens, Some(unresolved)),
 +                None => return (self.err_ty(), None),
 +            }
 +        } else {
 +            match resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
 +                Some(it) => it,
 +                None => return (self.err_ty(), None),
 +            }
 +        };
 +        return match resolution {
 +            TypeNs::AdtId(AdtId::StructId(strukt)) => {
 +                let substs = ctx.substs_from_path(path, strukt.into(), true);
 +                let ty = self.db.ty(strukt.into());
 +                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
 +            }
 +            TypeNs::AdtId(AdtId::UnionId(u)) => {
 +                let substs = ctx.substs_from_path(path, u.into(), true);
 +                let ty = self.db.ty(u.into());
 +                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                forbid_unresolved_segments((ty, Some(u.into())), unresolved)
 +            }
 +            TypeNs::EnumVariantId(var) => {
 +                let substs = ctx.substs_from_path(path, var.into(), true);
 +                let ty = self.db.ty(var.parent.into());
 +                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                forbid_unresolved_segments((ty, Some(var.into())), unresolved)
 +            }
 +            TypeNs::SelfType(impl_id) => {
 +                let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
 +                let substs = generics.placeholder_subst(self.db);
 +                let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
 +                self.resolve_variant_on_alias(ty, unresolved, path)
 +            }
 +            TypeNs::TypeAliasId(it) => {
 +                let container = it.lookup(self.db.upcast()).container;
 +                let parent_subst = match container {
 +                    ItemContainerId::TraitId(id) => {
 +                        let subst = TyBuilder::subst_for_def(self.db, id, None)
 +                            .fill_with_inference_vars(&mut self.table)
 +                            .build();
 +                        Some(subst)
 +                    }
 +                    // Type aliases do not exist in impls.
 +                    _ => None,
 +                };
 +                let ty = TyBuilder::def_ty(self.db, it.into(), parent_subst)
 +                    .fill_with_inference_vars(&mut self.table)
 +                    .build();
 +                self.resolve_variant_on_alias(ty, unresolved, path)
 +            }
 +            TypeNs::AdtSelfType(_) => {
 +                // FIXME this could happen in array size expressions, once we're checking them
 +                (self.err_ty(), None)
 +            }
 +            TypeNs::GenericParam(_) => {
 +                // FIXME potentially resolve assoc type
 +                (self.err_ty(), None)
 +            }
 +            TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::TraitId(_) => {
 +                // FIXME diagnostic
 +                (self.err_ty(), None)
 +            }
 +        };
 +
 +        fn forbid_unresolved_segments(
 +            result: (Ty, Option<VariantId>),
 +            unresolved: Option<usize>,
 +        ) -> (Ty, Option<VariantId>) {
 +            if unresolved.is_none() {
 +                result
 +            } else {
 +                // FIXME diagnostic
 +                (TyKind::Error.intern(Interner), None)
 +            }
 +        }
 +    }
 +
 +    fn resolve_variant_on_alias(
 +        &mut self,
 +        ty: Ty,
 +        unresolved: Option<usize>,
 +        path: &Path,
 +    ) -> (Ty, Option<VariantId>) {
 +        let remaining = unresolved.map(|x| path.segments().skip(x).len()).filter(|x| x > &0);
 +        match remaining {
 +            None => {
 +                let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id {
 +                    AdtId::StructId(s) => Some(VariantId::StructId(s)),
 +                    AdtId::UnionId(u) => Some(VariantId::UnionId(u)),
 +                    AdtId::EnumId(_) => {
 +                        // FIXME Error E0071, expected struct, variant or union type, found enum `Foo`
 +                        None
 +                    }
 +                });
 +                (ty, variant)
 +            }
 +            Some(1) => {
 +                let segment = path.mod_path().segments().last().unwrap();
 +                // this could be an enum variant or associated type
 +                if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
 +                    let enum_data = self.db.enum_data(enum_id);
 +                    if let Some(local_id) = enum_data.variant(segment) {
 +                        let variant = EnumVariantId { parent: enum_id, local_id };
 +                        return (ty, Some(variant.into()));
 +                    }
 +                }
 +                // FIXME potentially resolve assoc type
 +                (self.err_ty(), None)
 +            }
 +            Some(_) => {
 +                // FIXME diagnostic
 +                (self.err_ty(), None)
 +            }
 +        }
 +    }
 +
 +    fn resolve_lang_item(&self, name: Name) -> Option<LangItemTarget> {
 +        let krate = self.resolver.krate();
 +        self.db.lang_item(krate, name.to_smol_str())
 +    }
 +
 +    fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
 +        let path = path![core::iter::IntoIterator];
 +        let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![IntoIter])
 +    }
 +
 +    fn resolve_iterator_item(&self) -> Option<TypeAliasId> {
 +        let path = path![core::iter::Iterator];
 +        let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Item])
 +    }
 +
++    fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
++        // FIXME resolve via lang_item once try v2 is stable
++        let path = path![core::ops::Try];
++        let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
++        let trait_data = self.db.trait_data(trait_);
++        trait_data
++            // FIXME remove once try v2 is stable
++            .associated_type_by_name(&name![Ok])
++            .or_else(|| trait_data.associated_type_by_name(&name![Output]))
++    }
++
 +    fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
 +        let trait_ = self.resolve_lang_item(name![neg])?.as_trait()?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Output])
 +    }
 +
 +    fn resolve_ops_not_output(&self) -> Option<TypeAliasId> {
 +        let trait_ = self.resolve_lang_item(name![not])?.as_trait()?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Output])
 +    }
 +
 +    fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
 +        let trait_ = self
 +            .resolver
 +            .resolve_known_trait(self.db.upcast(), &path![core::future::IntoFuture])
 +            .or_else(|| self.resolve_lang_item(name![future_trait])?.as_trait())?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Output])
 +    }
 +
 +    fn resolve_boxed_box(&self) -> Option<AdtId> {
 +        let struct_ = self.resolve_lang_item(name![owned_box])?.as_struct()?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range_full(&self) -> Option<AdtId> {
 +        let path = path![core::ops::RangeFull];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range(&self) -> Option<AdtId> {
 +        let path = path![core::ops::Range];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range_inclusive(&self) -> Option<AdtId> {
 +        let path = path![core::ops::RangeInclusive];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range_from(&self) -> Option<AdtId> {
 +        let path = path![core::ops::RangeFrom];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range_to(&self) -> Option<AdtId> {
 +        let path = path![core::ops::RangeTo];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range_to_inclusive(&self) -> Option<AdtId> {
 +        let path = path![core::ops::RangeToInclusive];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_ops_index(&self) -> Option<TraitId> {
 +        self.resolve_lang_item(name![index])?.as_trait()
 +    }
 +
 +    fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
 +        let trait_ = self.resolve_ops_index()?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Output])
 +    }
 +}
 +
 +/// When inferring an expression, we propagate downward whatever type hint we
 +/// are able in the form of an `Expectation`.
 +#[derive(Clone, PartialEq, Eq, Debug)]
 +pub(crate) enum Expectation {
 +    None,
 +    HasType(Ty),
 +    // Castable(Ty), // rustc has this, we currently just don't propagate an expectation for casts
 +    RValueLikeUnsized(Ty),
 +}
 +
 +impl Expectation {
 +    /// The expectation that the type of the expression needs to equal the given
 +    /// type.
 +    fn has_type(ty: Ty) -> Self {
 +        if ty.is_unknown() {
 +            // FIXME: get rid of this?
 +            Expectation::None
 +        } else {
 +            Expectation::HasType(ty)
 +        }
 +    }
 +
 +    fn from_option(ty: Option<Ty>) -> Self {
 +        ty.map_or(Expectation::None, Expectation::HasType)
 +    }
 +
 +    /// The following explanation is copied straight from rustc:
 +    /// Provides an expectation for an rvalue expression given an *optional*
 +    /// hint, which is not required for type safety (the resulting type might
 +    /// be checked higher up, as is the case with `&expr` and `box expr`), but
 +    /// is useful in determining the concrete type.
 +    ///
 +    /// The primary use case is where the expected type is a fat pointer,
 +    /// like `&[isize]`. For example, consider the following statement:
 +    ///
 +    ///    let x: &[isize] = &[1, 2, 3];
 +    ///
 +    /// In this case, the expected type for the `&[1, 2, 3]` expression is
 +    /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
 +    /// expectation `ExpectHasType([isize])`, that would be too strong --
 +    /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`.
 +    /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced
 +    /// to the type `&[isize]`. Therefore, we propagate this more limited hint,
 +    /// which still is useful, because it informs integer literals and the like.
 +    /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
 +    /// for examples of where this comes up,.
 +    fn rvalue_hint(table: &mut unify::InferenceTable<'_>, ty: Ty) -> Self {
 +        // FIXME: do struct_tail_without_normalization
 +        match table.resolve_ty_shallow(&ty).kind(Interner) {
 +            TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => Expectation::RValueLikeUnsized(ty),
 +            _ => Expectation::has_type(ty),
 +        }
 +    }
 +
 +    /// This expresses no expectation on the type.
 +    fn none() -> Self {
 +        Expectation::None
 +    }
 +
 +    fn resolve(&self, table: &mut unify::InferenceTable<'_>) -> Expectation {
 +        match self {
 +            Expectation::None => Expectation::None,
 +            Expectation::HasType(t) => Expectation::HasType(table.resolve_ty_shallow(t)),
 +            Expectation::RValueLikeUnsized(t) => {
 +                Expectation::RValueLikeUnsized(table.resolve_ty_shallow(t))
 +            }
 +        }
 +    }
 +
 +    fn to_option(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> {
 +        match self.resolve(table) {
 +            Expectation::None => None,
 +            Expectation::HasType(t) |
 +            // Expectation::Castable(t) |
 +            Expectation::RValueLikeUnsized(t) => Some(t),
 +        }
 +    }
 +
 +    fn only_has_type(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> {
 +        match self {
 +            Expectation::HasType(t) => Some(table.resolve_ty_shallow(t)),
 +            // Expectation::Castable(_) |
 +            Expectation::RValueLikeUnsized(_) | Expectation::None => None,
 +        }
 +    }
 +
 +    /// Comment copied from rustc:
 +    /// Disregard "castable to" expectations because they
 +    /// can lead us astray. Consider for example `if cond
 +    /// {22} else {c} as u8` -- if we propagate the
 +    /// "castable to u8" constraint to 22, it will pick the
 +    /// type 22u8, which is overly constrained (c might not
 +    /// be a u8). In effect, the problem is that the
 +    /// "castable to" expectation is not the tightest thing
 +    /// we can say, so we want to drop it in this case.
 +    /// The tightest thing we can say is "must unify with
 +    /// else branch". Note that in the case of a "has type"
 +    /// constraint, this limitation does not hold.
 +    ///
 +    /// If the expected type is just a type variable, then don't use
 +    /// an expected type. Otherwise, we might write parts of the type
 +    /// when checking the 'then' block which are incompatible with the
 +    /// 'else' branch.
 +    fn adjust_for_branches(&self, table: &mut unify::InferenceTable<'_>) -> Expectation {
 +        match self {
 +            Expectation::HasType(ety) => {
 +                let ety = table.resolve_ty_shallow(ety);
 +                if !ety.is_ty_var() {
 +                    Expectation::HasType(ety)
 +                } else {
 +                    Expectation::None
 +                }
 +            }
 +            Expectation::RValueLikeUnsized(ety) => Expectation::RValueLikeUnsized(ety.clone()),
 +            _ => Expectation::None,
 +        }
 +    }
 +}
 +
 +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
 +enum Diverges {
 +    Maybe,
 +    Always,
 +}
 +
 +impl Diverges {
 +    fn is_always(self) -> bool {
 +        self == Diverges::Always
 +    }
 +}
 +
 +impl std::ops::BitAnd for Diverges {
 +    type Output = Self;
 +    fn bitand(self, other: Self) -> Self {
 +        std::cmp::min(self, other)
 +    }
 +}
 +
 +impl std::ops::BitOr for Diverges {
 +    type Output = Self;
 +    fn bitor(self, other: Self) -> Self {
 +        std::cmp::max(self, other)
 +    }
 +}
 +
 +impl std::ops::BitAndAssign for Diverges {
 +    fn bitand_assign(&mut self, other: Self) {
 +        *self = *self & other;
 +    }
 +}
 +
 +impl std::ops::BitOrAssign for Diverges {
 +    fn bitor_assign(&mut self, other: Self) {
 +        *self = *self | other;
 +    }
 +}
index 59ab50d0717ba6d5050e28c533f3c3543a881740,0000000000000000000000000000000000000000..f56108b26c45bdaea3096f4616828c28ba260d12
mode 100644,000000..100644
--- /dev/null
@@@ -1,1616 -1,0 +1,1533 @@@
- use hir_expand::{name, name::Name};
 +//! Type inference for expressions.
 +
 +use std::{
 +    collections::hash_map::Entry,
 +    iter::{repeat, repeat_with},
 +    mem,
 +};
 +
 +use chalk_ir::{
 +    cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
 +};
 +use hir_def::{
 +    expr::{
 +        ArithOp, Array, BinaryOp, ClosureKind, CmpOp, Expr, ExprId, LabelId, Literal, Statement,
 +        UnaryOp,
 +    },
 +    generics::TypeOrConstParamData,
 +    path::{GenericArg, GenericArgs},
 +    resolver::resolver_for_expr,
 +    ConstParamId, FieldId, ItemContainerId, Lookup,
 +};
-     infer::{coerce::CoerceMany, find_continuable, path, BreakableKind},
++use hir_expand::name::Name;
 +use stdx::always;
 +use syntax::ast::RangeOp;
 +
 +use crate::{
 +    autoderef::{self, Autoderef},
 +    consteval,
-     static_lifetime, to_assoc_type_id, to_chalk_trait_id,
++    infer::{coerce::CoerceMany, find_continuable, BreakableKind},
 +    lower::{
 +        const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
 +    },
 +    mapping::{from_chalk, ToChalk},
 +    method_resolution::{self, lang_names_for_bin_op, VisibleFromModule},
 +    primitive::{self, UintTy},
-     AdtId, AliasEq, AliasTy, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner,
-     ProjectionTy, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
++    static_lifetime, to_chalk_trait_id,
 +    utils::{generics, Generics},
-             &Expr::Try { expr } => {
-                 let inner_ty = self.infer_expr_inner(expr, &Expectation::none());
-                 match self.resolve_try_impl_for(inner_ty.clone()) {
-                     Some((_, Some((output, residual)))) => {
-                         if let Some((_trait, false)) =
-                             self.implements_from_residual(self.return_ty.clone(), residual)
-                         {
-                             self.push_diagnostic(InferenceDiagnostic::IncorrectTryTarget {
-                                 expr: tgt_expr,
-                             });
-                         }
-                         output
-                     }
-                     Some((trait_, None)) => {
-                         self.push_diagnostic(InferenceDiagnostic::DoesNotImplement {
-                             expr,
-                             trait_,
-                             ty: inner_ty,
-                         });
-                         self.err_ty()
-                     }
-                     None => self.err_ty(),
-                 }
++    AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar,
++    Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
 +};
 +
 +use super::{
 +    coerce::auto_deref_adjust_steps, find_breakable, BindingMode, BreakableContext, Diverges,
 +    Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch,
 +};
 +
 +impl<'a> InferenceContext<'a> {
 +    pub(crate) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
 +        let ty = self.infer_expr_inner(tgt_expr, expected);
 +        if let Some(expected_ty) = expected.only_has_type(&mut self.table) {
 +            let could_unify = self.unify(&ty, &expected_ty);
 +            if !could_unify {
 +                self.result.type_mismatches.insert(
 +                    tgt_expr.into(),
 +                    TypeMismatch { expected: expected_ty, actual: ty.clone() },
 +                );
 +            }
 +        }
 +        ty
 +    }
 +
 +    /// Infer type of expression with possibly implicit coerce to the expected type.
 +    /// Return the type after possible coercion.
 +    pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
 +        let ty = self.infer_expr_inner(expr, expected);
 +        if let Some(target) = expected.only_has_type(&mut self.table) {
 +            match self.coerce(Some(expr), &ty, &target) {
 +                Ok(res) => res,
 +                Err(_) => {
 +                    self.result.type_mismatches.insert(
 +                        expr.into(),
 +                        TypeMismatch { expected: target.clone(), actual: ty.clone() },
 +                    );
 +                    target
 +                }
 +            }
 +        } else {
 +            ty
 +        }
 +    }
 +
 +    fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
 +        self.db.unwind_if_cancelled();
 +
 +        let ty = match &self.body[tgt_expr] {
 +            Expr::Missing => self.err_ty(),
 +            &Expr::If { condition, then_branch, else_branch } => {
 +                self.infer_expr(
 +                    condition,
 +                    &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
 +                );
 +
 +                let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
 +                let mut both_arms_diverge = Diverges::Always;
 +
 +                let result_ty = self.table.new_type_var();
 +                let then_ty = self.infer_expr_inner(then_branch, expected);
 +                both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe);
 +                let mut coerce = CoerceMany::new(result_ty);
 +                coerce.coerce(self, Some(then_branch), &then_ty);
 +                let else_ty = match else_branch {
 +                    Some(else_branch) => self.infer_expr_inner(else_branch, expected),
 +                    None => TyBuilder::unit(),
 +                };
 +                both_arms_diverge &= self.diverges;
 +                // FIXME: create a synthetic `else {}` so we have something to refer to here instead of None?
 +                coerce.coerce(self, else_branch, &else_ty);
 +
 +                self.diverges = condition_diverges | both_arms_diverge;
 +
 +                coerce.complete()
 +            }
 +            &Expr::Let { pat, expr } => {
 +                let input_ty = self.infer_expr(expr, &Expectation::none());
 +                self.infer_pat(pat, &input_ty, BindingMode::default());
 +                TyKind::Scalar(Scalar::Bool).intern(Interner)
 +            }
 +            Expr::Block { statements, tail, label, id: _ } => {
 +                let old_resolver = mem::replace(
 +                    &mut self.resolver,
 +                    resolver_for_expr(self.db.upcast(), self.owner, tgt_expr),
 +                );
 +                let ty = match label {
 +                    Some(_) => {
 +                        let break_ty = self.table.new_type_var();
 +                        let (breaks, ty) = self.with_breakable_ctx(
 +                            BreakableKind::Block,
 +                            break_ty.clone(),
 +                            *label,
 +                            |this| {
 +                                this.infer_block(
 +                                    tgt_expr,
 +                                    statements,
 +                                    *tail,
 +                                    &Expectation::has_type(break_ty),
 +                                )
 +                            },
 +                        );
 +                        breaks.unwrap_or(ty)
 +                    }
 +                    None => self.infer_block(tgt_expr, statements, *tail, expected),
 +                };
 +                self.resolver = old_resolver;
 +                ty
 +            }
 +            Expr::Unsafe { body } => self.infer_expr(*body, expected),
 +            Expr::Const { body } => {
 +                self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
 +                    this.infer_expr(*body, expected)
 +                })
 +                .1
 +            }
 +            Expr::TryBlock { body } => {
 +                self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
 +                    let _inner = this.infer_expr(*body, expected);
 +                });
 +                // FIXME should be std::result::Result<{inner}, _>
 +                self.err_ty()
 +            }
 +            Expr::Async { body } => {
 +                let ret_ty = self.table.new_type_var();
 +                let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
 +                let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
 +
 +                let (_, inner_ty) =
 +                    self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
 +                        this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty))
 +                    });
 +
 +                self.diverges = prev_diverges;
 +                self.return_ty = prev_ret_ty;
 +
 +                // Use the first type parameter as the output type of future.
 +                // existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
 +                let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
 +                let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
 +                TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty))
 +                    .intern(Interner)
 +            }
 +            &Expr::Loop { body, label } => {
 +                let ty = self.table.new_type_var();
 +                let (breaks, ()) =
 +                    self.with_breakable_ctx(BreakableKind::Loop, ty, label, |this| {
 +                        this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
 +                    });
 +
 +                match breaks {
 +                    Some(breaks) => {
 +                        self.diverges = Diverges::Maybe;
 +                        breaks
 +                    }
 +                    None => TyKind::Never.intern(Interner),
 +                }
 +            }
 +            &Expr::While { condition, body, label } => {
 +                self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
 +                    this.infer_expr(
 +                        condition,
 +                        &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
 +                    );
 +                    this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
 +                });
 +
 +                // the body may not run, so it diverging doesn't mean we diverge
 +                self.diverges = Diverges::Maybe;
 +                TyBuilder::unit()
 +            }
 +            &Expr::For { iterable, body, pat, label } => {
 +                let iterable_ty = self.infer_expr(iterable, &Expectation::none());
 +                let into_iter_ty =
 +                    self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
 +                let pat_ty =
 +                    self.resolve_associated_type(into_iter_ty, self.resolve_iterator_item());
 +
 +                self.infer_pat(pat, &pat_ty, BindingMode::default());
 +                self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
 +                    this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
 +                });
 +
 +                // the body may not run, so it diverging doesn't mean we diverge
 +                self.diverges = Diverges::Maybe;
 +                TyBuilder::unit()
 +            }
 +            Expr::Closure { body, args, ret_type, arg_types, closure_kind } => {
 +                assert_eq!(args.len(), arg_types.len());
 +
 +                let mut sig_tys = Vec::new();
 +
 +                // collect explicitly written argument types
 +                for arg_type in arg_types.iter() {
 +                    let arg_ty = match arg_type {
 +                        Some(type_ref) => self.make_ty(type_ref),
 +                        None => self.table.new_type_var(),
 +                    };
 +                    sig_tys.push(arg_ty);
 +                }
 +
 +                // add return type
 +                let ret_ty = match ret_type {
 +                    Some(type_ref) => self.make_ty(type_ref),
 +                    None => self.table.new_type_var(),
 +                };
 +                sig_tys.push(ret_ty.clone());
 +                let sig_ty = TyKind::Function(FnPointer {
 +                    num_binders: 0,
 +                    sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false },
 +                    substitution: FnSubst(
 +                        Substitution::from_iter(Interner, sig_tys.clone()).shifted_in(Interner),
 +                    ),
 +                })
 +                .intern(Interner);
 +
 +                let (ty, resume_yield_tys) = if matches!(closure_kind, ClosureKind::Generator(_)) {
 +                    // FIXME: report error when there are more than 1 parameter.
 +                    let resume_ty = match sig_tys.first() {
 +                        // When `sig_tys.len() == 1` the first type is the return type, not the
 +                        // first parameter type.
 +                        Some(ty) if sig_tys.len() > 1 => ty.clone(),
 +                        _ => self.result.standard_types.unit.clone(),
 +                    };
 +                    let yield_ty = self.table.new_type_var();
 +
 +                    let subst = TyBuilder::subst_for_generator(self.db, self.owner)
 +                        .push(resume_ty.clone())
 +                        .push(yield_ty.clone())
 +                        .push(ret_ty.clone())
 +                        .build();
 +
 +                    let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
 +                    let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
 +
 +                    (generator_ty, Some((resume_ty, yield_ty)))
 +                } else {
 +                    let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
 +                    let closure_ty =
 +                        TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
 +                            .intern(Interner);
 +
 +                    (closure_ty, None)
 +                };
 +
 +                // Eagerly try to relate the closure type with the expected
 +                // type, otherwise we often won't have enough information to
 +                // infer the body.
 +                self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected);
 +
 +                // Now go through the argument patterns
 +                for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
 +                    self.infer_pat(*arg_pat, &arg_ty, BindingMode::default());
 +                }
 +
 +                let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
 +                let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
 +                let prev_resume_yield_tys =
 +                    mem::replace(&mut self.resume_yield_tys, resume_yield_tys);
 +
 +                self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
 +                    this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
 +                });
 +
 +                self.diverges = prev_diverges;
 +                self.return_ty = prev_ret_ty;
 +                self.resume_yield_tys = prev_resume_yield_tys;
 +
 +                ty
 +            }
 +            Expr::Call { callee, args, .. } => {
 +                let callee_ty = self.infer_expr(*callee, &Expectation::none());
 +                let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone());
 +                let mut res = None;
 +                let mut derefed_callee = callee_ty.clone();
 +                // manual loop to be able to access `derefs.table`
 +                while let Some((callee_deref_ty, _)) = derefs.next() {
 +                    res = derefs.table.callable_sig(&callee_deref_ty, args.len());
 +                    if res.is_some() {
 +                        derefed_callee = callee_deref_ty;
 +                        break;
 +                    }
 +                }
 +                // if the function is unresolved, we use is_varargs=true to
 +                // suppress the arg count diagnostic here
 +                let is_varargs =
 +                    derefed_callee.callable_sig(self.db).map_or(false, |sig| sig.is_varargs)
 +                        || res.is_none();
 +                let (param_tys, ret_ty) = match res {
 +                    Some(res) => {
 +                        let adjustments = auto_deref_adjust_steps(&derefs);
 +                        self.write_expr_adj(*callee, adjustments);
 +                        res
 +                    }
 +                    None => (Vec::new(), self.err_ty()), // FIXME diagnostic
 +                };
 +                let indices_to_skip = self.check_legacy_const_generics(derefed_callee, args);
 +                self.register_obligations_for_call(&callee_ty);
 +
 +                let expected_inputs = self.expected_inputs_for_expected_output(
 +                    expected,
 +                    ret_ty.clone(),
 +                    param_tys.clone(),
 +                );
 +
 +                self.check_call_arguments(
 +                    tgt_expr,
 +                    args,
 +                    &expected_inputs,
 +                    &param_tys,
 +                    &indices_to_skip,
 +                    is_varargs,
 +                );
 +                self.normalize_associated_types_in(ret_ty)
 +            }
 +            Expr::MethodCall { receiver, args, method_name, generic_args } => self
 +                .infer_method_call(
 +                    tgt_expr,
 +                    *receiver,
 +                    args,
 +                    method_name,
 +                    generic_args.as_deref(),
 +                    expected,
 +                ),
 +            Expr::Match { expr, arms } => {
 +                let input_ty = self.infer_expr(*expr, &Expectation::none());
 +
 +                let expected = expected.adjust_for_branches(&mut self.table);
 +
 +                let result_ty = if arms.is_empty() {
 +                    TyKind::Never.intern(Interner)
 +                } else {
 +                    match &expected {
 +                        Expectation::HasType(ty) => ty.clone(),
 +                        _ => self.table.new_type_var(),
 +                    }
 +                };
 +                let mut coerce = CoerceMany::new(result_ty);
 +
 +                let matchee_diverges = self.diverges;
 +                let mut all_arms_diverge = Diverges::Always;
 +
 +                for arm in arms.iter() {
 +                    self.diverges = Diverges::Maybe;
 +                    let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
 +                    if let Some(guard_expr) = arm.guard {
 +                        self.infer_expr(
 +                            guard_expr,
 +                            &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
 +                        );
 +                    }
 +
 +                    let arm_ty = self.infer_expr_inner(arm.expr, &expected);
 +                    all_arms_diverge &= self.diverges;
 +                    coerce.coerce(self, Some(arm.expr), &arm_ty);
 +                }
 +
 +                self.diverges = matchee_diverges | all_arms_diverge;
 +
 +                coerce.complete()
 +            }
 +            Expr::Path(p) => {
 +                // FIXME this could be more efficient...
 +                let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
 +                self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or_else(|| self.err_ty())
 +            }
 +            Expr::Continue { label } => {
 +                if let None = find_continuable(&mut self.breakables, label.as_ref()) {
 +                    self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
 +                        expr: tgt_expr,
 +                        is_break: false,
 +                    });
 +                };
 +                TyKind::Never.intern(Interner)
 +            }
 +            Expr::Break { expr, label } => {
 +                let val_ty = if let Some(expr) = *expr {
 +                    self.infer_expr(expr, &Expectation::none())
 +                } else {
 +                    TyBuilder::unit()
 +                };
 +
 +                match find_breakable(&mut self.breakables, label.as_ref()) {
 +                    Some(ctxt) => {
 +                        // avoiding the borrowck
 +                        let mut coerce = mem::replace(
 +                            &mut ctxt.coerce,
 +                            CoerceMany::new(self.result.standard_types.unknown.clone()),
 +                        );
 +
 +                        // FIXME: create a synthetic `()` during lowering so we have something to refer to here?
 +                        coerce.coerce(self, *expr, &val_ty);
 +
 +                        let ctxt = find_breakable(&mut self.breakables, label.as_ref())
 +                            .expect("breakable stack changed during coercion");
 +                        ctxt.coerce = coerce;
 +                        ctxt.may_break = true;
 +                    }
 +                    None => {
 +                        self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
 +                            expr: tgt_expr,
 +                            is_break: true,
 +                        });
 +                    }
 +                }
 +                TyKind::Never.intern(Interner)
 +            }
 +            Expr::Return { expr } => {
 +                if let Some(expr) = expr {
 +                    self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone()));
 +                } else {
 +                    let unit = TyBuilder::unit();
 +                    let _ = self.coerce(Some(tgt_expr), &unit, &self.return_ty.clone());
 +                }
 +                TyKind::Never.intern(Interner)
 +            }
 +            Expr::Yield { expr } => {
 +                if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() {
 +                    if let Some(expr) = expr {
 +                        self.infer_expr_coerce(*expr, &Expectation::has_type(yield_ty));
 +                    } else {
 +                        let unit = self.result.standard_types.unit.clone();
 +                        let _ = self.coerce(Some(tgt_expr), &unit, &yield_ty);
 +                    }
 +                    resume_ty
 +                } else {
 +                    // FIXME: report error (yield expr in non-generator)
 +                    TyKind::Error.intern(Interner)
 +                }
 +            }
 +            Expr::RecordLit { path, fields, spread, .. } => {
 +                let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
 +                if let Some(variant) = def_id {
 +                    self.write_variant_resolution(tgt_expr.into(), variant);
 +                }
 +
 +                if let Some(t) = expected.only_has_type(&mut self.table) {
 +                    self.unify(&ty, &t);
 +                }
 +
 +                let substs = ty
 +                    .as_adt()
 +                    .map(|(_, s)| s.clone())
 +                    .unwrap_or_else(|| Substitution::empty(Interner));
 +                let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default();
 +                let variant_data = def_id.map(|it| it.variant_data(self.db.upcast()));
 +                for field in fields.iter() {
 +                    let field_def =
 +                        variant_data.as_ref().and_then(|it| match it.field(&field.name) {
 +                            Some(local_id) => Some(FieldId { parent: def_id.unwrap(), local_id }),
 +                            None => {
 +                                self.push_diagnostic(InferenceDiagnostic::NoSuchField {
 +                                    expr: field.expr,
 +                                });
 +                                None
 +                            }
 +                        });
 +                    let field_ty = field_def.map_or(self.err_ty(), |it| {
 +                        field_types[it.local_id].clone().substitute(Interner, &substs)
 +                    });
 +                    self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
 +                }
 +                if let Some(expr) = spread {
 +                    self.infer_expr(*expr, &Expectation::has_type(ty.clone()));
 +                }
 +                ty
 +            }
 +            Expr::Field { expr, name } => {
 +                let receiver_ty = self.infer_expr_inner(*expr, &Expectation::none());
 +
 +                let mut autoderef = Autoderef::new(&mut self.table, receiver_ty);
 +                let ty = autoderef.by_ref().find_map(|(derefed_ty, _)| {
 +                    let (field_id, parameters) = match derefed_ty.kind(Interner) {
 +                        TyKind::Tuple(_, substs) => {
 +                            return name.as_tuple_index().and_then(|idx| {
 +                                substs
 +                                    .as_slice(Interner)
 +                                    .get(idx)
 +                                    .map(|a| a.assert_ty_ref(Interner))
 +                                    .cloned()
 +                            });
 +                        }
 +                        TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => {
 +                            let local_id = self.db.struct_data(*s).variant_data.field(name)?;
 +                            let field = FieldId { parent: (*s).into(), local_id };
 +                            (field, parameters.clone())
 +                        }
 +                        TyKind::Adt(AdtId(hir_def::AdtId::UnionId(u)), parameters) => {
 +                            let local_id = self.db.union_data(*u).variant_data.field(name)?;
 +                            let field = FieldId { parent: (*u).into(), local_id };
 +                            (field, parameters.clone())
 +                        }
 +                        _ => return None,
 +                    };
 +                    let is_visible = self.db.field_visibilities(field_id.parent)[field_id.local_id]
 +                        .is_visible_from(self.db.upcast(), self.resolver.module());
 +                    if !is_visible {
 +                        // Write down the first field resolution even if it is not visible
 +                        // This aids IDE features for private fields like goto def and in
 +                        // case of autoderef finding an applicable field, this will be
 +                        // overwritten in a following cycle
 +                        if let Entry::Vacant(entry) = self.result.field_resolutions.entry(tgt_expr)
 +                        {
 +                            entry.insert(field_id);
 +                        }
 +                        return None;
 +                    }
 +                    // can't have `write_field_resolution` here because `self.table` is borrowed :(
 +                    self.result.field_resolutions.insert(tgt_expr, field_id);
 +                    let ty = self.db.field_types(field_id.parent)[field_id.local_id]
 +                        .clone()
 +                        .substitute(Interner, &parameters);
 +                    Some(ty)
 +                });
 +                let ty = match ty {
 +                    Some(ty) => {
 +                        let adjustments = auto_deref_adjust_steps(&autoderef);
 +                        self.write_expr_adj(*expr, adjustments);
 +                        let ty = self.insert_type_vars(ty);
 +                        let ty = self.normalize_associated_types_in(ty);
 +                        ty
 +                    }
 +                    _ => self.err_ty(),
 +                };
 +                ty
 +            }
 +            Expr::Await { expr } => {
 +                let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
 +                self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
 +            }
-     /// Check whether `ty` implements `FromResidual<r>`
-     fn implements_from_residual(&mut self, ty: Ty, r: Ty) -> Option<(hir_def::TraitId, bool)> {
-         let from_residual_trait = self
-             .resolver
-             .resolve_known_trait(self.db.upcast(), &(super::path![core::ops::FromResidual]))?;
-         let r = GenericArgData::Ty(r).intern(Interner);
-         let b = TyBuilder::trait_ref(self.db, from_residual_trait);
-         if b.remaining() != 2 {
-             return Some((from_residual_trait, false));
-         }
-         let trait_ref = b.push(ty).push(r).build();
-         Some((from_residual_trait, self.table.try_obligation(trait_ref.cast(Interner)).is_some()))
-     }
-     fn resolve_try_impl_for(&mut self, ty: Ty) -> Option<(hir_def::TraitId, Option<(Ty, Ty)>)> {
-         let path = path![core::ops::Try];
-         let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
-         let trait_ref = TyBuilder::trait_ref(self.db, trait_).push(ty).build();
-         let substitution = trait_ref.substitution.clone();
-         self.push_obligation(trait_ref.clone().cast(Interner));
-         let trait_data = self.db.trait_data(trait_);
-         let output = trait_data.associated_type_by_name(&name![Output]);
-         let residual = trait_data.associated_type_by_name(&name![Residual]);
-         let output_ty = match output {
-             Some(output) => {
-                 let output_ty = self.table.new_type_var();
-                 let alias_eq = AliasEq {
-                     alias: AliasTy::Projection(ProjectionTy {
-                         associated_ty_id: to_assoc_type_id(output),
-                         substitution: substitution.clone(),
-                     }),
-                     ty: output_ty.clone(),
-                 };
-                 self.push_obligation(alias_eq.cast(Interner));
-                 output_ty
-             }
-             None => self.err_ty(),
-         };
-         let residual_ty = match residual {
-             Some(residual) => {
-                 let residual_ty = self.table.new_type_var();
-                 let alias_eq = AliasEq {
-                     alias: AliasTy::Projection(ProjectionTy {
-                         associated_ty_id: to_assoc_type_id(residual),
-                         substitution,
-                     }),
-                     ty: residual_ty.clone(),
-                 };
-                 self.push_obligation(alias_eq.cast(Interner));
-                 residual_ty
-             }
-             None => self.err_ty(),
-         };
-         // FIXME: We are doing the work twice here I think?
-         Some((
-             trait_,
-             self.table.try_obligation(trait_ref.cast(Interner)).map(|_| (output_ty, residual_ty)),
-         ))
-     }
++            Expr::Try { expr } => {
++                let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
++                self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok())
 +            }
 +            Expr::Cast { expr, type_ref } => {
 +                // FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary)
 +                let _inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
 +                let cast_ty = self.make_ty(type_ref);
 +                // FIXME check the cast...
 +                cast_ty
 +            }
 +            Expr::Ref { expr, rawness, mutability } => {
 +                let mutability = lower_to_chalk_mutability(*mutability);
 +                let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = expected
 +                    .only_has_type(&mut self.table)
 +                    .as_ref()
 +                    .and_then(|t| t.as_reference_or_ptr())
 +                {
 +                    if exp_mutability == Mutability::Mut && mutability == Mutability::Not {
 +                        // FIXME: record type error - expected mut reference but found shared ref,
 +                        // which cannot be coerced
 +                    }
 +                    if exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr {
 +                        // FIXME: record type error - expected reference but found ptr,
 +                        // which cannot be coerced
 +                    }
 +                    Expectation::rvalue_hint(&mut self.table, Ty::clone(exp_inner))
 +                } else {
 +                    Expectation::none()
 +                };
 +                let inner_ty = self.infer_expr_inner(*expr, &expectation);
 +                match rawness {
 +                    Rawness::RawPtr => TyKind::Raw(mutability, inner_ty),
 +                    Rawness::Ref => TyKind::Ref(mutability, static_lifetime(), inner_ty),
 +                }
 +                .intern(Interner)
 +            }
 +            &Expr::Box { expr } => self.infer_expr_box(expr, expected),
 +            Expr::UnaryOp { expr, op } => {
 +                let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
 +                let inner_ty = self.resolve_ty_shallow(&inner_ty);
 +                match op {
 +                    UnaryOp::Deref => {
 +                        autoderef::deref(&mut self.table, inner_ty).unwrap_or_else(|| self.err_ty())
 +                    }
 +                    UnaryOp::Neg => {
 +                        match inner_ty.kind(Interner) {
 +                            // Fast path for builtins
 +                            TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_))
 +                            | TyKind::InferenceVar(
 +                                _,
 +                                TyVariableKind::Integer | TyVariableKind::Float,
 +                            ) => inner_ty,
 +                            // Otherwise we resolve via the std::ops::Neg trait
 +                            _ => self
 +                                .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()),
 +                        }
 +                    }
 +                    UnaryOp::Not => {
 +                        match inner_ty.kind(Interner) {
 +                            // Fast path for builtins
 +                            TyKind::Scalar(Scalar::Bool | Scalar::Int(_) | Scalar::Uint(_))
 +                            | TyKind::InferenceVar(_, TyVariableKind::Integer) => inner_ty,
 +                            // Otherwise we resolve via the std::ops::Not trait
 +                            _ => self
 +                                .resolve_associated_type(inner_ty, self.resolve_ops_not_output()),
 +                        }
 +                    }
 +                }
 +            }
 +            Expr::BinaryOp { lhs, rhs, op } => match op {
 +                Some(BinaryOp::Assignment { op: None }) => {
 +                    let lhs = *lhs;
 +                    let is_ordinary = match &self.body[lhs] {
 +                        Expr::Array(_)
 +                        | Expr::RecordLit { .. }
 +                        | Expr::Tuple { .. }
 +                        | Expr::Underscore => false,
 +                        Expr::Call { callee, .. } => !matches!(&self.body[*callee], Expr::Path(_)),
 +                        _ => true,
 +                    };
 +
 +                    // In ordinary (non-destructuring) assignments, the type of
 +                    // `lhs` must be inferred first so that the ADT fields
 +                    // instantiations in RHS can be coerced to it. Note that this
 +                    // cannot happen in destructuring assignments because of how
 +                    // they are desugared.
 +                    if is_ordinary {
 +                        let lhs_ty = self.infer_expr(lhs, &Expectation::none());
 +                        self.infer_expr_coerce(*rhs, &Expectation::has_type(lhs_ty));
 +                    } else {
 +                        let rhs_ty = self.infer_expr(*rhs, &Expectation::none());
 +                        self.infer_assignee_expr(lhs, &rhs_ty);
 +                    }
 +                    self.result.standard_types.unit.clone()
 +                }
 +                Some(BinaryOp::LogicOp(_)) => {
 +                    let bool_ty = self.result.standard_types.bool_.clone();
 +                    self.infer_expr_coerce(*lhs, &Expectation::HasType(bool_ty.clone()));
 +                    let lhs_diverges = self.diverges;
 +                    self.infer_expr_coerce(*rhs, &Expectation::HasType(bool_ty.clone()));
 +                    // Depending on the LHS' value, the RHS can never execute.
 +                    self.diverges = lhs_diverges;
 +                    bool_ty
 +                }
 +                Some(op) => self.infer_overloadable_binop(*lhs, *op, *rhs, tgt_expr),
 +                _ => self.err_ty(),
 +            },
 +            Expr::Range { lhs, rhs, range_type } => {
 +                let lhs_ty = lhs.map(|e| self.infer_expr_inner(e, &Expectation::none()));
 +                let rhs_expect = lhs_ty
 +                    .as_ref()
 +                    .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone()));
 +                let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect));
 +                match (range_type, lhs_ty, rhs_ty) {
 +                    (RangeOp::Exclusive, None, None) => match self.resolve_range_full() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Inclusive, None, Some(ty)) => {
 +                        match self.resolve_range_to_inclusive() {
 +                            Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                            None => self.err_ty(),
 +                        }
 +                    }
 +                    (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Inclusive, Some(_), Some(ty)) => {
 +                        match self.resolve_range_inclusive() {
 +                            Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                            None => self.err_ty(),
 +                        }
 +                    }
 +                    (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Inclusive, _, None) => self.err_ty(),
 +                }
 +            }
 +            Expr::Index { base, index } => {
 +                let base_ty = self.infer_expr_inner(*base, &Expectation::none());
 +                let index_ty = self.infer_expr(*index, &Expectation::none());
 +
 +                if let Some(index_trait) = self.resolve_ops_index() {
 +                    let canonicalized = self.canonicalize(base_ty.clone());
 +                    let receiver_adjustments = method_resolution::resolve_indexing_op(
 +                        self.db,
 +                        self.trait_env.clone(),
 +                        canonicalized.value,
 +                        index_trait,
 +                    );
 +                    let (self_ty, adj) = receiver_adjustments
 +                        .map_or((self.err_ty(), Vec::new()), |adj| {
 +                            adj.apply(&mut self.table, base_ty)
 +                        });
 +                    self.write_expr_adj(*base, adj);
 +                    self.resolve_associated_type_with_params(
 +                        self_ty,
 +                        self.resolve_ops_index_output(),
 +                        &[GenericArgData::Ty(index_ty).intern(Interner)],
 +                    )
 +                } else {
 +                    self.err_ty()
 +                }
 +            }
 +            Expr::Tuple { exprs, .. } => {
 +                let mut tys = match expected
 +                    .only_has_type(&mut self.table)
 +                    .as_ref()
 +                    .map(|t| t.kind(Interner))
 +                {
 +                    Some(TyKind::Tuple(_, substs)) => substs
 +                        .iter(Interner)
 +                        .map(|a| a.assert_ty_ref(Interner).clone())
 +                        .chain(repeat_with(|| self.table.new_type_var()))
 +                        .take(exprs.len())
 +                        .collect::<Vec<_>>(),
 +                    _ => (0..exprs.len()).map(|_| self.table.new_type_var()).collect(),
 +                };
 +
 +                for (expr, ty) in exprs.iter().zip(tys.iter_mut()) {
 +                    self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
 +                }
 +
 +                TyKind::Tuple(tys.len(), Substitution::from_iter(Interner, tys)).intern(Interner)
 +            }
 +            Expr::Array(array) => {
 +                let elem_ty =
 +                    match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(Interner)) {
 +                        Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st.clone(),
 +                        _ => self.table.new_type_var(),
 +                    };
 +                let mut coerce = CoerceMany::new(elem_ty.clone());
 +
 +                let expected = Expectation::has_type(elem_ty.clone());
 +                let len = match array {
 +                    Array::ElementList { elements, .. } => {
 +                        for &expr in elements.iter() {
 +                            let cur_elem_ty = self.infer_expr_inner(expr, &expected);
 +                            coerce.coerce(self, Some(expr), &cur_elem_ty);
 +                        }
 +                        consteval::usize_const(Some(elements.len() as u128))
 +                    }
 +                    &Array::Repeat { initializer, repeat } => {
 +                        self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty));
 +                        self.infer_expr(
 +                            repeat,
 +                            &Expectation::has_type(
 +                                TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
 +                            ),
 +                        );
 +
 +                        if let Some(g_def) = self.owner.as_generic_def_id() {
 +                            let generics = generics(self.db.upcast(), g_def);
 +                            consteval::eval_to_const(
 +                                repeat,
 +                                ParamLoweringMode::Placeholder,
 +                                self,
 +                                || generics,
 +                                DebruijnIndex::INNERMOST,
 +                            )
 +                        } else {
 +                            consteval::usize_const(None)
 +                        }
 +                    }
 +                };
 +
 +                TyKind::Array(coerce.complete(), len).intern(Interner)
 +            }
 +            Expr::Literal(lit) => match lit {
 +                Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(Interner),
 +                Literal::String(..) => {
 +                    TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(Interner))
 +                        .intern(Interner)
 +                }
 +                Literal::ByteString(bs) => {
 +                    let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner);
 +
 +                    let len = consteval::usize_const(Some(bs.len() as u128));
 +
 +                    let array_type = TyKind::Array(byte_type, len).intern(Interner);
 +                    TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(Interner)
 +                }
 +                Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(Interner),
 +                Literal::Int(_v, ty) => match ty {
 +                    Some(int_ty) => {
 +                        TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(*int_ty)))
 +                            .intern(Interner)
 +                    }
 +                    None => self.table.new_integer_var(),
 +                },
 +                Literal::Uint(_v, ty) => match ty {
 +                    Some(int_ty) => {
 +                        TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(*int_ty)))
 +                            .intern(Interner)
 +                    }
 +                    None => self.table.new_integer_var(),
 +                },
 +                Literal::Float(_v, ty) => match ty {
 +                    Some(float_ty) => {
 +                        TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(*float_ty)))
 +                            .intern(Interner)
 +                    }
 +                    None => self.table.new_float_var(),
 +                },
 +            },
 +            Expr::Underscore => {
 +                // Underscore expressions may only appear in assignee expressions,
 +                // which are handled by `infer_assignee_expr()`, so any underscore
 +                // expression reaching this branch is an error.
 +                self.err_ty()
 +            }
 +        };
 +        // use a new type variable if we got unknown here
 +        let ty = self.insert_type_vars_shallow(ty);
 +        self.write_expr_ty(tgt_expr, ty.clone());
 +        if self.resolve_ty_shallow(&ty).is_never() {
 +            // Any expression that produces a value of type `!` must have diverged
 +            self.diverges = Diverges::Always;
 +        }
 +        ty
 +    }
 +
 +    fn infer_expr_box(&mut self, inner_expr: ExprId, expected: &Expectation) -> Ty {
 +        if let Some(box_id) = self.resolve_boxed_box() {
 +            let table = &mut self.table;
 +            let inner_exp = expected
 +                .to_option(table)
 +                .as_ref()
 +                .map(|e| e.as_adt())
 +                .flatten()
 +                .filter(|(e_adt, _)| e_adt == &box_id)
 +                .map(|(_, subts)| {
 +                    let g = subts.at(Interner, 0);
 +                    Expectation::rvalue_hint(table, Ty::clone(g.assert_ty_ref(Interner)))
 +                })
 +                .unwrap_or_else(Expectation::none);
 +
 +            let inner_ty = self.infer_expr_inner(inner_expr, &inner_exp);
 +            TyBuilder::adt(self.db, box_id)
 +                .push(inner_ty)
 +                .fill_with_defaults(self.db, || self.table.new_type_var())
 +                .build()
 +        } else {
 +            self.err_ty()
 +        }
 +    }
 +
 +    pub(super) fn infer_assignee_expr(&mut self, lhs: ExprId, rhs_ty: &Ty) -> Ty {
 +        let is_rest_expr = |expr| {
 +            matches!(
 +                &self.body[expr],
 +                Expr::Range { lhs: None, rhs: None, range_type: RangeOp::Exclusive },
 +            )
 +        };
 +
 +        let rhs_ty = self.resolve_ty_shallow(rhs_ty);
 +
 +        let ty = match &self.body[lhs] {
 +            Expr::Tuple { exprs, .. } => {
 +                // We don't consider multiple ellipses. This is analogous to
 +                // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
 +                let ellipsis = exprs.iter().position(|e| is_rest_expr(*e));
 +                let exprs: Vec<_> = exprs.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
 +
 +                self.infer_tuple_pat_like(&rhs_ty, (), ellipsis, &exprs)
 +            }
 +            Expr::Call { callee, args, .. } => {
 +                // Tuple structs
 +                let path = match &self.body[*callee] {
 +                    Expr::Path(path) => Some(path),
 +                    _ => None,
 +                };
 +
 +                // We don't consider multiple ellipses. This is analogous to
 +                // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
 +                let ellipsis = args.iter().position(|e| is_rest_expr(*e));
 +                let args: Vec<_> = args.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
 +
 +                self.infer_tuple_struct_pat_like(path, &rhs_ty, (), lhs, ellipsis, &args)
 +            }
 +            Expr::Array(Array::ElementList { elements, .. }) => {
 +                let elem_ty = match rhs_ty.kind(Interner) {
 +                    TyKind::Array(st, _) => st.clone(),
 +                    _ => self.err_ty(),
 +                };
 +
 +                // There's no need to handle `..` as it cannot be bound.
 +                let sub_exprs = elements.iter().filter(|e| !is_rest_expr(**e));
 +
 +                for e in sub_exprs {
 +                    self.infer_assignee_expr(*e, &elem_ty);
 +                }
 +
 +                match rhs_ty.kind(Interner) {
 +                    TyKind::Array(_, _) => rhs_ty.clone(),
 +                    // Even when `rhs_ty` is not an array type, this assignee
 +                    // expression is inferred to be an array (of unknown element
 +                    // type and length). This should not be just an error type,
 +                    // because we are to compute the unifiability of this type and
 +                    // `rhs_ty` in the end of this function to issue type mismatches.
 +                    _ => TyKind::Array(self.err_ty(), crate::consteval::usize_const(None))
 +                        .intern(Interner),
 +                }
 +            }
 +            Expr::RecordLit { path, fields, .. } => {
 +                let subs = fields.iter().map(|f| (f.name.clone(), f.expr));
 +
 +                self.infer_record_pat_like(path.as_deref(), &rhs_ty, (), lhs.into(), subs)
 +            }
 +            Expr::Underscore => rhs_ty.clone(),
 +            _ => {
 +                // `lhs` is a place expression, a unit struct, or an enum variant.
 +                let lhs_ty = self.infer_expr(lhs, &Expectation::none());
 +
 +                // This is the only branch where this function may coerce any type.
 +                // We are returning early to avoid the unifiability check below.
 +                let lhs_ty = self.insert_type_vars_shallow(lhs_ty);
 +                let ty = match self.coerce(None, &rhs_ty, &lhs_ty) {
 +                    Ok(ty) => ty,
 +                    Err(_) => {
 +                        self.result.type_mismatches.insert(
 +                            lhs.into(),
 +                            TypeMismatch { expected: rhs_ty.clone(), actual: lhs_ty.clone() },
 +                        );
 +                        // `rhs_ty` is returned so no further type mismatches are
 +                        // reported because of this mismatch.
 +                        rhs_ty
 +                    }
 +                };
 +                self.write_expr_ty(lhs, ty.clone());
 +                return ty;
 +            }
 +        };
 +
 +        let ty = self.insert_type_vars_shallow(ty);
 +        if !self.unify(&ty, &rhs_ty) {
 +            self.result
 +                .type_mismatches
 +                .insert(lhs.into(), TypeMismatch { expected: rhs_ty.clone(), actual: ty.clone() });
 +        }
 +        self.write_expr_ty(lhs, ty.clone());
 +        ty
 +    }
 +
 +    fn infer_overloadable_binop(
 +        &mut self,
 +        lhs: ExprId,
 +        op: BinaryOp,
 +        rhs: ExprId,
 +        tgt_expr: ExprId,
 +    ) -> Ty {
 +        let lhs_expectation = Expectation::none();
 +        let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
 +        let rhs_ty = self.table.new_type_var();
 +
 +        let trait_func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
 +            let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?;
 +            let func = self.db.trait_data(trait_id).method_by_name(&name)?;
 +            Some((trait_id, func))
 +        });
 +        let (trait_, func) = match trait_func {
 +            Some(it) => it,
 +            None => {
 +                let rhs_ty = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone());
 +                let rhs_ty = self.infer_expr_coerce(rhs, &Expectation::from_option(rhs_ty));
 +                return self
 +                    .builtin_binary_op_return_ty(op, lhs_ty, rhs_ty)
 +                    .unwrap_or_else(|| self.err_ty());
 +            }
 +        };
 +
 +        // HACK: We can use this substitution for the function because the function itself doesn't
 +        // have its own generic parameters.
 +        let subst = TyBuilder::subst_for_def(self.db, trait_, None)
 +            .push(lhs_ty.clone())
 +            .push(rhs_ty.clone())
 +            .build();
 +        self.write_method_resolution(tgt_expr, func, subst.clone());
 +
 +        let method_ty = self.db.value_ty(func.into()).substitute(Interner, &subst);
 +        self.register_obligations_for_call(&method_ty);
 +
 +        self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty.clone()));
 +
 +        let ret_ty = match method_ty.callable_sig(self.db) {
 +            Some(sig) => sig.ret().clone(),
 +            None => self.err_ty(),
 +        };
 +
 +        let ret_ty = self.normalize_associated_types_in(ret_ty);
 +
 +        // FIXME: record autoref adjustments
 +
 +        // use knowledge of built-in binary ops, which can sometimes help inference
 +        if let Some(builtin_rhs) = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone()) {
 +            self.unify(&builtin_rhs, &rhs_ty);
 +        }
 +        if let Some(builtin_ret) = self.builtin_binary_op_return_ty(op, lhs_ty, rhs_ty) {
 +            self.unify(&builtin_ret, &ret_ty);
 +        }
 +
 +        ret_ty
 +    }
 +
 +    fn infer_block(
 +        &mut self,
 +        expr: ExprId,
 +        statements: &[Statement],
 +        tail: Option<ExprId>,
 +        expected: &Expectation,
 +    ) -> Ty {
 +        for stmt in statements {
 +            match stmt {
 +                Statement::Let { pat, type_ref, initializer, else_branch } => {
 +                    let decl_ty = type_ref
 +                        .as_ref()
 +                        .map(|tr| self.make_ty(tr))
 +                        .unwrap_or_else(|| self.err_ty());
 +
 +                    // Always use the declared type when specified
 +                    let mut ty = decl_ty.clone();
 +
 +                    if let Some(expr) = initializer {
 +                        let actual_ty =
 +                            self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty.clone()));
 +                        if decl_ty.is_unknown() {
 +                            ty = actual_ty;
 +                        }
 +                    }
 +
 +                    if let Some(expr) = else_branch {
 +                        self.infer_expr_coerce(
 +                            *expr,
 +                            &Expectation::has_type(Ty::new(Interner, TyKind::Never)),
 +                        );
 +                    }
 +
 +                    self.infer_pat(*pat, &ty, BindingMode::default());
 +                }
 +                Statement::Expr { expr, .. } => {
 +                    self.infer_expr(*expr, &Expectation::none());
 +                }
 +            }
 +        }
 +
 +        if let Some(expr) = tail {
 +            self.infer_expr_coerce(expr, expected)
 +        } else {
 +            // Citing rustc: if there is no explicit tail expression,
 +            // that is typically equivalent to a tail expression
 +            // of `()` -- except if the block diverges. In that
 +            // case, there is no value supplied from the tail
 +            // expression (assuming there are no other breaks,
 +            // this implies that the type of the block will be
 +            // `!`).
 +            if self.diverges.is_always() {
 +                // we don't even make an attempt at coercion
 +                self.table.new_maybe_never_var()
 +            } else {
 +                if let Some(t) = expected.only_has_type(&mut self.table) {
 +                    if self.coerce(Some(expr), &TyBuilder::unit(), &t).is_err() {
 +                        self.result.type_mismatches.insert(
 +                            expr.into(),
 +                            TypeMismatch { expected: t.clone(), actual: TyBuilder::unit() },
 +                        );
 +                    }
 +                    t
 +                } else {
 +                    TyBuilder::unit()
 +                }
 +            }
 +        }
 +    }
 +
 +    fn infer_method_call(
 +        &mut self,
 +        tgt_expr: ExprId,
 +        receiver: ExprId,
 +        args: &[ExprId],
 +        method_name: &Name,
 +        generic_args: Option<&GenericArgs>,
 +        expected: &Expectation,
 +    ) -> Ty {
 +        let receiver_ty = self.infer_expr(receiver, &Expectation::none());
 +        let canonicalized_receiver = self.canonicalize(receiver_ty.clone());
 +
 +        let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast());
 +
 +        let resolved = method_resolution::lookup_method(
 +            &canonicalized_receiver.value,
 +            self.db,
 +            self.trait_env.clone(),
 +            &traits_in_scope,
 +            VisibleFromModule::Filter(self.resolver.module()),
 +            method_name,
 +        );
 +        let (receiver_ty, method_ty, substs) = match resolved {
 +            Some((adjust, func)) => {
 +                let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty);
 +                let generics = generics(self.db.upcast(), func.into());
 +                let substs = self.substs_for_method_call(generics, generic_args);
 +                self.write_expr_adj(receiver, adjustments);
 +                self.write_method_resolution(tgt_expr, func, substs.clone());
 +                (ty, self.db.value_ty(func.into()), substs)
 +            }
 +            None => (
 +                receiver_ty,
 +                Binders::empty(Interner, self.err_ty()),
 +                Substitution::empty(Interner),
 +            ),
 +        };
 +        let method_ty = method_ty.substitute(Interner, &substs);
 +        self.register_obligations_for_call(&method_ty);
 +        let (formal_receiver_ty, param_tys, ret_ty, is_varargs) =
 +            match method_ty.callable_sig(self.db) {
 +                Some(sig) => {
 +                    if !sig.params().is_empty() {
 +                        (
 +                            sig.params()[0].clone(),
 +                            sig.params()[1..].to_vec(),
 +                            sig.ret().clone(),
 +                            sig.is_varargs,
 +                        )
 +                    } else {
 +                        (self.err_ty(), Vec::new(), sig.ret().clone(), sig.is_varargs)
 +                    }
 +                }
 +                None => (self.err_ty(), Vec::new(), self.err_ty(), true),
 +            };
 +        self.unify(&formal_receiver_ty, &receiver_ty);
 +
 +        let expected_inputs =
 +            self.expected_inputs_for_expected_output(expected, ret_ty.clone(), param_tys.clone());
 +
 +        self.check_call_arguments(tgt_expr, args, &expected_inputs, &param_tys, &[], is_varargs);
 +        self.normalize_associated_types_in(ret_ty)
 +    }
 +
 +    fn expected_inputs_for_expected_output(
 +        &mut self,
 +        expected_output: &Expectation,
 +        output: Ty,
 +        inputs: Vec<Ty>,
 +    ) -> Vec<Ty> {
 +        if let Some(expected_ty) = expected_output.to_option(&mut self.table) {
 +            self.table.fudge_inference(|table| {
 +                if table.try_unify(&expected_ty, &output).is_ok() {
 +                    table.resolve_with_fallback(inputs, &|var, kind, _, _| match kind {
 +                        chalk_ir::VariableKind::Ty(tk) => var.to_ty(Interner, tk).cast(Interner),
 +                        chalk_ir::VariableKind::Lifetime => {
 +                            var.to_lifetime(Interner).cast(Interner)
 +                        }
 +                        chalk_ir::VariableKind::Const(ty) => {
 +                            var.to_const(Interner, ty).cast(Interner)
 +                        }
 +                    })
 +                } else {
 +                    Vec::new()
 +                }
 +            })
 +        } else {
 +            Vec::new()
 +        }
 +    }
 +
 +    fn check_call_arguments(
 +        &mut self,
 +        expr: ExprId,
 +        args: &[ExprId],
 +        expected_inputs: &[Ty],
 +        param_tys: &[Ty],
 +        skip_indices: &[u32],
 +        is_varargs: bool,
 +    ) {
 +        if args.len() != param_tys.len() + skip_indices.len() && !is_varargs {
 +            self.push_diagnostic(InferenceDiagnostic::MismatchedArgCount {
 +                call_expr: expr,
 +                expected: param_tys.len() + skip_indices.len(),
 +                found: args.len(),
 +            });
 +        }
 +
 +        // Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 --
 +        // We do this in a pretty awful way: first we type-check any arguments
 +        // that are not closures, then we type-check the closures. This is so
 +        // that we have more information about the types of arguments when we
 +        // type-check the functions. This isn't really the right way to do this.
 +        for &check_closures in &[false, true] {
 +            let mut skip_indices = skip_indices.into_iter().copied().fuse().peekable();
 +            let param_iter = param_tys.iter().cloned().chain(repeat(self.err_ty()));
 +            let expected_iter = expected_inputs
 +                .iter()
 +                .cloned()
 +                .chain(param_iter.clone().skip(expected_inputs.len()));
 +            for (idx, ((&arg, param_ty), expected_ty)) in
 +                args.iter().zip(param_iter).zip(expected_iter).enumerate()
 +            {
 +                let is_closure = matches!(&self.body[arg], Expr::Closure { .. });
 +                if is_closure != check_closures {
 +                    continue;
 +                }
 +
 +                while skip_indices.peek().map_or(false, |i| *i < idx as u32) {
 +                    skip_indices.next();
 +                }
 +                if skip_indices.peek().copied() == Some(idx as u32) {
 +                    continue;
 +                }
 +
 +                // the difference between param_ty and expected here is that
 +                // expected is the parameter when the expected *return* type is
 +                // taken into account. So in `let _: &[i32] = identity(&[1, 2])`
 +                // the expected type is already `&[i32]`, whereas param_ty is
 +                // still an unbound type variable. We don't always want to force
 +                // the parameter to coerce to the expected type (for example in
 +                // `coerce_unsize_expected_type_4`).
 +                let param_ty = self.normalize_associated_types_in(param_ty);
 +                let expected = Expectation::rvalue_hint(&mut self.table, expected_ty);
 +                // infer with the expected type we have...
 +                let ty = self.infer_expr_inner(arg, &expected);
 +
 +                // then coerce to either the expected type or just the formal parameter type
 +                let coercion_target = if let Some(ty) = expected.only_has_type(&mut self.table) {
 +                    // if we are coercing to the expectation, unify with the
 +                    // formal parameter type to connect everything
 +                    self.unify(&ty, &param_ty);
 +                    ty
 +                } else {
 +                    param_ty
 +                };
 +                if !coercion_target.is_unknown() {
 +                    if self.coerce(Some(arg), &ty, &coercion_target).is_err() {
 +                        self.result.type_mismatches.insert(
 +                            arg.into(),
 +                            TypeMismatch { expected: coercion_target, actual: ty.clone() },
 +                        );
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn substs_for_method_call(
 +        &mut self,
 +        def_generics: Generics,
 +        generic_args: Option<&GenericArgs>,
 +    ) -> Substitution {
 +        let (parent_params, self_params, type_params, const_params, impl_trait_params) =
 +            def_generics.provenance_split();
 +        assert_eq!(self_params, 0); // method shouldn't have another Self param
 +        let total_len = parent_params + type_params + const_params + impl_trait_params;
 +        let mut substs = Vec::with_capacity(total_len);
 +
 +        // handle provided arguments
 +        if let Some(generic_args) = generic_args {
 +            // if args are provided, it should be all of them, but we can't rely on that
 +            for (arg, kind_id) in generic_args
 +                .args
 +                .iter()
 +                .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
 +                .take(type_params + const_params)
 +                .zip(def_generics.iter_id())
 +            {
 +                if let Some(g) = generic_arg_to_chalk(
 +                    self.db,
 +                    kind_id,
 +                    arg,
 +                    self,
 +                    |this, type_ref| this.make_ty(type_ref),
 +                    |this, c, ty| {
 +                        const_or_path_to_chalk(
 +                            this.db,
 +                            &this.resolver,
 +                            ty,
 +                            c,
 +                            ParamLoweringMode::Placeholder,
 +                            || generics(this.db.upcast(), (&this.resolver).generic_def().unwrap()),
 +                            DebruijnIndex::INNERMOST,
 +                        )
 +                    },
 +                ) {
 +                    substs.push(g);
 +                }
 +            }
 +        };
 +
 +        // Handle everything else as unknown. This also handles generic arguments for the method's
 +        // parent (impl or trait), which should come after those for the method.
 +        for (id, data) in def_generics.iter().skip(substs.len()) {
 +            match data {
 +                TypeOrConstParamData::TypeParamData(_) => {
 +                    substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner))
 +                }
 +                TypeOrConstParamData::ConstParamData(_) => {
 +                    substs.push(
 +                        GenericArgData::Const(self.table.new_const_var(
 +                            self.db.const_param_ty(ConstParamId::from_unchecked(id)),
 +                        ))
 +                        .intern(Interner),
 +                    )
 +                }
 +            }
 +        }
 +        assert_eq!(substs.len(), total_len);
 +        Substitution::from_iter(Interner, substs)
 +    }
 +
 +    fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
 +        let callable_ty = self.resolve_ty_shallow(callable_ty);
 +        if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(Interner) {
 +            let def: CallableDefId = from_chalk(self.db, *fn_def);
 +            let generic_predicates = self.db.generic_predicates(def.into());
 +            for predicate in generic_predicates.iter() {
 +                let (predicate, binders) = predicate
 +                    .clone()
 +                    .substitute(Interner, parameters)
 +                    .into_value_and_skipped_binders();
 +                always!(binders.len(Interner) == 0); // quantified where clauses not yet handled
 +                self.push_obligation(predicate.cast(Interner));
 +            }
 +            // add obligation for trait implementation, if this is a trait method
 +            match def {
 +                CallableDefId::FunctionId(f) => {
 +                    if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container {
 +                        // construct a TraitRef
 +                        let params_len = parameters.len(Interner);
 +                        let trait_params_len = generics(self.db.upcast(), trait_.into()).len();
 +                        let substs = Substitution::from_iter(
 +                            Interner,
 +                            // The generic parameters for the trait come after those for the
 +                            // function.
 +                            &parameters.as_slice(Interner)[params_len - trait_params_len..],
 +                        );
 +                        self.push_obligation(
 +                            TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
 +                                .cast(Interner),
 +                        );
 +                    }
 +                }
 +                CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {}
 +            }
 +        }
 +    }
 +
 +    /// Returns the argument indices to skip.
 +    fn check_legacy_const_generics(&mut self, callee: Ty, args: &[ExprId]) -> Box<[u32]> {
 +        let (func, subst) = match callee.kind(Interner) {
 +            TyKind::FnDef(fn_id, subst) => {
 +                let callable = CallableDefId::from_chalk(self.db, *fn_id);
 +                let func = match callable {
 +                    CallableDefId::FunctionId(f) => f,
 +                    _ => return Default::default(),
 +                };
 +                (func, subst)
 +            }
 +            _ => return Default::default(),
 +        };
 +
 +        let data = self.db.function_data(func);
 +        if data.legacy_const_generics_indices.is_empty() {
 +            return Default::default();
 +        }
 +
 +        // only use legacy const generics if the param count matches with them
 +        if data.params.len() + data.legacy_const_generics_indices.len() != args.len() {
 +            if args.len() <= data.params.len() {
 +                return Default::default();
 +            } else {
 +                // there are more parameters than there should be without legacy
 +                // const params; use them
 +                let mut indices = data.legacy_const_generics_indices.clone();
 +                indices.sort();
 +                return indices;
 +            }
 +        }
 +
 +        // check legacy const parameters
 +        for (subst_idx, arg_idx) in data.legacy_const_generics_indices.iter().copied().enumerate() {
 +            let arg = match subst.at(Interner, subst_idx).constant(Interner) {
 +                Some(c) => c,
 +                None => continue, // not a const parameter?
 +            };
 +            if arg_idx >= args.len() as u32 {
 +                continue;
 +            }
 +            let _ty = arg.data(Interner).ty.clone();
 +            let expected = Expectation::none(); // FIXME use actual const ty, when that is lowered correctly
 +            self.infer_expr(args[arg_idx as usize], &expected);
 +            // FIXME: evaluate and unify with the const
 +        }
 +        let mut indices = data.legacy_const_generics_indices.clone();
 +        indices.sort();
 +        indices
 +    }
 +
 +    fn builtin_binary_op_return_ty(&mut self, op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Option<Ty> {
 +        let lhs_ty = self.resolve_ty_shallow(&lhs_ty);
 +        let rhs_ty = self.resolve_ty_shallow(&rhs_ty);
 +        match op {
 +            BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => {
 +                Some(TyKind::Scalar(Scalar::Bool).intern(Interner))
 +            }
 +            BinaryOp::Assignment { .. } => Some(TyBuilder::unit()),
 +            BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => {
 +                // all integer combinations are valid here
 +                if matches!(
 +                    lhs_ty.kind(Interner),
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
 +                        | TyKind::InferenceVar(_, TyVariableKind::Integer)
 +                ) && matches!(
 +                    rhs_ty.kind(Interner),
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
 +                        | TyKind::InferenceVar(_, TyVariableKind::Integer)
 +                ) {
 +                    Some(lhs_ty)
 +                } else {
 +                    None
 +                }
 +            }
 +            BinaryOp::ArithOp(_) => match (lhs_ty.kind(Interner), rhs_ty.kind(Interner)) {
 +                // (int, int) | (uint, uint) | (float, float)
 +                (TyKind::Scalar(Scalar::Int(_)), TyKind::Scalar(Scalar::Int(_)))
 +                | (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_)))
 +                | (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => {
 +                    Some(rhs_ty)
 +                }
 +                // ({int}, int) | ({int}, uint)
 +                (
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
 +                ) => Some(rhs_ty),
 +                // (int, {int}) | (uint, {int})
 +                (
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                ) => Some(lhs_ty),
 +                // ({float} | float)
 +                (
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                    TyKind::Scalar(Scalar::Float(_)),
 +                ) => Some(rhs_ty),
 +                // (float, {float})
 +                (
 +                    TyKind::Scalar(Scalar::Float(_)),
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                ) => Some(lhs_ty),
 +                // ({int}, {int}) | ({float}, {float})
 +                (
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                )
 +                | (
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                ) => Some(rhs_ty),
 +                _ => None,
 +            },
 +        }
 +    }
 +
 +    fn builtin_binary_op_rhs_expectation(&mut self, op: BinaryOp, lhs_ty: Ty) -> Option<Ty> {
 +        Some(match op {
 +            BinaryOp::LogicOp(..) => TyKind::Scalar(Scalar::Bool).intern(Interner),
 +            BinaryOp::Assignment { op: None } => lhs_ty,
 +            BinaryOp::CmpOp(CmpOp::Eq { .. }) => match self
 +                .resolve_ty_shallow(&lhs_ty)
 +                .kind(Interner)
 +            {
 +                TyKind::Scalar(_) | TyKind::Str => lhs_ty,
 +                TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
 +                _ => return None,
 +            },
 +            BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => return None,
 +            BinaryOp::CmpOp(CmpOp::Ord { .. })
 +            | BinaryOp::Assignment { op: Some(_) }
 +            | BinaryOp::ArithOp(_) => match self.resolve_ty_shallow(&lhs_ty).kind(Interner) {
 +                TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_)) => lhs_ty,
 +                TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
 +                _ => return None,
 +            },
 +        })
 +    }
 +
 +    fn with_breakable_ctx<T>(
 +        &mut self,
 +        kind: BreakableKind,
 +        ty: Ty,
 +        label: Option<LabelId>,
 +        cb: impl FnOnce(&mut Self) -> T,
 +    ) -> (Option<Ty>, T) {
 +        self.breakables.push({
 +            let label = label.map(|label| self.body[label].name.clone());
 +            BreakableContext { kind, may_break: false, coerce: CoerceMany::new(ty), label }
 +        });
 +        let res = cb(self);
 +        let ctx = self.breakables.pop().expect("breakable stack broken");
 +        (ctx.may_break.then(|| ctx.coerce.complete()), res)
 +    }
 +}
index a79efeb6daa84dbc0a736ff01668dbcaa139b0e3,0000000000000000000000000000000000000000..3a1a3f4fdeb3b70d66d95c5415598723b6324c6c
mode 100644,000000..100644
--- /dev/null
@@@ -1,1347 -1,0 +1,1329 @@@
-             return Some(adj);
-         }
-     }
-     None
- }
- /// Returns the receiver type for the try branch trait call.
- pub fn resolve_branch_op(
-     db: &dyn HirDatabase,
-     env: Arc<TraitEnvironment>,
-     ty: Canonical<Ty>,
-     try_trait: TraitId,
- ) -> Option<ReceiverAdjustments> {
-     let mut table = InferenceTable::new(db, env.clone());
-     let ty = table.instantiate_canonical(ty);
-     let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
-     for (ty, adj) in deref_chain.into_iter().zip(adj) {
-         let goal = generic_implements_goal(db, env.clone(), try_trait, &ty);
-         if db.trait_solve(env.krate, goal.cast(Interner)).is_some() {
 +//! This module is concerned with finding methods that a given type provides.
 +//! For details about how this works in rustc, see the method lookup page in the
 +//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
 +//! and the corresponding code mostly in rustc_hir_analysis/check/method/probe.rs.
 +use std::{iter, ops::ControlFlow, sync::Arc};
 +
 +use arrayvec::ArrayVec;
 +use base_db::{CrateId, Edition};
 +use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
 +use hir_def::{
 +    data::ImplData, item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId, ConstId,
 +    FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId,
 +    TraitId,
 +};
 +use hir_expand::name::Name;
 +use rustc_hash::{FxHashMap, FxHashSet};
 +use stdx::never;
 +
 +use crate::{
 +    autoderef::{self, AutoderefKind},
 +    db::HirDatabase,
 +    from_foreign_def_id,
 +    infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
 +    primitive::{FloatTy, IntTy, UintTy},
 +    static_lifetime,
 +    utils::all_super_traits,
 +    AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
 +    Scalar, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
 +};
 +
 +/// This is used as a key for indexing impls.
 +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 +pub enum TyFingerprint {
 +    // These are lang item impls:
 +    Str,
 +    Slice,
 +    Array,
 +    Never,
 +    RawPtr(Mutability),
 +    Scalar(Scalar),
 +    // These can have user-defined impls:
 +    Adt(hir_def::AdtId),
 +    Dyn(TraitId),
 +    ForeignType(ForeignDefId),
 +    // These only exist for trait impls
 +    Unit,
 +    Unnameable,
 +    Function(u32),
 +}
 +
 +impl TyFingerprint {
 +    /// Creates a TyFingerprint for looking up an inherent impl. Only certain
 +    /// types can have inherent impls: if we have some `struct S`, we can have
 +    /// an `impl S`, but not `impl &S`. Hence, this will return `None` for
 +    /// reference types and such.
 +    pub fn for_inherent_impl(ty: &Ty) -> Option<TyFingerprint> {
 +        let fp = match ty.kind(Interner) {
 +            TyKind::Str => TyFingerprint::Str,
 +            TyKind::Never => TyFingerprint::Never,
 +            TyKind::Slice(..) => TyFingerprint::Slice,
 +            TyKind::Array(..) => TyFingerprint::Array,
 +            TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
 +            TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
 +            TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
 +            TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
 +            TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?,
 +            _ => return None,
 +        };
 +        Some(fp)
 +    }
 +
 +    /// Creates a TyFingerprint for looking up a trait impl.
 +    pub fn for_trait_impl(ty: &Ty) -> Option<TyFingerprint> {
 +        let fp = match ty.kind(Interner) {
 +            TyKind::Str => TyFingerprint::Str,
 +            TyKind::Never => TyFingerprint::Never,
 +            TyKind::Slice(..) => TyFingerprint::Slice,
 +            TyKind::Array(..) => TyFingerprint::Array,
 +            TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
 +            TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
 +            TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
 +            TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
 +            TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?,
 +            TyKind::Ref(_, _, ty) => return TyFingerprint::for_trait_impl(ty),
 +            TyKind::Tuple(_, subst) => {
 +                let first_ty = subst.interned().get(0).map(|arg| arg.assert_ty_ref(Interner));
 +                match first_ty {
 +                    Some(ty) => return TyFingerprint::for_trait_impl(ty),
 +                    None => TyFingerprint::Unit,
 +                }
 +            }
 +            TyKind::AssociatedType(_, _)
 +            | TyKind::OpaqueType(_, _)
 +            | TyKind::FnDef(_, _)
 +            | TyKind::Closure(_, _)
 +            | TyKind::Generator(..)
 +            | TyKind::GeneratorWitness(..) => TyFingerprint::Unnameable,
 +            TyKind::Function(fn_ptr) => {
 +                TyFingerprint::Function(fn_ptr.substitution.0.len(Interner) as u32)
 +            }
 +            TyKind::Alias(_)
 +            | TyKind::Placeholder(_)
 +            | TyKind::BoundVar(_)
 +            | TyKind::InferenceVar(_, _)
 +            | TyKind::Error => return None,
 +        };
 +        Some(fp)
 +    }
 +}
 +
 +pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::I8)),
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::I16)),
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::I32)),
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::I64)),
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::I128)),
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::Isize)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::U8)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::U16)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::U32)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::U64)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::U128)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::Usize)),
 +];
 +
 +pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [
 +    TyFingerprint::Scalar(Scalar::Float(FloatTy::F32)),
 +    TyFingerprint::Scalar(Scalar::Float(FloatTy::F64)),
 +];
 +
 +/// Trait impls defined or available in some crate.
 +#[derive(Debug, Eq, PartialEq)]
 +pub struct TraitImpls {
 +    // If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type.
 +    map: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
 +}
 +
 +impl TraitImpls {
 +    pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
 +        let _p = profile::span("trait_impls_in_crate_query").detail(|| format!("{krate:?}"));
 +        let mut impls = Self { map: FxHashMap::default() };
 +
 +        let crate_def_map = db.crate_def_map(krate);
 +        impls.collect_def_map(db, &crate_def_map);
 +        impls.shrink_to_fit();
 +
 +        Arc::new(impls)
 +    }
 +
 +    pub(crate) fn trait_impls_in_block_query(
 +        db: &dyn HirDatabase,
 +        block: BlockId,
 +    ) -> Option<Arc<Self>> {
 +        let _p = profile::span("trait_impls_in_block_query");
 +        let mut impls = Self { map: FxHashMap::default() };
 +
 +        let block_def_map = db.block_def_map(block)?;
 +        impls.collect_def_map(db, &block_def_map);
 +        impls.shrink_to_fit();
 +
 +        Some(Arc::new(impls))
 +    }
 +
 +    pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
 +        let _p = profile::span("trait_impls_in_deps_query").detail(|| format!("{krate:?}"));
 +        let crate_graph = db.crate_graph();
 +        let mut res = Self { map: FxHashMap::default() };
 +
 +        for krate in crate_graph.transitive_deps(krate) {
 +            res.merge(&db.trait_impls_in_crate(krate));
 +        }
 +        res.shrink_to_fit();
 +
 +        Arc::new(res)
 +    }
 +
 +    fn shrink_to_fit(&mut self) {
 +        self.map.shrink_to_fit();
 +        self.map.values_mut().for_each(|map| {
 +            map.shrink_to_fit();
 +            map.values_mut().for_each(Vec::shrink_to_fit);
 +        });
 +    }
 +
 +    fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
 +        for (_module_id, module_data) in def_map.modules() {
 +            for impl_id in module_data.scope.impls() {
 +                let target_trait = match db.impl_trait(impl_id) {
 +                    Some(tr) => tr.skip_binders().hir_trait_id(),
 +                    None => continue,
 +                };
 +                let self_ty = db.impl_self_ty(impl_id);
 +                let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
 +                self.map
 +                    .entry(target_trait)
 +                    .or_default()
 +                    .entry(self_ty_fp)
 +                    .or_default()
 +                    .push(impl_id);
 +            }
 +
 +            // To better support custom derives, collect impls in all unnamed const items.
 +            // const _: () = { ... };
 +            for konst in collect_unnamed_consts(db, &module_data.scope) {
 +                let body = db.body(konst.into());
 +                for (_, block_def_map) in body.blocks(db.upcast()) {
 +                    self.collect_def_map(db, &block_def_map);
 +                }
 +            }
 +        }
 +    }
 +
 +    fn merge(&mut self, other: &Self) {
 +        for (trait_, other_map) in &other.map {
 +            let map = self.map.entry(*trait_).or_default();
 +            for (fp, impls) in other_map {
 +                map.entry(*fp).or_default().extend(impls);
 +            }
 +        }
 +    }
 +
 +    /// Queries all trait impls for the given type.
 +    pub fn for_self_ty_without_blanket_impls(
 +        &self,
 +        fp: TyFingerprint,
 +    ) -> impl Iterator<Item = ImplId> + '_ {
 +        self.map
 +            .values()
 +            .flat_map(move |impls| impls.get(&Some(fp)).into_iter())
 +            .flat_map(|it| it.iter().copied())
 +    }
 +
 +    /// Queries all impls of the given trait.
 +    pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ {
 +        self.map
 +            .get(&trait_)
 +            .into_iter()
 +            .flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
 +    }
 +
 +    /// Queries all impls of `trait_` that may apply to `self_ty`.
 +    pub fn for_trait_and_self_ty(
 +        &self,
 +        trait_: TraitId,
 +        self_ty: TyFingerprint,
 +    ) -> impl Iterator<Item = ImplId> + '_ {
 +        self.map
 +            .get(&trait_)
 +            .into_iter()
 +            .flat_map(move |map| map.get(&Some(self_ty)).into_iter().chain(map.get(&None)))
 +            .flat_map(|v| v.iter().copied())
 +    }
 +
 +    pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
 +        self.map.values().flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
 +    }
 +}
 +
 +/// Inherent impls defined in some crate.
 +///
 +/// Inherent impls can only be defined in the crate that also defines the self type of the impl
 +/// (note that some primitives are considered to be defined by both libcore and liballoc).
 +///
 +/// This makes inherent impl lookup easier than trait impl lookup since we only have to consider a
 +/// single crate.
 +#[derive(Debug, Eq, PartialEq)]
 +pub struct InherentImpls {
 +    map: FxHashMap<TyFingerprint, Vec<ImplId>>,
 +}
 +
 +impl InherentImpls {
 +    pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
 +        let mut impls = Self { map: FxHashMap::default() };
 +
 +        let crate_def_map = db.crate_def_map(krate);
 +        impls.collect_def_map(db, &crate_def_map);
 +        impls.shrink_to_fit();
 +
 +        Arc::new(impls)
 +    }
 +
 +    pub(crate) fn inherent_impls_in_block_query(
 +        db: &dyn HirDatabase,
 +        block: BlockId,
 +    ) -> Option<Arc<Self>> {
 +        let mut impls = Self { map: FxHashMap::default() };
 +        if let Some(block_def_map) = db.block_def_map(block) {
 +            impls.collect_def_map(db, &block_def_map);
 +            impls.shrink_to_fit();
 +            return Some(Arc::new(impls));
 +        }
 +        None
 +    }
 +
 +    fn shrink_to_fit(&mut self) {
 +        self.map.values_mut().for_each(Vec::shrink_to_fit);
 +        self.map.shrink_to_fit();
 +    }
 +
 +    fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
 +        for (_module_id, module_data) in def_map.modules() {
 +            for impl_id in module_data.scope.impls() {
 +                let data = db.impl_data(impl_id);
 +                if data.target_trait.is_some() {
 +                    continue;
 +                }
 +
 +                let self_ty = db.impl_self_ty(impl_id);
 +                let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders());
 +                if let Some(fp) = fp {
 +                    self.map.entry(fp).or_default().push(impl_id);
 +                }
 +                // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution)
 +            }
 +
 +            // To better support custom derives, collect impls in all unnamed const items.
 +            // const _: () = { ... };
 +            for konst in collect_unnamed_consts(db, &module_data.scope) {
 +                let body = db.body(konst.into());
 +                for (_, block_def_map) in body.blocks(db.upcast()) {
 +                    self.collect_def_map(db, &block_def_map);
 +                }
 +            }
 +        }
 +    }
 +
 +    pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] {
 +        match TyFingerprint::for_inherent_impl(self_ty) {
 +            Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]),
 +            None => &[],
 +        }
 +    }
 +
 +    pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
 +        self.map.values().flat_map(|v| v.iter().copied())
 +    }
 +}
 +
 +pub(crate) fn inherent_impl_crates_query(
 +    db: &dyn HirDatabase,
 +    krate: CrateId,
 +    fp: TyFingerprint,
 +) -> ArrayVec<CrateId, 2> {
 +    let _p = profile::span("inherent_impl_crates_query");
 +    let mut res = ArrayVec::new();
 +    let crate_graph = db.crate_graph();
 +
 +    for krate in crate_graph.transitive_deps(krate) {
 +        if res.is_full() {
 +            // we don't currently look for or store more than two crates here,
 +            // so don't needlessly look at more crates than necessary.
 +            break;
 +        }
 +        let impls = db.inherent_impls_in_crate(krate);
 +        if impls.map.get(&fp).map_or(false, |v| !v.is_empty()) {
 +            res.push(krate);
 +        }
 +    }
 +
 +    res
 +}
 +
 +fn collect_unnamed_consts<'a>(
 +    db: &'a dyn HirDatabase,
 +    scope: &'a ItemScope,
 +) -> impl Iterator<Item = ConstId> + 'a {
 +    let unnamed_consts = scope.unnamed_consts();
 +
 +    // FIXME: Also treat consts named `_DERIVE_*` as unnamed, since synstructure generates those.
 +    // Should be removed once synstructure stops doing that.
 +    let synstructure_hack_consts = scope.values().filter_map(|(item, _)| match item {
 +        ModuleDefId::ConstId(id) => {
 +            let loc = id.lookup(db.upcast());
 +            let item_tree = loc.id.item_tree(db.upcast());
 +            if item_tree[loc.id.value]
 +                .name
 +                .as_ref()
 +                .map_or(false, |n| n.to_smol_str().starts_with("_DERIVE_"))
 +            {
 +                Some(id)
 +            } else {
 +                None
 +            }
 +        }
 +        _ => None,
 +    });
 +
 +    unnamed_consts.chain(synstructure_hack_consts)
 +}
 +
 +pub fn def_crates(
 +    db: &dyn HirDatabase,
 +    ty: &Ty,
 +    cur_crate: CrateId,
 +) -> Option<ArrayVec<CrateId, 2>> {
 +    let mod_to_crate_ids = |module: ModuleId| Some(iter::once(module.krate()).collect());
 +
 +    let fp = TyFingerprint::for_inherent_impl(ty);
 +
 +    match ty.kind(Interner) {
 +        TyKind::Adt(AdtId(def_id), _) => mod_to_crate_ids(def_id.module(db.upcast())),
 +        TyKind::Foreign(id) => {
 +            mod_to_crate_ids(from_foreign_def_id(*id).lookup(db.upcast()).module(db.upcast()))
 +        }
 +        TyKind::Dyn(_) => ty
 +            .dyn_trait()
 +            .and_then(|trait_| mod_to_crate_ids(GenericDefId::TraitId(trait_).module(db.upcast()))),
 +        // for primitives, there may be impls in various places (core and alloc
 +        // mostly). We just check the whole crate graph for crates with impls
 +        // (cached behind a query).
 +        TyKind::Scalar(_)
 +        | TyKind::Str
 +        | TyKind::Slice(_)
 +        | TyKind::Array(..)
 +        | TyKind::Raw(..) => {
 +            Some(db.inherent_impl_crates(cur_crate, fp.expect("fingerprint for primitive")))
 +        }
 +        _ => return None,
 +    }
 +}
 +
 +pub fn lang_names_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, Name)> {
 +    use hir_expand::name;
 +    use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering};
 +    Some(match op {
 +        BinaryOp::LogicOp(_) => return None,
 +        BinaryOp::ArithOp(aop) => match aop {
 +            ArithOp::Add => (name!(add), name!(add)),
 +            ArithOp::Mul => (name!(mul), name!(mul)),
 +            ArithOp::Sub => (name!(sub), name!(sub)),
 +            ArithOp::Div => (name!(div), name!(div)),
 +            ArithOp::Rem => (name!(rem), name!(rem)),
 +            ArithOp::Shl => (name!(shl), name!(shl)),
 +            ArithOp::Shr => (name!(shr), name!(shr)),
 +            ArithOp::BitXor => (name!(bitxor), name!(bitxor)),
 +            ArithOp::BitOr => (name!(bitor), name!(bitor)),
 +            ArithOp::BitAnd => (name!(bitand), name!(bitand)),
 +        },
 +        BinaryOp::Assignment { op: Some(aop) } => match aop {
 +            ArithOp::Add => (name!(add_assign), name!(add_assign)),
 +            ArithOp::Mul => (name!(mul_assign), name!(mul_assign)),
 +            ArithOp::Sub => (name!(sub_assign), name!(sub_assign)),
 +            ArithOp::Div => (name!(div_assign), name!(div_assign)),
 +            ArithOp::Rem => (name!(rem_assign), name!(rem_assign)),
 +            ArithOp::Shl => (name!(shl_assign), name!(shl_assign)),
 +            ArithOp::Shr => (name!(shr_assign), name!(shr_assign)),
 +            ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)),
 +            ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)),
 +            ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)),
 +        },
 +        BinaryOp::CmpOp(cop) => match cop {
 +            CmpOp::Eq { negated: false } => (name!(eq), name!(eq)),
 +            CmpOp::Eq { negated: true } => (name!(ne), name!(eq)),
 +            CmpOp::Ord { ordering: Ordering::Less, strict: false } => {
 +                (name!(le), name!(partial_ord))
 +            }
 +            CmpOp::Ord { ordering: Ordering::Less, strict: true } => {
 +                (name!(lt), name!(partial_ord))
 +            }
 +            CmpOp::Ord { ordering: Ordering::Greater, strict: false } => {
 +                (name!(ge), name!(partial_ord))
 +            }
 +            CmpOp::Ord { ordering: Ordering::Greater, strict: true } => {
 +                (name!(gt), name!(partial_ord))
 +            }
 +        },
 +        BinaryOp::Assignment { op: None } => return None,
 +    })
 +}
 +
 +/// Look up the method with the given name.
 +pub(crate) fn lookup_method(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: &Name,
 +) -> Option<(ReceiverAdjustments, FunctionId)> {
 +    iterate_method_candidates(
 +        ty,
 +        db,
 +        env,
 +        traits_in_scope,
 +        visible_from_module,
 +        Some(name),
 +        LookupMode::MethodCall,
 +        |adjustments, f| match f {
 +            AssocItemId::FunctionId(f) => Some((adjustments, f)),
 +            _ => None,
 +        },
 +    )
 +}
 +
 +/// Whether we're looking up a dotted method call (like `v.len()`) or a path
 +/// (like `Vec::new`).
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +pub enum LookupMode {
 +    /// Looking up a method call like `v.len()`: We only consider candidates
 +    /// that have a `self` parameter, and do autoderef.
 +    MethodCall,
 +    /// Looking up a path like `Vec::new` or `Vec::default`: We consider all
 +    /// candidates including associated constants, but don't do autoderef.
 +    Path,
 +}
 +
 +#[derive(Clone, Copy)]
 +pub enum VisibleFromModule {
 +    /// Filter for results that are visible from the given module
 +    Filter(ModuleId),
 +    /// Include impls from the given block.
 +    IncludeBlock(BlockId),
 +    /// Do nothing special in regards visibility
 +    None,
 +}
 +
 +impl From<Option<ModuleId>> for VisibleFromModule {
 +    fn from(module: Option<ModuleId>) -> Self {
 +        match module {
 +            Some(module) => Self::Filter(module),
 +            None => Self::None,
 +        }
 +    }
 +}
 +
 +impl From<Option<BlockId>> for VisibleFromModule {
 +    fn from(block: Option<BlockId>) -> Self {
 +        match block {
 +            Some(block) => Self::IncludeBlock(block),
 +            None => Self::None,
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Default)]
 +pub struct ReceiverAdjustments {
 +    autoref: Option<Mutability>,
 +    autoderefs: usize,
 +    unsize_array: bool,
 +}
 +
 +impl ReceiverAdjustments {
 +    pub(crate) fn apply(&self, table: &mut InferenceTable<'_>, ty: Ty) -> (Ty, Vec<Adjustment>) {
 +        let mut ty = ty;
 +        let mut adjust = Vec::new();
 +        for _ in 0..self.autoderefs {
 +            match autoderef::autoderef_step(table, ty.clone()) {
 +                None => {
 +                    never!("autoderef not possible for {:?}", ty);
 +                    ty = TyKind::Error.intern(Interner);
 +                    break;
 +                }
 +                Some((kind, new_ty)) => {
 +                    ty = new_ty.clone();
 +                    adjust.push(Adjustment {
 +                        kind: Adjust::Deref(match kind {
 +                            // FIXME should we know the mutability here?
 +                            AutoderefKind::Overloaded => Some(OverloadedDeref(Mutability::Not)),
 +                            AutoderefKind::Builtin => None,
 +                        }),
 +                        target: new_ty,
 +                    });
 +                }
 +            }
 +        }
 +        if self.unsize_array {
 +            ty = match ty.kind(Interner) {
 +                TyKind::Array(inner, _) => TyKind::Slice(inner.clone()).intern(Interner),
 +                _ => {
 +                    never!("unsize_array with non-array {:?}", ty);
 +                    ty
 +                }
 +            };
 +            // FIXME this is kind of wrong since the unsize needs to happen to a pointer/reference
 +            adjust.push(Adjustment {
 +                kind: Adjust::Pointer(PointerCast::Unsize),
 +                target: ty.clone(),
 +            });
 +        }
 +        if let Some(m) = self.autoref {
 +            ty = TyKind::Ref(m, static_lifetime(), ty).intern(Interner);
 +            adjust
 +                .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty.clone() });
 +        }
 +        (ty, adjust)
 +    }
 +
 +    fn with_autoref(&self, m: Mutability) -> ReceiverAdjustments {
 +        Self { autoref: Some(m), ..*self }
 +    }
 +}
 +
 +// This would be nicer if it just returned an iterator, but that runs into
 +// lifetime problems, because we need to borrow temp `CrateImplDefs`.
 +// FIXME add a context type here?
 +pub(crate) fn iterate_method_candidates<T>(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    mode: LookupMode,
 +    mut callback: impl FnMut(ReceiverAdjustments, AssocItemId) -> Option<T>,
 +) -> Option<T> {
 +    let mut slot = None;
 +    iterate_method_candidates_dyn(
 +        ty,
 +        db,
 +        env,
 +        traits_in_scope,
 +        visible_from_module,
 +        name,
 +        mode,
 +        &mut |adj, item| {
 +            assert!(slot.is_none());
 +            if let Some(it) = callback(adj, item) {
 +                slot = Some(it);
 +                return ControlFlow::Break(());
 +            }
 +            ControlFlow::Continue(())
 +        },
 +    );
 +    slot
 +}
 +
 +pub fn lookup_impl_method(
 +    self_ty: &Ty,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    trait_: TraitId,
 +    name: &Name,
 +) -> Option<FunctionId> {
 +    let self_ty_fp = TyFingerprint::for_trait_impl(self_ty)?;
 +    let trait_impls = db.trait_impls_in_deps(env.krate);
 +    let impls = trait_impls.for_trait_and_self_ty(trait_, self_ty_fp);
 +    let mut table = InferenceTable::new(db, env.clone());
 +    find_matching_impl(impls, &mut table, &self_ty).and_then(|data| {
 +        data.items.iter().find_map(|it| match it {
 +            AssocItemId::FunctionId(f) => (db.function_data(*f).name == *name).then(|| *f),
 +            _ => None,
 +        })
 +    })
 +}
 +
 +fn find_matching_impl(
 +    mut impls: impl Iterator<Item = ImplId>,
 +    table: &mut InferenceTable<'_>,
 +    self_ty: &Ty,
 +) -> Option<Arc<ImplData>> {
 +    let db = table.db;
 +    loop {
 +        let impl_ = impls.next()?;
 +        let r = table.run_in_snapshot(|table| {
 +            let impl_data = db.impl_data(impl_);
 +            let substs =
 +                TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
 +            let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
 +
 +            table
 +                .unify(self_ty, &impl_ty)
 +                .then(|| {
 +                    let wh_goals =
 +                        crate::chalk_db::convert_where_clauses(db, impl_.into(), &substs)
 +                            .into_iter()
 +                            .map(|b| b.cast(Interner));
 +
 +                    let goal = crate::Goal::all(Interner, wh_goals);
 +
 +                    table.try_obligation(goal).map(|_| impl_data)
 +                })
 +                .flatten()
 +        });
 +        if r.is_some() {
 +            break r;
 +        }
 +    }
 +}
 +
 +pub fn iterate_path_candidates(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    iterate_method_candidates_dyn(
 +        ty,
 +        db,
 +        env,
 +        traits_in_scope,
 +        visible_from_module,
 +        name,
 +        LookupMode::Path,
 +        // the adjustments are not relevant for path lookup
 +        &mut |_, id| callback(id),
 +    )
 +}
 +
 +pub fn iterate_method_candidates_dyn(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    mode: LookupMode,
 +    callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    match mode {
 +        LookupMode::MethodCall => {
 +            // For method calls, rust first does any number of autoderef, and
 +            // then one autoref (i.e. when the method takes &self or &mut self).
 +            // Note that when we've got a receiver like &S, even if the method
 +            // we find in the end takes &self, we still do the autoderef step
 +            // (just as rustc does an autoderef and then autoref again).
 +
 +            // We have to be careful about the order we're looking at candidates
 +            // in here. Consider the case where we're resolving `x.clone()`
 +            // where `x: &Vec<_>`. This resolves to the clone method with self
 +            // type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where
 +            // the receiver type exactly matches before cases where we have to
 +            // do autoref. But in the autoderef steps, the `&_` self type comes
 +            // up *before* the `Vec<_>` self type.
 +            //
 +            // On the other hand, we don't want to just pick any by-value method
 +            // before any by-autoref method; it's just that we need to consider
 +            // the methods by autoderef order of *receiver types*, not *self
 +            // types*.
 +
 +            let mut table = InferenceTable::new(db, env.clone());
 +            let ty = table.instantiate_canonical(ty.clone());
 +            let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
 +
 +            let result = deref_chain.into_iter().zip(adj).try_for_each(|(receiver_ty, adj)| {
 +                iterate_method_candidates_with_autoref(
 +                    &receiver_ty,
 +                    adj,
 +                    db,
 +                    env.clone(),
 +                    traits_in_scope,
 +                    visible_from_module,
 +                    name,
 +                    callback,
 +                )
 +            });
 +            result
 +        }
 +        LookupMode::Path => {
 +            // No autoderef for path lookups
 +            iterate_method_candidates_for_self_ty(
 +                ty,
 +                db,
 +                env,
 +                traits_in_scope,
 +                visible_from_module,
 +                name,
 +                callback,
 +            )
 +        }
 +    }
 +}
 +
 +fn iterate_method_candidates_with_autoref(
 +    receiver_ty: &Canonical<Ty>,
 +    first_adjustment: ReceiverAdjustments,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    if receiver_ty.value.is_general_var(Interner, &receiver_ty.binders) {
 +        // don't try to resolve methods on unknown types
 +        return ControlFlow::Continue(());
 +    }
 +
 +    iterate_method_candidates_by_receiver(
 +        receiver_ty,
 +        first_adjustment.clone(),
 +        db,
 +        env.clone(),
 +        traits_in_scope,
 +        visible_from_module,
 +        name,
 +        &mut callback,
 +    )?;
 +
 +    let refed = Canonical {
 +        value: TyKind::Ref(Mutability::Not, static_lifetime(), receiver_ty.value.clone())
 +            .intern(Interner),
 +        binders: receiver_ty.binders.clone(),
 +    };
 +
 +    iterate_method_candidates_by_receiver(
 +        &refed,
 +        first_adjustment.with_autoref(Mutability::Not),
 +        db,
 +        env.clone(),
 +        traits_in_scope,
 +        visible_from_module,
 +        name,
 +        &mut callback,
 +    )?;
 +
 +    let ref_muted = Canonical {
 +        value: TyKind::Ref(Mutability::Mut, static_lifetime(), receiver_ty.value.clone())
 +            .intern(Interner),
 +        binders: receiver_ty.binders.clone(),
 +    };
 +
 +    iterate_method_candidates_by_receiver(
 +        &ref_muted,
 +        first_adjustment.with_autoref(Mutability::Mut),
 +        db,
 +        env,
 +        traits_in_scope,
 +        visible_from_module,
 +        name,
 +        &mut callback,
 +    )
 +}
 +
 +fn iterate_method_candidates_by_receiver(
 +    receiver_ty: &Canonical<Ty>,
 +    receiver_adjustments: ReceiverAdjustments,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    let mut table = InferenceTable::new(db, env);
 +    let receiver_ty = table.instantiate_canonical(receiver_ty.clone());
 +    let snapshot = table.snapshot();
 +    // We're looking for methods with *receiver* type receiver_ty. These could
 +    // be found in any of the derefs of receiver_ty, so we have to go through
 +    // that.
 +    let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone());
 +    while let Some((self_ty, _)) = autoderef.next() {
 +        iterate_inherent_methods(
 +            &self_ty,
 +            &mut autoderef.table,
 +            name,
 +            Some(&receiver_ty),
 +            Some(receiver_adjustments.clone()),
 +            visible_from_module,
 +            &mut callback,
 +        )?
 +    }
 +
 +    table.rollback_to(snapshot);
 +
 +    let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone());
 +    while let Some((self_ty, _)) = autoderef.next() {
 +        iterate_trait_method_candidates(
 +            &self_ty,
 +            &mut autoderef.table,
 +            traits_in_scope,
 +            name,
 +            Some(&receiver_ty),
 +            Some(receiver_adjustments.clone()),
 +            &mut callback,
 +        )?
 +    }
 +
 +    ControlFlow::Continue(())
 +}
 +
 +fn iterate_method_candidates_for_self_ty(
 +    self_ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    let mut table = InferenceTable::new(db, env);
 +    let self_ty = table.instantiate_canonical(self_ty.clone());
 +    iterate_inherent_methods(
 +        &self_ty,
 +        &mut table,
 +        name,
 +        None,
 +        None,
 +        visible_from_module,
 +        &mut callback,
 +    )?;
 +    iterate_trait_method_candidates(
 +        &self_ty,
 +        &mut table,
 +        traits_in_scope,
 +        name,
 +        None,
 +        None,
 +        callback,
 +    )
 +}
 +
 +fn iterate_trait_method_candidates(
 +    self_ty: &Ty,
 +    table: &mut InferenceTable<'_>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    name: Option<&Name>,
 +    receiver_ty: Option<&Ty>,
 +    receiver_adjustments: Option<ReceiverAdjustments>,
 +    callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    let db = table.db;
 +    let env = table.trait_env.clone();
 +    let self_is_array = matches!(self_ty.kind(Interner), chalk_ir::TyKind::Array(..));
 +
 +    let canonical_self_ty = table.canonicalize(self_ty.clone()).value;
 +
 +    'traits: for &t in traits_in_scope {
 +        let data = db.trait_data(t);
 +
 +        // Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during
 +        // method resolution, if the receiver is an array, and we're compiling for editions before
 +        // 2021.
 +        // This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for
 +        // arrays.
 +        if data.skip_array_during_method_dispatch && self_is_array {
 +            // FIXME: this should really be using the edition of the method name's span, in case it
 +            // comes from a macro
 +            if db.crate_graph()[env.krate].edition < Edition::Edition2021 {
 +                continue;
 +            }
 +        }
 +
 +        // we'll be lazy about checking whether the type implements the
 +        // trait, but if we find out it doesn't, we'll skip the rest of the
 +        // iteration
 +        let mut known_implemented = false;
 +        for &(_, item) in data.items.iter() {
 +            // Don't pass a `visible_from_module` down to `is_valid_candidate`,
 +            // since only inherent methods should be included into visibility checking.
 +            if !is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
 +                continue;
 +            }
 +            if !known_implemented {
 +                let goal = generic_implements_goal(db, env.clone(), t, &canonical_self_ty);
 +                if db.trait_solve(env.krate, goal.cast(Interner)).is_none() {
 +                    continue 'traits;
 +                }
 +            }
 +            known_implemented = true;
 +            callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
 +        }
 +    }
 +    ControlFlow::Continue(())
 +}
 +
 +fn iterate_inherent_methods(
 +    self_ty: &Ty,
 +    table: &mut InferenceTable<'_>,
 +    name: Option<&Name>,
 +    receiver_ty: Option<&Ty>,
 +    receiver_adjustments: Option<ReceiverAdjustments>,
 +    visible_from_module: VisibleFromModule,
 +    callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    let db = table.db;
 +    let env = table.trait_env.clone();
 +
 +    // For trait object types and placeholder types with trait bounds, the methods of the trait and
 +    // its super traits are considered inherent methods. This matters because these methods have
 +    // higher priority than the other traits' methods, which would be considered in
 +    // `iterate_trait_method_candidates()` only after this function.
 +    match self_ty.kind(Interner) {
 +        TyKind::Placeholder(_) => {
 +            let env = table.trait_env.clone();
 +            let traits = env
 +                .traits_in_scope_from_clauses(self_ty.clone())
 +                .flat_map(|t| all_super_traits(db.upcast(), t));
 +            iterate_inherent_trait_methods(
 +                self_ty,
 +                table,
 +                name,
 +                receiver_ty,
 +                receiver_adjustments.clone(),
 +                callback,
 +                traits,
 +            )?;
 +        }
 +        TyKind::Dyn(_) => {
 +            if let Some(principal_trait) = self_ty.dyn_trait() {
 +                let traits = all_super_traits(db.upcast(), principal_trait);
 +                iterate_inherent_trait_methods(
 +                    self_ty,
 +                    table,
 +                    name,
 +                    receiver_ty,
 +                    receiver_adjustments.clone(),
 +                    callback,
 +                    traits.into_iter(),
 +                )?;
 +            }
 +        }
 +        _ => {}
 +    }
 +
 +    let def_crates = match def_crates(db, self_ty, env.krate) {
 +        Some(k) => k,
 +        None => return ControlFlow::Continue(()),
 +    };
 +
 +    let (module, block) = match visible_from_module {
 +        VisibleFromModule::Filter(module) => (Some(module), module.containing_block()),
 +        VisibleFromModule::IncludeBlock(block) => (None, Some(block)),
 +        VisibleFromModule::None => (None, None),
 +    };
 +
 +    if let Some(block_id) = block {
 +        if let Some(impls) = db.inherent_impls_in_block(block_id) {
 +            impls_for_self_ty(
 +                &impls,
 +                self_ty,
 +                table,
 +                name,
 +                receiver_ty,
 +                receiver_adjustments.clone(),
 +                module,
 +                callback,
 +            )?;
 +        }
 +    }
 +
 +    for krate in def_crates {
 +        let impls = db.inherent_impls_in_crate(krate);
 +        impls_for_self_ty(
 +            &impls,
 +            self_ty,
 +            table,
 +            name,
 +            receiver_ty,
 +            receiver_adjustments.clone(),
 +            module,
 +            callback,
 +        )?;
 +    }
 +    return ControlFlow::Continue(());
 +
 +    fn iterate_inherent_trait_methods(
 +        self_ty: &Ty,
 +        table: &mut InferenceTable<'_>,
 +        name: Option<&Name>,
 +        receiver_ty: Option<&Ty>,
 +        receiver_adjustments: Option<ReceiverAdjustments>,
 +        callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +        traits: impl Iterator<Item = TraitId>,
 +    ) -> ControlFlow<()> {
 +        let db = table.db;
 +        for t in traits {
 +            let data = db.trait_data(t);
 +            for &(_, item) in data.items.iter() {
 +                // We don't pass `visible_from_module` as all trait items should be visible.
 +                if is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
 +                    callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
 +                }
 +            }
 +        }
 +        ControlFlow::Continue(())
 +    }
 +
 +    fn impls_for_self_ty(
 +        impls: &InherentImpls,
 +        self_ty: &Ty,
 +        table: &mut InferenceTable<'_>,
 +        name: Option<&Name>,
 +        receiver_ty: Option<&Ty>,
 +        receiver_adjustments: Option<ReceiverAdjustments>,
 +        visible_from_module: Option<ModuleId>,
 +        callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +    ) -> ControlFlow<()> {
 +        let db = table.db;
 +        let impls_for_self_ty = impls.for_self_ty(self_ty);
 +        for &impl_def in impls_for_self_ty {
 +            for &item in &db.impl_data(impl_def).items {
 +                if !is_valid_candidate(table, name, receiver_ty, item, self_ty, visible_from_module)
 +                {
 +                    continue;
 +                }
 +                callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
 +            }
 +        }
 +        ControlFlow::Continue(())
 +    }
 +}
 +
 +/// Returns the receiver type for the index trait call.
 +pub fn resolve_indexing_op(
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    ty: Canonical<Ty>,
 +    index_trait: TraitId,
 +) -> Option<ReceiverAdjustments> {
 +    let mut table = InferenceTable::new(db, env.clone());
 +    let ty = table.instantiate_canonical(ty);
 +    let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
 +    for (ty, adj) in deref_chain.into_iter().zip(adj) {
 +        let goal = generic_implements_goal(db, env.clone(), index_trait, &ty);
 +        if db.trait_solve(env.krate, goal.cast(Interner)).is_some() {
 +            return Some(adj);
 +        }
 +    }
 +    None
 +}
 +
 +macro_rules! check_that {
 +    ($cond:expr) => {
 +        if !$cond {
 +            return false;
 +        }
 +    };
 +}
 +
 +fn is_valid_candidate(
 +    table: &mut InferenceTable<'_>,
 +    name: Option<&Name>,
 +    receiver_ty: Option<&Ty>,
 +    item: AssocItemId,
 +    self_ty: &Ty,
 +    visible_from_module: Option<ModuleId>,
 +) -> bool {
 +    let db = table.db;
 +    match item {
 +        AssocItemId::FunctionId(m) => {
 +            is_valid_fn_candidate(table, m, name, receiver_ty, self_ty, visible_from_module)
 +        }
 +        AssocItemId::ConstId(c) => {
 +            let data = db.const_data(c);
 +            check_that!(receiver_ty.is_none());
 +
 +            check_that!(name.map_or(true, |n| data.name.as_ref() == Some(n)));
 +            check_that!(visible_from_module.map_or(true, |from_module| {
 +                let v = db.const_visibility(c).is_visible_from(db.upcast(), from_module);
 +                if !v {
 +                    cov_mark::hit!(const_candidate_not_visible);
 +                }
 +                v
 +            }));
 +            if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container {
 +                let self_ty_matches = table.run_in_snapshot(|table| {
 +                    let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
 +                        .fill_with_inference_vars(table)
 +                        .build();
 +                    table.unify(&expected_self_ty, &self_ty)
 +                });
 +                if !self_ty_matches {
 +                    cov_mark::hit!(const_candidate_self_type_mismatch);
 +                    return false;
 +                }
 +            }
 +            true
 +        }
 +        _ => false,
 +    }
 +}
 +
 +fn is_valid_fn_candidate(
 +    table: &mut InferenceTable<'_>,
 +    fn_id: FunctionId,
 +    name: Option<&Name>,
 +    receiver_ty: Option<&Ty>,
 +    self_ty: &Ty,
 +    visible_from_module: Option<ModuleId>,
 +) -> bool {
 +    let db = table.db;
 +    let data = db.function_data(fn_id);
 +
 +    check_that!(name.map_or(true, |n| n == &data.name));
 +    check_that!(visible_from_module.map_or(true, |from_module| {
 +        let v = db.function_visibility(fn_id).is_visible_from(db.upcast(), from_module);
 +        if !v {
 +            cov_mark::hit!(autoderef_candidate_not_visible);
 +        }
 +        v
 +    }));
 +
 +    table.run_in_snapshot(|table| {
 +        let container = fn_id.lookup(db.upcast()).container;
 +        let (impl_subst, expect_self_ty) = match container {
 +            ItemContainerId::ImplId(it) => {
 +                let subst =
 +                    TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
 +                let self_ty = db.impl_self_ty(it).substitute(Interner, &subst);
 +                (subst, self_ty)
 +            }
 +            ItemContainerId::TraitId(it) => {
 +                let subst =
 +                    TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
 +                let self_ty = subst.at(Interner, 0).assert_ty_ref(Interner).clone();
 +                (subst, self_ty)
 +            }
 +            _ => unreachable!(),
 +        };
 +
 +        let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
 +            .fill_with_inference_vars(table)
 +            .build();
 +
 +        check_that!(table.unify(&expect_self_ty, self_ty));
 +
 +        if let Some(receiver_ty) = receiver_ty {
 +            check_that!(data.has_self_param());
 +
 +            let sig = db.callable_item_signature(fn_id.into());
 +            let expected_receiver =
 +                sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
 +
 +            check_that!(table.unify(&receiver_ty, &expected_receiver));
 +        }
 +
 +        if let ItemContainerId::ImplId(impl_id) = container {
 +            // We need to consider the bounds on the impl to distinguish functions of the same name
 +            // for a type.
 +            let predicates = db.generic_predicates(impl_id.into());
 +            predicates
 +                .iter()
 +                .map(|predicate| {
 +                    let (p, b) = predicate
 +                        .clone()
 +                        .substitute(Interner, &impl_subst)
 +                        // Skipping the inner binders is ok, as we don't handle quantified where
 +                        // clauses yet.
 +                        .into_value_and_skipped_binders();
 +                    stdx::always!(b.len(Interner) == 0);
 +                    p
 +                })
 +                // It's ok to get ambiguity here, as we may not have enough information to prove
 +                // obligations. We'll check if the user is calling the selected method properly
 +                // later anyway.
 +                .all(|p| table.try_obligation(p.cast(Interner)).is_some())
 +        } else {
 +            // For `ItemContainerId::TraitId`, we check if `self_ty` implements the trait in
 +            // `iterate_trait_method_candidates()`.
 +            // For others, this function shouldn't be called.
 +            true
 +        }
 +    })
 +}
 +
 +pub fn implements_trait(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    trait_: TraitId,
 +) -> bool {
 +    let goal = generic_implements_goal(db, env.clone(), trait_, ty);
 +    let solution = db.trait_solve(env.krate, goal.cast(Interner));
 +
 +    solution.is_some()
 +}
 +
 +pub fn implements_trait_unique(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    trait_: TraitId,
 +) -> bool {
 +    let goal = generic_implements_goal(db, env.clone(), trait_, ty);
 +    let solution = db.trait_solve(env.krate, goal.cast(Interner));
 +
 +    matches!(solution, Some(crate::Solution::Unique(_)))
 +}
 +
 +/// This creates Substs for a trait with the given Self type and type variables
 +/// for all other parameters, to query Chalk with it.
 +fn generic_implements_goal(
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    trait_: TraitId,
 +    self_ty: &Canonical<Ty>,
 +) -> Canonical<InEnvironment<super::DomainGoal>> {
 +    let mut kinds = self_ty.binders.interned().to_vec();
 +    let trait_ref = TyBuilder::trait_ref(db, trait_)
 +        .push(self_ty.value.clone())
 +        .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
 +        .build();
 +    kinds.extend(trait_ref.substitution.iter(Interner).skip(1).map(|x| {
 +        let vk = match x.data(Interner) {
 +            chalk_ir::GenericArgData::Ty(_) => {
 +                chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
 +            }
 +            chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
 +            chalk_ir::GenericArgData::Const(c) => {
 +                chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
 +            }
 +        };
 +        chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
 +    }));
 +    let obligation = trait_ref.cast(Interner);
 +    Canonical {
 +        binders: CanonicalVarKinds::from_iter(Interner, kinds),
 +        value: InEnvironment::new(&env.env, obligation),
 +    }
 +}
 +
 +fn autoderef_method_receiver(
 +    table: &mut InferenceTable<'_>,
 +    ty: Ty,
 +) -> (Vec<Canonical<Ty>>, Vec<ReceiverAdjustments>) {
 +    let (mut deref_chain, mut adjustments): (Vec<_>, Vec<_>) = (Vec::new(), Vec::new());
 +    let mut autoderef = autoderef::Autoderef::new(table, ty);
 +    while let Some((ty, derefs)) = autoderef.next() {
 +        deref_chain.push(autoderef.table.canonicalize(ty).value);
 +        adjustments.push(ReceiverAdjustments {
 +            autoref: None,
 +            autoderefs: derefs,
 +            unsize_array: false,
 +        });
 +    }
 +    // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!)
 +    if let (Some((TyKind::Array(parameters, _), binders)), Some(adj)) = (
 +        deref_chain.last().map(|ty| (ty.value.kind(Interner), ty.binders.clone())),
 +        adjustments.last().cloned(),
 +    ) {
 +        let unsized_ty = TyKind::Slice(parameters.clone()).intern(Interner);
 +        deref_chain.push(Canonical { value: unsized_ty, binders });
 +        adjustments.push(ReceiverAdjustments { unsize_array: true, ..adj });
 +    }
 +    (deref_chain, adjustments)
 +}
index b91172e33422d67ad40c74ad62f4167399240754,0000000000000000000000000000000000000000..555b6972fb71eecb775979f640b33baa2e3a712e
mode 100644,000000..100644
--- /dev/null
@@@ -1,3883 -1,0 +1,3965 @@@
- //- minicore: try
- fn test() -> core::ops::ControlFlow<u32, f32> {
-     let r: core::ops::ControlFlow<u32, f32> = core::ops::ControlFlow::Continue(1.0);
 +use cov_mark::check;
 +use expect_test::expect;
 +
 +use super::{check, check_infer, check_infer_with_mismatches, check_no_mismatches, check_types};
 +
 +#[test]
 +fn infer_await() {
 +    check_types(
 +        r#"
 +//- minicore: future
 +struct IntFuture;
 +
 +impl core::future::Future for IntFuture {
 +    type Output = u64;
 +}
 +
 +fn test() {
 +    let r = IntFuture;
 +    let v = r.await;
 +    v;
 +} //^ u64
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_async() {
 +    check_types(
 +        r#"
 +//- minicore: future
 +async fn foo() -> u64 { 128 }
 +
 +fn test() {
 +    let r = foo();
 +    let v = r.await;
 +    v;
 +} //^ u64
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_desugar_async() {
 +    check_types(
 +        r#"
 +//- minicore: future, sized
 +async fn foo() -> u64 { 128 }
 +
 +fn test() {
 +    let r = foo();
 +    r;
 +} //^ impl Future<Output = u64>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_async_block() {
 +    check_types(
 +        r#"
 +//- minicore: future, option
 +async fn test() {
 +    let a = async { 42 };
 +    a;
 +//  ^ impl Future<Output = i32>
 +    let x = a.await;
 +    x;
 +//  ^ i32
 +    let b = async {}.await;
 +    b;
 +//  ^ ()
 +    let c = async {
 +        let y = None;
 +        y
 +    //  ^ Option<u64>
 +    };
 +    let _: Option<u64> = c.await;
 +    c;
 +//  ^ impl Future<Output = Option<u64>>
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn auto_sized_async_block() {
 +    check_no_mismatches(
 +        r#"
 +//- minicore: future, sized
 +
 +use core::future::Future;
 +struct MyFut<Fut>(Fut);
 +
 +impl<Fut> Future for MyFut<Fut>
 +where Fut: Future
 +{
 +    type Output = Fut::Output;
 +}
 +async fn reproduction() -> usize {
 +    let f = async {999usize};
 +    MyFut(f).await
 +}
 +    "#,
 +    );
 +    check_no_mismatches(
 +        r#"
 +//- minicore: future
 +//#11815
 +#[lang = "sized"]
 +pub trait Sized {}
 +
 +#[lang = "unsize"]
 +pub trait Unsize<T: ?Sized> {}
 +
 +#[lang = "coerce_unsized"]
 +pub trait CoerceUnsized<T> {}
 +
 +pub unsafe trait Allocator {}
 +
 +pub struct Global;
 +unsafe impl Allocator for Global {}
 +
 +#[lang = "owned_box"]
 +#[fundamental]
 +pub struct Box<T: ?Sized, A: Allocator = Global>;
 +
 +impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
 +
 +fn send() ->  Box<dyn Future<Output = ()> + Send + 'static>{
 +    box async move {}
 +}
 +
 +fn not_send() -> Box<dyn Future<Output = ()> + 'static> {
 +    box async move {}
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn into_future_trait() {
 +    check_types(
 +        r#"
 +//- minicore: future
 +struct Futurable;
 +impl core::future::IntoFuture for Futurable {
 +    type Output = u64;
 +    type IntoFuture = IntFuture;
 +}
 +
 +struct IntFuture;
 +impl core::future::Future for IntFuture {
 +    type Output = u64;
 +}
 +
 +fn test() {
 +    let r = Futurable;
 +    let v = r.await;
 +    v;
 +} //^ u64
 +"#,
 +    );
 +}
 +
++#[test]
++fn infer_try() {
++    check_types(
++        r#"
++//- /main.rs crate:main deps:core
++fn test() {
++    let r: Result<i32, u64> = Result::Ok(1);
++    let v = r?;
++    v;
++} //^ i32
++
++//- /core.rs crate:core
++pub mod ops {
++    pub trait Try {
++        type Ok;
++        type Error;
++    }
++}
++
++pub mod result {
++    pub enum Result<O, E> {
++        Ok(O),
++        Err(E)
++    }
++
++    impl<O, E> crate::ops::Try for Result<O, E> {
++        type Ok = O;
++        type Error = E;
++    }
++}
++
++pub mod prelude {
++    pub mod rust_2018 {
++        pub use crate::{result::*, ops::*};
++    }
++}
++"#,
++    );
++}
++
 +#[test]
 +fn infer_try_trait_v2() {
 +    check_types(
 +        r#"
-       //^ f32
-     r
++//- /main.rs crate:main deps:core
++fn test() {
++    let r: Result<i32, u64> = Result::Ok(1);
 +    let v = r?;
++    v;
++} //^ i32
++
++//- /core.rs crate:core
++mod ops {
++    mod try_trait {
++        pub trait Try: FromResidual {
++            type Output;
++            type Residual;
++        }
++        pub trait FromResidual<R = <Self as Try>::Residual> {}
++    }
++
++    pub use self::try_trait::FromResidual;
++    pub use self::try_trait::Try;
++}
++
++mod convert {
++    pub trait From<T> {}
++    impl<T> From<T> for T {}
++}
++
++pub mod result {
++    use crate::convert::From;
++    use crate::ops::{Try, FromResidual};
++
++    pub enum Infallible {}
++    pub enum Result<O, E> {
++        Ok(O),
++        Err(E)
++    }
++
++    impl<O, E> Try for Result<O, E> {
++        type Output = O;
++        type Error = Result<Infallible, E>;
++    }
++
++    impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {}
++}
++
++pub mod prelude {
++    pub mod rust_2018 {
++        pub use crate::result::*;
++    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_for_loop() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:core,alloc
 +#![no_std]
 +use alloc::collections::Vec;
 +
 +fn test() {
 +    let v = Vec::new();
 +    v.push("foo");
 +    for x in v {
 +        x;
 +    } //^ &str
 +}
 +
 +//- /core.rs crate:core
 +pub mod iter {
 +    pub trait IntoIterator {
 +        type Item;
 +        type IntoIter: Iterator<Item = Self::Item>;
 +    }
 +    pub trait Iterator {
 +        type Item;
 +    }
 +}
 +pub mod prelude {
 +    pub mod rust_2018 {
 +        pub use crate::iter::*;
 +    }
 +}
 +
 +//- /alloc.rs crate:alloc deps:core
 +#![no_std]
 +pub mod collections {
 +    pub struct Vec<T> {}
 +    impl<T> Vec<T> {
 +        pub fn new() -> Self { Vec {} }
 +        pub fn push(&mut self, t: T) { }
 +    }
 +
 +    impl<T> IntoIterator for Vec<T> {
 +        type Item = T;
 +        type IntoIter = IntoIter<T>;
 +    }
 +
 +    struct IntoIter<T> {}
 +    impl<T> Iterator for IntoIter<T> {
 +        type Item = T;
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_neg() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:std
 +struct Bar;
 +struct Foo;
 +
 +impl std::ops::Neg for Bar {
 +    type Output = Foo;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = -a;
 +    b;
 +} //^ Foo
 +
 +//- /std.rs crate:std
 +#[prelude_import] use ops::*;
 +mod ops {
 +    #[lang = "neg"]
 +    pub trait Neg {
 +        type Output;
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_not() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:std
 +struct Bar;
 +struct Foo;
 +
 +impl std::ops::Not for Bar {
 +    type Output = Foo;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = !a;
 +    b;
 +} //^ Foo
 +
 +//- /std.rs crate:std
 +#[prelude_import] use ops::*;
 +mod ops {
 +    #[lang = "not"]
 +    pub trait Not {
 +        type Output;
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_from_bound_1() {
 +    check_types(
 +        r#"
 +trait Trait<T> {}
 +struct S<T>(T);
 +impl<U> Trait<U> for S<U> {}
 +fn foo<T: Trait<u32>>(t: T) {}
 +fn test() {
 +    let s = S(unknown);
 +           // ^^^^^^^ u32
 +    foo(s);
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_from_bound_2() {
 +    check_types(
 +        r#"
 +trait Trait<T> {}
 +struct S<T>(T);
 +impl<U> Trait<U> for S<U> {}
 +fn foo<U, T: Trait<U>>(t: T) -> U { loop {} }
 +fn test() {
 +    let s = S(unknown);
 +           // ^^^^^^^ u32
 +    let x: u32 = foo(s);
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_default_method_self_bound_implements_trait() {
 +    cov_mark::check!(trait_self_implements_self);
 +    check(
 +        r#"
 +trait Trait {
 +    fn foo(&self) -> i64;
 +    fn bar(&self) -> () {
 +        self.foo();
 +     // ^^^^^^^^^^ type: i64
 +    }
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_default_method_self_bound_implements_super_trait() {
 +    check(
 +        r#"
 +trait SuperTrait {
 +    fn foo(&self) -> i64;
 +}
 +trait Trait: SuperTrait {
 +    fn bar(&self) -> () {
 +        self.foo();
 +     // ^^^^^^^^^^ type: i64
 +    }
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_project_associated_type() {
 +    check_types(
 +        r#"
 +trait Iterable {
 +    type Item;
 +}
 +struct S;
 +impl Iterable for S { type Item = u32; }
 +fn test<T: Iterable>() {
 +    let x: <S as Iterable>::Item = 1;
 +                                // ^ u32
 +    let y: <T as Iterable>::Item = u;
 +                                // ^ Iterable::Item<T>
 +    let z: T::Item = u;
 +                  // ^ Iterable::Item<T>
 +    let a: <T>::Item = u;
 +                    // ^ Iterable::Item<T>
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_return_associated_type() {
 +    check_types(
 +        r#"
 +trait Iterable {
 +    type Item;
 +}
 +struct S;
 +impl Iterable for S { type Item = u32; }
 +fn foo1<T: Iterable>(t: T) -> T::Item { loop {} }
 +fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item { loop {} }
 +fn foo3<T: Iterable>(t: T) -> <T>::Item { loop {} }
 +fn test() {
 +    foo1(S);
 + // ^^^^^^^ u32
 +    foo2(S);
 + // ^^^^^^^ u32
 +    foo3(S);
 + // ^^^^^^^ u32
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn associated_type_shorthand_from_method_bound() {
 +    check_types(
 +        r#"
 +trait Iterable {
 +    type Item;
 +}
 +struct S<T>;
 +impl<T> S<T> {
 +    fn foo(self) -> T::Item where T: Iterable { loop {} }
 +}
 +fn test<T: Iterable>() {
 +    let s: S<T>;
 +    s.foo();
 + // ^^^^^^^ Iterable::Item<T>
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn associated_type_shorthand_from_self_issue_12484() {
 +    check_types(
 +        r#"
 +trait Bar {
 +    type A;
 +}
 +trait Foo {
 +    type A;
 +    fn test(a: Self::A, _: impl Bar) {
 +        a;
 +      //^ Foo::A<Self>
 +    }
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_type_bound() {
 +    check_types(
 +        r#"
 +trait Iterable {
 +    type Item;
 +}
 +fn test<T: Iterable<Item=u32>>() {
 +    let y: T::Item = unknown;
 +                  // ^^^^^^^ u32
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_const_body() {
 +    // FIXME make check_types work with other bodies
 +    check_infer(
 +        r#"
 +const A: u32 = 1 + 1;
 +static B: u64 = { let x = 1; x };
 +"#,
 +        expect![[r#"
 +            15..16 '1': u32
 +            15..20 '1 + 1': u32
 +            19..20 '1': u32
 +            38..54 '{ let ...1; x }': u64
 +            44..45 'x': u64
 +            48..49 '1': u64
 +            51..52 'x': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn tuple_struct_fields() {
 +    check_infer(
 +        r#"
 +struct S(i32, u64);
 +fn test() -> u64 {
 +    let a = S(4, 6);
 +    let b = a.0;
 +    a.1
 +}"#,
 +        expect![[r#"
 +            37..86 '{     ... a.1 }': u64
 +            47..48 'a': S
 +            51..52 'S': S(i32, u64) -> S
 +            51..58 'S(4, 6)': S
 +            53..54 '4': i32
 +            56..57 '6': u64
 +            68..69 'b': i32
 +            72..73 'a': S
 +            72..75 'a.0': i32
 +            81..82 'a': S
 +            81..84 'a.1': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn tuple_struct_with_fn() {
 +    check_infer(
 +        r#"
 +struct S(fn(u32) -> u64);
 +fn test() -> u64 {
 +    let a = S(|i| 2*i);
 +    let b = a.0(4);
 +    a.0(2)
 +}"#,
 +        expect![[r#"
 +            43..101 '{     ...0(2) }': u64
 +            53..54 'a': S
 +            57..58 'S': S(fn(u32) -> u64) -> S
 +            57..67 'S(|i| 2*i)': S
 +            59..66 '|i| 2*i': |u32| -> u64
 +            60..61 'i': u32
 +            63..64 '2': u32
 +            63..66 '2*i': u32
 +            65..66 'i': u32
 +            77..78 'b': u64
 +            81..82 'a': S
 +            81..84 'a.0': fn(u32) -> u64
 +            81..87 'a.0(4)': u64
 +            85..86 '4': u32
 +            93..94 'a': S
 +            93..96 'a.0': fn(u32) -> u64
 +            93..99 'a.0(2)': u64
 +            97..98 '2': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn indexing_arrays() {
 +    check_infer(
 +        "fn main() { &mut [9][2]; }",
 +        expect![[r#"
 +            10..26 '{ &mut...[2]; }': ()
 +            12..23 '&mut [9][2]': &mut {unknown}
 +            17..20 '[9]': [i32; 1]
 +            17..23 '[9][2]': {unknown}
 +            18..19 '9': i32
 +            21..22 '2': i32
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn infer_ops_index() {
 +    check_types(
 +        r#"
 +//- minicore: index
 +struct Bar;
 +struct Foo;
 +
 +impl core::ops::Index<u32> for Bar {
 +    type Output = Foo;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = a[1u32];
 +    b;
 +} //^ Foo
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_index_field() {
 +    check_types(
 +        r#"
 +//- minicore: index
 +struct Bar;
 +struct Foo {
 +    field: u32;
 +}
 +
 +impl core::ops::Index<u32> for Bar {
 +    type Output = Foo;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = a[1u32].field;
 +    b;
 +} //^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_index_field_autoderef() {
 +    check_types(
 +        r#"
 +//- minicore: index
 +struct Bar;
 +struct Foo {
 +    field: u32;
 +}
 +
 +impl core::ops::Index<u32> for Bar {
 +    type Output = Foo;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = (&a[1u32]).field;
 +    b;
 +} //^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_index_int() {
 +    check_types(
 +        r#"
 +//- minicore: index
 +struct Bar;
 +struct Foo;
 +
 +impl core::ops::Index<u32> for Bar {
 +    type Output = Foo;
 +}
 +
 +struct Range;
 +impl core::ops::Index<Range> for Bar {
 +    type Output = Bar;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = a[1];
 +    b;
 +  //^ Foo
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_index_autoderef() {
 +    check_types(
 +        r#"
 +//- minicore: index, slice
 +fn test() {
 +    let a = &[1u32, 2, 3];
 +    let b = a[1];
 +    b;
 +} //^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_trait() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Arc<T: ?Sized>;
 +impl<T: ?Sized> core::ops::Deref for Arc<T> {
 +    type Target = T;
 +}
 +
 +struct S;
 +impl S {
 +    fn foo(&self) -> u128 { 0 }
 +}
 +
 +fn test(s: Arc<S>) {
 +    (*s, s.foo());
 +} //^^^^^^^^^^^^^ (S, u128)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_trait_with_inference_var() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Arc<T: ?Sized>;
 +fn new_arc<T: ?Sized>() -> Arc<T> { Arc }
 +impl<T: ?Sized> core::ops::Deref for Arc<T> {
 +    type Target = T;
 +}
 +
 +struct S;
 +fn foo(a: Arc<S>) {}
 +
 +fn test() {
 +    let a = new_arc();
 +    let b = *a;
 +          //^^ S
 +    foo(a);
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_trait_infinite_recursion() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct S;
 +
 +impl core::ops::Deref for S {
 +    type Target = S;
 +}
 +
 +fn test(s: S) {
 +    s.foo();
 +} //^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_trait_with_question_mark_size() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Arc<T: ?Sized>;
 +impl<T: ?Sized> core::ops::Deref for Arc<T> {
 +    type Target = T;
 +}
 +
 +struct S;
 +impl S {
 +    fn foo(&self) -> u128 { 0 }
 +}
 +
 +fn test(s: Arc<S>) {
 +    (*s, s.foo());
 +} //^^^^^^^^^^^^^ (S, u128)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_trait_with_implicit_sized_requirement_on_inference_var() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Foo<T>;
 +impl<T> core::ops::Deref for Foo<T> {
 +    type Target = ();
 +}
 +fn test() {
 +    let foo = Foo;
 +    *foo;
 +  //^^^^ ()
 +    let _: Foo<u8> = foo;
 +}
 +"#,
 +    )
 +}
 +
 +#[test]
 +fn obligation_from_function_clause() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +trait Trait<T> {}
 +impl Trait<u32> for S {}
 +
 +fn foo<T: Trait<U>, U>(t: T) -> U { loop {} }
 +
 +fn test(s: S) {
 +    foo(s);
 +} //^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn obligation_from_method_clause() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +struct S;
 +
 +trait Trait<T> {}
 +impl Trait<isize> for S {}
 +
 +struct O;
 +impl O {
 +    fn foo<T: Trait<U>, U>(&self, t: T) -> U { loop {} }
 +}
 +
 +fn test() {
 +    O.foo(S);
 +} //^^^^^^^^ isize
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn obligation_from_self_method_clause() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +trait Trait<T> {}
 +impl Trait<i64> for S {}
 +
 +impl S {
 +    fn foo<U>(&self) -> U where Self: Trait<U> { loop {} }
 +}
 +
 +fn test() {
 +    S.foo();
 +} //^^^^^^^ i64
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn obligation_from_impl_clause() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +trait Trait<T> {}
 +impl Trait<&str> for S {}
 +
 +struct O<T>;
 +impl<U, T: Trait<U>> O<T> {
 +    fn foo(&self) -> U { loop {} }
 +}
 +
 +fn test(o: O<S>) {
 +    o.foo();
 +} //^^^^^^^ &str
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn generic_param_env_1() {
 +    check_types(
 +        r#"
 +trait Clone {}
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl Clone for S {}
 +impl<T> Trait for T where T: Clone {}
 +fn test<T: Clone>(t: T) { t.foo(); }
 +                        //^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn generic_param_env_1_not_met() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +trait Clone {}
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl Clone for S {}
 +impl<T> Trait for T where T: Clone {}
 +fn test<T>(t: T) { t.foo(); }
 +                 //^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn generic_param_env_2() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl Trait for S {}
 +fn test<T: Trait>(t: T) { t.foo(); }
 +                        //^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn generic_param_env_2_not_met() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl Trait for S {}
 +fn test<T>(t: T) { t.foo(); }
 +                 //^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn generic_param_env_deref() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +trait Trait {}
 +impl<T> core::ops::Deref for T where T: Trait {
 +    type Target = i128;
 +}
 +fn test<T: Trait>(t: T) { *t; }
 +                        //^^ i128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn associated_type_placeholder() {
 +    // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types].
 +    check_types(
 +        r#"
 +pub trait ApplyL {
 +    type Out;
 +}
 +
 +pub struct RefMutL<T>;
 +
 +impl<T> ApplyL for RefMutL<T> {
 +    type Out = <T as ApplyL>::Out;
 +}
 +
 +fn test<T: ApplyL>() {
 +    let y: <RefMutL<T> as ApplyL>::Out = no_matter;
 +    y;
 +} //^ ApplyL::Out<T>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn associated_type_placeholder_2() {
 +    check_types(
 +        r#"
 +pub trait ApplyL {
 +    type Out;
 +}
 +fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out;
 +
 +fn test<T: ApplyL>(t: T) {
 +    let y = foo(t);
 +    y;
 +} //^ ApplyL::Out<T>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn argument_impl_trait() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +    fn foo2(&self) -> i64;
 +}
 +fn bar(x: impl Trait<u16>) {}
 +struct S<T>(T);
 +impl<T> Trait<T> for S<T> {}
 +
 +fn test(x: impl Trait<u64>, y: &impl Trait<u32>) {
 +    x;
 +    y;
 +    let z = S(1);
 +    bar(z);
 +    x.foo();
 +    y.foo();
 +    z.foo();
 +    x.foo2();
 +    y.foo2();
 +    z.foo2();
 +}"#,
 +        expect![[r#"
 +            29..33 'self': &Self
 +            54..58 'self': &Self
 +            77..78 'x': impl Trait<u16>
 +            97..99 '{}': ()
 +            154..155 'x': impl Trait<u64>
 +            174..175 'y': &impl Trait<u32>
 +            195..323 '{     ...2(); }': ()
 +            201..202 'x': impl Trait<u64>
 +            208..209 'y': &impl Trait<u32>
 +            219..220 'z': S<u16>
 +            223..224 'S': S<u16>(u16) -> S<u16>
 +            223..227 'S(1)': S<u16>
 +            225..226 '1': u16
 +            233..236 'bar': fn bar(S<u16>)
 +            233..239 'bar(z)': ()
 +            237..238 'z': S<u16>
 +            245..246 'x': impl Trait<u64>
 +            245..252 'x.foo()': u64
 +            258..259 'y': &impl Trait<u32>
 +            258..265 'y.foo()': u32
 +            271..272 'z': S<u16>
 +            271..278 'z.foo()': u16
 +            284..285 'x': impl Trait<u64>
 +            284..292 'x.foo2()': i64
 +            298..299 'y': &impl Trait<u32>
 +            298..306 'y.foo2()': i64
 +            312..313 'z': S<u16>
 +            312..320 'z.foo2()': i64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn argument_impl_trait_type_args_1() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +trait Foo {
 +    // this function has an implicit Self param, an explicit type param,
 +    // and an implicit impl Trait param!
 +    fn bar<T>(x: impl Trait) -> T { loop {} }
 +}
 +fn foo<T>(x: impl Trait) -> T { loop {} }
 +struct S;
 +impl Trait for S {}
 +struct F;
 +impl Foo for F {}
 +
 +fn test() {
 +    Foo::bar(S);
 +    <F as Foo>::bar(S);
 +    F::bar(S);
 +    Foo::bar::<u32>(S);
 +    <F as Foo>::bar::<u32>(S);
 +
 +    foo(S);
 +    foo::<u32>(S);
 +    foo::<u32, i32>(S); // we should ignore the extraneous i32
 +}"#,
 +        expect![[r#"
 +            155..156 'x': impl Trait
 +            175..186 '{ loop {} }': T
 +            177..184 'loop {}': !
 +            182..184 '{}': ()
 +            199..200 'x': impl Trait
 +            219..230 '{ loop {} }': T
 +            221..228 'loop {}': !
 +            226..228 '{}': ()
 +            300..509 '{     ... i32 }': ()
 +            306..314 'Foo::bar': fn bar<{unknown}, {unknown}>(S) -> {unknown}
 +            306..317 'Foo::bar(S)': {unknown}
 +            315..316 'S': S
 +            323..338 '<F as Foo>::bar': fn bar<F, {unknown}>(S) -> {unknown}
 +            323..341 '<F as ...bar(S)': {unknown}
 +            339..340 'S': S
 +            347..353 'F::bar': fn bar<F, {unknown}>(S) -> {unknown}
 +            347..356 'F::bar(S)': {unknown}
 +            354..355 'S': S
 +            362..377 'Foo::bar::<u32>': fn bar<{unknown}, u32>(S) -> u32
 +            362..380 'Foo::b...32>(S)': u32
 +            378..379 'S': S
 +            386..408 '<F as ...:<u32>': fn bar<F, u32>(S) -> u32
 +            386..411 '<F as ...32>(S)': u32
 +            409..410 'S': S
 +            418..421 'foo': fn foo<{unknown}>(S) -> {unknown}
 +            418..424 'foo(S)': {unknown}
 +            422..423 'S': S
 +            430..440 'foo::<u32>': fn foo<u32>(S) -> u32
 +            430..443 'foo::<u32>(S)': u32
 +            441..442 'S': S
 +            449..464 'foo::<u32, i32>': fn foo<u32>(S) -> u32
 +            449..467 'foo::<...32>(S)': u32
 +            465..466 'S': S
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn argument_impl_trait_type_args_2() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +struct S;
 +impl Trait for S {}
 +struct F<T>;
 +impl<T> F<T> {
 +    fn foo<U>(self, x: impl Trait) -> (T, U) { loop {} }
 +}
 +
 +fn test() {
 +    F.foo(S);
 +    F::<u32>.foo(S);
 +    F::<u32>.foo::<i32>(S);
 +    F::<u32>.foo::<i32, u32>(S); // extraneous argument should be ignored
 +}"#,
 +        expect![[r#"
 +            87..91 'self': F<T>
 +            93..94 'x': impl Trait
 +            118..129 '{ loop {} }': (T, U)
 +            120..127 'loop {}': !
 +            125..127 '{}': ()
 +            143..283 '{     ...ored }': ()
 +            149..150 'F': F<{unknown}>
 +            149..157 'F.foo(S)': ({unknown}, {unknown})
 +            155..156 'S': S
 +            163..171 'F::<u32>': F<u32>
 +            163..178 'F::<u32>.foo(S)': (u32, {unknown})
 +            176..177 'S': S
 +            184..192 'F::<u32>': F<u32>
 +            184..206 'F::<u3...32>(S)': (u32, i32)
 +            204..205 'S': S
 +            212..220 'F::<u32>': F<u32>
 +            212..239 'F::<u3...32>(S)': (u32, i32)
 +            237..238 'S': S
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn argument_impl_trait_to_fn_pointer() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +fn foo(x: impl Trait) { loop {} }
 +struct S;
 +impl Trait for S {}
 +
 +fn test() {
 +    let f: fn(S) -> () = foo;
 +}"#,
 +        expect![[r#"
 +            22..23 'x': impl Trait
 +            37..48 '{ loop {} }': ()
 +            39..46 'loop {}': !
 +            44..46 '{}': ()
 +            90..123 '{     ...foo; }': ()
 +            100..101 'f': fn(S)
 +            117..120 'foo': fn foo(S)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn impl_trait() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +    fn foo2(&self) -> i64;
 +}
 +fn bar() -> impl Trait<u64> {}
 +
 +fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
 +    x;
 +    y;
 +    let z = bar();
 +    x.foo();
 +    y.foo();
 +    z.foo();
 +    x.foo2();
 +    y.foo2();
 +    z.foo2();
 +}"#,
 +        expect![[r#"
 +            29..33 'self': &Self
 +            54..58 'self': &Self
 +            98..100 '{}': ()
 +            110..111 'x': impl Trait<u64>
 +            130..131 'y': &impl Trait<u64>
 +            151..268 '{     ...2(); }': ()
 +            157..158 'x': impl Trait<u64>
 +            164..165 'y': &impl Trait<u64>
 +            175..176 'z': impl Trait<u64>
 +            179..182 'bar': fn bar() -> impl Trait<u64>
 +            179..184 'bar()': impl Trait<u64>
 +            190..191 'x': impl Trait<u64>
 +            190..197 'x.foo()': u64
 +            203..204 'y': &impl Trait<u64>
 +            203..210 'y.foo()': u64
 +            216..217 'z': impl Trait<u64>
 +            216..223 'z.foo()': u64
 +            229..230 'x': impl Trait<u64>
 +            229..237 'x.foo2()': i64
 +            243..244 'y': &impl Trait<u64>
 +            243..251 'y.foo2()': i64
 +            257..258 'z': impl Trait<u64>
 +            257..265 'z.foo2()': i64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn simple_return_pos_impl_trait() {
 +    cov_mark::check!(lower_rpit);
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +}
 +fn bar() -> impl Trait<u64> { loop {} }
 +
 +fn test() {
 +    let a = bar();
 +    a.foo();
 +}"#,
 +        expect![[r#"
 +            29..33 'self': &Self
 +            71..82 '{ loop {} }': !
 +            73..80 'loop {}': !
 +            78..80 '{}': ()
 +            94..129 '{     ...o(); }': ()
 +            104..105 'a': impl Trait<u64>
 +            108..111 'bar': fn bar() -> impl Trait<u64>
 +            108..113 'bar()': impl Trait<u64>
 +            119..120 'a': impl Trait<u64>
 +            119..126 'a.foo()': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn more_return_pos_impl_trait() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Iterator {
 +    type Item;
 +    fn next(&mut self) -> Self::Item;
 +}
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +}
 +fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) { loop {} }
 +fn baz<T>(t: T) -> (impl Iterator<Item = impl Trait<T>>, impl Trait<T>) { loop {} }
 +
 +fn test() {
 +    let (a, b) = bar();
 +    a.next().foo();
 +    b.foo();
 +    let (c, d) = baz(1u128);
 +    c.next().foo();
 +    d.foo();
 +}"#,
 +        expect![[r#"
 +            49..53 'self': &mut Self
 +            101..105 'self': &Self
 +            184..195 '{ loop {} }': ({unknown}, {unknown})
 +            186..193 'loop {}': !
 +            191..193 '{}': ()
 +            206..207 't': T
 +            268..279 '{ loop {} }': ({unknown}, {unknown})
 +            270..277 'loop {}': !
 +            275..277 '{}': ()
 +            291..413 '{     ...o(); }': ()
 +            301..307 '(a, b)': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
 +            302..303 'a': impl Iterator<Item = impl Trait<u32>>
 +            305..306 'b': impl Trait<u64>
 +            310..313 'bar': fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
 +            310..315 'bar()': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
 +            321..322 'a': impl Iterator<Item = impl Trait<u32>>
 +            321..329 'a.next()': impl Trait<u32>
 +            321..335 'a.next().foo()': u32
 +            341..342 'b': impl Trait<u64>
 +            341..348 'b.foo()': u64
 +            358..364 '(c, d)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
 +            359..360 'c': impl Iterator<Item = impl Trait<u128>>
 +            362..363 'd': impl Trait<u128>
 +            367..370 'baz': fn baz<u128>(u128) -> (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
 +            367..377 'baz(1u128)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
 +            371..376 '1u128': u128
 +            383..384 'c': impl Iterator<Item = impl Trait<u128>>
 +            383..391 'c.next()': impl Trait<u128>
 +            383..397 'c.next().foo()': u128
 +            403..404 'd': impl Trait<u128>
 +            403..410 'd.foo()': u128
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_from_return_pos_impl_trait() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn, sized
 +trait Trait<T> {}
 +struct Bar<T>(T);
 +impl<T> Trait<T> for Bar<T> {}
 +fn foo<const C: u8, T>() -> (impl FnOnce(&str, T), impl Trait<u8>) {
 +    (|input, t| {}, Bar(C))
 +}
 +"#,
 +        expect![[r#"
 +            134..165 '{     ...(C)) }': (|&str, T| -> (), Bar<u8>)
 +            140..163 '(|inpu...ar(C))': (|&str, T| -> (), Bar<u8>)
 +            141..154 '|input, t| {}': |&str, T| -> ()
 +            142..147 'input': &str
 +            149..150 't': T
 +            152..154 '{}': ()
 +            156..159 'Bar': Bar<u8>(u8) -> Bar<u8>
 +            156..162 'Bar(C)': Bar<u8>
 +            160..161 'C': u8
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn dyn_trait() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +    fn foo2(&self) -> i64;
 +}
 +fn bar() -> dyn Trait<u64> {}
 +
 +fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
 +    x;
 +    y;
 +    let z = bar();
 +    x.foo();
 +    y.foo();
 +    z.foo();
 +    x.foo2();
 +    y.foo2();
 +    z.foo2();
 +}"#,
 +        expect![[r#"
 +            29..33 'self': &Self
 +            54..58 'self': &Self
 +            97..99 '{}': dyn Trait<u64>
 +            109..110 'x': dyn Trait<u64>
 +            128..129 'y': &dyn Trait<u64>
 +            148..265 '{     ...2(); }': ()
 +            154..155 'x': dyn Trait<u64>
 +            161..162 'y': &dyn Trait<u64>
 +            172..173 'z': dyn Trait<u64>
 +            176..179 'bar': fn bar() -> dyn Trait<u64>
 +            176..181 'bar()': dyn Trait<u64>
 +            187..188 'x': dyn Trait<u64>
 +            187..194 'x.foo()': u64
 +            200..201 'y': &dyn Trait<u64>
 +            200..207 'y.foo()': u64
 +            213..214 'z': dyn Trait<u64>
 +            213..220 'z.foo()': u64
 +            226..227 'x': dyn Trait<u64>
 +            226..234 'x.foo2()': i64
 +            240..241 'y': &dyn Trait<u64>
 +            240..248 'y.foo2()': i64
 +            254..255 'z': dyn Trait<u64>
 +            254..262 'z.foo2()': i64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn dyn_trait_in_impl() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait<T, U> {
 +    fn foo(&self) -> (T, U);
 +}
 +struct S<T, U> {}
 +impl<T, U> S<T, U> {
 +    fn bar(&self) -> &dyn Trait<T, U> { loop {} }
 +}
 +trait Trait2<T, U> {
 +    fn baz(&self) -> (T, U);
 +}
 +impl<T, U> Trait2<T, U> for dyn Trait<T, U> { }
 +
 +fn test(s: S<u32, i32>) {
 +    s.bar().baz();
 +}"#,
 +        expect![[r#"
 +            32..36 'self': &Self
 +            102..106 'self': &S<T, U>
 +            128..139 '{ loop {} }': &dyn Trait<T, U>
 +            130..137 'loop {}': !
 +            135..137 '{}': ()
 +            175..179 'self': &Self
 +            251..252 's': S<u32, i32>
 +            267..289 '{     ...z(); }': ()
 +            273..274 's': S<u32, i32>
 +            273..280 's.bar()': &dyn Trait<u32, i32>
 +            273..286 's.bar().baz()': (u32, i32)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn dyn_trait_bare() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait {
 +    fn foo(&self) -> u64;
 +}
 +fn bar() -> Trait {}
 +
 +fn test(x: Trait, y: &Trait) -> u64 {
 +    x;
 +    y;
 +    let z = bar();
 +    x.foo();
 +    y.foo();
 +    z.foo();
 +}"#,
 +        expect![[r#"
 +            26..30 'self': &Self
 +            60..62 '{}': dyn Trait
 +            72..73 'x': dyn Trait
 +            82..83 'y': &dyn Trait
 +            100..175 '{     ...o(); }': u64
 +            106..107 'x': dyn Trait
 +            113..114 'y': &dyn Trait
 +            124..125 'z': dyn Trait
 +            128..131 'bar': fn bar() -> dyn Trait
 +            128..133 'bar()': dyn Trait
 +            139..140 'x': dyn Trait
 +            139..146 'x.foo()': u64
 +            152..153 'y': &dyn Trait
 +            152..159 'y.foo()': u64
 +            165..166 'z': dyn Trait
 +            165..172 'z.foo()': u64
 +        "#]],
 +    );
 +
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn, coerce_unsized
 +struct S;
 +impl S {
 +    fn foo(&self) {}
 +}
 +fn f(_: &Fn(S)) {}
 +fn main() {
 +    f(&|number| number.foo());
 +}
 +        "#,
 +        expect![[r#"
 +            31..35 'self': &S
 +            37..39 '{}': ()
 +            47..48 '_': &dyn Fn(S)
 +            58..60 '{}': ()
 +            71..105 '{     ...()); }': ()
 +            77..78 'f': fn f(&dyn Fn(S))
 +            77..102 'f(&|nu...foo())': ()
 +            79..101 '&|numb....foo()': &|S| -> ()
 +            80..101 '|numbe....foo()': |S| -> ()
 +            81..87 'number': S
 +            89..95 'number': S
 +            89..101 'number.foo()': ()
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn weird_bounds() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +fn test(
 +    a: impl Trait + 'lifetime,
 +    b: impl 'lifetime,
 +    c: impl (Trait),
 +    d: impl ('lifetime),
 +    e: impl ?Sized,
 +    f: impl Trait + ?Sized
 +) {}
 +"#,
 +        expect![[r#"
 +            28..29 'a': impl Trait
 +            59..60 'b': impl Sized
 +            82..83 'c': impl Trait
 +            103..104 'd': impl Sized
 +            128..129 'e': impl ?Sized
 +            148..149 'f': impl Trait + ?Sized
 +            173..175 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn error_bound_chalk() {
 +    check_types(
 +        r#"
 +trait Trait {
 +    fn foo(&self) -> u32 { 0 }
 +}
 +
 +fn test(x: (impl Trait + UnknownTrait)) {
 +    x.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn assoc_type_bindings() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait {
 +    type Type;
 +}
 +
 +fn get<T: Trait>(t: T) -> <T as Trait>::Type {}
 +fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
 +fn set<T: Trait<Type = u64>>(t: T) -> T {t}
 +
 +struct S<T>;
 +impl<T> Trait for S<T> { type Type = T; }
 +
 +fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
 +    get(x);
 +    get2(x);
 +    get(y);
 +    get2(y);
 +    get(set(S));
 +    get2(set(S));
 +    get2(S::<str>);
 +}"#,
 +        expect![[r#"
 +            49..50 't': T
 +            77..79 '{}': Trait::Type<T>
 +            111..112 't': T
 +            122..124 '{}': U
 +            154..155 't': T
 +            165..168 '{t}': T
 +            166..167 't': T
 +            256..257 'x': T
 +            262..263 'y': impl Trait<Type = i64>
 +            289..397 '{     ...r>); }': ()
 +            295..298 'get': fn get<T>(T) -> <T as Trait>::Type
 +            295..301 'get(x)': u32
 +            299..300 'x': T
 +            307..311 'get2': fn get2<u32, T>(T) -> u32
 +            307..314 'get2(x)': u32
 +            312..313 'x': T
 +            320..323 'get': fn get<impl Trait<Type = i64>>(impl Trait<Type = i64>) -> <impl Trait<Type = i64> as Trait>::Type
 +            320..326 'get(y)': i64
 +            324..325 'y': impl Trait<Type = i64>
 +            332..336 'get2': fn get2<i64, impl Trait<Type = i64>>(impl Trait<Type = i64>) -> i64
 +            332..339 'get2(y)': i64
 +            337..338 'y': impl Trait<Type = i64>
 +            345..348 'get': fn get<S<u64>>(S<u64>) -> <S<u64> as Trait>::Type
 +            345..356 'get(set(S))': u64
 +            349..352 'set': fn set<S<u64>>(S<u64>) -> S<u64>
 +            349..355 'set(S)': S<u64>
 +            353..354 'S': S<u64>
 +            362..366 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64
 +            362..374 'get2(set(S))': u64
 +            367..370 'set': fn set<S<u64>>(S<u64>) -> S<u64>
 +            367..373 'set(S)': S<u64>
 +            371..372 'S': S<u64>
 +            380..384 'get2': fn get2<str, S<str>>(S<str>) -> str
 +            380..394 'get2(S::<str>)': str
 +            385..393 'S::<str>': S<str>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn impl_trait_assoc_binding_projection_bug() {
 +    check_types(
 +        r#"
 +//- minicore: iterator
 +pub trait Language {
 +    type Kind;
 +}
 +pub enum RustLanguage {}
 +impl Language for RustLanguage {
 +    type Kind = SyntaxKind;
 +}
 +struct SyntaxNode<L> {}
 +fn foo() -> impl Iterator<Item = SyntaxNode<RustLanguage>> {}
 +
 +trait Clone {
 +    fn clone(&self) -> Self;
 +}
 +
 +fn api_walkthrough() {
 +    for node in foo() {
 +        node.clone();
 +    } //^^^^^^^^^^^^ {unknown}
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn projection_eq_within_chalk() {
 +    check_infer(
 +        r#"
 +trait Trait1 {
 +    type Type;
 +}
 +trait Trait2<T> {
 +    fn foo(self) -> T;
 +}
 +impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {}
 +
 +fn test<T: Trait1<Type = u32>>(x: T) {
 +    x.foo();
 +}"#,
 +        expect![[r#"
 +            61..65 'self': Self
 +            163..164 'x': T
 +            169..185 '{     ...o(); }': ()
 +            175..176 'x': T
 +            175..182 'x.foo()': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn where_clause_trait_in_scope_for_method_resolution() {
 +    check_types(
 +        r#"
 +mod foo {
 +    trait Trait {
 +        fn foo(&self) -> u32 { 0 }
 +    }
 +}
 +
 +fn test<T: foo::Trait>(x: T) {
 +    x.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn super_trait_method_resolution() {
 +    check_infer(
 +        r#"
 +mod foo {
 +    trait SuperTrait {
 +        fn foo(&self) -> u32 {}
 +    }
 +}
 +trait Trait1: foo::SuperTrait {}
 +trait Trait2 where Self: foo::SuperTrait {}
 +
 +fn test<T: Trait1, U: Trait2>(x: T, y: U) {
 +    x.foo();
 +    y.foo();
 +}"#,
 +        expect![[r#"
 +            49..53 'self': &Self
 +            62..64 '{}': u32
 +            181..182 'x': T
 +            187..188 'y': U
 +            193..222 '{     ...o(); }': ()
 +            199..200 'x': T
 +            199..206 'x.foo()': u32
 +            212..213 'y': U
 +            212..219 'y.foo()': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn super_trait_impl_trait_method_resolution() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +mod foo {
 +    trait SuperTrait {
 +        fn foo(&self) -> u32 {}
 +    }
 +}
 +trait Trait1: foo::SuperTrait {}
 +
 +fn test(x: &impl Trait1) {
 +    x.foo();
 +}"#,
 +        expect![[r#"
 +            49..53 'self': &Self
 +            62..64 '{}': u32
 +            115..116 'x': &impl Trait1
 +            132..148 '{     ...o(); }': ()
 +            138..139 'x': &impl Trait1
 +            138..145 'x.foo()': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn super_trait_cycle() {
 +    // This just needs to not crash
 +    check_infer(
 +        r#"
 +        trait A: B {}
 +        trait B: A {}
 +
 +        fn test<T: A>(x: T) {
 +            x.foo();
 +        }
 +        "#,
 +        expect![[r#"
 +            43..44 'x': T
 +            49..65 '{     ...o(); }': ()
 +            55..56 'x': T
 +            55..62 'x.foo()': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn super_trait_assoc_type_bounds() {
 +    check_infer(
 +        r#"
 +trait SuperTrait { type Type; }
 +trait Trait where Self: SuperTrait {}
 +
 +fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
 +fn set<T: Trait<Type = u64>>(t: T) -> T {t}
 +
 +struct S<T>;
 +impl<T> SuperTrait for S<T> { type Type = T; }
 +impl<T> Trait for S<T> {}
 +
 +fn test() {
 +    get2(set(S));
 +}"#,
 +        expect![[r#"
 +            102..103 't': T
 +            113..115 '{}': U
 +            145..146 't': T
 +            156..159 '{t}': T
 +            157..158 't': T
 +            258..279 '{     ...S)); }': ()
 +            264..268 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64
 +            264..276 'get2(set(S))': u64
 +            269..272 'set': fn set<S<u64>>(S<u64>) -> S<u64>
 +            269..275 'set(S)': S<u64>
 +            273..274 'S': S<u64>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn fn_trait() {
 +    check_infer_with_mismatches(
 +        r#"
 +trait FnOnce<Args> {
 +    type Output;
 +
 +    fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output;
 +}
 +
 +fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
 +    f.call_once((1, 2));
 +}"#,
 +        expect![[r#"
 +            56..60 'self': Self
 +            62..66 'args': Args
 +            149..150 'f': F
 +            155..183 '{     ...2)); }': ()
 +            161..162 'f': F
 +            161..180 'f.call...1, 2))': u128
 +            173..179 '(1, 2)': (u32, u64)
 +            174..175 '1': u32
 +            177..178 '2': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn fn_ptr_and_item() {
 +    check_infer_with_mismatches(
 +        r#"
 +#[lang="fn_once"]
 +trait FnOnce<Args> {
 +    type Output;
 +
 +    fn call_once(self, args: Args) -> Self::Output;
 +}
 +
 +trait Foo<T> {
 +    fn foo(&self) -> T;
 +}
 +
 +struct Bar<T>(T);
 +
 +impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> {
 +    fn foo(&self) -> (A1, R) { loop {} }
 +}
 +
 +enum Opt<T> { None, Some(T) }
 +impl<T> Opt<T> {
 +    fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> { loop {} }
 +}
 +
 +fn test() {
 +    let bar: Bar<fn(u8) -> u32>;
 +    bar.foo();
 +
 +    let opt: Opt<u8>;
 +    let f: fn(u8) -> u32;
 +    opt.map(f);
 +}"#,
 +        expect![[r#"
 +            74..78 'self': Self
 +            80..84 'args': Args
 +            139..143 'self': &Self
 +            243..247 'self': &Bar<F>
 +            260..271 '{ loop {} }': (A1, R)
 +            262..269 'loop {}': !
 +            267..269 '{}': ()
 +            355..359 'self': Opt<T>
 +            361..362 'f': F
 +            377..388 '{ loop {} }': Opt<U>
 +            379..386 'loop {}': !
 +            384..386 '{}': ()
 +            402..518 '{     ...(f); }': ()
 +            412..415 'bar': Bar<fn(u8) -> u32>
 +            441..444 'bar': Bar<fn(u8) -> u32>
 +            441..450 'bar.foo()': (u8, u32)
 +            461..464 'opt': Opt<u8>
 +            483..484 'f': fn(u8) -> u32
 +            505..508 'opt': Opt<u8>
 +            505..515 'opt.map(f)': Opt<u32>
 +            513..514 'f': fn(u8) -> u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn fn_trait_deref_with_ty_default() {
 +    check_infer(
 +        r#"
 +//- minicore: deref, fn
 +struct Foo;
 +
 +impl Foo {
 +    fn foo(&self) -> usize {}
 +}
 +
 +struct Lazy<T, F = fn() -> T>(F);
 +
 +impl<T, F> Lazy<T, F> {
 +    pub fn new(f: F) -> Lazy<T, F> {}
 +}
 +
 +impl<T, F: FnOnce() -> T> core::ops::Deref for Lazy<T, F> {
 +    type Target = T;
 +}
 +
 +fn test() {
 +    let lazy1: Lazy<Foo, _> = Lazy::new(|| Foo);
 +    let r1 = lazy1.foo();
 +
 +    fn make_foo_fn() -> Foo {}
 +    let make_foo_fn_ptr: fn() -> Foo = make_foo_fn;
 +    let lazy2: Lazy<Foo, _> = Lazy::new(make_foo_fn_ptr);
 +    let r2 = lazy2.foo();
 +}"#,
 +        expect![[r#"
 +            36..40 'self': &Foo
 +            51..53 '{}': usize
 +            131..132 'f': F
 +            151..153 '{}': Lazy<T, F>
 +            251..497 '{     ...o(); }': ()
 +            261..266 'lazy1': Lazy<Foo, || -> Foo>
 +            283..292 'Lazy::new': fn new<Foo, || -> Foo>(|| -> Foo) -> Lazy<Foo, || -> Foo>
 +            283..300 'Lazy::...| Foo)': Lazy<Foo, || -> Foo>
 +            293..299 '|| Foo': || -> Foo
 +            296..299 'Foo': Foo
 +            310..312 'r1': usize
 +            315..320 'lazy1': Lazy<Foo, || -> Foo>
 +            315..326 'lazy1.foo()': usize
 +            368..383 'make_foo_fn_ptr': fn() -> Foo
 +            399..410 'make_foo_fn': fn make_foo_fn() -> Foo
 +            420..425 'lazy2': Lazy<Foo, fn() -> Foo>
 +            442..451 'Lazy::new': fn new<Foo, fn() -> Foo>(fn() -> Foo) -> Lazy<Foo, fn() -> Foo>
 +            442..468 'Lazy::...n_ptr)': Lazy<Foo, fn() -> Foo>
 +            452..467 'make_foo_fn_ptr': fn() -> Foo
 +            478..480 'r2': usize
 +            483..488 'lazy2': Lazy<Foo, fn() -> Foo>
 +            483..494 'lazy2.foo()': usize
 +            357..359 '{}': Foo
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn closure_1() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn
 +enum Option<T> { Some(T), None }
 +impl<T> Option<T> {
 +    fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { loop {} }
 +}
 +
 +fn test() {
 +    let x = Option::Some(1u32);
 +    x.map(|v| v + 1);
 +    x.map(|_v| 1u64);
 +    let y: Option<i64> = x.map(|_v| 1);
 +}"#,
 +        expect![[r#"
 +            86..90 'self': Option<T>
 +            92..93 'f': F
 +            111..122 '{ loop {} }': Option<U>
 +            113..120 'loop {}': !
 +            118..120 '{}': ()
 +            136..255 '{     ... 1); }': ()
 +            146..147 'x': Option<u32>
 +            150..162 'Option::Some': Some<u32>(u32) -> Option<u32>
 +            150..168 'Option...(1u32)': Option<u32>
 +            163..167 '1u32': u32
 +            174..175 'x': Option<u32>
 +            174..190 'x.map(...v + 1)': Option<u32>
 +            180..189 '|v| v + 1': |u32| -> u32
 +            181..182 'v': u32
 +            184..185 'v': u32
 +            184..189 'v + 1': u32
 +            188..189 '1': u32
 +            196..197 'x': Option<u32>
 +            196..212 'x.map(... 1u64)': Option<u64>
 +            202..211 '|_v| 1u64': |u32| -> u64
 +            203..205 '_v': u32
 +            207..211 '1u64': u64
 +            222..223 'y': Option<i64>
 +            239..240 'x': Option<u32>
 +            239..252 'x.map(|_v| 1)': Option<i64>
 +            245..251 '|_v| 1': |u32| -> i64
 +            246..248 '_v': u32
 +            250..251 '1': i64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn closure_2() {
 +    check_types(
 +        r#"
 +//- minicore: add, fn
 +
 +impl core::ops::Add for u64 {
 +    type Output = Self;
 +    fn add(self, rhs: u64) -> Self::Output {0}
 +}
 +
 +impl core::ops::Add for u128 {
 +    type Output = Self;
 +    fn add(self, rhs: u128) -> Self::Output {0}
 +}
 +
 +fn test<F: FnOnce(u32) -> u64>(f: F) {
 +    f(1);
 +  //  ^ u32
 +  //^^^^ u64
 +    let g = |v| v + 1;
 +              //^^^^^ u64
 +          //^^^^^^^^^ |u64| -> u64
 +    g(1u64);
 +  //^^^^^^^ u64
 +    let h = |v| 1u128 + v;
 +          //^^^^^^^^^^^^^ |u128| -> u128
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn closure_as_argument_inference_order() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn
 +fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U { loop {} }
 +fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U { loop {} }
 +
 +struct S;
 +impl S {
 +    fn method(self) -> u64;
 +
 +    fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U { loop {} }
 +    fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U { loop {} }
 +}
 +
 +fn test() {
 +    let x1 = foo1(S, |s| s.method());
 +    let x2 = foo2(|s| s.method(), S);
 +    let x3 = S.foo1(S, |s| s.method());
 +    let x4 = S.foo2(|s| s.method(), S);
 +}"#,
 +        expect![[r#"
 +            33..34 'x': T
 +            39..40 'f': F
 +            50..61 '{ loop {} }': U
 +            52..59 'loop {}': !
 +            57..59 '{}': ()
 +            95..96 'f': F
 +            101..102 'x': T
 +            112..123 '{ loop {} }': U
 +            114..121 'loop {}': !
 +            119..121 '{}': ()
 +            158..162 'self': S
 +            210..214 'self': S
 +            216..217 'x': T
 +            222..223 'f': F
 +            233..244 '{ loop {} }': U
 +            235..242 'loop {}': !
 +            240..242 '{}': ()
 +            282..286 'self': S
 +            288..289 'f': F
 +            294..295 'x': T
 +            305..316 '{ loop {} }': U
 +            307..314 'loop {}': !
 +            312..314 '{}': ()
 +            330..489 '{     ... S); }': ()
 +            340..342 'x1': u64
 +            345..349 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64
 +            345..368 'foo1(S...hod())': u64
 +            350..351 'S': S
 +            353..367 '|s| s.method()': |S| -> u64
 +            354..355 's': S
 +            357..358 's': S
 +            357..367 's.method()': u64
 +            378..380 'x2': u64
 +            383..387 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64
 +            383..406 'foo2(|...(), S)': u64
 +            388..402 '|s| s.method()': |S| -> u64
 +            389..390 's': S
 +            392..393 's': S
 +            392..402 's.method()': u64
 +            404..405 'S': S
 +            416..418 'x3': u64
 +            421..422 'S': S
 +            421..446 'S.foo1...hod())': u64
 +            428..429 'S': S
 +            431..445 '|s| s.method()': |S| -> u64
 +            432..433 's': S
 +            435..436 's': S
 +            435..445 's.method()': u64
 +            456..458 'x4': u64
 +            461..462 'S': S
 +            461..486 'S.foo2...(), S)': u64
 +            468..482 '|s| s.method()': |S| -> u64
 +            469..470 's': S
 +            472..473 's': S
 +            472..482 's.method()': u64
 +            484..485 'S': S
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn fn_item_fn_trait() {
 +    check_types(
 +        r#"
 +//- minicore: fn
 +struct S;
 +
 +fn foo() -> S { S }
 +
 +fn takes_closure<U, F: FnOnce() -> U>(f: F) -> U { f() }
 +
 +fn test() {
 +    takes_closure(foo);
 +} //^^^^^^^^^^^^^^^^^^ S
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_1() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +trait Trait {
 +    type Item;
 +}
 +
 +trait Trait2 {
 +    fn foo(&self) -> u32;
 +}
 +
 +fn test<T: Trait>() where T::Item: Trait2 {
 +    let x: T::Item = no_matter;
 +    x.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_2() {
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +    type Item;
 +}
 +
 +trait Trait2 {
 +    fn foo(&self) -> u32;
 +}
 +
 +fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
 +    let x: T::Item = no_matter;
 +    x.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_on_impl_self() {
 +    check_infer(
 +        r#"
 +//- /main.rs
 +trait Trait {
 +    type Item;
 +
 +    fn f(&self, x: Self::Item);
 +}
 +
 +struct S;
 +
 +impl Trait for S {
 +    type Item = u32;
 +    fn f(&self, x: Self::Item) { let y = x; }
 +}
 +
 +struct S2;
 +
 +impl Trait for S2 {
 +    type Item = i32;
 +    fn f(&self, x: <Self>::Item) { let y = x; }
 +}"#,
 +        expect![[r#"
 +            40..44 'self': &Self
 +            46..47 'x': Trait::Item<Self>
 +            126..130 'self': &S
 +            132..133 'x': u32
 +            147..161 '{ let y = x; }': ()
 +            153..154 'y': u32
 +            157..158 'x': u32
 +            228..232 'self': &S2
 +            234..235 'x': i32
 +            251..265 '{ let y = x; }': ()
 +            257..258 'y': i32
 +            261..262 'x': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_on_trait_self() {
 +    check_types(
 +        r#"
 +trait Trait {
 +    type Item;
 +
 +    fn f(&self) -> Self::Item { loop {} }
 +}
 +
 +struct S;
 +impl Trait for S {
 +    type Item = u32;
 +}
 +
 +fn test() {
 +    S.f();
 +} //^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_chalk_fold() {
 +    check_types(
 +        r#"
 +trait Interner {}
 +trait Fold<I: Interner, TI = I> {
 +    type Result;
 +}
 +
 +struct Ty<I: Interner> {}
 +impl<I: Interner, TI: Interner> Fold<I, TI> for Ty<I> {
 +    type Result = Ty<TI>;
 +}
 +
 +fn fold<I: Interner, T>(interner: &I, t: T) -> T::Result
 +where
 +    T: Fold<I, I>,
 +{
 +    loop {}
 +}
 +
 +fn foo<I: Interner>(interner: &I, t: Ty<I>) {
 +    fold(interner, t);
 +} //^^^^^^^^^^^^^^^^^ Ty<I>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_impl_self_ty() {
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +   fn foo(&self);
 +}
 +
 +struct S;
 +
 +impl Trait<Self> for S {}
 +
 +fn test() {
 +    S.foo();
 +} //^^^^^^^ ()
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_impl_self_ty_cycle() {
 +    check_types(
 +        r#"
 +trait Trait {
 +   fn foo(&self);
 +}
 +
 +struct S<T>;
 +
 +impl Trait for S<Self> {}
 +
 +fn test() {
 +    S.foo();
 +} //^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_cycle_1() {
 +    // This is not a cycle, because the `T: Trait2<T::Item>` bound depends only on the `T: Trait`
 +    // bound, not on itself (since only `Trait` can define `Item`).
 +    check_types(
 +        r#"
 +trait Trait {
 +    type Item;
 +}
 +
 +trait Trait2<T> {}
 +
 +fn test<T: Trait>() where T: Trait2<T::Item> {
 +    let x: T::Item = no_matter;
 +}                  //^^^^^^^^^ Trait::Item<T>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_cycle_2() {
 +    // this is a legitimate cycle
 +    check_types(
 +        r#"
 +//- /main.rs
 +trait Trait<T> {
 +    type Item;
 +}
 +
 +fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
 +    let x: T::Item = no_matter;
 +}                  //^^^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_cycle_3() {
 +    // this is a cycle for rustc; we currently accept it
 +    check_types(
 +        r#"
 +//- /main.rs
 +trait Trait {
 +    type Item;
 +    type OtherItem;
 +}
 +
 +fn test<T>() where T: Trait<OtherItem = T::Item> {
 +    let x: T::Item = no_matter;
 +}                  //^^^^^^^^^ Trait::Item<T>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_no_cycle() {
 +    // this is not a cycle
 +    check_types(
 +        r#"
 +//- /main.rs
 +trait Index {
 +    type Output;
 +}
 +
 +type Key<S: UnificationStoreBase> = <S as UnificationStoreBase>::Key;
 +
 +pub trait UnificationStoreBase: Index<Output = Key<Self>> {
 +    type Key;
 +
 +    fn len(&self) -> usize;
 +}
 +
 +pub trait UnificationStoreMut: UnificationStoreBase {
 +    fn push(&mut self, value: Self::Key);
 +}
 +
 +fn test<T>(t: T) where T: UnificationStoreMut {
 +    let x;
 +    t.push(x);
 +    let y: Key<T>;
 +    (x, y);
 +} //^^^^^^ (UnificationStoreBase::Key<T>, UnificationStoreBase::Key<T>)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn inline_assoc_type_bounds_1() {
 +    check_types(
 +        r#"
 +trait Iterator {
 +    type Item;
 +}
 +trait OtherTrait<T> {
 +    fn foo(&self) -> T;
 +}
 +
 +// workaround for Chalk assoc type normalization problems
 +pub struct S<T>;
 +impl<T: Iterator> Iterator for S<T> {
 +    type Item = <T as Iterator>::Item;
 +}
 +
 +fn test<I: Iterator<Item: OtherTrait<u32>>>() {
 +    let x: <S<I> as Iterator>::Item;
 +    x.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn inline_assoc_type_bounds_2() {
 +    check_types(
 +        r#"
 +trait Iterator {
 +    type Item;
 +}
 +
 +fn test<I: Iterator<Item: Iterator<Item = u32>>>() {
 +    let x: <<I as Iterator>::Item as Iterator>::Item;
 +    x;
 +} //^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn proc_macro_server_types() {
 +    check_infer(
 +        r#"
 +macro_rules! with_api {
 +    ($S:ident, $self:ident, $m:ident) => {
 +        $m! {
 +            TokenStream {
 +                fn new() -> $S::TokenStream;
 +            },
 +            Group {
 +            },
 +        }
 +    };
 +}
 +macro_rules! associated_item {
 +    (type TokenStream) =>
 +        (type TokenStream: 'static;);
 +    (type Group) =>
 +        (type Group: 'static;);
 +    ($($item:tt)*) => ($($item)*;)
 +}
 +macro_rules! declare_server_traits {
 +    ($($name:ident {
 +        $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
 +    }),* $(,)?) => {
 +        pub trait Types {
 +            $(associated_item!(type $name);)*
 +        }
 +
 +        $(pub trait $name: Types {
 +            $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)*
 +        })*
 +
 +        pub trait Server: Types $(+ $name)* {}
 +        impl<S: Types $(+ $name)*> Server for S {}
 +    }
 +}
 +
 +with_api!(Self, self_, declare_server_traits);
 +struct G {}
 +struct T {}
 +struct RustAnalyzer;
 +impl Types for RustAnalyzer {
 +    type TokenStream = T;
 +    type Group = G;
 +}
 +
 +fn make<T>() -> T { loop {} }
 +impl TokenStream for RustAnalyzer {
 +    fn new() -> Self::TokenStream {
 +        let group: Self::Group = make();
 +        make()
 +    }
 +}"#,
 +        expect![[r#"
 +            1075..1086 '{ loop {} }': T
 +            1077..1084 'loop {}': !
 +            1082..1084 '{}': ()
 +            1157..1220 '{     ...     }': T
 +            1171..1176 'group': G
 +            1192..1196 'make': fn make<G>() -> G
 +            1192..1198 'make()': G
 +            1208..1212 'make': fn make<T>() -> T
 +            1208..1214 'make()': T
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn unify_impl_trait() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Trait<T> {}
 +
 +fn foo(x: impl Trait<u32>) { loop {} }
 +fn bar<T>(x: impl Trait<T>) -> T { loop {} }
 +
 +struct S<T>(T);
 +impl<T> Trait<T> for S<T> {}
 +
 +fn default<T>() -> T { loop {} }
 +
 +fn test() -> impl Trait<i32> {
 +    let s1 = S(default());
 +    foo(s1);
 +    let x: i32 = bar(S(default()));
 +    S(default())
 +}"#,
 +        expect![[r#"
 +            26..27 'x': impl Trait<u32>
 +            46..57 '{ loop {} }': ()
 +            48..55 'loop {}': !
 +            53..55 '{}': ()
 +            68..69 'x': impl Trait<T>
 +            91..102 '{ loop {} }': T
 +            93..100 'loop {}': !
 +            98..100 '{}': ()
 +            171..182 '{ loop {} }': T
 +            173..180 'loop {}': !
 +            178..180 '{}': ()
 +            213..309 '{     ...t()) }': S<i32>
 +            223..225 's1': S<u32>
 +            228..229 'S': S<u32>(u32) -> S<u32>
 +            228..240 'S(default())': S<u32>
 +            230..237 'default': fn default<u32>() -> u32
 +            230..239 'default()': u32
 +            246..249 'foo': fn foo(S<u32>)
 +            246..253 'foo(s1)': ()
 +            250..252 's1': S<u32>
 +            263..264 'x': i32
 +            272..275 'bar': fn bar<i32>(S<i32>) -> i32
 +            272..289 'bar(S(...lt()))': i32
 +            276..277 'S': S<i32>(i32) -> S<i32>
 +            276..288 'S(default())': S<i32>
 +            278..285 'default': fn default<i32>() -> i32
 +            278..287 'default()': i32
 +            295..296 'S': S<i32>(i32) -> S<i32>
 +            295..307 'S(default())': S<i32>
 +            297..304 'default': fn default<i32>() -> i32
 +            297..306 'default()': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn assoc_types_from_bounds() {
 +    check_infer(
 +        r#"
 +//- minicore: fn
 +trait T {
 +    type O;
 +}
 +
 +impl T for () {
 +    type O = ();
 +}
 +
 +fn f<X, F>(_v: F)
 +where
 +    X: T,
 +    F: FnOnce(&X::O),
 +{ }
 +
 +fn main() {
 +    f::<(), _>(|z| { z; });
 +}"#,
 +        expect![[r#"
 +            72..74 '_v': F
 +            117..120 '{ }': ()
 +            132..163 '{     ... }); }': ()
 +            138..148 'f::<(), _>': fn f<(), |&()| -> ()>(|&()| -> ())
 +            138..160 'f::<()... z; })': ()
 +            149..159 '|z| { z; }': |&()| -> ()
 +            150..151 'z': &()
 +            153..159 '{ z; }': ()
 +            155..156 'z': &()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn associated_type_bound() {
 +    check_types(
 +        r#"
 +pub trait Trait {
 +    type Item: OtherTrait<u32>;
 +}
 +pub trait OtherTrait<T> {
 +    fn foo(&self) -> T;
 +}
 +
 +// this is just a workaround for chalk#234
 +pub struct S<T>;
 +impl<T: Trait> Trait for S<T> {
 +    type Item = <T as Trait>::Item;
 +}
 +
 +fn test<T: Trait>() {
 +    let y: <S<T> as Trait>::Item = no_matter;
 +    y.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn dyn_trait_through_chalk() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Box<T: ?Sized> {}
 +impl<T: ?Sized> core::ops::Deref for Box<T> {
 +    type Target = T;
 +}
 +trait Trait {
 +    fn foo(&self);
 +}
 +
 +fn test(x: Box<dyn Trait>) {
 +    x.foo();
 +} //^^^^^^^ ()
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn string_to_owned() {
 +    check_types(
 +        r#"
 +struct String {}
 +pub trait ToOwned {
 +    type Owned;
 +    fn to_owned(&self) -> Self::Owned;
 +}
 +impl ToOwned for str {
 +    type Owned = String;
 +}
 +fn test() {
 +    "foo".to_owned();
 +} //^^^^^^^^^^^^^^^^ String
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn iterator_chain() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn, option
 +pub trait Iterator {
 +    type Item;
 +
 +    fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
 +    where
 +        F: FnMut(Self::Item) -> Option<B>,
 +    { loop {} }
 +
 +    fn for_each<F>(self, f: F)
 +    where
 +        F: FnMut(Self::Item),
 +    { loop {} }
 +}
 +
 +pub trait IntoIterator {
 +    type Item;
 +    type IntoIter: Iterator<Item = Self::Item>;
 +    fn into_iter(self) -> Self::IntoIter;
 +}
 +
 +pub struct FilterMap<I, F> { }
 +impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
 +where
 +    F: FnMut(I::Item) -> Option<B>,
 +{
 +    type Item = B;
 +}
 +
 +#[stable(feature = "rust1", since = "1.0.0")]
 +impl<I: Iterator> IntoIterator for I {
 +    type Item = I::Item;
 +    type IntoIter = I;
 +
 +    fn into_iter(self) -> I {
 +        self
 +    }
 +}
 +
 +struct Vec<T> {}
 +impl<T> Vec<T> {
 +    fn new() -> Self { loop {} }
 +}
 +
 +impl<T> IntoIterator for Vec<T> {
 +    type Item = T;
 +    type IntoIter = IntoIter<T>;
 +}
 +
 +pub struct IntoIter<T> { }
 +impl<T> Iterator for IntoIter<T> {
 +    type Item = T;
 +}
 +
 +fn main() {
 +    Vec::<i32>::new().into_iter()
 +    .filter_map(|x| if x > 0 { Some(x as u32) } else { None })
 +    .for_each(|y| { y; });
 +}"#,
 +        expect![[r#"
 +            61..65 'self': Self
 +            67..68 'f': F
 +            152..163 '{ loop {} }': FilterMap<Self, F>
 +            154..161 'loop {}': !
 +            159..161 '{}': ()
 +            184..188 'self': Self
 +            190..191 'f': F
 +            240..251 '{ loop {} }': ()
 +            242..249 'loop {}': !
 +            247..249 '{}': ()
 +            360..364 'self': Self
 +            689..693 'self': I
 +            700..720 '{     ...     }': I
 +            710..714 'self': I
 +            779..790 '{ loop {} }': Vec<T>
 +            781..788 'loop {}': !
 +            786..788 '{}': ()
 +            977..1104 '{     ... }); }': ()
 +            983..998 'Vec::<i32>::new': fn new<i32>() -> Vec<i32>
 +            983..1000 'Vec::<...:new()': Vec<i32>
 +            983..1012 'Vec::<...iter()': IntoIter<i32>
 +            983..1075 'Vec::<...one })': FilterMap<IntoIter<i32>, |i32| -> Option<u32>>
 +            983..1101 'Vec::<... y; })': ()
 +            1029..1074 '|x| if...None }': |i32| -> Option<u32>
 +            1030..1031 'x': i32
 +            1033..1074 'if x >...None }': Option<u32>
 +            1036..1037 'x': i32
 +            1036..1041 'x > 0': bool
 +            1040..1041 '0': i32
 +            1042..1060 '{ Some...u32) }': Option<u32>
 +            1044..1048 'Some': Some<u32>(u32) -> Option<u32>
 +            1044..1058 'Some(x as u32)': Option<u32>
 +            1049..1050 'x': i32
 +            1049..1057 'x as u32': u32
 +            1066..1074 '{ None }': Option<u32>
 +            1068..1072 'None': Option<u32>
 +            1090..1100 '|y| { y; }': |u32| -> ()
 +            1091..1092 'y': u32
 +            1094..1100 '{ y; }': ()
 +            1096..1097 'y': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn nested_assoc() {
 +    check_types(
 +        r#"
 +struct Bar;
 +struct Foo;
 +
 +trait A {
 +    type OutputA;
 +}
 +
 +impl A for Bar {
 +    type OutputA = Foo;
 +}
 +
 +trait B {
 +    type Output;
 +    fn foo() -> Self::Output;
 +}
 +
 +impl<T:A> B for T {
 +    type Output = T::OutputA;
 +    fn foo() -> Self::Output { loop {} }
 +}
 +
 +fn main() {
 +    Bar::foo();
 +} //^^^^^^^^^^ Foo
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_object_no_coercion() {
 +    check_infer_with_mismatches(
 +        r#"
 +trait Foo {}
 +
 +fn foo(x: &dyn Foo) {}
 +
 +fn test(x: &dyn Foo) {
 +    foo(x);
 +}"#,
 +        expect![[r#"
 +            21..22 'x': &dyn Foo
 +            34..36 '{}': ()
 +            46..47 'x': &dyn Foo
 +            59..74 '{     foo(x); }': ()
 +            65..68 'foo': fn foo(&dyn Foo)
 +            65..71 'foo(x)': ()
 +            69..70 'x': &dyn Foo
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn builtin_copy() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: copy
 +struct IsCopy;
 +impl Copy for IsCopy {}
 +struct NotCopy;
 +
 +trait Test { fn test(&self) -> bool; }
 +impl<T: Copy> Test for T {}
 +
 +fn test() {
 +    IsCopy.test();
 +    NotCopy.test();
 +    (IsCopy, IsCopy).test();
 +    (IsCopy, NotCopy).test();
 +}"#,
 +        expect![[r#"
 +            78..82 'self': &Self
 +            134..235 '{     ...t(); }': ()
 +            140..146 'IsCopy': IsCopy
 +            140..153 'IsCopy.test()': bool
 +            159..166 'NotCopy': NotCopy
 +            159..173 'NotCopy.test()': {unknown}
 +            179..195 '(IsCop...sCopy)': (IsCopy, IsCopy)
 +            179..202 '(IsCop...test()': bool
 +            180..186 'IsCopy': IsCopy
 +            188..194 'IsCopy': IsCopy
 +            208..225 '(IsCop...tCopy)': (IsCopy, NotCopy)
 +            208..232 '(IsCop...test()': {unknown}
 +            209..215 'IsCopy': IsCopy
 +            217..224 'NotCopy': NotCopy
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn builtin_fn_def_copy() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: copy
 +fn foo() {}
 +fn bar<T: Copy>(T) -> T {}
 +struct Struct(usize);
 +enum Enum { Variant(usize) }
 +
 +trait Test { fn test(&self) -> bool; }
 +impl<T: Copy> Test for T {}
 +
 +fn test() {
 +    foo.test();
 +    bar.test();
 +    Struct.test();
 +    Enum::Variant.test();
 +}"#,
 +        expect![[r#"
 +            9..11 '{}': ()
 +            28..29 'T': {unknown}
 +            36..38 '{}': T
 +            36..38: expected T, got ()
 +            113..117 'self': &Self
 +            169..249 '{     ...t(); }': ()
 +            175..178 'foo': fn foo()
 +            175..185 'foo.test()': bool
 +            191..194 'bar': fn bar<{unknown}>({unknown}) -> {unknown}
 +            191..201 'bar.test()': bool
 +            207..213 'Struct': Struct(usize) -> Struct
 +            207..220 'Struct.test()': bool
 +            226..239 'Enum::Variant': Variant(usize) -> Enum
 +            226..246 'Enum::...test()': bool
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn builtin_fn_ptr_copy() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: copy
 +trait Test { fn test(&self) -> bool; }
 +impl<T: Copy> Test for T {}
 +
 +fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) {
 +    f1.test();
 +    f2.test();
 +    f3.test();
 +}"#,
 +        expect![[r#"
 +            22..26 'self': &Self
 +            76..78 'f1': fn()
 +            86..88 'f2': fn(usize) -> u8
 +            107..109 'f3': fn(u8, u8) -> &u8
 +            130..178 '{     ...t(); }': ()
 +            136..138 'f1': fn()
 +            136..145 'f1.test()': bool
 +            151..153 'f2': fn(usize) -> u8
 +            151..160 'f2.test()': bool
 +            166..168 'f3': fn(u8, u8) -> &u8
 +            166..175 'f3.test()': bool
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn builtin_sized() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Test { fn test(&self) -> bool; }
 +impl<T: Sized> Test for T {}
 +
 +fn test() {
 +    1u8.test();
 +    (*"foo").test(); // not Sized
 +    (1u8, 1u8).test();
 +    (1u8, *"foo").test(); // not Sized
 +}"#,
 +        expect![[r#"
 +            22..26 'self': &Self
 +            79..194 '{     ...ized }': ()
 +            85..88 '1u8': u8
 +            85..95 '1u8.test()': bool
 +            101..116 '(*"foo").test()': {unknown}
 +            102..108 '*"foo"': str
 +            103..108 '"foo"': &str
 +            135..145 '(1u8, 1u8)': (u8, u8)
 +            135..152 '(1u8, ...test()': bool
 +            136..139 '1u8': u8
 +            141..144 '1u8': u8
 +            158..171 '(1u8, *"foo")': (u8, str)
 +            158..178 '(1u8, ...test()': {unknown}
 +            159..162 '1u8': u8
 +            164..170 '*"foo"': str
 +            165..170 '"foo"': &str
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn integer_range_iterate() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:core
 +fn test() {
 +    for x in 0..100 { x; }
 +}                   //^ i32
 +
 +//- /core.rs crate:core
 +pub mod ops {
 +    pub struct Range<Idx> {
 +        pub start: Idx,
 +        pub end: Idx,
 +    }
 +}
 +
 +pub mod iter {
 +    pub trait Iterator {
 +        type Item;
 +    }
 +
 +    pub trait IntoIterator {
 +        type Item;
 +        type IntoIter: Iterator<Item = Self::Item>;
 +    }
 +
 +    impl<T> IntoIterator for T where T: Iterator {
 +        type Item = <T as Iterator>::Item;
 +        type IntoIter = Self;
 +    }
 +}
 +
 +trait Step {}
 +impl Step for i32 {}
 +impl Step for i64 {}
 +
 +impl<A: Step> iter::Iterator for ops::Range<A> {
 +    type Item = A;
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_closure_arg() {
 +    check_infer(
 +        r#"
 +//- /lib.rs
 +
 +enum Option<T> {
 +    None,
 +    Some(T)
 +}
 +
 +fn foo() {
 +    let s = Option::None;
 +    let f = |x: Option<i32>| {};
 +    (&f)(s)
 +}"#,
 +        expect![[r#"
 +            52..126 '{     ...)(s) }': ()
 +            62..63 's': Option<i32>
 +            66..78 'Option::None': Option<i32>
 +            88..89 'f': |Option<i32>| -> ()
 +            92..111 '|x: Op...2>| {}': |Option<i32>| -> ()
 +            93..94 'x': Option<i32>
 +            109..111 '{}': ()
 +            117..124 '(&f)(s)': ()
 +            118..120 '&f': &|Option<i32>| -> ()
 +            119..120 'f': |Option<i32>| -> ()
 +            122..123 's': Option<i32>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn dyn_fn_param_informs_call_site_closure_signature() {
 +    cov_mark::check!(dyn_fn_param_informs_call_site_closure_signature);
 +    check_types(
 +        r#"
 +//- minicore: fn, coerce_unsized
 +struct S;
 +impl S {
 +    fn inherent(&self) -> u8 { 0 }
 +}
 +fn take_dyn_fn(f: &dyn Fn(S)) {}
 +
 +fn f() {
 +    take_dyn_fn(&|x| { x.inherent(); });
 +                     //^^^^^^^^^^^^ u8
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_fn_trait_arg() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn, option
 +fn foo<F, T>(f: F) -> T
 +where
 +    F: Fn(Option<i32>) -> T,
 +{
 +    let s = None;
 +    f(s)
 +}
 +"#,
 +        expect![[r#"
 +            13..14 'f': F
 +            59..89 '{     ...f(s) }': T
 +            69..70 's': Option<i32>
 +            73..77 'None': Option<i32>
 +            83..84 'f': F
 +            83..87 'f(s)': T
 +            85..86 's': Option<i32>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_box_fn_arg() {
 +    // The type mismatch is because we don't define Unsize and CoerceUnsized
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn, deref, option
 +#[lang = "owned_box"]
 +pub struct Box<T: ?Sized> {
 +    inner: *mut T,
 +}
 +
 +impl<T: ?Sized> core::ops::Deref for Box<T> {
 +    type Target = T;
 +
 +    fn deref(&self) -> &T {
 +        &self.inner
 +    }
 +}
 +
 +fn foo() {
 +    let s = None;
 +    let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {});
 +    f(&s);
 +}"#,
 +        expect![[r#"
 +            154..158 'self': &Box<T>
 +            166..193 '{     ...     }': &T
 +            176..187 '&self.inner': &*mut T
 +            177..181 'self': &Box<T>
 +            177..187 'self.inner': *mut T
 +            206..296 '{     ...&s); }': ()
 +            216..217 's': Option<i32>
 +            220..224 'None': Option<i32>
 +            234..235 'f': Box<dyn FnOnce(&Option<i32>)>
 +            269..282 'box (|ps| {})': Box<|&Option<i32>| -> ()>
 +            274..281 '|ps| {}': |&Option<i32>| -> ()
 +            275..277 'ps': &Option<i32>
 +            279..281 '{}': ()
 +            288..289 'f': Box<dyn FnOnce(&Option<i32>)>
 +            288..293 'f(&s)': ()
 +            290..292 '&s': &Option<i32>
 +            291..292 's': Option<i32>
 +            269..282: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|&Option<i32>| -> ()>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_dyn_fn_output() {
 +    check_types(
 +        r#"
 +//- minicore: fn
 +fn foo() {
 +    let f: &dyn Fn() -> i32;
 +    f();
 +  //^^^ i32
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_dyn_fn_once_output() {
 +    check_types(
 +        r#"
 +//- minicore: fn
 +fn foo() {
 +    let f: dyn FnOnce() -> i32;
 +    f();
 +  //^^^ i32
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn variable_kinds_1() {
 +    check_types(
 +        r#"
 +trait Trait<T> { fn get(self, t: T) -> T; }
 +struct S;
 +impl Trait<u128> for S {}
 +impl Trait<f32> for S {}
 +fn test() {
 +    S.get(1);
 +  //^^^^^^^^ u128
 +    S.get(1.);
 +  //^^^^^^^^^ f32
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn variable_kinds_2() {
 +    check_types(
 +        r#"
 +trait Trait { fn get(self) -> Self; }
 +impl Trait for u128 {}
 +impl Trait for f32 {}
 +fn test() {
 +    1.get();
 +  //^^^^^^^ u128
 +    (1.).get();
 +  //^^^^^^^^^^ f32
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn underscore_import() {
 +    check_types(
 +        r#"
 +mod tr {
 +    pub trait Tr {
 +        fn method(&self) -> u8 { 0 }
 +    }
 +}
 +
 +struct Tr;
 +impl crate::tr::Tr for Tr {}
 +
 +use crate::tr::Tr as _;
 +fn test() {
 +    Tr.method();
 +  //^^^^^^^^^^^ u8
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn inner_use() {
 +    check_types(
 +        r#"
 +mod m {
 +    pub trait Tr {
 +        fn method(&self) -> u8 { 0 }
 +    }
 +
 +    impl Tr for () {}
 +}
 +
 +fn f() {
 +    use m::Tr;
 +
 +    ().method();
 +  //^^^^^^^^^^^ u8
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn trait_in_scope_with_inner_item() {
 +    check_infer(
 +        r#"
 +mod m {
 +    pub trait Tr {
 +        fn method(&self) -> u8 { 0 }
 +    }
 +
 +    impl Tr for () {}
 +}
 +
 +use m::Tr;
 +
 +fn f() {
 +    fn inner() {
 +        ().method();
 +      //^^^^^^^^^^^ u8
 +    }
 +}"#,
 +        expect![[r#"
 +            46..50 'self': &Self
 +            58..63 '{ 0 }': u8
 +            60..61 '0': u8
 +            115..185 '{     ...   } }': ()
 +            132..183 '{     ...     }': ()
 +            142..144 '()': ()
 +            142..153 '().method()': u8
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn inner_use_in_block() {
 +    check_types(
 +        r#"
 +mod m {
 +    pub trait Tr {
 +        fn method(&self) -> u8 { 0 }
 +    }
 +
 +    impl Tr for () {}
 +}
 +
 +fn f() {
 +    {
 +        use m::Tr;
 +
 +        ().method();
 +      //^^^^^^^^^^^ u8
 +    }
 +
 +    {
 +        ().method();
 +      //^^^^^^^^^^^ {unknown}
 +    }
 +
 +    ().method();
 +  //^^^^^^^^^^^ {unknown}
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn nested_inner_function_calling_self() {
 +    check_infer(
 +        r#"
 +struct S;
 +fn f() {
 +    fn inner() -> S {
 +        let s = inner();
 +    }
 +}"#,
 +        expect![[r#"
 +            17..73 '{     ...   } }': ()
 +            39..71 '{     ...     }': S
 +            53..54 's': S
 +            57..62 'inner': fn inner() -> S
 +            57..64 'inner()': S
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn infer_default_trait_type_parameter() {
 +    check_infer(
 +        r#"
 +struct A;
 +
 +trait Op<RHS=Self> {
 +    type Output;
 +
 +    fn do_op(self, rhs: RHS) -> Self::Output;
 +}
 +
 +impl Op for A {
 +    type Output = bool;
 +
 +    fn do_op(self, rhs: Self) -> Self::Output {
 +        true
 +    }
 +}
 +
 +fn test() {
 +    let x = A;
 +    let y = A;
 +    let r = x.do_op(y);
 +}"#,
 +        expect![[r#"
 +            63..67 'self': Self
 +            69..72 'rhs': RHS
 +            153..157 'self': A
 +            159..162 'rhs': A
 +            186..206 '{     ...     }': bool
 +            196..200 'true': bool
 +            220..277 '{     ...(y); }': ()
 +            230..231 'x': A
 +            234..235 'A': A
 +            245..246 'y': A
 +            249..250 'A': A
 +            260..261 'r': bool
 +            264..265 'x': A
 +            264..274 'x.do_op(y)': bool
 +            272..273 'y': A
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn qualified_path_as_qualified_trait() {
 +    check_infer(
 +        r#"
 +mod foo {
 +
 +    pub trait Foo {
 +        type Target;
 +    }
 +    pub trait Bar {
 +        type Output;
 +        fn boo() -> Self::Output {
 +            loop {}
 +        }
 +    }
 +}
 +
 +struct F;
 +impl foo::Foo for F {
 +    type Target = ();
 +}
 +impl foo::Bar for F {
 +    type Output = <F as foo::Foo>::Target;
 +}
 +
 +fn foo() {
 +    use foo::Bar;
 +    let x = <F as Bar>::boo();
 +}"#,
 +        expect![[r#"
 +            132..163 '{     ...     }': Bar::Output<Self>
 +            146..153 'loop {}': !
 +            151..153 '{}': ()
 +            306..358 '{     ...o(); }': ()
 +            334..335 'x': ()
 +            338..353 '<F as Bar>::boo': fn boo<F>() -> <F as Bar>::Output
 +            338..355 '<F as ...:boo()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn renamed_extern_crate_in_block() {
 +    check_types(
 +        r#"
 +//- /lib.rs crate:lib deps:serde
 +use serde::Deserialize;
 +
 +struct Foo {}
 +
 +const _ : () = {
 +    extern crate serde as _serde;
 +    impl _serde::Deserialize for Foo {
 +        fn deserialize() -> u8 { 0 }
 +    }
 +};
 +
 +fn foo() {
 +    Foo::deserialize();
 +  //^^^^^^^^^^^^^^^^^^ u8
 +}
 +
 +//- /serde.rs crate:serde
 +
 +pub trait Deserialize {
 +    fn deserialize() -> u8;
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn bin_op_with_rhs_is_self_for_assoc_bound() {
 +    check_no_mismatches(
 +        r#"//- minicore: eq
 +        fn repro<T>(t: T) -> bool
 +where
 +    T: Request,
 +    T::Output: Convertable,
 +{
 +    let a = execute(&t).convert();
 +    let b = execute(&t).convert();
 +    a.eq(&b);
 +    let a = execute(&t).convert2();
 +    let b = execute(&t).convert2();
 +    a.eq(&b)
 +}
 +fn execute<T>(t: &T) -> T::Output
 +where
 +    T: Request,
 +{
 +    <T as Request>::output()
 +}
 +trait Convertable {
 +    type TraitSelf: PartialEq<Self::TraitSelf>;
 +    type AssocAsDefaultSelf: PartialEq;
 +    fn convert(self) -> Self::AssocAsDefaultSelf;
 +    fn convert2(self) -> Self::TraitSelf;
 +}
 +trait Request {
 +    type Output;
 +    fn output() -> Self::Output;
 +}
 +     "#,
 +    );
 +}
 +
 +#[test]
 +fn bin_op_adt_with_rhs_primitive() {
 +    check_infer_with_mismatches(
 +        r#"
 +#[lang = "add"]
 +pub trait Add<Rhs = Self> {
 +    type Output;
 +    fn add(self, rhs: Rhs) -> Self::Output;
 +}
 +
 +struct Wrapper(u32);
 +impl Add<u32> for Wrapper {
 +    type Output = Self;
 +    fn add(self, rhs: u32) -> Wrapper {
 +        Wrapper(rhs)
 +    }
 +}
 +fn main(){
 +    let wrapped = Wrapper(10);
 +    let num: u32 = 2;
 +    let res = wrapped + num;
 +
 +}"#,
 +        expect![[r#"
 +            72..76 'self': Self
 +            78..81 'rhs': Rhs
 +            192..196 'self': Wrapper
 +            198..201 'rhs': u32
 +            219..247 '{     ...     }': Wrapper
 +            229..236 'Wrapper': Wrapper(u32) -> Wrapper
 +            229..241 'Wrapper(rhs)': Wrapper
 +            237..240 'rhs': u32
 +            259..345 '{     ...um;  }': ()
 +            269..276 'wrapped': Wrapper
 +            279..286 'Wrapper': Wrapper(u32) -> Wrapper
 +            279..290 'Wrapper(10)': Wrapper
 +            287..289 '10': u32
 +            300..303 'num': u32
 +            311..312 '2': u32
 +            322..325 'res': Wrapper
 +            328..335 'wrapped': Wrapper
 +            328..341 'wrapped + num': Wrapper
 +            338..341 'num': u32
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn array_length() {
 +    check_infer(
 +        r#"
 +trait T {
 +    type Output;
 +    fn do_thing(&self) -> Self::Output;
 +}
 +
 +impl T for [u8; 4] {
 +    type Output = usize;
 +    fn do_thing(&self) -> Self::Output {
 +        2
 +    }
 +}
 +
 +impl T for [u8; 2] {
 +    type Output = u8;
 +    fn do_thing(&self) -> Self::Output {
 +        2
 +    }
 +}
 +
 +fn main() {
 +    let v = [0u8; 2];
 +    let v2 = v.do_thing();
 +    let v3 = [0u8; 4];
 +    let v4 = v3.do_thing();
 +}
 +"#,
 +        expect![[r#"
 +            44..48 'self': &Self
 +            133..137 'self': &[u8; 4]
 +            155..172 '{     ...     }': usize
 +            165..166 '2': usize
 +            236..240 'self': &[u8; 2]
 +            258..275 '{     ...     }': u8
 +            268..269 '2': u8
 +            289..392 '{     ...g(); }': ()
 +            299..300 'v': [u8; 2]
 +            303..311 '[0u8; 2]': [u8; 2]
 +            304..307 '0u8': u8
 +            309..310 '2': usize
 +            321..323 'v2': u8
 +            326..327 'v': [u8; 2]
 +            326..338 'v.do_thing()': u8
 +            348..350 'v3': [u8; 4]
 +            353..361 '[0u8; 4]': [u8; 4]
 +            354..357 '0u8': u8
 +            359..360 '4': usize
 +            371..373 'v4': usize
 +            376..378 'v3': [u8; 4]
 +            376..389 'v3.do_thing()': usize
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn const_generics() {
 +    check_infer(
 +        r#"
 +trait T {
 +    type Output;
 +    fn do_thing(&self) -> Self::Output;
 +}
 +
 +impl<const L: usize> T for [u8; L] {
 +    type Output = [u8; L];
 +    fn do_thing(&self) -> Self::Output {
 +        *self
 +    }
 +}
 +
 +fn main() {
 +    let v = [0u8; 2];
 +    let v2 = v.do_thing();
 +}
 +"#,
 +        expect![[r#"
 +            44..48 'self': &Self
 +            151..155 'self': &[u8; L]
 +            173..194 '{     ...     }': [u8; L]
 +            183..188 '*self': [u8; L]
 +            184..188 'self': &[u8; L]
 +            208..260 '{     ...g(); }': ()
 +            218..219 'v': [u8; 2]
 +            222..230 '[0u8; 2]': [u8; 2]
 +            223..226 '0u8': u8
 +            228..229 '2': usize
 +            240..242 'v2': [u8; 2]
 +            245..246 'v': [u8; 2]
 +            245..257 'v.do_thing()': [u8; 2]
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn fn_returning_unit() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn
 +fn test<F: FnOnce()>(f: F) {
 +    let _: () = f();
 +}"#,
 +        expect![[r#"
 +            21..22 'f': F
 +            27..51 '{     ...f(); }': ()
 +            37..38 '_': ()
 +            45..46 'f': F
 +            45..48 'f()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn trait_in_scope_of_trait_impl() {
 +    check_infer(
 +        r#"
 +mod foo {
 +    pub trait Foo {
 +        fn foo(self);
 +        fn bar(self) -> usize { 0 }
 +    }
 +}
 +impl foo::Foo for u32 {
 +    fn foo(self) {
 +        let _x = self.bar();
 +    }
 +}
 +    "#,
 +        expect![[r#"
 +            45..49 'self': Self
 +            67..71 'self': Self
 +            82..87 '{ 0 }': usize
 +            84..85 '0': usize
 +            131..135 'self': u32
 +            137..173 '{     ...     }': ()
 +            151..153 '_x': usize
 +            156..160 'self': u32
 +            156..166 'self.bar()': usize
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_async_ret_type() {
 +    check_types(
 +        r#"
 +//- minicore: future, result
 +struct Fooey;
 +
 +impl Fooey {
 +    fn collect<B: Convert>(self) -> B {
 +        B::new()
 +    }
 +}
 +
 +trait Convert {
 +    fn new() -> Self;
 +}
 +impl Convert for u32 {
 +    fn new() -> Self { 0 }
 +}
 +
 +async fn get_accounts() -> Result<u32, ()> {
 +    let ret = Fooey.collect();
 +    //        ^^^^^^^^^^^^^^^ u32
 +    Ok(ret)
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn local_impl_1() {
 +    check!(block_local_impls);
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +}
 +
 +fn test() {
 +    struct S;
 +    impl Trait<u32> for S {
 +        fn foo(&self) -> u32 { 0 }
 +    }
 +
 +    S.foo();
 + // ^^^^^^^ u32
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn local_impl_2() {
 +    check!(block_local_impls);
 +    check_types(
 +        r#"
 +struct S;
 +
 +fn test() {
 +    trait Trait<T> {
 +        fn foo(&self) -> T;
 +    }
 +    impl Trait<u32> for S {
 +        fn foo(&self) -> u32 { 0 }
 +    }
 +
 +    S.foo();
 + // ^^^^^^^ u32
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn local_impl_3() {
 +    check!(block_local_impls);
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +}
 +
 +fn test() {
 +    struct S1;
 +    {
 +        struct S2;
 +
 +        impl Trait<S1> for S2 {
 +            fn foo(&self) -> S1 { S1 }
 +        }
 +
 +        S2.foo();
 +     // ^^^^^^^^ S1
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn associated_type_sized_bounds() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +struct Yes;
 +trait IsSized { const IS_SIZED: Yes; }
 +impl<T: Sized> IsSized for T { const IS_SIZED: Yes = Yes; }
 +
 +trait Foo {
 +    type Explicit: Sized;
 +    type Implicit;
 +    type Relaxed: ?Sized;
 +}
 +fn f<F: Foo>() {
 +    F::Explicit::IS_SIZED;
 +    F::Implicit::IS_SIZED;
 +    F::Relaxed::IS_SIZED;
 +}
 +"#,
 +        expect![[r#"
 +            104..107 'Yes': Yes
 +            212..295 '{     ...ZED; }': ()
 +            218..239 'F::Exp..._SIZED': Yes
 +            245..266 'F::Imp..._SIZED': Yes
 +            272..292 'F::Rel..._SIZED': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn dyn_map() {
 +    check_types(
 +        r#"
 +pub struct Key<K, V, P = (K, V)> {}
 +
 +pub trait Policy {
 +    type K;
 +    type V;
 +}
 +
 +impl<K, V> Policy for (K, V) {
 +    type K = K;
 +    type V = V;
 +}
 +
 +pub struct KeyMap<KEY> {}
 +
 +impl<P: Policy> KeyMap<Key<P::K, P::V, P>> {
 +    pub fn get(&self, key: &P::K) -> P::V {
 +        loop {}
 +    }
 +}
 +
 +struct Fn {}
 +struct FunctionId {}
 +
 +fn test() {
 +    let key_map: &KeyMap<Key<Fn, FunctionId>> = loop {};
 +    let key;
 +    let result = key_map.get(key);
 +      //^^^^^^ FunctionId
 +}
 +"#,
 +    )
 +}
 +
 +#[test]
 +fn dyn_multiple_auto_traits_in_different_order() {
 +    check_no_mismatches(
 +        r#"
 +auto trait Send {}
 +auto trait Sync {}
 +
 +fn f(t: &(dyn Sync + Send)) {}
 +fn g(t: &(dyn Send + Sync)) {
 +    f(t);
 +}
 +        "#,
 +    );
 +
 +    check_no_mismatches(
 +        r#"
 +auto trait Send {}
 +auto trait Sync {}
 +trait T {}
 +
 +fn f(t: &(dyn T + Send + Sync)) {}
 +fn g(t: &(dyn Sync + T + Send)) {
 +    f(t);
 +}
 +        "#,
 +    );
 +
 +    check_infer_with_mismatches(
 +        r#"
 +auto trait Send {}
 +auto trait Sync {}
 +trait T1 {}
 +trait T2 {}
 +
 +fn f(t: &(dyn T1 + T2 + Send + Sync)) {}
 +fn g(t: &(dyn Sync + T2 + T1 + Send)) {
 +    f(t);
 +}
 +        "#,
 +        expect![[r#"
 +            68..69 't': &{unknown}
 +            101..103 '{}': ()
 +            109..110 't': &{unknown}
 +            142..155 '{     f(t); }': ()
 +            148..149 'f': fn f(&{unknown})
 +            148..152 'f(t)': ()
 +            150..151 't': &{unknown}
 +        "#]],
 +    );
 +
 +    check_no_mismatches(
 +        r#"
 +auto trait Send {}
 +auto trait Sync {}
 +trait T {
 +    type Proj: Send + Sync;
 +}
 +
 +fn f(t: &(dyn T<Proj = ()>  + Send + Sync)) {}
 +fn g(t: &(dyn Sync + T<Proj = ()> + Send)) {
 +    f(t);
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn dyn_multiple_projection_bounds() {
 +    check_no_mismatches(
 +        r#"
 +trait Trait {
 +    type T;
 +    type U;
 +}
 +
 +fn f(t: &dyn Trait<T = (), U = ()>) {}
 +fn g(t: &dyn Trait<U = (), T = ()>) {
 +    f(t);
 +}
 +        "#,
 +    );
 +
 +    check_types(
 +        r#"
 +trait Trait {
 +    type T;
 +}
 +
 +fn f(t: &dyn Trait<T = (), T = ()>) {}
 +   //^&{unknown}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn dyn_duplicate_auto_trait() {
 +    check_no_mismatches(
 +        r#"
 +auto trait Send {}
 +
 +fn f(t: &(dyn Send + Send)) {}
 +fn g(t: &(dyn Send)) {
 +    f(t);
 +}
 +        "#,
 +    );
 +
 +    check_no_mismatches(
 +        r#"
 +auto trait Send {}
 +trait T {}
 +
 +fn f(t: &(dyn T + Send + Send)) {}
 +fn g(t: &(dyn T + Send)) {
 +    f(t);
 +}
 +        "#,
 +    );
 +}
index 6c8b3088adc0f1c56779c651136d18d06fea5712,0000000000000000000000000000000000000000..c5dc60f1ec5f962e319af3c48191fe2769984243
mode 100644,000000..100644
--- /dev/null
@@@ -1,184 -1,0 +1,172 @@@
- use hir_def::{path::ModPath, TraitId};
 +//! Re-export diagnostics such that clients of `hir` don't have to depend on
 +//! low-level crates.
 +//!
 +//! This probably isn't the best way to do this -- ideally, diagnostics should
 +//! be expressed in terms of hir types themselves.
 +use base_db::CrateId;
 +use cfg::{CfgExpr, CfgOptions};
 +use either::Either;
-     IncorrectTryExpr,
++use hir_def::path::ModPath;
 +use hir_expand::{name::Name, HirFileId, InFile};
 +use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
 +
 +use crate::{MacroKind, Type};
 +
 +macro_rules! diagnostics {
 +    ($($diag:ident,)*) => {
 +        #[derive(Debug)]
 +        pub enum AnyDiagnostic {$(
 +            $diag(Box<$diag>),
 +        )*}
 +
 +        $(
 +            impl From<$diag> for AnyDiagnostic {
 +                fn from(d: $diag) -> AnyDiagnostic {
 +                    AnyDiagnostic::$diag(Box::new(d))
 +                }
 +            }
 +        )*
 +    };
 +}
 +
 +diagnostics![
 +    BreakOutsideOfLoop,
 +    InactiveCode,
 +    IncorrectCase,
-     NotImplemented,
 +    InvalidDeriveTarget,
 +    MacroError,
 +    MalformedDerive,
 +    MismatchedArgCount,
 +    MissingFields,
 +    MissingMatchArms,
 +    MissingUnsafe,
- #[derive(Debug)]
- pub struct IncorrectTryExpr {
-     pub expr: InFile<AstPtr<ast::Expr>>,
- }
- #[derive(Debug)]
- pub struct NotImplemented {
-     pub expr: InFile<AstPtr<ast::Expr>>,
-     pub trait_: TraitId,
-     pub ty: Type,
- }
 +    NoSuchField,
 +    ReplaceFilterMapNextWithFindMap,
 +    TypeMismatch,
 +    UnimplementedBuiltinMacro,
 +    UnresolvedExternCrate,
 +    UnresolvedImport,
 +    UnresolvedMacroCall,
 +    UnresolvedModule,
 +    UnresolvedProcMacro,
 +];
 +
 +#[derive(Debug)]
 +pub struct UnresolvedModule {
 +    pub decl: InFile<AstPtr<ast::Module>>,
 +    pub candidates: Box<[String]>,
 +}
 +
 +#[derive(Debug)]
 +pub struct UnresolvedExternCrate {
 +    pub decl: InFile<AstPtr<ast::ExternCrate>>,
 +}
 +
 +#[derive(Debug)]
 +pub struct UnresolvedImport {
 +    pub decl: InFile<AstPtr<ast::UseTree>>,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct UnresolvedMacroCall {
 +    pub macro_call: InFile<SyntaxNodePtr>,
 +    pub precise_location: Option<TextRange>,
 +    pub path: ModPath,
 +    pub is_bang: bool,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct InactiveCode {
 +    pub node: InFile<SyntaxNodePtr>,
 +    pub cfg: CfgExpr,
 +    pub opts: CfgOptions,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct UnresolvedProcMacro {
 +    pub node: InFile<SyntaxNodePtr>,
 +    /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange`
 +    /// to use instead.
 +    pub precise_location: Option<TextRange>,
 +    pub macro_name: Option<String>,
 +    pub kind: MacroKind,
 +    /// The crate id of the proc-macro this macro belongs to, or `None` if the proc-macro can't be found.
 +    pub krate: CrateId,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct MacroError {
 +    pub node: InFile<SyntaxNodePtr>,
 +    pub precise_location: Option<TextRange>,
 +    pub message: String,
 +}
 +
 +#[derive(Debug)]
 +pub struct UnimplementedBuiltinMacro {
 +    pub node: InFile<SyntaxNodePtr>,
 +}
 +
 +#[derive(Debug)]
 +pub struct InvalidDeriveTarget {
 +    pub node: InFile<SyntaxNodePtr>,
 +}
 +
 +#[derive(Debug)]
 +pub struct MalformedDerive {
 +    pub node: InFile<SyntaxNodePtr>,
 +}
 +
 +#[derive(Debug)]
 +pub struct NoSuchField {
 +    pub field: InFile<AstPtr<ast::RecordExprField>>,
 +}
 +
 +#[derive(Debug)]
 +pub struct BreakOutsideOfLoop {
 +    pub expr: InFile<AstPtr<ast::Expr>>,
 +    pub is_break: bool,
 +}
 +
 +#[derive(Debug)]
 +pub struct MissingUnsafe {
 +    pub expr: InFile<AstPtr<ast::Expr>>,
 +}
 +
 +#[derive(Debug)]
 +pub struct MissingFields {
 +    pub file: HirFileId,
 +    pub field_list_parent: Either<AstPtr<ast::RecordExpr>, AstPtr<ast::RecordPat>>,
 +    pub field_list_parent_path: Option<AstPtr<ast::Path>>,
 +    pub missed_fields: Vec<Name>,
 +}
 +
 +#[derive(Debug)]
 +pub struct ReplaceFilterMapNextWithFindMap {
 +    pub file: HirFileId,
 +    /// This expression is the whole method chain up to and including `.filter_map(..).next()`.
 +    pub next_expr: AstPtr<ast::Expr>,
 +}
 +
 +#[derive(Debug)]
 +pub struct MismatchedArgCount {
 +    pub call_expr: InFile<AstPtr<ast::Expr>>,
 +    pub expected: usize,
 +    pub found: usize,
 +}
 +
 +#[derive(Debug)]
 +pub struct MissingMatchArms {
 +    pub file: HirFileId,
 +    pub match_expr: AstPtr<ast::Expr>,
 +    pub uncovered_patterns: String,
 +}
 +
 +#[derive(Debug)]
 +pub struct TypeMismatch {
 +    // FIXME: add mismatches in patterns as well
 +    pub expr: InFile<AstPtr<ast::Expr>>,
 +    pub expected: Type,
 +    pub actual: Type,
 +}
 +
 +pub use hir_ty::diagnostics::IncorrectCase;
index e6c5c6b5833980eaf9f8679fc5945c9ee3ec18dd,0000000000000000000000000000000000000000..f5324208c9a4ef12cf6704f1a9066b11c7378b27
mode 100644,000000..100644
--- /dev/null
@@@ -1,3757 -1,0 +1,3741 @@@
-         AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, IncorrectTryExpr,
-         InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, MissingFields,
-         MissingMatchArms, MissingUnsafe, NoSuchField, NotImplemented,
-         ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro,
-         UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, UnresolvedModule,
-         UnresolvedProcMacro,
 +//! HIR (previously known as descriptors) provides a high-level object oriented
 +//! access to Rust code.
 +//!
 +//! The principal difference between HIR and syntax trees is that HIR is bound
 +//! to a particular crate instance. That is, it has cfg flags and features
 +//! applied. So, the relation between syntax and HIR is many-to-one.
 +//!
 +//! HIR is the public API of the all of the compiler logic above syntax trees.
 +//! It is written in "OO" style. Each type is self contained (as in, it knows it's
 +//! parents and full context). It should be "clean code".
 +//!
 +//! `hir_*` crates are the implementation of the compiler logic.
 +//! They are written in "ECS" style, with relatively little abstractions.
 +//! Many types are not self-contained, and explicitly use local indexes, arenas, etc.
 +//!
 +//! `hir` is what insulates the "we don't know how to actually write an incremental compiler"
 +//! from the ide with completions, hovers, etc. It is a (soft, internal) boundary:
 +//! <https://www.tedinski.com/2018/02/06/system-boundaries.html>.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +#![recursion_limit = "512"]
 +
 +mod semantics;
 +mod source_analyzer;
 +
 +mod from_id;
 +mod attrs;
 +mod has_source;
 +
 +pub mod diagnostics;
 +pub mod db;
 +pub mod symbols;
 +
 +mod display;
 +
 +use std::{iter, ops::ControlFlow, sync::Arc};
 +
 +use arrayvec::ArrayVec;
 +use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind};
 +use either::Either;
 +use hir_def::{
 +    adt::{ReprData, VariantData},
 +    body::{BodyDiagnostic, SyntheticSyntax},
 +    expr::{BindingAnnotation, LabelId, Pat, PatId},
 +    generics::{TypeOrConstParamData, TypeParamProvenance},
 +    item_tree::ItemTreeNode,
 +    lang_item::LangItemTarget,
 +    nameres::{self, diagnostics::DefDiagnostic},
 +    per_ns::PerNs,
 +    resolver::{HasResolver, Resolver},
 +    src::HasSource as _,
 +    AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
 +    EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
 +    LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId,
 +    TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
 +};
 +use hir_expand::{name::name, MacroCallKind};
 +use hir_ty::{
 +    all_super_traits, autoderef,
 +    consteval::{unknown_const_as_generic, ComputedExpr, ConstEvalError, ConstExt},
 +    diagnostics::BodyValidationDiagnostic,
 +    method_resolution::{self, TyFingerprint},
 +    primitive::UintTy,
 +    traits::FnTrait,
 +    AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
 +    GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
 +    TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, WhereClause,
 +};
 +use itertools::Itertools;
 +use nameres::diagnostics::DefDiagnosticKind;
 +use once_cell::unsync::Lazy;
 +use rustc_hash::FxHashSet;
 +use stdx::{impl_from, never};
 +use syntax::{
 +    ast::{self, Expr, HasAttrs as _, HasDocComments, HasName},
 +    AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T,
 +};
 +
 +use crate::db::{DefDatabase, HirDatabase};
 +
 +pub use crate::{
 +    attrs::{HasAttrs, Namespace},
 +    diagnostics::{
-             match *d {
++        AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, InvalidDeriveTarget,
++        MacroError, MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms,
++        MissingUnsafe, NoSuchField, ReplaceFilterMapNextWithFindMap, TypeMismatch,
++        UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
++        UnresolvedModule, UnresolvedProcMacro,
 +    },
 +    has_source::HasSource,
 +    semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
 +};
 +
 +// Be careful with these re-exports.
 +//
 +// `hir` is the boundary between the compiler and the IDE. It should try hard to
 +// isolate the compiler from the ide, to allow the two to be refactored
 +// independently. Re-exporting something from the compiler is the sure way to
 +// breach the boundary.
 +//
 +// Generally, a refactoring which *removes* a name from this list is a good
 +// idea!
 +pub use {
 +    cfg::{CfgAtom, CfgExpr, CfgOptions},
 +    hir_def::{
 +        adt::StructKind,
 +        attr::{Attr, Attrs, AttrsWithOwner, Documentation},
 +        builtin_attr::AttributeTemplate,
 +        find_path::PrefixKind,
 +        import_map,
 +        nameres::ModuleSource,
 +        path::{ModPath, PathKind},
 +        type_ref::{Mutability, TypeRef},
 +        visibility::Visibility,
 +    },
 +    hir_expand::{
 +        name::{known, Name},
 +        ExpandResult, HirFileId, InFile, MacroFile, Origin,
 +    },
 +    hir_ty::display::HirDisplay,
 +};
 +
 +// These are negative re-exports: pub using these names is forbidden, they
 +// should remain private to hir internals.
 +#[allow(unused)]
 +use {
 +    hir_def::path::Path,
 +    hir_expand::{hygiene::Hygiene, name::AsName},
 +};
 +
 +/// hir::Crate describes a single crate. It's the main interface with which
 +/// a crate's dependencies interact. Mostly, it should be just a proxy for the
 +/// root module.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Crate {
 +    pub(crate) id: CrateId,
 +}
 +
 +#[derive(Debug)]
 +pub struct CrateDependency {
 +    pub krate: Crate,
 +    pub name: Name,
 +}
 +
 +impl Crate {
 +    pub fn origin(self, db: &dyn HirDatabase) -> CrateOrigin {
 +        db.crate_graph()[self.id].origin.clone()
 +    }
 +
 +    pub fn is_builtin(self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.origin(db), CrateOrigin::Lang(_))
 +    }
 +
 +    pub fn dependencies(self, db: &dyn HirDatabase) -> Vec<CrateDependency> {
 +        db.crate_graph()[self.id]
 +            .dependencies
 +            .iter()
 +            .map(|dep| {
 +                let krate = Crate { id: dep.crate_id };
 +                let name = dep.as_name();
 +                CrateDependency { krate, name }
 +            })
 +            .collect()
 +    }
 +
 +    pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec<Crate> {
 +        let crate_graph = db.crate_graph();
 +        crate_graph
 +            .iter()
 +            .filter(|&krate| {
 +                crate_graph[krate].dependencies.iter().any(|it| it.crate_id == self.id)
 +            })
 +            .map(|id| Crate { id })
 +            .collect()
 +    }
 +
 +    pub fn transitive_reverse_dependencies(
 +        self,
 +        db: &dyn HirDatabase,
 +    ) -> impl Iterator<Item = Crate> {
 +        db.crate_graph().transitive_rev_deps(self.id).map(|id| Crate { id })
 +    }
 +
 +    pub fn root_module(self, db: &dyn HirDatabase) -> Module {
 +        let def_map = db.crate_def_map(self.id);
 +        Module { id: def_map.module_id(def_map.root()) }
 +    }
 +
 +    pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> {
 +        let def_map = db.crate_def_map(self.id);
 +        def_map.modules().map(|(id, _)| def_map.module_id(id).into()).collect()
 +    }
 +
 +    pub fn root_file(self, db: &dyn HirDatabase) -> FileId {
 +        db.crate_graph()[self.id].root_file_id
 +    }
 +
 +    pub fn edition(self, db: &dyn HirDatabase) -> Edition {
 +        db.crate_graph()[self.id].edition
 +    }
 +
 +    pub fn version(self, db: &dyn HirDatabase) -> Option<String> {
 +        db.crate_graph()[self.id].version.clone()
 +    }
 +
 +    pub fn display_name(self, db: &dyn HirDatabase) -> Option<CrateDisplayName> {
 +        db.crate_graph()[self.id].display_name.clone()
 +    }
 +
 +    pub fn query_external_importables(
 +        self,
 +        db: &dyn DefDatabase,
 +        query: import_map::Query,
 +    ) -> impl Iterator<Item = Either<ModuleDef, Macro>> {
 +        let _p = profile::span("query_external_importables");
 +        import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| {
 +            match ItemInNs::from(item) {
 +                ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id),
 +                ItemInNs::Macros(mac_id) => Either::Right(mac_id),
 +            }
 +        })
 +    }
 +
 +    pub fn all(db: &dyn HirDatabase) -> Vec<Crate> {
 +        db.crate_graph().iter().map(|id| Crate { id }).collect()
 +    }
 +
 +    /// Try to get the root URL of the documentation of a crate.
 +    pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> {
 +        // Look for #![doc(html_root_url = "...")]
 +        let attrs = db.attrs(AttrDefId::ModuleId(self.root_module(db).into()));
 +        let doc_url = attrs.by_key("doc").find_string_value_in_tt("html_root_url");
 +        doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/")
 +    }
 +
 +    pub fn cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
 +        db.crate_graph()[self.id].cfg_options.clone()
 +    }
 +
 +    pub fn potential_cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
 +        db.crate_graph()[self.id].potential_cfg_options.clone()
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Module {
 +    pub(crate) id: ModuleId,
 +}
 +
 +/// The defs which can be visible in the module.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum ModuleDef {
 +    Module(Module),
 +    Function(Function),
 +    Adt(Adt),
 +    // Can't be directly declared, but can be imported.
 +    Variant(Variant),
 +    Const(Const),
 +    Static(Static),
 +    Trait(Trait),
 +    TypeAlias(TypeAlias),
 +    BuiltinType(BuiltinType),
 +    Macro(Macro),
 +}
 +impl_from!(
 +    Module,
 +    Function,
 +    Adt(Struct, Enum, Union),
 +    Variant,
 +    Const,
 +    Static,
 +    Trait,
 +    TypeAlias,
 +    BuiltinType,
 +    Macro
 +    for ModuleDef
 +);
 +
 +impl From<VariantDef> for ModuleDef {
 +    fn from(var: VariantDef) -> Self {
 +        match var {
 +            VariantDef::Struct(t) => Adt::from(t).into(),
 +            VariantDef::Union(t) => Adt::from(t).into(),
 +            VariantDef::Variant(t) => t.into(),
 +        }
 +    }
 +}
 +
 +impl ModuleDef {
 +    pub fn module(self, db: &dyn HirDatabase) -> Option<Module> {
 +        match self {
 +            ModuleDef::Module(it) => it.parent(db),
 +            ModuleDef::Function(it) => Some(it.module(db)),
 +            ModuleDef::Adt(it) => Some(it.module(db)),
 +            ModuleDef::Variant(it) => Some(it.module(db)),
 +            ModuleDef::Const(it) => Some(it.module(db)),
 +            ModuleDef::Static(it) => Some(it.module(db)),
 +            ModuleDef::Trait(it) => Some(it.module(db)),
 +            ModuleDef::TypeAlias(it) => Some(it.module(db)),
 +            ModuleDef::Macro(it) => Some(it.module(db)),
 +            ModuleDef::BuiltinType(_) => None,
 +        }
 +    }
 +
 +    pub fn canonical_path(&self, db: &dyn HirDatabase) -> Option<String> {
 +        let mut segments = vec![self.name(db)?];
 +        for m in self.module(db)?.path_to_root(db) {
 +            segments.extend(m.name(db))
 +        }
 +        segments.reverse();
 +        Some(segments.into_iter().join("::"))
 +    }
 +
 +    pub fn canonical_module_path(
 +        &self,
 +        db: &dyn HirDatabase,
 +    ) -> Option<impl Iterator<Item = Module>> {
 +        self.module(db).map(|it| it.path_to_root(db).into_iter().rev())
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        let name = match self {
 +            ModuleDef::Module(it) => it.name(db)?,
 +            ModuleDef::Const(it) => it.name(db)?,
 +            ModuleDef::Adt(it) => it.name(db),
 +            ModuleDef::Trait(it) => it.name(db),
 +            ModuleDef::Function(it) => it.name(db),
 +            ModuleDef::Variant(it) => it.name(db),
 +            ModuleDef::TypeAlias(it) => it.name(db),
 +            ModuleDef::Static(it) => it.name(db),
 +            ModuleDef::Macro(it) => it.name(db),
 +            ModuleDef::BuiltinType(it) => it.name(),
 +        };
 +        Some(name)
 +    }
 +
 +    pub fn diagnostics(self, db: &dyn HirDatabase) -> Vec<AnyDiagnostic> {
 +        let id = match self {
 +            ModuleDef::Adt(it) => match it {
 +                Adt::Struct(it) => it.id.into(),
 +                Adt::Enum(it) => it.id.into(),
 +                Adt::Union(it) => it.id.into(),
 +            },
 +            ModuleDef::Trait(it) => it.id.into(),
 +            ModuleDef::Function(it) => it.id.into(),
 +            ModuleDef::TypeAlias(it) => it.id.into(),
 +            ModuleDef::Module(it) => it.id.into(),
 +            ModuleDef::Const(it) => it.id.into(),
 +            ModuleDef::Static(it) => it.id.into(),
 +            ModuleDef::Variant(it) => {
 +                EnumVariantId { parent: it.parent.into(), local_id: it.id }.into()
 +            }
 +            ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => return Vec::new(),
 +        };
 +
 +        let module = match self.module(db) {
 +            Some(it) => it,
 +            None => return Vec::new(),
 +        };
 +
 +        let mut acc = Vec::new();
 +
 +        match self.as_def_with_body() {
 +            Some(def) => {
 +                def.diagnostics(db, &mut acc);
 +            }
 +            None => {
 +                for diag in hir_ty::diagnostics::incorrect_case(db, module.id.krate(), id) {
 +                    acc.push(diag.into())
 +                }
 +            }
 +        }
 +
 +        acc
 +    }
 +
 +    pub fn as_def_with_body(self) -> Option<DefWithBody> {
 +        match self {
 +            ModuleDef::Function(it) => Some(it.into()),
 +            ModuleDef::Const(it) => Some(it.into()),
 +            ModuleDef::Static(it) => Some(it.into()),
 +            ModuleDef::Variant(it) => Some(it.into()),
 +
 +            ModuleDef::Module(_)
 +            | ModuleDef::Adt(_)
 +            | ModuleDef::Trait(_)
 +            | ModuleDef::TypeAlias(_)
 +            | ModuleDef::Macro(_)
 +            | ModuleDef::BuiltinType(_) => None,
 +        }
 +    }
 +
 +    pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
 +        Some(match self {
 +            ModuleDef::Module(it) => it.attrs(db),
 +            ModuleDef::Function(it) => it.attrs(db),
 +            ModuleDef::Adt(it) => it.attrs(db),
 +            ModuleDef::Variant(it) => it.attrs(db),
 +            ModuleDef::Const(it) => it.attrs(db),
 +            ModuleDef::Static(it) => it.attrs(db),
 +            ModuleDef::Trait(it) => it.attrs(db),
 +            ModuleDef::TypeAlias(it) => it.attrs(db),
 +            ModuleDef::Macro(it) => it.attrs(db),
 +            ModuleDef::BuiltinType(_) => return None,
 +        })
 +    }
 +}
 +
 +impl HasVisibility for ModuleDef {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match *self {
 +            ModuleDef::Module(it) => it.visibility(db),
 +            ModuleDef::Function(it) => it.visibility(db),
 +            ModuleDef::Adt(it) => it.visibility(db),
 +            ModuleDef::Const(it) => it.visibility(db),
 +            ModuleDef::Static(it) => it.visibility(db),
 +            ModuleDef::Trait(it) => it.visibility(db),
 +            ModuleDef::TypeAlias(it) => it.visibility(db),
 +            ModuleDef::Variant(it) => it.visibility(db),
 +            ModuleDef::Macro(it) => it.visibility(db),
 +            ModuleDef::BuiltinType(_) => Visibility::Public,
 +        }
 +    }
 +}
 +
 +impl Module {
 +    /// Name of this module.
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        let def_map = self.id.def_map(db.upcast());
 +        let parent = def_map[self.id.local_id].parent?;
 +        def_map[parent].children.iter().find_map(|(name, module_id)| {
 +            if *module_id == self.id.local_id {
 +                Some(name.clone())
 +            } else {
 +                None
 +            }
 +        })
 +    }
 +
 +    /// Returns the crate this module is part of.
 +    pub fn krate(self) -> Crate {
 +        Crate { id: self.id.krate() }
 +    }
 +
 +    /// Topmost parent of this module. Every module has a `crate_root`, but some
 +    /// might be missing `krate`. This can happen if a module's file is not included
 +    /// in the module tree of any target in `Cargo.toml`.
 +    pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
 +        let def_map = db.crate_def_map(self.id.krate());
 +        Module { id: def_map.module_id(def_map.root()) }
 +    }
 +
 +    pub fn is_crate_root(self, db: &dyn HirDatabase) -> bool {
 +        let def_map = db.crate_def_map(self.id.krate());
 +        def_map.root() == self.id.local_id
 +    }
 +
 +    /// Iterates over all child modules.
 +    pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> {
 +        let def_map = self.id.def_map(db.upcast());
 +        let children = def_map[self.id.local_id]
 +            .children
 +            .iter()
 +            .map(|(_, module_id)| Module { id: def_map.module_id(*module_id) })
 +            .collect::<Vec<_>>();
 +        children.into_iter()
 +    }
 +
 +    /// Finds a parent module.
 +    pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> {
 +        // FIXME: handle block expressions as modules (their parent is in a different DefMap)
 +        let def_map = self.id.def_map(db.upcast());
 +        let parent_id = def_map[self.id.local_id].parent?;
 +        Some(Module { id: def_map.module_id(parent_id) })
 +    }
 +
 +    pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> {
 +        let mut res = vec![self];
 +        let mut curr = self;
 +        while let Some(next) = curr.parent(db) {
 +            res.push(next);
 +            curr = next
 +        }
 +        res
 +    }
 +
 +    /// Returns a `ModuleScope`: a set of items, visible in this module.
 +    pub fn scope(
 +        self,
 +        db: &dyn HirDatabase,
 +        visible_from: Option<Module>,
 +    ) -> Vec<(Name, ScopeDef)> {
 +        self.id.def_map(db.upcast())[self.id.local_id]
 +            .scope
 +            .entries()
 +            .filter_map(|(name, def)| {
 +                if let Some(m) = visible_from {
 +                    let filtered =
 +                        def.filter_visibility(|vis| vis.is_visible_from(db.upcast(), m.id));
 +                    if filtered.is_none() && !def.is_none() {
 +                        None
 +                    } else {
 +                        Some((name, filtered))
 +                    }
 +                } else {
 +                    Some((name, def))
 +                }
 +            })
 +            .flat_map(|(name, def)| {
 +                ScopeDef::all_items(def).into_iter().map(move |item| (name.clone(), item))
 +            })
 +            .collect()
 +    }
 +
 +    /// Fills `acc` with the module's diagnostics.
 +    pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
 +        let _p = profile::span("Module::diagnostics").detail(|| {
 +            format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
 +        });
 +        let def_map = self.id.def_map(db.upcast());
 +        for diag in def_map.diagnostics() {
 +            if diag.in_module != self.id.local_id {
 +                // FIXME: This is accidentally quadratic.
 +                continue;
 +            }
 +            emit_def_diagnostic(db, acc, diag);
 +        }
 +        for decl in self.declarations(db) {
 +            match decl {
 +                ModuleDef::Module(m) => {
 +                    // Only add diagnostics from inline modules
 +                    if def_map[m.id.local_id].origin.is_inline() {
 +                        m.diagnostics(db, acc)
 +                    }
 +                }
 +                ModuleDef::Trait(t) => {
 +                    for diag in db.trait_data_with_diagnostics(t.id).1.iter() {
 +                        emit_def_diagnostic(db, acc, diag);
 +                    }
 +                    acc.extend(decl.diagnostics(db))
 +                }
 +                ModuleDef::Adt(adt) => {
 +                    match adt {
 +                        Adt::Struct(s) => {
 +                            for diag in db.struct_data_with_diagnostics(s.id).1.iter() {
 +                                emit_def_diagnostic(db, acc, diag);
 +                            }
 +                        }
 +                        Adt::Union(u) => {
 +                            for diag in db.union_data_with_diagnostics(u.id).1.iter() {
 +                                emit_def_diagnostic(db, acc, diag);
 +                            }
 +                        }
 +                        Adt::Enum(e) => {
 +                            for v in e.variants(db) {
 +                                acc.extend(ModuleDef::Variant(v).diagnostics(db));
 +                            }
 +
 +                            for diag in db.enum_data_with_diagnostics(e.id).1.iter() {
 +                                emit_def_diagnostic(db, acc, diag);
 +                            }
 +                        }
 +                    }
 +                    acc.extend(decl.diagnostics(db))
 +                }
 +                _ => acc.extend(decl.diagnostics(db)),
 +            }
 +        }
 +
 +        for impl_def in self.impl_defs(db) {
 +            for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() {
 +                emit_def_diagnostic(db, acc, diag);
 +            }
 +
 +            for item in impl_def.items(db) {
 +                let def: DefWithBody = match item {
 +                    AssocItem::Function(it) => it.into(),
 +                    AssocItem::Const(it) => it.into(),
 +                    AssocItem::TypeAlias(_) => continue,
 +                };
 +
 +                def.diagnostics(db, acc);
 +            }
 +        }
 +    }
 +
 +    pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> {
 +        let def_map = self.id.def_map(db.upcast());
 +        let scope = &def_map[self.id.local_id].scope;
 +        scope
 +            .declarations()
 +            .map(ModuleDef::from)
 +            .chain(scope.unnamed_consts().map(|id| ModuleDef::Const(Const::from(id))))
 +            .collect()
 +    }
 +
 +    pub fn legacy_macros(self, db: &dyn HirDatabase) -> Vec<Macro> {
 +        let def_map = self.id.def_map(db.upcast());
 +        let scope = &def_map[self.id.local_id].scope;
 +        scope.legacy_macros().flat_map(|(_, it)| it).map(|&it| MacroId::from(it).into()).collect()
 +    }
 +
 +    pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> {
 +        let def_map = self.id.def_map(db.upcast());
 +        def_map[self.id.local_id].scope.impls().map(Impl::from).collect()
 +    }
 +
 +    /// Finds a path that can be used to refer to the given item from within
 +    /// this module, if possible.
 +    pub fn find_use_path(
 +        self,
 +        db: &dyn DefDatabase,
 +        item: impl Into<ItemInNs>,
 +        prefer_no_std: bool,
 +    ) -> Option<ModPath> {
 +        hir_def::find_path::find_path(db, item.into().into(), self.into(), prefer_no_std)
 +    }
 +
 +    /// Finds a path that can be used to refer to the given item from within
 +    /// this module, if possible. This is used for returning import paths for use-statements.
 +    pub fn find_use_path_prefixed(
 +        self,
 +        db: &dyn DefDatabase,
 +        item: impl Into<ItemInNs>,
 +        prefix_kind: PrefixKind,
 +        prefer_no_std: bool,
 +    ) -> Option<ModPath> {
 +        hir_def::find_path::find_path_prefixed(
 +            db,
 +            item.into().into(),
 +            self.into(),
 +            prefix_kind,
 +            prefer_no_std,
 +        )
 +    }
 +}
 +
 +fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: &DefDiagnostic) {
 +    match &diag.kind {
 +        DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => {
 +            let decl = declaration.to_node(db.upcast());
 +            acc.push(
 +                UnresolvedModule {
 +                    decl: InFile::new(declaration.file_id, AstPtr::new(&decl)),
 +                    candidates: candidates.clone(),
 +                }
 +                .into(),
 +            )
 +        }
 +        DefDiagnosticKind::UnresolvedExternCrate { ast } => {
 +            let item = ast.to_node(db.upcast());
 +            acc.push(
 +                UnresolvedExternCrate { decl: InFile::new(ast.file_id, AstPtr::new(&item)) }.into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnresolvedImport { id, index } => {
 +            let file_id = id.file_id();
 +            let item_tree = id.item_tree(db.upcast());
 +            let import = &item_tree[id.value];
 +
 +            let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index);
 +            acc.push(
 +                UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }.into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
 +            let item = ast.to_node(db.upcast());
 +            acc.push(
 +                InactiveCode {
 +                    node: ast.with_value(AstPtr::new(&item).into()),
 +                    cfg: cfg.clone(),
 +                    opts: opts.clone(),
 +                }
 +                .into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnresolvedProcMacro { ast, krate } => {
 +            let (node, precise_location, macro_name, kind) = precise_macro_call_location(ast, db);
 +            acc.push(
 +                UnresolvedProcMacro { node, precise_location, macro_name, kind, krate: *krate }
 +                    .into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
 +            let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
 +            acc.push(
 +                UnresolvedMacroCall {
 +                    macro_call: node,
 +                    precise_location,
 +                    path: path.clone(),
 +                    is_bang: matches!(ast, MacroCallKind::FnLike { .. }),
 +                }
 +                .into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::MacroError { ast, message } => {
 +            let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
 +            acc.push(MacroError { node, precise_location, message: message.clone() }.into());
 +        }
 +
 +        DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
 +            let node = ast.to_node(db.upcast());
 +            // Must have a name, otherwise we wouldn't emit it.
 +            let name = node.name().expect("unimplemented builtin macro with no name");
 +            acc.push(
 +                UnimplementedBuiltinMacro {
 +                    node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&name))),
 +                }
 +                .into(),
 +            );
 +        }
 +        DefDiagnosticKind::InvalidDeriveTarget { ast, id } => {
 +            let node = ast.to_node(db.upcast());
 +            let derive = node.attrs().nth(*id as usize);
 +            match derive {
 +                Some(derive) => {
 +                    acc.push(
 +                        InvalidDeriveTarget {
 +                            node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
 +                        }
 +                        .into(),
 +                    );
 +                }
 +                None => stdx::never!("derive diagnostic on item without derive attribute"),
 +            }
 +        }
 +        DefDiagnosticKind::MalformedDerive { ast, id } => {
 +            let node = ast.to_node(db.upcast());
 +            let derive = node.attrs().nth(*id as usize);
 +            match derive {
 +                Some(derive) => {
 +                    acc.push(
 +                        MalformedDerive {
 +                            node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
 +                        }
 +                        .into(),
 +                    );
 +                }
 +                None => stdx::never!("derive diagnostic on item without derive attribute"),
 +            }
 +        }
 +    }
 +}
 +
 +fn precise_macro_call_location(
 +    ast: &MacroCallKind,
 +    db: &dyn HirDatabase,
 +) -> (InFile<SyntaxNodePtr>, Option<TextRange>, Option<String>, MacroKind) {
 +    // FIXME: maaybe we actually want slightly different ranges for the different macro diagnostics
 +    // - e.g. the full attribute for macro errors, but only the name for name resolution
 +    match ast {
 +        MacroCallKind::FnLike { ast_id, .. } => {
 +            let node = ast_id.to_node(db.upcast());
 +            (
 +                ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
 +                node.path()
 +                    .and_then(|it| it.segment())
 +                    .and_then(|it| it.name_ref())
 +                    .map(|it| it.syntax().text_range()),
 +                node.path().and_then(|it| it.segment()).map(|it| it.to_string()),
 +                MacroKind::ProcMacro,
 +            )
 +        }
 +        MacroCallKind::Derive { ast_id, derive_attr_index, derive_index } => {
 +            let node = ast_id.to_node(db.upcast());
 +            // Compute the precise location of the macro name's token in the derive
 +            // list.
 +            let token = (|| {
 +                let derive_attr = node
 +                    .doc_comments_and_attrs()
 +                    .nth(*derive_attr_index as usize)
 +                    .and_then(Either::left)?;
 +                let token_tree = derive_attr.meta()?.token_tree()?;
 +                let group_by = token_tree
 +                    .syntax()
 +                    .children_with_tokens()
 +                    .filter_map(|elem| match elem {
 +                        syntax::NodeOrToken::Token(tok) => Some(tok),
 +                        _ => None,
 +                    })
 +                    .group_by(|t| t.kind() == T![,]);
 +                let (_, mut group) = group_by
 +                    .into_iter()
 +                    .filter(|&(comma, _)| !comma)
 +                    .nth(*derive_index as usize)?;
 +                group.find(|t| t.kind() == T![ident])
 +            })();
 +            (
 +                ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
 +                token.as_ref().map(|tok| tok.text_range()),
 +                token.as_ref().map(ToString::to_string),
 +                MacroKind::Derive,
 +            )
 +        }
 +        MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
 +            let node = ast_id.to_node(db.upcast());
 +            let attr = node
 +                .doc_comments_and_attrs()
 +                .nth((*invoc_attr_index) as usize)
 +                .and_then(Either::left)
 +                .unwrap_or_else(|| panic!("cannot find attribute #{}", invoc_attr_index));
 +
 +            (
 +                ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))),
 +                Some(attr.syntax().text_range()),
 +                attr.path()
 +                    .and_then(|path| path.segment())
 +                    .and_then(|seg| seg.name_ref())
 +                    .as_ref()
 +                    .map(ToString::to_string),
 +                MacroKind::Attr,
 +            )
 +        }
 +    }
 +}
 +
 +impl HasVisibility for Module {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        let def_map = self.id.def_map(db.upcast());
 +        let module_data = &def_map[self.id.local_id];
 +        module_data.visibility
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Field {
 +    pub(crate) parent: VariantDef,
 +    pub(crate) id: LocalFieldId,
 +}
 +
 +#[derive(Debug, PartialEq, Eq)]
 +pub enum FieldSource {
 +    Named(ast::RecordField),
 +    Pos(ast::TupleField),
 +}
 +
 +impl Field {
 +    pub fn name(&self, db: &dyn HirDatabase) -> Name {
 +        self.parent.variant_data(db).fields()[self.id].name.clone()
 +    }
 +
 +    /// Returns the type as in the signature of the struct (i.e., with
 +    /// placeholder types for type parameters). Only use this in the context of
 +    /// the field definition.
 +    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
 +        let var_id = self.parent.into();
 +        let generic_def_id: GenericDefId = match self.parent {
 +            VariantDef::Struct(it) => it.id.into(),
 +            VariantDef::Union(it) => it.id.into(),
 +            VariantDef::Variant(it) => it.parent.id.into(),
 +        };
 +        let substs = TyBuilder::placeholder_subst(db, generic_def_id);
 +        let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
 +        Type::new(db, var_id, ty)
 +    }
 +
 +    pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
 +        self.parent
 +    }
 +}
 +
 +impl HasVisibility for Field {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        let variant_data = self.parent.variant_data(db);
 +        let visibility = &variant_data.fields()[self.id].visibility;
 +        let parent_id: hir_def::VariantId = self.parent.into();
 +        visibility.resolve(db.upcast(), &parent_id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Struct {
 +    pub(crate) id: StructId,
 +}
 +
 +impl Struct {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.struct_data(self.id).name.clone()
 +    }
 +
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        db.struct_data(self.id)
 +            .variant_data
 +            .fields()
 +            .iter()
 +            .map(|(id, _)| Field { parent: self.into(), id })
 +            .collect()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +
 +    pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprData> {
 +        db.struct_data(self.id).repr.clone()
 +    }
 +
 +    pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
 +        self.variant_data(db).kind()
 +    }
 +
 +    fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        db.struct_data(self.id).variant_data.clone()
 +    }
 +}
 +
 +impl HasVisibility for Struct {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.struct_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Union {
 +    pub(crate) id: UnionId,
 +}
 +
 +impl Union {
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.union_data(self.id).name.clone()
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        db.union_data(self.id)
 +            .variant_data
 +            .fields()
 +            .iter()
 +            .map(|(id, _)| Field { parent: self.into(), id })
 +            .collect()
 +    }
 +
 +    fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        db.union_data(self.id).variant_data.clone()
 +    }
 +}
 +
 +impl HasVisibility for Union {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.union_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Enum {
 +    pub(crate) id: EnumId,
 +}
 +
 +impl Enum {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.enum_data(self.id).name.clone()
 +    }
 +
 +    pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> {
 +        db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +
 +    /// The type of the enum variant bodies.
 +    pub fn variant_body_ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::new_for_crate(
 +            self.id.lookup(db.upcast()).container.krate(),
 +            TyBuilder::builtin(match db.enum_data(self.id).variant_body_type() {
 +                Either::Left(builtin) => hir_def::builtin_type::BuiltinType::Int(builtin),
 +                Either::Right(builtin) => hir_def::builtin_type::BuiltinType::Uint(builtin),
 +            }),
 +        )
 +    }
 +
 +    pub fn is_data_carrying(self, db: &dyn HirDatabase) -> bool {
 +        self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit))
 +    }
 +}
 +
 +impl HasVisibility for Enum {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.enum_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +impl From<&Variant> for DefWithBodyId {
 +    fn from(&v: &Variant) -> Self {
 +        DefWithBodyId::VariantId(v.into())
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Variant {
 +    pub(crate) parent: Enum,
 +    pub(crate) id: LocalEnumVariantId,
 +}
 +
 +impl Variant {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.parent.module(db)
 +    }
 +
 +    pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum {
 +        self.parent
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.enum_data(self.parent.id).variants[self.id].name.clone()
 +    }
 +
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        self.variant_data(db)
 +            .fields()
 +            .iter()
 +            .map(|(id, _)| Field { parent: self.into(), id })
 +            .collect()
 +    }
 +
 +    pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
 +        self.variant_data(db).kind()
 +    }
 +
 +    pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
 +    }
 +
 +    pub fn value(self, db: &dyn HirDatabase) -> Option<Expr> {
 +        self.source(db)?.value.expr()
 +    }
 +
 +    pub fn eval(self, db: &dyn HirDatabase) -> Result<ComputedExpr, ConstEvalError> {
 +        db.const_eval_variant(self.into())
 +    }
 +}
 +
 +/// Variants inherit visibility from the parent enum.
 +impl HasVisibility for Variant {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        self.parent_enum(db).visibility(db)
 +    }
 +}
 +
 +/// A Data Type
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum Adt {
 +    Struct(Struct),
 +    Union(Union),
 +    Enum(Enum),
 +}
 +impl_from!(Struct, Union, Enum for Adt);
 +
 +impl Adt {
 +    pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
 +        let subst = db.generic_defaults(self.into());
 +        subst.iter().any(|ty| match ty.skip_binders().data(Interner) {
 +            GenericArgData::Ty(x) => x.is_unknown(),
 +            _ => false,
 +        })
 +    }
 +
 +    /// Turns this ADT into a type. Any type parameters of the ADT will be
 +    /// turned into unknown types, which is good for e.g. finding the most
 +    /// general set of completions, but will not look very nice when printed.
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let id = AdtId::from(self);
 +        Type::from_def(db, id)
 +    }
 +
 +    /// Turns this ADT into a type with the given type parameters. This isn't
 +    /// the greatest API, FIXME find a better one.
 +    pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type {
 +        let id = AdtId::from(self);
 +        let mut it = args.iter().map(|t| t.ty.clone());
 +        let ty = TyBuilder::def_ty(db, id.into(), None)
 +            .fill(|x| {
 +                let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
 +                match x {
 +                    ParamKind::Type => GenericArgData::Ty(r).intern(Interner),
 +                    ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
 +                }
 +            })
 +            .build();
 +        Type::new(db, id, ty)
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            Adt::Struct(s) => s.module(db),
 +            Adt::Union(s) => s.module(db),
 +            Adt::Enum(e) => e.module(db),
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        match self {
 +            Adt::Struct(s) => s.name(db),
 +            Adt::Union(u) => u.name(db),
 +            Adt::Enum(e) => e.name(db),
 +        }
 +    }
 +
 +    pub fn as_enum(&self) -> Option<Enum> {
 +        if let Self::Enum(v) = self {
 +            Some(*v)
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +impl HasVisibility for Adt {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match self {
 +            Adt::Struct(it) => it.visibility(db),
 +            Adt::Union(it) => it.visibility(db),
 +            Adt::Enum(it) => it.visibility(db),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum VariantDef {
 +    Struct(Struct),
 +    Union(Union),
 +    Variant(Variant),
 +}
 +impl_from!(Struct, Union, Variant for VariantDef);
 +
 +impl VariantDef {
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        match self {
 +            VariantDef::Struct(it) => it.fields(db),
 +            VariantDef::Union(it) => it.fields(db),
 +            VariantDef::Variant(it) => it.fields(db),
 +        }
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            VariantDef::Struct(it) => it.module(db),
 +            VariantDef::Union(it) => it.module(db),
 +            VariantDef::Variant(it) => it.module(db),
 +        }
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> Name {
 +        match self {
 +            VariantDef::Struct(s) => s.name(db),
 +            VariantDef::Union(u) => u.name(db),
 +            VariantDef::Variant(e) => e.name(db),
 +        }
 +    }
 +
 +    pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        match self {
 +            VariantDef::Struct(it) => it.variant_data(db),
 +            VariantDef::Union(it) => it.variant_data(db),
 +            VariantDef::Variant(it) => it.variant_data(db),
 +        }
 +    }
 +}
 +
 +/// The defs which have a body.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum DefWithBody {
 +    Function(Function),
 +    Static(Static),
 +    Const(Const),
 +    Variant(Variant),
 +}
 +impl_from!(Function, Const, Static, Variant for DefWithBody);
 +
 +impl DefWithBody {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            DefWithBody::Const(c) => c.module(db),
 +            DefWithBody::Function(f) => f.module(db),
 +            DefWithBody::Static(s) => s.module(db),
 +            DefWithBody::Variant(v) => v.module(db),
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        match self {
 +            DefWithBody::Function(f) => Some(f.name(db)),
 +            DefWithBody::Static(s) => Some(s.name(db)),
 +            DefWithBody::Const(c) => c.name(db),
 +            DefWithBody::Variant(v) => Some(v.name(db)),
 +        }
 +    }
 +
 +    /// Returns the type this def's body has to evaluate to.
 +    pub fn body_type(self, db: &dyn HirDatabase) -> Type {
 +        match self {
 +            DefWithBody::Function(it) => it.ret_type(db),
 +            DefWithBody::Static(it) => it.ty(db),
 +            DefWithBody::Const(it) => it.ty(db),
 +            DefWithBody::Variant(it) => it.parent.variant_body_ty(db),
 +        }
 +    }
 +
 +    fn id(&self) -> DefWithBodyId {
 +        match self {
 +            DefWithBody::Function(it) => it.id.into(),
 +            DefWithBody::Static(it) => it.id.into(),
 +            DefWithBody::Const(it) => it.id.into(),
 +            DefWithBody::Variant(it) => it.into(),
 +        }
 +    }
 +
 +    /// A textual representation of the HIR of this def's body for debugging purposes.
 +    pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
 +        let body = db.body(self.id());
 +        body.pretty_print(db.upcast(), self.id())
 +    }
 +
 +    pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
 +        let krate = self.module(db).id.krate();
 +
 +        let (body, source_map) = db.body_with_source_map(self.into());
 +
 +        for (_, def_map) in body.blocks(db.upcast()) {
 +            for diag in def_map.diagnostics() {
 +                emit_def_diagnostic(db, acc, diag);
 +            }
 +        }
 +
 +        for diag in source_map.diagnostics() {
 +            match diag {
 +                BodyDiagnostic::InactiveCode { node, cfg, opts } => acc.push(
 +                    InactiveCode { node: node.clone(), cfg: cfg.clone(), opts: opts.clone() }
 +                        .into(),
 +                ),
 +                BodyDiagnostic::MacroError { node, message } => acc.push(
 +                    MacroError {
 +                        node: node.clone().map(|it| it.into()),
 +                        precise_location: None,
 +                        message: message.to_string(),
 +                    }
 +                    .into(),
 +                ),
 +                BodyDiagnostic::UnresolvedProcMacro { node, krate } => acc.push(
 +                    UnresolvedProcMacro {
 +                        node: node.clone().map(|it| it.into()),
 +                        precise_location: None,
 +                        macro_name: None,
 +                        kind: MacroKind::ProcMacro,
 +                        krate: *krate,
 +                    }
 +                    .into(),
 +                ),
 +                BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push(
 +                    UnresolvedMacroCall {
 +                        macro_call: node.clone().map(|ast_ptr| ast_ptr.into()),
 +                        precise_location: None,
 +                        path: path.clone(),
 +                        is_bang: true,
 +                    }
 +                    .into(),
 +                ),
 +            }
 +        }
 +
 +        let infer = db.infer(self.into());
 +        let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1);
 +        for d in &infer.diagnostics {
-                     let field = source_map.field_syntax(expr);
++            match d {
 +                hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
-                 hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
++                    let field = source_map.field_syntax(*expr);
 +                    acc.push(NoSuchField { field }.into())
 +                }
-                     match source_map.expr_syntax(call_expr) {
++                &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
 +                    let expr = source_map
 +                        .expr_syntax(expr)
 +                        .expect("break outside of loop in synthetic syntax");
 +                    acc.push(BreakOutsideOfLoop { expr, is_break }.into())
 +                }
 +                hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
-                                 expected: expected,
-                                 found: found,
++                    match source_map.expr_syntax(*call_expr) {
 +                        Ok(source_ptr) => acc.push(
 +                            MismatchedArgCount {
 +                                call_expr: source_ptr,
-                 hir_ty::InferenceDiagnostic::IncorrectTryTarget { expr } => {
-                     let expr = source_map.expr_syntax(expr).expect("try in synthetic syntax");
-                     acc.push(IncorrectTryExpr { expr }.into())
-                 }
-                 hir_ty::InferenceDiagnostic::DoesNotImplement { expr, trait_, ref ty } => {
-                     let expr = source_map.expr_syntax(expr).expect("try in synthetic syntax");
-                     acc.push(
-                         NotImplemented {
-                             expr,
-                             trait_,
-                             ty: Type::new(db, DefWithBodyId::from(self), ty.clone()),
-                         }
-                         .into(),
-                     )
-                 }
++                                expected: *expected,
++                                found: *found,
 +                            }
 +                            .into(),
 +                        ),
 +                        Err(SyntheticSyntax) => (),
 +                    }
 +                }
 +            }
 +        }
 +        for (expr, mismatch) in infer.expr_type_mismatches() {
 +            let expr = match source_map.expr_syntax(expr) {
 +                Ok(expr) => expr,
 +                Err(SyntheticSyntax) => continue,
 +            };
 +            acc.push(
 +                TypeMismatch {
 +                    expr,
 +                    expected: Type::new(db, DefWithBodyId::from(self), mismatch.expected.clone()),
 +                    actual: Type::new(db, DefWithBodyId::from(self), mismatch.actual.clone()),
 +                }
 +                .into(),
 +            );
 +        }
 +
 +        for expr in hir_ty::diagnostics::missing_unsafe(db, self.into()) {
 +            match source_map.expr_syntax(expr) {
 +                Ok(expr) => acc.push(MissingUnsafe { expr }.into()),
 +                Err(SyntheticSyntax) => {
 +                    // FIXME: Here and eslwhere in this file, the `expr` was
 +                    // desugared, report or assert that this doesn't happen.
 +                }
 +            }
 +        }
 +
 +        for diagnostic in BodyValidationDiagnostic::collect(db, self.into()) {
 +            match diagnostic {
 +                BodyValidationDiagnostic::RecordMissingFields {
 +                    record,
 +                    variant,
 +                    missed_fields,
 +                } => {
 +                    let variant_data = variant.variant_data(db.upcast());
 +                    let missed_fields = missed_fields
 +                        .into_iter()
 +                        .map(|idx| variant_data.fields()[idx].name.clone())
 +                        .collect();
 +
 +                    match record {
 +                        Either::Left(record_expr) => match source_map.expr_syntax(record_expr) {
 +                            Ok(source_ptr) => {
 +                                let root = source_ptr.file_syntax(db.upcast());
 +                                if let ast::Expr::RecordExpr(record_expr) =
 +                                    &source_ptr.value.to_node(&root)
 +                                {
 +                                    if record_expr.record_expr_field_list().is_some() {
 +                                        acc.push(
 +                                            MissingFields {
 +                                                file: source_ptr.file_id,
 +                                                field_list_parent: Either::Left(AstPtr::new(
 +                                                    record_expr,
 +                                                )),
 +                                                field_list_parent_path: record_expr
 +                                                    .path()
 +                                                    .map(|path| AstPtr::new(&path)),
 +                                                missed_fields,
 +                                            }
 +                                            .into(),
 +                                        )
 +                                    }
 +                                }
 +                            }
 +                            Err(SyntheticSyntax) => (),
 +                        },
 +                        Either::Right(record_pat) => match source_map.pat_syntax(record_pat) {
 +                            Ok(source_ptr) => {
 +                                if let Some(expr) = source_ptr.value.as_ref().left() {
 +                                    let root = source_ptr.file_syntax(db.upcast());
 +                                    if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) {
 +                                        if record_pat.record_pat_field_list().is_some() {
 +                                            acc.push(
 +                                                MissingFields {
 +                                                    file: source_ptr.file_id,
 +                                                    field_list_parent: Either::Right(AstPtr::new(
 +                                                        &record_pat,
 +                                                    )),
 +                                                    field_list_parent_path: record_pat
 +                                                        .path()
 +                                                        .map(|path| AstPtr::new(&path)),
 +                                                    missed_fields,
 +                                                }
 +                                                .into(),
 +                                            )
 +                                        }
 +                                    }
 +                                }
 +                            }
 +                            Err(SyntheticSyntax) => (),
 +                        },
 +                    }
 +                }
 +                BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => {
 +                    if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) {
 +                        acc.push(
 +                            ReplaceFilterMapNextWithFindMap {
 +                                file: next_source_ptr.file_id,
 +                                next_expr: next_source_ptr.value,
 +                            }
 +                            .into(),
 +                        );
 +                    }
 +                }
 +                BodyValidationDiagnostic::MissingMatchArms { match_expr, uncovered_patterns } => {
 +                    match source_map.expr_syntax(match_expr) {
 +                        Ok(source_ptr) => {
 +                            let root = source_ptr.file_syntax(db.upcast());
 +                            if let ast::Expr::MatchExpr(match_expr) =
 +                                &source_ptr.value.to_node(&root)
 +                            {
 +                                if let Some(match_expr) = match_expr.expr() {
 +                                    acc.push(
 +                                        MissingMatchArms {
 +                                            file: source_ptr.file_id,
 +                                            match_expr: AstPtr::new(&match_expr),
 +                                            uncovered_patterns,
 +                                        }
 +                                        .into(),
 +                                    );
 +                                }
 +                            }
 +                        }
 +                        Err(SyntheticSyntax) => (),
 +                    }
 +                }
 +            }
 +        }
 +
 +        let def: ModuleDef = match self {
 +            DefWithBody::Function(it) => it.into(),
 +            DefWithBody::Static(it) => it.into(),
 +            DefWithBody::Const(it) => it.into(),
 +            DefWithBody::Variant(it) => it.into(),
 +        };
 +        for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) {
 +            acc.push(diag.into())
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Function {
 +    pub(crate) id: FunctionId,
 +}
 +
 +impl Function {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.lookup(db.upcast()).module(db.upcast()).into()
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.function_data(self.id).name.clone()
 +    }
 +
 +    /// Get this function's return type
 +    pub fn ret_type(self, db: &dyn HirDatabase) -> Type {
 +        let resolver = self.id.resolver(db.upcast());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        let ty = callable_sig.ret().clone();
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    pub fn async_ret_type(self, db: &dyn HirDatabase) -> Option<Type> {
 +        if !self.is_async(db) {
 +            return None;
 +        }
 +        let resolver = self.id.resolver(db.upcast());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        let ret_ty = callable_sig.ret().clone();
 +        for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() {
 +            if let WhereClause::AliasEq(output_eq) = pred.into_value_and_skipped_binders().0 {
 +                return Type::new_with_resolver_inner(db, &resolver, output_eq.ty).into();
 +            }
 +        }
 +        never!("Async fn ret_type should be impl Future");
 +        None
 +    }
 +
 +    pub fn has_self_param(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_self_param()
 +    }
 +
 +    pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
 +        self.has_self_param(db).then(|| SelfParam { func: self.id })
 +    }
 +
 +    pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> {
 +        let environment = db.trait_environment(self.id.into());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        callable_sig
 +            .params()
 +            .iter()
 +            .enumerate()
 +            .map(|(idx, ty)| {
 +                let ty = Type { env: environment.clone(), ty: ty.clone() };
 +                Param { func: self, ty, idx }
 +            })
 +            .collect()
 +    }
 +
 +    pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> {
 +        if self.self_param(db).is_none() {
 +            return None;
 +        }
 +        Some(self.params_without_self(db))
 +    }
 +
 +    pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param> {
 +        let environment = db.trait_environment(self.id.into());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        let skip = if db.function_data(self.id).has_self_param() { 1 } else { 0 };
 +        callable_sig
 +            .params()
 +            .iter()
 +            .enumerate()
 +            .skip(skip)
 +            .map(|(idx, ty)| {
 +                let ty = Type { env: environment.clone(), ty: ty.clone() };
 +                Param { func: self, ty, idx }
 +            })
 +            .collect()
 +    }
 +
 +    pub fn is_const(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_const_kw()
 +    }
 +
 +    pub fn is_async(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_async_kw()
 +    }
 +
 +    pub fn is_unsafe_to_call(self, db: &dyn HirDatabase) -> bool {
 +        hir_ty::is_fn_unsafe_to_call(db, self.id)
 +    }
 +
 +    /// Whether this function declaration has a definition.
 +    ///
 +    /// This is false in the case of required (not provided) trait methods.
 +    pub fn has_body(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_body()
 +    }
 +
 +    pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> {
 +        let function_data = db.function_data(self.id);
 +        let attrs = &function_data.attrs;
 +        // FIXME: Store this in FunctionData flags?
 +        if !(attrs.is_proc_macro()
 +            || attrs.is_proc_macro_attribute()
 +            || attrs.is_proc_macro_derive())
 +        {
 +            return None;
 +        }
 +        let loc = self.id.lookup(db.upcast());
 +        let def_map = db.crate_def_map(loc.krate(db).into());
 +        def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() })
 +    }
 +}
 +
 +// Note: logically, this belongs to `hir_ty`, but we are not using it there yet.
 +#[derive(Clone, Copy, PartialEq, Eq)]
 +pub enum Access {
 +    Shared,
 +    Exclusive,
 +    Owned,
 +}
 +
 +impl From<hir_ty::Mutability> for Access {
 +    fn from(mutability: hir_ty::Mutability) -> Access {
 +        match mutability {
 +            hir_ty::Mutability::Not => Access::Shared,
 +            hir_ty::Mutability::Mut => Access::Exclusive,
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Debug)]
 +pub struct Param {
 +    func: Function,
 +    /// The index in parameter list, including self parameter.
 +    idx: usize,
 +    ty: Type,
 +}
 +
 +impl Param {
 +    pub fn ty(&self) -> &Type {
 +        &self.ty
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
 +        db.function_data(self.func.id).params[self.idx].0.clone()
 +    }
 +
 +    pub fn as_local(&self, db: &dyn HirDatabase) -> Option<Local> {
 +        let parent = DefWithBodyId::FunctionId(self.func.into());
 +        let body = db.body(parent);
 +        let pat_id = body.params[self.idx];
 +        if let Pat::Bind { .. } = &body[pat_id] {
 +            Some(Local { parent, pat_id: body.params[self.idx] })
 +        } else {
 +            None
 +        }
 +    }
 +
 +    pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option<ast::Pat> {
 +        self.source(db).and_then(|p| p.value.pat())
 +    }
 +
 +    pub fn source(&self, db: &dyn HirDatabase) -> Option<InFile<ast::Param>> {
 +        let InFile { file_id, value } = self.func.source(db)?;
 +        let params = value.param_list()?;
 +        if params.self_param().is_some() {
 +            params.params().nth(self.idx.checked_sub(1)?)
 +        } else {
 +            params.params().nth(self.idx)
 +        }
 +        .map(|value| InFile { file_id, value })
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct SelfParam {
 +    func: FunctionId,
 +}
 +
 +impl SelfParam {
 +    pub fn access(self, db: &dyn HirDatabase) -> Access {
 +        let func_data = db.function_data(self.func);
 +        func_data
 +            .params
 +            .first()
 +            .map(|(_, param)| match &**param {
 +                TypeRef::Reference(.., mutability) => match mutability {
 +                    hir_def::type_ref::Mutability::Shared => Access::Shared,
 +                    hir_def::type_ref::Mutability::Mut => Access::Exclusive,
 +                },
 +                _ => Access::Owned,
 +            })
 +            .unwrap_or(Access::Owned)
 +    }
 +
 +    pub fn display(self, db: &dyn HirDatabase) -> &'static str {
 +        match self.access(db) {
 +            Access::Shared => "&self",
 +            Access::Exclusive => "&mut self",
 +            Access::Owned => "self",
 +        }
 +    }
 +
 +    pub fn source(&self, db: &dyn HirDatabase) -> Option<InFile<ast::SelfParam>> {
 +        let InFile { file_id, value } = Function::from(self.func).source(db)?;
 +        value
 +            .param_list()
 +            .and_then(|params| params.self_param())
 +            .map(|value| InFile { file_id, value })
 +    }
 +
 +    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
 +        let substs = TyBuilder::placeholder_subst(db, self.func);
 +        let callable_sig =
 +            db.callable_item_signature(self.func.into()).substitute(Interner, &substs);
 +        let environment = db.trait_environment(self.func.into());
 +        let ty = callable_sig.params()[0].clone();
 +        Type { env: environment, ty }
 +    }
 +}
 +
 +impl HasVisibility for Function {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.function_visibility(self.id)
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Const {
 +    pub(crate) id: ConstId,
 +}
 +
 +impl Const {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        db.const_data(self.id).name.clone()
 +    }
 +
 +    pub fn value(self, db: &dyn HirDatabase) -> Option<ast::Expr> {
 +        self.source(db)?.value.body()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let data = db.const_data(self.id);
 +        let resolver = self.id.resolver(db.upcast());
 +        let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
 +        let ty = ctx.lower_ty(&data.type_ref);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    pub fn eval(self, db: &dyn HirDatabase) -> Result<ComputedExpr, ConstEvalError> {
 +        db.const_eval(self.id)
 +    }
 +}
 +
 +impl HasVisibility for Const {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.const_visibility(self.id)
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Static {
 +    pub(crate) id: StaticId,
 +}
 +
 +impl Static {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.static_data(self.id).name.clone()
 +    }
 +
 +    pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
 +        db.static_data(self.id).mutable
 +    }
 +
 +    pub fn value(self, db: &dyn HirDatabase) -> Option<ast::Expr> {
 +        self.source(db)?.value.body()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let data = db.static_data(self.id);
 +        let resolver = self.id.resolver(db.upcast());
 +        let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
 +        let ty = ctx.lower_ty(&data.type_ref);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +}
 +
 +impl HasVisibility for Static {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.static_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Trait {
 +    pub(crate) id: TraitId,
 +}
 +
 +impl Trait {
 +    pub fn lang(db: &dyn HirDatabase, krate: Crate, name: &Name) -> Option<Trait> {
 +        db.lang_item(krate.into(), name.to_smol_str())
 +            .and_then(LangItemTarget::as_trait)
 +            .map(Into::into)
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.trait_data(self.id).name.clone()
 +    }
 +
 +    pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
 +        db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
 +    }
 +
 +    pub fn items_with_supertraits(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
 +        let traits = all_super_traits(db.upcast(), self.into());
 +        traits.iter().flat_map(|tr| Trait::from(*tr).items(db)).collect()
 +    }
 +
 +    pub fn is_auto(self, db: &dyn HirDatabase) -> bool {
 +        db.trait_data(self.id).is_auto
 +    }
 +
 +    pub fn is_unsafe(&self, db: &dyn HirDatabase) -> bool {
 +        db.trait_data(self.id).is_unsafe
 +    }
 +
 +    pub fn type_or_const_param_count(
 +        &self,
 +        db: &dyn HirDatabase,
 +        count_required_only: bool,
 +    ) -> usize {
 +        db.generic_params(GenericDefId::from(self.id))
 +            .type_or_consts
 +            .iter()
 +            .filter(|(_, ty)| match ty {
 +                TypeOrConstParamData::TypeParamData(ty)
 +                    if ty.provenance != TypeParamProvenance::TypeParamList =>
 +                {
 +                    false
 +                }
 +                _ => true,
 +            })
 +            .filter(|(_, ty)| !count_required_only || !ty.has_default())
 +            .count()
 +    }
 +}
 +
 +impl HasVisibility for Trait {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.trait_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct TypeAlias {
 +    pub(crate) id: TypeAliasId,
 +}
 +
 +impl TypeAlias {
 +    pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
 +        let subst = db.generic_defaults(self.id.into());
 +        subst.iter().any(|ty| match ty.skip_binders().data(Interner) {
 +            GenericArgData::Ty(x) => x.is_unknown(),
 +            _ => false,
 +        })
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
 +    }
 +
 +    pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
 +        db.type_alias_data(self.id).type_ref.as_deref().cloned()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.type_alias_data(self.id).name.clone()
 +    }
 +}
 +
 +impl HasVisibility for TypeAlias {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        let function_data = db.type_alias_data(self.id);
 +        let visibility = &function_data.visibility;
 +        visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct BuiltinType {
 +    pub(crate) inner: hir_def::builtin_type::BuiltinType,
 +}
 +
 +impl BuiltinType {
 +    pub fn str() -> BuiltinType {
 +        BuiltinType { inner: hir_def::builtin_type::BuiltinType::Str }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::new_for_crate(db.crate_graph().iter().next().unwrap(), TyBuilder::builtin(self.inner))
 +    }
 +
 +    pub fn name(self) -> Name {
 +        self.inner.as_name()
 +    }
 +
 +    pub fn is_int(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Int(_))
 +    }
 +
 +    pub fn is_uint(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Uint(_))
 +    }
 +
 +    pub fn is_float(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_))
 +    }
 +
 +    pub fn is_char(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Char)
 +    }
 +
 +    pub fn is_bool(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Bool)
 +    }
 +
 +    pub fn is_str(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Str)
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum MacroKind {
 +    /// `macro_rules!` or Macros 2.0 macro.
 +    Declarative,
 +    /// A built-in or custom derive.
 +    Derive,
 +    /// A built-in function-like macro.
 +    BuiltIn,
 +    /// A procedural attribute macro.
 +    Attr,
 +    /// A function-like procedural macro.
 +    ProcMacro,
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Macro {
 +    pub(crate) id: MacroId,
 +}
 +
 +impl Macro {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.module(db.upcast()) }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        match self.id {
 +            MacroId::Macro2Id(id) => db.macro2_data(id).name.clone(),
 +            MacroId::MacroRulesId(id) => db.macro_rules_data(id).name.clone(),
 +            MacroId::ProcMacroId(id) => db.proc_macro_data(id).name.clone(),
 +        }
 +    }
 +
 +    pub fn is_macro_export(self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.id, MacroId::MacroRulesId(id) if db.macro_rules_data(id).macro_export)
 +    }
 +
 +    pub fn kind(&self, db: &dyn HirDatabase) -> MacroKind {
 +        match self.id {
 +            MacroId::Macro2Id(it) => match it.lookup(db.upcast()).expander {
 +                MacroExpander::Declarative => MacroKind::Declarative,
 +                MacroExpander::BuiltIn(_) | MacroExpander::BuiltInEager(_) => MacroKind::BuiltIn,
 +                MacroExpander::BuiltInAttr(_) => MacroKind::Attr,
 +                MacroExpander::BuiltInDerive(_) => MacroKind::Derive,
 +            },
 +            MacroId::MacroRulesId(it) => match it.lookup(db.upcast()).expander {
 +                MacroExpander::Declarative => MacroKind::Declarative,
 +                MacroExpander::BuiltIn(_) | MacroExpander::BuiltInEager(_) => MacroKind::BuiltIn,
 +                MacroExpander::BuiltInAttr(_) => MacroKind::Attr,
 +                MacroExpander::BuiltInDerive(_) => MacroKind::Derive,
 +            },
 +            MacroId::ProcMacroId(it) => match it.lookup(db.upcast()).kind {
 +                ProcMacroKind::CustomDerive => MacroKind::Derive,
 +                ProcMacroKind::FuncLike => MacroKind::ProcMacro,
 +                ProcMacroKind::Attr => MacroKind::Attr,
 +            },
 +        }
 +    }
 +
 +    pub fn is_fn_like(&self, db: &dyn HirDatabase) -> bool {
 +        match self.kind(db) {
 +            MacroKind::Declarative | MacroKind::BuiltIn | MacroKind::ProcMacro => true,
 +            MacroKind::Attr | MacroKind::Derive => false,
 +        }
 +    }
 +
 +    pub fn is_builtin_derive(&self, db: &dyn HirDatabase) -> bool {
 +        match self.id {
 +            MacroId::Macro2Id(it) => {
 +                matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInDerive(_))
 +            }
 +            MacroId::MacroRulesId(it) => {
 +                matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInDerive(_))
 +            }
 +            MacroId::ProcMacroId(_) => false,
 +        }
 +    }
 +
 +    pub fn is_attr(&self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.kind(db), MacroKind::Attr)
 +    }
 +
 +    pub fn is_derive(&self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.kind(db), MacroKind::Derive)
 +    }
 +}
 +
 +impl HasVisibility for Macro {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match self.id {
 +            MacroId::Macro2Id(id) => {
 +                let data = db.macro2_data(id);
 +                let visibility = &data.visibility;
 +                visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +            }
 +            MacroId::MacroRulesId(_) => Visibility::Public,
 +            MacroId::ProcMacroId(_) => Visibility::Public,
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 +pub enum ItemInNs {
 +    Types(ModuleDef),
 +    Values(ModuleDef),
 +    Macros(Macro),
 +}
 +
 +impl From<Macro> for ItemInNs {
 +    fn from(it: Macro) -> Self {
 +        Self::Macros(it)
 +    }
 +}
 +
 +impl From<ModuleDef> for ItemInNs {
 +    fn from(module_def: ModuleDef) -> Self {
 +        match module_def {
 +            ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => {
 +                ItemInNs::Values(module_def)
 +            }
 +            _ => ItemInNs::Types(module_def),
 +        }
 +    }
 +}
 +
 +impl ItemInNs {
 +    pub fn as_module_def(self) -> Option<ModuleDef> {
 +        match self {
 +            ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
 +            ItemInNs::Macros(_) => None,
 +        }
 +    }
 +
 +    /// Returns the crate defining this item (or `None` if `self` is built-in).
 +    pub fn krate(&self, db: &dyn HirDatabase) -> Option<Crate> {
 +        match self {
 +            ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate()),
 +            ItemInNs::Macros(id) => Some(id.module(db).krate()),
 +        }
 +    }
 +
 +    pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
 +        match self {
 +            ItemInNs::Types(it) | ItemInNs::Values(it) => it.attrs(db),
 +            ItemInNs::Macros(it) => Some(it.attrs(db)),
 +        }
 +    }
 +}
 +
 +/// Invariant: `inner.as_assoc_item(db).is_some()`
 +/// We do not actively enforce this invariant.
 +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 +pub enum AssocItem {
 +    Function(Function),
 +    Const(Const),
 +    TypeAlias(TypeAlias),
 +}
 +#[derive(Debug)]
 +pub enum AssocItemContainer {
 +    Trait(Trait),
 +    Impl(Impl),
 +}
 +pub trait AsAssocItem {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem>;
 +}
 +
 +impl AsAssocItem for Function {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        as_assoc_item(db, AssocItem::Function, self.id)
 +    }
 +}
 +impl AsAssocItem for Const {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        as_assoc_item(db, AssocItem::Const, self.id)
 +    }
 +}
 +impl AsAssocItem for TypeAlias {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        as_assoc_item(db, AssocItem::TypeAlias, self.id)
 +    }
 +}
 +impl AsAssocItem for ModuleDef {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        match self {
 +            ModuleDef::Function(it) => it.as_assoc_item(db),
 +            ModuleDef::Const(it) => it.as_assoc_item(db),
 +            ModuleDef::TypeAlias(it) => it.as_assoc_item(db),
 +            _ => None,
 +        }
 +    }
 +}
 +fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem>
 +where
 +    ID: Lookup<Data = AssocItemLoc<AST>>,
 +    DEF: From<ID>,
 +    CTOR: FnOnce(DEF) -> AssocItem,
 +    AST: ItemTreeNode,
 +{
 +    match id.lookup(db.upcast()).container {
 +        ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
 +        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
 +    }
 +}
 +
 +impl AssocItem {
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        match self {
 +            AssocItem::Function(it) => Some(it.name(db)),
 +            AssocItem::Const(it) => it.name(db),
 +            AssocItem::TypeAlias(it) => Some(it.name(db)),
 +        }
 +    }
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            AssocItem::Function(f) => f.module(db),
 +            AssocItem::Const(c) => c.module(db),
 +            AssocItem::TypeAlias(t) => t.module(db),
 +        }
 +    }
 +    pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer {
 +        let container = match self {
 +            AssocItem::Function(it) => it.id.lookup(db.upcast()).container,
 +            AssocItem::Const(it) => it.id.lookup(db.upcast()).container,
 +            AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container,
 +        };
 +        match container {
 +            ItemContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
 +            ItemContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
 +            ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
 +                panic!("invalid AssocItem")
 +            }
 +        }
 +    }
 +
 +    pub fn containing_trait(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        match self.container(db) {
 +            AssocItemContainer::Trait(t) => Some(t),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn containing_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        match self.container(db) {
 +            AssocItemContainer::Impl(i) => i.trait_(db),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn containing_trait_or_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        match self.container(db) {
 +            AssocItemContainer::Trait(t) => Some(t),
 +            AssocItemContainer::Impl(i) => i.trait_(db),
 +        }
 +    }
 +}
 +
 +impl HasVisibility for AssocItem {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match self {
 +            AssocItem::Function(f) => f.visibility(db),
 +            AssocItem::Const(c) => c.visibility(db),
 +            AssocItem::TypeAlias(t) => t.visibility(db),
 +        }
 +    }
 +}
 +
 +impl From<AssocItem> for ModuleDef {
 +    fn from(assoc: AssocItem) -> Self {
 +        match assoc {
 +            AssocItem::Function(it) => ModuleDef::Function(it),
 +            AssocItem::Const(it) => ModuleDef::Const(it),
 +            AssocItem::TypeAlias(it) => ModuleDef::TypeAlias(it),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 +pub enum GenericDef {
 +    Function(Function),
 +    Adt(Adt),
 +    Trait(Trait),
 +    TypeAlias(TypeAlias),
 +    Impl(Impl),
 +    // enum variants cannot have generics themselves, but their parent enums
 +    // can, and this makes some code easier to write
 +    Variant(Variant),
 +    // consts can have type parameters from their parents (i.e. associated consts of traits)
 +    Const(Const),
 +}
 +impl_from!(
 +    Function,
 +    Adt(Struct, Enum, Union),
 +    Trait,
 +    TypeAlias,
 +    Impl,
 +    Variant,
 +    Const
 +    for GenericDef
 +);
 +
 +impl GenericDef {
 +    pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
 +        let generics = db.generic_params(self.into());
 +        let ty_params = generics.type_or_consts.iter().map(|(local_id, _)| {
 +            let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } };
 +            match toc.split(db) {
 +                Either::Left(x) => GenericParam::ConstParam(x),
 +                Either::Right(x) => GenericParam::TypeParam(x),
 +            }
 +        });
 +        let lt_params = generics
 +            .lifetimes
 +            .iter()
 +            .map(|(local_id, _)| LifetimeParam {
 +                id: LifetimeParamId { parent: self.into(), local_id },
 +            })
 +            .map(GenericParam::LifetimeParam);
 +        lt_params.chain(ty_params).collect()
 +    }
 +
 +    pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
 +        let generics = db.generic_params(self.into());
 +        generics
 +            .type_or_consts
 +            .iter()
 +            .map(|(local_id, _)| TypeOrConstParam {
 +                id: TypeOrConstParamId { parent: self.into(), local_id },
 +            })
 +            .collect()
 +    }
 +}
 +
 +/// A single local definition.
 +///
 +/// If the definition of this is part of a "MultiLocal", that is a local that has multiple declarations due to or-patterns
 +/// then this only references a single one of those.
 +/// To retrieve the other locals you should use [`Local::associated_locals`]
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct Local {
 +    pub(crate) parent: DefWithBodyId,
 +    pub(crate) pat_id: PatId,
 +}
 +
 +impl Local {
 +    pub fn is_param(self, db: &dyn HirDatabase) -> bool {
 +        let src = self.source(db);
 +        match src.value {
 +            Either::Left(pat) => pat
 +                .syntax()
 +                .ancestors()
 +                .map(|it| it.kind())
 +                .take_while(|&kind| ast::Pat::can_cast(kind) || ast::Param::can_cast(kind))
 +                .any(ast::Param::can_cast),
 +            Either::Right(_) => true,
 +        }
 +    }
 +
 +    pub fn as_self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
 +        match self.parent {
 +            DefWithBodyId::FunctionId(func) if self.is_self(db) => Some(SelfParam { func }),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let body = db.body(self.parent);
 +        match &body[self.pat_id] {
 +            Pat::Bind { name, .. } => name.clone(),
 +            _ => {
 +                stdx::never!("hir::Local is missing a name!");
 +                Name::missing()
 +            }
 +        }
 +    }
 +
 +    pub fn is_self(self, db: &dyn HirDatabase) -> bool {
 +        self.name(db) == name![self]
 +    }
 +
 +    pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
 +        let body = db.body(self.parent);
 +        matches!(&body[self.pat_id], Pat::Bind { mode: BindingAnnotation::Mutable, .. })
 +    }
 +
 +    pub fn is_ref(self, db: &dyn HirDatabase) -> bool {
 +        let body = db.body(self.parent);
 +        matches!(
 +            &body[self.pat_id],
 +            Pat::Bind { mode: BindingAnnotation::Ref | BindingAnnotation::RefMut, .. }
 +        )
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
 +        self.parent.into()
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.parent(db).module(db)
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let def = self.parent;
 +        let infer = db.infer(def);
 +        let ty = infer[self.pat_id].clone();
 +        Type::new(db, def, ty)
 +    }
 +
 +    pub fn associated_locals(self, db: &dyn HirDatabase) -> Box<[Local]> {
 +        let body = db.body(self.parent);
 +        body.ident_patterns_for(&self.pat_id)
 +            .iter()
 +            .map(|&pat_id| Local { parent: self.parent, pat_id })
 +            .collect()
 +    }
 +
 +    /// If this local is part of a multi-local, retrieve the representative local.
 +    /// That is the local that references are being resolved to.
 +    pub fn representative(self, db: &dyn HirDatabase) -> Local {
 +        let body = db.body(self.parent);
 +        Local { pat_id: body.pattern_representative(self.pat_id), ..self }
 +    }
 +
 +    pub fn source(self, db: &dyn HirDatabase) -> InFile<Either<ast::IdentPat, ast::SelfParam>> {
 +        let (_body, source_map) = db.body_with_source_map(self.parent);
 +        let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm...
 +        let root = src.file_syntax(db.upcast());
 +        src.map(|ast| match ast {
 +            // Suspicious unwrap
 +            Either::Left(it) => Either::Left(it.cast().unwrap().to_node(&root)),
 +            Either::Right(it) => Either::Right(it.to_node(&root)),
 +        })
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct DeriveHelper {
 +    pub(crate) derive: MacroId,
 +    pub(crate) idx: usize,
 +}
 +
 +impl DeriveHelper {
 +    pub fn derive(&self) -> Macro {
 +        Macro { id: self.derive.into() }
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> Name {
 +        match self.derive {
 +            MacroId::Macro2Id(_) => None,
 +            MacroId::MacroRulesId(_) => None,
 +            MacroId::ProcMacroId(proc_macro) => db
 +                .proc_macro_data(proc_macro)
 +                .helpers
 +                .as_ref()
 +                .and_then(|it| it.get(self.idx))
 +                .cloned(),
 +        }
 +        .unwrap_or_else(|| Name::missing())
 +    }
 +}
 +
 +// FIXME: Wrong name? This is could also be a registered attribute
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct BuiltinAttr {
 +    krate: Option<CrateId>,
 +    idx: usize,
 +}
 +
 +impl BuiltinAttr {
 +    // FIXME: consider crates\hir_def\src\nameres\attr_resolution.rs?
 +    pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<Self> {
 +        if let builtin @ Some(_) = Self::builtin(name) {
 +            return builtin;
 +        }
 +        let idx = db.crate_def_map(krate.id).registered_attrs().iter().position(|it| it == name)?;
 +        Some(BuiltinAttr { krate: Some(krate.id), idx })
 +    }
 +
 +    fn builtin(name: &str) -> Option<Self> {
 +        hir_def::builtin_attr::INERT_ATTRIBUTES
 +            .iter()
 +            .position(|tool| tool.name == name)
 +            .map(|idx| BuiltinAttr { krate: None, idx })
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> SmolStr {
 +        // FIXME: Return a `Name` here
 +        match self.krate {
 +            Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx].clone(),
 +            None => SmolStr::new(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].name),
 +        }
 +    }
 +
 +    pub fn template(&self, _: &dyn HirDatabase) -> Option<AttributeTemplate> {
 +        match self.krate {
 +            Some(_) => None,
 +            None => Some(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].template),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct ToolModule {
 +    krate: Option<CrateId>,
 +    idx: usize,
 +}
 +
 +impl ToolModule {
 +    // FIXME: consider crates\hir_def\src\nameres\attr_resolution.rs?
 +    pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<Self> {
 +        if let builtin @ Some(_) = Self::builtin(name) {
 +            return builtin;
 +        }
 +        let idx = db.crate_def_map(krate.id).registered_tools().iter().position(|it| it == name)?;
 +        Some(ToolModule { krate: Some(krate.id), idx })
 +    }
 +
 +    fn builtin(name: &str) -> Option<Self> {
 +        hir_def::builtin_attr::TOOL_MODULES
 +            .iter()
 +            .position(|&tool| tool == name)
 +            .map(|idx| ToolModule { krate: None, idx })
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> SmolStr {
 +        // FIXME: Return a `Name` here
 +        match self.krate {
 +            Some(krate) => db.crate_def_map(krate).registered_tools()[self.idx].clone(),
 +            None => SmolStr::new(hir_def::builtin_attr::TOOL_MODULES[self.idx]),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct Label {
 +    pub(crate) parent: DefWithBodyId,
 +    pub(crate) label_id: LabelId,
 +}
 +
 +impl Label {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.parent(db).module(db)
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
 +        self.parent.into()
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let body = db.body(self.parent);
 +        body[self.label_id].name.clone()
 +    }
 +
 +    pub fn source(self, db: &dyn HirDatabase) -> InFile<ast::Label> {
 +        let (_body, source_map) = db.body_with_source_map(self.parent);
 +        let src = source_map.label_syntax(self.label_id);
 +        let root = src.file_syntax(db.upcast());
 +        src.map(|ast| ast.to_node(&root))
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum GenericParam {
 +    TypeParam(TypeParam),
 +    ConstParam(ConstParam),
 +    LifetimeParam(LifetimeParam),
 +}
 +impl_from!(TypeParam, ConstParam, LifetimeParam for GenericParam);
 +
 +impl GenericParam {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            GenericParam::TypeParam(it) => it.module(db),
 +            GenericParam::ConstParam(it) => it.module(db),
 +            GenericParam::LifetimeParam(it) => it.module(db),
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        match self {
 +            GenericParam::TypeParam(it) => it.name(db),
 +            GenericParam::ConstParam(it) => it.name(db),
 +            GenericParam::LifetimeParam(it) => it.name(db),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct TypeParam {
 +    pub(crate) id: TypeParamId,
 +}
 +
 +impl TypeParam {
 +    pub fn merge(self) -> TypeOrConstParam {
 +        TypeOrConstParam { id: self.id.into() }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        self.merge().name(db)
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent().module(db.upcast()).into()
 +    }
 +
 +    /// Is this type parameter implicitly introduced (eg. `Self` in a trait or an `impl Trait`
 +    /// argument)?
 +    pub fn is_implicit(self, db: &dyn HirDatabase) -> bool {
 +        let params = db.generic_params(self.id.parent());
 +        let data = &params.type_or_consts[self.id.local_id()];
 +        match data.type_param().unwrap().provenance {
 +            hir_def::generics::TypeParamProvenance::TypeParamList => false,
 +            hir_def::generics::TypeParamProvenance::TraitSelf
 +            | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => true,
 +        }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let resolver = self.id.parent().resolver(db.upcast());
 +        let ty =
 +            TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id.into())).intern(Interner);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    /// FIXME: this only lists trait bounds from the item defining the type
 +    /// parameter, not additional bounds that might be added e.g. by a method if
 +    /// the parameter comes from an impl!
 +    pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
 +        db.generic_predicates_for_param(self.id.parent(), self.id.into(), None)
 +            .iter()
 +            .filter_map(|pred| match &pred.skip_binders().skip_binders() {
 +                hir_ty::WhereClause::Implemented(trait_ref) => {
 +                    Some(Trait::from(trait_ref.hir_trait_id()))
 +                }
 +                _ => None,
 +            })
 +            .collect()
 +    }
 +
 +    pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
 +        let params = db.generic_defaults(self.id.parent());
 +        let local_idx = hir_ty::param_idx(db, self.id.into())?;
 +        let resolver = self.id.parent().resolver(db.upcast());
 +        let ty = params.get(local_idx)?.clone();
 +        let subst = TyBuilder::placeholder_subst(db, self.id.parent());
 +        let ty = ty.substitute(Interner, &subst);
 +        match ty.data(Interner) {
 +            GenericArgData::Ty(x) => Some(Type::new_with_resolver_inner(db, &resolver, x.clone())),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct LifetimeParam {
 +    pub(crate) id: LifetimeParamId,
 +}
 +
 +impl LifetimeParam {
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let params = db.generic_params(self.id.parent);
 +        params.lifetimes[self.id.local_id].name.clone()
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent.module(db.upcast()).into()
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
 +        self.id.parent.into()
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct ConstParam {
 +    pub(crate) id: ConstParamId,
 +}
 +
 +impl ConstParam {
 +    pub fn merge(self) -> TypeOrConstParam {
 +        TypeOrConstParam { id: self.id.into() }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let params = db.generic_params(self.id.parent());
 +        match params.type_or_consts[self.id.local_id()].name() {
 +            Some(x) => x.clone(),
 +            None => {
 +                never!();
 +                Name::missing()
 +            }
 +        }
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent().module(db.upcast()).into()
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
 +        self.id.parent().into()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::new(db, self.id.parent(), db.const_param_ty(self.id))
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct TypeOrConstParam {
 +    pub(crate) id: TypeOrConstParamId,
 +}
 +
 +impl TypeOrConstParam {
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let params = db.generic_params(self.id.parent);
 +        match params.type_or_consts[self.id.local_id].name() {
 +            Some(n) => n.clone(),
 +            _ => Name::missing(),
 +        }
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent.module(db.upcast()).into()
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
 +        self.id.parent.into()
 +    }
 +
 +    pub fn split(self, db: &dyn HirDatabase) -> Either<ConstParam, TypeParam> {
 +        let params = db.generic_params(self.id.parent);
 +        match &params.type_or_consts[self.id.local_id] {
 +            hir_def::generics::TypeOrConstParamData::TypeParamData(_) => {
 +                Either::Right(TypeParam { id: TypeParamId::from_unchecked(self.id) })
 +            }
 +            hir_def::generics::TypeOrConstParamData::ConstParamData(_) => {
 +                Either::Left(ConstParam { id: ConstParamId::from_unchecked(self.id) })
 +            }
 +        }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        match self.split(db) {
 +            Either::Left(x) => x.ty(db),
 +            Either::Right(x) => x.ty(db),
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Impl {
 +    pub(crate) id: ImplId,
 +}
 +
 +impl Impl {
 +    pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<Impl> {
 +        let inherent = db.inherent_impls_in_crate(krate.id);
 +        let trait_ = db.trait_impls_in_crate(krate.id);
 +
 +        inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
 +    }
 +
 +    pub fn all_for_type(db: &dyn HirDatabase, Type { ty, env }: Type) -> Vec<Impl> {
 +        let def_crates = match method_resolution::def_crates(db, &ty, env.krate) {
 +            Some(def_crates) => def_crates,
 +            None => return Vec::new(),
 +        };
 +
 +        let filter = |impl_def: &Impl| {
 +            let self_ty = impl_def.self_ty(db);
 +            let rref = self_ty.remove_ref();
 +            ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty))
 +        };
 +
 +        let fp = TyFingerprint::for_inherent_impl(&ty);
 +        let fp = match fp {
 +            Some(fp) => fp,
 +            None => return Vec::new(),
 +        };
 +
 +        let mut all = Vec::new();
 +        def_crates.iter().for_each(|&id| {
 +            all.extend(
 +                db.inherent_impls_in_crate(id)
 +                    .for_self_ty(&ty)
 +                    .iter()
 +                    .cloned()
 +                    .map(Self::from)
 +                    .filter(filter),
 +            )
 +        });
 +        for id in def_crates
 +            .iter()
 +            .flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db))
 +            .map(|Crate { id }| id)
 +            .chain(def_crates.iter().copied())
 +            .unique()
 +        {
 +            all.extend(
 +                db.trait_impls_in_crate(id)
 +                    .for_self_ty_without_blanket_impls(fp)
 +                    .map(Self::from)
 +                    .filter(filter),
 +            );
 +        }
 +        all
 +    }
 +
 +    pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec<Impl> {
 +        let krate = trait_.module(db).krate();
 +        let mut all = Vec::new();
 +        for Crate { id } in krate.transitive_reverse_dependencies(db).into_iter() {
 +            let impls = db.trait_impls_in_crate(id);
 +            all.extend(impls.for_trait(trait_.id).map(Self::from))
 +        }
 +        all
 +    }
 +
 +    // FIXME: the return type is wrong. This should be a hir version of
 +    // `TraitRef` (to account for parameters and qualifiers)
 +    pub fn trait_(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        let trait_ref = db.impl_trait(self.id)?.skip_binders().clone();
 +        let id = hir_ty::from_chalk_trait_id(trait_ref.trait_id);
 +        Some(Trait { id })
 +    }
 +
 +    pub fn self_ty(self, db: &dyn HirDatabase) -> Type {
 +        let resolver = self.id.resolver(db.upcast());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let ty = db.impl_self_ty(self.id).substitute(Interner, &substs);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
 +        db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect()
 +    }
 +
 +    pub fn is_negative(self, db: &dyn HirDatabase) -> bool {
 +        db.impl_data(self.id).is_negative
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.lookup(db.upcast()).container.into()
 +    }
 +
 +    pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> {
 +        let src = self.source(db)?;
 +        src.file_id.is_builtin_derive(db.upcast())
 +    }
 +}
 +
 +#[derive(Clone, PartialEq, Eq, Debug)]
 +pub struct Type {
 +    env: Arc<TraitEnvironment>,
 +    ty: Ty,
 +}
 +
 +impl Type {
 +    pub(crate) fn new_with_resolver(db: &dyn HirDatabase, resolver: &Resolver, ty: Ty) -> Type {
 +        Type::new_with_resolver_inner(db, resolver, ty)
 +    }
 +
 +    pub(crate) fn new_with_resolver_inner(
 +        db: &dyn HirDatabase,
 +        resolver: &Resolver,
 +        ty: Ty,
 +    ) -> Type {
 +        let environment = resolver.generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(resolver.krate())),
 +            |d| db.trait_environment(d),
 +        );
 +        Type { env: environment, ty }
 +    }
 +
 +    pub(crate) fn new_for_crate(krate: CrateId, ty: Ty) -> Type {
 +        Type { env: Arc::new(TraitEnvironment::empty(krate)), ty }
 +    }
 +
 +    pub fn reference(inner: &Type, m: Mutability) -> Type {
 +        inner.derived(
 +            TyKind::Ref(
 +                if m.is_mut() { hir_ty::Mutability::Mut } else { hir_ty::Mutability::Not },
 +                hir_ty::static_lifetime(),
 +                inner.ty.clone(),
 +            )
 +            .intern(Interner),
 +        )
 +    }
 +
 +    fn new(db: &dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty) -> Type {
 +        let resolver = lexical_env.resolver(db.upcast());
 +        let environment = resolver.generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(resolver.krate())),
 +            |d| db.trait_environment(d),
 +        );
 +        Type { env: environment, ty }
 +    }
 +
 +    fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into<TyDefId>) -> Type {
 +        let ty_def = def.into();
 +        let parent_subst = match ty_def {
 +            TyDefId::TypeAliasId(id) => match id.lookup(db.upcast()).container {
 +                ItemContainerId::TraitId(id) => {
 +                    let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
 +                    Some(subst)
 +                }
 +                ItemContainerId::ImplId(id) => {
 +                    let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
 +                    Some(subst)
 +                }
 +                _ => None,
 +            },
 +            _ => None,
 +        };
 +        let ty = TyBuilder::def_ty(db, ty_def, parent_subst).fill_with_unknown().build();
 +        Type::new(db, def, ty)
 +    }
 +
 +    pub fn new_slice(ty: Type) -> Type {
 +        Type { env: ty.env, ty: TyBuilder::slice(ty.ty) }
 +    }
 +
 +    pub fn is_unit(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Tuple(0, ..))
 +    }
 +
 +    pub fn is_bool(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Bool))
 +    }
 +
 +    pub fn is_never(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Never)
 +    }
 +
 +    pub fn is_mutable_reference(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..))
 +    }
 +
 +    pub fn is_reference(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Ref(..))
 +    }
 +
 +    pub fn as_reference(&self) -> Option<(Type, Mutability)> {
 +        let (ty, _lt, m) = self.ty.as_reference()?;
 +        let m = Mutability::from_mutable(matches!(m, hir_ty::Mutability::Mut));
 +        Some((self.derived(ty.clone()), m))
 +    }
 +
 +    pub fn is_slice(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Slice(..))
 +    }
 +
 +    pub fn is_usize(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)))
 +    }
 +
 +    pub fn remove_ref(&self) -> Option<Type> {
 +        match &self.ty.kind(Interner) {
 +            TyKind::Ref(.., ty) => Some(self.derived(ty.clone())),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn strip_references(&self) -> Type {
 +        self.derived(self.ty.strip_references().clone())
 +    }
 +
 +    pub fn strip_reference(&self) -> Type {
 +        self.derived(self.ty.strip_reference().clone())
 +    }
 +
 +    pub fn is_unknown(&self) -> bool {
 +        self.ty.is_unknown()
 +    }
 +
 +    /// Checks that particular type `ty` implements `std::future::IntoFuture` or
 +    /// `std::future::Future`.
 +    /// This function is used in `.await` syntax completion.
 +    pub fn impls_into_future(&self, db: &dyn HirDatabase) -> bool {
 +        let trait_ = db
 +            .lang_item(self.env.krate, SmolStr::new_inline("into_future"))
 +            .and_then(|it| {
 +                let into_future_fn = it.as_function()?;
 +                let assoc_item = as_assoc_item(db, AssocItem::Function, into_future_fn)?;
 +                let into_future_trait = assoc_item.containing_trait_or_trait_impl(db)?;
 +                Some(into_future_trait.id)
 +            })
 +            .or_else(|| {
 +                let future_trait =
 +                    db.lang_item(self.env.krate, SmolStr::new_inline("future_trait"))?;
 +                future_trait.as_trait()
 +            });
 +
 +        let trait_ = match trait_ {
 +            Some(it) => it,
 +            None => return false,
 +        };
 +
 +        let canonical_ty =
 +            Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
 +        method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), trait_)
 +    }
 +
 +    /// Checks that particular type `ty` implements `std::ops::FnOnce`.
 +    ///
 +    /// This function can be used to check if a particular type is callable, since FnOnce is a
 +    /// supertrait of Fn and FnMut, so all callable types implements at least FnOnce.
 +    pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool {
 +        let fnonce_trait = match FnTrait::FnOnce.get_id(db, self.env.krate) {
 +            Some(it) => it,
 +            None => return false,
 +        };
 +
 +        let canonical_ty =
 +            Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
 +        method_resolution::implements_trait_unique(
 +            &canonical_ty,
 +            db,
 +            self.env.clone(),
 +            fnonce_trait,
 +        )
 +    }
 +
 +    pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
 +        let mut it = args.iter().map(|t| t.ty.clone());
 +        let trait_ref = TyBuilder::trait_ref(db, trait_.id)
 +            .push(self.ty.clone())
 +            .fill(|x| {
 +                let r = it.next().unwrap();
 +                match x {
 +                    ParamKind::Type => GenericArgData::Ty(r).intern(Interner),
 +                    ParamKind::Const(ty) => {
 +                        // FIXME: this code is not covered in tests.
 +                        unknown_const_as_generic(ty.clone())
 +                    }
 +                }
 +            })
 +            .build();
 +
 +        let goal = Canonical {
 +            value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(Interner)),
 +            binders: CanonicalVarKinds::empty(Interner),
 +        };
 +
 +        db.trait_solve(self.env.krate, goal).is_some()
 +    }
 +
 +    pub fn normalize_trait_assoc_type(
 +        &self,
 +        db: &dyn HirDatabase,
 +        args: &[Type],
 +        alias: TypeAlias,
 +    ) -> Option<Type> {
 +        let mut args = args.iter();
 +        let trait_id = match alias.id.lookup(db.upcast()).container {
 +            ItemContainerId::TraitId(id) => id,
 +            _ => unreachable!("non assoc type alias reached in normalize_trait_assoc_type()"),
 +        };
 +        let parent_subst = TyBuilder::subst_for_def(db, trait_id, None)
 +            .push(self.ty.clone())
 +            .fill(|x| {
 +                // FIXME: this code is not covered in tests.
 +                match x {
 +                    ParamKind::Type => {
 +                        GenericArgData::Ty(args.next().unwrap().ty.clone()).intern(Interner)
 +                    }
 +                    ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
 +                }
 +            })
 +            .build();
 +        // FIXME: We don't handle GATs yet.
 +        let projection = TyBuilder::assoc_type_projection(db, alias.id, Some(parent_subst)).build();
 +
 +        let ty = db.normalize_projection(projection, self.env.clone());
 +        if ty.is_unknown() {
 +            None
 +        } else {
 +            Some(self.derived(ty))
 +        }
 +    }
 +
 +    pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
 +        let lang_item = db.lang_item(self.env.krate, SmolStr::new_inline("copy"));
 +        let copy_trait = match lang_item {
 +            Some(LangItemTarget::TraitId(it)) => it,
 +            _ => return false,
 +        };
 +        self.impls_trait(db, copy_trait.into(), &[])
 +    }
 +
 +    pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
 +        let callee = match self.ty.kind(Interner) {
 +            TyKind::Closure(id, _) => Callee::Closure(*id),
 +            TyKind::Function(_) => Callee::FnPtr,
 +            _ => Callee::Def(self.ty.callable_def(db)?),
 +        };
 +
 +        let sig = self.ty.callable_sig(db)?;
 +        Some(Callable { ty: self.clone(), sig, callee, is_bound_method: false })
 +    }
 +
 +    pub fn is_closure(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::Closure { .. })
 +    }
 +
 +    pub fn is_fn(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::FnDef(..) | TyKind::Function { .. })
 +    }
 +
 +    pub fn is_array(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::Array(..))
 +    }
 +
 +    pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
 +        let adt_id = match *self.ty.kind(Interner) {
 +            TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id,
 +            _ => return false,
 +        };
 +
 +        let adt = adt_id.into();
 +        match adt {
 +            Adt::Struct(s) => matches!(s.repr(db), Some(ReprData { packed: true, .. })),
 +            _ => false,
 +        }
 +    }
 +
 +    pub fn is_raw_ptr(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::Raw(..))
 +    }
 +
 +    pub fn contains_unknown(&self) -> bool {
 +        return go(&self.ty);
 +
 +        fn go(ty: &Ty) -> bool {
 +            match ty.kind(Interner) {
 +                TyKind::Error => true,
 +
 +                TyKind::Adt(_, substs)
 +                | TyKind::AssociatedType(_, substs)
 +                | TyKind::Tuple(_, substs)
 +                | TyKind::OpaqueType(_, substs)
 +                | TyKind::FnDef(_, substs)
 +                | TyKind::Closure(_, substs) => {
 +                    substs.iter(Interner).filter_map(|a| a.ty(Interner)).any(go)
 +                }
 +
 +                TyKind::Array(_ty, len) if len.is_unknown() => true,
 +                TyKind::Array(ty, _)
 +                | TyKind::Slice(ty)
 +                | TyKind::Raw(_, ty)
 +                | TyKind::Ref(_, _, ty) => go(ty),
 +
 +                TyKind::Scalar(_)
 +                | TyKind::Str
 +                | TyKind::Never
 +                | TyKind::Placeholder(_)
 +                | TyKind::BoundVar(_)
 +                | TyKind::InferenceVar(_, _)
 +                | TyKind::Dyn(_)
 +                | TyKind::Function(_)
 +                | TyKind::Alias(_)
 +                | TyKind::Foreign(_)
 +                | TyKind::Generator(..)
 +                | TyKind::GeneratorWitness(..) => false,
 +            }
 +        }
 +    }
 +
 +    pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
 +        let (variant_id, substs) = match self.ty.kind(Interner) {
 +            TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), substs) => ((*s).into(), substs),
 +            TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), substs) => ((*u).into(), substs),
 +            _ => return Vec::new(),
 +        };
 +
 +        db.field_types(variant_id)
 +            .iter()
 +            .map(|(local_id, ty)| {
 +                let def = Field { parent: variant_id.into(), id: local_id };
 +                let ty = ty.clone().substitute(Interner, substs);
 +                (def, self.derived(ty))
 +            })
 +            .collect()
 +    }
 +
 +    pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> {
 +        if let TyKind::Tuple(_, substs) = &self.ty.kind(Interner) {
 +            substs
 +                .iter(Interner)
 +                .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone()))
 +                .collect()
 +        } else {
 +            Vec::new()
 +        }
 +    }
 +
 +    pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
 +        self.autoderef_(db).map(move |ty| self.derived(ty))
 +    }
 +
 +    fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a {
 +        // There should be no inference vars in types passed here
 +        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 +        let environment = self.env.clone();
 +        autoderef(db, environment, canonical).map(|canonical| canonical.value)
 +    }
 +
 +    // This would be nicer if it just returned an iterator, but that runs into
 +    // lifetime problems, because we need to borrow temp `CrateImplDefs`.
 +    pub fn iterate_assoc_items<T>(
 +        &self,
 +        db: &dyn HirDatabase,
 +        krate: Crate,
 +        mut callback: impl FnMut(AssocItem) -> Option<T>,
 +    ) -> Option<T> {
 +        let mut slot = None;
 +        self.iterate_assoc_items_dyn(db, krate, &mut |assoc_item_id| {
 +            slot = callback(assoc_item_id.into());
 +            slot.is_some()
 +        });
 +        slot
 +    }
 +
 +    fn iterate_assoc_items_dyn(
 +        &self,
 +        db: &dyn HirDatabase,
 +        krate: Crate,
 +        callback: &mut dyn FnMut(AssocItemId) -> bool,
 +    ) {
 +        let def_crates = match method_resolution::def_crates(db, &self.ty, krate.id) {
 +            Some(it) => it,
 +            None => return,
 +        };
 +        for krate in def_crates {
 +            let impls = db.inherent_impls_in_crate(krate);
 +
 +            for impl_def in impls.for_self_ty(&self.ty) {
 +                for &item in db.impl_data(*impl_def).items.iter() {
 +                    if callback(item) {
 +                        return;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    pub fn type_arguments(&self) -> impl Iterator<Item = Type> + '_ {
 +        self.ty
 +            .strip_references()
 +            .as_adt()
 +            .into_iter()
 +            .flat_map(|(_, substs)| substs.iter(Interner))
 +            .filter_map(|arg| arg.ty(Interner).cloned())
 +            .map(move |ty| self.derived(ty))
 +    }
 +
 +    pub fn iterate_method_candidates<T>(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        // FIXME this can be retrieved from `scope`, except autoimport uses this
 +        // to specify a different set, so the method needs to be split
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        mut callback: impl FnMut(Function) -> Option<T>,
 +    ) -> Option<T> {
 +        let _p = profile::span("iterate_method_candidates");
 +        let mut slot = None;
 +
 +        self.iterate_method_candidates_dyn(
 +            db,
 +            scope,
 +            traits_in_scope,
 +            with_local_impls,
 +            name,
 +            &mut |assoc_item_id| {
 +                if let AssocItemId::FunctionId(func) = assoc_item_id {
 +                    if let Some(res) = callback(func.into()) {
 +                        slot = Some(res);
 +                        return ControlFlow::Break(());
 +                    }
 +                }
 +                ControlFlow::Continue(())
 +            },
 +        );
 +        slot
 +    }
 +
 +    fn iterate_method_candidates_dyn(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
 +    ) {
 +        // There should be no inference vars in types passed here
 +        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 +
 +        let krate = scope.krate();
 +        let environment = scope.resolver().generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(krate.id)),
 +            |d| db.trait_environment(d),
 +        );
 +
 +        method_resolution::iterate_method_candidates_dyn(
 +            &canonical,
 +            db,
 +            environment,
 +            traits_in_scope,
 +            with_local_impls.and_then(|b| b.id.containing_block()).into(),
 +            name,
 +            method_resolution::LookupMode::MethodCall,
 +            &mut |_adj, id| callback(id),
 +        );
 +    }
 +
 +    pub fn iterate_path_candidates<T>(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        mut callback: impl FnMut(AssocItem) -> Option<T>,
 +    ) -> Option<T> {
 +        let _p = profile::span("iterate_path_candidates");
 +        let mut slot = None;
 +        self.iterate_path_candidates_dyn(
 +            db,
 +            scope,
 +            traits_in_scope,
 +            with_local_impls,
 +            name,
 +            &mut |assoc_item_id| {
 +                if let Some(res) = callback(assoc_item_id.into()) {
 +                    slot = Some(res);
 +                    return ControlFlow::Break(());
 +                }
 +                ControlFlow::Continue(())
 +            },
 +        );
 +        slot
 +    }
 +
 +    fn iterate_path_candidates_dyn(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
 +    ) {
 +        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 +
 +        let krate = scope.krate();
 +        let environment = scope.resolver().generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(krate.id)),
 +            |d| db.trait_environment(d),
 +        );
 +
 +        method_resolution::iterate_path_candidates(
 +            &canonical,
 +            db,
 +            environment,
 +            traits_in_scope,
 +            with_local_impls.and_then(|b| b.id.containing_block()).into(),
 +            name,
 +            &mut |id| callback(id),
 +        );
 +    }
 +
 +    pub fn as_adt(&self) -> Option<Adt> {
 +        let (adt, _subst) = self.ty.as_adt()?;
 +        Some(adt.into())
 +    }
 +
 +    pub fn as_builtin(&self) -> Option<BuiltinType> {
 +        self.ty.as_builtin().map(|inner| BuiltinType { inner })
 +    }
 +
 +    pub fn as_dyn_trait(&self) -> Option<Trait> {
 +        self.ty.dyn_trait().map(Into::into)
 +    }
 +
 +    /// If a type can be represented as `dyn Trait`, returns all traits accessible via this type,
 +    /// or an empty iterator otherwise.
 +    pub fn applicable_inherent_traits<'a>(
 +        &'a self,
 +        db: &'a dyn HirDatabase,
 +    ) -> impl Iterator<Item = Trait> + 'a {
 +        let _p = profile::span("applicable_inherent_traits");
 +        self.autoderef_(db)
 +            .filter_map(|ty| ty.dyn_trait())
 +            .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id))
 +            .map(Trait::from)
 +    }
 +
 +    pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Trait> + 'a {
 +        let _p = profile::span("env_traits");
 +        self.autoderef_(db)
 +            .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_)))
 +            .flat_map(|ty| {
 +                self.env
 +                    .traits_in_scope_from_clauses(ty)
 +                    .flat_map(|t| hir_ty::all_super_traits(db.upcast(), t))
 +            })
 +            .map(Trait::from)
 +    }
 +
 +    pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<impl Iterator<Item = Trait>> {
 +        self.ty.impl_trait_bounds(db).map(|it| {
 +            it.into_iter().filter_map(|pred| match pred.skip_binders() {
 +                hir_ty::WhereClause::Implemented(trait_ref) => {
 +                    Some(Trait::from(trait_ref.hir_trait_id()))
 +                }
 +                _ => None,
 +            })
 +        })
 +    }
 +
 +    pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> {
 +        self.ty.associated_type_parent_trait(db).map(Into::into)
 +    }
 +
 +    fn derived(&self, ty: Ty) -> Type {
 +        Type { env: self.env.clone(), ty }
 +    }
 +
 +    pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) {
 +        // TypeWalk::walk for a Ty at first visits parameters and only after that the Ty itself.
 +        // We need a different order here.
 +
 +        fn walk_substs(
 +            db: &dyn HirDatabase,
 +            type_: &Type,
 +            substs: &Substitution,
 +            cb: &mut impl FnMut(Type),
 +        ) {
 +            for ty in substs.iter(Interner).filter_map(|a| a.ty(Interner)) {
 +                walk_type(db, &type_.derived(ty.clone()), cb);
 +            }
 +        }
 +
 +        fn walk_bounds(
 +            db: &dyn HirDatabase,
 +            type_: &Type,
 +            bounds: &[QuantifiedWhereClause],
 +            cb: &mut impl FnMut(Type),
 +        ) {
 +            for pred in bounds {
 +                if let WhereClause::Implemented(trait_ref) = pred.skip_binders() {
 +                    cb(type_.clone());
 +                    // skip the self type. it's likely the type we just got the bounds from
 +                    for ty in
 +                        trait_ref.substitution.iter(Interner).skip(1).filter_map(|a| a.ty(Interner))
 +                    {
 +                        walk_type(db, &type_.derived(ty.clone()), cb);
 +                    }
 +                }
 +            }
 +        }
 +
 +        fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
 +            let ty = type_.ty.strip_references();
 +            match ty.kind(Interner) {
 +                TyKind::Adt(_, substs) => {
 +                    cb(type_.derived(ty.clone()));
 +                    walk_substs(db, type_, substs, cb);
 +                }
 +                TyKind::AssociatedType(_, substs) => {
 +                    if ty.associated_type_parent_trait(db).is_some() {
 +                        cb(type_.derived(ty.clone()));
 +                    }
 +                    walk_substs(db, type_, substs, cb);
 +                }
 +                TyKind::OpaqueType(_, subst) => {
 +                    if let Some(bounds) = ty.impl_trait_bounds(db) {
 +                        walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
 +                    }
 +
 +                    walk_substs(db, type_, subst, cb);
 +                }
 +                TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
 +                    if let Some(bounds) = ty.impl_trait_bounds(db) {
 +                        walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
 +                    }
 +
 +                    walk_substs(db, type_, &opaque_ty.substitution, cb);
 +                }
 +                TyKind::Placeholder(_) => {
 +                    if let Some(bounds) = ty.impl_trait_bounds(db) {
 +                        walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
 +                    }
 +                }
 +                TyKind::Dyn(bounds) => {
 +                    walk_bounds(
 +                        db,
 +                        &type_.derived(ty.clone()),
 +                        bounds.bounds.skip_binders().interned(),
 +                        cb,
 +                    );
 +                }
 +
 +                TyKind::Ref(_, _, ty)
 +                | TyKind::Raw(_, ty)
 +                | TyKind::Array(ty, _)
 +                | TyKind::Slice(ty) => {
 +                    walk_type(db, &type_.derived(ty.clone()), cb);
 +                }
 +
 +                TyKind::FnDef(_, substs)
 +                | TyKind::Tuple(_, substs)
 +                | TyKind::Closure(.., substs) => {
 +                    walk_substs(db, type_, substs, cb);
 +                }
 +                TyKind::Function(hir_ty::FnPointer { substitution, .. }) => {
 +                    walk_substs(db, type_, &substitution.0, cb);
 +                }
 +
 +                _ => {}
 +            }
 +        }
 +
 +        walk_type(db, self, &mut cb);
 +    }
 +
 +    pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
 +        let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
 +        hir_ty::could_unify(db, self.env.clone(), &tys)
 +    }
 +
 +    pub fn could_coerce_to(&self, db: &dyn HirDatabase, to: &Type) -> bool {
 +        let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), to.ty.clone()));
 +        hir_ty::could_coerce(db, self.env.clone(), &tys)
 +    }
 +
 +    pub fn as_type_param(&self, db: &dyn HirDatabase) -> Option<TypeParam> {
 +        match self.ty.kind(Interner) {
 +            TyKind::Placeholder(p) => Some(TypeParam {
 +                id: TypeParamId::from_unchecked(hir_ty::from_placeholder_idx(db, *p)),
 +            }),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub struct Callable {
 +    ty: Type,
 +    sig: CallableSig,
 +    callee: Callee,
 +    pub(crate) is_bound_method: bool,
 +}
 +
 +#[derive(Debug)]
 +enum Callee {
 +    Def(CallableDefId),
 +    Closure(ClosureId),
 +    FnPtr,
 +}
 +
 +pub enum CallableKind {
 +    Function(Function),
 +    TupleStruct(Struct),
 +    TupleEnumVariant(Variant),
 +    Closure,
 +    FnPtr,
 +}
 +
 +impl Callable {
 +    pub fn kind(&self) -> CallableKind {
 +        use Callee::*;
 +        match self.callee {
 +            Def(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()),
 +            Def(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()),
 +            Def(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()),
 +            Closure(_) => CallableKind::Closure,
 +            FnPtr => CallableKind::FnPtr,
 +        }
 +    }
 +    pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> {
 +        let func = match self.callee {
 +            Callee::Def(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
 +            _ => return None,
 +        };
 +        let src = func.lookup(db.upcast()).source(db.upcast());
 +        let param_list = src.value.param_list()?;
 +        param_list.self_param()
 +    }
 +    pub fn n_params(&self) -> usize {
 +        self.sig.params().len() - if self.is_bound_method { 1 } else { 0 }
 +    }
 +    pub fn params(
 +        &self,
 +        db: &dyn HirDatabase,
 +    ) -> Vec<(Option<Either<ast::SelfParam, ast::Pat>>, Type)> {
 +        let types = self
 +            .sig
 +            .params()
 +            .iter()
 +            .skip(if self.is_bound_method { 1 } else { 0 })
 +            .map(|ty| self.ty.derived(ty.clone()));
 +        let map_param = |it: ast::Param| it.pat().map(Either::Right);
 +        let patterns = match self.callee {
 +            Callee::Def(CallableDefId::FunctionId(func)) => {
 +                let src = func.lookup(db.upcast()).source(db.upcast());
 +                src.value.param_list().map(|param_list| {
 +                    param_list
 +                        .self_param()
 +                        .map(|it| Some(Either::Left(it)))
 +                        .filter(|_| !self.is_bound_method)
 +                        .into_iter()
 +                        .chain(param_list.params().map(map_param))
 +                })
 +            }
 +            Callee::Closure(closure_id) => match closure_source(db, closure_id) {
 +                Some(src) => src.param_list().map(|param_list| {
 +                    param_list
 +                        .self_param()
 +                        .map(|it| Some(Either::Left(it)))
 +                        .filter(|_| !self.is_bound_method)
 +                        .into_iter()
 +                        .chain(param_list.params().map(map_param))
 +                }),
 +                None => None,
 +            },
 +            _ => None,
 +        };
 +        patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect()
 +    }
 +    pub fn return_type(&self) -> Type {
 +        self.ty.derived(self.sig.ret().clone())
 +    }
 +}
 +
 +fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option<ast::ClosureExpr> {
 +    let (owner, expr_id) = db.lookup_intern_closure(closure.into());
 +    let (_, source_map) = db.body_with_source_map(owner);
 +    let ast = source_map.expr_syntax(expr_id).ok()?;
 +    let root = ast.file_syntax(db.upcast());
 +    let expr = ast.value.to_node(&root);
 +    match expr {
 +        ast::Expr::ClosureExpr(it) => Some(it),
 +        _ => None,
 +    }
 +}
 +
 +#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 +pub enum BindingMode {
 +    Move,
 +    Ref(Mutability),
 +}
 +
 +/// For IDE only
 +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 +pub enum ScopeDef {
 +    ModuleDef(ModuleDef),
 +    GenericParam(GenericParam),
 +    ImplSelfType(Impl),
 +    AdtSelfType(Adt),
 +    Local(Local),
 +    Label(Label),
 +    Unknown,
 +}
 +
 +impl ScopeDef {
 +    pub fn all_items(def: PerNs) -> ArrayVec<Self, 3> {
 +        let mut items = ArrayVec::new();
 +
 +        match (def.take_types(), def.take_values()) {
 +            (Some(m1), None) => items.push(ScopeDef::ModuleDef(m1.into())),
 +            (None, Some(m2)) => items.push(ScopeDef::ModuleDef(m2.into())),
 +            (Some(m1), Some(m2)) => {
 +                // Some items, like unit structs and enum variants, are
 +                // returned as both a type and a value. Here we want
 +                // to de-duplicate them.
 +                if m1 != m2 {
 +                    items.push(ScopeDef::ModuleDef(m1.into()));
 +                    items.push(ScopeDef::ModuleDef(m2.into()));
 +                } else {
 +                    items.push(ScopeDef::ModuleDef(m1.into()));
 +                }
 +            }
 +            (None, None) => {}
 +        };
 +
 +        if let Some(macro_def_id) = def.take_macros() {
 +            items.push(ScopeDef::ModuleDef(ModuleDef::Macro(macro_def_id.into())));
 +        }
 +
 +        if items.is_empty() {
 +            items.push(ScopeDef::Unknown);
 +        }
 +
 +        items
 +    }
 +
 +    pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
 +        match self {
 +            ScopeDef::ModuleDef(it) => it.attrs(db),
 +            ScopeDef::GenericParam(it) => Some(it.attrs(db)),
 +            ScopeDef::ImplSelfType(_)
 +            | ScopeDef::AdtSelfType(_)
 +            | ScopeDef::Local(_)
 +            | ScopeDef::Label(_)
 +            | ScopeDef::Unknown => None,
 +        }
 +    }
 +
 +    pub fn krate(&self, db: &dyn HirDatabase) -> Option<Crate> {
 +        match self {
 +            ScopeDef::ModuleDef(it) => it.module(db).map(|m| m.krate()),
 +            ScopeDef::GenericParam(it) => Some(it.module(db).krate()),
 +            ScopeDef::ImplSelfType(_) => None,
 +            ScopeDef::AdtSelfType(it) => Some(it.module(db).krate()),
 +            ScopeDef::Local(it) => Some(it.module(db).krate()),
 +            ScopeDef::Label(it) => Some(it.module(db).krate()),
 +            ScopeDef::Unknown => None,
 +        }
 +    }
 +}
 +
 +impl From<ItemInNs> for ScopeDef {
 +    fn from(item: ItemInNs) -> Self {
 +        match item {
 +            ItemInNs::Types(id) => ScopeDef::ModuleDef(id),
 +            ItemInNs::Values(id) => ScopeDef::ModuleDef(id),
 +            ItemInNs::Macros(id) => ScopeDef::ModuleDef(ModuleDef::Macro(id)),
 +        }
 +    }
 +}
 +
 +pub trait HasVisibility {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility;
 +    fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool {
 +        let vis = self.visibility(db);
 +        vis.is_visible_from(db.upcast(), module.id)
 +    }
 +}
 +
 +/// Trait for obtaining the defining crate of an item.
 +pub trait HasCrate {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate;
 +}
 +
 +impl<T: hir_def::HasModule> HasCrate for T {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db.upcast()).krate().into()
 +    }
 +}
 +
 +impl HasCrate for AssocItem {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Struct {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Union {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Field {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.parent_def(db).module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Variant {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Function {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Const {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for TypeAlias {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Type {
 +    fn krate(&self, _db: &dyn HirDatabase) -> Crate {
 +        self.env.krate.into()
 +    }
 +}
 +
 +impl HasCrate for Macro {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Trait {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Static {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Adt {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Module {
 +    fn krate(&self, _: &dyn HirDatabase) -> Crate {
 +        Module::krate(*self)
 +    }
 +}
index eaa6de73eb35d4bc0ec6ffafb1ba464e29d4507b,0000000000000000000000000000000000000000..ccdfcb0d9e4fd14767a23c1b9baf27c61b36857e
mode 100644,000000..100644
--- /dev/null
@@@ -1,255 -1,0 +1,255 @@@
-                 (statement.syntax().text_range().start(), indent, None, format!("\n{}", indent))
 +use crate::assist_context::{AssistContext, Assists};
 +use hir::{HasVisibility, HirDisplay, Module};
 +use ide_db::{
 +    assists::{AssistId, AssistKind},
 +    base_db::{FileId, Upcast},
 +    defs::{Definition, NameRefClass},
 +};
 +use syntax::{
 +    ast::{self, edit::IndentLevel, NameRef},
 +    AstNode, Direction, SyntaxKind, TextSize,
 +};
 +
 +// Assist: generate_constant
 +//
 +// Generate a named constant.
 +//
 +// ```
 +// struct S { i: usize }
 +// impl S { pub fn new(n: usize) {} }
 +// fn main() {
 +//     let v = S::new(CAPA$0CITY);
 +// }
 +// ```
 +// ->
 +// ```
 +// struct S { i: usize }
 +// impl S { pub fn new(n: usize) {} }
 +// fn main() {
 +//     const CAPACITY: usize = $0;
 +//     let v = S::new(CAPACITY);
 +// }
 +// ```
 +
 +pub(crate) fn generate_constant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let constant_token = ctx.find_node_at_offset::<ast::NameRef>()?;
 +    if constant_token.to_string().chars().any(|it| !(it.is_uppercase() || it == '_')) {
 +        cov_mark::hit!(not_constant_name);
 +        return None;
 +    }
 +    if NameRefClass::classify(&ctx.sema, &constant_token).is_some() {
 +        cov_mark::hit!(already_defined);
 +        return None;
 +    }
 +    let expr = constant_token.syntax().ancestors().find_map(ast::Expr::cast)?;
 +    let statement = expr.syntax().ancestors().find_map(ast::Stmt::cast)?;
 +    let ty = ctx.sema.type_of_expr(&expr)?;
 +    let scope = ctx.sema.scope(statement.syntax())?;
 +    let constant_module = scope.module();
 +    let type_name = ty.original().display_source_code(ctx.db(), constant_module.into()).ok()?;
 +    let target = statement.syntax().parent()?.text_range();
 +    let path = constant_token.syntax().ancestors().find_map(ast::Path::cast)?;
 +
 +    let name_refs = path.segments().map(|s| s.name_ref());
 +    let mut outer_exists = false;
 +    let mut not_exist_name_ref = Vec::new();
 +    let mut current_module = constant_module;
 +    for name_ref in name_refs {
 +        let name_ref_value = name_ref?;
 +        let name_ref_class = NameRefClass::classify(&ctx.sema, &name_ref_value);
 +        match name_ref_class {
 +            Some(NameRefClass::Definition(Definition::Module(m))) => {
 +                if !m.visibility(ctx.sema.db).is_visible_from(ctx.sema.db, constant_module.into()) {
 +                    return None;
 +                }
 +                outer_exists = true;
 +                current_module = m;
 +            }
 +            Some(_) => {
 +                return None;
 +            }
 +            None => {
 +                not_exist_name_ref.push(name_ref_value);
 +            }
 +        }
 +    }
 +    let (offset, indent, file_id, post_string) =
 +        target_data_for_generate_constant(ctx, current_module, constant_module).unwrap_or_else(
 +            || {
 +                let indent = IndentLevel::from_node(statement.syntax());
-             builder.insert(offset, format!("{}{}", text, post_string));
++                (statement.syntax().text_range().start(), indent, None, format!("\n{indent}"))
 +            },
 +        );
 +
 +    let text = get_text_for_generate_constant(not_exist_name_ref, indent, outer_exists, type_name)?;
 +    acc.add(
 +        AssistId("generate_constant", AssistKind::QuickFix),
 +        "Generate constant",
 +        target,
 +        |builder| {
 +            if let Some(file_id) = file_id {
 +                builder.edit_file(file_id);
 +            }
-     let mut text = format!("{}const {}: {} = $0;", vis, constant_token, type_name);
++            builder.insert(offset, format!("{text}{post_string}"));
 +        },
 +    )
 +}
 +
 +fn get_text_for_generate_constant(
 +    mut not_exist_name_ref: Vec<NameRef>,
 +    indent: IndentLevel,
 +    outer_exists: bool,
 +    type_name: String,
 +) -> Option<String> {
 +    let constant_token = not_exist_name_ref.pop()?;
 +    let vis = if not_exist_name_ref.len() == 0 && !outer_exists { "" } else { "\npub " };
-         text = format!("{}mod {} {{{}\n}}", vis, name_ref.to_string(), text);
++    let mut text = format!("{vis}const {constant_token}: {type_name} = $0;");
 +    while let Some(name_ref) = not_exist_name_ref.pop() {
 +        let vis = if not_exist_name_ref.len() == 0 && !outer_exists { "" } else { "\npub " };
 +        text = text.replace("\n", "\n    ");
-     Some(text.replace("\n", &format!("\n{}", indent)))
++        text = format!("{vis}mod {name_ref} {{{text}\n}}");
 +    }
-                 if siblings_has_newline { format!("{}", indent) } else { format!("\n{}", indent) };
++    Some(text.replace("\n", &format!("\n{indent}")))
 +}
 +
 +fn target_data_for_generate_constant(
 +    ctx: &AssistContext<'_>,
 +    current_module: Module,
 +    constant_module: Module,
 +) -> Option<(TextSize, IndentLevel, Option<FileId>, String)> {
 +    if current_module == constant_module {
 +        // insert in current file
 +        return None;
 +    }
 +    let in_file_source = current_module.definition_source(ctx.sema.db);
 +    let file_id = in_file_source.file_id.original_file(ctx.sema.db.upcast());
 +    match in_file_source.value {
 +        hir::ModuleSource::Module(module_node) => {
 +            let indent = IndentLevel::from_node(module_node.syntax());
 +            let l_curly_token = module_node.item_list()?.l_curly_token()?;
 +            let offset = l_curly_token.text_range().end();
 +
 +            let siblings_has_newline = l_curly_token
 +                .siblings_with_tokens(Direction::Next)
 +                .find(|it| it.kind() == SyntaxKind::WHITESPACE && it.to_string().contains("\n"))
 +                .is_some();
 +            let post_string =
++                if siblings_has_newline { format!("{indent}") } else { format!("\n{indent}") };
 +            Some((offset, indent + 1, Some(file_id), post_string))
 +        }
 +        _ => Some((TextSize::from(0), 0.into(), Some(file_id), "\n".into())),
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use super::*;
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    #[test]
 +    fn test_trivial() {
 +        check_assist(
 +            generate_constant,
 +            r#"struct S { i: usize }
 +impl S {
 +    pub fn new(n: usize) {}
 +}
 +fn main() {
 +    let v = S::new(CAPA$0CITY);
 +}"#,
 +            r#"struct S { i: usize }
 +impl S {
 +    pub fn new(n: usize) {}
 +}
 +fn main() {
 +    const CAPACITY: usize = $0;
 +    let v = S::new(CAPACITY);
 +}"#,
 +        );
 +    }
 +    #[test]
 +    fn test_wont_apply_when_defined() {
 +        cov_mark::check!(already_defined);
 +        check_assist_not_applicable(
 +            generate_constant,
 +            r#"struct S { i: usize }
 +impl S {
 +    pub fn new(n: usize) {}
 +}
 +fn main() {
 +    const CAPACITY: usize = 10;
 +    let v = S::new(CAPAC$0ITY);
 +}"#,
 +        );
 +    }
 +    #[test]
 +    fn test_wont_apply_when_maybe_not_constant() {
 +        cov_mark::check!(not_constant_name);
 +        check_assist_not_applicable(
 +            generate_constant,
 +            r#"struct S { i: usize }
 +impl S {
 +    pub fn new(n: usize) {}
 +}
 +fn main() {
 +    let v = S::new(capa$0city);
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_constant_with_path() {
 +        check_assist(
 +            generate_constant,
 +            r#"mod foo {}
 +fn bar() -> i32 {
 +    foo::A_CON$0STANT
 +}"#,
 +            r#"mod foo {
 +    pub const A_CONSTANT: i32 = $0;
 +}
 +fn bar() -> i32 {
 +    foo::A_CONSTANT
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_constant_with_longer_path() {
 +        check_assist(
 +            generate_constant,
 +            r#"mod foo {
 +    pub mod goo {}
 +}
 +fn bar() -> i32 {
 +    foo::goo::A_CON$0STANT
 +}"#,
 +            r#"mod foo {
 +    pub mod goo {
 +        pub const A_CONSTANT: i32 = $0;
 +    }
 +}
 +fn bar() -> i32 {
 +    foo::goo::A_CONSTANT
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_constant_with_not_exist_longer_path() {
 +        check_assist(
 +            generate_constant,
 +            r#"fn bar() -> i32 {
 +    foo::goo::A_CON$0STANT
 +}"#,
 +            r#"mod foo {
 +    pub mod goo {
 +        pub const A_CONSTANT: i32 = $0;
 +    }
 +}
 +fn bar() -> i32 {
 +    foo::goo::A_CONSTANT
 +}"#,
 +        );
 +    }
 +}
index 5e9995a9866445ec96dca5a9991440551119f169,0000000000000000000000000000000000000000..a6e3d49e0d1ae59b95fda24da8fa82559bf3aaa1
mode 100644,000000..100644
--- /dev/null
@@@ -1,179 -1,0 +1,178 @@@
- impl Default for {0} {{
 +use ide_db::{famous_defs::FamousDefs, RootDatabase};
 +use syntax::ast::{self, AstNode, HasName};
 +
 +use crate::{AssistContext, AssistId, AssistKind, Assists};
 +
 +// Assist: generate_default_from_enum_variant
 +//
 +// Adds a Default impl for an enum using a variant.
 +//
 +// ```
 +// enum Version {
 +//  Undefined,
 +//  Minor$0,
 +//  Major,
 +// }
 +// ```
 +// ->
 +// ```
 +// enum Version {
 +//  Undefined,
 +//  Minor,
 +//  Major,
 +// }
 +//
 +// impl Default for Version {
 +//     fn default() -> Self {
 +//         Self::Minor
 +//     }
 +// }
 +// ```
 +pub(crate) fn generate_default_from_enum_variant(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +) -> Option<()> {
 +    let variant = ctx.find_node_at_offset::<ast::Variant>()?;
 +    let variant_name = variant.name()?;
 +    let enum_name = variant.parent_enum().name()?;
 +    if !matches!(variant.kind(), ast::StructKind::Unit) {
 +        cov_mark::hit!(test_gen_default_on_non_unit_variant_not_implemented);
 +        return None;
 +    }
 +
 +    if existing_default_impl(&ctx.sema, &variant).is_some() {
 +        cov_mark::hit!(test_gen_default_impl_already_exists);
 +        return None;
 +    }
 +
 +    let target = variant.syntax().text_range();
 +    acc.add(
 +        AssistId("generate_default_from_enum_variant", AssistKind::Generate),
 +        "Generate `Default` impl from this enum variant",
 +        target,
 +        |edit| {
 +            let start_offset = variant.parent_enum().syntax().text_range().end();
 +            let buf = format!(
 +                r#"
 +
-         Self::{1}
++impl Default for {enum_name} {{
 +    fn default() -> Self {{
-                 enum_name, variant_name
++        Self::{variant_name}
 +    }}
 +}}"#,
 +            );
 +            edit.insert(start_offset, buf);
 +        },
 +    )
 +}
 +
 +fn existing_default_impl(
 +    sema: &'_ hir::Semantics<'_, RootDatabase>,
 +    variant: &ast::Variant,
 +) -> Option<()> {
 +    let variant = sema.to_def(variant)?;
 +    let enum_ = variant.parent_enum(sema.db);
 +    let krate = enum_.module(sema.db).krate();
 +
 +    let default_trait = FamousDefs(sema, krate).core_default_Default()?;
 +    let enum_type = enum_.ty(sema.db);
 +
 +    if enum_type.impls_trait(sema.db, default_trait, &[]) {
 +        Some(())
 +    } else {
 +        None
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_generate_default_from_variant() {
 +        check_assist(
 +            generate_default_from_enum_variant,
 +            r#"
 +//- minicore: default
 +enum Variant {
 +    Undefined,
 +    Minor$0,
 +    Major,
 +}
 +"#,
 +            r#"
 +enum Variant {
 +    Undefined,
 +    Minor,
 +    Major,
 +}
 +
 +impl Default for Variant {
 +    fn default() -> Self {
 +        Self::Minor
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_default_already_implemented() {
 +        cov_mark::check!(test_gen_default_impl_already_exists);
 +        check_assist_not_applicable(
 +            generate_default_from_enum_variant,
 +            r#"
 +//- minicore: default
 +enum Variant {
 +    Undefined,
 +    Minor$0,
 +    Major,
 +}
 +
 +impl Default for Variant {
 +    fn default() -> Self {
 +        Self::Minor
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_add_from_impl_no_element() {
 +        cov_mark::check!(test_gen_default_on_non_unit_variant_not_implemented);
 +        check_assist_not_applicable(
 +            generate_default_from_enum_variant,
 +            r#"
 +//- minicore: default
 +enum Variant {
 +    Undefined,
 +    Minor(u32)$0,
 +    Major,
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_default_from_variant_with_one_variant() {
 +        check_assist(
 +            generate_default_from_enum_variant,
 +            r#"
 +//- minicore: default
 +enum Variant { Undefi$0ned }
 +"#,
 +            r#"
 +enum Variant { Undefined }
 +
 +impl Default for Variant {
 +    fn default() -> Self {
 +        Self::Undefined
 +    }
 +}
 +"#,
 +        );
 +    }
 +}
index cbd33de19eda0c047675d36cb966e4133d14158a,0000000000000000000000000000000000000000..49d9fd707ffccc234436efd8da912ed5c5a52c06
mode 100644,000000..100644
--- /dev/null
@@@ -1,657 -1,0 +1,658 @@@
- use itertools::Itertools;
 +use ide_db::famous_defs::FamousDefs;
-     ast::{self, HasGenericParams, HasName, HasTypeBounds, Impl},
 +use stdx::format_to;
 +use syntax::{
-     let generic_params = impl_.generic_param_list();
-     let mut buf = String::with_capacity(code.len());
-     buf.push_str("\n\n");
-     buf.push_str("impl");
-     if let Some(generic_params) = &generic_params {
-         let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
-         let toc_params = generic_params.type_or_const_params().map(|toc_param| match toc_param {
-             ast::TypeOrConstParam::Type(type_param) => {
-                 let mut buf = String::new();
-                 if let Some(it) = type_param.name() {
-                     format_to!(buf, "{}", it.syntax());
-                 }
-                 if let Some(it) = type_param.colon_token() {
-                     format_to!(buf, "{} ", it);
++    ast::{self, make, HasGenericParams, HasName, Impl},
 +    AstNode,
 +};
 +
 +use crate::{
 +    assist_context::{AssistContext, Assists},
 +    AssistId,
 +};
 +
 +// Assist: generate_default_from_new
 +//
 +// Generates default implementation from new method.
 +//
 +// ```
 +// struct Example { _inner: () }
 +//
 +// impl Example {
 +//     pub fn n$0ew() -> Self {
 +//         Self { _inner: () }
 +//     }
 +// }
 +// ```
 +// ->
 +// ```
 +// struct Example { _inner: () }
 +//
 +// impl Example {
 +//     pub fn new() -> Self {
 +//         Self { _inner: () }
 +//     }
 +// }
 +//
 +// impl Default for Example {
 +//     fn default() -> Self {
 +//         Self::new()
 +//     }
 +// }
 +// ```
 +pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let fn_node = ctx.find_node_at_offset::<ast::Fn>()?;
 +    let fn_name = fn_node.name()?;
 +
 +    if fn_name.text() != "new" {
 +        cov_mark::hit!(other_function_than_new);
 +        return None;
 +    }
 +
 +    if fn_node.param_list()?.params().next().is_some() {
 +        cov_mark::hit!(new_function_with_parameters);
 +        return None;
 +    }
 +
 +    let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?;
 +    if is_default_implemented(ctx, &impl_) {
 +        cov_mark::hit!(default_block_is_already_present);
 +        cov_mark::hit!(struct_in_module_with_default);
 +        return None;
 +    }
 +
 +    let insert_location = impl_.syntax().text_range();
 +
 +    acc.add(
 +        AssistId("generate_default_from_new", crate::AssistKind::Generate),
 +        "Generate a Default impl from a new fn",
 +        insert_location,
 +        move |builder| {
 +            let default_code = "    fn default() -> Self {
 +        Self::new()
 +    }";
 +            let code = generate_trait_impl_text_from_impl(&impl_, "Default", default_code);
 +            builder.insert(insert_location.end(), code);
 +        },
 +    )
 +}
 +
++// FIXME: based on from utils::generate_impl_text_inner
 +fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code: &str) -> String {
-                 if let Some(it) = type_param.type_bound_list() {
-                     format_to!(buf, "{}", it.syntax());
++    let impl_ty = impl_.self_ty().unwrap();
++    let generic_params = impl_.generic_param_list().map(|generic_params| {
++        let lifetime_params =
++            generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
++        let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| {
++            // remove defaults since they can't be specified in impls
++            match param {
++                ast::TypeOrConstParam::Type(param) => {
++                    let param = param.clone_for_update();
++                    param.remove_default();
++                    Some(ast::GenericParam::TypeParam(param))
 +                }
-                 buf
++                ast::TypeOrConstParam::Const(param) => {
++                    let param = param.clone_for_update();
++                    param.remove_default();
++                    Some(ast::GenericParam::ConstParam(param))
 +                }
-             ast::TypeOrConstParam::Const(const_param) => const_param.syntax().to_string(),
 +            }
-         let generics = lifetimes.chain(toc_params).format(", ");
-         format_to!(buf, "<{}>", generics);
-     }
 +        });
-     buf.push(' ');
-     buf.push_str(trait_text);
-     buf.push_str(" for ");
-     buf.push_str(&impl_.self_ty().unwrap().syntax().text().to_string());
 +
-             format_to!(buf, "\n{}\n{{\n{}\n}}", where_clause, code);
++        make::generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
++    });
++
++    let mut buf = String::with_capacity(code.len());
++    buf.push_str("\n\n");
++
++    // `impl{generic_params} {trait_text} for {impl_.self_ty()}`
++    buf.push_str("impl");
++    if let Some(generic_params) = &generic_params {
++        format_to!(buf, "{generic_params}")
++    }
++    format_to!(buf, " {trait_text} for {impl_ty}");
 +
 +    match impl_.where_clause() {
 +        Some(where_clause) => {
-             format_to!(buf, " {{\n{}\n}}", code);
++            format_to!(buf, "\n{where_clause}\n{{\n{code}\n}}");
 +        }
 +        None => {
++            format_to!(buf, " {{\n{code}\n}}");
 +        }
 +    }
 +
 +    buf
 +}
 +
 +fn is_default_implemented(ctx: &AssistContext<'_>, impl_: &Impl) -> bool {
 +    let db = ctx.sema.db;
 +    let impl_ = ctx.sema.to_def(impl_);
 +    let impl_def = match impl_ {
 +        Some(value) => value,
 +        None => return false,
 +    };
 +
 +    let ty = impl_def.self_ty(db);
 +    let krate = impl_def.module(db).krate();
 +    let default = FamousDefs(&ctx.sema, krate).core_default_Default();
 +    let default_trait = match default {
 +        Some(value) => value,
 +        None => return false,
 +    };
 +
 +    ty.impls_trait(db, default_trait, &[])
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn generate_default() {
 +        check_assist(
 +            generate_default_from_new,
 +            r#"
 +//- minicore: default
 +struct Example { _inner: () }
 +
 +impl Example {
 +    pub fn ne$0w() -> Self {
 +        Self { _inner: () }
 +    }
 +}
 +
 +fn main() {}
 +"#,
 +            r#"
 +struct Example { _inner: () }
 +
 +impl Example {
 +    pub fn new() -> Self {
 +        Self { _inner: () }
 +    }
 +}
 +
 +impl Default for Example {
 +    fn default() -> Self {
 +        Self::new()
 +    }
 +}
 +
 +fn main() {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn generate_default2() {
 +        check_assist(
 +            generate_default_from_new,
 +            r#"
 +//- minicore: default
 +struct Test { value: u32 }
 +
 +impl Test {
 +    pub fn ne$0w() -> Self {
 +        Self { value: 0 }
 +    }
 +}
 +"#,
 +            r#"
 +struct Test { value: u32 }
 +
 +impl Test {
 +    pub fn new() -> Self {
 +        Self { value: 0 }
 +    }
 +}
 +
 +impl Default for Test {
 +    fn default() -> Self {
 +        Self::new()
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn new_function_with_generic() {
 +        check_assist(
 +            generate_default_from_new,
 +            r#"
 +//- minicore: default
 +pub struct Foo<T> {
 +    _bar: *mut T,
 +}
 +
 +impl<T> Foo<T> {
 +    pub fn ne$0w() -> Self {
 +        unimplemented!()
 +    }
 +}
 +"#,
 +            r#"
 +pub struct Foo<T> {
 +    _bar: *mut T,
 +}
 +
 +impl<T> Foo<T> {
 +    pub fn new() -> Self {
 +        unimplemented!()
 +    }
 +}
 +
 +impl<T> Default for Foo<T> {
 +    fn default() -> Self {
 +        Self::new()
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn new_function_with_generics() {
 +        check_assist(
 +            generate_default_from_new,
 +            r#"
 +//- minicore: default
 +pub struct Foo<T, B> {
 +    _tars: *mut T,
 +    _bar: *mut B,
 +}
 +
 +impl<T, B> Foo<T, B> {
 +    pub fn ne$0w() -> Self {
 +        unimplemented!()
 +    }
 +}
 +"#,
 +            r#"
 +pub struct Foo<T, B> {
 +    _tars: *mut T,
 +    _bar: *mut B,
 +}
 +
 +impl<T, B> Foo<T, B> {
 +    pub fn new() -> Self {
 +        unimplemented!()
 +    }
 +}
 +
 +impl<T, B> Default for Foo<T, B> {
 +    fn default() -> Self {
 +        Self::new()
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn new_function_with_generic_and_bound() {
 +        check_assist(
 +            generate_default_from_new,
 +            r#"
 +//- minicore: default
 +pub struct Foo<T> {
 +    t: T,
 +}
 +
 +impl<T: From<i32>> Foo<T> {
 +    pub fn ne$0w() -> Self {
 +        Foo { t: 0.into() }
 +    }
 +}
 +"#,
 +            r#"
 +pub struct Foo<T> {
 +    t: T,
 +}
 +
 +impl<T: From<i32>> Foo<T> {
 +    pub fn new() -> Self {
 +        Foo { t: 0.into() }
 +    }
 +}
 +
 +impl<T: From<i32>> Default for Foo<T> {
 +    fn default() -> Self {
 +        Self::new()
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn new_function_with_generics_and_bounds() {
 +        check_assist(
 +            generate_default_from_new,
 +            r#"
 +//- minicore: default
 +pub struct Foo<T, B> {
 +    _tars: T,
 +    _bar: B,
 +}
 +
 +impl<T: From<i32>, B: From<i64>> Foo<T, B> {
 +    pub fn ne$0w() -> Self {
 +        unimplemented!()
 +    }
 +}
 +"#,
 +            r#"
 +pub struct Foo<T, B> {
 +    _tars: T,
 +    _bar: B,
 +}
 +
 +impl<T: From<i32>, B: From<i64>> Foo<T, B> {
 +    pub fn new() -> Self {
 +        unimplemented!()
 +    }
 +}
 +
 +impl<T: From<i32>, B: From<i64>> Default for Foo<T, B> {
 +    fn default() -> Self {
 +        Self::new()
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn new_function_with_generic_and_where() {
 +        check_assist(
 +            generate_default_from_new,
 +            r#"
 +//- minicore: default
 +pub struct Foo<T> {
 +    t: T,
 +}
 +
 +impl<T: From<i32>> Foo<T>
 +where
 +    Option<T>: Debug
 +{
 +    pub fn ne$0w() -> Self {
 +        Foo { t: 0.into() }
 +    }
 +}
 +"#,
 +            r#"
 +pub struct Foo<T> {
 +    t: T,
 +}
 +
 +impl<T: From<i32>> Foo<T>
 +where
 +    Option<T>: Debug
 +{
 +    pub fn new() -> Self {
 +        Foo { t: 0.into() }
 +    }
 +}
 +
 +impl<T: From<i32>> Default for Foo<T>
 +where
 +    Option<T>: Debug
 +{
 +    fn default() -> Self {
 +        Self::new()
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn new_function_with_generics_and_wheres() {
 +        check_assist(
 +            generate_default_from_new,
 +            r#"
 +//- minicore: default
 +pub struct Foo<T, B> {
 +    _tars: T,
 +    _bar: B,
 +}
 +
 +impl<T: From<i32>, B: From<i64>> Foo<T, B>
 +where
 +    Option<T>: Debug, Option<B>: Debug,
 +{
 +    pub fn ne$0w() -> Self {
 +        unimplemented!()
 +    }
 +}
 +"#,
 +            r#"
 +pub struct Foo<T, B> {
 +    _tars: T,
 +    _bar: B,
 +}
 +
 +impl<T: From<i32>, B: From<i64>> Foo<T, B>
 +where
 +    Option<T>: Debug, Option<B>: Debug,
 +{
 +    pub fn new() -> Self {
 +        unimplemented!()
 +    }
 +}
 +
 +impl<T: From<i32>, B: From<i64>> Default for Foo<T, B>
 +where
 +    Option<T>: Debug, Option<B>: Debug,
 +{
 +    fn default() -> Self {
 +        Self::new()
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn new_function_with_parameters() {
 +        cov_mark::check!(new_function_with_parameters);
 +        check_assist_not_applicable(
 +            generate_default_from_new,
 +            r#"
 +//- minicore: default
 +struct Example { _inner: () }
 +
 +impl Example {
 +    pub fn $0new(value: ()) -> Self {
 +        Self { _inner: value }
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn other_function_than_new() {
 +        cov_mark::check!(other_function_than_new);
 +        check_assist_not_applicable(
 +            generate_default_from_new,
 +            r#"
 +struct Example { _inner: () }
 +
 +impl Example {
 +    pub fn a$0dd() -> Self {
 +        Self { _inner: () }
 +    }
 +}
 +
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn default_block_is_already_present() {
 +        cov_mark::check!(default_block_is_already_present);
 +        check_assist_not_applicable(
 +            generate_default_from_new,
 +            r#"
 +//- minicore: default
 +struct Example { _inner: () }
 +
 +impl Example {
 +    pub fn n$0ew() -> Self {
 +        Self { _inner: () }
 +    }
 +}
 +
 +impl Default for Example {
 +    fn default() -> Self {
 +        Self::new()
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn standalone_new_function() {
 +        check_assist_not_applicable(
 +            generate_default_from_new,
 +            r#"
 +fn n$0ew() -> u32 {
 +    0
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn multiple_struct_blocks() {
 +        check_assist(
 +            generate_default_from_new,
 +            r#"
 +//- minicore: default
 +struct Example { _inner: () }
 +struct Test { value: u32 }
 +
 +impl Example {
 +    pub fn new$0() -> Self {
 +        Self { _inner: () }
 +    }
 +}
 +"#,
 +            r#"
 +struct Example { _inner: () }
 +struct Test { value: u32 }
 +
 +impl Example {
 +    pub fn new() -> Self {
 +        Self { _inner: () }
 +    }
 +}
 +
 +impl Default for Example {
 +    fn default() -> Self {
 +        Self::new()
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn when_struct_is_after_impl() {
 +        check_assist(
 +            generate_default_from_new,
 +            r#"
 +//- minicore: default
 +impl Example {
 +    pub fn $0new() -> Self {
 +        Self { _inner: () }
 +    }
 +}
 +
 +struct Example { _inner: () }
 +"#,
 +            r#"
 +impl Example {
 +    pub fn new() -> Self {
 +        Self { _inner: () }
 +    }
 +}
 +
 +impl Default for Example {
 +    fn default() -> Self {
 +        Self::new()
 +    }
 +}
 +
 +struct Example { _inner: () }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_in_module() {
 +        check_assist(
 +            generate_default_from_new,
 +            r#"
 +//- minicore: default
 +mod test {
 +    struct Example { _inner: () }
 +
 +    impl Example {
 +        pub fn n$0ew() -> Self {
 +            Self { _inner: () }
 +        }
 +    }
 +}
 +"#,
 +            r#"
 +mod test {
 +    struct Example { _inner: () }
 +
 +    impl Example {
 +        pub fn new() -> Self {
 +            Self { _inner: () }
 +        }
 +    }
 +
 +impl Default for Example {
 +    fn default() -> Self {
 +        Self::new()
 +    }
 +}
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_in_module_with_default() {
 +        cov_mark::check!(struct_in_module_with_default);
 +        check_assist_not_applicable(
 +            generate_default_from_new,
 +            r#"
 +//- minicore: default
 +mod test {
 +    struct Example { _inner: () }
 +
 +    impl Example {
 +        pub fn n$0ew() -> Self {
 +            Self { _inner: () }
 +        }
 +    }
 +
 +    impl Default for Example {
 +        fn default() -> Self {
 +            Self::new()
 +        }
 +    }
 +}
 +"#,
 +        );
 +    }
 +}
index 85b193663a05bc5e2798d7408d53a08500c43b93,0000000000000000000000000000000000000000..ceae80755037c00b56f401edb70c5a6264cb176e
mode 100644,000000..100644
--- /dev/null
@@@ -1,334 -1,0 +1,334 @@@
-             (format!("{}", field_name), field_ty, field.syntax().text_range())
 +use hir::{self, HasCrate, HasSource, HasVisibility};
 +use syntax::ast::{self, make, AstNode, HasGenericParams, HasName, HasVisibility as _};
 +
 +use crate::{
 +    utils::{convert_param_list_to_arg_list, find_struct_impl, render_snippet, Cursor},
 +    AssistContext, AssistId, AssistKind, Assists, GroupLabel,
 +};
 +use syntax::ast::edit::AstNodeEdit;
 +
 +// Assist: generate_delegate_methods
 +//
 +// Generate delegate methods.
 +//
 +// ```
 +// struct Age(u8);
 +// impl Age {
 +//     fn age(&self) -> u8 {
 +//         self.0
 +//     }
 +// }
 +//
 +// struct Person {
 +//     ag$0e: Age,
 +// }
 +// ```
 +// ->
 +// ```
 +// struct Age(u8);
 +// impl Age {
 +//     fn age(&self) -> u8 {
 +//         self.0
 +//     }
 +// }
 +//
 +// struct Person {
 +//     age: Age,
 +// }
 +//
 +// impl Person {
 +//     $0fn age(&self) -> u8 {
 +//         self.age.age()
 +//     }
 +// }
 +// ```
 +pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
 +    let strukt_name = strukt.name()?;
 +    let current_module = ctx.sema.scope(strukt.syntax())?.module();
 +
 +    let (field_name, field_ty, target) = match ctx.find_node_at_offset::<ast::RecordField>() {
 +        Some(field) => {
 +            let field_name = field.name()?;
 +            let field_ty = field.ty()?;
-             (format!("{}", field_list_index), field_ty, field.syntax().text_range())
++            (field_name.to_string(), field_ty, field.syntax().text_range())
 +        }
 +        None => {
 +            let field = ctx.find_node_at_offset::<ast::TupleField>()?;
 +            let field_list = ctx.find_node_at_offset::<ast::TupleFieldList>()?;
 +            let field_list_index = field_list.fields().position(|it| it == field)?;
 +            let field_ty = field.ty()?;
-         let impl_def = find_struct_impl(ctx, &adt, &name).flatten();
++            (field_list_index.to_string(), field_ty, field.syntax().text_range())
 +        }
 +    };
 +
 +    let sema_field_ty = ctx.sema.resolve_type(&field_ty)?;
 +    let krate = sema_field_ty.krate(ctx.db());
 +    let mut methods = vec![];
 +    sema_field_ty.iterate_assoc_items(ctx.db(), krate, |item| {
 +        if let hir::AssocItem::Function(f) = item {
 +            if f.self_param(ctx.db()).is_some() && f.is_visible_from(ctx.db(), current_module) {
 +                methods.push(f)
 +            }
 +        }
 +        Option::<()>::None
 +    });
 +
 +    for method in methods {
 +        let adt = ast::Adt::Struct(strukt.clone());
 +        let name = method.name(ctx.db()).to_string();
-                                 let snippet = format!("\n\n{}", snippet);
++        let impl_def = find_struct_impl(ctx, &adt, &[name]).flatten();
 +        acc.add_group(
 +            &GroupLabel("Generate delegate methods…".to_owned()),
 +            AssistId("generate_delegate_methods", AssistKind::Generate),
 +            format!("Generate delegate for `{}.{}()`", field_name, method.name(ctx.db())),
 +            target,
 +            |builder| {
 +                // Create the function
 +                let method_source = match method.source(ctx.db()) {
 +                    Some(source) => source.value,
 +                    None => return,
 +                };
 +                let method_name = method.name(ctx.db());
 +                let vis = method_source.visibility();
 +                let name = make::name(&method.name(ctx.db()).to_string());
 +                let params =
 +                    method_source.param_list().unwrap_or_else(|| make::param_list(None, []));
 +                let type_params = method_source.generic_param_list();
 +                let arg_list = match method_source.param_list() {
 +                    Some(list) => convert_param_list_to_arg_list(list),
 +                    None => make::arg_list([]),
 +                };
 +                let tail_expr = make::expr_method_call(
 +                    make::ext::field_from_idents(["self", &field_name]).unwrap(), // This unwrap is ok because we have at least 1 arg in the list
 +                    make::name_ref(&method_name.to_string()),
 +                    arg_list,
 +                );
 +                let body = make::block_expr([], Some(tail_expr));
 +                let ret_type = method_source.ret_type();
 +                let is_async = method_source.async_token().is_some();
 +                let f = make::fn_(vis, name, type_params, params, body, ret_type, is_async)
 +                    .indent(ast::edit::IndentLevel(1))
 +                    .clone_for_update();
 +
 +                let cursor = Cursor::Before(f.syntax());
 +
 +                // Create or update an impl block, attach the function to it,
 +                // then insert into our code.
 +                match impl_def {
 +                    Some(impl_def) => {
 +                        // Remember where in our source our `impl` block lives.
 +                        let impl_def = impl_def.clone_for_update();
 +                        let old_range = impl_def.syntax().text_range();
 +
 +                        // Attach the function to the impl block
 +                        let assoc_items = impl_def.get_or_create_assoc_item_list();
 +                        assoc_items.add_item(f.clone().into());
 +
 +                        // Update the impl block.
 +                        match ctx.config.snippet_cap {
 +                            Some(cap) => {
 +                                let snippet = render_snippet(cap, impl_def.syntax(), cursor);
 +                                builder.replace_snippet(cap, old_range, snippet);
 +                            }
 +                            None => {
 +                                builder.replace(old_range, impl_def.syntax().to_string());
 +                            }
 +                        }
 +                    }
 +                    None => {
 +                        // Attach the function to the impl block
 +                        let name = &strukt_name.to_string();
 +                        let params = strukt.generic_param_list();
 +                        let ty_params = params.clone();
 +                        let impl_def = make::impl_(make::ext::ident_path(name), params, ty_params)
 +                            .clone_for_update();
 +                        let assoc_items = impl_def.get_or_create_assoc_item_list();
 +                        assoc_items.add_item(f.clone().into());
 +
 +                        // Insert the impl block.
 +                        match ctx.config.snippet_cap {
 +                            Some(cap) => {
 +                                let offset = strukt.syntax().text_range().end();
 +                                let snippet = render_snippet(cap, impl_def.syntax(), cursor);
++                                let snippet = format!("\n\n{snippet}");
 +                                builder.insert_snippet(cap, offset, snippet);
 +                            }
 +                            None => {
 +                                let offset = strukt.syntax().text_range().end();
 +                                let snippet = format!("\n\n{}", impl_def.syntax());
 +                                builder.insert(offset, snippet);
 +                            }
 +                        }
 +                    }
 +                }
 +            },
 +        )?;
 +    }
 +    Some(())
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_generate_delegate_create_impl_block() {
 +        check_assist(
 +            generate_delegate_methods,
 +            r#"
 +struct Age(u8);
 +impl Age {
 +    fn age(&self) -> u8 {
 +        self.0
 +    }
 +}
 +
 +struct Person {
 +    ag$0e: Age,
 +}"#,
 +            r#"
 +struct Age(u8);
 +impl Age {
 +    fn age(&self) -> u8 {
 +        self.0
 +    }
 +}
 +
 +struct Person {
 +    age: Age,
 +}
 +
 +impl Person {
 +    $0fn age(&self) -> u8 {
 +        self.age.age()
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_delegate_update_impl_block() {
 +        check_assist(
 +            generate_delegate_methods,
 +            r#"
 +struct Age(u8);
 +impl Age {
 +    fn age(&self) -> u8 {
 +        self.0
 +    }
 +}
 +
 +struct Person {
 +    ag$0e: Age,
 +}
 +
 +impl Person {}"#,
 +            r#"
 +struct Age(u8);
 +impl Age {
 +    fn age(&self) -> u8 {
 +        self.0
 +    }
 +}
 +
 +struct Person {
 +    age: Age,
 +}
 +
 +impl Person {
 +    $0fn age(&self) -> u8 {
 +        self.age.age()
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_delegate_tuple_struct() {
 +        check_assist(
 +            generate_delegate_methods,
 +            r#"
 +struct Age(u8);
 +impl Age {
 +    fn age(&self) -> u8 {
 +        self.0
 +    }
 +}
 +
 +struct Person(A$0ge);"#,
 +            r#"
 +struct Age(u8);
 +impl Age {
 +    fn age(&self) -> u8 {
 +        self.0
 +    }
 +}
 +
 +struct Person(Age);
 +
 +impl Person {
 +    $0fn age(&self) -> u8 {
 +        self.0.age()
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_delegate_enable_all_attributes() {
 +        check_assist(
 +            generate_delegate_methods,
 +            r#"
 +struct Age<T>(T);
 +impl<T> Age<T> {
 +    pub(crate) async fn age<J, 'a>(&'a mut self, ty: T, arg: J) -> T {
 +        self.0
 +    }
 +}
 +
 +struct Person<T> {
 +    ag$0e: Age<T>,
 +}"#,
 +            r#"
 +struct Age<T>(T);
 +impl<T> Age<T> {
 +    pub(crate) async fn age<J, 'a>(&'a mut self, ty: T, arg: J) -> T {
 +        self.0
 +    }
 +}
 +
 +struct Person<T> {
 +    age: Age<T>,
 +}
 +
 +impl<T> Person<T> {
 +    $0pub(crate) async fn age<J, 'a>(&'a mut self, ty: T, arg: J) -> T {
 +        self.age.age(ty, arg)
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_delegate_visibility() {
 +        check_assist_not_applicable(
 +            generate_delegate_methods,
 +            r#"
 +mod m {
 +    pub struct Age(u8);
 +    impl Age {
 +        fn age(&self) -> u8 {
 +            self.0
 +        }
 +    }
 +}
 +
 +struct Person {
 +    ag$0e: m::Age,
 +}"#,
 +        )
 +    }
 +}
index 8f4405a8c869cf9273e481775f98bff95e63a24b,0000000000000000000000000000000000000000..55b7afb3d3b098e81fca1da02ea84f672dc6bc46
mode 100644,000000..100644
--- /dev/null
@@@ -1,345 -1,0 +1,343 @@@
-         format!("Generate `{:?}` impl using `{}`", deref_type_to_generate, field_name),
 +use std::fmt::Display;
 +
 +use hir::{ModPath, ModuleDef};
 +use ide_db::{famous_defs::FamousDefs, RootDatabase};
 +use syntax::{
 +    ast::{self, HasName},
 +    AstNode, SyntaxNode,
 +};
 +
 +use crate::{
 +    assist_context::{AssistContext, Assists, SourceChangeBuilder},
 +    utils::generate_trait_impl_text,
 +    AssistId, AssistKind,
 +};
 +
 +// Assist: generate_deref
 +//
 +// Generate `Deref` impl using the given struct field.
 +//
 +// ```
 +// # //- minicore: deref, deref_mut
 +// struct A;
 +// struct B {
 +//    $0a: A
 +// }
 +// ```
 +// ->
 +// ```
 +// struct A;
 +// struct B {
 +//    a: A
 +// }
 +//
 +// impl core::ops::Deref for B {
 +//     type Target = A;
 +//
 +//     fn deref(&self) -> &Self::Target {
 +//         &self.a
 +//     }
 +// }
 +// ```
 +pub(crate) fn generate_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    generate_record_deref(acc, ctx).or_else(|| generate_tuple_deref(acc, ctx))
 +}
 +
 +fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
 +    let field = ctx.find_node_at_offset::<ast::RecordField>()?;
 +
 +    let deref_type_to_generate = match existing_deref_impl(&ctx.sema, &strukt) {
 +        None => DerefType::Deref,
 +        Some(DerefType::Deref) => DerefType::DerefMut,
 +        Some(DerefType::DerefMut) => {
 +            cov_mark::hit!(test_add_record_deref_impl_already_exists);
 +            return None;
 +        }
 +    };
 +
 +    let module = ctx.sema.to_def(&strukt)?.module(ctx.db());
 +    let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?;
 +    let trait_path =
 +        module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_no_std)?;
 +
 +    let field_type = field.ty()?;
 +    let field_name = field.name()?;
 +    let target = field.syntax().text_range();
 +    acc.add(
 +        AssistId("generate_deref", AssistKind::Generate),
-         format!("Generate `{:?}` impl using `{}`", deref_type_to_generate, field.syntax()),
++        format!("Generate `{deref_type_to_generate:?}` impl using `{field_name}`"),
 +        target,
 +        |edit| {
 +            generate_edit(
 +                edit,
 +                strukt,
 +                field_type.syntax(),
 +                field_name.syntax(),
 +                deref_type_to_generate,
 +                trait_path,
 +            )
 +        },
 +    )
 +}
 +
 +fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
 +    let field = ctx.find_node_at_offset::<ast::TupleField>()?;
 +    let field_list = ctx.find_node_at_offset::<ast::TupleFieldList>()?;
 +    let field_list_index =
 +        field_list.syntax().children().into_iter().position(|s| &s == field.syntax())?;
 +
 +    let deref_type_to_generate = match existing_deref_impl(&ctx.sema, &strukt) {
 +        None => DerefType::Deref,
 +        Some(DerefType::Deref) => DerefType::DerefMut,
 +        Some(DerefType::DerefMut) => {
 +            cov_mark::hit!(test_add_field_deref_impl_already_exists);
 +            return None;
 +        }
 +    };
 +
 +    let module = ctx.sema.to_def(&strukt)?.module(ctx.db());
 +    let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?;
 +    let trait_path =
 +        module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_no_std)?;
 +
 +    let field_type = field.ty()?;
 +    let target = field.syntax().text_range();
 +    acc.add(
 +        AssistId("generate_deref", AssistKind::Generate),
-             r#"    type Target = {0};
++        format!("Generate `{deref_type_to_generate:?}` impl using `{field}`"),
 +        target,
 +        |edit| {
 +            generate_edit(
 +                edit,
 +                strukt,
 +                field_type.syntax(),
 +                field_list_index,
 +                deref_type_to_generate,
 +                trait_path,
 +            )
 +        },
 +    )
 +}
 +
 +fn generate_edit(
 +    edit: &mut SourceChangeBuilder,
 +    strukt: ast::Struct,
 +    field_type_syntax: &SyntaxNode,
 +    field_name: impl Display,
 +    deref_type: DerefType,
 +    trait_path: ModPath,
 +) {
 +    let start_offset = strukt.syntax().text_range().end();
 +    let impl_code = match deref_type {
 +        DerefType::Deref => format!(
-         &self.{1}
++            r#"    type Target = {field_type_syntax};
 +
 +    fn deref(&self) -> &Self::Target {{
-             field_type_syntax, field_name
++        &self.{field_name}
 +    }}"#,
-         &mut self.{}
 +        ),
 +        DerefType::DerefMut => format!(
 +            r#"    fn deref_mut(&mut self) -> &mut Self::Target {{
-             field_name
++        &mut self.{field_name}
 +    }}"#,
 +        ),
 +    };
 +    let strukt_adt = ast::Adt::Struct(strukt);
 +    let deref_impl = generate_trait_impl_text(&strukt_adt, &trait_path.to_string(), &impl_code);
 +    edit.insert(start_offset, deref_impl);
 +}
 +
 +fn existing_deref_impl(
 +    sema: &hir::Semantics<'_, RootDatabase>,
 +    strukt: &ast::Struct,
 +) -> Option<DerefType> {
 +    let strukt = sema.to_def(strukt)?;
 +    let krate = strukt.module(sema.db).krate();
 +
 +    let deref_trait = FamousDefs(sema, krate).core_ops_Deref()?;
 +    let deref_mut_trait = FamousDefs(sema, krate).core_ops_DerefMut()?;
 +    let strukt_type = strukt.ty(sema.db);
 +
 +    if strukt_type.impls_trait(sema.db, deref_trait, &[]) {
 +        if strukt_type.impls_trait(sema.db, deref_mut_trait, &[]) {
 +            Some(DerefType::DerefMut)
 +        } else {
 +            Some(DerefType::Deref)
 +        }
 +    } else {
 +        None
 +    }
 +}
 +
 +#[derive(Debug)]
 +enum DerefType {
 +    Deref,
 +    DerefMut,
 +}
 +
 +impl DerefType {
 +    fn to_trait(
 +        &self,
 +        sema: &hir::Semantics<'_, RootDatabase>,
 +        krate: hir::Crate,
 +    ) -> Option<hir::Trait> {
 +        match self {
 +            DerefType::Deref => FamousDefs(sema, krate).core_ops_Deref(),
 +            DerefType::DerefMut => FamousDefs(sema, krate).core_ops_DerefMut(),
 +        }
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_generate_record_deref() {
 +        check_assist(
 +            generate_deref,
 +            r#"
 +//- minicore: deref
 +struct A { }
 +struct B { $0a: A }"#,
 +            r#"
 +struct A { }
 +struct B { a: A }
 +
 +impl core::ops::Deref for B {
 +    type Target = A;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.a
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_record_deref_short_path() {
 +        check_assist(
 +            generate_deref,
 +            r#"
 +//- minicore: deref
 +use core::ops::Deref;
 +struct A { }
 +struct B { $0a: A }"#,
 +            r#"
 +use core::ops::Deref;
 +struct A { }
 +struct B { a: A }
 +
 +impl Deref for B {
 +    type Target = A;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.a
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_field_deref_idx_0() {
 +        check_assist(
 +            generate_deref,
 +            r#"
 +//- minicore: deref
 +struct A { }
 +struct B($0A);"#,
 +            r#"
 +struct A { }
 +struct B(A);
 +
 +impl core::ops::Deref for B {
 +    type Target = A;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.0
 +    }
 +}"#,
 +        );
 +    }
 +    #[test]
 +    fn test_generate_field_deref_idx_1() {
 +        check_assist(
 +            generate_deref,
 +            r#"
 +//- minicore: deref
 +struct A { }
 +struct B(u8, $0A);"#,
 +            r#"
 +struct A { }
 +struct B(u8, A);
 +
 +impl core::ops::Deref for B {
 +    type Target = A;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.1
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generates_derefmut_when_deref_present() {
 +        check_assist(
 +            generate_deref,
 +            r#"
 +//- minicore: deref, deref_mut
 +struct B { $0a: u8 }
 +
 +impl core::ops::Deref for B {}
 +"#,
 +            r#"
 +struct B { a: u8 }
 +
 +impl core::ops::DerefMut for B {
 +    fn deref_mut(&mut self) -> &mut Self::Target {
 +        &mut self.a
 +    }
 +}
 +
 +impl core::ops::Deref for B {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_record_deref_not_applicable_if_already_impl() {
 +        cov_mark::check!(test_add_record_deref_impl_already_exists);
 +        check_assist_not_applicable(
 +            generate_deref,
 +            r#"
 +//- minicore: deref, deref_mut
 +struct A { }
 +struct B { $0a: A }
 +
 +impl core::ops::Deref for B {}
 +impl core::ops::DerefMut for B {}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_generate_field_deref_not_applicable_if_already_impl() {
 +        cov_mark::check!(test_add_field_deref_impl_already_exists);
 +        check_assist_not_applicable(
 +            generate_deref,
 +            r#"
 +//- minicore: deref, deref_mut
 +struct A { }
 +struct B($0A)
 +
 +impl core::ops::Deref for B {}
 +impl core::ops::DerefMut for B {}
 +"#,
 +        )
 +    }
 +}
index c91141f8eb50f27fd41ccf8634587c62c2b55747,0000000000000000000000000000000000000000..b8415c72a2a3256ec14d84fb0ab874dc151d4c01
mode 100644,000000..100644
--- /dev/null
@@@ -1,1328 -1,0 +1,1338 @@@
-     format_to!(example, "use {};\n\n", build_path(ast_func, ctx)?);
 +use hir::{AsAssocItem, HasVisibility, ModuleDef, Visibility};
 +use ide_db::assists::{AssistId, AssistKind};
 +use itertools::Itertools;
 +use stdx::{format_to, to_lower_snake_case};
 +use syntax::{
 +    algo::skip_whitespace_token,
 +    ast::{self, edit::IndentLevel, HasDocComments, HasName},
 +    match_ast, AstNode, AstToken,
 +};
 +
 +use crate::assist_context::{AssistContext, Assists};
 +
 +// Assist: generate_documentation_template
 +//
 +// Adds a documentation template above a function definition / declaration.
 +//
 +// ```
 +// pub struct S;
 +// impl S {
 +//     pub unsafe fn set_len$0(&mut self, len: usize) -> Result<(), std::io::Error> {
 +//         /* ... */
 +//     }
 +// }
 +// ```
 +// ->
 +// ```
 +// pub struct S;
 +// impl S {
 +//     /// Sets the length of this [`S`].
 +//     ///
 +//     /// # Errors
 +//     ///
 +//     /// This function will return an error if .
 +//     ///
 +//     /// # Safety
 +//     ///
 +//     /// .
 +//     pub unsafe fn set_len(&mut self, len: usize) -> Result<(), std::io::Error> {
 +//         /* ... */
 +//     }
 +// }
 +// ```
 +pub(crate) fn generate_documentation_template(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +) -> Option<()> {
 +    let name = ctx.find_node_at_offset::<ast::Name>()?;
 +    let ast_func = name.syntax().parent().and_then(ast::Fn::cast)?;
 +    if is_in_trait_impl(&ast_func, ctx) || ast_func.doc_comments().next().is_some() {
 +        return None;
 +    }
 +
 +    let parent_syntax = ast_func.syntax();
 +    let text_range = parent_syntax.text_range();
 +    let indent_level = IndentLevel::from_node(parent_syntax);
 +
 +    acc.add(
 +        AssistId("generate_documentation_template", AssistKind::Generate),
 +        "Generate a documentation template",
 +        text_range,
 +        |builder| {
 +            // Introduction / short function description before the sections
 +            let mut doc_lines = vec![introduction_builder(&ast_func, ctx).unwrap_or(".".into())];
 +            // Then come the sections
 +            for section_builder in [panics_builder, errors_builder, safety_builder] {
 +                if let Some(mut lines) = section_builder(&ast_func) {
 +                    doc_lines.push("".into());
 +                    doc_lines.append(&mut lines);
 +                }
 +            }
 +            builder.insert(text_range.start(), documentation_from_lines(doc_lines, indent_level));
 +        },
 +    )
 +}
 +
 +// Assist: generate_doc_example
 +//
 +// Generates a rustdoc example when editing an item's documentation.
 +//
 +// ```
 +// /// Adds two numbers.$0
 +// pub fn add(a: i32, b: i32) -> i32 { a + b }
 +// ```
 +// ->
 +// ```
 +// /// Adds two numbers.
 +// ///
 +// /// # Examples
 +// ///
 +// /// ```
 +// /// use test::add;
 +// ///
 +// /// assert_eq!(add(a, b), );
 +// /// ```
 +// pub fn add(a: i32, b: i32) -> i32 { a + b }
 +// ```
 +pub(crate) fn generate_doc_example(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let tok: ast::Comment = ctx.find_token_at_offset()?;
 +    let node = tok.syntax().parent()?;
 +    let last_doc_token =
 +        ast::AnyHasDocComments::cast(node.clone())?.doc_comments().last()?.syntax().clone();
 +    let next_token = skip_whitespace_token(last_doc_token.next_token()?, syntax::Direction::Next)?;
 +
 +    let example = match_ast! {
 +        match node {
 +            ast::Fn(it) => make_example_for_fn(&it, ctx)?,
 +            _ => return None,
 +        }
 +    };
 +
 +    let mut lines = string_vec_from(&["", "# Examples", "", "```"]);
 +    lines.extend(example.lines().map(String::from));
 +    lines.push("```".into());
 +    let indent_level = IndentLevel::from_node(&node);
 +
 +    acc.add(
 +        AssistId("generate_doc_example", AssistKind::Generate),
 +        "Generate a documentation example",
 +        node.text_range(),
 +        |builder| {
 +            builder.insert(
 +                next_token.text_range().start(),
 +                documentation_from_lines(lines, indent_level),
 +            );
 +        },
 +    )
 +}
 +
 +fn make_example_for_fn(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<String> {
 +    if !is_public(ast_func, ctx)? {
 +        // Doctests for private items can't actually name the item, so they're pretty useless.
 +        return None;
 +    }
 +
 +    if is_in_trait_def(ast_func, ctx) {
 +        // This is not yet implemented.
 +        return None;
 +    }
 +
 +    let mut example = String::new();
 +
++    let use_path = build_path(ast_func, ctx)?;
 +    let is_unsafe = ast_func.unsafe_token().is_some();
 +    let param_list = ast_func.param_list()?;
 +    let ref_mut_params = ref_mut_params(&param_list);
 +    let self_name = self_name(ast_func);
 +
-         if let Some(mtbl) = is_ref_mut_self(ast_func) {
-             let mtbl = if mtbl == true { " mut" } else { "" };
-             format_to!(example, "let{} {} = ;\n", mtbl, self_name);
++    format_to!(example, "use {use_path};\n\n");
 +    if let Some(self_name) = &self_name {
-         format_to!(example, "let mut {} = ;\n", param_name);
++        if let Some(mut_) = is_ref_mut_self(ast_func) {
++            let mut_ = if mut_ == true { "mut " } else { "" };
++            format_to!(example, "let {mut_}{self_name} = ;\n");
 +        }
 +    }
 +    for param_name in &ref_mut_params {
-             format_to!(example, "assert_eq!({}, );\n", function_call);
++        format_to!(example, "let mut {param_name} = ;\n");
 +    }
 +    // Call the function, check result
 +    let function_call = function_call(ast_func, &param_list, self_name.as_deref(), is_unsafe)?;
 +    if returns_a_value(ast_func, ctx) {
 +        if count_parameters(&param_list) < 3 {
-             format_to!(example, "let result = {};\n", function_call);
++            format_to!(example, "assert_eq!({function_call}, );\n");
 +        } else {
-         format_to!(example, "{};\n", function_call);
++            format_to!(example, "let result = {function_call};\n");
 +            example.push_str("assert_eq!(result, );\n");
 +        }
 +    } else {
-     if is_ref_mut_self(ast_func) == Some(true) {
-         format_to!(example, "assert_eq!({}, );", self_name?);
++        format_to!(example, "{function_call};\n");
 +    }
 +    // Check the mutated values
-         format_to!(example, "assert_eq!({}, );", param_name);
++    if let Some(self_name) = &self_name {
++        if is_ref_mut_self(ast_func) == Some(true) {
++            format_to!(example, "assert_eq!({self_name}, );");
++        }
 +    }
 +    for param_name in &ref_mut_params {
-                 Some(format!("Creates a new [`{}`].", linkable_self_ty?))
++        format_to!(example, "assert_eq!({param_name}, );");
 +    }
++
 +    Some(example)
 +}
 +
 +fn introduction_builder(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<String> {
 +    let hir_func = ctx.sema.to_def(ast_func)?;
 +    let container = hir_func.as_assoc_item(ctx.db())?.container(ctx.db());
 +    if let hir::AssocItemContainer::Impl(imp) = container {
 +        let ret_ty = hir_func.ret_type(ctx.db());
 +        let self_ty = imp.self_ty(ctx.db());
 +        let name = ast_func.name()?.to_string();
 +        let linkable_self_ty = self_type_without_lifetimes(ast_func);
 +        let linkable_self_ty = linkable_self_ty.as_deref();
 +
 +        let intro_for_new = || {
 +            let is_new = name == "new";
 +            if is_new && ret_ty == self_ty {
-                 Some(format!("Returns{reference} the {what} of this [`{}`].", linkable_self_ty?))
++                let self_ty = linkable_self_ty?;
++                Some(format!("Creates a new [`{self_ty}`]."))
 +            } else {
 +                None
 +            }
 +        };
 +
 +        let intro_for_getter = || match (
 +            hir_func.self_param(ctx.sema.db),
 +            &*hir_func.params_without_self(ctx.sema.db),
 +        ) {
 +            (Some(self_param), []) if self_param.access(ctx.sema.db) != hir::Access::Owned => {
 +                if name.starts_with("as_") || name.starts_with("to_") || name == "get" {
 +                    return None;
 +                }
 +                let mut what = name.trim_end_matches("_mut").replace('_', " ");
 +                if what == "len" {
 +                    what = "length".into()
 +                }
 +                let reference = if ret_ty.is_mutable_reference() {
 +                    " a mutable reference to"
 +                } else if ret_ty.is_reference() {
 +                    " a reference to"
 +                } else {
 +                    ""
 +                };
-             Some(format!("Sets the {what} of this [`{}`].", linkable_self_ty?))
++
++                let self_ty = linkable_self_ty?;
++                Some(format!("Returns{reference} the {what} of this [`{self_ty}`]."))
 +            }
 +            _ => None,
 +        };
 +
 +        let intro_for_setter = || {
 +            if !name.starts_with("set_") {
 +                return None;
 +            }
 +
 +            let mut what = name.trim_start_matches("set_").replace('_', " ");
 +            if what == "len" {
 +                what = "length".into()
 +            };
-                 true => format!("&mut {}", name),
++
++            let self_ty = linkable_self_ty?;
++            Some(format!("Sets the {what} of this [`{self_ty}`]."))
 +        };
 +
 +        if let Some(intro) = intro_for_new() {
 +            return Some(intro);
 +        }
 +        if let Some(intro) = intro_for_getter() {
 +            return Some(intro);
 +        }
 +        if let Some(intro) = intro_for_setter() {
 +            return Some(intro);
 +        }
 +    }
 +    None
 +}
 +
 +/// Builds an optional `# Panics` section
 +fn panics_builder(ast_func: &ast::Fn) -> Option<Vec<String>> {
 +    match can_panic(ast_func) {
 +        Some(true) => Some(string_vec_from(&["# Panics", "", "Panics if ."])),
 +        _ => None,
 +    }
 +}
 +
 +/// Builds an optional `# Errors` section
 +fn errors_builder(ast_func: &ast::Fn) -> Option<Vec<String>> {
 +    match return_type(ast_func)?.to_string().contains("Result") {
 +        true => Some(string_vec_from(&["# Errors", "", "This function will return an error if ."])),
 +        false => None,
 +    }
 +}
 +
 +/// Builds an optional `# Safety` section
 +fn safety_builder(ast_func: &ast::Fn) -> Option<Vec<String>> {
 +    let is_unsafe = ast_func.unsafe_token().is_some();
 +    match is_unsafe {
 +        true => Some(string_vec_from(&["# Safety", "", "."])),
 +        false => None,
 +    }
 +}
 +
 +/// Checks if the function is public / exported
 +fn is_public(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<bool> {
 +    let hir_func = ctx.sema.to_def(ast_func)?;
 +    Some(
 +        hir_func.visibility(ctx.db()) == Visibility::Public
 +            && all_parent_mods_public(&hir_func, ctx),
 +    )
 +}
 +
 +/// Checks that all parent modules of the function are public / exported
 +fn all_parent_mods_public(hir_func: &hir::Function, ctx: &AssistContext<'_>) -> bool {
 +    let mut module = hir_func.module(ctx.db());
 +    loop {
 +        if let Some(parent) = module.parent(ctx.db()) {
 +            match ModuleDef::from(module).visibility(ctx.db()) {
 +                Visibility::Public => module = parent,
 +                _ => break false,
 +            }
 +        } else {
 +            break true;
 +        }
 +    }
 +}
 +
 +/// Returns the name of the current crate
 +fn crate_name(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<String> {
 +    let krate = ctx.sema.scope(ast_func.syntax())?.krate();
 +    Some(krate.display_name(ctx.db())?.to_string())
 +}
 +
 +/// `None` if function without a body; some bool to guess if function can panic
 +fn can_panic(ast_func: &ast::Fn) -> Option<bool> {
 +    let body = ast_func.body()?.to_string();
 +    let can_panic = body.contains("panic!(")
 +        // FIXME it would be better to not match `debug_assert*!` macro invocations
 +        || body.contains("assert!(")
 +        || body.contains(".unwrap()")
 +        || body.contains(".expect(");
 +    Some(can_panic)
 +}
 +
 +/// Helper function to get the name that should be given to `self` arguments
 +fn self_name(ast_func: &ast::Fn) -> Option<String> {
 +    self_partial_type(ast_func).map(|name| to_lower_snake_case(&name))
 +}
 +
 +/// Heper function to get the name of the type of `self`
 +fn self_type(ast_func: &ast::Fn) -> Option<ast::Type> {
 +    ast_func.syntax().ancestors().find_map(ast::Impl::cast).and_then(|i| i.self_ty())
 +}
 +
 +/// Output the real name of `Self` like `MyType<T>`, without the lifetimes.
 +fn self_type_without_lifetimes(ast_func: &ast::Fn) -> Option<String> {
 +    let path_segment = match self_type(ast_func)? {
 +        ast::Type::PathType(path_type) => path_type.path()?.segment()?,
 +        _ => return None,
 +    };
 +    let mut name = path_segment.name_ref()?.to_string();
 +    let generics = path_segment.generic_arg_list().into_iter().flat_map(|list| {
 +        list.generic_args()
 +            .filter(|generic| matches!(generic, ast::GenericArg::TypeArg(_)))
 +            .map(|generic| generic.to_string())
 +    });
 +    let generics: String = generics.format(", ").to_string();
 +    if !generics.is_empty() {
 +        name.push('<');
 +        name.push_str(&generics);
 +        name.push('>');
 +    }
 +    Some(name)
 +}
 +
 +/// Heper function to get the name of the type of `self` without generic arguments
 +fn self_partial_type(ast_func: &ast::Fn) -> Option<String> {
 +    let mut self_type = self_type(ast_func)?.to_string();
 +    if let Some(idx) = self_type.find(|c| ['<', ' '].contains(&c)) {
 +        self_type.truncate(idx);
 +    }
 +    Some(self_type)
 +}
 +
 +/// Helper function to determine if the function is in a trait implementation
 +fn is_in_trait_impl(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> bool {
 +    ctx.sema
 +        .to_def(ast_func)
 +        .and_then(|hir_func| hir_func.as_assoc_item(ctx.db()))
 +        .and_then(|assoc_item| assoc_item.containing_trait_impl(ctx.db()))
 +        .is_some()
 +}
 +
 +/// Helper function to determine if the function definition is in a trait definition
 +fn is_in_trait_def(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> bool {
 +    ctx.sema
 +        .to_def(ast_func)
 +        .and_then(|hir_func| hir_func.as_assoc_item(ctx.db()))
 +        .and_then(|assoc_item| assoc_item.containing_trait(ctx.db()))
 +        .is_some()
 +}
 +
 +/// Returns `None` if no `self` at all, `Some(true)` if there is `&mut self` else `Some(false)`
 +fn is_ref_mut_self(ast_func: &ast::Fn) -> Option<bool> {
 +    let self_param = ast_func.param_list()?.self_param()?;
 +    Some(self_param.mut_token().is_some() && self_param.amp_token().is_some())
 +}
 +
 +/// Helper function to determine if a parameter is `&mut`
 +fn is_a_ref_mut_param(param: &ast::Param) -> bool {
 +    match param.ty() {
 +        Some(ast::Type::RefType(param_ref)) => param_ref.mut_token().is_some(),
 +        _ => false,
 +    }
 +}
 +
 +/// Helper function to build the list of `&mut` parameters
 +fn ref_mut_params(param_list: &ast::ParamList) -> Vec<String> {
 +    param_list
 +        .params()
 +        .filter_map(|param| match is_a_ref_mut_param(&param) {
 +            // Maybe better filter the param name (to do this maybe extract a function from
 +            // `arguments_from_params`?) in case of a `mut a: &mut T`. Anyway managing most (not
 +            // all) cases might be enough, the goal is just to produce a template.
 +            true => Some(param.pat()?.to_string()),
 +            false => None,
 +        })
 +        .collect()
 +}
 +
 +/// Helper function to build the comma-separated list of arguments of the function
 +fn arguments_from_params(param_list: &ast::ParamList) -> String {
 +    let args_iter = param_list.params().map(|param| match param.pat() {
 +        // To avoid `mut` in the function call (which would be a nonsense), `Pat` should not be
 +        // written as is so its variants must be managed independently. Other variants (for
 +        // instance `TuplePat`) could be managed later.
 +        Some(ast::Pat::IdentPat(ident_pat)) => match ident_pat.name() {
 +            Some(name) => match is_a_ref_mut_param(&param) {
-         format!("{}.{}({})", self_name?, name, arguments)
++                true => format!("&mut {name}"),
 +                false => name.to_string(),
 +            },
 +            None => "_".to_string(),
 +        },
 +        _ => "_".to_string(),
 +    });
 +    args_iter.format(", ").to_string()
 +}
 +
 +/// Helper function to build a function call. `None` if expected `self_name` was not provided
 +fn function_call(
 +    ast_func: &ast::Fn,
 +    param_list: &ast::ParamList,
 +    self_name: Option<&str>,
 +    is_unsafe: bool,
 +) -> Option<String> {
 +    let name = ast_func.name()?;
 +    let arguments = arguments_from_params(param_list);
 +    let function_call = if param_list.self_param().is_some() {
-         format!("{}::{}({})", implementation, name, arguments)
++        let self_ = self_name?;
++        format!("{self_}.{name}({arguments})")
 +    } else if let Some(implementation) = self_partial_type(ast_func) {
-         format!("{}({})", name, arguments)
++        format!("{implementation}::{name}({arguments})")
 +    } else {
-         true => Some(format!("unsafe {{ {} }}", function_call)),
++        format!("{name}({arguments})")
 +    };
 +    match is_unsafe {
-         Some(path) => Some(format!("{}::{}::{}", crate_name, path, leaf)),
-         None => Some(format!("{}::{}", crate_name, leaf)),
++        true => Some(format!("unsafe {{ {function_call} }}")),
 +        false => Some(function_call),
 +    }
 +}
 +
 +/// Helper function to count the parameters including `self`
 +fn count_parameters(param_list: &ast::ParamList) -> usize {
 +    param_list.params().count() + if param_list.self_param().is_some() { 1 } else { 0 }
 +}
 +
 +/// Helper function to transform lines of documentation into a Rust code documentation
 +fn documentation_from_lines(doc_lines: Vec<String>, indent_level: IndentLevel) -> String {
 +    let mut result = String::new();
 +    for doc_line in doc_lines {
 +        result.push_str("///");
 +        if !doc_line.is_empty() {
 +            result.push(' ');
 +            result.push_str(&doc_line);
 +        }
 +        result.push('\n');
 +        result.push_str(&indent_level.to_string());
 +    }
 +    result
 +}
 +
 +/// Helper function to transform an array of borrowed strings to an owned `Vec<String>`
 +fn string_vec_from(string_array: &[&str]) -> Vec<String> {
 +    string_array.iter().map(|&s| s.to_owned()).collect()
 +}
 +
 +/// Helper function to build the path of the module in the which is the node
 +fn build_path(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<String> {
 +    let crate_name = crate_name(ast_func, ctx)?;
 +    let leaf = self_partial_type(ast_func)
 +        .or_else(|| ast_func.name().map(|n| n.to_string()))
 +        .unwrap_or_else(|| "*".into());
 +    let module_def: ModuleDef = ctx.sema.to_def(ast_func)?.module(ctx.db()).into();
 +    match module_def.canonical_path(ctx.db()) {
++        Some(path) => Some(format!("{crate_name}::{path}::{leaf}")),
++        None => Some(format!("{crate_name}::{leaf}")),
 +    }
 +}
 +
 +/// Helper function to get the return type of a function
 +fn return_type(ast_func: &ast::Fn) -> Option<ast::Type> {
 +    ast_func.ret_type()?.ty()
 +}
 +
 +/// Helper function to determine if the function returns some data
 +fn returns_a_value(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> bool {
 +    ctx.sema
 +        .to_def(ast_func)
 +        .map(|hir_func| hir_func.ret_type(ctx.db()))
 +        .map(|ret_ty| !ret_ty.is_unit() && !ret_ty.is_never())
 +        .unwrap_or(false)
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn not_applicable_on_function_calls() {
 +        check_assist_not_applicable(
 +            generate_documentation_template,
 +            r#"
 +fn hello_world() {}
 +fn calls_hello_world() {
 +    hello_world$0();
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn not_applicable_in_trait_impl() {
 +        check_assist_not_applicable(
 +            generate_documentation_template,
 +            r#"
 +trait MyTrait {}
 +struct MyStruct;
 +impl MyTrait for MyStruct {
 +    fn hello_world$0();
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn not_applicable_if_function_already_documented() {
 +        check_assist_not_applicable(
 +            generate_documentation_template,
 +            r#"
 +/// Some documentation here
 +pub fn $0documented_function() {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn supports_noop_function() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub fn no$0op() {}
 +"#,
 +            r#"
 +/// .
 +pub fn noop() {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn is_applicable_if_function_is_private() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +fn priv$0ate() {}
 +"#,
 +            r#"
 +/// .
 +fn private() {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_doc_example_for_private_fn() {
 +        check_assist_not_applicable(
 +            generate_doc_example,
 +            r#"
 +///$0
 +fn private() {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn supports_a_parameter() {
 +        check_assist(
 +            generate_doc_example,
 +            r#"
 +/// $0.
 +pub fn noop_with_param(_a: i32) {}
 +"#,
 +            r#"
 +/// .
 +///
 +/// # Examples
 +///
 +/// ```
 +/// use test::noop_with_param;
 +///
 +/// noop_with_param(_a);
 +/// ```
 +pub fn noop_with_param(_a: i32) {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn detects_unsafe_function() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub unsafe fn no$0op_unsafe() {}
 +"#,
 +            r#"
 +/// .
 +///
 +/// # Safety
 +///
 +/// .
 +pub unsafe fn noop_unsafe() {}
 +"#,
 +        );
 +        check_assist(
 +            generate_doc_example,
 +            r#"
 +/// .
 +///
 +/// # Safety$0
 +///
 +/// .
 +pub unsafe fn noop_unsafe() {}
 +"#,
 +            r#"
 +/// .
 +///
 +/// # Safety
 +///
 +/// .
 +///
 +/// # Examples
 +///
 +/// ```
 +/// use test::noop_unsafe;
 +///
 +/// unsafe { noop_unsafe() };
 +/// ```
 +pub unsafe fn noop_unsafe() {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn guesses_panic_macro_can_panic() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub fn panic$0s_if(a: bool) {
 +    if a {
 +        panic!();
 +    }
 +}
 +"#,
 +            r#"
 +/// .
 +///
 +/// # Panics
 +///
 +/// Panics if .
 +pub fn panics_if(a: bool) {
 +    if a {
 +        panic!();
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn guesses_assert_macro_can_panic() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub fn $0panics_if_not(a: bool) {
 +    assert!(a == true);
 +}
 +"#,
 +            r#"
 +/// .
 +///
 +/// # Panics
 +///
 +/// Panics if .
 +pub fn panics_if_not(a: bool) {
 +    assert!(a == true);
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn guesses_unwrap_can_panic() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub fn $0panics_if_none(a: Option<()>) {
 +    a.unwrap();
 +}
 +"#,
 +            r#"
 +/// .
 +///
 +/// # Panics
 +///
 +/// Panics if .
 +pub fn panics_if_none(a: Option<()>) {
 +    a.unwrap();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn guesses_expect_can_panic() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub fn $0panics_if_none2(a: Option<()>) {
 +    a.expect("Bouh!");
 +}
 +"#,
 +            r#"
 +/// .
 +///
 +/// # Panics
 +///
 +/// Panics if .
 +pub fn panics_if_none2(a: Option<()>) {
 +    a.expect("Bouh!");
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn checks_output_in_example() {
 +        check_assist(
 +            generate_doc_example,
 +            r#"
 +///$0
 +pub fn returns_a_value$0() -> i32 {
 +    0
 +}
 +"#,
 +            r#"
 +///
 +///
 +/// # Examples
 +///
 +/// ```
 +/// use test::returns_a_value;
 +///
 +/// assert_eq!(returns_a_value(), );
 +/// ```
 +pub fn returns_a_value() -> i32 {
 +    0
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn detects_result_output() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub fn returns_a_result$0() -> Result<i32, std::io::Error> {
 +    Ok(0)
 +}
 +"#,
 +            r#"
 +/// .
 +///
 +/// # Errors
 +///
 +/// This function will return an error if .
 +pub fn returns_a_result() -> Result<i32, std::io::Error> {
 +    Ok(0)
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn checks_ref_mut_in_example() {
 +        check_assist(
 +            generate_doc_example,
 +            r#"
 +///$0
 +pub fn modifies_a_value$0(a: &mut i32) {
 +    *a = 0;
 +}
 +"#,
 +            r#"
 +///
 +///
 +/// # Examples
 +///
 +/// ```
 +/// use test::modifies_a_value;
 +///
 +/// let mut a = ;
 +/// modifies_a_value(&mut a);
 +/// assert_eq!(a, );
 +/// ```
 +pub fn modifies_a_value(a: &mut i32) {
 +    *a = 0;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn stores_result_if_at_least_3_params() {
 +        check_assist(
 +            generate_doc_example,
 +            r#"
 +///$0
 +pub fn sum3$0(a: i32, b: i32, c: i32) -> i32 {
 +    a + b + c
 +}
 +"#,
 +            r#"
 +///
 +///
 +/// # Examples
 +///
 +/// ```
 +/// use test::sum3;
 +///
 +/// let result = sum3(a, b, c);
 +/// assert_eq!(result, );
 +/// ```
 +pub fn sum3(a: i32, b: i32, c: i32) -> i32 {
 +    a + b + c
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn supports_fn_in_mods() {
 +        check_assist(
 +            generate_doc_example,
 +            r#"
 +pub mod a {
 +    pub mod b {
 +        ///$0
 +        pub fn noop() {}
 +    }
 +}
 +"#,
 +            r#"
 +pub mod a {
 +    pub mod b {
 +        ///
 +        ///
 +        /// # Examples
 +        ///
 +        /// ```
 +        /// use test::a::b::noop;
 +        ///
 +        /// noop();
 +        /// ```
 +        pub fn noop() {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn supports_fn_in_impl() {
 +        check_assist(
 +            generate_doc_example,
 +            r#"
 +pub struct MyStruct;
 +impl MyStruct {
 +    ///$0
 +    pub fn noop() {}
 +}
 +"#,
 +            r#"
 +pub struct MyStruct;
 +impl MyStruct {
 +    ///
 +    ///
 +    /// # Examples
 +    ///
 +    /// ```
 +    /// use test::MyStruct;
 +    ///
 +    /// MyStruct::noop();
 +    /// ```
 +    pub fn noop() {}
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn supports_unsafe_fn_in_trait() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub trait MyTrait {
 +    unsafe fn unsafe_funct$0ion_trait();
 +}
 +"#,
 +            r#"
 +pub trait MyTrait {
 +    /// .
 +    ///
 +    /// # Safety
 +    ///
 +    /// .
 +    unsafe fn unsafe_function_trait();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn supports_fn_in_trait_with_default_panicking() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub trait MyTrait {
 +    fn function_trait_with_$0default_panicking() {
 +        panic!()
 +    }
 +}
 +"#,
 +            r#"
 +pub trait MyTrait {
 +    /// .
 +    ///
 +    /// # Panics
 +    ///
 +    /// Panics if .
 +    fn function_trait_with_default_panicking() {
 +        panic!()
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn supports_fn_in_trait_returning_result() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub trait MyTrait {
 +    fn function_tr$0ait_returning_result() -> Result<(), std::io::Error>;
 +}
 +"#,
 +            r#"
 +pub trait MyTrait {
 +    /// .
 +    ///
 +    /// # Errors
 +    ///
 +    /// This function will return an error if .
 +    fn function_trait_returning_result() -> Result<(), std::io::Error>;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn detects_new() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub struct String(u8);
 +impl String {
 +    pub fn new$0(x: u8) -> String {
 +        String(x)
 +    }
 +}
 +"#,
 +            r#"
 +pub struct String(u8);
 +impl String {
 +    /// Creates a new [`String`].
 +    pub fn new(x: u8) -> String {
 +        String(x)
 +    }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +#[derive(Debug, PartialEq)]
 +pub struct MyGenericStruct<T> {
 +    pub x: T,
 +}
 +impl<T> MyGenericStruct<T> {
 +    pub fn new$0(x: T) -> MyGenericStruct<T> {
 +        MyGenericStruct { x }
 +    }
 +}
 +"#,
 +            r#"
 +#[derive(Debug, PartialEq)]
 +pub struct MyGenericStruct<T> {
 +    pub x: T,
 +}
 +impl<T> MyGenericStruct<T> {
 +    /// Creates a new [`MyGenericStruct<T>`].
 +    pub fn new(x: T) -> MyGenericStruct<T> {
 +        MyGenericStruct { x }
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn removes_one_lifetime_from_description() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +#[derive(Debug, PartialEq)]
 +pub struct MyGenericStruct<'a, T> {
 +    pub x: &'a T,
 +}
 +impl<'a, T> MyGenericStruct<'a, T> {
 +    pub fn new$0(x: &'a T) -> Self {
 +        MyGenericStruct { x }
 +    }
 +}
 +"#,
 +            r#"
 +#[derive(Debug, PartialEq)]
 +pub struct MyGenericStruct<'a, T> {
 +    pub x: &'a T,
 +}
 +impl<'a, T> MyGenericStruct<'a, T> {
 +    /// Creates a new [`MyGenericStruct<T>`].
 +    pub fn new(x: &'a T) -> Self {
 +        MyGenericStruct { x }
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn removes_all_lifetimes_from_description() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +#[derive(Debug, PartialEq)]
 +pub struct MyGenericStruct<'a, 'b, T> {
 +    pub x: &'a T,
 +    pub y: &'b T,
 +}
 +impl<'a, 'b, T> MyGenericStruct<'a, 'b, T> {
 +    pub fn new$0(x: &'a T, y: &'b T) -> Self {
 +        MyGenericStruct { x, y }
 +    }
 +}
 +"#,
 +            r#"
 +#[derive(Debug, PartialEq)]
 +pub struct MyGenericStruct<'a, 'b, T> {
 +    pub x: &'a T,
 +    pub y: &'b T,
 +}
 +impl<'a, 'b, T> MyGenericStruct<'a, 'b, T> {
 +    /// Creates a new [`MyGenericStruct<T>`].
 +    pub fn new(x: &'a T, y: &'b T) -> Self {
 +        MyGenericStruct { x, y }
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn removes_all_lifetimes_and_brackets_from_description() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +#[derive(Debug, PartialEq)]
 +pub struct MyGenericStruct<'a, 'b> {
 +    pub x: &'a usize,
 +    pub y: &'b usize,
 +}
 +impl<'a, 'b> MyGenericStruct<'a, 'b> {
 +    pub fn new$0(x: &'a usize, y: &'b usize) -> Self {
 +        MyGenericStruct { x, y }
 +    }
 +}
 +"#,
 +            r#"
 +#[derive(Debug, PartialEq)]
 +pub struct MyGenericStruct<'a, 'b> {
 +    pub x: &'a usize,
 +    pub y: &'b usize,
 +}
 +impl<'a, 'b> MyGenericStruct<'a, 'b> {
 +    /// Creates a new [`MyGenericStruct`].
 +    pub fn new(x: &'a usize, y: &'b usize) -> Self {
 +        MyGenericStruct { x, y }
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn detects_new_with_self() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +#[derive(Debug, PartialEq)]
 +pub struct MyGenericStruct2<T> {
 +    pub x: T,
 +}
 +impl<T> MyGenericStruct2<T> {
 +    pub fn new$0(x: T) -> Self {
 +        MyGenericStruct2 { x }
 +    }
 +}
 +"#,
 +            r#"
 +#[derive(Debug, PartialEq)]
 +pub struct MyGenericStruct2<T> {
 +    pub x: T,
 +}
 +impl<T> MyGenericStruct2<T> {
 +    /// Creates a new [`MyGenericStruct2<T>`].
 +    pub fn new(x: T) -> Self {
 +        MyGenericStruct2 { x }
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn supports_method_call() {
 +        check_assist(
 +            generate_doc_example,
 +            r#"
 +impl<T> MyGenericStruct<T> {
 +    ///$0
 +    pub fn consume(self) {}
 +}
 +"#,
 +            r#"
 +impl<T> MyGenericStruct<T> {
 +    ///
 +    ///
 +    /// # Examples
 +    ///
 +    /// ```
 +    /// use test::MyGenericStruct;
 +    ///
 +    /// let my_generic_struct = ;
 +    /// my_generic_struct.consume();
 +    /// ```
 +    pub fn consume(self) {}
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn checks_modified_self_param() {
 +        check_assist(
 +            generate_doc_example,
 +            r#"
 +impl<T> MyGenericStruct<T> {
 +    ///$0
 +    pub fn modify(&mut self, new_value: T) {
 +        self.x = new_value;
 +    }
 +}
 +"#,
 +            r#"
 +impl<T> MyGenericStruct<T> {
 +    ///
 +    ///
 +    /// # Examples
 +    ///
 +    /// ```
 +    /// use test::MyGenericStruct;
 +    ///
 +    /// let mut my_generic_struct = ;
 +    /// my_generic_struct.modify(new_value);
 +    /// assert_eq!(my_generic_struct, );
 +    /// ```
 +    pub fn modify(&mut self, new_value: T) {
 +        self.x = new_value;
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn generates_intro_for_getters() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub struct S;
 +impl S {
 +    pub fn speed$0(&self) -> f32 { 0.0 }
 +}
 +"#,
 +            r#"
 +pub struct S;
 +impl S {
 +    /// Returns the speed of this [`S`].
 +    pub fn speed(&self) -> f32 { 0.0 }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub struct S;
 +impl S {
 +    pub fn data$0(&self) -> &[u8] { &[] }
 +}
 +"#,
 +            r#"
 +pub struct S;
 +impl S {
 +    /// Returns a reference to the data of this [`S`].
 +    pub fn data(&self) -> &[u8] { &[] }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub struct S;
 +impl S {
 +    pub fn data$0(&mut self) -> &mut [u8] { &mut [] }
 +}
 +"#,
 +            r#"
 +pub struct S;
 +impl S {
 +    /// Returns a mutable reference to the data of this [`S`].
 +    pub fn data(&mut self) -> &mut [u8] { &mut [] }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub struct S;
 +impl S {
 +    pub fn data_mut$0(&mut self) -> &mut [u8] { &mut [] }
 +}
 +"#,
 +            r#"
 +pub struct S;
 +impl S {
 +    /// Returns a mutable reference to the data of this [`S`].
 +    pub fn data_mut(&mut self) -> &mut [u8] { &mut [] }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_getter_intro_for_prefixed_methods() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub struct S;
 +impl S {
 +    pub fn as_bytes$0(&self) -> &[u8] { &[] }
 +}
 +"#,
 +            r#"
 +pub struct S;
 +impl S {
 +    /// .
 +    pub fn as_bytes(&self) -> &[u8] { &[] }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn generates_intro_for_setters() {
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub struct S;
 +impl S {
 +    pub fn set_data$0(&mut self, data: Vec<u8>) {}
 +}
 +"#,
 +            r#"
 +pub struct S;
 +impl S {
 +    /// Sets the data of this [`S`].
 +    pub fn set_data(&mut self, data: Vec<u8>) {}
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_documentation_template,
 +            r#"
 +pub struct S;
 +impl S {
 +    pub fn set_domain_name$0(&mut self, name: String) {}
 +}
 +"#,
 +            r#"
 +pub struct S;
 +impl S {
 +    /// Sets the domain name of this [`S`].
 +    pub fn set_domain_name(&mut self, name: String) {}
 +}
 +"#,
 +        );
 +    }
 +}
index 52d27d8a7d63350b385cf74c5806e23bb612c9c0,0000000000000000000000000000000000000000..63e91b835f1f857d651b2a7daf2eac7675980145
mode 100644,000000..100644
--- /dev/null
@@@ -1,316 -1,0 +1,310 @@@
-     let impl_def = find_struct_impl(ctx, &parent_enum, &fn_name)?;
 +use ide_db::assists::GroupLabel;
 +use stdx::to_lower_snake_case;
 +use syntax::ast::HasVisibility;
 +use syntax::ast::{self, AstNode, HasName};
 +
 +use crate::{
 +    utils::{add_method_to_adt, find_struct_impl},
 +    AssistContext, AssistId, AssistKind, Assists,
 +};
 +
 +// Assist: generate_enum_is_method
 +//
 +// Generate an `is_` method for this enum variant.
 +//
 +// ```
 +// enum Version {
 +//  Undefined,
 +//  Minor$0,
 +//  Major,
 +// }
 +// ```
 +// ->
 +// ```
 +// enum Version {
 +//  Undefined,
 +//  Minor,
 +//  Major,
 +// }
 +//
 +// impl Version {
 +//     /// Returns `true` if the version is [`Minor`].
 +//     ///
 +//     /// [`Minor`]: Version::Minor
 +//     #[must_use]
 +//     fn is_minor(&self) -> bool {
 +//         matches!(self, Self::Minor)
 +//     }
 +// }
 +// ```
 +pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let variant = ctx.find_node_at_offset::<ast::Variant>()?;
 +    let variant_name = variant.name()?;
 +    let parent_enum = ast::Adt::Enum(variant.parent_enum());
 +    let pattern_suffix = match variant.kind() {
 +        ast::StructKind::Record(_) => " { .. }",
 +        ast::StructKind::Tuple(_) => "(..)",
 +        ast::StructKind::Unit => "",
 +    };
 +
 +    let enum_name = parent_enum.name()?;
 +    let enum_lowercase_name = to_lower_snake_case(&enum_name.to_string()).replace('_', " ");
 +    let fn_name = format!("is_{}", &to_lower_snake_case(&variant_name.text()));
 +
 +    // Return early if we've found an existing new fn
-             let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
++    let impl_def = find_struct_impl(ctx, &parent_enum, &[fn_name.clone()])?;
 +
 +    let target = variant.syntax().text_range();
 +    acc.add_group(
 +        &GroupLabel("Generate an `is_`,`as_`, or `try_into_` for this enum variant".to_owned()),
 +        AssistId("generate_enum_is_method", AssistKind::Generate),
 +        "Generate an `is_` method for this enum variant",
 +        target,
 +        |builder| {
-                 "    /// Returns `true` if the {} is [`{variant}`].
++            let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{v} "));
 +            let method = format!(
-     /// [`{variant}`]: {}::{variant}
++                "    /// Returns `true` if the {enum_lowercase_name} is [`{variant_name}`].
 +    ///
-     {}fn {}(&self) -> bool {{
-         matches!(self, Self::{variant}{})
++    /// [`{variant_name}`]: {enum_name}::{variant_name}
 +    #[must_use]
-                 enum_lowercase_name,
-                 enum_name,
-                 vis,
-                 fn_name,
-                 pattern_suffix,
-                 variant = variant_name
++    {vis}fn {fn_name}(&self) -> bool {{
++        matches!(self, Self::{variant_name}{pattern_suffix})
 +    }}",
 +            );
 +
 +            add_method_to_adt(builder, &parent_enum, impl_def, &method);
 +        },
 +    )
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_generate_enum_is_from_variant() {
 +        check_assist(
 +            generate_enum_is_method,
 +            r#"
 +enum Variant {
 +    Undefined,
 +    Minor$0,
 +    Major,
 +}"#,
 +            r#"enum Variant {
 +    Undefined,
 +    Minor,
 +    Major,
 +}
 +
 +impl Variant {
 +    /// Returns `true` if the variant is [`Minor`].
 +    ///
 +    /// [`Minor`]: Variant::Minor
 +    #[must_use]
 +    fn is_minor(&self) -> bool {
 +        matches!(self, Self::Minor)
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_enum_is_already_implemented() {
 +        check_assist_not_applicable(
 +            generate_enum_is_method,
 +            r#"
 +enum Variant {
 +    Undefined,
 +    Minor$0,
 +    Major,
 +}
 +
 +impl Variant {
 +    fn is_minor(&self) -> bool {
 +        matches!(self, Self::Minor)
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_enum_is_from_tuple_variant() {
 +        check_assist(
 +            generate_enum_is_method,
 +            r#"
 +enum Variant {
 +    Undefined,
 +    Minor(u32)$0,
 +    Major,
 +}"#,
 +            r#"enum Variant {
 +    Undefined,
 +    Minor(u32),
 +    Major,
 +}
 +
 +impl Variant {
 +    /// Returns `true` if the variant is [`Minor`].
 +    ///
 +    /// [`Minor`]: Variant::Minor
 +    #[must_use]
 +    fn is_minor(&self) -> bool {
 +        matches!(self, Self::Minor(..))
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_enum_is_from_record_variant() {
 +        check_assist(
 +            generate_enum_is_method,
 +            r#"
 +enum Variant {
 +    Undefined,
 +    Minor { foo: i32 }$0,
 +    Major,
 +}"#,
 +            r#"enum Variant {
 +    Undefined,
 +    Minor { foo: i32 },
 +    Major,
 +}
 +
 +impl Variant {
 +    /// Returns `true` if the variant is [`Minor`].
 +    ///
 +    /// [`Minor`]: Variant::Minor
 +    #[must_use]
 +    fn is_minor(&self) -> bool {
 +        matches!(self, Self::Minor { .. })
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_enum_is_from_variant_with_one_variant() {
 +        check_assist(
 +            generate_enum_is_method,
 +            r#"enum Variant { Undefi$0ned }"#,
 +            r#"
 +enum Variant { Undefined }
 +
 +impl Variant {
 +    /// Returns `true` if the variant is [`Undefined`].
 +    ///
 +    /// [`Undefined`]: Variant::Undefined
 +    #[must_use]
 +    fn is_undefined(&self) -> bool {
 +        matches!(self, Self::Undefined)
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_enum_is_from_variant_with_visibility_marker() {
 +        check_assist(
 +            generate_enum_is_method,
 +            r#"
 +pub(crate) enum Variant {
 +    Undefined,
 +    Minor$0,
 +    Major,
 +}"#,
 +            r#"pub(crate) enum Variant {
 +    Undefined,
 +    Minor,
 +    Major,
 +}
 +
 +impl Variant {
 +    /// Returns `true` if the variant is [`Minor`].
 +    ///
 +    /// [`Minor`]: Variant::Minor
 +    #[must_use]
 +    pub(crate) fn is_minor(&self) -> bool {
 +        matches!(self, Self::Minor)
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_multiple_generate_enum_is_from_variant() {
 +        check_assist(
 +            generate_enum_is_method,
 +            r#"
 +enum Variant {
 +    Undefined,
 +    Minor,
 +    Major$0,
 +}
 +
 +impl Variant {
 +    /// Returns `true` if the variant is [`Minor`].
 +    ///
 +    /// [`Minor`]: Variant::Minor
 +    #[must_use]
 +    fn is_minor(&self) -> bool {
 +        matches!(self, Self::Minor)
 +    }
 +}"#,
 +            r#"enum Variant {
 +    Undefined,
 +    Minor,
 +    Major,
 +}
 +
 +impl Variant {
 +    /// Returns `true` if the variant is [`Minor`].
 +    ///
 +    /// [`Minor`]: Variant::Minor
 +    #[must_use]
 +    fn is_minor(&self) -> bool {
 +        matches!(self, Self::Minor)
 +    }
 +
 +    /// Returns `true` if the variant is [`Major`].
 +    ///
 +    /// [`Major`]: Variant::Major
 +    #[must_use]
 +    fn is_major(&self) -> bool {
 +        matches!(self, Self::Major)
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_enum_is_variant_names() {
 +        check_assist(
 +            generate_enum_is_method,
 +            r#"
 +enum GeneratorState {
 +    Yielded,
 +    Complete$0,
 +    Major,
 +}"#,
 +            r#"enum GeneratorState {
 +    Yielded,
 +    Complete,
 +    Major,
 +}
 +
 +impl GeneratorState {
 +    /// Returns `true` if the generator state is [`Complete`].
 +    ///
 +    /// [`Complete`]: GeneratorState::Complete
 +    #[must_use]
 +    fn is_complete(&self) -> bool {
 +        matches!(self, Self::Complete)
 +    }
 +}"#,
 +        );
 +    }
 +}
index b19aa0f652aa71acbc5ee9e213ec6520fe241432,0000000000000000000000000000000000000000..bdd3cf4f06c253692d3e3989075ec4cd56e4ba15
mode 100644,000000..100644
--- /dev/null
@@@ -1,342 -1,0 +1,337 @@@
-             let pattern_suffix = format!(" {{ {} }}", name);
 +use ide_db::assists::GroupLabel;
 +use itertools::Itertools;
 +use stdx::to_lower_snake_case;
 +use syntax::ast::HasVisibility;
 +use syntax::ast::{self, AstNode, HasName};
 +
 +use crate::{
 +    utils::{add_method_to_adt, find_struct_impl},
 +    AssistContext, AssistId, AssistKind, Assists,
 +};
 +
 +// Assist: generate_enum_try_into_method
 +//
 +// Generate a `try_into_` method for this enum variant.
 +//
 +// ```
 +// enum Value {
 +//  Number(i32),
 +//  Text(String)$0,
 +// }
 +// ```
 +// ->
 +// ```
 +// enum Value {
 +//  Number(i32),
 +//  Text(String),
 +// }
 +//
 +// impl Value {
 +//     fn try_into_text(self) -> Result<String, Self> {
 +//         if let Self::Text(v) = self {
 +//             Ok(v)
 +//         } else {
 +//             Err(self)
 +//         }
 +//     }
 +// }
 +// ```
 +pub(crate) fn generate_enum_try_into_method(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +) -> Option<()> {
 +    generate_enum_projection_method(
 +        acc,
 +        ctx,
 +        "generate_enum_try_into_method",
 +        "Generate a `try_into_` method for this enum variant",
 +        ProjectionProps {
 +            fn_name_prefix: "try_into",
 +            self_param: "self",
 +            return_prefix: "Result<",
 +            return_suffix: ", Self>",
 +            happy_case: "Ok",
 +            sad_case: "Err(self)",
 +        },
 +    )
 +}
 +
 +// Assist: generate_enum_as_method
 +//
 +// Generate an `as_` method for this enum variant.
 +//
 +// ```
 +// enum Value {
 +//  Number(i32),
 +//  Text(String)$0,
 +// }
 +// ```
 +// ->
 +// ```
 +// enum Value {
 +//  Number(i32),
 +//  Text(String),
 +// }
 +//
 +// impl Value {
 +//     fn as_text(&self) -> Option<&String> {
 +//         if let Self::Text(v) = self {
 +//             Some(v)
 +//         } else {
 +//             None
 +//         }
 +//     }
 +// }
 +// ```
 +pub(crate) fn generate_enum_as_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    generate_enum_projection_method(
 +        acc,
 +        ctx,
 +        "generate_enum_as_method",
 +        "Generate an `as_` method for this enum variant",
 +        ProjectionProps {
 +            fn_name_prefix: "as",
 +            self_param: "&self",
 +            return_prefix: "Option<&",
 +            return_suffix: ">",
 +            happy_case: "Some",
 +            sad_case: "None",
 +        },
 +    )
 +}
 +
 +struct ProjectionProps {
 +    fn_name_prefix: &'static str,
 +    self_param: &'static str,
 +    return_prefix: &'static str,
 +    return_suffix: &'static str,
 +    happy_case: &'static str,
 +    sad_case: &'static str,
 +}
 +
 +fn generate_enum_projection_method(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +    assist_id: &'static str,
 +    assist_description: &str,
 +    props: ProjectionProps,
 +) -> Option<()> {
++    let ProjectionProps {
++        fn_name_prefix,
++        self_param,
++        return_prefix,
++        return_suffix,
++        happy_case,
++        sad_case,
++    } = props;
 +    let variant = ctx.find_node_at_offset::<ast::Variant>()?;
 +    let variant_name = variant.name()?;
 +    let parent_enum = ast::Adt::Enum(variant.parent_enum());
 +
 +    let (pattern_suffix, field_type, bound_name) = match variant.kind() {
 +        ast::StructKind::Record(record) => {
 +            let (field,) = record.fields().collect_tuple()?;
 +            let name = field.name()?.to_string();
 +            let ty = field.ty()?;
-     let fn_name =
-         format!("{}_{}", props.fn_name_prefix, &to_lower_snake_case(&variant_name.text()));
++            let pattern_suffix = format!(" {{ {name} }}");
 +            (pattern_suffix, ty, name)
 +        }
 +        ast::StructKind::Tuple(tuple) => {
 +            let (field,) = tuple.fields().collect_tuple()?;
 +            let ty = field.ty()?;
 +            ("(v)".to_owned(), ty, "v".to_owned())
 +        }
 +        ast::StructKind::Unit => return None,
 +    };
 +
-     let impl_def = find_struct_impl(ctx, &parent_enum, &fn_name)?;
++    let fn_name = format!("{}_{}", fn_name_prefix, &to_lower_snake_case(&variant_name.text()));
 +
 +    // Return early if we've found an existing new fn
-             let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
++    let impl_def = find_struct_impl(ctx, &parent_enum, &[fn_name.clone()])?;
 +
 +    let target = variant.syntax().text_range();
 +    acc.add_group(
 +        &GroupLabel("Generate an `is_`,`as_`, or `try_into_` for this enum variant".to_owned()),
 +        AssistId(assist_id, AssistKind::Generate),
 +        assist_description,
 +        target,
 +        |builder| {
-                 "    {0}fn {1}({2}) -> {3}{4}{5} {{
-         if let Self::{6}{7} = self {{
-             {8}({9})
++            let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{v} "));
 +            let method = format!(
-             {10}
++                "    {vis}fn {fn_name}({self_param}) -> {return_prefix}{field_type}{return_suffix} {{
++        if let Self::{variant_name}{pattern_suffix} = self {{
++            {happy_case}({bound_name})
 +        }} else {{
-     }}",
-                 vis,
-                 fn_name,
-                 props.self_param,
-                 props.return_prefix,
-                 field_type.syntax(),
-                 props.return_suffix,
-                 variant_name,
-                 pattern_suffix,
-                 props.happy_case,
-                 bound_name,
-                 props.sad_case,
-             );
++            {sad_case}
 +        }}
++    }}");
 +
 +            add_method_to_adt(builder, &parent_enum, impl_def, &method);
 +        },
 +    )
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_generate_enum_try_into_tuple_variant() {
 +        check_assist(
 +            generate_enum_try_into_method,
 +            r#"
 +enum Value {
 +    Number(i32),
 +    Text(String)$0,
 +}"#,
 +            r#"enum Value {
 +    Number(i32),
 +    Text(String),
 +}
 +
 +impl Value {
 +    fn try_into_text(self) -> Result<String, Self> {
 +        if let Self::Text(v) = self {
 +            Ok(v)
 +        } else {
 +            Err(self)
 +        }
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_enum_try_into_already_implemented() {
 +        check_assist_not_applicable(
 +            generate_enum_try_into_method,
 +            r#"enum Value {
 +    Number(i32),
 +    Text(String)$0,
 +}
 +
 +impl Value {
 +    fn try_into_text(self) -> Result<String, Self> {
 +        if let Self::Text(v) = self {
 +            Ok(v)
 +        } else {
 +            Err(self)
 +        }
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_enum_try_into_unit_variant() {
 +        check_assist_not_applicable(
 +            generate_enum_try_into_method,
 +            r#"enum Value {
 +    Number(i32),
 +    Text(String),
 +    Unit$0,
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_enum_try_into_record_with_multiple_fields() {
 +        check_assist_not_applicable(
 +            generate_enum_try_into_method,
 +            r#"enum Value {
 +    Number(i32),
 +    Text(String),
 +    Both { first: i32, second: String }$0,
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_enum_try_into_tuple_with_multiple_fields() {
 +        check_assist_not_applicable(
 +            generate_enum_try_into_method,
 +            r#"enum Value {
 +    Number(i32),
 +    Text(String, String)$0,
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_enum_try_into_record_variant() {
 +        check_assist(
 +            generate_enum_try_into_method,
 +            r#"enum Value {
 +    Number(i32),
 +    Text { text: String }$0,
 +}"#,
 +            r#"enum Value {
 +    Number(i32),
 +    Text { text: String },
 +}
 +
 +impl Value {
 +    fn try_into_text(self) -> Result<String, Self> {
 +        if let Self::Text { text } = self {
 +            Ok(text)
 +        } else {
 +            Err(self)
 +        }
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_enum_as_tuple_variant() {
 +        check_assist(
 +            generate_enum_as_method,
 +            r#"
 +enum Value {
 +    Number(i32),
 +    Text(String)$0,
 +}"#,
 +            r#"enum Value {
 +    Number(i32),
 +    Text(String),
 +}
 +
 +impl Value {
 +    fn as_text(&self) -> Option<&String> {
 +        if let Self::Text(v) = self {
 +            Some(v)
 +        } else {
 +            None
 +        }
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_enum_as_record_variant() {
 +        check_assist(
 +            generate_enum_as_method,
 +            r#"enum Value {
 +    Number(i32),
 +    Text { text: String }$0,
 +}"#,
 +            r#"enum Value {
 +    Number(i32),
 +    Text { text: String },
 +}
 +
 +impl Value {
 +    fn as_text(&self) -> Option<&String> {
 +        if let Self::Text { text } = self {
 +            Some(text)
 +        } else {
 +            None
 +        }
 +    }
 +}"#,
 +        );
 +    }
 +}
index 507ea012babfc431fcd184f8eff266d9ca580fe2,0000000000000000000000000000000000000000..7c81d2c6a6cc9b3767861f94fa1849f10a2edfe7
mode 100644,000000..100644
--- /dev/null
@@@ -1,310 -1,0 +1,305 @@@
-             let from_trait = format!("From<{}>", field_type.syntax());
 +use ide_db::{famous_defs::FamousDefs, RootDatabase};
 +use syntax::ast::{self, AstNode, HasName};
 +
 +use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists};
 +
 +// Assist: generate_from_impl_for_enum
 +//
 +// Adds a From impl for this enum variant with one tuple field.
 +//
 +// ```
 +// enum A { $0One(u32) }
 +// ```
 +// ->
 +// ```
 +// enum A { One(u32) }
 +//
 +// impl From<u32> for A {
 +//     fn from(v: u32) -> Self {
 +//         Self::One(v)
 +//     }
 +// }
 +// ```
 +pub(crate) fn generate_from_impl_for_enum(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +) -> Option<()> {
 +    let variant = ctx.find_node_at_offset::<ast::Variant>()?;
 +    let variant_name = variant.name()?;
 +    let enum_ = ast::Adt::Enum(variant.parent_enum());
 +    let (field_name, field_type) = match variant.kind() {
 +        ast::StructKind::Tuple(field_list) => {
 +            if field_list.fields().count() != 1 {
 +                return None;
 +            }
 +            (None, field_list.fields().next()?.ty()?)
 +        }
 +        ast::StructKind::Record(field_list) => {
 +            if field_list.fields().count() != 1 {
 +                return None;
 +            }
 +            let field = field_list.fields().next()?;
 +            (Some(field.name()?), field.ty()?)
 +        }
 +        ast::StructKind::Unit => return None,
 +    };
 +
 +    if existing_from_impl(&ctx.sema, &variant).is_some() {
 +        cov_mark::hit!(test_add_from_impl_already_exists);
 +        return None;
 +    }
 +
 +    let target = variant.syntax().text_range();
 +    acc.add(
 +        AssistId("generate_from_impl_for_enum", AssistKind::Generate),
 +        "Generate `From` impl for this enum variant",
 +        target,
 +        |edit| {
 +            let start_offset = variant.parent_enum().syntax().text_range().end();
-                     r#"    fn from({0}: {1}) -> Self {{
-         Self::{2} {{ {0} }}
-     }}"#,
-                     name.text(),
-                     field_type.syntax(),
-                     variant_name,
++            let from_trait = format!("From<{field_type}>");
 +            let impl_code = if let Some(name) = field_name {
 +                format!(
-                     r#"    fn from(v: {}) -> Self {{
-         Self::{}(v)
-     }}"#,
-                     field_type.syntax(),
-                     variant_name,
++                    r#"    fn from({name}: {field_type}) -> Self {{
++        Self::{variant_name} {{ {name} }}
++    }}"#
 +                )
 +            } else {
 +                format!(
++                    r#"    fn from(v: {field_type}) -> Self {{
++        Self::{variant_name}(v)
++    }}"#
 +                )
 +            };
 +            let from_impl = generate_trait_impl_text(&enum_, &from_trait, &impl_code);
 +            edit.insert(start_offset, from_impl);
 +        },
 +    )
 +}
 +
 +fn existing_from_impl(
 +    sema: &'_ hir::Semantics<'_, RootDatabase>,
 +    variant: &ast::Variant,
 +) -> Option<()> {
 +    let variant = sema.to_def(variant)?;
 +    let enum_ = variant.parent_enum(sema.db);
 +    let krate = enum_.module(sema.db).krate();
 +
 +    let from_trait = FamousDefs(sema, krate).core_convert_From()?;
 +
 +    let enum_type = enum_.ty(sema.db);
 +
 +    let wrapped_type = variant.fields(sema.db).get(0)?.ty(sema.db);
 +
 +    if enum_type.impls_trait(sema.db, from_trait, &[wrapped_type]) {
 +        Some(())
 +    } else {
 +        None
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_generate_from_impl_for_enum() {
 +        check_assist(
 +            generate_from_impl_for_enum,
 +            r#"
 +//- minicore: from
 +enum A { $0One(u32) }
 +"#,
 +            r#"
 +enum A { One(u32) }
 +
 +impl From<u32> for A {
 +    fn from(v: u32) -> Self {
 +        Self::One(v)
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_from_impl_for_enum_complicated_path() {
 +        check_assist(
 +            generate_from_impl_for_enum,
 +            r#"
 +//- minicore: from
 +enum A { $0One(foo::bar::baz::Boo) }
 +"#,
 +            r#"
 +enum A { One(foo::bar::baz::Boo) }
 +
 +impl From<foo::bar::baz::Boo> for A {
 +    fn from(v: foo::bar::baz::Boo) -> Self {
 +        Self::One(v)
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_add_from_impl_no_element() {
 +        check_assist_not_applicable(
 +            generate_from_impl_for_enum,
 +            r#"
 +//- minicore: from
 +enum A { $0One }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_add_from_impl_more_than_one_element_in_tuple() {
 +        check_assist_not_applicable(
 +            generate_from_impl_for_enum,
 +            r#"
 +//- minicore: from
 +enum A { $0One(u32, String) }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_add_from_impl_struct_variant() {
 +        check_assist(
 +            generate_from_impl_for_enum,
 +            r#"
 +//- minicore: from
 +enum A { $0One { x: u32 } }
 +"#,
 +            r#"
 +enum A { One { x: u32 } }
 +
 +impl From<u32> for A {
 +    fn from(x: u32) -> Self {
 +        Self::One { x }
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_add_from_impl_already_exists() {
 +        cov_mark::check!(test_add_from_impl_already_exists);
 +        check_assist_not_applicable(
 +            generate_from_impl_for_enum,
 +            r#"
 +//- minicore: from
 +enum A { $0One(u32), }
 +
 +impl From<u32> for A {
 +    fn from(v: u32) -> Self {
 +        Self::One(v)
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_add_from_impl_different_variant_impl_exists() {
 +        check_assist(
 +            generate_from_impl_for_enum,
 +            r#"
 +//- minicore: from
 +enum A { $0One(u32), Two(String), }
 +
 +impl From<String> for A {
 +    fn from(v: String) -> Self {
 +        A::Two(v)
 +    }
 +}
 +
 +pub trait From<T> {
 +    fn from(T) -> Self;
 +}
 +"#,
 +            r#"
 +enum A { One(u32), Two(String), }
 +
 +impl From<u32> for A {
 +    fn from(v: u32) -> Self {
 +        Self::One(v)
 +    }
 +}
 +
 +impl From<String> for A {
 +    fn from(v: String) -> Self {
 +        A::Two(v)
 +    }
 +}
 +
 +pub trait From<T> {
 +    fn from(T) -> Self;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_add_from_impl_static_str() {
 +        check_assist(
 +            generate_from_impl_for_enum,
 +            r#"
 +//- minicore: from
 +enum A { $0One(&'static str) }
 +"#,
 +            r#"
 +enum A { One(&'static str) }
 +
 +impl From<&'static str> for A {
 +    fn from(v: &'static str) -> Self {
 +        Self::One(v)
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_add_from_impl_generic_enum() {
 +        check_assist(
 +            generate_from_impl_for_enum,
 +            r#"
 +//- minicore: from
 +enum Generic<T, U: Clone> { $0One(T), Two(U) }
 +"#,
 +            r#"
 +enum Generic<T, U: Clone> { One(T), Two(U) }
 +
 +impl<T, U: Clone> From<T> for Generic<T, U> {
 +    fn from(v: T) -> Self {
 +        Self::One(v)
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_add_from_impl_with_lifetime() {
 +        check_assist(
 +            generate_from_impl_for_enum,
 +            r#"
 +//- minicore: from
 +enum Generic<'a> { $0One(&'a i32) }
 +"#,
 +            r#"
 +enum Generic<'a> { One(&'a i32) }
 +
 +impl<'a> From<&'a i32> for Generic<'a> {
 +    fn from(v: &'a i32) -> Self {
 +        Self::One(v)
 +    }
 +}
 +"#,
 +        );
 +    }
 +}
index 8b67982f9158234b91afa04bf28c691b543b2d10,0000000000000000000000000000000000000000..c229127e48ffca348a66a7d56a54b75e8cb34c0a
mode 100644,000000..100644
--- /dev/null
@@@ -1,1848 -1,0 +1,1852 @@@
-             func = format!("\n{}impl {} {{\n{}\n{}}}", indent, name, func, indent);
 +use hir::{Adt, HasSource, HirDisplay, Module, Semantics, TypeInfo};
 +use ide_db::{
 +    base_db::FileId,
 +    defs::{Definition, NameRefClass},
 +    famous_defs::FamousDefs,
 +    FxHashMap, FxHashSet, RootDatabase, SnippetCap,
 +};
 +use stdx::to_lower_snake_case;
 +use syntax::{
 +    ast::{
 +        self,
 +        edit::{AstNodeEdit, IndentLevel},
 +        make, AstNode, CallExpr, HasArgList, HasModuleItem,
 +    },
 +    SyntaxKind, SyntaxNode, TextRange, TextSize,
 +};
 +
 +use crate::{
 +    utils::convert_reference_type,
 +    utils::{find_struct_impl, render_snippet, Cursor},
 +    AssistContext, AssistId, AssistKind, Assists,
 +};
 +
 +// Assist: generate_function
 +//
 +// Adds a stub function with a signature matching the function under the cursor.
 +//
 +// ```
 +// struct Baz;
 +// fn baz() -> Baz { Baz }
 +// fn foo() {
 +//     bar$0("", baz());
 +// }
 +//
 +// ```
 +// ->
 +// ```
 +// struct Baz;
 +// fn baz() -> Baz { Baz }
 +// fn foo() {
 +//     bar("", baz());
 +// }
 +//
 +// fn bar(arg: &str, baz: Baz) ${0:-> _} {
 +//     todo!()
 +// }
 +//
 +// ```
 +pub(crate) fn generate_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    gen_fn(acc, ctx).or_else(|| gen_method(acc, ctx))
 +}
 +
 +fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
 +    let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
 +    let path = path_expr.path()?;
 +    let name_ref = path.segment()?.name_ref()?;
 +    if ctx.sema.resolve_path(&path).is_some() {
 +        // The function call already resolves, no need to add a function
 +        return None;
 +    }
 +
 +    let fn_name = &*name_ref.text();
 +    let TargetInfo { target_module, adt_name, target, file, insert_offset } =
 +        fn_target_info(ctx, path, &call, fn_name)?;
 +    let function_builder = FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target)?;
 +    let text_range = call.syntax().text_range();
 +    let label = format!("Generate {} function", function_builder.fn_name);
 +    add_func_to_accumulator(
 +        acc,
 +        ctx,
 +        text_range,
 +        function_builder,
 +        insert_offset,
 +        file,
 +        adt_name,
 +        label,
 +    )
 +}
 +
 +struct TargetInfo {
 +    target_module: Option<Module>,
 +    adt_name: Option<hir::Name>,
 +    target: GeneratedFunctionTarget,
 +    file: FileId,
 +    insert_offset: TextSize,
 +}
 +
 +impl TargetInfo {
 +    fn new(
 +        target_module: Option<Module>,
 +        adt_name: Option<hir::Name>,
 +        target: GeneratedFunctionTarget,
 +        file: FileId,
 +        insert_offset: TextSize,
 +    ) -> Self {
 +        Self { target_module, adt_name, target, file, insert_offset }
 +    }
 +}
 +
 +fn fn_target_info(
 +    ctx: &AssistContext<'_>,
 +    path: ast::Path,
 +    call: &CallExpr,
 +    fn_name: &str,
 +) -> Option<TargetInfo> {
 +    match path.qualifier() {
 +        Some(qualifier) => match ctx.sema.resolve_path(&qualifier) {
 +            Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => {
 +                get_fn_target_info(ctx, &Some(module), call.clone())
 +            }
 +            Some(hir::PathResolution::Def(hir::ModuleDef::Adt(adt))) => {
 +                if let hir::Adt::Enum(_) = adt {
 +                    // Don't suggest generating function if the name starts with an uppercase letter
 +                    if fn_name.starts_with(char::is_uppercase) {
 +                        return None;
 +                    }
 +                }
 +
 +                assoc_fn_target_info(ctx, call, adt, fn_name)
 +            }
 +            Some(hir::PathResolution::SelfType(impl_)) => {
 +                let adt = impl_.self_ty(ctx.db()).as_adt()?;
 +                assoc_fn_target_info(ctx, call, adt, fn_name)
 +            }
 +            _ => None,
 +        },
 +        _ => get_fn_target_info(ctx, &None, call.clone()),
 +    }
 +}
 +
 +fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
 +    if ctx.sema.resolve_method_call(&call).is_some() {
 +        return None;
 +    }
 +
 +    let fn_name = call.name_ref()?;
 +    let adt = ctx.sema.type_of_expr(&call.receiver()?)?.original().strip_references().as_adt()?;
 +
 +    let current_module = ctx.sema.scope(call.syntax())?.module();
 +    let target_module = adt.module(ctx.sema.db);
 +
 +    if current_module.krate() != target_module.krate() {
 +        return None;
 +    }
 +    let (impl_, file) = get_adt_source(ctx, &adt, fn_name.text().as_str())?;
 +    let (target, insert_offset) = get_method_target(ctx, &impl_, &adt)?;
 +
 +    let function_builder =
 +        FunctionBuilder::from_method_call(ctx, &call, &fn_name, target_module, target)?;
 +    let text_range = call.syntax().text_range();
 +    let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
 +    let label = format!("Generate {} method", function_builder.fn_name);
 +    add_func_to_accumulator(
 +        acc,
 +        ctx,
 +        text_range,
 +        function_builder,
 +        insert_offset,
 +        file,
 +        adt_name,
 +        label,
 +    )
 +}
 +
 +fn add_func_to_accumulator(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +    text_range: TextRange,
 +    function_builder: FunctionBuilder,
 +    insert_offset: TextSize,
 +    file: FileId,
 +    adt_name: Option<hir::Name>,
 +    label: String,
 +) -> Option<()> {
 +    acc.add(AssistId("generate_function", AssistKind::Generate), label, text_range, |builder| {
 +        let indent = IndentLevel::from_node(function_builder.target.syntax());
 +        let function_template = function_builder.render(adt_name.is_some());
 +        let mut func = function_template.to_string(ctx.config.snippet_cap);
 +        if let Some(name) = adt_name {
-     find_struct_impl(ctx, &adt_source, fn_name).map(|impl_| (impl_, range.file_id))
++            func = format!("\n{indent}impl {name} {{\n{func}\n{indent}}}");
 +        }
 +        builder.edit_file(file);
 +        match ctx.config.snippet_cap {
 +            Some(cap) => builder.insert_snippet(cap, insert_offset, func),
 +            None => builder.insert(insert_offset, func),
 +        }
 +    })
 +}
 +
 +fn get_adt_source(
 +    ctx: &AssistContext<'_>,
 +    adt: &hir::Adt,
 +    fn_name: &str,
 +) -> Option<(Option<ast::Impl>, FileId)> {
 +    let range = adt.source(ctx.sema.db)?.syntax().original_file_range(ctx.sema.db);
 +    let file = ctx.sema.parse(range.file_id);
 +    let adt_source =
 +        ctx.sema.find_node_at_offset_with_macros(file.syntax(), range.range.start())?;
-                 let cursor = if self.should_focus_return_type {
++    find_struct_impl(ctx, &adt_source, &[fn_name.to_string()]).map(|impl_| (impl_, range.file_id))
 +}
 +
 +struct FunctionTemplate {
 +    leading_ws: String,
 +    fn_def: ast::Fn,
 +    ret_type: Option<ast::RetType>,
 +    should_focus_return_type: bool,
 +    trailing_ws: String,
 +    tail_expr: ast::Expr,
 +}
 +
 +impl FunctionTemplate {
 +    fn to_string(&self, cap: Option<SnippetCap>) -> String {
++        let Self { leading_ws, fn_def, ret_type, should_focus_return_type, trailing_ws, tail_expr } =
++            self;
++
 +        let f = match cap {
 +            Some(cap) => {
-                     match self.ret_type {
-                         Some(ref ret_type) => ret_type.syntax(),
-                         None => self.tail_expr.syntax(),
++                let cursor = if *should_focus_return_type {
 +                    // Focus the return type if there is one
-                     self.tail_expr.syntax()
++                    match ret_type {
++                        Some(ret_type) => ret_type.syntax(),
++                        None => tail_expr.syntax(),
 +                    }
 +                } else {
-                 render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(cursor))
++                    tail_expr.syntax()
 +                };
-             None => self.fn_def.to_string(),
++                render_snippet(cap, fn_def.syntax(), Cursor::Replace(cursor))
 +            }
-         format!("{}{}{}", self.leading_ws, f, self.trailing_ws)
++            None => fn_def.to_string(),
 +        };
 +
-                     leading_ws = format!("{}", indent);
++        format!("{leading_ws}{f}{trailing_ws}")
 +    }
 +}
 +
 +struct FunctionBuilder {
 +    target: GeneratedFunctionTarget,
 +    fn_name: ast::Name,
 +    type_params: Option<ast::GenericParamList>,
 +    params: ast::ParamList,
 +    ret_type: Option<ast::RetType>,
 +    should_focus_return_type: bool,
 +    needs_pub: bool,
 +    is_async: bool,
 +}
 +
 +impl FunctionBuilder {
 +    /// Prepares a generated function that matches `call`.
 +    /// The function is generated in `target_module` or next to `call`
 +    fn from_call(
 +        ctx: &AssistContext<'_>,
 +        call: &ast::CallExpr,
 +        fn_name: &str,
 +        target_module: Option<hir::Module>,
 +        target: GeneratedFunctionTarget,
 +    ) -> Option<Self> {
 +        let needs_pub = target_module.is_some();
 +        let target_module =
 +            target_module.or_else(|| ctx.sema.scope(target.syntax()).map(|it| it.module()))?;
 +        let fn_name = make::name(fn_name);
 +        let (type_params, params) =
 +            fn_args(ctx, target_module, ast::CallableExpr::Call(call.clone()))?;
 +
 +        let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast);
 +        let is_async = await_expr.is_some();
 +
 +        let (ret_type, should_focus_return_type) =
 +            make_return_type(ctx, &ast::Expr::CallExpr(call.clone()), target_module);
 +
 +        Some(Self {
 +            target,
 +            fn_name,
 +            type_params,
 +            params,
 +            ret_type,
 +            should_focus_return_type,
 +            needs_pub,
 +            is_async,
 +        })
 +    }
 +
 +    fn from_method_call(
 +        ctx: &AssistContext<'_>,
 +        call: &ast::MethodCallExpr,
 +        name: &ast::NameRef,
 +        target_module: Module,
 +        target: GeneratedFunctionTarget,
 +    ) -> Option<Self> {
 +        let needs_pub =
 +            !module_is_descendant(&ctx.sema.scope(call.syntax())?.module(), &target_module, ctx);
 +        let fn_name = make::name(&name.text());
 +        let (type_params, params) =
 +            fn_args(ctx, target_module, ast::CallableExpr::MethodCall(call.clone()))?;
 +
 +        let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast);
 +        let is_async = await_expr.is_some();
 +
 +        let (ret_type, should_focus_return_type) =
 +            make_return_type(ctx, &ast::Expr::MethodCallExpr(call.clone()), target_module);
 +
 +        Some(Self {
 +            target,
 +            fn_name,
 +            type_params,
 +            params,
 +            ret_type,
 +            should_focus_return_type,
 +            needs_pub,
 +            is_async,
 +        })
 +    }
 +
 +    fn render(self, is_method: bool) -> FunctionTemplate {
 +        let placeholder_expr = make::ext::expr_todo();
 +        let fn_body = make::block_expr(vec![], Some(placeholder_expr));
 +        let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None };
 +        let mut fn_def = make::fn_(
 +            visibility,
 +            self.fn_name,
 +            self.type_params,
 +            self.params,
 +            fn_body,
 +            self.ret_type,
 +            self.is_async,
 +        );
 +        let leading_ws;
 +        let trailing_ws;
 +
 +        match self.target {
 +            GeneratedFunctionTarget::BehindItem(it) => {
 +                let mut indent = IndentLevel::from_node(&it);
 +                if is_method {
 +                    indent = indent + 1;
-                     leading_ws = format!("\n\n{}", indent);
++                    leading_ws = format!("{indent}");
 +                } else {
-                 leading_ws = format!("\n{}", indent + 1);
-                 fn_def = fn_def.indent(indent + 1);
-                 trailing_ws = format!("\n{}", indent);
++                    leading_ws = format!("\n\n{indent}");
 +                }
 +
 +                fn_def = fn_def.indent(indent);
 +                trailing_ws = String::new();
 +            }
 +            GeneratedFunctionTarget::InEmptyItemList(it) => {
 +                let indent = IndentLevel::from_node(&it);
++                let leading_indent = indent + 1;
++                leading_ws = format!("\n{leading_indent}");
++                fn_def = fn_def.indent(leading_indent);
++                trailing_ws = format!("\n{indent}");
 +            }
 +        };
 +
 +        FunctionTemplate {
 +            leading_ws,
 +            ret_type: fn_def.ret_type(),
 +            // PANIC: we guarantee we always create a function body with a tail expr
 +            tail_expr: fn_def.body().unwrap().tail_expr().unwrap(),
 +            should_focus_return_type: self.should_focus_return_type,
 +            fn_def,
 +            trailing_ws,
 +        }
 +    }
 +}
 +
 +/// Makes an optional return type along with whether the return type should be focused by the cursor.
 +/// If we cannot infer what the return type should be, we create a placeholder type.
 +///
 +/// The rule for whether we focus a return type or not (and thus focus the function body),
 +/// is rather simple:
 +/// * If we could *not* infer what the return type should be, focus it (so the user can fill-in
 +/// the correct return type).
 +/// * If we could infer the return type, don't focus it (and thus focus the function body) so the
 +/// user can change the `todo!` function body.
 +fn make_return_type(
 +    ctx: &AssistContext<'_>,
 +    call: &ast::Expr,
 +    target_module: Module,
 +) -> (Option<ast::RetType>, bool) {
 +    let (ret_ty, should_focus_return_type) = {
 +        match ctx.sema.type_of_expr(call).map(TypeInfo::original) {
 +            Some(ty) if ty.is_unknown() => (Some(make::ty_placeholder()), true),
 +            None => (Some(make::ty_placeholder()), true),
 +            Some(ty) if ty.is_unit() => (None, false),
 +            Some(ty) => {
 +                let rendered = ty.display_source_code(ctx.db(), target_module.into());
 +                match rendered {
 +                    Ok(rendered) => (Some(make::ty(&rendered)), false),
 +                    Err(_) => (Some(make::ty_placeholder()), true),
 +                }
 +            }
 +        }
 +    };
 +    let ret_type = ret_ty.map(make::ret_type);
 +    (ret_type, should_focus_return_type)
 +}
 +
 +fn get_fn_target_info(
 +    ctx: &AssistContext<'_>,
 +    target_module: &Option<Module>,
 +    call: CallExpr,
 +) -> Option<TargetInfo> {
 +    let (target, file, insert_offset) = get_fn_target(ctx, target_module, call)?;
 +    Some(TargetInfo::new(*target_module, None, target, file, insert_offset))
 +}
 +
 +fn get_fn_target(
 +    ctx: &AssistContext<'_>,
 +    target_module: &Option<Module>,
 +    call: CallExpr,
 +) -> Option<(GeneratedFunctionTarget, FileId, TextSize)> {
 +    let mut file = ctx.file_id();
 +    let target = match target_module {
 +        Some(target_module) => {
 +            let module_source = target_module.definition_source(ctx.db());
 +            let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, &module_source)?;
 +            file = in_file;
 +            target
 +        }
 +        None => next_space_for_fn_after_call_site(ast::CallableExpr::Call(call))?,
 +    };
 +    Some((target.clone(), file, get_insert_offset(&target)))
 +}
 +
 +fn get_method_target(
 +    ctx: &AssistContext<'_>,
 +    impl_: &Option<ast::Impl>,
 +    adt: &Adt,
 +) -> Option<(GeneratedFunctionTarget, TextSize)> {
 +    let target = match impl_ {
 +        Some(impl_) => next_space_for_fn_in_impl(impl_)?,
 +        None => {
 +            GeneratedFunctionTarget::BehindItem(adt.source(ctx.sema.db)?.syntax().value.clone())
 +        }
 +    };
 +    Some((target.clone(), get_insert_offset(&target)))
 +}
 +
 +fn assoc_fn_target_info(
 +    ctx: &AssistContext<'_>,
 +    call: &CallExpr,
 +    adt: hir::Adt,
 +    fn_name: &str,
 +) -> Option<TargetInfo> {
 +    let current_module = ctx.sema.scope(call.syntax())?.module();
 +    let module = adt.module(ctx.sema.db);
 +    let target_module = if current_module == module { None } else { Some(module) };
 +    if current_module.krate() != module.krate() {
 +        return None;
 +    }
 +    let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?;
 +    let (target, insert_offset) = get_method_target(ctx, &impl_, &adt)?;
 +    let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
 +    Some(TargetInfo::new(target_module, adt_name, target, file, insert_offset))
 +}
 +
 +fn get_insert_offset(target: &GeneratedFunctionTarget) -> TextSize {
 +    match &target {
 +        GeneratedFunctionTarget::BehindItem(it) => it.text_range().end(),
 +        GeneratedFunctionTarget::InEmptyItemList(it) => it.text_range().start() + TextSize::of('{'),
 +    }
 +}
 +
 +#[derive(Clone)]
 +enum GeneratedFunctionTarget {
 +    BehindItem(SyntaxNode),
 +    InEmptyItemList(SyntaxNode),
 +}
 +
 +impl GeneratedFunctionTarget {
 +    fn syntax(&self) -> &SyntaxNode {
 +        match self {
 +            GeneratedFunctionTarget::BehindItem(it) => it,
 +            GeneratedFunctionTarget::InEmptyItemList(it) => it,
 +        }
 +    }
 +}
 +
 +/// Computes the type variables and arguments required for the generated function
 +fn fn_args(
 +    ctx: &AssistContext<'_>,
 +    target_module: hir::Module,
 +    call: ast::CallableExpr,
 +) -> Option<(Option<ast::GenericParamList>, ast::ParamList)> {
 +    let mut arg_names = Vec::new();
 +    let mut arg_types = Vec::new();
 +    for arg in call.arg_list()?.args() {
 +        arg_names.push(fn_arg_name(&ctx.sema, &arg));
 +        arg_types.push(fn_arg_type(ctx, target_module, &arg));
 +    }
 +    deduplicate_arg_names(&mut arg_names);
 +    let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| {
 +        make::param(make::ext::simple_ident_pat(make::name(&name)).into(), make::ty(&ty))
 +    });
 +
 +    Some((
 +        None,
 +        make::param_list(
 +            match call {
 +                ast::CallableExpr::Call(_) => None,
 +                ast::CallableExpr::MethodCall(_) => Some(make::self_param()),
 +            },
 +            params,
 +        ),
 +    ))
 +}
 +
 +/// Makes duplicate argument names unique by appending incrementing numbers.
 +///
 +/// ```
 +/// let mut names: Vec<String> =
 +///     vec!["foo".into(), "foo".into(), "bar".into(), "baz".into(), "bar".into()];
 +/// deduplicate_arg_names(&mut names);
 +/// let expected: Vec<String> =
 +///     vec!["foo_1".into(), "foo_2".into(), "bar_1".into(), "baz".into(), "bar_2".into()];
 +/// assert_eq!(names, expected);
 +/// ```
 +fn deduplicate_arg_names(arg_names: &mut Vec<String>) {
 +    let mut arg_name_counts = FxHashMap::default();
 +    for name in arg_names.iter() {
 +        *arg_name_counts.entry(name).or_insert(0) += 1;
 +    }
 +    let duplicate_arg_names: FxHashSet<String> = arg_name_counts
 +        .into_iter()
 +        .filter(|(_, count)| *count >= 2)
 +        .map(|(name, _)| name.clone())
 +        .collect();
 +
 +    let mut counter_per_name = FxHashMap::default();
 +    for arg_name in arg_names.iter_mut() {
 +        if duplicate_arg_names.contains(arg_name) {
 +            let counter = counter_per_name.entry(arg_name.clone()).or_insert(1);
 +            arg_name.push('_');
 +            arg_name.push_str(&counter.to_string());
 +            *counter += 1;
 +        }
 +    }
 +}
 +
 +fn fn_arg_name(sema: &Semantics<'_, RootDatabase>, arg_expr: &ast::Expr) -> String {
 +    let name = (|| match arg_expr {
 +        ast::Expr::CastExpr(cast_expr) => Some(fn_arg_name(sema, &cast_expr.expr()?)),
 +        expr => {
 +            let name_ref = expr
 +                .syntax()
 +                .descendants()
 +                .filter_map(ast::NameRef::cast)
 +                .filter(|name| name.ident_token().is_some())
 +                .last()?;
 +            if let Some(NameRefClass::Definition(Definition::Const(_) | Definition::Static(_))) =
 +                NameRefClass::classify(sema, &name_ref)
 +            {
 +                return Some(name_ref.to_string().to_lowercase());
 +            };
 +            Some(to_lower_snake_case(&name_ref.to_string()))
 +        }
 +    })();
 +    match name {
 +        Some(mut name) if name.starts_with(|c: char| c.is_ascii_digit()) => {
 +            name.insert_str(0, "arg");
 +            name
 +        }
 +        Some(name) => name,
 +        None => "arg".to_string(),
 +    }
 +}
 +
 +fn fn_arg_type(ctx: &AssistContext<'_>, target_module: hir::Module, fn_arg: &ast::Expr) -> String {
 +    fn maybe_displayed_type(
 +        ctx: &AssistContext<'_>,
 +        target_module: hir::Module,
 +        fn_arg: &ast::Expr,
 +    ) -> Option<String> {
 +        let ty = ctx.sema.type_of_expr(fn_arg)?.adjusted();
 +        if ty.is_unknown() {
 +            return None;
 +        }
 +
 +        if ty.is_reference() || ty.is_mutable_reference() {
 +            let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(fn_arg.syntax())?.krate());
 +            convert_reference_type(ty.strip_references(), ctx.db(), famous_defs)
 +                .map(|conversion| conversion.convert_type(ctx.db()))
 +                .or_else(|| ty.display_source_code(ctx.db(), target_module.into()).ok())
 +        } else {
 +            ty.display_source_code(ctx.db(), target_module.into()).ok()
 +        }
 +    }
 +
 +    maybe_displayed_type(ctx, target_module, fn_arg).unwrap_or_else(|| String::from("_"))
 +}
 +
 +/// Returns the position inside the current mod or file
 +/// directly after the current block
 +/// We want to write the generated function directly after
 +/// fns, impls or macro calls, but inside mods
 +fn next_space_for_fn_after_call_site(expr: ast::CallableExpr) -> Option<GeneratedFunctionTarget> {
 +    let mut ancestors = expr.syntax().ancestors().peekable();
 +    let mut last_ancestor: Option<SyntaxNode> = None;
 +    while let Some(next_ancestor) = ancestors.next() {
 +        match next_ancestor.kind() {
 +            SyntaxKind::SOURCE_FILE => {
 +                break;
 +            }
 +            SyntaxKind::ITEM_LIST => {
 +                if ancestors.peek().map(|a| a.kind()) == Some(SyntaxKind::MODULE) {
 +                    break;
 +                }
 +            }
 +            _ => {}
 +        }
 +        last_ancestor = Some(next_ancestor);
 +    }
 +    last_ancestor.map(GeneratedFunctionTarget::BehindItem)
 +}
 +
 +fn next_space_for_fn_in_module(
 +    db: &dyn hir::db::AstDatabase,
 +    module_source: &hir::InFile<hir::ModuleSource>,
 +) -> Option<(FileId, GeneratedFunctionTarget)> {
 +    let file = module_source.file_id.original_file(db);
 +    let assist_item = match &module_source.value {
 +        hir::ModuleSource::SourceFile(it) => match it.items().last() {
 +            Some(last_item) => GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()),
 +            None => GeneratedFunctionTarget::BehindItem(it.syntax().clone()),
 +        },
 +        hir::ModuleSource::Module(it) => match it.item_list().and_then(|it| it.items().last()) {
 +            Some(last_item) => GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()),
 +            None => GeneratedFunctionTarget::InEmptyItemList(it.item_list()?.syntax().clone()),
 +        },
 +        hir::ModuleSource::BlockExpr(it) => {
 +            if let Some(last_item) =
 +                it.statements().take_while(|stmt| matches!(stmt, ast::Stmt::Item(_))).last()
 +            {
 +                GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())
 +            } else {
 +                GeneratedFunctionTarget::InEmptyItemList(it.syntax().clone())
 +            }
 +        }
 +    };
 +    Some((file, assist_item))
 +}
 +
 +fn next_space_for_fn_in_impl(impl_: &ast::Impl) -> Option<GeneratedFunctionTarget> {
 +    if let Some(last_item) = impl_.assoc_item_list().and_then(|it| it.assoc_items().last()) {
 +        Some(GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()))
 +    } else {
 +        Some(GeneratedFunctionTarget::InEmptyItemList(impl_.assoc_item_list()?.syntax().clone()))
 +    }
 +}
 +
 +fn module_is_descendant(module: &hir::Module, ans: &hir::Module, ctx: &AssistContext<'_>) -> bool {
 +    if module == ans {
 +        return true;
 +    }
 +    for c in ans.children(ctx.sema.db) {
 +        if module_is_descendant(module, &c, ctx) {
 +            return true;
 +        }
 +    }
 +    false
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn add_function_with_no_args() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    bar$0();
 +}
 +",
 +            r"
 +fn foo() {
 +    bar();
 +}
 +
 +fn bar() ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_from_method() {
 +        // This ensures that the function is correctly generated
 +        // in the next outer mod or file
 +        check_assist(
 +            generate_function,
 +            r"
 +impl Foo {
 +    fn foo() {
 +        bar$0();
 +    }
 +}
 +",
 +            r"
 +impl Foo {
 +    fn foo() {
 +        bar();
 +    }
 +}
 +
 +fn bar() ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_directly_after_current_block() {
 +        // The new fn should not be created at the end of the file or module
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo1() {
 +    bar$0();
 +}
 +
 +fn foo2() {}
 +",
 +            r"
 +fn foo1() {
 +    bar();
 +}
 +
 +fn bar() ${0:-> _} {
 +    todo!()
 +}
 +
 +fn foo2() {}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_no_args_in_same_module() {
 +        check_assist(
 +            generate_function,
 +            r"
 +mod baz {
 +    fn foo() {
 +        bar$0();
 +    }
 +}
 +",
 +            r"
 +mod baz {
 +    fn foo() {
 +        bar();
 +    }
 +
 +    fn bar() ${0:-> _} {
 +        todo!()
 +    }
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_upper_camel_case_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct BazBaz;
 +fn foo() {
 +    bar$0(BazBaz);
 +}
 +",
 +            r"
 +struct BazBaz;
 +fn foo() {
 +    bar(BazBaz);
 +}
 +
 +fn bar(baz_baz: BazBaz) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn add_function_with_upper_camel_case_arg_as_cast() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct BazBaz;
 +fn foo() {
 +    bar$0(&BazBaz as *const BazBaz);
 +}
 +",
 +            r"
 +struct BazBaz;
 +fn foo() {
 +    bar(&BazBaz as *const BazBaz);
 +}
 +
 +fn bar(baz_baz: *const BazBaz) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn add_function_with_function_call_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct Baz;
 +fn baz() -> Baz { todo!() }
 +fn foo() {
 +    bar$0(baz());
 +}
 +",
 +            r"
 +struct Baz;
 +fn baz() -> Baz { todo!() }
 +fn foo() {
 +    bar(baz());
 +}
 +
 +fn bar(baz: Baz) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn add_function_with_method_call_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct Baz;
 +impl Baz {
 +    fn foo(&self) -> Baz {
 +        ba$0r(self.baz())
 +    }
 +    fn baz(&self) -> Baz {
 +        Baz
 +    }
 +}
 +",
 +            r"
 +struct Baz;
 +impl Baz {
 +    fn foo(&self) -> Baz {
 +        bar(self.baz())
 +    }
 +    fn baz(&self) -> Baz {
 +        Baz
 +    }
 +}
 +
 +fn bar(baz: Baz) -> Baz {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_string_literal_arg() {
 +        check_assist(
 +            generate_function,
 +            r#"
 +fn foo() {
 +    $0bar("bar")
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    bar("bar")
 +}
 +
 +fn bar(arg: &str) {
 +    ${0:todo!()}
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_char_literal_arg() {
 +        check_assist(
 +            generate_function,
 +            r#"
 +fn foo() {
 +    $0bar('x')
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    bar('x')
 +}
 +
 +fn bar(arg: char) {
 +    ${0:todo!()}
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_int_literal_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    $0bar(42)
 +}
 +",
 +            r"
 +fn foo() {
 +    bar(42)
 +}
 +
 +fn bar(arg: i32) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_cast_int_literal_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    $0bar(42 as u8)
 +}
 +",
 +            r"
 +fn foo() {
 +    bar(42 as u8)
 +}
 +
 +fn bar(arg: u8) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn name_of_cast_variable_is_used() {
 +        // Ensures that the name of the cast type isn't used
 +        // in the generated function signature.
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    let x = 42;
 +    bar$0(x as u8)
 +}
 +",
 +            r"
 +fn foo() {
 +    let x = 42;
 +    bar(x as u8)
 +}
 +
 +fn bar(x: u8) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_variable_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    let worble = ();
 +    $0bar(worble)
 +}
 +",
 +            r"
 +fn foo() {
 +    let worble = ();
 +    bar(worble)
 +}
 +
 +fn bar(worble: ()) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_impl_trait_arg() {
 +        check_assist(
 +            generate_function,
 +            r#"
 +//- minicore: sized
 +trait Foo {}
 +fn foo() -> impl Foo {
 +    todo!()
 +}
 +fn baz() {
 +    $0bar(foo())
 +}
 +"#,
 +            r#"
 +trait Foo {}
 +fn foo() -> impl Foo {
 +    todo!()
 +}
 +fn baz() {
 +    bar(foo())
 +}
 +
 +fn bar(foo: impl Foo) {
 +    ${0:todo!()}
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn borrowed_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct Baz;
 +fn baz() -> Baz { todo!() }
 +
 +fn foo() {
 +    bar$0(&baz())
 +}
 +",
 +            r"
 +struct Baz;
 +fn baz() -> Baz { todo!() }
 +
 +fn foo() {
 +    bar(&baz())
 +}
 +
 +fn bar(baz: &Baz) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_qualified_path_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +mod Baz {
 +    pub struct Bof;
 +    pub fn baz() -> Bof { Bof }
 +}
 +fn foo() {
 +    $0bar(Baz::baz())
 +}
 +",
 +            r"
 +mod Baz {
 +    pub struct Bof;
 +    pub fn baz() -> Bof { Bof }
 +}
 +fn foo() {
 +    bar(Baz::baz())
 +}
 +
 +fn bar(baz: Baz::Bof) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_generic_arg() {
 +        // FIXME: This is wrong, generated `bar` should include generic parameter.
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo<T>(t: T) {
 +    $0bar(t)
 +}
 +",
 +            r"
 +fn foo<T>(t: T) {
 +    bar(t)
 +}
 +
 +fn bar(t: T) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_fn_arg() {
 +        // FIXME: The argument in `bar` is wrong.
 +        check_assist(
 +            generate_function,
 +            r"
 +struct Baz;
 +impl Baz {
 +    fn new() -> Self { Baz }
 +}
 +fn foo() {
 +    $0bar(Baz::new);
 +}
 +",
 +            r"
 +struct Baz;
 +impl Baz {
 +    fn new() -> Self { Baz }
 +}
 +fn foo() {
 +    bar(Baz::new);
 +}
 +
 +fn bar(new: fn) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_closure_arg() {
 +        // FIXME: The argument in `bar` is wrong.
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    let closure = |x: i64| x - 1;
 +    $0bar(closure)
 +}
 +",
 +            r"
 +fn foo() {
 +    let closure = |x: i64| x - 1;
 +    bar(closure)
 +}
 +
 +fn bar(closure: _) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn unresolveable_types_default_to_placeholder() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    $0bar(baz)
 +}
 +",
 +            r"
 +fn foo() {
 +    bar(baz)
 +}
 +
 +fn bar(baz: _) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn arg_names_dont_overlap() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct Baz;
 +fn baz() -> Baz { Baz }
 +fn foo() {
 +    $0bar(baz(), baz())
 +}
 +",
 +            r"
 +struct Baz;
 +fn baz() -> Baz { Baz }
 +fn foo() {
 +    bar(baz(), baz())
 +}
 +
 +fn bar(baz_1: Baz, baz_2: Baz) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn arg_name_counters_start_at_1_per_name() {
 +        check_assist(
 +            generate_function,
 +            r#"
 +struct Baz;
 +fn baz() -> Baz { Baz }
 +fn foo() {
 +    $0bar(baz(), baz(), "foo", "bar")
 +}
 +"#,
 +            r#"
 +struct Baz;
 +fn baz() -> Baz { Baz }
 +fn foo() {
 +    bar(baz(), baz(), "foo", "bar")
 +}
 +
 +fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) {
 +    ${0:todo!()}
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_in_module() {
 +        check_assist(
 +            generate_function,
 +            r"
 +mod bar {}
 +
 +fn foo() {
 +    bar::my_fn$0()
 +}
 +",
 +            r"
 +mod bar {
 +    pub(crate) fn my_fn() {
 +        ${0:todo!()}
 +    }
 +}
 +
 +fn foo() {
 +    bar::my_fn()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn qualified_path_uses_correct_scope() {
 +        check_assist(
 +            generate_function,
 +            r#"
 +mod foo {
 +    pub struct Foo;
 +}
 +fn bar() {
 +    use foo::Foo;
 +    let foo = Foo;
 +    baz$0(foo)
 +}
 +"#,
 +            r#"
 +mod foo {
 +    pub struct Foo;
 +}
 +fn bar() {
 +    use foo::Foo;
 +    let foo = Foo;
 +    baz(foo)
 +}
 +
 +fn baz(foo: foo::Foo) {
 +    ${0:todo!()}
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_in_module_containing_other_items() {
 +        check_assist(
 +            generate_function,
 +            r"
 +mod bar {
 +    fn something_else() {}
 +}
 +
 +fn foo() {
 +    bar::my_fn$0()
 +}
 +",
 +            r"
 +mod bar {
 +    fn something_else() {}
 +
 +    pub(crate) fn my_fn() {
 +        ${0:todo!()}
 +    }
 +}
 +
 +fn foo() {
 +    bar::my_fn()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_in_nested_module() {
 +        check_assist(
 +            generate_function,
 +            r"
 +mod bar {
 +    mod baz {}
 +}
 +
 +fn foo() {
 +    bar::baz::my_fn$0()
 +}
 +",
 +            r"
 +mod bar {
 +    mod baz {
 +        pub(crate) fn my_fn() {
 +            ${0:todo!()}
 +        }
 +    }
 +}
 +
 +fn foo() {
 +    bar::baz::my_fn()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_in_another_file() {
 +        check_assist(
 +            generate_function,
 +            r"
 +//- /main.rs
 +mod foo;
 +
 +fn main() {
 +    foo::bar$0()
 +}
 +//- /foo.rs
 +",
 +            r"
 +
 +
 +pub(crate) fn bar() {
 +    ${0:todo!()}
 +}",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_return_type() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn main() {
 +    let x: u32 = foo$0();
 +}
 +",
 +            r"
 +fn main() {
 +    let x: u32 = foo();
 +}
 +
 +fn foo() -> u32 {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_not_applicable_if_function_already_exists() {
 +        check_assist_not_applicable(
 +            generate_function,
 +            r"
 +fn foo() {
 +    bar$0();
 +}
 +
 +fn bar() {}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_not_applicable_if_unresolved_variable_in_call_is_selected() {
 +        check_assist_not_applicable(
 +            // bar is resolved, but baz isn't.
 +            // The assist is only active if the cursor is on an unresolved path,
 +            // but the assist should only be offered if the path is a function call.
 +            generate_function,
 +            r#"
 +fn foo() {
 +    bar(b$0az);
 +}
 +
 +fn bar(baz: ()) {}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn create_method_with_no_args() {
 +        check_assist(
 +            generate_function,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {
 +        self.bar()$0;
 +    }
 +}
 +"#,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {
 +        self.bar();
 +    }
 +
 +    fn bar(&self) ${0:-> _} {
 +        todo!()
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn create_function_with_async() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    $0bar(42).await();
 +}
 +",
 +            r"
 +fn foo() {
 +    bar(42).await();
 +}
 +
 +async fn bar(arg: i32) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_method() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +fn foo() {S.bar$0();}
 +",
 +            r"
 +struct S;
 +impl S {
 +    fn bar(&self) ${0:-> _} {
 +        todo!()
 +    }
 +}
 +fn foo() {S.bar();}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_method_within_an_impl() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +fn foo() {S.bar$0();}
 +impl S {}
 +
 +",
 +            r"
 +struct S;
 +fn foo() {S.bar();}
 +impl S {
 +    fn bar(&self) ${0:-> _} {
 +        todo!()
 +    }
 +}
 +
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_method_from_different_module() {
 +        check_assist(
 +            generate_function,
 +            r"
 +mod s {
 +    pub struct S;
 +}
 +fn foo() {s::S.bar$0();}
 +",
 +            r"
 +mod s {
 +    pub struct S;
 +    impl S {
 +        pub(crate) fn bar(&self) ${0:-> _} {
 +            todo!()
 +        }
 +    }
 +}
 +fn foo() {s::S.bar();}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_method_from_descendant_module() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +mod s {
 +    fn foo() {
 +        super::S.bar$0();
 +    }
 +}
 +
 +",
 +            r"
 +struct S;
 +impl S {
 +    fn bar(&self) ${0:-> _} {
 +        todo!()
 +    }
 +}
 +mod s {
 +    fn foo() {
 +        super::S.bar();
 +    }
 +}
 +
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_method_with_cursor_anywhere_on_call_expresion() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +fn foo() {$0S.bar();}
 +",
 +            r"
 +struct S;
 +impl S {
 +    fn bar(&self) ${0:-> _} {
 +        todo!()
 +    }
 +}
 +fn foo() {S.bar();}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_static_method() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +fn foo() {S::bar$0();}
 +",
 +            r"
 +struct S;
 +impl S {
 +    fn bar() ${0:-> _} {
 +        todo!()
 +    }
 +}
 +fn foo() {S::bar();}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_static_method_within_an_impl() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +fn foo() {S::bar$0();}
 +impl S {}
 +
 +",
 +            r"
 +struct S;
 +fn foo() {S::bar();}
 +impl S {
 +    fn bar() ${0:-> _} {
 +        todo!()
 +    }
 +}
 +
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_static_method_from_different_module() {
 +        check_assist(
 +            generate_function,
 +            r"
 +mod s {
 +    pub struct S;
 +}
 +fn foo() {s::S::bar$0();}
 +",
 +            r"
 +mod s {
 +    pub struct S;
 +    impl S {
 +        pub(crate) fn bar() ${0:-> _} {
 +            todo!()
 +        }
 +    }
 +}
 +fn foo() {s::S::bar();}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_static_method_with_cursor_anywhere_on_call_expresion() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +fn foo() {$0S::bar();}
 +",
 +            r"
 +struct S;
 +impl S {
 +    fn bar() ${0:-> _} {
 +        todo!()
 +    }
 +}
 +fn foo() {S::bar();}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_static_method_within_an_impl_with_self_syntax() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +impl S {
 +    fn foo(&self) {
 +        Self::bar$0();
 +    }
 +}
 +",
 +            r"
 +struct S;
 +impl S {
 +    fn foo(&self) {
 +        Self::bar();
 +    }
 +
 +    fn bar() ${0:-> _} {
 +        todo!()
 +    }
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn no_panic_on_invalid_global_path() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn main() {
 +    ::foo$0();
 +}
 +",
 +            r"
 +fn main() {
 +    ::foo();
 +}
 +
 +fn foo() ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn handle_tuple_indexing() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn main() {
 +    let a = ((),);
 +    foo$0(a.0);
 +}
 +",
 +            r"
 +fn main() {
 +    let a = ((),);
 +    foo(a.0);
 +}
 +
 +fn foo(a: ()) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_const_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +const VALUE: usize = 0;
 +fn main() {
 +    foo$0(VALUE);
 +}
 +",
 +            r"
 +const VALUE: usize = 0;
 +fn main() {
 +    foo(VALUE);
 +}
 +
 +fn foo(value: usize) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_static_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +static VALUE: usize = 0;
 +fn main() {
 +    foo$0(VALUE);
 +}
 +",
 +            r"
 +static VALUE: usize = 0;
 +fn main() {
 +    foo(VALUE);
 +}
 +
 +fn foo(value: usize) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_static_mut_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +static mut VALUE: usize = 0;
 +fn main() {
 +    foo$0(VALUE);
 +}
 +",
 +            r"
 +static mut VALUE: usize = 0;
 +fn main() {
 +    foo(VALUE);
 +}
 +
 +fn foo(value: usize) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_enum_variant() {
 +        check_assist_not_applicable(
 +            generate_function,
 +            r"
 +enum Foo {}
 +fn main() {
 +    Foo::Bar$0(true)
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn applicable_for_enum_method() {
 +        check_assist(
 +            generate_function,
 +            r"
 +enum Foo {}
 +fn main() {
 +    Foo::new$0();
 +}
 +",
 +            r"
 +enum Foo {}
 +impl Foo {
 +    fn new() ${0:-> _} {
 +        todo!()
 +    }
 +}
 +fn main() {
 +    Foo::new();
 +}
 +",
 +        )
 +    }
 +}
index 76fcef0cad9512a7b823be4cb3bce514923f29f8,0000000000000000000000000000000000000000..5e71914283495e7a44afd3310bb015406285a38c
mode 100644,000000..100644
--- /dev/null
@@@ -1,492 -1,0 +1,711 @@@
- use syntax::ast::{self, AstNode, HasName, HasVisibility};
 +use ide_db::famous_defs::FamousDefs;
 +use stdx::{format_to, to_lower_snake_case};
-     let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
-     let field = ctx.find_node_at_offset::<ast::RecordField>()?;
++use syntax::{
++    ast::{self, AstNode, HasName, HasVisibility},
++    TextRange,
++};
 +
 +use crate::{
 +    utils::{convert_reference_type, find_impl_block_end, find_struct_impl, generate_impl_text},
 +    AssistContext, AssistId, AssistKind, Assists, GroupLabel,
 +};
 +
 +// Assist: generate_getter
 +//
 +// Generate a getter method.
 +//
 +// ```
 +// # //- minicore: as_ref
 +// # pub struct String;
 +// # impl AsRef<str> for String {
 +// #     fn as_ref(&self) -> &str {
 +// #         ""
 +// #     }
 +// # }
 +// #
 +// struct Person {
 +//     nam$0e: String,
 +// }
 +// ```
 +// ->
 +// ```
 +// # pub struct String;
 +// # impl AsRef<str> for String {
 +// #     fn as_ref(&self) -> &str {
 +// #         ""
 +// #     }
 +// # }
 +// #
 +// struct Person {
 +//     name: String,
 +// }
 +//
 +// impl Person {
 +//     fn $0name(&self) -> &str {
 +//         self.name.as_ref()
 +//     }
 +// }
 +// ```
 +pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    generate_getter_impl(acc, ctx, false)
 +}
 +
 +// Assist: generate_getter_mut
 +//
 +// Generate a mut getter method.
 +//
 +// ```
 +// struct Person {
 +//     nam$0e: String,
 +// }
 +// ```
 +// ->
 +// ```
 +// struct Person {
 +//     name: String,
 +// }
 +//
 +// impl Person {
 +//     fn $0name_mut(&mut self) -> &mut String {
 +//         &mut self.name
 +//     }
 +// }
 +// ```
 +pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    generate_getter_impl(acc, ctx, true)
 +}
 +
++#[derive(Clone, Debug)]
++struct RecordFieldInfo {
++    field_name: syntax::ast::Name,
++    field_ty: syntax::ast::Type,
++    fn_name: String,
++    target: TextRange,
++}
++
++struct GetterInfo {
++    impl_def: Option<ast::Impl>,
++    strukt: ast::Struct,
++    mutable: bool,
++}
++
 +pub(crate) fn generate_getter_impl(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +    mutable: bool,
 +) -> Option<()> {
-     let field_name = field.name()?;
-     let field_ty = field.ty()?;
++    // This if condition denotes two modes this assist can work in:
++    // - First is acting upon selection of record fields
++    // - Next is acting upon a single record field
++    //
++    // This is the only part where implementation diverges a bit,
++    // subsequent code is generic for both of these modes
 +
-     // Return early if we've found an existing fn
-     let mut fn_name = to_lower_snake_case(&field_name.to_string());
-     if mutable {
-         format_to!(fn_name, "_mut");
++    let (strukt, info_of_record_fields, fn_names) = if !ctx.has_empty_selection() {
++        // Selection Mode
++        let node = ctx.covering_element();
 +
-     let impl_def = find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?;
++        let node = match node {
++            syntax::NodeOrToken::Node(n) => n,
++            syntax::NodeOrToken::Token(t) => t.parent()?,
++        };
++
++        let parent_struct = node.ancestors().find_map(ast::Struct::cast)?;
++
++        let (info_of_record_fields, field_names) =
++            extract_and_parse_record_fields(&parent_struct, ctx.selection_trimmed(), mutable)?;
++
++        (parent_struct, info_of_record_fields, field_names)
++    } else {
++        // Single Record Field mode
++        let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
++        let field = ctx.find_node_at_offset::<ast::RecordField>()?;
++
++        let record_field_info = parse_record_field(field, mutable)?;
++
++        let fn_name = record_field_info.fn_name.clone();
++
++        (strukt, vec![record_field_info], vec![fn_name])
++    };
++
++    // No record fields to do work on :(
++    if info_of_record_fields.len() == 0 {
++        return None;
 +    }
-     let target = field.syntax().text_range();
++
++    let impl_def = find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), &fn_names)?;
 +
 +    let (id, label) = if mutable {
 +        ("generate_getter_mut", "Generate a mut getter method")
 +    } else {
 +        ("generate_getter", "Generate a getter method")
 +    };
-             if impl_def.is_some() {
-                 buf.push('\n');
++
++    // Computing collective text range of all record fields in selected region
++    let target: TextRange = info_of_record_fields
++        .iter()
++        .map(|record_field_info| record_field_info.target)
++        .reduce(|acc, target| acc.cover(target))?;
++
++    let getter_info = GetterInfo { impl_def, strukt, mutable };
++
 +    acc.add_group(
 +        &GroupLabel("Generate getter/setter".to_owned()),
 +        AssistId(id, AssistKind::Generate),
 +        label,
 +        target,
 +        |builder| {
++            let record_fields_count = info_of_record_fields.len();
++
 +            let mut buf = String::with_capacity(512);
 +
-             let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
-             let (ty, body) = if mutable {
-                 (format!("&mut {}", field_ty), format!("&mut self.{}", field_name))
-             } else {
-                 (|| {
-                     let krate = ctx.sema.scope(field_ty.syntax())?.krate();
-                     let famous_defs = &FamousDefs(&ctx.sema, krate);
-                     ctx.sema
-                         .resolve_type(&field_ty)
-                         .and_then(|ty| convert_reference_type(ty, ctx.db(), famous_defs))
-                         .map(|conversion| {
-                             cov_mark::hit!(convert_reference_type);
-                             (
-                                 conversion.convert_type(ctx.db()),
-                                 conversion.getter(field_name.to_string()),
-                             )
-                         })
-                 })()
-                 .unwrap_or_else(|| (format!("&{}", field_ty), format!("&self.{}", field_name)))
-             };
-             format_to!(
-                 buf,
-                 "    {}fn {}(&{}self) -> {} {{
-         {}
-     }}",
-                 vis,
-                 fn_name,
-                 mutable.then(|| "mut ").unwrap_or_default(),
-                 ty,
-                 body,
-             );
-             let start_offset = impl_def
-                 .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf))
++            // Check if an impl exists
++            if let Some(impl_def) = &getter_info.impl_def {
++                // Check if impl is empty
++                if let Some(assoc_item_list) = impl_def.assoc_item_list() {
++                    if assoc_item_list.assoc_items().next().is_some() {
++                        // If not empty then only insert a new line
++                        buf.push('\n');
++                    }
++                }
 +            }
 +
-                     buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf);
-                     strukt.syntax().text_range().end()
++            for (i, record_field_info) in info_of_record_fields.iter().enumerate() {
++                // this buf inserts a newline at the end of a getter
++                // automatically, if one wants to add one more newline
++                // for separating it from other assoc items, that needs
++                // to be handled spearately
++                let mut getter_buf =
++                    generate_getter_from_info(ctx, &getter_info, &record_field_info);
++
++                // Insert `$0` only for last getter we generate
++                if i == record_fields_count - 1 {
++                    getter_buf = getter_buf.replacen("fn ", "fn $0", 1);
++                }
++
++                // For first element we do not merge with '\n', as
++                // that can be inserted by impl_def check defined
++                // above, for other cases which are:
++                //
++                // - impl exists but it empty, here we would ideally
++                // not want to keep newline between impl <struct> {
++                // and fn <fn-name>() { line
++                //
++                // - next if impl itself does not exist, in this
++                // case we ourselves generate a new impl and that
++                // again ends up with the same reasoning as above
++                // for not keeping newline
++                if i == 0 {
++                    buf = buf + &getter_buf;
++                } else {
++                    buf = buf + "\n" + &getter_buf;
++                }
++
++                // We don't insert a new line at the end of
++                // last getter as it will end up in the end
++                // of an impl where we would not like to keep
++                // getter and end of impl ( i.e. `}` ) with an
++                // extra line for no reason
++                if i < record_fields_count - 1 {
++                    buf = buf + "\n";
++                }
++            }
++
++            let start_offset = getter_info
++                .impl_def
++                .as_ref()
++                .and_then(|impl_def| find_impl_block_end(impl_def.to_owned(), &mut buf))
 +                .unwrap_or_else(|| {
-                 Some(cap) => {
-                     builder.insert_snippet(cap, start_offset, buf.replacen("fn ", "fn $0", 1))
-                 }
++                    buf = generate_impl_text(&ast::Adt::Struct(getter_info.strukt.clone()), &buf);
++                    getter_info.strukt.syntax().text_range().end()
 +                });
 +
 +            match ctx.config.snippet_cap {
++                Some(cap) => builder.insert_snippet(cap, start_offset, buf),
 +                None => builder.insert(start_offset, buf),
 +            }
 +        },
 +    )
 +}
 +
++fn generate_getter_from_info(
++    ctx: &AssistContext<'_>,
++    info: &GetterInfo,
++    record_field_info: &RecordFieldInfo,
++) -> String {
++    let mut buf = String::with_capacity(512);
++
++    let vis = info.strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
++    let (ty, body) = if info.mutable {
++        (
++            format!("&mut {}", record_field_info.field_ty),
++            format!("&mut self.{}", record_field_info.field_name),
++        )
++    } else {
++        (|| {
++            let krate = ctx.sema.scope(record_field_info.field_ty.syntax())?.krate();
++            let famous_defs = &FamousDefs(&ctx.sema, krate);
++            ctx.sema
++                .resolve_type(&record_field_info.field_ty)
++                .and_then(|ty| convert_reference_type(ty, ctx.db(), famous_defs))
++                .map(|conversion| {
++                    cov_mark::hit!(convert_reference_type);
++                    (
++                        conversion.convert_type(ctx.db()),
++                        conversion.getter(record_field_info.field_name.to_string()),
++                    )
++                })
++        })()
++        .unwrap_or_else(|| {
++            (
++                format!("&{}", record_field_info.field_ty),
++                format!("&self.{}", record_field_info.field_name),
++            )
++        })
++    };
++
++    format_to!(
++        buf,
++        "    {}fn {}(&{}self) -> {} {{
++        {}
++    }}",
++        vis,
++        record_field_info.fn_name,
++        info.mutable.then(|| "mut ").unwrap_or_default(),
++        ty,
++        body,
++    );
++
++    buf
++}
++
++fn extract_and_parse_record_fields(
++    node: &ast::Struct,
++    selection_range: TextRange,
++    mutable: bool,
++) -> Option<(Vec<RecordFieldInfo>, Vec<String>)> {
++    let mut field_names: Vec<String> = vec![];
++    let field_list = node.field_list()?;
++
++    match field_list {
++        ast::FieldList::RecordFieldList(ele) => {
++            let info_of_record_fields_in_selection = ele
++                .fields()
++                .filter_map(|record_field| {
++                    if selection_range.contains_range(record_field.syntax().text_range()) {
++                        let record_field_info = parse_record_field(record_field, mutable)?;
++                        field_names.push(record_field_info.fn_name.clone());
++                        return Some(record_field_info);
++                    }
++
++                    None
++                })
++                .collect::<Vec<RecordFieldInfo>>();
++
++            if info_of_record_fields_in_selection.len() == 0 {
++                return None;
++            }
++
++            Some((info_of_record_fields_in_selection, field_names))
++        }
++        ast::FieldList::TupleFieldList(_) => {
++            return None;
++        }
++    }
++}
++
++fn parse_record_field(record_field: ast::RecordField, mutable: bool) -> Option<RecordFieldInfo> {
++    let field_name = record_field.name()?;
++    let field_ty = record_field.ty()?;
++
++    let mut fn_name = to_lower_snake_case(&field_name.to_string());
++    if mutable {
++        format_to!(fn_name, "_mut");
++    }
++
++    let target = record_field.syntax().text_range();
++
++    Some(RecordFieldInfo { field_name, field_ty, fn_name, target })
++}
++
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_generate_getter_from_field() {
 +        check_assist(
 +            generate_getter,
 +            r#"
 +struct Context {
 +    dat$0a: Data,
 +}
 +"#,
 +            r#"
 +struct Context {
 +    data: Data,
 +}
 +
 +impl Context {
 +    fn $0data(&self) -> &Data {
 +        &self.data
 +    }
 +}
 +"#,
 +        );
 +
 +        check_assist(
 +            generate_getter_mut,
 +            r#"
 +struct Context {
 +    dat$0a: Data,
 +}
 +"#,
 +            r#"
 +struct Context {
 +    data: Data,
 +}
 +
 +impl Context {
 +    fn $0data_mut(&mut self) -> &mut Data {
 +        &mut self.data
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_getter_already_implemented() {
 +        check_assist_not_applicable(
 +            generate_getter,
 +            r#"
 +struct Context {
 +    dat$0a: Data,
 +}
 +
 +impl Context {
 +    fn data(&self) -> &Data {
 +        &self.data
 +    }
 +}
 +"#,
 +        );
 +
 +        check_assist_not_applicable(
 +            generate_getter_mut,
 +            r#"
 +struct Context {
 +    dat$0a: Data,
 +}
 +
 +impl Context {
 +    fn data_mut(&mut self) -> &mut Data {
 +        &mut self.data
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_getter_from_field_with_visibility_marker() {
 +        check_assist(
 +            generate_getter,
 +            r#"
 +pub(crate) struct Context {
 +    dat$0a: Data,
 +}
 +"#,
 +            r#"
 +pub(crate) struct Context {
 +    data: Data,
 +}
 +
 +impl Context {
 +    pub(crate) fn $0data(&self) -> &Data {
 +        &self.data
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_multiple_generate_getter() {
 +        check_assist(
 +            generate_getter,
 +            r#"
 +struct Context {
 +    data: Data,
 +    cou$0nt: usize,
 +}
 +
 +impl Context {
 +    fn data(&self) -> &Data {
 +        &self.data
 +    }
 +}
 +"#,
 +            r#"
 +struct Context {
 +    data: Data,
 +    count: usize,
 +}
 +
 +impl Context {
 +    fn data(&self) -> &Data {
 +        &self.data
 +    }
 +
 +    fn $0count(&self) -> &usize {
 +        &self.count
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_not_a_special_case() {
 +        cov_mark::check_count!(convert_reference_type, 0);
 +        // Fake string which doesn't implement AsRef<str>
 +        check_assist(
 +            generate_getter,
 +            r#"
 +pub struct String;
 +
 +struct S { foo: $0String }
 +"#,
 +            r#"
 +pub struct String;
 +
 +struct S { foo: String }
 +
 +impl S {
 +    fn $0foo(&self) -> &String {
 +        &self.foo
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_convert_reference_type() {
 +        cov_mark::check_count!(convert_reference_type, 6);
 +
 +        // Copy
 +        check_assist(
 +            generate_getter,
 +            r#"
 +//- minicore: copy
 +struct S { foo: $0bool }
 +"#,
 +            r#"
 +struct S { foo: bool }
 +
 +impl S {
 +    fn $0foo(&self) -> bool {
 +        self.foo
 +    }
 +}
 +"#,
 +        );
 +
 +        // AsRef<str>
 +        check_assist(
 +            generate_getter,
 +            r#"
 +//- minicore: as_ref
 +pub struct String;
 +impl AsRef<str> for String {
 +    fn as_ref(&self) -> &str {
 +        ""
 +    }
 +}
 +
 +struct S { foo: $0String }
 +"#,
 +            r#"
 +pub struct String;
 +impl AsRef<str> for String {
 +    fn as_ref(&self) -> &str {
 +        ""
 +    }
 +}
 +
 +struct S { foo: String }
 +
 +impl S {
 +    fn $0foo(&self) -> &str {
 +        self.foo.as_ref()
 +    }
 +}
 +"#,
 +        );
 +
 +        // AsRef<T>
 +        check_assist(
 +            generate_getter,
 +            r#"
 +//- minicore: as_ref
 +struct Sweets;
 +
 +pub struct Box<T>(T);
 +impl<T> AsRef<T> for Box<T> {
 +    fn as_ref(&self) -> &T {
 +        &self.0
 +    }
 +}
 +
 +struct S { foo: $0Box<Sweets> }
 +"#,
 +            r#"
 +struct Sweets;
 +
 +pub struct Box<T>(T);
 +impl<T> AsRef<T> for Box<T> {
 +    fn as_ref(&self) -> &T {
 +        &self.0
 +    }
 +}
 +
 +struct S { foo: Box<Sweets> }
 +
 +impl S {
 +    fn $0foo(&self) -> &Sweets {
 +        self.foo.as_ref()
 +    }
 +}
 +"#,
 +        );
 +
 +        // AsRef<[T]>
 +        check_assist(
 +            generate_getter,
 +            r#"
 +//- minicore: as_ref
 +pub struct Vec<T>;
 +impl<T> AsRef<[T]> for Vec<T> {
 +    fn as_ref(&self) -> &[T] {
 +        &[]
 +    }
 +}
 +
 +struct S { foo: $0Vec<()> }
 +"#,
 +            r#"
 +pub struct Vec<T>;
 +impl<T> AsRef<[T]> for Vec<T> {
 +    fn as_ref(&self) -> &[T] {
 +        &[]
 +    }
 +}
 +
 +struct S { foo: Vec<()> }
 +
 +impl S {
 +    fn $0foo(&self) -> &[()] {
 +        self.foo.as_ref()
 +    }
 +}
 +"#,
 +        );
 +
 +        // Option
 +        check_assist(
 +            generate_getter,
 +            r#"
 +//- minicore: option
 +struct Failure;
 +
 +struct S { foo: $0Option<Failure> }
 +"#,
 +            r#"
 +struct Failure;
 +
 +struct S { foo: Option<Failure> }
 +
 +impl S {
 +    fn $0foo(&self) -> Option<&Failure> {
 +        self.foo.as_ref()
 +    }
 +}
 +"#,
 +        );
 +
 +        // Result
 +        check_assist(
 +            generate_getter,
 +            r#"
 +//- minicore: result
 +struct Context {
 +    dat$0a: Result<bool, i32>,
 +}
 +"#,
 +            r#"
 +struct Context {
 +    data: Result<bool, i32>,
 +}
 +
 +impl Context {
 +    fn $0data(&self) -> Result<&bool, &i32> {
 +        self.data.as_ref()
 +    }
 +}
 +"#,
 +        );
 +    }
++
++    #[test]
++    fn test_generate_multiple_getters_from_selection() {
++        check_assist(
++            generate_getter,
++            r#"
++struct Context {
++    $0data: Data,
++    count: usize,$0
++}
++    "#,
++            r#"
++struct Context {
++    data: Data,
++    count: usize,
++}
++
++impl Context {
++    fn data(&self) -> &Data {
++        &self.data
++    }
++
++    fn $0count(&self) -> &usize {
++        &self.count
++    }
++}
++    "#,
++        );
++    }
++
++    #[test]
++    fn test_generate_multiple_getters_from_selection_one_already_exists() {
++        // As impl for one of the fields already exist, skip it
++        check_assist_not_applicable(
++            generate_getter,
++            r#"
++struct Context {
++    $0data: Data,
++    count: usize,$0
++}
++
++impl Context {
++    fn data(&self) -> &Data {
++        &self.data
++    }
++}
++    "#,
++        );
++    }
 +}
index 307cea3d0a4f875aee3a92d954c133c0688c22c1,0000000000000000000000000000000000000000..9af26c04eb458b34d0759a227023c9b5445e5795
mode 100644,000000..100644
--- /dev/null
@@@ -1,190 -1,0 +1,190 @@@
-         format!("Generate impl for `{}`", name),
 +use syntax::ast::{self, AstNode, HasName};
 +
 +use crate::{utils::generate_impl_text, AssistContext, AssistId, AssistKind, Assists};
 +
 +// Assist: generate_impl
 +//
 +// Adds a new inherent impl for a type.
 +//
 +// ```
 +// struct Ctx<T: Clone> {
 +//     data: T,$0
 +// }
 +// ```
 +// ->
 +// ```
 +// struct Ctx<T: Clone> {
 +//     data: T,
 +// }
 +//
 +// impl<T: Clone> Ctx<T> {
 +//     $0
 +// }
 +// ```
 +pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let nominal = ctx.find_node_at_offset::<ast::Adt>()?;
 +    let name = nominal.name()?;
 +    let target = nominal.syntax().text_range();
 +
 +    acc.add(
 +        AssistId("generate_impl", AssistKind::Generate),
++        format!("Generate impl for `{name}`"),
 +        target,
 +        |edit| {
 +            let start_offset = nominal.syntax().text_range().end();
 +            match ctx.config.snippet_cap {
 +                Some(cap) => {
 +                    let snippet = generate_impl_text(&nominal, "    $0");
 +                    edit.insert_snippet(cap, start_offset, snippet);
 +                }
 +                None => {
 +                    let snippet = generate_impl_text(&nominal, "");
 +                    edit.insert(start_offset, snippet);
 +                }
 +            }
 +        },
 +    )
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_target};
 +
 +    use super::*;
 +
 +    // FIXME: break up into separate test fns
 +    #[test]
 +    fn test_add_impl() {
 +        check_assist(
 +            generate_impl,
 +            "struct Foo {$0}\n",
 +            "struct Foo {}\n\nimpl Foo {\n    $0\n}\n",
 +        );
 +        check_assist(
 +            generate_impl,
 +            "struct Foo<T: Clone> {$0}",
 +            "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n    $0\n}",
 +        );
 +        check_assist(
 +            generate_impl,
 +            "struct Foo<'a, T: Foo<'a>> {$0}",
 +            "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n    $0\n}",
 +        );
 +        check_assist(
 +            generate_impl,
 +            r#"
 +            struct MyOwnArray<T, const S: usize> {}$0"#,
 +            r#"
 +            struct MyOwnArray<T, const S: usize> {}
 +
 +            impl<T, const S: usize> MyOwnArray<T, S> {
 +                $0
 +            }"#,
 +        );
 +        check_assist(
 +            generate_impl,
 +            r#"
 +            #[cfg(feature = "foo")]
 +            struct Foo<'a, T: Foo<'a>> {$0}"#,
 +            r#"
 +            #[cfg(feature = "foo")]
 +            struct Foo<'a, T: Foo<'a>> {}
 +
 +            #[cfg(feature = "foo")]
 +            impl<'a, T: Foo<'a>> Foo<'a, T> {
 +                $0
 +            }"#,
 +        );
 +
 +        check_assist(
 +            generate_impl,
 +            r#"
 +            #[cfg(not(feature = "foo"))]
 +            struct Foo<'a, T: Foo<'a>> {$0}"#,
 +            r#"
 +            #[cfg(not(feature = "foo"))]
 +            struct Foo<'a, T: Foo<'a>> {}
 +
 +            #[cfg(not(feature = "foo"))]
 +            impl<'a, T: Foo<'a>> Foo<'a, T> {
 +                $0
 +            }"#,
 +        );
 +
 +        check_assist(
 +            generate_impl,
 +            r#"
 +            struct Defaulted<T = i32> {}$0"#,
 +            r#"
 +            struct Defaulted<T = i32> {}
 +
 +            impl<T> Defaulted<T> {
 +                $0
 +            }"#,
 +        );
 +
 +        check_assist(
 +            generate_impl,
 +            r#"
 +            struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}$0"#,
 +            r#"
 +            struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}
 +
 +            impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> Defaulted<'a, 'b, T, S> {
 +                $0
 +            }"#,
 +        );
 +
 +        check_assist(
 +            generate_impl,
 +            r#"
 +            struct Defaulted<const N: i32 = 0> {}$0"#,
 +            r#"
 +            struct Defaulted<const N: i32 = 0> {}
 +
 +            impl<const N: i32> Defaulted<N> {
 +                $0
 +            }"#,
 +        );
 +
 +        check_assist(
 +            generate_impl,
 +            r#"pub trait Trait {}
 +struct Struct<T>$0
 +where
 +    T: Trait,
 +{
 +    inner: T,
 +}"#,
 +            r#"pub trait Trait {}
 +struct Struct<T>
 +where
 +    T: Trait,
 +{
 +    inner: T,
 +}
 +
 +impl<T> Struct<T>
 +where
 +    T: Trait,
 +{
 +    $0
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_impl_target() {
 +        check_assist_target(
 +            generate_impl,
 +            "
 +struct SomeThingIrrelevant;
 +/// Has a lifetime parameter
 +struct Foo<'a, T: Foo<'a>> {$0}
 +struct EvenMoreIrrelevant;
 +",
 +            "/// Has a lifetime parameter
 +struct Foo<'a, T: Foo<'a>> {}",
 +        );
 +    }
 +}
index 9cda74d9e0d31e4c41c65ed99b396d1cec982545,0000000000000000000000000000000000000000..17fadea0eaf19d28737afadc72a6b43861ba4fce
mode 100644,000000..100644
--- /dev/null
@@@ -1,498 -1,0 +1,504 @@@
-     let impl_def = find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), "new")?;
 +use ide_db::{
 +    imports::import_assets::item_for_path_search, use_trivial_contructor::use_trivial_constructor,
 +};
 +use itertools::Itertools;
 +use stdx::format_to;
 +use syntax::ast::{self, AstNode, HasName, HasVisibility, StructKind};
 +
 +use crate::{
 +    utils::{find_impl_block_start, find_struct_impl, generate_impl_text},
 +    AssistContext, AssistId, AssistKind, Assists,
 +};
 +
 +// Assist: generate_new
 +//
 +// Adds a `fn new` for a type.
 +//
 +// ```
 +// struct Ctx<T: Clone> {
 +//      data: T,$0
 +// }
 +// ```
 +// ->
 +// ```
 +// struct Ctx<T: Clone> {
 +//      data: T,
 +// }
 +//
 +// impl<T: Clone> Ctx<T> {
 +//     fn $0new(data: T) -> Self { Self { data } }
 +// }
 +// ```
 +pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
 +
 +    // We want to only apply this to non-union structs with named fields
 +    let field_list = match strukt.kind() {
 +        StructKind::Record(named) => named,
 +        _ => return None,
 +    };
 +
 +    // Return early if we've found an existing new fn
-         let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
++    let impl_def =
++        find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), &[String::from("new")])?;
 +
 +    let current_module = ctx.sema.scope(strukt.syntax())?.module();
 +
 +    let target = strukt.syntax().text_range();
 +    acc.add(AssistId("generate_new", AssistKind::Generate), "Generate `new`", target, |builder| {
 +        let mut buf = String::with_capacity(512);
 +
 +        if impl_def.is_some() {
 +            buf.push('\n');
 +        }
 +
-                 Some(format!("{}: {}", f.name()?.syntax(), expr))
++        let vis = strukt.visibility().map_or(String::new(), |v| format!("{v} "));
 +
 +        let trivial_constructors = field_list
 +            .fields()
 +            .map(|f| {
++                let name = f.name()?;
++
 +                let ty = ctx.sema.resolve_type(&f.ty()?)?;
 +
 +                let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?));
 +
 +                let type_path = current_module.find_use_path(
 +                    ctx.sema.db,
 +                    item_for_path_search(ctx.sema.db, item_in_ns)?,
 +                    ctx.config.prefer_no_std,
 +                )?;
 +
 +                let expr = use_trivial_constructor(
 +                    &ctx.sema.db,
 +                    ide_db::helpers::mod_path_to_ast(&type_path),
 +                    &ty,
 +                )?;
 +
-                     Some(format!("{}: {}", f.name()?.syntax(), f.ty()?.syntax()))
++                Some(format!("{name}: {expr}"))
 +            })
 +            .collect::<Vec<_>>();
 +
 +        let params = field_list
 +            .fields()
 +            .enumerate()
 +            .filter_map(|(i, f)| {
 +                if trivial_constructors[i].is_none() {
-         format_to!(buf, "    {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields);
++                    let name = f.name()?;
++                    let ty = f.ty()?;
++
++                    Some(format!("{name}: {ty}"))
 +                } else {
 +                    None
 +                }
 +            })
 +            .format(", ");
 +
 +        let fields = field_list
 +            .fields()
 +            .enumerate()
 +            .filter_map(|(i, f)| {
 +                let contructor = trivial_constructors[i].clone();
 +                if contructor.is_some() {
 +                    contructor
 +                } else {
 +                    Some(f.name()?.to_string())
 +                }
 +            })
 +            .format(", ");
 +
++        format_to!(buf, "    {vis}fn new({params}) -> Self {{ Self {{ {fields} }} }}");
 +
 +        let start_offset = impl_def
 +            .and_then(|impl_def| find_impl_block_start(impl_def, &mut buf))
 +            .unwrap_or_else(|| {
 +                buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf);
 +                strukt.syntax().text_range().end()
 +            });
 +
 +        match ctx.config.snippet_cap {
 +            None => builder.insert(start_offset, buf),
 +            Some(cap) => {
 +                buf = buf.replace("fn new", "fn $0new");
 +                builder.insert_snippet(cap, start_offset, buf);
 +            }
 +        }
 +    })
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_generate_new_with_zst_fields() {
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Empty;
 +
 +struct Foo { empty: Empty $0}
 +"#,
 +            r#"
 +struct Empty;
 +
 +struct Foo { empty: Empty }
 +
 +impl Foo {
 +    fn $0new() -> Self { Self { empty: Empty } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Empty;
 +
 +struct Foo { baz: String, empty: Empty $0}
 +"#,
 +            r#"
 +struct Empty;
 +
 +struct Foo { baz: String, empty: Empty }
 +
 +impl Foo {
 +    fn $0new(baz: String) -> Self { Self { baz, empty: Empty } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +enum Empty { Bar }
 +
 +struct Foo { empty: Empty $0}
 +"#,
 +            r#"
 +enum Empty { Bar }
 +
 +struct Foo { empty: Empty }
 +
 +impl Foo {
 +    fn $0new() -> Self { Self { empty: Empty::Bar } }
 +}
 +"#,
 +        );
 +
 +        // make sure the assist only works on unit variants
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Empty {}
 +
 +struct Foo { empty: Empty $0}
 +"#,
 +            r#"
 +struct Empty {}
 +
 +struct Foo { empty: Empty }
 +
 +impl Foo {
 +    fn $0new(empty: Empty) -> Self { Self { empty } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +enum Empty { Bar {} }
 +
 +struct Foo { empty: Empty $0}
 +"#,
 +            r#"
 +enum Empty { Bar {} }
 +
 +struct Foo { empty: Empty }
 +
 +impl Foo {
 +    fn $0new(empty: Empty) -> Self { Self { empty } }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_new() {
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo {$0}
 +"#,
 +            r#"
 +struct Foo {}
 +
 +impl Foo {
 +    fn $0new() -> Self { Self {  } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo<T: Clone> {$0}
 +"#,
 +            r#"
 +struct Foo<T: Clone> {}
 +
 +impl<T: Clone> Foo<T> {
 +    fn $0new() -> Self { Self {  } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo<'a, T: Foo<'a>> {$0}
 +"#,
 +            r#"
 +struct Foo<'a, T: Foo<'a>> {}
 +
 +impl<'a, T: Foo<'a>> Foo<'a, T> {
 +    fn $0new() -> Self { Self {  } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo { baz: String $0}
 +"#,
 +            r#"
 +struct Foo { baz: String }
 +
 +impl Foo {
 +    fn $0new(baz: String) -> Self { Self { baz } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo { baz: String, qux: Vec<i32> $0}
 +"#,
 +            r#"
 +struct Foo { baz: String, qux: Vec<i32> }
 +
 +impl Foo {
 +    fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn check_that_visibility_modifiers_dont_get_brought_in() {
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo { pub baz: String, pub qux: Vec<i32> $0}
 +"#,
 +            r#"
 +struct Foo { pub baz: String, pub qux: Vec<i32> }
 +
 +impl Foo {
 +    fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn check_it_reuses_existing_impls() {
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo {$0}
 +
 +impl Foo {}
 +"#,
 +            r#"
 +struct Foo {}
 +
 +impl Foo {
 +    fn $0new() -> Self { Self {  } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo {$0}
 +
 +impl Foo {
 +    fn qux(&self) {}
 +}
 +"#,
 +            r#"
 +struct Foo {}
 +
 +impl Foo {
 +    fn $0new() -> Self { Self {  } }
 +
 +    fn qux(&self) {}
 +}
 +"#,
 +        );
 +
 +        check_assist(
 +            generate_new,
 +            r#"
 +struct Foo {$0}
 +
 +impl Foo {
 +    fn qux(&self) {}
 +    fn baz() -> i32 {
 +        5
 +    }
 +}
 +"#,
 +            r#"
 +struct Foo {}
 +
 +impl Foo {
 +    fn $0new() -> Self { Self {  } }
 +
 +    fn qux(&self) {}
 +    fn baz() -> i32 {
 +        5
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn check_visibility_of_new_fn_based_on_struct() {
 +        check_assist(
 +            generate_new,
 +            r#"
 +pub struct Foo {$0}
 +"#,
 +            r#"
 +pub struct Foo {}
 +
 +impl Foo {
 +    pub fn $0new() -> Self { Self {  } }
 +}
 +"#,
 +        );
 +        check_assist(
 +            generate_new,
 +            r#"
 +pub(crate) struct Foo {$0}
 +"#,
 +            r#"
 +pub(crate) struct Foo {}
 +
 +impl Foo {
 +    pub(crate) fn $0new() -> Self { Self {  } }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn generate_new_not_applicable_if_fn_exists() {
 +        check_assist_not_applicable(
 +            generate_new,
 +            r#"
 +struct Foo {$0}
 +
 +impl Foo {
 +    fn new() -> Self {
 +        Self
 +    }
 +}
 +"#,
 +        );
 +
 +        check_assist_not_applicable(
 +            generate_new,
 +            r#"
 +struct Foo {$0}
 +
 +impl Foo {
 +    fn New() -> Self {
 +        Self
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn generate_new_target() {
 +        check_assist_target(
 +            generate_new,
 +            r#"
 +struct SomeThingIrrelevant;
 +/// Has a lifetime parameter
 +struct Foo<'a, T: Foo<'a>> {$0}
 +struct EvenMoreIrrelevant;
 +"#,
 +            "/// Has a lifetime parameter
 +struct Foo<'a, T: Foo<'a>> {}",
 +        );
 +    }
 +
 +    #[test]
 +    fn test_unrelated_new() {
 +        check_assist(
 +            generate_new,
 +            r#"
 +pub struct AstId<N: AstNode> {
 +    file_id: HirFileId,
 +    file_ast_id: FileAstId<N>,
 +}
 +
 +impl<N: AstNode> AstId<N> {
 +    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
 +        AstId { file_id, file_ast_id }
 +    }
 +}
 +
 +pub struct Source<T> {
 +    pub file_id: HirFileId,$0
 +    pub ast: T,
 +}
 +
 +impl<T> Source<T> {
 +    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
 +        Source { file_id: self.file_id, ast: f(self.ast) }
 +    }
 +}
 +"#,
 +            r#"
 +pub struct AstId<N: AstNode> {
 +    file_id: HirFileId,
 +    file_ast_id: FileAstId<N>,
 +}
 +
 +impl<N: AstNode> AstId<N> {
 +    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
 +        AstId { file_id, file_ast_id }
 +    }
 +}
 +
 +pub struct Source<T> {
 +    pub file_id: HirFileId,
 +    pub ast: T,
 +}
 +
 +impl<T> Source<T> {
 +    pub fn $0new(file_id: HirFileId, ast: T) -> Self { Self { file_id, ast } }
 +
 +    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
 +        Source { file_id: self.file_id, ast: f(self.ast) }
 +    }
 +}
 +"#,
 +        );
 +    }
 +}
index 2a7ad6ce3681145f0f8940124e5c2a8709d882a7,0000000000000000000000000000000000000000..62f72df1c9d619823fa08bbac6352453df429cff
mode 100644,000000..100644
--- /dev/null
@@@ -1,184 -1,0 +1,175 @@@
-     let impl_def = find_struct_impl(
-         ctx,
-         &ast::Adt::Struct(strukt.clone()),
-         format!("set_{}", fn_name).as_str(),
-     )?;
 +use stdx::{format_to, to_lower_snake_case};
 +use syntax::ast::{self, AstNode, HasName, HasVisibility};
 +
 +use crate::{
 +    utils::{find_impl_block_end, find_struct_impl, generate_impl_text},
 +    AssistContext, AssistId, AssistKind, Assists, GroupLabel,
 +};
 +
 +// Assist: generate_setter
 +//
 +// Generate a setter method.
 +//
 +// ```
 +// struct Person {
 +//     nam$0e: String,
 +// }
 +// ```
 +// ->
 +// ```
 +// struct Person {
 +//     name: String,
 +// }
 +//
 +// impl Person {
 +//     fn set_name(&mut self, name: String) {
 +//         self.name = name;
 +//     }
 +// }
 +// ```
 +pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
 +    let field = ctx.find_node_at_offset::<ast::RecordField>()?;
 +
 +    let field_name = field.name()?;
 +    let field_ty = field.ty()?;
 +
 +    // Return early if we've found an existing fn
 +    let fn_name = to_lower_snake_case(&field_name.to_string());
-             let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
++    let impl_def =
++        find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), &[format!("set_{fn_name}")])?;
 +
 +    let target = field.syntax().text_range();
 +    acc.add_group(
 +        &GroupLabel("Generate getter/setter".to_owned()),
 +        AssistId("generate_setter", AssistKind::Generate),
 +        "Generate a setter method",
 +        target,
 +        |builder| {
 +            let mut buf = String::with_capacity(512);
 +
 +            if impl_def.is_some() {
 +                buf.push('\n');
 +            }
 +
-                 "    {}fn set_{}(&mut self, {}: {}) {{
-         self.{} = {};
-     }}",
-                 vis,
-                 fn_name,
-                 fn_name,
-                 field_ty,
-                 fn_name,
-                 fn_name,
++            let vis = strukt.visibility().map_or(String::new(), |v| format!("{v} "));
 +            format_to!(
 +                buf,
++                "    {vis}fn set_{fn_name}(&mut self, {fn_name}: {field_ty}) {{
++        self.{fn_name} = {fn_name};
++    }}"
 +            );
 +
 +            let start_offset = impl_def
 +                .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf))
 +                .unwrap_or_else(|| {
 +                    buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf);
 +                    strukt.syntax().text_range().end()
 +                });
 +
 +            builder.insert(start_offset, buf);
 +        },
 +    )
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    fn check_not_applicable(ra_fixture: &str) {
 +        check_assist_not_applicable(generate_setter, ra_fixture)
 +    }
 +
 +    #[test]
 +    fn test_generate_setter_from_field() {
 +        check_assist(
 +            generate_setter,
 +            r#"
 +struct Person<T: Clone> {
 +    dat$0a: T,
 +}"#,
 +            r#"
 +struct Person<T: Clone> {
 +    data: T,
 +}
 +
 +impl<T: Clone> Person<T> {
 +    fn set_data(&mut self, data: T) {
 +        self.data = data;
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_setter_already_implemented() {
 +        check_not_applicable(
 +            r#"
 +struct Person<T: Clone> {
 +    dat$0a: T,
 +}
 +
 +impl<T: Clone> Person<T> {
 +    fn set_data(&mut self, data: T) {
 +        self.data = data;
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_generate_setter_from_field_with_visibility_marker() {
 +        check_assist(
 +            generate_setter,
 +            r#"
 +pub(crate) struct Person<T: Clone> {
 +    dat$0a: T,
 +}"#,
 +            r#"
 +pub(crate) struct Person<T: Clone> {
 +    data: T,
 +}
 +
 +impl<T: Clone> Person<T> {
 +    pub(crate) fn set_data(&mut self, data: T) {
 +        self.data = data;
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_multiple_generate_setter() {
 +        check_assist(
 +            generate_setter,
 +            r#"
 +struct Context<T: Clone> {
 +    data: T,
 +    cou$0nt: usize,
 +}
 +
 +impl<T: Clone> Context<T> {
 +    fn set_data(&mut self, data: T) {
 +        self.data = data;
 +    }
 +}"#,
 +            r#"
 +struct Context<T: Clone> {
 +    data: T,
 +    count: usize,
 +}
 +
 +impl<T: Clone> Context<T> {
 +    fn set_data(&mut self, data: T) {
 +        self.data = data;
 +    }
 +
 +    fn set_count(&mut self, count: usize) {
 +        self.count = count;
 +    }
 +}"#,
 +        );
 +    }
 +}
index 38396cd7d7bafd47c36e4d4d473915cdc41f827a,0000000000000000000000000000000000000000..db32e7182c44d76ab78db38123862d8fe9f84257
mode 100644,000000..100644
--- /dev/null
@@@ -1,703 -1,0 +1,707 @@@
-     name: &str,
 +//! Assorted functions shared by several assists.
 +
 +use std::ops;
 +
 +pub(crate) use gen_trait_fn_body::gen_trait_fn_body;
 +use hir::{db::HirDatabase, HirDisplay, Semantics};
 +use ide_db::{famous_defs::FamousDefs, path_transform::PathTransform, RootDatabase, SnippetCap};
 +use stdx::format_to;
 +use syntax::{
 +    ast::{
 +        self,
 +        edit::{self, AstNodeEdit},
 +        edit_in_place::{AttrsOwnerEdit, Removable},
 +        make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
 +    },
 +    ted, AstNode, AstToken, Direction, SourceFile,
 +    SyntaxKind::*,
 +    SyntaxNode, TextRange, TextSize, T,
 +};
 +
 +use crate::assist_context::{AssistContext, SourceChangeBuilder};
 +
 +pub(crate) mod suggest_name;
 +mod gen_trait_fn_body;
 +
 +pub(crate) fn unwrap_trivial_block(block_expr: ast::BlockExpr) -> ast::Expr {
 +    extract_trivial_expression(&block_expr)
 +        .filter(|expr| !expr.syntax().text().contains_char('\n'))
 +        .unwrap_or_else(|| block_expr.into())
 +}
 +
 +pub fn extract_trivial_expression(block_expr: &ast::BlockExpr) -> Option<ast::Expr> {
 +    if block_expr.modifier().is_some() {
 +        return None;
 +    }
 +    let stmt_list = block_expr.stmt_list()?;
 +    let has_anything_else = |thing: &SyntaxNode| -> bool {
 +        let mut non_trivial_children =
 +            stmt_list.syntax().children_with_tokens().filter(|it| match it.kind() {
 +                WHITESPACE | T!['{'] | T!['}'] => false,
 +                _ => it.as_node() != Some(thing),
 +            });
 +        non_trivial_children.next().is_some()
 +    };
 +
 +    if let Some(expr) = stmt_list.tail_expr() {
 +        if has_anything_else(expr.syntax()) {
 +            return None;
 +        }
 +        return Some(expr);
 +    }
 +    // Unwrap `{ continue; }`
 +    let stmt = stmt_list.statements().next()?;
 +    if let ast::Stmt::ExprStmt(expr_stmt) = stmt {
 +        if has_anything_else(expr_stmt.syntax()) {
 +            return None;
 +        }
 +        let expr = expr_stmt.expr()?;
 +        if matches!(expr.syntax().kind(), CONTINUE_EXPR | BREAK_EXPR | RETURN_EXPR) {
 +            return Some(expr);
 +        }
 +    }
 +    None
 +}
 +
 +/// This is a method with a heuristics to support test methods annotated with custom test annotations, such as
 +/// `#[test_case(...)]`, `#[tokio::test]` and similar.
 +/// Also a regular `#[test]` annotation is supported.
 +///
 +/// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test,
 +/// but it's better than not to have the runnables for the tests at all.
 +pub fn test_related_attribute(fn_def: &ast::Fn) -> Option<ast::Attr> {
 +    fn_def.attrs().find_map(|attr| {
 +        let path = attr.path()?;
 +        let text = path.syntax().text().to_string();
 +        if text.starts_with("test") || text.ends_with("test") {
 +            Some(attr)
 +        } else {
 +            None
 +        }
 +    })
 +}
 +
 +#[derive(Copy, Clone, PartialEq)]
 +pub enum DefaultMethods {
 +    Only,
 +    No,
 +}
 +
 +pub fn filter_assoc_items(
 +    sema: &Semantics<'_, RootDatabase>,
 +    items: &[hir::AssocItem],
 +    default_methods: DefaultMethods,
 +) -> Vec<ast::AssocItem> {
 +    fn has_def_name(item: &ast::AssocItem) -> bool {
 +        match item {
 +            ast::AssocItem::Fn(def) => def.name(),
 +            ast::AssocItem::TypeAlias(def) => def.name(),
 +            ast::AssocItem::Const(def) => def.name(),
 +            ast::AssocItem::MacroCall(_) => None,
 +        }
 +        .is_some()
 +    }
 +
 +    items
 +        .iter()
 +        // Note: This throws away items with no source.
 +        .filter_map(|&i| {
 +            let item = match i {
 +                hir::AssocItem::Function(i) => ast::AssocItem::Fn(sema.source(i)?.value),
 +                hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(sema.source(i)?.value),
 +                hir::AssocItem::Const(i) => ast::AssocItem::Const(sema.source(i)?.value),
 +            };
 +            Some(item)
 +        })
 +        .filter(has_def_name)
 +        .filter(|it| match it {
 +            ast::AssocItem::Fn(def) => matches!(
 +                (default_methods, def.body()),
 +                (DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None)
 +            ),
 +            _ => default_methods == DefaultMethods::No,
 +        })
 +        .collect::<Vec<_>>()
 +}
 +
 +pub fn add_trait_assoc_items_to_impl(
 +    sema: &Semantics<'_, RootDatabase>,
 +    items: Vec<ast::AssocItem>,
 +    trait_: hir::Trait,
 +    impl_: ast::Impl,
 +    target_scope: hir::SemanticsScope<'_>,
 +) -> (ast::Impl, ast::AssocItem) {
 +    let source_scope = sema.scope_for_def(trait_);
 +
 +    let transform = PathTransform::trait_impl(&target_scope, &source_scope, trait_, impl_.clone());
 +
 +    let items = items.into_iter().map(|assoc_item| {
 +        transform.apply(assoc_item.syntax());
 +        assoc_item.remove_attrs_and_docs();
 +        assoc_item
 +    });
 +
 +    let res = impl_.clone_for_update();
 +
 +    let assoc_item_list = res.get_or_create_assoc_item_list();
 +    let mut first_item = None;
 +    for item in items {
 +        first_item.get_or_insert_with(|| item.clone());
 +        match &item {
 +            ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
 +                let body = make::block_expr(None, Some(make::ext::expr_todo()))
 +                    .indent(edit::IndentLevel(1));
 +                ted::replace(fn_.get_or_create_body().syntax(), body.clone_for_update().syntax())
 +            }
 +            ast::AssocItem::TypeAlias(type_alias) => {
 +                if let Some(type_bound_list) = type_alias.type_bound_list() {
 +                    type_bound_list.remove()
 +                }
 +            }
 +            _ => {}
 +        }
 +
 +        assoc_item_list.add_item(item)
 +    }
 +
 +    (res, first_item.unwrap())
 +}
 +
 +#[derive(Clone, Copy, Debug)]
 +pub(crate) enum Cursor<'a> {
 +    Replace(&'a SyntaxNode),
 +    Before(&'a SyntaxNode),
 +}
 +
 +impl<'a> Cursor<'a> {
 +    fn node(self) -> &'a SyntaxNode {
 +        match self {
 +            Cursor::Replace(node) | Cursor::Before(node) => node,
 +        }
 +    }
 +}
 +
 +pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor<'_>) -> String {
 +    assert!(cursor.node().ancestors().any(|it| it == *node));
 +    let range = cursor.node().text_range() - node.text_range().start();
 +    let range: ops::Range<usize> = range.into();
 +
 +    let mut placeholder = cursor.node().to_string();
 +    escape(&mut placeholder);
 +    let tab_stop = match cursor {
 +        Cursor::Replace(placeholder) => format!("${{0:{}}}", placeholder),
 +        Cursor::Before(placeholder) => format!("$0{}", placeholder),
 +    };
 +
 +    let mut buf = node.to_string();
 +    buf.replace_range(range, &tab_stop);
 +    return buf;
 +
 +    fn escape(buf: &mut String) {
 +        stdx::replace(buf, '{', r"\{");
 +        stdx::replace(buf, '}', r"\}");
 +        stdx::replace(buf, '$', r"\$");
 +    }
 +}
 +
 +pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
 +    node.children_with_tokens()
 +        .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
 +        .map(|it| it.text_range().start())
 +        .unwrap_or_else(|| node.text_range().start())
 +}
 +
 +pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr {
 +    invert_special_case(&expr).unwrap_or_else(|| make::expr_prefix(T![!], expr))
 +}
 +
 +fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
 +    match expr {
 +        ast::Expr::BinExpr(bin) => {
 +            let bin = bin.clone_for_update();
 +            let op_token = bin.op_token()?;
 +            let rev_token = match op_token.kind() {
 +                T![==] => T![!=],
 +                T![!=] => T![==],
 +                T![<] => T![>=],
 +                T![<=] => T![>],
 +                T![>] => T![<=],
 +                T![>=] => T![<],
 +                // Parenthesize other expressions before prefixing `!`
 +                _ => return Some(make::expr_prefix(T![!], make::expr_paren(expr.clone()))),
 +            };
 +            ted::replace(op_token, make::token(rev_token));
 +            Some(bin.into())
 +        }
 +        ast::Expr::MethodCallExpr(mce) => {
 +            let receiver = mce.receiver()?;
 +            let method = mce.name_ref()?;
 +            let arg_list = mce.arg_list()?;
 +
 +            let method = match method.text().as_str() {
 +                "is_some" => "is_none",
 +                "is_none" => "is_some",
 +                "is_ok" => "is_err",
 +                "is_err" => "is_ok",
 +                _ => return None,
 +            };
 +            Some(make::expr_method_call(receiver, make::name_ref(method), arg_list))
 +        }
 +        ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::UnaryOp::Not => match pe.expr()? {
 +            ast::Expr::ParenExpr(parexpr) => parexpr.expr(),
 +            _ => pe.expr(),
 +        },
 +        ast::Expr::Literal(lit) => match lit.kind() {
 +            ast::LiteralKind::Bool(b) => match b {
 +                true => Some(ast::Expr::Literal(make::expr_literal("false"))),
 +                false => Some(ast::Expr::Literal(make::expr_literal("true"))),
 +            },
 +            _ => None,
 +        },
 +        _ => None,
 +    }
 +}
 +
 +pub(crate) fn next_prev() -> impl Iterator<Item = Direction> {
 +    [Direction::Next, Direction::Prev].into_iter()
 +}
 +
 +pub(crate) fn does_pat_match_variant(pat: &ast::Pat, var: &ast::Pat) -> bool {
 +    let first_node_text = |pat: &ast::Pat| pat.syntax().first_child().map(|node| node.text());
 +
 +    let pat_head = match pat {
 +        ast::Pat::IdentPat(bind_pat) => match bind_pat.pat() {
 +            Some(p) => first_node_text(&p),
 +            None => return pat.syntax().text() == var.syntax().text(),
 +        },
 +        pat => first_node_text(pat),
 +    };
 +
 +    let var_head = first_node_text(var);
 +
 +    pat_head == var_head
 +}
 +
 +pub(crate) fn does_nested_pattern(pat: &ast::Pat) -> bool {
 +    let depth = calc_depth(pat, 0);
 +
 +    if 1 < depth {
 +        return true;
 +    }
 +    false
 +}
 +
 +fn calc_depth(pat: &ast::Pat, depth: usize) -> usize {
 +    match pat {
 +        ast::Pat::IdentPat(_)
 +        | ast::Pat::BoxPat(_)
 +        | ast::Pat::RestPat(_)
 +        | ast::Pat::LiteralPat(_)
 +        | ast::Pat::MacroPat(_)
 +        | ast::Pat::OrPat(_)
 +        | ast::Pat::ParenPat(_)
 +        | ast::Pat::PathPat(_)
 +        | ast::Pat::WildcardPat(_)
 +        | ast::Pat::RangePat(_)
 +        | ast::Pat::RecordPat(_)
 +        | ast::Pat::RefPat(_)
 +        | ast::Pat::SlicePat(_)
 +        | ast::Pat::TuplePat(_)
 +        | ast::Pat::ConstBlockPat(_) => depth,
 +
 +        // FIXME: Other patterns may also be nested. Currently it simply supports only `TupleStructPat`
 +        ast::Pat::TupleStructPat(pat) => {
 +            let mut max_depth = depth;
 +            for p in pat.fields() {
 +                let d = calc_depth(&p, depth + 1);
 +                if d > max_depth {
 +                    max_depth = d
 +                }
 +            }
 +            max_depth
 +        }
 +    }
 +}
 +
 +// Uses a syntax-driven approach to find any impl blocks for the struct that
 +// exist within the module/file
 +//
 +// Returns `None` if we've found an existing fn
 +//
 +// FIXME: change the new fn checking to a more semantic approach when that's more
 +// viable (e.g. we process proc macros, etc)
 +// FIXME: this partially overlaps with `find_impl_block_*`
++
++/// `find_struct_impl` looks for impl of a struct, but this also has additional feature
++/// where it takes a list of function names and check if they exist inside impl_, if
++/// even one match is found, it returns None
 +pub(crate) fn find_struct_impl(
 +    ctx: &AssistContext<'_>,
 +    adt: &ast::Adt,
-         if has_fn(impl_blk, name) {
++    names: &[String],
 +) -> Option<Option<ast::Impl>> {
 +    let db = ctx.db();
 +    let module = adt.syntax().parent()?;
 +
 +    let struct_def = ctx.sema.to_def(adt)?;
 +
 +    let block = module.descendants().filter_map(ast::Impl::cast).find_map(|impl_blk| {
 +        let blk = ctx.sema.to_def(&impl_blk)?;
 +
 +        // FIXME: handle e.g. `struct S<T>; impl<U> S<U> {}`
 +        // (we currently use the wrong type parameter)
 +        // also we wouldn't want to use e.g. `impl S<u32>`
 +
 +        let same_ty = match blk.self_ty(db).as_adt() {
 +            Some(def) => def == struct_def,
 +            None => false,
 +        };
 +        let not_trait_impl = blk.trait_(db).is_none();
 +
 +        if !(same_ty && not_trait_impl) {
 +            None
 +        } else {
 +            Some(impl_blk)
 +        }
 +    });
 +
 +    if let Some(ref impl_blk) = block {
- fn has_fn(imp: &ast::Impl, rhs_name: &str) -> bool {
++        if has_any_fn(impl_blk, names) {
 +            return None;
 +        }
 +    }
 +
 +    Some(block)
 +}
 +
-                     if name.text().eq_ignore_ascii_case(rhs_name) {
++fn has_any_fn(imp: &ast::Impl, names: &[String]) -> bool {
 +    if let Some(il) = imp.assoc_item_list() {
 +        for item in il.assoc_items() {
 +            if let ast::AssocItem::Fn(f) = item {
 +                if let Some(name) = f.name() {
++                    if names.iter().any(|n| n.eq_ignore_ascii_case(&name.text())) {
 +                        return true;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    false
 +}
 +
 +/// Find the start of the `impl` block for the given `ast::Impl`.
 +//
 +// FIXME: this partially overlaps with `find_struct_impl`
 +pub(crate) fn find_impl_block_start(impl_def: ast::Impl, buf: &mut String) -> Option<TextSize> {
 +    buf.push('\n');
 +    let start = impl_def.assoc_item_list().and_then(|it| it.l_curly_token())?.text_range().end();
 +    Some(start)
 +}
 +
 +/// Find the end of the `impl` block for the given `ast::Impl`.
 +//
 +// FIXME: this partially overlaps with `find_struct_impl`
 +pub(crate) fn find_impl_block_end(impl_def: ast::Impl, buf: &mut String) -> Option<TextSize> {
 +    buf.push('\n');
 +    let end = impl_def
 +        .assoc_item_list()
 +        .and_then(|it| it.r_curly_token())?
 +        .prev_sibling_or_token()?
 +        .text_range()
 +        .end();
 +    Some(end)
 +}
 +
 +// Generates the surrounding `impl Type { <code> }` including type and lifetime
 +// parameters
 +pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String {
 +    generate_impl_text_inner(adt, None, code)
 +}
 +
 +// Generates the surrounding `impl <trait> for Type { <code> }` including type
 +// and lifetime parameters
 +pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &str) -> String {
 +    generate_impl_text_inner(adt, Some(trait_text), code)
 +}
 +
 +fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str) -> String {
 +    // Ensure lifetime params are before type & const params
 +    let generic_params = adt.generic_param_list().map(|generic_params| {
 +        let lifetime_params =
 +            generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
 +        let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| {
 +            // remove defaults since they can't be specified in impls
 +            match param {
 +                ast::TypeOrConstParam::Type(param) => {
 +                    let param = param.clone_for_update();
 +                    param.remove_default();
 +                    Some(ast::GenericParam::TypeParam(param))
 +                }
 +                ast::TypeOrConstParam::Const(param) => {
 +                    let param = param.clone_for_update();
 +                    param.remove_default();
 +                    Some(ast::GenericParam::ConstParam(param))
 +                }
 +            }
 +        });
 +
 +        make::generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
 +    });
 +
 +    // FIXME: use syntax::make & mutable AST apis instead
 +    // `trait_text` and `code` can't be opaque blobs of text
 +    let mut buf = String::with_capacity(code.len());
 +
 +    // Copy any cfg attrs from the original adt
 +    buf.push_str("\n\n");
 +    let cfg_attrs = adt
 +        .attrs()
 +        .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false));
 +    cfg_attrs.for_each(|attr| buf.push_str(&format!("{attr}\n")));
 +
 +    // `impl{generic_params} {trait_text} for {name}{generic_params.to_generic_args()}`
 +    buf.push_str("impl");
 +    if let Some(generic_params) = &generic_params {
 +        format_to!(buf, "{generic_params}");
 +    }
 +    buf.push(' ');
 +    if let Some(trait_text) = trait_text {
 +        buf.push_str(trait_text);
 +        buf.push_str(" for ");
 +    }
 +    buf.push_str(&adt.name().unwrap().text());
 +    if let Some(generic_params) = generic_params {
 +        format_to!(buf, "{}", generic_params.to_generic_args());
 +    }
 +
 +    match adt.where_clause() {
 +        Some(where_clause) => {
 +            format_to!(buf, "\n{where_clause}\n{{\n{code}\n}}");
 +        }
 +        None => {
 +            format_to!(buf, " {{\n{code}\n}}");
 +        }
 +    }
 +
 +    buf
 +}
 +
 +pub(crate) fn add_method_to_adt(
 +    builder: &mut SourceChangeBuilder,
 +    adt: &ast::Adt,
 +    impl_def: Option<ast::Impl>,
 +    method: &str,
 +) {
 +    let mut buf = String::with_capacity(method.len() + 2);
 +    if impl_def.is_some() {
 +        buf.push('\n');
 +    }
 +    buf.push_str(method);
 +
 +    let start_offset = impl_def
 +        .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf))
 +        .unwrap_or_else(|| {
 +            buf = generate_impl_text(adt, &buf);
 +            adt.syntax().text_range().end()
 +        });
 +
 +    builder.insert(start_offset, buf);
 +}
 +
 +#[derive(Debug)]
 +pub(crate) struct ReferenceConversion {
 +    conversion: ReferenceConversionType,
 +    ty: hir::Type,
 +}
 +
 +#[derive(Debug)]
 +enum ReferenceConversionType {
 +    // reference can be stripped if the type is Copy
 +    Copy,
 +    // &String -> &str
 +    AsRefStr,
 +    // &Vec<T> -> &[T]
 +    AsRefSlice,
 +    // &Box<T> -> &T
 +    Dereferenced,
 +    // &Option<T> -> Option<&T>
 +    Option,
 +    // &Result<T, E> -> Result<&T, &E>
 +    Result,
 +}
 +
 +impl ReferenceConversion {
 +    pub(crate) fn convert_type(&self, db: &dyn HirDatabase) -> String {
 +        match self.conversion {
 +            ReferenceConversionType::Copy => self.ty.display(db).to_string(),
 +            ReferenceConversionType::AsRefStr => "&str".to_string(),
 +            ReferenceConversionType::AsRefSlice => {
 +                let type_argument_name =
 +                    self.ty.type_arguments().next().unwrap().display(db).to_string();
 +                format!("&[{}]", type_argument_name)
 +            }
 +            ReferenceConversionType::Dereferenced => {
 +                let type_argument_name =
 +                    self.ty.type_arguments().next().unwrap().display(db).to_string();
 +                format!("&{}", type_argument_name)
 +            }
 +            ReferenceConversionType::Option => {
 +                let type_argument_name =
 +                    self.ty.type_arguments().next().unwrap().display(db).to_string();
 +                format!("Option<&{}>", type_argument_name)
 +            }
 +            ReferenceConversionType::Result => {
 +                let mut type_arguments = self.ty.type_arguments();
 +                let first_type_argument_name =
 +                    type_arguments.next().unwrap().display(db).to_string();
 +                let second_type_argument_name =
 +                    type_arguments.next().unwrap().display(db).to_string();
 +                format!("Result<&{}, &{}>", first_type_argument_name, second_type_argument_name)
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn getter(&self, field_name: String) -> String {
 +        match self.conversion {
 +            ReferenceConversionType::Copy => format!("self.{}", field_name),
 +            ReferenceConversionType::AsRefStr
 +            | ReferenceConversionType::AsRefSlice
 +            | ReferenceConversionType::Dereferenced
 +            | ReferenceConversionType::Option
 +            | ReferenceConversionType::Result => format!("self.{}.as_ref()", field_name),
 +        }
 +    }
 +}
 +
 +// FIXME: It should return a new hir::Type, but currently constructing new types is too cumbersome
 +//        and all users of this function operate on string type names, so they can do the conversion
 +//        itself themselves.
 +pub(crate) fn convert_reference_type(
 +    ty: hir::Type,
 +    db: &RootDatabase,
 +    famous_defs: &FamousDefs<'_, '_>,
 +) -> Option<ReferenceConversion> {
 +    handle_copy(&ty, db)
 +        .or_else(|| handle_as_ref_str(&ty, db, famous_defs))
 +        .or_else(|| handle_as_ref_slice(&ty, db, famous_defs))
 +        .or_else(|| handle_dereferenced(&ty, db, famous_defs))
 +        .or_else(|| handle_option_as_ref(&ty, db, famous_defs))
 +        .or_else(|| handle_result_as_ref(&ty, db, famous_defs))
 +        .map(|conversion| ReferenceConversion { ty, conversion })
 +}
 +
 +fn handle_copy(ty: &hir::Type, db: &dyn HirDatabase) -> Option<ReferenceConversionType> {
 +    ty.is_copy(db).then(|| ReferenceConversionType::Copy)
 +}
 +
 +fn handle_as_ref_str(
 +    ty: &hir::Type,
 +    db: &dyn HirDatabase,
 +    famous_defs: &FamousDefs<'_, '_>,
 +) -> Option<ReferenceConversionType> {
 +    let str_type = hir::BuiltinType::str().ty(db);
 +
 +    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[str_type])
 +        .then(|| ReferenceConversionType::AsRefStr)
 +}
 +
 +fn handle_as_ref_slice(
 +    ty: &hir::Type,
 +    db: &dyn HirDatabase,
 +    famous_defs: &FamousDefs<'_, '_>,
 +) -> Option<ReferenceConversionType> {
 +    let type_argument = ty.type_arguments().next()?;
 +    let slice_type = hir::Type::new_slice(type_argument);
 +
 +    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[slice_type])
 +        .then(|| ReferenceConversionType::AsRefSlice)
 +}
 +
 +fn handle_dereferenced(
 +    ty: &hir::Type,
 +    db: &dyn HirDatabase,
 +    famous_defs: &FamousDefs<'_, '_>,
 +) -> Option<ReferenceConversionType> {
 +    let type_argument = ty.type_arguments().next()?;
 +
 +    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[type_argument])
 +        .then(|| ReferenceConversionType::Dereferenced)
 +}
 +
 +fn handle_option_as_ref(
 +    ty: &hir::Type,
 +    db: &dyn HirDatabase,
 +    famous_defs: &FamousDefs<'_, '_>,
 +) -> Option<ReferenceConversionType> {
 +    if ty.as_adt() == famous_defs.core_option_Option()?.ty(db).as_adt() {
 +        Some(ReferenceConversionType::Option)
 +    } else {
 +        None
 +    }
 +}
 +
 +fn handle_result_as_ref(
 +    ty: &hir::Type,
 +    db: &dyn HirDatabase,
 +    famous_defs: &FamousDefs<'_, '_>,
 +) -> Option<ReferenceConversionType> {
 +    if ty.as_adt() == famous_defs.core_result_Result()?.ty(db).as_adt() {
 +        Some(ReferenceConversionType::Result)
 +    } else {
 +        None
 +    }
 +}
 +
 +pub(crate) fn get_methods(items: &ast::AssocItemList) -> Vec<ast::Fn> {
 +    items
 +        .assoc_items()
 +        .flat_map(|i| match i {
 +            ast::AssocItem::Fn(f) => Some(f),
 +            _ => None,
 +        })
 +        .filter(|f| f.name().is_some())
 +        .collect()
 +}
 +
 +/// Trim(remove leading and trailing whitespace) `initial_range` in `source_file`, return the trimmed range.
 +pub(crate) fn trimmed_text_range(source_file: &SourceFile, initial_range: TextRange) -> TextRange {
 +    let mut trimmed_range = initial_range;
 +    while source_file
 +        .syntax()
 +        .token_at_offset(trimmed_range.start())
 +        .find_map(Whitespace::cast)
 +        .is_some()
 +        && trimmed_range.start() < trimmed_range.end()
 +    {
 +        let start = trimmed_range.start() + TextSize::from(1);
 +        trimmed_range = TextRange::new(start, trimmed_range.end());
 +    }
 +    while source_file
 +        .syntax()
 +        .token_at_offset(trimmed_range.end())
 +        .find_map(Whitespace::cast)
 +        .is_some()
 +        && trimmed_range.start() < trimmed_range.end()
 +    {
 +        let end = trimmed_range.end() - TextSize::from(1);
 +        trimmed_range = TextRange::new(trimmed_range.start(), end);
 +    }
 +    trimmed_range
 +}
 +
 +/// Convert a list of function params to a list of arguments that can be passed
 +/// into a function call.
 +pub(crate) fn convert_param_list_to_arg_list(list: ast::ParamList) -> ast::ArgList {
 +    let mut args = vec![];
 +    for param in list.params() {
 +        if let Some(ast::Pat::IdentPat(pat)) = param.pat() {
 +            if let Some(name) = pat.name() {
 +                let name = name.to_string();
 +                let expr = make::expr_path(make::ext::ident_path(&name));
 +                args.push(expr);
 +            }
 +        }
 +    }
 +    make::arg_list(args)
 +}
index 4577072149a72d7b6d3a0d64f391f1bc5ef6404d,0000000000000000000000000000000000000000..ae299f0584148937c64b897e7cf658359a5c7069
mode 100644,000000..100644
--- /dev/null
@@@ -1,295 -1,0 +1,291 @@@
-     pub(crate) mod incorrect_try_expr;
 +//! Diagnostics rendering and fixits.
 +//!
 +//! Most of the diagnostics originate from the dark depth of the compiler, and
 +//! are originally expressed in term of IR. When we emit the diagnostic, we are
 +//! usually not in the position to decide how to best "render" it in terms of
 +//! user-authored source code. We are especially not in the position to offer
 +//! fixits, as the compiler completely lacks the infrastructure to edit the
 +//! source code.
 +//!
 +//! Instead, we "bubble up" raw, structured diagnostics until the `hir` crate,
 +//! where we "cook" them so that each diagnostic is formulated in terms of `hir`
 +//! types. Well, at least that's the aspiration, the "cooking" is somewhat
 +//! ad-hoc at the moment. Anyways, we get a bunch of ide-friendly diagnostic
 +//! structs from hir, and we want to render them to unified serializable
 +//! representation (span, level, message) here. If we can, we also provide
 +//! fixits. By the way, that's why we want to keep diagnostics structured
 +//! internally -- so that we have all the info to make fixes.
 +//!
 +//! We have one "handler" module per diagnostic code. Such a module contains
 +//! rendering, optional fixes and tests. It's OK if some low-level compiler
 +//! functionality ends up being tested via a diagnostic.
 +//!
 +//! There are also a couple of ad-hoc diagnostics implemented directly here, we
 +//! don't yet have a great pattern for how to do them properly.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +mod handlers {
 +    pub(crate) mod break_outside_of_loop;
 +    pub(crate) mod inactive_code;
 +    pub(crate) mod incorrect_case;
-     pub(crate) mod not_implemented;
 +    pub(crate) mod invalid_derive_target;
 +    pub(crate) mod macro_error;
 +    pub(crate) mod malformed_derive;
 +    pub(crate) mod mismatched_arg_count;
 +    pub(crate) mod missing_fields;
 +    pub(crate) mod missing_match_arms;
 +    pub(crate) mod missing_unsafe;
-             AnyDiagnostic::IncorrectTryExpr(d) => handlers::incorrect_try_expr::incorrect_try_expr(&ctx, &d),
 +    pub(crate) mod no_such_field;
 +    pub(crate) mod replace_filter_map_next_with_find_map;
 +    pub(crate) mod type_mismatch;
 +    pub(crate) mod unimplemented_builtin_macro;
 +    pub(crate) mod unresolved_extern_crate;
 +    pub(crate) mod unresolved_import;
 +    pub(crate) mod unresolved_macro_call;
 +    pub(crate) mod unresolved_module;
 +    pub(crate) mod unresolved_proc_macro;
 +
 +    // The handlers below are unusual, the implement the diagnostics as well.
 +    pub(crate) mod field_shorthand;
 +    pub(crate) mod useless_braces;
 +    pub(crate) mod unlinked_file;
 +    pub(crate) mod json_is_not_rust;
 +}
 +
 +#[cfg(test)]
 +mod tests;
 +
 +use hir::{diagnostics::AnyDiagnostic, InFile, Semantics};
 +use ide_db::{
 +    assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
 +    base_db::{FileId, FileRange, SourceDatabase},
 +    imports::insert_use::InsertUseConfig,
 +    label::Label,
 +    source_change::SourceChange,
 +    FxHashSet, RootDatabase,
 +};
 +use syntax::{algo::find_node_at_range, ast::AstNode, SyntaxNodePtr, TextRange};
 +
 +#[derive(Copy, Clone, Debug, PartialEq)]
 +pub struct DiagnosticCode(pub &'static str);
 +
 +impl DiagnosticCode {
 +    pub fn as_str(&self) -> &str {
 +        self.0
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub struct Diagnostic {
 +    pub code: DiagnosticCode,
 +    pub message: String,
 +    pub range: TextRange,
 +    pub severity: Severity,
 +    pub unused: bool,
 +    pub experimental: bool,
 +    pub fixes: Option<Vec<Assist>>,
 +}
 +
 +impl Diagnostic {
 +    fn new(code: &'static str, message: impl Into<String>, range: TextRange) -> Diagnostic {
 +        let message = message.into();
 +        Diagnostic {
 +            code: DiagnosticCode(code),
 +            message,
 +            range,
 +            severity: Severity::Error,
 +            unused: false,
 +            experimental: false,
 +            fixes: None,
 +        }
 +    }
 +
 +    fn experimental(mut self) -> Diagnostic {
 +        self.experimental = true;
 +        self
 +    }
 +
 +    fn severity(mut self, severity: Severity) -> Diagnostic {
 +        self.severity = severity;
 +        self
 +    }
 +
 +    fn with_fixes(mut self, fixes: Option<Vec<Assist>>) -> Diagnostic {
 +        self.fixes = fixes;
 +        self
 +    }
 +
 +    fn with_unused(mut self, unused: bool) -> Diagnostic {
 +        self.unused = unused;
 +        self
 +    }
 +}
 +
 +#[derive(Debug, Copy, Clone)]
 +pub enum Severity {
 +    Error,
 +    // We don't actually emit this one yet, but we should at some point.
 +    // Warning,
 +    WeakWarning,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum ExprFillDefaultMode {
 +    Todo,
 +    Default,
 +}
 +impl Default for ExprFillDefaultMode {
 +    fn default() -> Self {
 +        Self::Todo
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +pub struct DiagnosticsConfig {
 +    pub proc_macros_enabled: bool,
 +    pub proc_attr_macros_enabled: bool,
 +    pub disable_experimental: bool,
 +    pub disabled: FxHashSet<String>,
 +    pub expr_fill_default: ExprFillDefaultMode,
 +    // FIXME: We may want to include a whole `AssistConfig` here
 +    pub insert_use: InsertUseConfig,
 +    pub prefer_no_std: bool,
 +}
 +
 +impl DiagnosticsConfig {
 +    pub fn test_sample() -> Self {
 +        use hir::PrefixKind;
 +        use ide_db::imports::insert_use::ImportGranularity;
 +
 +        Self {
 +            proc_macros_enabled: Default::default(),
 +            proc_attr_macros_enabled: Default::default(),
 +            disable_experimental: Default::default(),
 +            disabled: Default::default(),
 +            expr_fill_default: Default::default(),
 +            insert_use: InsertUseConfig {
 +                granularity: ImportGranularity::Preserve,
 +                enforce_granularity: false,
 +                prefix_kind: PrefixKind::Plain,
 +                group: false,
 +                skip_glob_imports: false,
 +            },
 +            prefer_no_std: false,
 +        }
 +    }
 +}
 +
 +struct DiagnosticsContext<'a> {
 +    config: &'a DiagnosticsConfig,
 +    sema: Semantics<'a, RootDatabase>,
 +    resolve: &'a AssistResolveStrategy,
 +}
 +
 +pub fn diagnostics(
 +    db: &RootDatabase,
 +    config: &DiagnosticsConfig,
 +    resolve: &AssistResolveStrategy,
 +    file_id: FileId,
 +) -> Vec<Diagnostic> {
 +    let _p = profile::span("diagnostics");
 +    let sema = Semantics::new(db);
 +    let parse = db.parse(file_id);
 +    let mut res = Vec::new();
 +
 +    // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
 +    res.extend(
 +        parse.errors().iter().take(128).map(|err| {
 +            Diagnostic::new("syntax-error", format!("Syntax Error: {}", err), err.range())
 +        }),
 +    );
 +
 +    let parse = sema.parse(file_id);
 +
 +    for node in parse.syntax().descendants() {
 +        handlers::useless_braces::useless_braces(&mut res, file_id, &node);
 +        handlers::field_shorthand::field_shorthand(&mut res, file_id, &node);
 +        handlers::json_is_not_rust::json_in_items(&sema, &mut res, file_id, &node, &config);
 +    }
 +
 +    let module = sema.to_module_def(file_id);
 +
 +    let ctx = DiagnosticsContext { config, sema, resolve };
 +    if module.is_none() {
 +        handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id);
 +    }
 +
 +    let mut diags = Vec::new();
 +    if let Some(m) = module {
 +        m.diagnostics(db, &mut diags)
 +    }
 +
 +    for diag in diags {
 +        #[rustfmt::skip]
 +        let d = match diag {
 +            AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
 +            AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d),
-             AnyDiagnostic::NotImplemented(d) => handlers::not_implemented::not_implemented(&ctx, &d),
 +            AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
 +            AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d),
 +            AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),
 +            AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d),
 +            AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d),
 +            AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d),
 +            AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d),
 +            AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d),
 +            AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d),
 +            AnyDiagnostic::UnimplementedBuiltinMacro(d) => handlers::unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d),
 +            AnyDiagnostic::UnresolvedExternCrate(d) => handlers::unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
 +            AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d),
 +            AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d),
 +            AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d),
 +            AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d, config.proc_macros_enabled, config.proc_attr_macros_enabled),
 +            AnyDiagnostic::InvalidDeriveTarget(d) => handlers::invalid_derive_target::invalid_derive_target(&ctx, &d),
 +
 +            AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) {
 +                Some(it) => it,
 +                None => continue,
 +            }
 +        };
 +        res.push(d)
 +    }
 +
 +    res.retain(|d| {
 +        !ctx.config.disabled.contains(d.code.as_str())
 +            && !(ctx.config.disable_experimental && d.experimental)
 +    });
 +
 +    res
 +}
 +
 +fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist {
 +    let mut res = unresolved_fix(id, label, target);
 +    res.source_change = Some(source_change);
 +    res
 +}
 +
 +fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
 +    assert!(!id.contains(' '));
 +    Assist {
 +        id: AssistId(id, AssistKind::QuickFix),
 +        label: Label::new(label.to_string()),
 +        group: None,
 +        target,
 +        source_change: None,
 +        trigger_signature_help: false,
 +    }
 +}
 +
 +fn adjusted_display_range<N: AstNode>(
 +    ctx: &DiagnosticsContext<'_>,
 +    diag_ptr: InFile<SyntaxNodePtr>,
 +    adj: &dyn Fn(N) -> Option<TextRange>,
 +) -> TextRange {
 +    let FileRange { file_id, range } = ctx.sema.diagnostics_display_range(diag_ptr);
 +
 +    let source_file = ctx.sema.db.parse(file_id);
 +    find_node_at_range::<N>(&source_file.syntax_node(), range)
 +        .filter(|it| it.syntax().text_range() == range)
 +        .and_then(adj)
 +        .unwrap_or(range)
 +}
index 5cab017a58dbdba582340ca11d9c682bfd58294c,0000000000000000000000000000000000000000..eb997e6fef83022f726dec8a2ff0e5cbcd6fdc86
mode 100644,000000..100644
--- /dev/null
@@@ -1,5325 -1,0 +1,5309 @@@
-     check_hover_range(
-         r#"
- //- minicore: try
- use core::ops::ControlFlow;
- fn foo() -> ControlFlow<()> {
-     $0ControlFlow::Break(())?$0;
-     ControlFlow::Continue(())
- }
- "#,
-         expect![[r#"
-             ```text
-             Try Target Type: ControlFlow<(), {unknown}>
-             Propagated as:          ControlFlow<(), ()>
-             ```
-         "#]],
-     );
 +use expect_test::{expect, Expect};
 +use ide_db::base_db::{FileLoader, FileRange};
 +use syntax::TextRange;
 +
 +use crate::{fixture, hover::HoverDocFormat, HoverConfig};
 +
 +fn check_hover_no_result(ra_fixture: &str) {
 +    let (analysis, position) = fixture::position(ra_fixture);
 +    let hover = analysis
 +        .hover(
 +            &HoverConfig {
 +                links_in_hover: true,
 +                documentation: Some(HoverDocFormat::Markdown),
 +                keywords: true,
 +            },
 +            FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
 +        )
 +        .unwrap();
 +    assert!(hover.is_none(), "hover not expected but found: {:?}", hover.unwrap());
 +}
 +
 +#[track_caller]
 +fn check(ra_fixture: &str, expect: Expect) {
 +    let (analysis, position) = fixture::position(ra_fixture);
 +    let hover = analysis
 +        .hover(
 +            &HoverConfig {
 +                links_in_hover: true,
 +                documentation: Some(HoverDocFormat::Markdown),
 +                keywords: true,
 +            },
 +            FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
 +        )
 +        .unwrap()
 +        .unwrap();
 +
 +    let content = analysis.db.file_text(position.file_id);
 +    let hovered_element = &content[hover.range];
 +
 +    let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
 +    expect.assert_eq(&actual)
 +}
 +
 +fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
 +    let (analysis, position) = fixture::position(ra_fixture);
 +    let hover = analysis
 +        .hover(
 +            &HoverConfig {
 +                links_in_hover: false,
 +                documentation: Some(HoverDocFormat::Markdown),
 +                keywords: true,
 +            },
 +            FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
 +        )
 +        .unwrap()
 +        .unwrap();
 +
 +    let content = analysis.db.file_text(position.file_id);
 +    let hovered_element = &content[hover.range];
 +
 +    let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
 +    expect.assert_eq(&actual)
 +}
 +
 +fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) {
 +    let (analysis, position) = fixture::position(ra_fixture);
 +    let hover = analysis
 +        .hover(
 +            &HoverConfig {
 +                links_in_hover: true,
 +                documentation: Some(HoverDocFormat::PlainText),
 +                keywords: true,
 +            },
 +            FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
 +        )
 +        .unwrap()
 +        .unwrap();
 +
 +    let content = analysis.db.file_text(position.file_id);
 +    let hovered_element = &content[hover.range];
 +
 +    let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
 +    expect.assert_eq(&actual)
 +}
 +
 +fn check_actions(ra_fixture: &str, expect: Expect) {
 +    let (analysis, file_id, position) = fixture::range_or_position(ra_fixture);
 +    let hover = analysis
 +        .hover(
 +            &HoverConfig {
 +                links_in_hover: true,
 +                documentation: Some(HoverDocFormat::Markdown),
 +                keywords: true,
 +            },
 +            FileRange { file_id, range: position.range_or_empty() },
 +        )
 +        .unwrap()
 +        .unwrap();
 +    expect.assert_debug_eq(&hover.info.actions)
 +}
 +
 +fn check_hover_range(ra_fixture: &str, expect: Expect) {
 +    let (analysis, range) = fixture::range(ra_fixture);
 +    let hover = analysis
 +        .hover(
 +            &HoverConfig {
 +                links_in_hover: false,
 +                documentation: Some(HoverDocFormat::Markdown),
 +                keywords: true,
 +            },
 +            range,
 +        )
 +        .unwrap()
 +        .unwrap();
 +    expect.assert_eq(hover.info.markup.as_str())
 +}
 +
 +fn check_hover_range_no_results(ra_fixture: &str) {
 +    let (analysis, range) = fixture::range(ra_fixture);
 +    let hover = analysis
 +        .hover(
 +            &HoverConfig {
 +                links_in_hover: false,
 +                documentation: Some(HoverDocFormat::Markdown),
 +                keywords: true,
 +            },
 +            range,
 +        )
 +        .unwrap();
 +    assert!(hover.is_none());
 +}
 +
 +#[test]
 +fn hover_descend_macros_avoids_duplicates() {
 +    check(
 +        r#"
 +macro_rules! dupe_use {
 +    ($local:ident) => {
 +        {
 +            $local;
 +            $local;
 +        }
 +    }
 +}
 +fn foo() {
 +    let local = 0;
 +    dupe_use!(local$0);
 +}
 +"#,
 +        expect![[r#"
 +            *local*
 +
 +            ```rust
 +            let local: i32
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_all_macro_descends() {
 +    check(
 +        r#"
 +macro_rules! m {
 +    ($name:ident) => {
 +        /// Outer
 +        fn $name() {}
 +
 +        mod module {
 +            /// Inner
 +            fn $name() {}
 +        }
 +    };
 +}
 +
 +m!(ab$0c);
 +            "#,
 +        expect![[r#"
 +            *abc*
 +
 +            ```rust
 +            test::module
 +            ```
 +
 +            ```rust
 +            fn abc()
 +            ```
 +
 +            ---
 +
 +            Inner
 +            ---
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            fn abc()
 +            ```
 +
 +            ---
 +
 +            Outer
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_type_of_an_expression() {
 +    check(
 +        r#"
 +pub fn foo() -> u32 { 1 }
 +
 +fn main() {
 +    let foo_test = foo()$0;
 +}
 +"#,
 +        expect![[r#"
 +            *foo()*
 +            ```rust
 +            u32
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_remove_markdown_if_configured() {
 +    check_hover_no_markdown(
 +        r#"
 +pub fn foo() -> u32 { 1 }
 +
 +fn main() {
 +    let foo_test = foo()$0;
 +}
 +"#,
 +        expect![[r#"
 +            *foo()*
 +            u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_long_type_of_an_expression() {
 +    check(
 +        r#"
 +struct Scan<A, B, C> { a: A, b: B, c: C }
 +struct Iter<I> { inner: I }
 +enum Option<T> { Some(T), None }
 +
 +struct OtherStruct<T> { i: T }
 +
 +fn scan<A, B, C>(a: A, b: B, c: C) -> Iter<Scan<OtherStruct<A>, B, C>> {
 +    Iter { inner: Scan { a, b, c } }
 +}
 +
 +fn main() {
 +    let num: i32 = 55;
 +    let closure = |memo: &mut u32, value: &u32, _another: &mut u32| -> Option<u32> {
 +        Option::Some(*memo + value)
 +    };
 +    let number = 5u32;
 +    let mut iter$0 = scan(OtherStruct { i: num }, closure, number);
 +}
 +"#,
 +        expect![[r#"
 +                *iter*
 +
 +                ```rust
 +                let mut iter: Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>>
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_fn_signature() {
 +    // Single file with result
 +    check(
 +        r#"
 +pub fn foo() -> u32 { 1 }
 +
 +fn main() { let foo_test = fo$0o(); }
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub fn foo() -> u32
 +                ```
 +            "#]],
 +    );
 +
 +    // Multiple candidates but results are ambiguous.
 +    check(
 +        r#"
 +//- /a.rs
 +pub fn foo() -> u32 { 1 }
 +
 +//- /b.rs
 +pub fn foo() -> &str { "" }
 +
 +//- /c.rs
 +pub fn foo(a: u32, b: u32) {}
 +
 +//- /main.rs
 +mod a;
 +mod b;
 +mod c;
 +
 +fn main() { let foo_test = fo$0o(); }
 +        "#,
 +        expect![[r#"
 +                *foo*
 +                ```rust
 +                {unknown}
 +                ```
 +            "#]],
 +    );
 +
 +    // Use literal `crate` in path
 +    check(
 +        r#"
 +pub struct X;
 +
 +fn foo() -> crate::X { X }
 +
 +fn main() { f$0oo(); }
 +        "#,
 +        expect![[r#"
 +            *foo*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            fn foo() -> crate::X
 +            ```
 +        "#]],
 +    );
 +
 +    // Check `super` in path
 +    check(
 +        r#"
 +pub struct X;
 +
 +mod m { pub fn foo() -> super::X { super::X } }
 +
 +fn main() { m::f$0oo(); }
 +        "#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test::m
 +                ```
 +
 +                ```rust
 +                pub fn foo() -> super::X
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_omits_unnamed_where_preds() {
 +    check(
 +        r#"
 +pub fn foo(bar: impl T) { }
 +
 +fn main() { fo$0o(); }
 +        "#,
 +        expect![[r#"
 +            *foo*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            pub fn foo(bar: impl T)
 +            ```
 +        "#]],
 +    );
 +    check(
 +        r#"
 +pub fn foo<V: AsRef<str>>(bar: impl T, baz: V) { }
 +
 +fn main() { fo$0o(); }
 +        "#,
 +        expect![[r#"
 +            *foo*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            pub fn foo<V>(bar: impl T, baz: V)
 +            where
 +                V: AsRef<str>,
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_fn_signature_with_type_params() {
 +    check(
 +        r#"
 +pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { }
 +
 +fn main() { let foo_test = fo$0o(); }
 +        "#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub fn foo<'a, T>(b: &'a T) -> &'a str
 +                where
 +                    T: AsRef<str>,
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_fn_signature_on_fn_name() {
 +    check(
 +        r#"
 +pub fn foo$0(a: u32, b: u32) -> u32 {}
 +
 +fn main() { }
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub fn foo(a: u32, b: u32) -> u32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_fn_doc() {
 +    check(
 +        r#"
 +/// # Example
 +/// ```
 +/// # use std::path::Path;
 +/// #
 +/// foo(Path::new("hello, world!"))
 +/// ```
 +pub fn foo$0(_: &Path) {}
 +
 +fn main() { }
 +"#,
 +        expect![[r##"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub fn foo(_: &Path)
 +                ```
 +
 +                ---
 +
 +                # Example
 +
 +                ```
 +                # use std::path::Path;
 +                #
 +                foo(Path::new("hello, world!"))
 +                ```
 +            "##]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_fn_doc_attr_raw_string() {
 +    check(
 +        r##"
 +#[doc = r#"Raw string doc attr"#]
 +pub fn foo$0(_: &Path) {}
 +
 +fn main() { }
 +"##,
 +        expect![[r##"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub fn foo(_: &Path)
 +                ```
 +
 +                ---
 +
 +                Raw string doc attr
 +            "##]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_struct_field_info() {
 +    // Hovering over the field when instantiating
 +    check(
 +        r#"
 +struct Foo { field_a: u32 }
 +
 +fn main() {
 +    let foo = Foo { field_a$0: 0, };
 +}
 +"#,
 +        expect![[r#"
 +                *field_a*
 +
 +                ```rust
 +                test::Foo
 +                ```
 +
 +                ```rust
 +                field_a: u32
 +                ```
 +            "#]],
 +    );
 +
 +    // Hovering over the field in the definition
 +    check(
 +        r#"
 +struct Foo { field_a$0: u32 }
 +
 +fn main() {
 +    let foo = Foo { field_a: 0 };
 +}
 +"#,
 +        expect![[r#"
 +                *field_a*
 +
 +                ```rust
 +                test::Foo
 +                ```
 +
 +                ```rust
 +                field_a: u32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_const_static() {
 +    check(
 +        r#"const foo$0: u32 = 123;"#,
 +        expect![[r#"
 +            *foo*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const foo: u32 = 123 (0x7B)
 +            ```
 +        "#]],
 +    );
 +    check(
 +        r#"
 +const foo$0: u32 = {
 +    let x = foo();
 +    x + 100
 +};"#,
 +        expect![[r#"
 +            *foo*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const foo: u32 = {
 +                let x = foo();
 +                x + 100
 +            }
 +            ```
 +        "#]],
 +    );
 +
 +    check(
 +        r#"static foo$0: u32 = 456;"#,
 +        expect![[r#"
 +            *foo*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            static foo: u32 = 456
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_default_generic_types() {
 +    check(
 +        r#"
 +struct Test<K, T = u8> { k: K, t: T }
 +
 +fn main() {
 +    let zz$0 = Test { t: 23u8, k: 33 };
 +}"#,
 +        expect![[r#"
 +                *zz*
 +
 +                ```rust
 +                let zz: Test<i32>
 +                ```
 +            "#]],
 +    );
 +    check_hover_range(
 +        r#"
 +struct Test<K, T = u8> { k: K, t: T }
 +
 +fn main() {
 +    let $0zz$0 = Test { t: 23u8, k: 33 };
 +}"#,
 +        expect![[r#"
 +            ```rust
 +            Test<i32, u8>
 +            ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_some() {
 +    check(
 +        r#"
 +enum Option<T> { Some(T) }
 +use Option::Some;
 +
 +fn main() { So$0me(12); }
 +"#,
 +        expect![[r#"
 +                *Some*
 +
 +                ```rust
 +                test::Option
 +                ```
 +
 +                ```rust
 +                Some(T)
 +                ```
 +            "#]],
 +    );
 +
 +    check(
 +        r#"
 +enum Option<T> { Some(T) }
 +use Option::Some;
 +
 +fn main() { let b$0ar = Some(12); }
 +"#,
 +        expect![[r#"
 +                *bar*
 +
 +                ```rust
 +                let bar: Option<i32>
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_enum_variant() {
 +    check(
 +        r#"
 +enum Option<T> {
 +    Some(T)
 +    /// The None variant
 +    Non$0e
 +}
 +"#,
 +        expect![[r#"
 +                *None*
 +
 +                ```rust
 +                test::Option
 +                ```
 +
 +                ```rust
 +                None
 +                ```
 +
 +                ---
 +
 +                The None variant
 +            "#]],
 +    );
 +
 +    check(
 +        r#"
 +enum Option<T> {
 +    /// The Some variant
 +    Some(T)
 +}
 +fn main() {
 +    let s = Option::Som$0e(12);
 +}
 +"#,
 +        expect![[r#"
 +                *Some*
 +
 +                ```rust
 +                test::Option
 +                ```
 +
 +                ```rust
 +                Some(T)
 +                ```
 +
 +                ---
 +
 +                The Some variant
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_for_local_variable() {
 +    check(
 +        r#"fn func(foo: i32) { fo$0o; }"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                foo: i32
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_for_local_variable_pat() {
 +    check(
 +        r#"fn func(fo$0o: i32) {}"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                foo: i32
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_local_var_edge() {
 +    check(
 +        r#"fn func(foo: i32) { if true { $0foo; }; }"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                foo: i32
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_for_param_edge() {
 +    check(
 +        r#"fn func($0foo: i32) {}"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                foo: i32
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_for_param_with_multiple_traits() {
 +    check(
 +        r#"
 +            //- minicore: sized
 +            trait Deref {
 +                type Target: ?Sized;
 +            }
 +            trait DerefMut {
 +                type Target: ?Sized;
 +            }
 +            fn f(_x$0: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#,
 +        expect![[r#"
 +                *_x*
 +
 +                ```rust
 +                _x: impl Deref<Target = u8> + DerefMut<Target = u8>
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_infer_associated_method_result() {
 +    check(
 +        r#"
 +struct Thing { x: u32 }
 +
 +impl Thing {
 +    fn new() -> Thing { Thing { x: 0 } }
 +}
 +
 +fn main() { let foo_$0test = Thing::new(); }
 +"#,
 +        expect![[r#"
 +                *foo_test*
 +
 +                ```rust
 +                let foo_test: Thing
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_infer_associated_method_exact() {
 +    check(
 +        r#"
 +mod wrapper {
 +    pub struct Thing { x: u32 }
 +
 +    impl Thing {
 +        pub fn new() -> Thing { Thing { x: 0 } }
 +    }
 +}
 +
 +fn main() { let foo_test = wrapper::Thing::new$0(); }
 +"#,
 +        expect![[r#"
 +                *new*
 +
 +                ```rust
 +                test::wrapper::Thing
 +                ```
 +
 +                ```rust
 +                pub fn new() -> Thing
 +                ```
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_infer_associated_const_in_pattern() {
 +    check(
 +        r#"
 +struct X;
 +impl X {
 +    const C: u32 = 1;
 +}
 +
 +fn main() {
 +    match 1 {
 +        X::C$0 => {},
 +        2 => {},
 +        _ => {}
 +    };
 +}
 +"#,
 +        expect![[r#"
 +            *C*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const C: u32 = 1
 +            ```
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_self() {
 +    check(
 +        r#"
 +struct Thing { x: u32 }
 +impl Thing {
 +    fn new() -> Self { Self$0 { x: 0 } }
 +}
 +"#,
 +        expect![[r#"
 +                *Self*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                struct Thing
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +struct Thing { x: u32 }
 +impl Thing {
 +    fn new() -> Self$0 { Self { x: 0 } }
 +}
 +"#,
 +        expect![[r#"
 +                *Self*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                struct Thing
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +enum Thing { A }
 +impl Thing {
 +    pub fn new() -> Self$0 { Thing::A }
 +}
 +"#,
 +        expect![[r#"
 +                *Self*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                enum Thing
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +        enum Thing { A }
 +        impl Thing {
 +            pub fn thing(a: Self$0) {}
 +        }
 +        "#,
 +        expect![[r#"
 +                *Self*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                enum Thing
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_shadowing_pat() {
 +    check(
 +        r#"
 +fn x() {}
 +
 +fn y() {
 +    let x = 0i32;
 +    x$0;
 +}
 +"#,
 +        expect![[r#"
 +                *x*
 +
 +                ```rust
 +                let x: i32
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_macro_invocation() {
 +    check(
 +        r#"
 +macro_rules! foo { () => {} }
 +
 +fn f() { fo$0o!(); }
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                macro_rules! foo
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_macro2_invocation() {
 +    check(
 +        r#"
 +/// foo bar
 +///
 +/// foo bar baz
 +macro foo() {}
 +
 +fn f() { fo$0o!(); }
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                macro foo
 +                ```
 +
 +                ---
 +
 +                foo bar
 +
 +                foo bar baz
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_tuple_field() {
 +    check(
 +        r#"struct TS(String, i32$0);"#,
 +        expect![[r#"
 +                *i32*
 +
 +                ```rust
 +                i32
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_through_macro() {
 +    check(
 +        r#"
 +macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
 +fn foo() {}
 +id! {
 +    fn bar() { fo$0o(); }
 +}
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                fn foo()
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_through_attr() {
 +    check(
 +        r#"
 +//- proc_macros: identity
 +#[proc_macros::identity]
 +fn foo$0() {}
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                fn foo()
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_through_expr_in_macro() {
 +    check(
 +        r#"
 +macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
 +fn foo(bar:u32) { let a = id!(ba$0r); }
 +"#,
 +        expect![[r#"
 +                *bar*
 +
 +                ```rust
 +                bar: u32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_through_expr_in_macro_recursive() {
 +    check(
 +        r#"
 +macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
 +macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
 +fn foo(bar:u32) { let a = id!(ba$0r); }
 +"#,
 +        expect![[r#"
 +                *bar*
 +
 +                ```rust
 +                bar: u32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_through_func_in_macro_recursive() {
 +    check(
 +        r#"
 +macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
 +macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
 +fn bar() -> u32 { 0 }
 +fn foo() { let a = id!([0u32, bar($0)] ); }
 +"#,
 +        expect![[r#"
 +                *bar()*
 +                ```rust
 +                u32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_through_literal_string_in_macro() {
 +    check(
 +        r#"
 +macro_rules! arr { ($($tt:tt)*) => { [$($tt)*] } }
 +fn foo() {
 +    let mastered_for_itunes = "";
 +    let _ = arr!("Tr$0acks", &mastered_for_itunes);
 +}
 +"#,
 +        expect![[r#"
 +                *"Tracks"*
 +                ```rust
 +                &str
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_through_assert_macro() {
 +    check(
 +        r#"
 +#[rustc_builtin_macro]
 +macro_rules! assert {}
 +
 +fn bar() -> bool { true }
 +fn foo() {
 +    assert!(ba$0r());
 +}
 +"#,
 +        expect![[r#"
 +                *bar*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                fn bar() -> bool
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_multiple_actions() {
 +    check_actions(
 +        r#"
 +struct Bar;
 +struct Foo { bar: Bar }
 +
 +fn foo(Foo { b$0ar }: &Foo) {}
 +        "#,
 +        expect![[r#"
 +            [
 +                GoToType(
 +                    [
 +                        HoverGotoTypeData {
 +                            mod_path: "test::Bar",
 +                            nav: NavigationTarget {
 +                                file_id: FileId(
 +                                    0,
 +                                ),
 +                                full_range: 0..11,
 +                                focus_range: 7..10,
 +                                name: "Bar",
 +                                kind: Struct,
 +                                description: "struct Bar",
 +                            },
 +                        },
 +                    ],
 +                ),
 +            ]
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_through_literal_string_in_builtin_macro() {
 +    check_hover_no_result(
 +        r#"
 +            #[rustc_builtin_macro]
 +            macro_rules! format {}
 +
 +            fn foo() {
 +                format!("hel$0lo {}", 0);
 +            }
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn test_hover_non_ascii_space_doc() {
 +    check(
 +        "
 +/// <- `\u{3000}` here
 +fn foo() { }
 +
 +fn bar() { fo$0o(); }
 +",
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                fn foo()
 +                ```
 +
 +                ---
 +
 +                \<- ` ` here
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_function_show_qualifiers() {
 +    check(
 +        r#"async fn foo$0() {}"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                async fn foo()
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"pub const unsafe fn foo$0() {}"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub const unsafe fn foo()
 +                ```
 +            "#]],
 +    );
 +    // Top level `pub(crate)` will be displayed as no visibility.
 +    check(
 +        r#"mod m { pub(crate) async unsafe extern "C" fn foo$0() {} }"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test::m
 +                ```
 +
 +                ```rust
 +                pub(crate) async unsafe extern "C" fn foo()
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_function_show_types() {
 +    check(
 +        r#"fn foo$0(a: i32, b:i32) -> i32 { 0 }"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                fn foo(a: i32, b: i32) -> i32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_function_pointer_show_identifiers() {
 +    check(
 +        r#"type foo$0 = fn(a: i32, b: i32) -> i32;"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                type foo = fn(a: i32, b: i32) -> i32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_function_pointer_no_identifier() {
 +    check(
 +        r#"type foo$0 = fn(i32, _: i32) -> i32;"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                type foo = fn(i32, i32) -> i32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_trait_show_qualifiers() {
 +    check_actions(
 +        r"unsafe trait foo$0() {}",
 +        expect![[r#"
 +                [
 +                    Implementation(
 +                        FilePosition {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            offset: 13,
 +                        },
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_extern_crate() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:std
 +extern crate st$0d;
 +//- /std/lib.rs crate:std
 +//! Standard library for this test
 +//!
 +//! Printed?
 +//! abc123
 +"#,
 +        expect![[r#"
 +                *std*
 +
 +                ```rust
 +                extern crate std
 +                ```
 +
 +                ---
 +
 +                Standard library for this test
 +
 +                Printed?
 +                abc123
 +            "#]],
 +    );
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:std
 +extern crate std as ab$0c;
 +//- /std/lib.rs crate:std
 +//! Standard library for this test
 +//!
 +//! Printed?
 +//! abc123
 +"#,
 +        expect![[r#"
 +                *abc*
 +
 +                ```rust
 +                extern crate std
 +                ```
 +
 +                ---
 +
 +                Standard library for this test
 +
 +                Printed?
 +                abc123
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_mod_with_same_name_as_function() {
 +    check(
 +        r#"
 +use self::m$0y::Bar;
 +mod my { pub struct Bar; }
 +
 +fn my() {}
 +"#,
 +        expect![[r#"
 +                *my*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                mod my
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_struct_doc_comment() {
 +    check(
 +        r#"
 +/// This is an example
 +/// multiline doc
 +///
 +/// # Example
 +///
 +/// ```
 +/// let five = 5;
 +///
 +/// assert_eq!(6, my_crate::add_one(5));
 +/// ```
 +struct Bar;
 +
 +fn foo() { let bar = Ba$0r; }
 +"#,
 +        expect![[r##"
 +                *Bar*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                struct Bar
 +                ```
 +
 +                ---
 +
 +                This is an example
 +                multiline doc
 +
 +                # Example
 +
 +                ```
 +                let five = 5;
 +
 +                assert_eq!(6, my_crate::add_one(5));
 +                ```
 +            "##]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_struct_doc_attr() {
 +    check(
 +        r#"
 +#[doc = "bar docs"]
 +struct Bar;
 +
 +fn foo() { let bar = Ba$0r; }
 +"#,
 +        expect![[r#"
 +                *Bar*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                struct Bar
 +                ```
 +
 +                ---
 +
 +                bar docs
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_struct_doc_attr_multiple_and_mixed() {
 +    check(
 +        r#"
 +/// bar docs 0
 +#[doc = "bar docs 1"]
 +#[doc = "bar docs 2"]
 +struct Bar;
 +
 +fn foo() { let bar = Ba$0r; }
 +"#,
 +        expect![[r#"
 +                *Bar*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                struct Bar
 +                ```
 +
 +                ---
 +
 +                bar docs 0
 +                bar docs 1
 +                bar docs 2
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_external_url() {
 +    check(
 +        r#"
 +pub struct Foo;
 +/// [external](https://www.google.com)
 +pub struct B$0ar
 +"#,
 +        expect![[r#"
 +                *Bar*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub struct Bar
 +                ```
 +
 +                ---
 +
 +                [external](https://www.google.com)
 +            "#]],
 +    );
 +}
 +
 +// Check that we don't rewrite links which we can't identify
 +#[test]
 +fn test_hover_unknown_target() {
 +    check(
 +        r#"
 +pub struct Foo;
 +/// [baz](Baz)
 +pub struct B$0ar
 +"#,
 +        expect![[r#"
 +                *Bar*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub struct Bar
 +                ```
 +
 +                ---
 +
 +                [baz](Baz)
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_no_links() {
 +    check_hover_no_links(
 +        r#"
 +/// Test cases:
 +/// case 1.  bare URL: https://www.example.com/
 +/// case 2.  inline URL with title: [example](https://www.example.com/)
 +/// case 3.  code reference: [`Result`]
 +/// case 4.  code reference but miss footnote: [`String`]
 +/// case 5.  autolink: <http://www.example.com/>
 +/// case 6.  email address: <test@example.com>
 +/// case 7.  reference: [example][example]
 +/// case 8.  collapsed link: [example][]
 +/// case 9.  shortcut link: [example]
 +/// case 10. inline without URL: [example]()
 +/// case 11. reference: [foo][foo]
 +/// case 12. reference: [foo][bar]
 +/// case 13. collapsed link: [foo][]
 +/// case 14. shortcut link: [foo]
 +/// case 15. inline without URL: [foo]()
 +/// case 16. just escaped text: \[foo]
 +/// case 17. inline link: [Foo](foo::Foo)
 +///
 +/// [`Result`]: ../../std/result/enum.Result.html
 +/// [^example]: https://www.example.com/
 +pub fn fo$0o() {}
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub fn foo()
 +                ```
 +
 +                ---
 +
 +                Test cases:
 +                case 1.  bare URL: https://www.example.com/
 +                case 2.  inline URL with title: [example](https://www.example.com/)
 +                case 3.  code reference: `Result`
 +                case 4.  code reference but miss footnote: `String`
 +                case 5.  autolink: http://www.example.com/
 +                case 6.  email address: test@example.com
 +                case 7.  reference: example
 +                case 8.  collapsed link: example
 +                case 9.  shortcut link: example
 +                case 10. inline without URL: example
 +                case 11. reference: foo
 +                case 12. reference: foo
 +                case 13. collapsed link: foo
 +                case 14. shortcut link: foo
 +                case 15. inline without URL: foo
 +                case 16. just escaped text: \[foo\]
 +                case 17. inline link: Foo
 +
 +                [^example]: https://www.example.com/
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_macro_generated_struct_fn_doc_comment() {
 +    cov_mark::check!(hover_macro_generated_struct_fn_doc_comment);
 +
 +    check(
 +        r#"
 +macro_rules! bar {
 +    () => {
 +        struct Bar;
 +        impl Bar {
 +            /// Do the foo
 +            fn foo(&self) {}
 +        }
 +    }
 +}
 +
 +bar!();
 +
 +fn foo() { let bar = Bar; bar.fo$0o(); }
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test::Bar
 +                ```
 +
 +                ```rust
 +                fn foo(&self)
 +                ```
 +
 +                ---
 +
 +                Do the foo
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_macro_generated_struct_fn_doc_attr() {
 +    cov_mark::check!(hover_macro_generated_struct_fn_doc_attr);
 +
 +    check(
 +        r#"
 +macro_rules! bar {
 +    () => {
 +        struct Bar;
 +        impl Bar {
 +            #[doc = "Do the foo"]
 +            fn foo(&self) {}
 +        }
 +    }
 +}
 +
 +bar!();
 +
 +fn foo() { let bar = Bar; bar.fo$0o(); }
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test::Bar
 +                ```
 +
 +                ```rust
 +                fn foo(&self)
 +                ```
 +
 +                ---
 +
 +                Do the foo
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_variadic_function() {
 +    check(
 +        r#"
 +extern "C" {
 +    pub fn foo(bar: i32, ...) -> i32;
 +}
 +
 +fn main() { let foo_test = unsafe { fo$0o(1, 2, 3); } }
 +"#,
 +        expect![[r#"
 +            *foo*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            pub unsafe fn foo(bar: i32, ...) -> i32
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_trait_has_impl_action() {
 +    check_actions(
 +        r#"trait foo$0() {}"#,
 +        expect![[r#"
 +                [
 +                    Implementation(
 +                        FilePosition {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            offset: 6,
 +                        },
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_struct_has_impl_action() {
 +    check_actions(
 +        r"struct foo$0() {}",
 +        expect![[r#"
 +                [
 +                    Implementation(
 +                        FilePosition {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            offset: 7,
 +                        },
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_union_has_impl_action() {
 +    check_actions(
 +        r#"union foo$0() {}"#,
 +        expect![[r#"
 +                [
 +                    Implementation(
 +                        FilePosition {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            offset: 6,
 +                        },
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_enum_has_impl_action() {
 +    check_actions(
 +        r"enum foo$0() { A, B }",
 +        expect![[r#"
 +                [
 +                    Implementation(
 +                        FilePosition {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            offset: 5,
 +                        },
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_self_has_impl_action() {
 +    check_actions(
 +        r#"struct foo where Self$0:;"#,
 +        expect![[r#"
 +                [
 +                    Implementation(
 +                        FilePosition {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            offset: 7,
 +                        },
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_test_has_action() {
 +    check_actions(
 +        r#"
 +#[test]
 +fn foo_$0test() {}
 +"#,
 +        expect![[r#"
 +            [
 +                Reference(
 +                    FilePosition {
 +                        file_id: FileId(
 +                            0,
 +                        ),
 +                        offset: 11,
 +                    },
 +                ),
 +                Runnable(
 +                    Runnable {
 +                        use_name_in_title: false,
 +                        nav: NavigationTarget {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            full_range: 0..24,
 +                            focus_range: 11..19,
 +                            name: "foo_test",
 +                            kind: Function,
 +                        },
 +                        kind: Test {
 +                            test_id: Path(
 +                                "foo_test",
 +                            ),
 +                            attr: TestAttr {
 +                                ignore: false,
 +                            },
 +                        },
 +                        cfg: None,
 +                    },
 +                ),
 +            ]
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_test_mod_has_action() {
 +    check_actions(
 +        r#"
 +mod tests$0 {
 +    #[test]
 +    fn foo_test() {}
 +}
 +"#,
 +        expect![[r#"
 +                [
 +                    Runnable(
 +                        Runnable {
 +                            use_name_in_title: false,
 +                            nav: NavigationTarget {
 +                                file_id: FileId(
 +                                    0,
 +                                ),
 +                                full_range: 0..46,
 +                                focus_range: 4..9,
 +                                name: "tests",
 +                                kind: Module,
 +                                description: "mod tests",
 +                            },
 +                            kind: TestMod {
 +                                path: "tests",
 +                            },
 +                            cfg: None,
 +                        },
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_struct_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +struct S{ f1: u32 }
 +
 +fn main() { let s$0t = S{ f1:0 }; }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..19,
 +                                    focus_range: 7..8,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_generic_struct_has_goto_type_actions() {
 +    check_actions(
 +        r#"
 +struct Arg(u32);
 +struct S<T>{ f1: T }
 +
 +fn main() { let s$0t = S{ f1:Arg(0) }; }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 17..37,
 +                                    focus_range: 24..25,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Arg",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..16,
 +                                    focus_range: 7..10,
 +                                    name: "Arg",
 +                                    kind: Struct,
 +                                    description: "struct Arg",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_generic_struct_has_flattened_goto_type_actions() {
 +    check_actions(
 +        r#"
 +struct Arg(u32);
 +struct S<T>{ f1: T }
 +
 +fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 17..37,
 +                                    focus_range: 24..25,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Arg",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..16,
 +                                    focus_range: 7..10,
 +                                    name: "Arg",
 +                                    kind: Struct,
 +                                    description: "struct Arg",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_tuple_has_goto_type_actions() {
 +    check_actions(
 +        r#"
 +struct A(u32);
 +struct B(u32);
 +mod M {
 +    pub struct C(u32);
 +}
 +
 +fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::A",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..14,
 +                                    focus_range: 7..8,
 +                                    name: "A",
 +                                    kind: Struct,
 +                                    description: "struct A",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::B",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 15..29,
 +                                    focus_range: 22..23,
 +                                    name: "B",
 +                                    kind: Struct,
 +                                    description: "struct B",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::M::C",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 42..60,
 +                                    focus_range: 53..54,
 +                                    name: "C",
 +                                    kind: Struct,
 +                                    description: "pub struct C",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_return_impl_trait_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {}
 +fn foo() -> impl Foo {}
 +
 +fn main() { let s$0t = foo(); }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_generic_return_impl_trait_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo<T> {}
 +struct S;
 +fn foo() -> impl Foo<S> {}
 +
 +fn main() { let s$0t = foo(); }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..15,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 16..25,
 +                                    focus_range: 23..24,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_return_impl_traits_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {}
 +trait Bar {}
 +fn foo() -> impl Foo + Bar {}
 +
 +fn main() { let s$0t = foo(); }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Bar",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 13..25,
 +                                    focus_range: 19..22,
 +                                    name: "Bar",
 +                                    kind: Trait,
 +                                    description: "trait Bar",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_generic_return_impl_traits_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo<T> {}
 +trait Bar<T> {}
 +struct S1 {}
 +struct S2 {}
 +
 +fn foo() -> impl Foo<S1> + Bar<S2> {}
 +
 +fn main() { let s$0t = foo(); }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..15,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Bar",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 16..31,
 +                                    focus_range: 22..25,
 +                                    name: "Bar",
 +                                    kind: Trait,
 +                                    description: "trait Bar<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S1",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 32..44,
 +                                    focus_range: 39..41,
 +                                    name: "S1",
 +                                    kind: Struct,
 +                                    description: "struct S1",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S2",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 45..57,
 +                                    focus_range: 52..54,
 +                                    name: "S2",
 +                                    kind: Struct,
 +                                    description: "struct S2",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_arg_impl_trait_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {}
 +fn foo(ar$0g: &impl Foo) {}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_arg_impl_traits_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {}
 +trait Bar<T> {}
 +struct S{}
 +
 +fn foo(ar$0g: &impl Foo + Bar<S>) {}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Bar",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 13..28,
 +                                    focus_range: 19..22,
 +                                    name: "Bar",
 +                                    kind: Trait,
 +                                    description: "trait Bar<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 29..39,
 +                                    focus_range: 36..37,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_async_block_impl_trait_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +//- /main.rs crate:main deps:core
 +// we don't use minicore here so that this test doesn't randomly fail
 +// when someone edits minicore
 +struct S;
 +fn foo() {
 +    let fo$0o = async { S };
 +}
 +//- /core.rs crate:core
 +pub mod future {
 +    #[lang = "future_trait"]
 +    pub trait Future {}
 +}
 +"#,
 +        expect![[r#"
 +            [
 +                GoToType(
 +                    [
 +                        HoverGotoTypeData {
 +                            mod_path: "core::future::Future",
 +                            nav: NavigationTarget {
 +                                file_id: FileId(
 +                                    1,
 +                                ),
 +                                full_range: 21..69,
 +                                focus_range: 60..66,
 +                                name: "Future",
 +                                kind: Trait,
 +                                description: "pub trait Future",
 +                            },
 +                        },
 +                        HoverGotoTypeData {
 +                            mod_path: "main::S",
 +                            nav: NavigationTarget {
 +                                file_id: FileId(
 +                                    0,
 +                                ),
 +                                full_range: 0..110,
 +                                focus_range: 108..109,
 +                                name: "S",
 +                                kind: Struct,
 +                                description: "struct S",
 +                            },
 +                        },
 +                    ],
 +                ),
 +            ]
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo<T> {}
 +struct S {}
 +fn foo(ar$0g: &impl Foo<S>) {}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..15,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 16..27,
 +                                    focus_range: 23..24,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_dyn_return_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {}
 +struct S;
 +impl Foo for S {}
 +
 +struct B<T>{}
 +fn foo() -> B<dyn Foo> {}
 +
 +fn main() { let s$0t = foo(); }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::B",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 42..55,
 +                                    focus_range: 49..50,
 +                                    name: "B",
 +                                    kind: Struct,
 +                                    description: "struct B<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_dyn_arg_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {}
 +fn foo(ar$0g: &dyn Foo) {}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_generic_dyn_arg_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo<T> {}
 +struct S {}
 +fn foo(ar$0g: &dyn Foo<S>) {}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..15,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 16..27,
 +                                    focus_range: 23..24,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_goto_type_action_links_order() {
 +    check_actions(
 +        r#"
 +trait ImplTrait<T> {}
 +trait DynTrait<T> {}
 +struct B<T> {}
 +struct S {}
 +
 +fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::ImplTrait",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..21,
 +                                    focus_range: 6..15,
 +                                    name: "ImplTrait",
 +                                    kind: Trait,
 +                                    description: "trait ImplTrait<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::B",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 43..57,
 +                                    focus_range: 50..51,
 +                                    name: "B",
 +                                    kind: Struct,
 +                                    description: "struct B<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::DynTrait",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 22..42,
 +                                    focus_range: 28..36,
 +                                    name: "DynTrait",
 +                                    kind: Trait,
 +                                    description: "trait DynTrait<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 58..69,
 +                                    focus_range: 65..66,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_associated_type_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {
 +    type Item;
 +    fn get(self) -> Self::Item {}
 +}
 +
 +struct Bar{}
 +struct S{}
 +
 +impl Foo for S { type Item = Bar; }
 +
 +fn test() -> impl Foo { S {} }
 +
 +fn main() { let s$0t = test().get(); }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..62,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_const_param_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +struct Bar;
 +struct Foo<const BAR: Bar>;
 +
 +impl<const BAR: Bar> Foo<BAR$0> {}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Bar",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..11,
 +                                    focus_range: 7..10,
 +                                    name: "Bar",
 +                                    kind: Struct,
 +                                    description: "struct Bar",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_type_param_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {}
 +
 +fn foo<T: Foo>(t: T$0){}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_self_has_go_to_type() {
 +    check_actions(
 +        r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self$0) {}
 +}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..11,
 +                                    focus_range: 7..10,
 +                                    name: "Foo",
 +                                    kind: Struct,
 +                                    description: "struct Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_displays_normalized_crate_names() {
 +    check(
 +        r#"
 +//- /lib.rs crate:name-with-dashes
 +pub mod wrapper {
 +    pub struct Thing { x: u32 }
 +
 +    impl Thing {
 +        pub fn new() -> Thing { Thing { x: 0 } }
 +    }
 +}
 +
 +//- /main.rs crate:main deps:name-with-dashes
 +fn main() { let foo_test = name_with_dashes::wrapper::Thing::new$0(); }
 +"#,
 +        expect![[r#"
 +            *new*
 +
 +            ```rust
 +            name_with_dashes::wrapper::Thing
 +            ```
 +
 +            ```rust
 +            pub fn new() -> Thing
 +            ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_field_pat_shorthand_ref_match_ergonomics() {
 +    check(
 +        r#"
 +struct S {
 +    f: i32,
 +}
 +
 +fn main() {
 +    let s = S { f: 0 };
 +    let S { f$0 } = &s;
 +}
 +"#,
 +        expect![[r#"
 +            *f*
 +
 +            ```rust
 +            f: &i32
 +            ```
 +            ---
 +
 +            ```rust
 +            test::S
 +            ```
 +
 +            ```rust
 +            f: i32
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn const_generic_order() {
 +    check(
 +        r#"
 +struct Foo;
 +struct S$0T<const C: usize = 1, T = Foo>(T);
 +"#,
 +        expect![[r#"
 +            *ST*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            struct ST<const C: usize, T = Foo>
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn const_generic_positive_i8_literal() {
 +    check(
 +        r#"
 +struct Const<const N: i8>;
 +
 +fn main() {
 +    let v$0alue = Const::<1>;
 +}
 +"#,
 +        expect![[r#"
 +            *value*
 +
 +            ```rust
 +            let value: Const<1>
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn const_generic_zero_i8_literal() {
 +    check(
 +        r#"
 +struct Const<const N: i8>;
 +
 +fn main() {
 +    let v$0alue = Const::<0>;
 +}
 +"#,
 +        expect![[r#"
 +            *value*
 +
 +            ```rust
 +            let value: Const<0>
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn const_generic_negative_i8_literal() {
 +    check(
 +        r#"
 +struct Const<const N: i8>;
 +
 +fn main() {
 +    let v$0alue = Const::<-1>;
 +}
 +"#,
 +        expect![[r#"
 +            *value*
 +
 +            ```rust
 +            let value: Const<-1>
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn const_generic_bool_literal() {
 +    check(
 +        r#"
 +struct Const<const F: bool>;
 +
 +fn main() {
 +    let v$0alue = Const::<true>;
 +}
 +"#,
 +        expect![[r#"
 +            *value*
 +
 +            ```rust
 +            let value: Const<true>
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn const_generic_char_literal() {
 +    check(
 +        r#"
 +struct Const<const C: char>;
 +
 +fn main() {
 +    let v$0alue = Const::<'🦀'>;
 +}
 +"#,
 +        expect![[r#"
 +            *value*
 +
 +            ```rust
 +            let value: Const<'🦀'>
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_self_param_shows_type() {
 +    check(
 +        r#"
 +struct Foo {}
 +impl Foo {
 +    fn bar(&sel$0f) {}
 +}
 +"#,
 +        expect![[r#"
 +                *self*
 +
 +                ```rust
 +                self: &Foo
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_self_param_shows_type_for_arbitrary_self_type() {
 +    check(
 +        r#"
 +struct Arc<T>(T);
 +struct Foo {}
 +impl Foo {
 +    fn bar(sel$0f: Arc<Foo>) {}
 +}
 +"#,
 +        expect![[r#"
 +                *self*
 +
 +                ```rust
 +                self: Arc<Foo>
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_doc_outer_inner() {
 +    check(
 +        r#"
 +/// Be quick;
 +mod Foo$0 {
 +    //! time is mana
 +
 +    /// This comment belongs to the function
 +    fn foo() {}
 +}
 +"#,
 +        expect![[r#"
 +                *Foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                mod Foo
 +                ```
 +
 +                ---
 +
 +                Be quick;
 +                time is mana
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_doc_outer_inner_attribue() {
 +    check(
 +        r#"
 +#[doc = "Be quick;"]
 +mod Foo$0 {
 +    #![doc = "time is mana"]
 +
 +    #[doc = "This comment belongs to the function"]
 +    fn foo() {}
 +}
 +"#,
 +        expect![[r#"
 +                *Foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                mod Foo
 +                ```
 +
 +                ---
 +
 +                Be quick;
 +                time is mana
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_doc_block_style_indentend() {
 +    check(
 +        r#"
 +/**
 +    foo
 +    ```rust
 +    let x = 3;
 +    ```
 +*/
 +fn foo$0() {}
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                fn foo()
 +                ```
 +
 +                ---
 +
 +                foo
 +
 +                ```rust
 +                let x = 3;
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_comments_dont_highlight_parent() {
 +    cov_mark::check!(no_highlight_on_comment_hover);
 +    check_hover_no_result(
 +        r#"
 +fn no_hover() {
 +    // no$0hover
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn hover_label() {
 +    check(
 +        r#"
 +fn foo() {
 +    'label$0: loop {}
 +}
 +"#,
 +        expect![[r#"
 +            *'label*
 +
 +            ```rust
 +            'label
 +            ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_lifetime() {
 +    check(
 +        r#"fn foo<'lifetime>(_: &'lifetime$0 ()) {}"#,
 +        expect![[r#"
 +            *'lifetime*
 +
 +            ```rust
 +            'lifetime
 +            ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_type_param() {
 +    check(
 +        r#"
 +//- minicore: sized
 +struct Foo<T>(T);
 +trait TraitA {}
 +trait TraitB {}
 +impl<T: TraitA + TraitB> Foo<T$0> where T: Sized {}
 +"#,
 +        expect![[r#"
 +                *T*
 +
 +                ```rust
 +                T: TraitA + TraitB
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +//- minicore: sized
 +struct Foo<T>(T);
 +impl<T> Foo<T$0> {}
 +"#,
 +        expect![[r#"
 +                *T*
 +
 +                ```rust
 +                T
 +                ```
 +                "#]],
 +    );
 +    // lifetimes bounds arent being tracked yet
 +    check(
 +        r#"
 +//- minicore: sized
 +struct Foo<T>(T);
 +impl<T: 'static> Foo<T$0> {}
 +"#,
 +        expect![[r#"
 +                *T*
 +
 +                ```rust
 +                T
 +                ```
 +                "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_type_param_sized_bounds() {
 +    // implicit `: Sized` bound
 +    check(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +struct Foo<T>(T);
 +impl<T: Trait> Foo<T$0> {}
 +"#,
 +        expect![[r#"
 +                *T*
 +
 +                ```rust
 +                T: Trait
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +struct Foo<T>(T);
 +impl<T: Trait + ?Sized> Foo<T$0> {}
 +"#,
 +        expect![[r#"
 +                *T*
 +
 +                ```rust
 +                T: Trait + ?Sized
 +                ```
 +            "#]],
 +    );
 +}
 +
 +mod type_param_sized_bounds {
 +    use super::*;
 +
 +    #[test]
 +    fn single_implicit() {
 +        check(
 +            r#"
 +//- minicore: sized
 +fn foo<T$0>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T
 +                    ```
 +                "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn single_explicit() {
 +        check(
 +            r#"
 +//- minicore: sized
 +fn foo<T$0: Sized>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T
 +                    ```
 +                "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn single_relaxed() {
 +        check(
 +            r#"
 +//- minicore: sized
 +fn foo<T$0: ?Sized>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T: ?Sized
 +                    ```
 +                "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn multiple_implicit() {
 +        check(
 +            r#"
 +//- minicore: sized
 +trait Trait {}
 +fn foo<T$0: Trait>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T: Trait
 +                    ```
 +                "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn multiple_explicit() {
 +        check(
 +            r#"
 +//- minicore: sized
 +trait Trait {}
 +fn foo<T$0: Trait + Sized>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T: Trait
 +                    ```
 +                "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn multiple_relaxed() {
 +        check(
 +            r#"
 +//- minicore: sized
 +trait Trait {}
 +fn foo<T$0: Trait + ?Sized>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T: Trait + ?Sized
 +                    ```
 +                "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn mixed() {
 +        check(
 +            r#"
 +//- minicore: sized
 +fn foo<T$0: ?Sized + Sized + Sized>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T
 +                    ```
 +                "#]],
 +        );
 +        check(
 +            r#"
 +//- minicore: sized
 +trait Trait {}
 +fn foo<T$0: Sized + ?Sized + Sized + Trait>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T: Trait
 +                    ```
 +                "#]],
 +        );
 +    }
 +}
 +
 +#[test]
 +fn hover_const_generic_type_alias() {
 +    check(
 +        r#"
 +struct Foo<const LEN: usize>;
 +type Fo$0o2 = Foo<2>;
 +"#,
 +        expect![[r#"
 +                *Foo2*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                type Foo2 = Foo<2>
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_const_param() {
 +    check(
 +        r#"
 +struct Foo<const LEN: usize>;
 +impl<const LEN: usize> Foo<LEN$0> {}
 +"#,
 +        expect![[r#"
 +                *LEN*
 +
 +                ```rust
 +                const LEN: usize
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_const_eval_variant() {
 +    // show hex for <10
 +    check(
 +        r#"
 +#[repr(u8)]
 +enum E {
 +    /// This is a doc
 +    A$0 = 1 << 3,
 +}
 +"#,
 +        expect![[r#"
 +            *A*
 +
 +            ```rust
 +            test::E
 +            ```
 +
 +            ```rust
 +            A = 8
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show hex for >10
 +    check(
 +        r#"
 +#[repr(u8)]
 +enum E {
 +    /// This is a doc
 +    A$0 = (1 << 3) + (1 << 2),
 +}
 +"#,
 +        expect![[r#"
 +            *A*
 +
 +            ```rust
 +            test::E
 +            ```
 +
 +            ```rust
 +            A = 12 (0xC)
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // enums in const eval
 +    check(
 +        r#"
 +#[repr(u8)]
 +enum E {
 +    A = 1,
 +    /// This is a doc
 +    B$0 = E::A as u8 + 1,
 +}
 +"#,
 +        expect![[r#"
 +            *B*
 +
 +            ```rust
 +            test::E
 +            ```
 +
 +            ```rust
 +            B = 2
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // unspecified variant should increment by one
 +    check(
 +        r#"
 +#[repr(u8)]
 +enum E {
 +    A = 4,
 +    /// This is a doc
 +    B$0,
 +}
 +"#,
 +        expect![[r#"
 +            *B*
 +
 +            ```rust
 +            test::E
 +            ```
 +
 +            ```rust
 +            B = 5
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_const_eval() {
 +    // show hex for <10
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: usize = 1 << 3;
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: usize = 8
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show hex for >10
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: usize = (1 << 3) + (1 << 2);
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: usize = 12 (0xC)
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show original body when const eval fails
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: usize = 2 - 3;
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: usize = 2 - 3
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // don't show hex for negatives
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: i32 = 2 - 3;
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: i32 = -1
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: &str = "bar";
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: &str = "bar"
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show char literal
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: char = 'a';
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: char = 'a'
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show escaped char literal
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: char = '\x61';
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: char = 'a'
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show byte literal
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: u8 = b'a';
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: u8 = 97 (0x61)
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show escaped byte literal
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: u8 = b'\x61';
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: u8 = 97 (0x61)
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show float literal
 +    check(
 +        r#"
 +    /// This is a doc
 +    const FOO$0: f64 = 1.0234;
 +    "#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: f64 = 1.0234
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    //show float typecasted from int
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: f32 = 1f32;
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: f32 = 1.0
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    //show f64 typecasted from float
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: f64 = 1.0f64;
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: f64 = 1.0
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_const_pat() {
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO: usize = 3;
 +fn foo() {
 +    match 5 {
 +        FOO$0 => (),
 +        _ => ()
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: usize = 3
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    check(
 +        r#"
 +enum E {
 +    /// This is a doc
 +    A = 3,
 +}
 +fn foo(e: E) {
 +    match e {
 +        E::A$0 => (),
 +        _ => ()
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            *A*
 +
 +            ```rust
 +            test::E
 +            ```
 +
 +            ```rust
 +            A = 3
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn array_repeat_exp() {
 +    check(
 +        r#"
 +fn main() {
 +    let til$0e4 = [0_u32; (4 * 8 * 8) / 32];
 +}
 +        "#,
 +        expect![[r#"
 +            *tile4*
 +
 +            ```rust
 +            let tile4: [u32; 8]
 +            ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_mod_def() {
 +    check(
 +        r#"
 +//- /main.rs
 +mod foo$0;
 +//- /foo.rs
 +//! For the horde!
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                mod foo
 +                ```
 +
 +                ---
 +
 +                For the horde!
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_self_in_use() {
 +    check(
 +        r#"
 +//! This should not appear
 +mod foo {
 +    /// But this should appear
 +    pub mod bar {}
 +}
 +use foo::bar::{self$0};
 +"#,
 +        expect![[r#"
 +                *self*
 +
 +                ```rust
 +                test::foo
 +                ```
 +
 +                ```rust
 +                mod bar
 +                ```
 +
 +                ---
 +
 +                But this should appear
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_keyword() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:std
 +fn f() { retur$0n; }
 +//- /libstd.rs crate:std
 +/// Docs for return_keyword
 +mod return_keyword {}
 +"#,
 +        expect![[r#"
 +                *return*
 +
 +                ```rust
 +                return
 +                ```
 +
 +                ---
 +
 +                Docs for return_keyword
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_keyword_doc() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:std
 +fn foo() {
 +    let bar = mov$0e || {};
 +}
 +//- /libstd.rs crate:std
 +#[doc(keyword = "move")]
 +/// [closure]
 +/// [closures][closure]
 +/// [threads]
 +/// <https://doc.rust-lang.org/nightly/book/ch13-01-closures.html>
 +///
 +/// [closure]: ../book/ch13-01-closures.html
 +/// [threads]: ../book/ch16-01-threads.html#using-move-closures-with-threads
 +mod move_keyword {}
 +"#,
 +        expect![[r##"
 +            *move*
 +
 +            ```rust
 +            move
 +            ```
 +
 +            ---
 +
 +            [closure](https://doc.rust-lang.org/nightly/book/ch13-01-closures.html)
 +            [closures](https://doc.rust-lang.org/nightly/book/ch13-01-closures.html)
 +            [threads](https://doc.rust-lang.org/nightly/book/ch16-01-threads.html#using-move-closures-with-threads)
 +            <https://doc.rust-lang.org/nightly/book/ch13-01-closures.html>
 +        "##]],
 +    );
 +}
 +
 +#[test]
 +fn hover_keyword_as_primitive() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:std
 +type F = f$0n(i32) -> i32;
 +//- /libstd.rs crate:std
 +/// Docs for prim_fn
 +mod prim_fn {}
 +"#,
 +        expect![[r#"
 +                *fn*
 +
 +                ```rust
 +                fn
 +                ```
 +
 +                ---
 +
 +                Docs for prim_fn
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_builtin() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:std
 +cosnt _: &str$0 = ""; }
 +
 +//- /libstd.rs crate:std
 +/// Docs for prim_str
 +/// [`foo`](../std/keyword.foo.html)
 +mod prim_str {}
 +"#,
 +        expect![[r#"
 +                *str*
 +
 +                ```rust
 +                str
 +                ```
 +
 +                ---
 +
 +                Docs for prim_str
 +                [`foo`](https://doc.rust-lang.org/nightly/std/keyword.foo.html)
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_macro_expanded_function() {
 +    check(
 +        r#"
 +struct S<'a, T>(&'a T);
 +trait Clone {}
 +macro_rules! foo {
 +    () => {
 +        fn bar<'t, T: Clone + 't>(s: &mut S<'t, T>, t: u32) -> *mut u32 where
 +            't: 't + 't,
 +            for<'a> T: Clone + 'a
 +        { 0 as _ }
 +    };
 +}
 +
 +foo!();
 +
 +fn main() {
 +    bar$0;
 +}
 +"#,
 +        expect![[r#"
 +                *bar*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32
 +                where
 +                    T: Clone + 't,
 +                    't: 't + 't,
 +                    for<'a> T: Clone + 'a,
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_intra_doc_links() {
 +    check(
 +        r#"
 +
 +pub mod theitem {
 +    /// This is the item. Cool!
 +    pub struct TheItem;
 +}
 +
 +/// Gives you a [`TheItem$0`].
 +///
 +/// [`TheItem`]: theitem::TheItem
 +pub fn gimme() -> theitem::TheItem {
 +    theitem::TheItem
 +}
 +"#,
 +        expect![[r#"
 +                *[`TheItem`]*
 +
 +                ```rust
 +                test::theitem
 +                ```
 +
 +                ```rust
 +                pub struct TheItem
 +                ```
 +
 +                ---
 +
 +                This is the item. Cool!
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_trait_assoc_typealias() {
 +    check(
 +        r#"
 +        fn main() {}
 +
 +trait T1 {
 +    type Bar;
 +    type Baz;
 +}
 +
 +struct Foo;
 +
 +mod t2 {
 +    pub trait T2 {
 +        type Bar;
 +    }
 +}
 +
 +use t2::T2;
 +
 +impl T2 for Foo {
 +    type Bar = String;
 +}
 +
 +impl T1 for Foo {
 +    type Bar = <Foo as t2::T2>::Ba$0r;
 +    //                          ^^^ unresolvedReference
 +}
 +        "#,
 +        expect![[r#"
 +*Bar*
 +
 +```rust
 +test::t2
 +```
 +
 +```rust
 +pub type Bar
 +```
 +"#]],
 +    );
 +}
 +#[test]
 +fn hover_generic_assoc() {
 +    check(
 +        r#"
 +fn foo<T: A>() where T::Assoc$0: {}
 +
 +trait A {
 +    type Assoc;
 +}"#,
 +        expect![[r#"
 +                *Assoc*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                type Assoc
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +fn foo<T: A>() {
 +    let _: <T>::Assoc$0;
 +}
 +
 +trait A {
 +    type Assoc;
 +}"#,
 +        expect![[r#"
 +                *Assoc*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                type Assoc
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +trait A where
 +    Self::Assoc$0: ,
 +{
 +    type Assoc;
 +}"#,
 +        expect![[r#"
 +                *Assoc*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                type Assoc
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn string_shadowed_with_inner_items() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:alloc
 +
 +/// Custom `String` type.
 +struct String;
 +
 +fn f() {
 +    let _: String$0;
 +
 +    fn inner() {}
 +}
 +
 +//- /alloc.rs crate:alloc
 +#[prelude_import]
 +pub use string::*;
 +
 +mod string {
 +    /// This is `alloc::String`.
 +    pub struct String;
 +}
 +"#,
 +        expect![[r#"
 +                *String*
 +
 +                ```rust
 +                main
 +                ```
 +
 +                ```rust
 +                struct String
 +                ```
 +
 +                ---
 +
 +                Custom `String` type.
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn function_doesnt_shadow_crate_in_use_tree() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:foo
 +use foo$0::{foo};
 +
 +//- /foo.rs crate:foo
 +pub fn foo() {}
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                extern crate foo
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_feature() {
 +    check(
 +        r#"#![feature(box_syntax$0)]"#,
 +        expect![[r##"
 +                *box_syntax*
 +                ```
 +                box_syntax
 +                ```
 +                ___
 +
 +                # `box_syntax`
 +
 +                The tracking issue for this feature is: [#49733]
 +
 +                [#49733]: https://github.com/rust-lang/rust/issues/49733
 +
 +                See also [`box_patterns`](box-patterns.md)
 +
 +                ------------------------
 +
 +                Currently the only stable way to create a `Box` is via the `Box::new` method.
 +                Also it is not possible in stable Rust to destructure a `Box` in a match
 +                pattern. The unstable `box` keyword can be used to create a `Box`. An example
 +                usage would be:
 +
 +                ```rust
 +                #![feature(box_syntax)]
 +
 +                fn main() {
 +                    let b = box 5;
 +                }
 +                ```
 +
 +            "##]],
 +    )
 +}
 +
 +#[test]
 +fn hover_lint() {
 +    check(
 +        r#"#![allow(arithmetic_overflow$0)]"#,
 +        expect![[r#"
 +                *arithmetic_overflow*
 +                ```
 +                arithmetic_overflow
 +                ```
 +                ___
 +
 +                arithmetic operation overflows
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_clippy_lint() {
 +    check(
 +        r#"#![allow(clippy::almost_swapped$0)]"#,
 +        expect![[r#"
 +                *almost_swapped*
 +                ```
 +                clippy::almost_swapped
 +                ```
 +                ___
 +
 +                Checks for `foo = bar; bar = foo` sequences.
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_attr_path_qualifier() {
 +    check(
 +        r#"
 +//- /foo.rs crate:foo
 +
 +//- /lib.rs crate:main.rs deps:foo
 +#[fo$0o::bar()]
 +struct Foo;
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                extern crate foo
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_rename() {
 +    check(
 +        r#"
 +use self as foo$0;
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                extern crate test
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +mod bar {}
 +use bar::{self as foo$0};
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                mod bar
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +mod bar {
 +    use super as foo$0;
 +}
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                extern crate test
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +use crate as foo$0;
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                extern crate test
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_attribute_in_macro() {
 +    check(
 +        r#"
 +//- minicore:derive
 +macro_rules! identity {
 +    ($struct:item) => {
 +        $struct
 +    };
 +}
 +#[rustc_builtin_macro]
 +pub macro Copy {}
 +identity!{
 +    #[derive(Copy$0)]
 +    struct Foo;
 +}
 +"#,
 +        expect![[r#"
 +            *Copy*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            macro Copy
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_derive_input() {
 +    check(
 +        r#"
 +//- minicore:derive
 +#[rustc_builtin_macro]
 +pub macro Copy {}
 +#[derive(Copy$0)]
 +struct Foo;
 +"#,
 +        expect![[r#"
 +            *Copy*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            macro Copy
 +            ```
 +        "#]],
 +    );
 +    check(
 +        r#"
 +//- minicore:derive
 +mod foo {
 +    #[rustc_builtin_macro]
 +    pub macro Copy {}
 +}
 +#[derive(foo::Copy$0)]
 +struct Foo;
 +"#,
 +        expect![[r#"
 +            *Copy*
 +
 +            ```rust
 +            test::foo
 +            ```
 +
 +            ```rust
 +            macro Copy
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_range_math() {
 +    check_hover_range(
 +        r#"
 +fn f() { let expr = $01 + 2 * 3$0 }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            i32
 +            ```"#]],
 +    );
 +
 +    check_hover_range(
 +        r#"
 +fn f() { let expr = 1 $0+ 2 * $03 }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            i32
 +            ```"#]],
 +    );
 +
 +    check_hover_range(
 +        r#"
 +fn f() { let expr = 1 + $02 * 3$0 }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            i32
 +            ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_range_arrays() {
 +    check_hover_range(
 +        r#"
 +fn f() { let expr = $0[1, 2, 3, 4]$0 }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            [i32; 4]
 +            ```"#]],
 +    );
 +
 +    check_hover_range(
 +        r#"
 +fn f() { let expr = [1, 2, $03, 4]$0 }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            [i32; 4]
 +            ```"#]],
 +    );
 +
 +    check_hover_range(
 +        r#"
 +fn f() { let expr = [1, 2, $03$0, 4] }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            i32
 +            ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_range_functions() {
 +    check_hover_range(
 +        r#"
 +fn f<T>(a: &[T]) { }
 +fn b() { $0f$0(&[1, 2, 3, 4, 5]); }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            fn f<i32>(&[i32])
 +            ```"#]],
 +    );
 +
 +    check_hover_range(
 +        r#"
 +fn f<T>(a: &[T]) { }
 +fn b() { f($0&[1, 2, 3, 4, 5]$0); }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            &[i32; 5]
 +            ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_range_shows_nothing_when_invalid() {
 +    check_hover_range_no_results(
 +        r#"
 +fn f<T>(a: &[T]) { }
 +fn b()$0 { f(&[1, 2, 3, 4, 5]); }$0
 +"#,
 +    );
 +
 +    check_hover_range_no_results(
 +        r#"
 +fn f<T>$0(a: &[T]) { }
 +fn b() { f(&[1, 2, 3,$0 4, 5]); }
 +"#,
 +    );
 +
 +    check_hover_range_no_results(
 +        r#"
 +fn $0f() { let expr = [1, 2, 3, 4]$0 }
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn hover_range_shows_unit_for_statements() {
 +    check_hover_range(
 +        r#"
 +fn f<T>(a: &[T]) { }
 +fn b() { $0f(&[1, 2, 3, 4, 5]); }$0
 +"#,
 +        expect![[r#"
 +            ```rust
 +            ()
 +            ```"#]],
 +    );
 +
 +    check_hover_range(
 +        r#"
 +fn f() { let expr$0 = $0[1, 2, 3, 4] }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            ()
 +            ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_range_for_pat() {
 +    check_hover_range(
 +        r#"
 +fn foo() {
 +    let $0x$0 = 0;
 +}
 +"#,
 +        expect![[r#"
 +                ```rust
 +                i32
 +                ```"#]],
 +    );
 +
 +    check_hover_range(
 +        r#"
 +fn foo() {
 +    let $0x$0 = "";
 +}
 +"#,
 +        expect![[r#"
 +                ```rust
 +                &str
 +                ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_range_shows_coercions_if_applicable_expr() {
 +    check_hover_range(
 +        r#"
 +fn foo() {
 +    let x: &u32 = $0&&&&&0$0;
 +}
 +"#,
 +        expect![[r#"
 +                ```text
 +                Type:       &&&&&u32
 +                Coerced to:     &u32
 +                ```
 +            "#]],
 +    );
 +    check_hover_range(
 +        r#"
 +fn foo() {
 +    let x: *const u32 = $0&0$0;
 +}
 +"#,
 +        expect![[r#"
 +                ```text
 +                Type:             &u32
 +                Coerced to: *const u32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_range_shows_type_actions() {
 +    check_actions(
 +        r#"
 +struct Foo;
 +fn foo() {
 +    let x: &Foo = $0&&&&&Foo$0;
 +}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..11,
 +                                    focus_range: 7..10,
 +                                    name: "Foo",
 +                                    kind: Struct,
 +                                    description: "struct Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_try_expr_res() {
 +    check_hover_range(
 +        r#"
 +//- minicore:result
 +struct FooError;
 +
 +fn foo() -> Result<(), FooError> {
 +    Ok($0Result::<(), FooError>::Ok(())?$0)
 +}
 +"#,
 +        expect![[r#"
 +                ```rust
 +                ()
 +                ```"#]],
 +    );
 +    check_hover_range(
 +        r#"
 +//- minicore:result
 +struct FooError;
 +struct BarError;
 +
 +fn foo() -> Result<(), FooError> {
 +    Ok($0Result::<(), BarError>::Ok(())?$0)
 +}
 +"#,
 +        expect![[r#"
 +                ```text
 +                Try Error Type: BarError
 +                Propagated as:  FooError
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_try_expr() {
 +    check_hover_range(
 +        r#"
 +struct NotResult<T, U>(T, U);
 +struct Short;
 +struct Looooong;
 +
 +fn foo() -> NotResult<(), Looooong> {
 +    $0NotResult((), Short)?$0;
 +}
 +"#,
 +        expect![[r#"
 +                ```text
 +                Try Target Type:    NotResult<(), Short>
 +                Propagated as:   NotResult<(), Looooong>
 +                ```
 +            "#]],
 +    );
 +    check_hover_range(
 +        r#"
 +struct NotResult<T, U>(T, U);
 +struct Short;
 +struct Looooong;
 +
 +fn foo() -> NotResult<(), Short> {
 +    $0NotResult((), Looooong)?$0;
 +}
 +"#,
 +        expect![[r#"
 +                ```text
 +                Try Target Type: NotResult<(), Looooong>
 +                Propagated as:      NotResult<(), Short>
 +                ```
 +            "#]],
 +    );
-             ```rust
-             i32
-             ```"#]],
 +}
 +
 +#[test]
 +fn hover_try_expr_option() {
 +    cov_mark::check!(hover_try_expr_opt_opt);
 +    check_hover_range(
 +        r#"
 +//- minicore: option, try
 +
 +fn foo() -> Option<()> {
 +    $0Some(0)?$0;
 +    None
 +}
 +"#,
 +        expect![[r#"
++                ```rust
++                <Option<i32> as Try>::Output
++                ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_deref_expr() {
 +    check_hover_range(
 +        r#"
 +//- minicore: deref
 +use core::ops::Deref;
 +
 +struct DerefExample<T> {
 +    value: T
 +}
 +
 +impl<T> Deref for DerefExample<T> {
 +    type Target = T;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.value
 +    }
 +}
 +
 +fn foo() {
 +    let x = DerefExample { value: 0 };
 +    let y: i32 = $0*x$0;
 +}
 +"#,
 +        expect![[r#"
 +                ```text
 +                Dereferenced from: DerefExample<i32>
 +                To type:                         i32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_deref_expr_with_coercion() {
 +    check_hover_range(
 +        r#"
 +//- minicore: deref
 +use core::ops::Deref;
 +
 +struct DerefExample<T> {
 +    value: T
 +}
 +
 +impl<T> Deref for DerefExample<T> {
 +    type Target = T;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.value
 +    }
 +}
 +
 +fn foo() {
 +    let x = DerefExample { value: &&&&&0 };
 +    let y: &i32 = $0*x$0;
 +}
 +"#,
 +        expect![[r#"
 +                ```text
 +                Dereferenced from: DerefExample<&&&&&i32>
 +                To type:                         &&&&&i32
 +                Coerced to:                          &i32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_intra_in_macro() {
 +    check(
 +        r#"
 +macro_rules! foo_macro {
 +    ($(#[$attr:meta])* $name:ident) => {
 +        $(#[$attr])*
 +        pub struct $name;
 +    }
 +}
 +
 +foo_macro!(
 +    /// Doc comment for [`Foo$0`]
 +    Foo
 +);
 +"#,
 +        expect![[r#"
 +            *[`Foo`]*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            pub struct Foo
 +            ```
 +
 +            ---
 +
 +            Doc comment for [`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_intra_in_attr() {
 +    check(
 +        r#"
 +#[doc = "Doc comment for [`Foo$0`]"]
 +pub struct Foo;
 +"#,
 +        expect![[r#"
 +            *[`Foo`]*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            pub struct Foo
 +            ```
 +
 +            ---
 +
 +            Doc comment for [`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_inert_attr() {
 +    check(
 +        r#"
 +#[doc$0 = ""]
 +pub struct Foo;
 +"#,
 +        expect![[r##"
 +            *doc*
 +
 +            ```rust
 +            #[doc]
 +            ```
 +
 +            ---
 +
 +            Valid forms are:
 +
 +            * \#\[doc(hidden|inline|...)\]
 +            * \#\[doc = string\]
 +        "##]],
 +    );
 +    check(
 +        r#"
 +#[allow$0()]
 +pub struct Foo;
 +"#,
 +        expect![[r##"
 +            *allow*
 +
 +            ```rust
 +            #[allow]
 +            ```
 +
 +            ---
 +
 +            Valid forms are:
 +
 +            * \#\[allow(lint1, lint2, ..., /\*opt\*/ reason = "...")\]
 +        "##]],
 +    );
 +}
 +
 +#[test]
 +fn hover_dollar_crate() {
 +    // $crate should be resolved to the right crate name.
 +
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:dep
 +dep::m!(KONST$0);
 +//- /dep.rs crate:dep
 +#[macro_export]
 +macro_rules! m {
 +    ( $name:ident ) => { const $name: $crate::Type = $crate::Type; };
 +}
 +
 +pub struct Type;
 +"#,
 +        expect![[r#"
 +            *KONST*
 +
 +            ```rust
 +            main
 +            ```
 +
 +            ```rust
 +            const KONST: dep::Type = $crate::Type
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_record_variant() {
 +    check(
 +        r#"
 +enum Enum {
 +    RecordV$0 { field: u32 }
 +}
 +"#,
 +        expect![[r#"
 +            *RecordV*
 +
 +            ```rust
 +            test::Enum
 +            ```
 +
 +            ```rust
 +            RecordV { field: u32 }
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_trait_impl_assoc_item_def_doc_forwarding() {
 +    check(
 +        r#"
 +trait T {
 +    /// Trait docs
 +    fn func() {}
 +}
 +impl T for () {
 +    fn func$0() {}
 +}
 +"#,
 +        expect![[r#"
 +            *func*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            fn func()
 +            ```
 +
 +            ---
 +
 +            Trait docs
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_ranged_macro_call() {
 +    check_hover_range(
 +        r#"
 +macro_rules! __rust_force_expr {
 +    ($e:expr) => {
 +        $e
 +    };
 +}
 +macro_rules! vec {
 +    ($elem:expr) => {
 +        __rust_force_expr!($elem)
 +    };
 +}
 +
 +struct Struct;
 +impl Struct {
 +    fn foo(self) {}
 +}
 +
 +fn f() {
 +    $0vec![Struct]$0;
 +}
 +"#,
 +        expect![[r#"
 +            ```rust
 +            Struct
 +            ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_deref() {
 +    check(
 +        r#"
 +//- minicore: deref
 +
 +struct Struct(usize);
 +
 +impl core::ops::Deref for Struct {
 +    type Target = usize;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.0
 +    }
 +}
 +
 +fn f() {
 +    $0*Struct(0);
 +}
 +"#,
 +        expect![[r#"
 +            ***
 +
 +            ```rust
 +            test::Struct
 +            ```
 +
 +            ```rust
 +            fn deref(&self) -> &Self::Target
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn static_const_macro_expanded_body() {
 +    check(
 +        r#"
 +macro_rules! m {
 +    () => {
 +        pub const V: i8 = {
 +            let e = 123;
 +            f(e) // Prevent const eval from evaluating this constant, we want to print the body's code.
 +        };
 +    };
 +}
 +m!();
 +fn main() { $0V; }
 +"#,
 +        expect![[r#"
 +            *V*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            pub const V: i8 = {
 +              let e = 123;
 +              f(e)
 +            }
 +            ```
 +        "#]],
 +    );
 +    check(
 +        r#"
 +macro_rules! m {
 +    () => {
 +        pub static V: i8 = {
 +            let e = 123;
 +        };
 +    };
 +}
 +m!();
 +fn main() { $0V; }
 +"#,
 +        expect![[r#"
 +            *V*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            pub static V: i8 = {
 +              let e = 123;
 +            }
 +            ```
 +        "#]],
 +    );
 +}
index 77fe0dbf5565866dd035718bc009b668cfc0365f,0000000000000000000000000000000000000000..416817ca0b42c8c3bd4d7bb4c9c8b3afa7c43906
mode 100644,000000..100644
--- /dev/null
@@@ -1,704 -1,0 +1,714 @@@
-     pub fn crate_for(&self, file_id: FileId) -> Cancellable<Vec<CrateId>> {
-         self.with_db(|db| parent_module::crate_for(db, file_id))
 +//! ide crate provides "ide-centric" APIs for the rust-analyzer. That is,
 +//! it generally operates with files and text ranges, and returns results as
 +//! Strings, suitable for displaying to the human.
 +//!
 +//! What powers this API are the `RootDatabase` struct, which defines a `salsa`
 +//! database, and the `hir` crate, where majority of the analysis happens.
 +//! However, IDE specific bits of the analysis (most notably completion) happen
 +//! in this crate.
 +
 +// For proving that RootDatabase is RefUnwindSafe.
 +#![recursion_limit = "128"]
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +#[allow(unused)]
 +macro_rules! eprintln {
 +    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
 +}
 +
 +#[cfg(test)]
 +mod fixture;
 +
 +mod markup;
 +mod prime_caches;
 +mod navigation_target;
 +
 +mod annotations;
 +mod call_hierarchy;
 +mod signature_help;
 +mod doc_links;
 +mod highlight_related;
 +mod expand_macro;
 +mod extend_selection;
 +mod file_structure;
 +mod folding_ranges;
 +mod goto_declaration;
 +mod goto_definition;
 +mod goto_implementation;
 +mod goto_type_definition;
 +mod hover;
 +mod inlay_hints;
 +mod join_lines;
 +mod markdown_remove;
 +mod matching_brace;
 +mod moniker;
 +mod move_item;
 +mod parent_module;
 +mod references;
 +mod rename;
 +mod runnables;
 +mod ssr;
 +mod static_index;
 +mod status;
 +mod syntax_highlighting;
 +mod syntax_tree;
 +mod typing;
 +mod view_crate_graph;
 +mod view_hir;
 +mod view_item_tree;
 +mod shuffle_crate_graph;
 +
 +use std::sync::Arc;
 +
 +use cfg::CfgOptions;
 +use ide_db::{
 +    base_db::{
 +        salsa::{self, ParallelDatabase},
 +        CrateOrigin, Env, FileLoader, FileSet, SourceDatabase, VfsPath,
 +    },
 +    symbol_index, LineIndexDatabase,
 +};
 +use syntax::SourceFile;
 +
 +use crate::navigation_target::{ToNav, TryToNav};
 +
 +pub use crate::{
 +    annotations::{Annotation, AnnotationConfig, AnnotationKind, AnnotationLocation},
 +    call_hierarchy::CallItem,
 +    expand_macro::ExpandedMacro,
 +    file_structure::{StructureNode, StructureNodeKind},
 +    folding_ranges::{Fold, FoldKind},
 +    highlight_related::{HighlightRelatedConfig, HighlightedRange},
 +    hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
 +    inlay_hints::{
 +        ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
 +        InlayTooltip, LifetimeElisionHints, ReborrowHints,
 +    },
 +    join_lines::JoinLinesConfig,
 +    markup::Markup,
 +    moniker::{MonikerDescriptorKind, MonikerKind, MonikerResult, PackageInformation},
 +    move_item::Direction,
 +    navigation_target::NavigationTarget,
 +    prime_caches::ParallelPrimeCachesProgress,
 +    references::ReferenceSearchResult,
 +    rename::RenameError,
 +    runnables::{Runnable, RunnableKind, TestId},
 +    signature_help::SignatureHelp,
 +    static_index::{StaticIndex, StaticIndexedFile, TokenId, TokenStaticData},
 +    syntax_highlighting::{
 +        tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag},
 +        HighlightConfig, HlRange,
 +    },
 +};
 +pub use hir::{Documentation, Semantics};
 +pub use ide_assists::{
 +    Assist, AssistConfig, AssistId, AssistKind, AssistResolveStrategy, SingleResolve,
 +};
 +pub use ide_completion::{
 +    CallableSnippets, CompletionConfig, CompletionItem, CompletionItemKind, CompletionRelevance,
 +    Snippet, SnippetScope,
 +};
 +pub use ide_db::{
 +    base_db::{
 +        Cancelled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange,
 +        SourceRoot, SourceRootId,
 +    },
 +    label::Label,
 +    line_index::{LineCol, LineColUtf16, LineIndex},
 +    search::{ReferenceCategory, SearchScope},
 +    source_change::{FileSystemEdit, SourceChange},
 +    symbol_index::Query,
 +    RootDatabase, SymbolKind,
 +};
 +pub use ide_diagnostics::{Diagnostic, DiagnosticsConfig, ExprFillDefaultMode, Severity};
 +pub use ide_ssr::SsrError;
 +pub use syntax::{TextRange, TextSize};
 +pub use text_edit::{Indel, TextEdit};
 +
 +pub type Cancellable<T> = Result<T, Cancelled>;
 +
 +/// Info associated with a text range.
 +#[derive(Debug)]
 +pub struct RangeInfo<T> {
 +    pub range: TextRange,
 +    pub info: T,
 +}
 +
 +impl<T> RangeInfo<T> {
 +    pub fn new(range: TextRange, info: T) -> RangeInfo<T> {
 +        RangeInfo { range, info }
 +    }
 +}
 +
 +/// `AnalysisHost` stores the current state of the world.
 +#[derive(Debug)]
 +pub struct AnalysisHost {
 +    db: RootDatabase,
 +}
 +
 +impl AnalysisHost {
 +    pub fn new(lru_capacity: Option<usize>) -> AnalysisHost {
 +        AnalysisHost { db: RootDatabase::new(lru_capacity) }
 +    }
 +
 +    pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
 +        self.db.update_lru_capacity(lru_capacity);
 +    }
 +
 +    /// Returns a snapshot of the current state, which you can query for
 +    /// semantic information.
 +    pub fn analysis(&self) -> Analysis {
 +        Analysis { db: self.db.snapshot() }
 +    }
 +
 +    /// Applies changes to the current state of the world. If there are
 +    /// outstanding snapshots, they will be canceled.
 +    pub fn apply_change(&mut self, change: Change) {
 +        self.db.apply_change(change)
 +    }
 +
 +    /// NB: this clears the database
 +    pub fn per_query_memory_usage(&mut self) -> Vec<(String, profile::Bytes)> {
 +        self.db.per_query_memory_usage()
 +    }
 +    pub fn request_cancellation(&mut self) {
 +        self.db.request_cancellation();
 +    }
 +    pub fn raw_database(&self) -> &RootDatabase {
 +        &self.db
 +    }
 +    pub fn raw_database_mut(&mut self) -> &mut RootDatabase {
 +        &mut self.db
 +    }
 +
 +    pub fn shuffle_crate_graph(&mut self) {
 +        shuffle_crate_graph::shuffle_crate_graph(&mut self.db);
 +    }
 +}
 +
 +impl Default for AnalysisHost {
 +    fn default() -> AnalysisHost {
 +        AnalysisHost::new(None)
 +    }
 +}
 +
 +/// Analysis is a snapshot of a world state at a moment in time. It is the main
 +/// entry point for asking semantic information about the world. When the world
 +/// state is advanced using `AnalysisHost::apply_change` method, all existing
 +/// `Analysis` are canceled (most method return `Err(Canceled)`).
 +#[derive(Debug)]
 +pub struct Analysis {
 +    db: salsa::Snapshot<RootDatabase>,
 +}
 +
 +// As a general design guideline, `Analysis` API are intended to be independent
 +// from the language server protocol. That is, when exposing some functionality
 +// we should think in terms of "what API makes most sense" and not in terms of
 +// "what types LSP uses". Although currently LSP is the only consumer of the
 +// API, the API should in theory be usable as a library, or via a different
 +// protocol.
 +impl Analysis {
 +    // Creates an analysis instance for a single file, without any external
 +    // dependencies, stdlib support or ability to apply changes. See
 +    // `AnalysisHost` for creating a fully-featured analysis.
 +    pub fn from_single_file(text: String) -> (Analysis, FileId) {
 +        let mut host = AnalysisHost::default();
 +        let file_id = FileId(0);
 +        let mut file_set = FileSet::default();
 +        file_set.insert(file_id, VfsPath::new_virtual_path("/main.rs".to_string()));
 +        let source_root = SourceRoot::new_local(file_set);
 +
 +        let mut change = Change::new();
 +        change.set_roots(vec![source_root]);
 +        let mut crate_graph = CrateGraph::default();
 +        // FIXME: cfg options
 +        // Default to enable test for single file.
 +        let mut cfg_options = CfgOptions::default();
 +        cfg_options.insert_atom("test".into());
 +        crate_graph.add_crate_root(
 +            file_id,
 +            Edition::CURRENT,
 +            None,
 +            None,
 +            cfg_options.clone(),
 +            cfg_options,
 +            Env::default(),
 +            Ok(Vec::new()),
 +            false,
 +            CrateOrigin::CratesIo { repo: None, name: None },
 +        );
 +        change.change_file(file_id, Some(Arc::new(text)));
 +        change.set_crate_graph(crate_graph);
 +        host.apply_change(change);
 +        (host.analysis(), file_id)
 +    }
 +
 +    /// Debug info about the current state of the analysis.
 +    pub fn status(&self, file_id: Option<FileId>) -> Cancellable<String> {
 +        self.with_db(|db| status::status(&*db, file_id))
 +    }
 +
 +    pub fn parallel_prime_caches<F>(&self, num_worker_threads: u8, cb: F) -> Cancellable<()>
 +    where
 +        F: Fn(ParallelPrimeCachesProgress) + Sync + std::panic::UnwindSafe,
 +    {
 +        self.with_db(move |db| prime_caches::parallel_prime_caches(db, num_worker_threads, &cb))
 +    }
 +
 +    /// Gets the text of the source file.
 +    pub fn file_text(&self, file_id: FileId) -> Cancellable<Arc<String>> {
 +        self.with_db(|db| db.file_text(file_id))
 +    }
 +
 +    /// Gets the syntax tree of the file.
 +    pub fn parse(&self, file_id: FileId) -> Cancellable<SourceFile> {
 +        self.with_db(|db| db.parse(file_id).tree())
 +    }
 +
 +    /// Returns true if this file belongs to an immutable library.
 +    pub fn is_library_file(&self, file_id: FileId) -> Cancellable<bool> {
 +        use ide_db::base_db::SourceDatabaseExt;
 +        self.with_db(|db| db.source_root(db.file_source_root(file_id)).is_library)
 +    }
 +
 +    /// Gets the file's `LineIndex`: data structure to convert between absolute
 +    /// offsets and line/column representation.
 +    pub fn file_line_index(&self, file_id: FileId) -> Cancellable<Arc<LineIndex>> {
 +        self.with_db(|db| db.line_index(file_id))
 +    }
 +
 +    /// Selects the next syntactic nodes encompassing the range.
 +    pub fn extend_selection(&self, frange: FileRange) -> Cancellable<TextRange> {
 +        self.with_db(|db| extend_selection::extend_selection(db, frange))
 +    }
 +
 +    /// Returns position of the matching brace (all types of braces are
 +    /// supported).
 +    pub fn matching_brace(&self, position: FilePosition) -> Cancellable<Option<TextSize>> {
 +        self.with_db(|db| {
 +            let parse = db.parse(position.file_id);
 +            let file = parse.tree();
 +            matching_brace::matching_brace(&file, position.offset)
 +        })
 +    }
 +
 +    /// Returns a syntax tree represented as `String`, for debug purposes.
 +    // FIXME: use a better name here.
 +    pub fn syntax_tree(
 +        &self,
 +        file_id: FileId,
 +        text_range: Option<TextRange>,
 +    ) -> Cancellable<String> {
 +        self.with_db(|db| syntax_tree::syntax_tree(db, file_id, text_range))
 +    }
 +
 +    pub fn view_hir(&self, position: FilePosition) -> Cancellable<String> {
 +        self.with_db(|db| view_hir::view_hir(db, position))
 +    }
 +
 +    pub fn view_item_tree(&self, file_id: FileId) -> Cancellable<String> {
 +        self.with_db(|db| view_item_tree::view_item_tree(db, file_id))
 +    }
 +
 +    /// Renders the crate graph to GraphViz "dot" syntax.
 +    pub fn view_crate_graph(&self, full: bool) -> Cancellable<Result<String, String>> {
 +        self.with_db(|db| view_crate_graph::view_crate_graph(db, full))
 +    }
 +
 +    pub fn expand_macro(&self, position: FilePosition) -> Cancellable<Option<ExpandedMacro>> {
 +        self.with_db(|db| expand_macro::expand_macro(db, position))
 +    }
 +
 +    /// Returns an edit to remove all newlines in the range, cleaning up minor
 +    /// stuff like trailing commas.
 +    pub fn join_lines(&self, config: &JoinLinesConfig, frange: FileRange) -> Cancellable<TextEdit> {
 +        self.with_db(|db| {
 +            let parse = db.parse(frange.file_id);
 +            join_lines::join_lines(config, &parse.tree(), frange.range)
 +        })
 +    }
 +
 +    /// Returns an edit which should be applied when opening a new line, fixing
 +    /// up minor stuff like continuing the comment.
 +    /// The edit will be a snippet (with `$0`).
 +    pub fn on_enter(&self, position: FilePosition) -> Cancellable<Option<TextEdit>> {
 +        self.with_db(|db| typing::on_enter(db, position))
 +    }
 +
 +    /// Returns an edit which should be applied after a character was typed.
 +    ///
 +    /// This is useful for some on-the-fly fixups, like adding `;` to `let =`
 +    /// automatically.
 +    pub fn on_char_typed(
 +        &self,
 +        position: FilePosition,
 +        char_typed: char,
 +        autoclose: bool,
 +    ) -> Cancellable<Option<SourceChange>> {
 +        // Fast path to not even parse the file.
 +        if !typing::TRIGGER_CHARS.contains(char_typed) {
 +            return Ok(None);
 +        }
 +        if char_typed == '<' && !autoclose {
 +            return Ok(None);
 +        }
 +
 +        self.with_db(|db| typing::on_char_typed(db, position, char_typed))
 +    }
 +
 +    /// Returns a tree representation of symbols in the file. Useful to draw a
 +    /// file outline.
 +    pub fn file_structure(&self, file_id: FileId) -> Cancellable<Vec<StructureNode>> {
 +        self.with_db(|db| file_structure::file_structure(&db.parse(file_id).tree()))
 +    }
 +
 +    /// Returns a list of the places in the file where type hints can be displayed.
 +    pub fn inlay_hints(
 +        &self,
 +        config: &InlayHintsConfig,
 +        file_id: FileId,
 +        range: Option<FileRange>,
 +    ) -> Cancellable<Vec<InlayHint>> {
 +        self.with_db(|db| inlay_hints::inlay_hints(db, file_id, range, config))
 +    }
 +
 +    /// Returns the set of folding ranges.
 +    pub fn folding_ranges(&self, file_id: FileId) -> Cancellable<Vec<Fold>> {
 +        self.with_db(|db| folding_ranges::folding_ranges(&db.parse(file_id).tree()))
 +    }
 +
 +    /// Fuzzy searches for a symbol.
 +    pub fn symbol_search(&self, query: Query) -> Cancellable<Vec<NavigationTarget>> {
 +        self.with_db(|db| {
 +            symbol_index::world_symbols(db, query)
 +                .into_iter() // xx: should we make this a par iter?
 +                .filter_map(|s| s.try_to_nav(db))
 +                .collect::<Vec<_>>()
 +        })
 +    }
 +
 +    /// Returns the definitions from the symbol at `position`.
 +    pub fn goto_definition(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
 +        self.with_db(|db| goto_definition::goto_definition(db, position))
 +    }
 +
 +    /// Returns the declaration from the symbol at `position`.
 +    pub fn goto_declaration(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
 +        self.with_db(|db| goto_declaration::goto_declaration(db, position))
 +    }
 +
 +    /// Returns the impls from the symbol at `position`.
 +    pub fn goto_implementation(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
 +        self.with_db(|db| goto_implementation::goto_implementation(db, position))
 +    }
 +
 +    /// Returns the type definitions for the symbol at `position`.
 +    pub fn goto_type_definition(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
 +        self.with_db(|db| goto_type_definition::goto_type_definition(db, position))
 +    }
 +
 +    /// Finds all usages of the reference at point.
 +    pub fn find_all_refs(
 +        &self,
 +        position: FilePosition,
 +        search_scope: Option<SearchScope>,
 +    ) -> Cancellable<Option<Vec<ReferenceSearchResult>>> {
 +        self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, search_scope))
 +    }
 +
 +    /// Returns a short text describing element at position.
 +    pub fn hover(
 +        &self,
 +        config: &HoverConfig,
 +        range: FileRange,
 +    ) -> Cancellable<Option<RangeInfo<HoverResult>>> {
 +        self.with_db(|db| hover::hover(db, range, config))
 +    }
 +
 +    /// Returns moniker of symbol at position.
 +    pub fn moniker(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<RangeInfo<Vec<moniker::MonikerResult>>>> {
 +        self.with_db(|db| moniker::moniker(db, position))
 +    }
 +
 +    /// Return URL(s) for the documentation of the symbol under the cursor.
 +    pub fn external_docs(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<doc_links::DocumentationLink>> {
 +        self.with_db(|db| doc_links::external_docs(db, &position))
 +    }
 +
 +    /// Computes parameter information at the given position.
 +    pub fn signature_help(&self, position: FilePosition) -> Cancellable<Option<SignatureHelp>> {
 +        self.with_db(|db| signature_help::signature_help(db, position))
 +    }
 +
 +    /// Computes call hierarchy candidates for the given file position.
 +    pub fn call_hierarchy(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
 +        self.with_db(|db| call_hierarchy::call_hierarchy(db, position))
 +    }
 +
 +    /// Computes incoming calls for the given file position.
 +    pub fn incoming_calls(&self, position: FilePosition) -> Cancellable<Option<Vec<CallItem>>> {
 +        self.with_db(|db| call_hierarchy::incoming_calls(db, position))
 +    }
 +
 +    /// Computes outgoing calls for the given file position.
 +    pub fn outgoing_calls(&self, position: FilePosition) -> Cancellable<Option<Vec<CallItem>>> {
 +        self.with_db(|db| call_hierarchy::outgoing_calls(db, position))
 +    }
 +
 +    /// Returns a `mod name;` declaration which created the current module.
 +    pub fn parent_module(&self, position: FilePosition) -> Cancellable<Vec<NavigationTarget>> {
 +        self.with_db(|db| parent_module::parent_module(db, position))
 +    }
 +
 +    /// Returns crates this file belongs too.
++    pub fn crates_for(&self, file_id: FileId) -> Cancellable<Vec<CrateId>> {
++        self.with_db(|db| parent_module::crates_for(db, file_id))
++    }
++
++    /// Returns crates this file belongs too.
++    pub fn transitive_rev_deps(&self, crate_id: CrateId) -> Cancellable<Vec<CrateId>> {
++        self.with_db(|db| db.crate_graph().transitive_rev_deps(crate_id).collect())
++    }
++
++    /// Returns crates this file *might* belong too.
++    pub fn relevant_crates_for(&self, file_id: FileId) -> Cancellable<Vec<CrateId>> {
++        self.with_db(|db| db.relevant_crates(file_id).iter().copied().collect())
 +    }
 +
 +    /// Returns the edition of the given crate.
 +    pub fn crate_edition(&self, crate_id: CrateId) -> Cancellable<Edition> {
 +        self.with_db(|db| db.crate_graph()[crate_id].edition)
 +    }
 +
 +    /// Returns the root file of the given crate.
 +    pub fn crate_root(&self, crate_id: CrateId) -> Cancellable<FileId> {
 +        self.with_db(|db| db.crate_graph()[crate_id].root_file_id)
 +    }
 +
 +    /// Returns the set of possible targets to run for the current file.
 +    pub fn runnables(&self, file_id: FileId) -> Cancellable<Vec<Runnable>> {
 +        self.with_db(|db| runnables::runnables(db, file_id))
 +    }
 +
 +    /// Returns the set of tests for the given file position.
 +    pub fn related_tests(
 +        &self,
 +        position: FilePosition,
 +        search_scope: Option<SearchScope>,
 +    ) -> Cancellable<Vec<Runnable>> {
 +        self.with_db(|db| runnables::related_tests(db, position, search_scope))
 +    }
 +
 +    /// Computes syntax highlighting for the given file
 +    pub fn highlight(
 +        &self,
 +        highlight_config: HighlightConfig,
 +        file_id: FileId,
 +    ) -> Cancellable<Vec<HlRange>> {
 +        self.with_db(|db| syntax_highlighting::highlight(db, highlight_config, file_id, None))
 +    }
 +
 +    /// Computes all ranges to highlight for a given item in a file.
 +    pub fn highlight_related(
 +        &self,
 +        config: HighlightRelatedConfig,
 +        position: FilePosition,
 +    ) -> Cancellable<Option<Vec<HighlightedRange>>> {
 +        self.with_db(|db| {
 +            highlight_related::highlight_related(&Semantics::new(db), config, position)
 +        })
 +    }
 +
 +    /// Computes syntax highlighting for the given file range.
 +    pub fn highlight_range(
 +        &self,
 +        highlight_config: HighlightConfig,
 +        frange: FileRange,
 +    ) -> Cancellable<Vec<HlRange>> {
 +        self.with_db(|db| {
 +            syntax_highlighting::highlight(db, highlight_config, frange.file_id, Some(frange.range))
 +        })
 +    }
 +
 +    /// Computes syntax highlighting for the given file.
 +    pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancellable<String> {
 +        self.with_db(|db| syntax_highlighting::highlight_as_html(db, file_id, rainbow))
 +    }
 +
 +    /// Computes completions at the given position.
 +    pub fn completions(
 +        &self,
 +        config: &CompletionConfig,
 +        position: FilePosition,
 +        trigger_character: Option<char>,
 +    ) -> Cancellable<Option<Vec<CompletionItem>>> {
 +        self.with_db(|db| {
 +            ide_completion::completions(db, config, position, trigger_character).map(Into::into)
 +        })
 +    }
 +
 +    /// Resolves additional completion data at the position given.
 +    pub fn resolve_completion_edits(
 +        &self,
 +        config: &CompletionConfig,
 +        position: FilePosition,
 +        imports: impl IntoIterator<Item = (String, String)> + std::panic::UnwindSafe,
 +    ) -> Cancellable<Vec<TextEdit>> {
 +        Ok(self
 +            .with_db(|db| ide_completion::resolve_completion_edits(db, config, position, imports))?
 +            .unwrap_or_default())
 +    }
 +
 +    /// Computes the set of diagnostics for the given file.
 +    pub fn diagnostics(
 +        &self,
 +        config: &DiagnosticsConfig,
 +        resolve: AssistResolveStrategy,
 +        file_id: FileId,
 +    ) -> Cancellable<Vec<Diagnostic>> {
 +        self.with_db(|db| ide_diagnostics::diagnostics(db, config, &resolve, file_id))
 +    }
 +
 +    /// Convenience function to return assists + quick fixes for diagnostics
 +    pub fn assists_with_fixes(
 +        &self,
 +        assist_config: &AssistConfig,
 +        diagnostics_config: &DiagnosticsConfig,
 +        resolve: AssistResolveStrategy,
 +        frange: FileRange,
 +    ) -> Cancellable<Vec<Assist>> {
 +        let include_fixes = match &assist_config.allowed {
 +            Some(it) => it.iter().any(|&it| it == AssistKind::None || it == AssistKind::QuickFix),
 +            None => true,
 +        };
 +
 +        self.with_db(|db| {
 +            let diagnostic_assists = if include_fixes {
 +                ide_diagnostics::diagnostics(db, diagnostics_config, &resolve, frange.file_id)
 +                    .into_iter()
 +                    .flat_map(|it| it.fixes.unwrap_or_default())
 +                    .filter(|it| it.target.intersect(frange.range).is_some())
 +                    .collect()
 +            } else {
 +                Vec::new()
 +            };
 +            let ssr_assists = ssr::ssr_assists(db, &resolve, frange);
 +            let assists = ide_assists::assists(db, assist_config, resolve, frange);
 +
 +            let mut res = diagnostic_assists;
 +            res.extend(ssr_assists.into_iter());
 +            res.extend(assists.into_iter());
 +
 +            res
 +        })
 +    }
 +
 +    /// Returns the edit required to rename reference at the position to the new
 +    /// name.
 +    pub fn rename(
 +        &self,
 +        position: FilePosition,
 +        new_name: &str,
 +    ) -> Cancellable<Result<SourceChange, RenameError>> {
 +        self.with_db(|db| rename::rename(db, position, new_name))
 +    }
 +
 +    pub fn prepare_rename(
 +        &self,
 +        position: FilePosition,
 +    ) -> Cancellable<Result<RangeInfo<()>, RenameError>> {
 +        self.with_db(|db| rename::prepare_rename(db, position))
 +    }
 +
 +    pub fn will_rename_file(
 +        &self,
 +        file_id: FileId,
 +        new_name_stem: &str,
 +    ) -> Cancellable<Option<SourceChange>> {
 +        self.with_db(|db| rename::will_rename_file(db, file_id, new_name_stem))
 +    }
 +
 +    pub fn structural_search_replace(
 +        &self,
 +        query: &str,
 +        parse_only: bool,
 +        resolve_context: FilePosition,
 +        selections: Vec<FileRange>,
 +    ) -> Cancellable<Result<SourceChange, SsrError>> {
 +        self.with_db(|db| {
 +            let rule: ide_ssr::SsrRule = query.parse()?;
 +            let mut match_finder =
 +                ide_ssr::MatchFinder::in_context(db, resolve_context, selections)?;
 +            match_finder.add_rule(rule)?;
 +            let edits = if parse_only { Default::default() } else { match_finder.edits() };
 +            Ok(SourceChange::from(edits))
 +        })
 +    }
 +
 +    pub fn annotations(
 +        &self,
 +        config: &AnnotationConfig,
 +        file_id: FileId,
 +    ) -> Cancellable<Vec<Annotation>> {
 +        self.with_db(|db| annotations::annotations(db, config, file_id))
 +    }
 +
 +    pub fn resolve_annotation(&self, annotation: Annotation) -> Cancellable<Annotation> {
 +        self.with_db(|db| annotations::resolve_annotation(db, annotation))
 +    }
 +
 +    pub fn move_item(
 +        &self,
 +        range: FileRange,
 +        direction: Direction,
 +    ) -> Cancellable<Option<TextEdit>> {
 +        self.with_db(|db| move_item::move_item(db, range, direction))
 +    }
 +
 +    /// Performs an operation on the database that may be canceled.
 +    ///
 +    /// rust-analyzer needs to be able to answer semantic questions about the
 +    /// code while the code is being modified. A common problem is that a
 +    /// long-running query is being calculated when a new change arrives.
 +    ///
 +    /// We can't just apply the change immediately: this will cause the pending
 +    /// query to see inconsistent state (it will observe an absence of
 +    /// repeatable read). So what we do is we **cancel** all pending queries
 +    /// before applying the change.
 +    ///
 +    /// Salsa implements cancellation by unwinding with a special value and
 +    /// catching it on the API boundary.
 +    fn with_db<F, T>(&self, f: F) -> Cancellable<T>
 +    where
 +        F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe,
 +    {
 +        Cancelled::catch(|| f(&self.db))
 +    }
 +}
 +
 +#[test]
 +fn analysis_is_send() {
 +    fn is_send<T: Send>() {}
 +    is_send::<Analysis>();
 +}
index 8f3cc86873f5ed06d5325274079e69bfa22f4fca,0000000000000000000000000000000000000000..506f9452cf1964d003e3d3f06b5c20f5bcc9cde5
mode 100644,000000..100644
--- /dev/null
@@@ -1,167 -1,0 +1,171 @@@
- use hir::Semantics;
++use hir::{db::DefDatabase, Semantics};
 +use ide_db::{
-     base_db::{CrateId, FileId, FilePosition},
++    base_db::{CrateId, FileId, FileLoader, FilePosition},
 +    RootDatabase,
 +};
 +use itertools::Itertools;
 +use syntax::{
 +    algo::find_node_at_offset,
 +    ast::{self, AstNode},
 +};
 +
 +use crate::NavigationTarget;
 +
 +// Feature: Parent Module
 +//
 +// Navigates to the parent module of the current module.
 +//
 +// |===
 +// | Editor  | Action Name
 +//
 +// | VS Code | **rust-analyzer: Locate parent module**
 +// |===
 +//
 +// image::https://user-images.githubusercontent.com/48062697/113065580-04c21800-91b1-11eb-9a32-00086161c0bd.gif[]
 +
 +/// This returns `Vec` because a module may be included from several places.
 +pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> {
 +    let sema = Semantics::new(db);
 +    let source_file = sema.parse(position.file_id);
 +
 +    let mut module = find_node_at_offset::<ast::Module>(source_file.syntax(), position.offset);
 +
 +    // If cursor is literally on `mod foo`, go to the grandpa.
 +    if let Some(m) = &module {
 +        if !m
 +            .item_list()
 +            .map_or(false, |it| it.syntax().text_range().contains_inclusive(position.offset))
 +        {
 +            cov_mark::hit!(test_resolve_parent_module_on_module_decl);
 +            module = m.syntax().ancestors().skip(1).find_map(ast::Module::cast);
 +        }
 +    }
 +
 +    match module {
 +        Some(module) => sema
 +            .to_def(&module)
 +            .into_iter()
 +            .map(|module| NavigationTarget::from_module_to_decl(db, module))
 +            .collect(),
 +        None => sema
 +            .to_module_defs(position.file_id)
 +            .map(|module| NavigationTarget::from_module_to_decl(db, module))
 +            .collect(),
 +    }
 +}
 +
 +/// Returns `Vec` for the same reason as `parent_module`
- pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
-     let sema = Semantics::new(db);
-     sema.to_module_defs(file_id).map(|module| module.krate().into()).unique().collect()
++pub(crate) fn crates_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
++    db.relevant_crates(file_id)
++        .iter()
++        .copied()
++        .filter(|&crate_id| db.crate_def_map(crate_id).modules_for_file(file_id).next().is_some())
++        .sorted()
++        .collect()
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use ide_db::base_db::FileRange;
 +
 +    use crate::fixture;
 +
 +    fn check(ra_fixture: &str) {
 +        let (analysis, position, expected) = fixture::annotations(ra_fixture);
 +        let navs = analysis.parent_module(position).unwrap();
 +        let navs = navs
 +            .iter()
 +            .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
 +            .collect::<Vec<_>>();
 +        assert_eq!(expected.into_iter().map(|(fr, _)| fr).collect::<Vec<_>>(), navs);
 +    }
 +
 +    #[test]
 +    fn test_resolve_parent_module() {
 +        check(
 +            r#"
 +//- /lib.rs
 +mod foo;
 +  //^^^
 +
 +//- /foo.rs
 +$0// empty
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_resolve_parent_module_on_module_decl() {
 +        cov_mark::check!(test_resolve_parent_module_on_module_decl);
 +        check(
 +            r#"
 +//- /lib.rs
 +mod foo;
 +  //^^^
 +//- /foo.rs
 +mod $0bar;
 +
 +//- /foo/bar.rs
 +// empty
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_resolve_parent_module_for_inline() {
 +        check(
 +            r#"
 +//- /lib.rs
 +mod foo {
 +    mod bar {
 +        mod baz { $0 }
 +    }     //^^^
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_resolve_multi_parent_module() {
 +        check(
 +            r#"
 +//- /main.rs
 +mod foo;
 +  //^^^
 +#[path = "foo.rs"]
 +mod bar;
 +  //^^^
 +//- /foo.rs
 +$0
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_resolve_crate_root() {
 +        let (analysis, file_id) = fixture::file(
 +            r#"
 +//- /foo.rs
 +$0
 +//- /main.rs
 +mod foo;
 +"#,
 +        );
-         assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1);
++        assert_eq!(analysis.crates_for(file_id).unwrap().len(), 1);
 +    }
 +
 +    #[test]
 +    fn test_resolve_multi_parent_crate() {
 +        let (analysis, file_id) = fixture::file(
 +            r#"
 +//- /baz.rs
 +$0
 +//- /foo.rs crate:foo
 +mod baz;
 +//- /bar.rs crate:bar
 +mod baz;
 +"#,
 +        );
-         assert_eq!(analysis.crate_for(file_id).unwrap().len(), 2);
++        assert_eq!(analysis.crates_for(file_id).unwrap().len(), 2);
 +    }
 +}
index 9e5eb909508f624e051042623de24232070a78ed,0000000000000000000000000000000000000000..27ad1a948d13bcd41df548d764fd4f5accfadb63
mode 100644,000000..100644
--- /dev/null
@@@ -1,324 -1,0 +1,322 @@@
-         } else {
-             continue;
-         };
 +//! This module provides `StaticIndex` which is used for powering
 +//! read-only code browsers and emitting LSIF
 +
 +use std::collections::HashMap;
 +
 +use hir::{db::HirDatabase, Crate, Module, Semantics};
 +use ide_db::{
 +    base_db::{FileId, FileRange, SourceDatabaseExt},
 +    defs::{Definition, IdentClass},
 +    FxHashSet, RootDatabase,
 +};
 +use syntax::{AstNode, SyntaxKind::*, SyntaxToken, TextRange, T};
 +
 +use crate::{
 +    hover::hover_for_definition,
 +    moniker::{crate_for_file, def_to_moniker, MonikerResult},
 +    Analysis, Fold, HoverConfig, HoverDocFormat, HoverResult, InlayHint, InlayHintsConfig,
 +    TryToNav,
 +};
 +
 +/// A static representation of fully analyzed source code.
 +///
 +/// The intended use-case is powering read-only code browsers and emitting LSIF
 +#[derive(Debug)]
 +pub struct StaticIndex<'a> {
 +    pub files: Vec<StaticIndexedFile>,
 +    pub tokens: TokenStore,
 +    analysis: &'a Analysis,
 +    db: &'a RootDatabase,
 +    def_map: HashMap<Definition, TokenId>,
 +}
 +
 +#[derive(Debug)]
 +pub struct ReferenceData {
 +    pub range: FileRange,
 +    pub is_definition: bool,
 +}
 +
 +#[derive(Debug)]
 +pub struct TokenStaticData {
 +    pub hover: Option<HoverResult>,
 +    pub definition: Option<FileRange>,
 +    pub references: Vec<ReferenceData>,
 +    pub moniker: Option<MonikerResult>,
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct TokenId(usize);
 +
 +impl TokenId {
 +    pub fn raw(self) -> usize {
 +        self.0
 +    }
 +}
 +
 +#[derive(Default, Debug)]
 +pub struct TokenStore(Vec<TokenStaticData>);
 +
 +impl TokenStore {
 +    pub fn insert(&mut self, data: TokenStaticData) -> TokenId {
 +        let id = TokenId(self.0.len());
 +        self.0.push(data);
 +        id
 +    }
 +
 +    pub fn get_mut(&mut self, id: TokenId) -> Option<&mut TokenStaticData> {
 +        self.0.get_mut(id.0)
 +    }
 +
 +    pub fn get(&self, id: TokenId) -> Option<&TokenStaticData> {
 +        self.0.get(id.0)
 +    }
 +
 +    pub fn iter(self) -> impl Iterator<Item = (TokenId, TokenStaticData)> {
 +        self.0.into_iter().enumerate().map(|(i, x)| (TokenId(i), x))
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub struct StaticIndexedFile {
 +    pub file_id: FileId,
 +    pub folds: Vec<Fold>,
 +    pub inlay_hints: Vec<InlayHint>,
 +    pub tokens: Vec<(TextRange, TokenId)>,
 +}
 +
 +fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
 +    let mut worklist: Vec<_> =
 +        Crate::all(db).into_iter().map(|krate| krate.root_module(db)).collect();
 +    let mut modules = Vec::new();
 +
 +    while let Some(module) = worklist.pop() {
 +        modules.push(module);
 +        worklist.extend(module.children(db));
 +    }
 +
 +    modules
 +}
 +
 +impl StaticIndex<'_> {
 +    fn add_file(&mut self, file_id: FileId) {
 +        let current_crate = crate_for_file(self.db, file_id);
 +        let folds = self.analysis.folding_ranges(file_id).unwrap();
 +        let inlay_hints = self
 +            .analysis
 +            .inlay_hints(
 +                &InlayHintsConfig {
 +                    render_colons: true,
 +                    type_hints: true,
 +                    parameter_hints: true,
 +                    chaining_hints: true,
 +                    closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock,
 +                    lifetime_elision_hints: crate::LifetimeElisionHints::Never,
 +                    reborrow_hints: crate::ReborrowHints::Never,
 +                    hide_named_constructor_hints: false,
 +                    hide_closure_initialization_hints: false,
 +                    param_names_for_lifetime_elision_hints: false,
 +                    binding_mode_hints: false,
 +                    max_length: Some(25),
 +                    closing_brace_hints_min_lines: Some(25),
 +                },
 +                file_id,
 +                None,
 +            )
 +            .unwrap();
 +        // hovers
 +        let sema = hir::Semantics::new(self.db);
 +        let tokens_or_nodes = sema.parse(file_id).syntax().clone();
 +        let tokens = tokens_or_nodes.descendants_with_tokens().filter_map(|x| match x {
 +            syntax::NodeOrToken::Node(_) => None,
 +            syntax::NodeOrToken::Token(x) => Some(x),
 +        });
 +        let hover_config = HoverConfig {
 +            links_in_hover: true,
 +            documentation: Some(HoverDocFormat::Markdown),
 +            keywords: true,
 +        };
 +        let tokens = tokens.filter(|token| {
 +            matches!(
 +                token.kind(),
 +                IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self]
 +            )
 +        });
 +        let mut result = StaticIndexedFile { file_id, inlay_hints, folds, tokens: vec![] };
 +        for token in tokens {
 +            let range = token.text_range();
 +            let node = token.parent().unwrap();
 +            let def = match get_definition(&sema, token.clone()) {
 +                Some(x) => x,
 +                None => continue,
 +            };
 +            let id = if let Some(x) = self.def_map.get(&def) {
 +                *x
 +            } else {
 +                let x = self.tokens.insert(TokenStaticData {
 +                    hover: hover_for_definition(&sema, file_id, def, &node, &hover_config),
 +                    definition: def
 +                        .try_to_nav(self.db)
 +                        .map(|x| FileRange { file_id: x.file_id, range: x.focus_or_full_range() }),
 +                    references: vec![],
 +                    moniker: current_crate.and_then(|cc| def_to_moniker(self.db, def, cc)),
 +                });
 +                self.def_map.insert(def, x);
 +                x
 +            };
 +            let token = self.tokens.get_mut(id).unwrap();
 +            token.references.push(ReferenceData {
 +                range: FileRange { range, file_id },
 +                is_definition: match def.try_to_nav(self.db) {
 +                    Some(x) => x.file_id == file_id && x.focus_or_full_range() == range,
 +                    None => false,
 +                },
 +            });
 +            result.tokens.push((range, id));
 +        }
 +        self.files.push(result);
 +    }
 +
 +    pub fn compute(analysis: &Analysis) -> StaticIndex<'_> {
 +        let db = &*analysis.db;
 +        let work = all_modules(db).into_iter().filter(|module| {
 +            let file_id = module.definition_source(db).file_id.original_file(db);
 +            let source_root = db.file_source_root(file_id);
 +            let source_root = db.source_root(source_root);
 +            !source_root.is_library
 +        });
 +        let mut this = StaticIndex {
 +            files: vec![],
 +            tokens: Default::default(),
 +            analysis,
 +            db,
 +            def_map: Default::default(),
 +        };
 +        let mut visited_files = FxHashSet::default();
 +        for module in work {
 +            let file_id = module.definition_source(db).file_id.original_file(db);
 +            if visited_files.contains(&file_id) {
 +                continue;
 +            }
 +            this.add_file(file_id);
 +            // mark the file
 +            visited_files.insert(file_id);
 +        }
 +        this
 +    }
 +}
 +
 +fn get_definition(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option<Definition> {
 +    for token in sema.descend_into_macros(token) {
 +        let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops);
 +        if let Some(&[x]) = def.as_deref() {
 +            return Some(x);
++        }
 +    }
 +    None
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::{fixture, StaticIndex};
 +    use ide_db::base_db::FileRange;
 +    use std::collections::HashSet;
 +    use syntax::TextSize;
 +
 +    fn check_all_ranges(ra_fixture: &str) {
 +        let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture);
 +        let s = StaticIndex::compute(&analysis);
 +        let mut range_set: HashSet<_> = ranges.iter().map(|x| x.0).collect();
 +        for f in s.files {
 +            for (range, _) in f.tokens {
 +                let x = FileRange { file_id: f.file_id, range };
 +                if !range_set.contains(&x) {
 +                    panic!("additional range {:?}", x);
 +                }
 +                range_set.remove(&x);
 +            }
 +        }
 +        if !range_set.is_empty() {
 +            panic!("unfound ranges {:?}", range_set);
 +        }
 +    }
 +
 +    fn check_definitions(ra_fixture: &str) {
 +        let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture);
 +        let s = StaticIndex::compute(&analysis);
 +        let mut range_set: HashSet<_> = ranges.iter().map(|x| x.0).collect();
 +        for (_, t) in s.tokens.iter() {
 +            if let Some(x) = t.definition {
 +                if x.range.start() == TextSize::from(0) {
 +                    // ignore definitions that are whole of file
 +                    continue;
 +                }
 +                if !range_set.contains(&x) {
 +                    panic!("additional definition {:?}", x);
 +                }
 +                range_set.remove(&x);
 +            }
 +        }
 +        if !range_set.is_empty() {
 +            panic!("unfound definitions {:?}", range_set);
 +        }
 +    }
 +
 +    #[test]
 +    fn struct_and_enum() {
 +        check_all_ranges(
 +            r#"
 +struct Foo;
 +     //^^^
 +enum E { X(Foo) }
 +   //^   ^ ^^^
 +"#,
 +        );
 +        check_definitions(
 +            r#"
 +struct Foo;
 +     //^^^
 +enum E { X(Foo) }
 +   //^   ^
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn multi_crate() {
 +        check_definitions(
 +            r#"
 +//- /main.rs crate:main deps:foo
 +
 +
 +use foo::func;
 +
 +fn main() {
 + //^^^^
 +    func();
 +}
 +//- /foo/lib.rs crate:foo
 +
 +pub func() {
 +
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn derives() {
 +        check_all_ranges(
 +            r#"
 +//- minicore:derive
 +#[rustc_builtin_macro]
 +//^^^^^^^^^^^^^^^^^^^
 +pub macro Copy {}
 +        //^^^^
 +#[derive(Copy)]
 +//^^^^^^ ^^^^
 +struct Hello(i32);
 +     //^^^^^ ^^^
 +"#,
 +        );
 +    }
 +}
index f4d0387440d475e23e4e7ef466cc608f3f9565de,0000000000000000000000000000000000000000..20810c25b3e81f976ee1b99190d788389165ad80
mode 100644,000000..100644
--- /dev/null
@@@ -1,164 -1,0 +1,164 @@@
-         let crates = crate::parent_module::crate_for(db, file_id);
 +use std::{fmt, sync::Arc};
 +
 +use hir::{ExpandResult, MacroFile};
 +use ide_db::base_db::{
 +    salsa::debug::{DebugQueryTable, TableEntry},
 +    CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId,
 +};
 +use ide_db::{
 +    symbol_index::{LibrarySymbolsQuery, SymbolIndex},
 +    RootDatabase,
 +};
 +use itertools::Itertools;
 +use profile::{memory_usage, Bytes};
 +use std::env;
 +use stdx::format_to;
 +use syntax::{ast, Parse, SyntaxNode};
 +
 +fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
 +    ide_db::base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>()
 +}
 +fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
 +    hir::db::ParseMacroExpansionQuery.in_db(db).entries::<SyntaxTreeStats>()
 +}
 +
 +// Feature: Status
 +//
 +// Shows internal statistic about memory usage of rust-analyzer.
 +//
 +// |===
 +// | Editor  | Action Name
 +//
 +// | VS Code | **rust-analyzer: Status**
 +// |===
 +// image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[]
 +pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
 +    let mut buf = String::new();
 +    format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::<FilesStats>());
 +    format_to!(buf, "{}\n", LibrarySymbolsQuery.in_db(db).entries::<LibrarySymbolsStats>());
 +    format_to!(buf, "{}\n", syntax_tree_stats(db));
 +    format_to!(buf, "{} (Macros)\n", macro_syntax_tree_stats(db));
 +    format_to!(buf, "{} in total\n", memory_usage());
 +    if env::var("RA_COUNT").is_ok() {
 +        format_to!(buf, "\nCounts:\n{}", profile::countme::get_all());
 +    }
 +
 +    if let Some(file_id) = file_id {
 +        format_to!(buf, "\nFile info:\n");
++        let crates = crate::parent_module::crates_for(db, file_id);
 +        if crates.is_empty() {
 +            format_to!(buf, "Does not belong to any crate");
 +        }
 +        let crate_graph = db.crate_graph();
 +        for krate in crates {
 +            let display_crate = |krate: CrateId| match &crate_graph[krate].display_name {
 +                Some(it) => format!("{}({:?})", it, krate),
 +                None => format!("{:?}", krate),
 +            };
 +            format_to!(buf, "Crate: {}\n", display_crate(krate));
 +            let deps = crate_graph[krate]
 +                .dependencies
 +                .iter()
 +                .map(|dep| format!("{}={:?}", dep.name, dep.crate_id))
 +                .format(", ");
 +            format_to!(buf, "Dependencies: {}\n", deps);
 +        }
 +    }
 +
 +    buf.trim().to_string()
 +}
 +
 +#[derive(Default)]
 +struct FilesStats {
 +    total: usize,
 +    size: Bytes,
 +}
 +
 +impl fmt::Display for FilesStats {
 +    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        write!(fmt, "{} of files", self.size)
 +    }
 +}
 +
 +impl FromIterator<TableEntry<FileId, Arc<String>>> for FilesStats {
 +    fn from_iter<T>(iter: T) -> FilesStats
 +    where
 +        T: IntoIterator<Item = TableEntry<FileId, Arc<String>>>,
 +    {
 +        let mut res = FilesStats::default();
 +        for entry in iter {
 +            res.total += 1;
 +            res.size += entry.value.unwrap().len();
 +        }
 +        res
 +    }
 +}
 +
 +#[derive(Default)]
 +pub(crate) struct SyntaxTreeStats {
 +    total: usize,
 +    pub(crate) retained: usize,
 +}
 +
 +impl fmt::Display for SyntaxTreeStats {
 +    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        write!(fmt, "{} trees, {} preserved", self.total, self.retained)
 +    }
 +}
 +
 +impl FromIterator<TableEntry<FileId, Parse<ast::SourceFile>>> for SyntaxTreeStats {
 +    fn from_iter<T>(iter: T) -> SyntaxTreeStats
 +    where
 +        T: IntoIterator<Item = TableEntry<FileId, Parse<ast::SourceFile>>>,
 +    {
 +        let mut res = SyntaxTreeStats::default();
 +        for entry in iter {
 +            res.total += 1;
 +            res.retained += entry.value.is_some() as usize;
 +        }
 +        res
 +    }
 +}
 +
 +impl<M> FromIterator<TableEntry<MacroFile, ExpandResult<Option<(Parse<SyntaxNode>, M)>>>>
 +    for SyntaxTreeStats
 +{
 +    fn from_iter<T>(iter: T) -> SyntaxTreeStats
 +    where
 +        T: IntoIterator<Item = TableEntry<MacroFile, ExpandResult<Option<(Parse<SyntaxNode>, M)>>>>,
 +    {
 +        let mut res = SyntaxTreeStats::default();
 +        for entry in iter {
 +            res.total += 1;
 +            res.retained += entry.value.is_some() as usize;
 +        }
 +        res
 +    }
 +}
 +
 +#[derive(Default)]
 +struct LibrarySymbolsStats {
 +    total: usize,
 +    size: Bytes,
 +}
 +
 +impl fmt::Display for LibrarySymbolsStats {
 +    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        write!(fmt, "{} of index symbols ({})", self.size, self.total)
 +    }
 +}
 +
 +impl FromIterator<TableEntry<SourceRootId, Arc<SymbolIndex>>> for LibrarySymbolsStats {
 +    fn from_iter<T>(iter: T) -> LibrarySymbolsStats
 +    where
 +        T: IntoIterator<Item = TableEntry<SourceRootId, Arc<SymbolIndex>>>,
 +    {
 +        let mut res = LibrarySymbolsStats::default();
 +        for entry in iter {
 +            let symbols = entry.value.unwrap();
 +            res.total += symbols.len();
 +            res.size += symbols.memory_size();
 +        }
 +        res
 +    }
 +}
index 6fd7c3166f821a04b5ae83283a58334fe43ae3d3,0000000000000000000000000000000000000000..cf9868740cb03a0d702fd65f517c101839caadd6
mode 100644,000000..100644
--- /dev/null
@@@ -1,28 -1,0 +1,30 @@@
- expect-test = "1.4.0"
 +[package]
 +name = "project-model"
 +version = "0.0.0"
 +description = "TBD"
 +license = "MIT OR Apache-2.0"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
 +tracing = "0.1.35"
 +rustc-hash = "1.1.0"
 +cargo_metadata = "0.15.0"
 +semver = "1.0.14"
 +serde = { version = "1.0.137", features = ["derive"] }
 +serde_json = "1.0.86"
 +anyhow = "1.0.62"
 +la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
 +
 +cfg = { path = "../cfg", version = "0.0.0" }
 +base-db = { path = "../base-db", version = "0.0.0" }
 +toolchain = { path = "../toolchain", version = "0.0.0" }
 +paths = { path = "../paths", version = "0.0.0" }
 +stdx = { path = "../stdx", version = "0.0.0" }
 +profile = { path = "../profile", version = "0.0.0" }
++
++[dev-dependencies]
++expect-test = "1.4.0"
index d9f09c0349566129a762c9f58d528dea9094fa38,0000000000000000000000000000000000000000..a26a7c57acfce7541617ea48b6f7704ed30dbf5f
mode 100644,000000..100644
--- /dev/null
@@@ -1,268 -1,0 +1,390 @@@
- use std::{cell::RefCell, io, path::PathBuf, process::Command};
 +//! Workspace information we get from cargo consists of two pieces. The first is
 +//! the output of `cargo metadata`. The second is the output of running
 +//! `build.rs` files (`OUT_DIR` env var, extra cfg flags) and compiling proc
 +//! macro.
 +//!
 +//! This module implements this second part. We use "build script" terminology
 +//! here, but it covers procedural macros as well.
 +
- use crate::{cfg_flag::CfgFlag, CargoConfig, CargoFeatures, CargoWorkspace, Package};
++use std::{
++    cell::RefCell,
++    io, mem,
++    path::{self, PathBuf},
++    process::Command,
++};
 +
 +use cargo_metadata::{camino::Utf8Path, Message};
 +use la_arena::ArenaMap;
 +use paths::AbsPathBuf;
 +use rustc_hash::FxHashMap;
 +use semver::Version;
 +use serde::Deserialize;
 +
-     outputs: ArenaMap<Package, Option<BuildScriptOutput>>,
++use crate::{
++    cfg_flag::CfgFlag, CargoConfig, CargoFeatures, CargoWorkspace, InvocationLocation,
++    InvocationStrategy, Package,
++};
 +
 +#[derive(Debug, Default, Clone, PartialEq, Eq)]
 +pub struct WorkspaceBuildScripts {
- impl WorkspaceBuildScripts {
-     fn build_command(config: &CargoConfig) -> Command {
-         if let Some([program, args @ ..]) = config.run_build_script_command.as_deref() {
-             let mut cmd = Command::new(program);
-             cmd.args(args);
-             cmd.envs(&config.extra_env);
-             return cmd;
-         }
++    outputs: ArenaMap<Package, BuildScriptOutput>,
 +    error: Option<String>,
 +}
 +
 +#[derive(Debug, Clone, Default, PartialEq, Eq)]
 +pub(crate) struct BuildScriptOutput {
 +    /// List of config flags defined by this package's build script.
 +    pub(crate) cfgs: Vec<CfgFlag>,
 +    /// List of cargo-related environment variables with their value.
 +    ///
 +    /// If the package has a build script which defines environment variables,
 +    /// they can also be found here.
 +    pub(crate) envs: Vec<(String, String)>,
 +    /// Directory where a build script might place its output.
 +    pub(crate) out_dir: Option<AbsPathBuf>,
 +    /// Path to the proc-macro library file if this package exposes proc-macros.
 +    pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>,
 +}
 +
-         let mut cmd = Command::new(toolchain::cargo());
-         cmd.envs(&config.extra_env);
-         cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]);
++impl BuildScriptOutput {
++    fn is_unchanged(&self) -> bool {
++        self.cfgs.is_empty()
++            && self.envs.is_empty()
++            && self.out_dir.is_none()
++            && self.proc_macro_dylib_path.is_none()
++    }
++}
 +
-         // --all-targets includes tests, benches and examples in addition to the
-         // default lib and bins. This is an independent concept from the --targets
-         // flag below.
-         cmd.arg("--all-targets");
++impl WorkspaceBuildScripts {
++    fn build_command(config: &CargoConfig) -> io::Result<Command> {
++        let mut cmd = match config.run_build_script_command.as_deref() {
++            Some([program, args @ ..]) => {
++                let mut cmd = Command::new(program);
++                cmd.args(args);
++                cmd
++            }
++            _ => {
++                let mut cmd = Command::new(toolchain::cargo());
 +
-         if let Some(target) = &config.target {
-             cmd.args(&["--target", target]);
-         }
++                cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]);
 +
-         match &config.features {
-             CargoFeatures::All => {
-                 cmd.arg("--all-features");
-             }
-             CargoFeatures::Selected { features, no_default_features } => {
-                 if *no_default_features {
-                     cmd.arg("--no-default-features");
++                // --all-targets includes tests, benches and examples in addition to the
++                // default lib and bins. This is an independent concept from the --targets
++                // flag below.
++                cmd.arg("--all-targets");
 +
-                 if !features.is_empty() {
-                     cmd.arg("--features");
-                     cmd.arg(features.join(" "));
++                if let Some(target) = &config.target {
++                    cmd.args(&["--target", target]);
 +                }
-         cmd
++
++                match &config.features {
++                    CargoFeatures::All => {
++                        cmd.arg("--all-features");
++                    }
++                    CargoFeatures::Selected { features, no_default_features } => {
++                        if *no_default_features {
++                            cmd.arg("--no-default-features");
++                        }
++                        if !features.is_empty() {
++                            cmd.arg("--features");
++                            cmd.arg(features.join(" "));
++                        }
++                    }
 +                }
++
++                cmd
 +            }
++        };
++
++        cmd.envs(&config.extra_env);
++        if config.wrap_rustc_in_build_scripts {
++            // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
++            // that to compile only proc macros and build scripts during the initial
++            // `cargo check`.
++            let myself = std::env::current_exe()?;
++            cmd.env("RUSTC_WRAPPER", myself);
++            cmd.env("RA_RUSTC_WRAPPER", "1");
 +        }
 +
-     pub(crate) fn run(
++        Ok(cmd)
 +    }
 +
-         match Self::run_(Self::build_command(config), config, workspace, progress) {
++    /// Runs the build scripts for the given workspace
++    pub(crate) fn run_for_workspace(
 +        config: &CargoConfig,
 +        workspace: &CargoWorkspace,
 +        progress: &dyn Fn(String),
 +        toolchain: &Option<Version>,
 +    ) -> io::Result<WorkspaceBuildScripts> {
 +        const RUST_1_62: Version = Version::new(1, 62, 0);
 +
-                 let mut cmd = Self::build_command(config);
++        let current_dir = match &config.invocation_location {
++            InvocationLocation::Root(root) if config.run_build_script_command.is_some() => {
++                root.as_path()
++            }
++            _ => &workspace.workspace_root(),
++        }
++        .as_ref();
++
++        match Self::run_per_ws(Self::build_command(config)?, workspace, current_dir, progress) {
 +            Ok(WorkspaceBuildScripts { error: Some(error), .. })
 +                if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) =>
 +            {
 +                // building build scripts failed, attempt to build with --keep-going so
 +                // that we potentially get more build data
-                 let mut res = Self::run_(cmd, config, workspace, progress)?;
++                let mut cmd = Self::build_command(config)?;
 +                cmd.args(&["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
-     fn run_(
-         mut cmd: Command,
++                let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?;
 +                res.error = Some(error);
 +                Ok(res)
 +            }
 +            res => res,
 +        }
 +    }
 +
-         workspace: &CargoWorkspace,
++    /// Runs the build scripts by invoking the configured command *once*.
++    /// This populates the outputs for all passed in workspaces.
++    pub(crate) fn run_once(
 +        config: &CargoConfig,
-     ) -> io::Result<WorkspaceBuildScripts> {
-         if config.wrap_rustc_in_build_scripts {
-             // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
-             // that to compile only proc macros and build scripts during the initial
-             // `cargo check`.
-             let myself = std::env::current_exe()?;
-             cmd.env("RUSTC_WRAPPER", myself);
-             cmd.env("RA_RUSTC_WRAPPER", "1");
++        workspaces: &[&CargoWorkspace],
 +        progress: &dyn Fn(String),
-         cmd.current_dir(workspace.workspace_root());
++    ) -> io::Result<Vec<WorkspaceBuildScripts>> {
++        assert_eq!(config.invocation_strategy, InvocationStrategy::Once);
++
++        let current_dir = match &config.invocation_location {
++            InvocationLocation::Root(root) => root,
++            InvocationLocation::Workspace => {
++                return Err(io::Error::new(
++                    io::ErrorKind::Other,
++                    "Cannot run build scripts from workspace with invocation strategy `once`",
++                ))
++            }
++        };
++        let cmd = Self::build_command(config)?;
++        // NB: Cargo.toml could have been modified between `cargo metadata` and
++        // `cargo check`. We shouldn't assume that package ids we see here are
++        // exactly those from `config`.
++        let mut by_id = FxHashMap::default();
++        // some workspaces might depend on the same crates, so we need to duplicate the outputs
++        // to those collisions
++        let mut collisions = Vec::new();
++        let mut res: Vec<_> = workspaces
++            .iter()
++            .enumerate()
++            .map(|(idx, workspace)| {
++                let mut res = WorkspaceBuildScripts::default();
++                for package in workspace.packages() {
++                    res.outputs.insert(package, BuildScriptOutput::default());
++                    if by_id.contains_key(&workspace[package].id) {
++                        collisions.push((&workspace[package].id, idx, package));
++                    } else {
++                        by_id.insert(workspace[package].id.clone(), (package, idx));
++                    }
++                }
++                res
++            })
++            .collect();
++
++        let errors = Self::run_command(
++            cmd,
++            current_dir.as_path().as_ref(),
++            |package, cb| {
++                if let Some(&(package, workspace)) = by_id.get(package) {
++                    cb(&workspaces[workspace][package].name, &mut res[workspace].outputs[package]);
++                }
++            },
++            progress,
++        )?;
++        res.iter_mut().for_each(|it| it.error = errors.clone());
++        collisions.into_iter().for_each(|(id, workspace, package)| {
++            if let Some(&(p, w)) = by_id.get(id) {
++                res[workspace].outputs[package] = res[w].outputs[p].clone();
++            }
++        });
++
++        if tracing::enabled!(tracing::Level::INFO) {
++            for (idx, workspace) in workspaces.iter().enumerate() {
++                for package in workspace.packages() {
++                    let package_build_data = &mut res[idx].outputs[package];
++                    if !package_build_data.is_unchanged() {
++                        tracing::info!(
++                            "{}: {:?}",
++                            workspace[package].manifest.parent().display(),
++                            package_build_data,
++                        );
++                    }
++                }
++            }
 +        }
 +
-             outputs.insert(package, None);
++        Ok(res)
++    }
 +
++    fn run_per_ws(
++        cmd: Command,
++        workspace: &CargoWorkspace,
++        current_dir: &path::Path,
++        progress: &dyn Fn(String),
++    ) -> io::Result<WorkspaceBuildScripts> {
 +        let mut res = WorkspaceBuildScripts::default();
 +        let outputs = &mut res.outputs;
 +        // NB: Cargo.toml could have been modified between `cargo metadata` and
 +        // `cargo check`. We shouldn't assume that package ids we see here are
 +        // exactly those from `config`.
 +        let mut by_id: FxHashMap<String, Package> = FxHashMap::default();
 +        for package in workspace.packages() {
-         tracing::info!("Running build scripts: {:?}", cmd);
++            outputs.insert(package, BuildScriptOutput::default());
 +            by_id.insert(workspace[package].id.clone(), package);
 +        }
 +
++        res.error = Self::run_command(
++            cmd,
++            current_dir,
++            |package, cb| {
++                if let Some(&package) = by_id.get(package) {
++                    cb(&workspace[package].name, &mut outputs[package]);
++                }
++            },
++            progress,
++        )?;
++
++        if tracing::enabled!(tracing::Level::INFO) {
++            for package in workspace.packages() {
++                let package_build_data = &mut outputs[package];
++                if !package_build_data.is_unchanged() {
++                    tracing::info!(
++                        "{}: {:?}",
++                        workspace[package].manifest.parent().display(),
++                        package_build_data,
++                    );
++                }
++            }
++        }
++
++        Ok(res)
++    }
++
++    fn run_command(
++        mut cmd: Command,
++        current_dir: &path::Path,
++        // ideally this would be something like:
++        // with_output_for: impl FnMut(&str, dyn FnOnce(&mut BuildScriptOutput)),
++        // but owned trait objects aren't a thing
++        mut with_output_for: impl FnMut(&str, &mut dyn FnMut(&str, &mut BuildScriptOutput)),
++        progress: &dyn Fn(String),
++    ) -> io::Result<Option<String>> {
 +        let errors = RefCell::new(String::new());
 +        let push_err = |err: &str| {
 +            let mut e = errors.borrow_mut();
 +            e.push_str(err);
 +            e.push('\n');
 +        };
 +
-                     Message::BuildScriptExecuted(message) => {
-                         let package = match by_id.get(&message.package_id.repr) {
-                             Some(&it) => it,
-                             None => return,
-                         };
-                         progress(format!("running build-script: {}", workspace[package].name));
-                         let cfgs = {
-                             let mut acc = Vec::new();
-                             for cfg in message.cfgs {
-                                 match cfg.parse::<CfgFlag>() {
-                                     Ok(it) => acc.push(it),
-                                     Err(err) => {
-                                         push_err(&format!(
-                                             "invalid cfg from cargo-metadata: {}",
-                                             err
-                                         ));
-                                         return;
-                                     }
-                                 };
++        tracing::info!("Running build scripts in {}: {:?}", current_dir.display(), cmd);
++        cmd.current_dir(current_dir);
 +        let output = stdx::process::spawn_with_streaming_output(
 +            cmd,
 +            &mut |line| {
 +                // Copy-pasted from existing cargo_metadata. It seems like we
 +                // should be using serde_stacker here?
 +                let mut deserializer = serde_json::Deserializer::from_str(line);
 +                deserializer.disable_recursion_limit();
 +                let message = Message::deserialize(&mut deserializer)
 +                    .unwrap_or_else(|_| Message::TextLine(line.to_string()));
 +
 +                match message {
-                             acc
-                         };
-                         // cargo_metadata crate returns default (empty) path for
-                         // older cargos, which is not absolute, so work around that.
-                         let out_dir = message.out_dir.into_os_string();
-                         if !out_dir.is_empty() {
-                             let data = outputs[package].get_or_insert_with(Default::default);
-                             data.out_dir = Some(AbsPathBuf::assert(PathBuf::from(out_dir)));
-                             data.cfgs = cfgs;
-                         }
-                         if !message.env.is_empty() {
-                             outputs[package].get_or_insert_with(Default::default).envs =
-                                 message.env;
-                         }
++                    Message::BuildScriptExecuted(mut message) => {
++                        with_output_for(&message.package_id.repr, &mut |name, data| {
++                            progress(format!("running build-script: {}", name));
++                            let cfgs = {
++                                let mut acc = Vec::new();
++                                for cfg in &message.cfgs {
++                                    match cfg.parse::<CfgFlag>() {
++                                        Ok(it) => acc.push(it),
++                                        Err(err) => {
++                                            push_err(&format!(
++                                                "invalid cfg from cargo-metadata: {}",
++                                                err
++                                            ));
++                                            return;
++                                        }
++                                    };
++                                }
++                                acc
++                            };
++                            if !message.env.is_empty() {
++                                data.envs = mem::take(&mut message.env);
 +                            }
-                         let package = match by_id.get(&message.package_id.repr) {
-                             Some(it) => *it,
-                             None => return,
-                         };
-                         progress(format!("building proc-macros: {}", message.target.name));
-                         if message.target.kind.iter().any(|k| k == "proc-macro") {
-                             // Skip rmeta file
-                             if let Some(filename) =
-                                 message.filenames.iter().find(|name| is_dylib(name))
-                             {
-                                 let filename = AbsPathBuf::assert(PathBuf::from(&filename));
-                                 outputs[package]
-                                     .get_or_insert_with(Default::default)
-                                     .proc_macro_dylib_path = Some(filename);
++                            // cargo_metadata crate returns default (empty) path for
++                            // older cargos, which is not absolute, so work around that.
++                            let out_dir = mem::take(&mut message.out_dir).into_os_string();
++                            if !out_dir.is_empty() {
++                                let out_dir = AbsPathBuf::assert(PathBuf::from(out_dir));
++                                // inject_cargo_env(package, package_build_data);
++                                // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
++                                if let Some(out_dir) =
++                                    out_dir.as_os_str().to_str().map(|s| s.to_owned())
++                                {
++                                    data.envs.push(("OUT_DIR".to_string(), out_dir));
++                                }
++                                data.out_dir = Some(out_dir);
++                                data.cfgs = cfgs;
++                            }
++                        });
 +                    }
 +                    Message::CompilerArtifact(message) => {
-                         }
++                        with_output_for(&message.package_id.repr, &mut |name, data| {
++                            progress(format!("building proc-macros: {}", name));
++                            if message.target.kind.iter().any(|k| k == "proc-macro") {
++                                // Skip rmeta file
++                                if let Some(filename) =
++                                    message.filenames.iter().find(|name| is_dylib(name))
++                                {
++                                    let filename = AbsPathBuf::assert(PathBuf::from(&filename));
++                                    data.proc_macro_dylib_path = Some(filename);
++                                }
 +                            }
-         for package in workspace.packages() {
-             if let Some(package_build_data) = &mut outputs[package] {
-                 tracing::info!(
-                     "{}: {:?}",
-                     workspace[package].manifest.parent().display(),
-                     package_build_data,
-                 );
-                 // inject_cargo_env(package, package_build_data);
-                 if let Some(out_dir) = &package_build_data.out_dir {
-                     // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
-                     if let Some(out_dir) = out_dir.as_os_str().to_str().map(|s| s.to_owned()) {
-                         package_build_data.envs.push(("OUT_DIR".to_string(), out_dir));
-                     }
-                 }
-             }
-         }
-         let mut errors = errors.into_inner();
-         if !output.status.success() {
-             if errors.is_empty() {
-                 errors = "cargo check failed".to_string();
-             }
-             res.error = Some(errors);
-         }
-         Ok(res)
++                        });
 +                    }
 +                    Message::CompilerMessage(message) => {
 +                        progress(message.target.name);
 +
 +                        if let Some(diag) = message.message.rendered.as_deref() {
 +                            push_err(diag);
 +                        }
 +                    }
 +                    Message::BuildFinished(_) => {}
 +                    Message::TextLine(_) => {}
 +                    _ => {}
 +                }
 +            },
 +            &mut |line| {
 +                push_err(line);
 +            },
 +        )?;
 +
-         self.outputs.get(idx)?.as_ref()
++        let errors = if !output.status.success() {
++            let errors = errors.into_inner();
++            Some(if errors.is_empty() { "cargo check failed".to_string() } else { errors })
++        } else {
++            None
++        };
++        Ok(errors)
 +    }
 +
 +    pub fn error(&self) -> Option<&str> {
 +        self.error.as_deref()
 +    }
 +
 +    pub(crate) fn get_output(&self, idx: Package) -> Option<&BuildScriptOutput> {
- // FIXME: File a better way to know if it is a dylib.
++        self.outputs.get(idx)
 +    }
 +}
 +
++// FIXME: Find a better way to know if it is a dylib.
 +fn is_dylib(path: &Utf8Path) -> bool {
 +    match path.extension().map(|e| e.to_string().to_lowercase()) {
 +        None => false,
 +        Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"),
 +    }
 +}
index 8e690f1125a015fd82725255a71bca4b3bbda411,0000000000000000000000000000000000000000..b4c2ba436772f3d237e3d831ba4352aef3f26a99
mode 100644,000000..100644
--- /dev/null
@@@ -1,514 -1,0 +1,518 @@@
- use crate::CfgOverrides;
- use crate::{utf8_stdout, ManifestPath};
 +//! See [`CargoWorkspace`].
 +
 +use std::iter;
 +use std::path::PathBuf;
 +use std::str::from_utf8;
 +use std::{ops, process::Command};
 +
 +use anyhow::{Context, Result};
 +use base_db::Edition;
 +use cargo_metadata::{CargoOpt, MetadataCommand};
 +use la_arena::{Arena, Idx};
 +use paths::{AbsPath, AbsPathBuf};
 +use rustc_hash::FxHashMap;
 +use serde::Deserialize;
 +use serde_json::from_value;
 +
-                     // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
-                     // https://github.com/oli-obk/cargo_metadata/issues/79
++use crate::{utf8_stdout, InvocationLocation, ManifestPath};
++use crate::{CfgOverrides, InvocationStrategy};
 +
 +/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
 +/// workspace. It pretty closely mirrors `cargo metadata` output.
 +///
 +/// Note that internally, rust-analyzer uses a different structure:
 +/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
 +/// while this knows about `Packages` & `Targets`: purely cargo-related
 +/// concepts.
 +///
 +/// We use absolute paths here, `cargo metadata` guarantees to always produce
 +/// abs paths.
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct CargoWorkspace {
 +    packages: Arena<PackageData>,
 +    targets: Arena<TargetData>,
 +    workspace_root: AbsPathBuf,
 +}
 +
 +impl ops::Index<Package> for CargoWorkspace {
 +    type Output = PackageData;
 +    fn index(&self, index: Package) -> &PackageData {
 +        &self.packages[index]
 +    }
 +}
 +
 +impl ops::Index<Target> for CargoWorkspace {
 +    type Output = TargetData;
 +    fn index(&self, index: Target) -> &TargetData {
 +        &self.targets[index]
 +    }
 +}
 +
 +/// Describes how to set the rustc source directory.
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum RustcSource {
 +    /// Explicit path for the rustc source directory.
 +    Path(AbsPathBuf),
 +    /// Try to automatically detect where the rustc source directory is.
 +    Discover,
 +}
 +
 +/// Crates to disable `#[cfg(test)]` on.
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum UnsetTestCrates {
 +    None,
 +    Only(Vec<String>),
 +    All,
 +}
 +
 +impl Default for UnsetTestCrates {
 +    fn default() -> Self {
 +        Self::None
 +    }
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum CargoFeatures {
 +    All,
 +    Selected {
 +        /// List of features to activate.
 +        features: Vec<String>,
 +        /// Do not activate the `default` feature.
 +        no_default_features: bool,
 +    },
 +}
 +
 +impl Default for CargoFeatures {
 +    fn default() -> Self {
 +        CargoFeatures::Selected { features: vec![], no_default_features: false }
 +    }
 +}
 +
 +#[derive(Default, Clone, Debug, PartialEq, Eq)]
 +pub struct CargoConfig {
 +    /// List of features to activate.
 +    pub features: CargoFeatures,
 +    /// rustc target
 +    pub target: Option<String>,
 +    /// Sysroot loading behavior
 +    pub sysroot: Option<RustcSource>,
 +    /// rustc private crate source
 +    pub rustc_source: Option<RustcSource>,
 +    /// crates to disable `#[cfg(test)]` on
 +    pub unset_test_crates: UnsetTestCrates,
 +    /// Invoke `cargo check` through the RUSTC_WRAPPER.
 +    pub wrap_rustc_in_build_scripts: bool,
 +    /// The command to run instead of `cargo check` for building build scripts.
 +    pub run_build_script_command: Option<Vec<String>>,
 +    /// Extra env vars to set when invoking the cargo command
 +    pub extra_env: FxHashMap<String, String>,
++    pub invocation_strategy: InvocationStrategy,
++    pub invocation_location: InvocationLocation,
 +}
 +
 +impl CargoConfig {
 +    pub fn cfg_overrides(&self) -> CfgOverrides {
 +        match &self.unset_test_crates {
 +            UnsetTestCrates::None => CfgOverrides::Selective(iter::empty().collect()),
 +            UnsetTestCrates::Only(unset_test_crates) => CfgOverrides::Selective(
 +                unset_test_crates
 +                    .iter()
 +                    .cloned()
 +                    .zip(iter::repeat_with(|| {
 +                        cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())])
 +                            .unwrap()
 +                    }))
 +                    .collect(),
 +            ),
 +            UnsetTestCrates::All => CfgOverrides::Wildcard(
 +                cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]).unwrap(),
 +            ),
 +        }
 +    }
 +}
 +
 +pub type Package = Idx<PackageData>;
 +
 +pub type Target = Idx<TargetData>;
 +
 +/// Information associated with a cargo crate
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct PackageData {
 +    /// Version given in the `Cargo.toml`
 +    pub version: semver::Version,
 +    /// Name as given in the `Cargo.toml`
 +    pub name: String,
 +    /// Repository as given in the `Cargo.toml`
 +    pub repository: Option<String>,
 +    /// Path containing the `Cargo.toml`
 +    pub manifest: ManifestPath,
 +    /// Targets provided by the crate (lib, bin, example, test, ...)
 +    pub targets: Vec<Target>,
 +    /// Does this package come from the local filesystem (and is editable)?
 +    pub is_local: bool,
 +    /// Whether this package is a member of the workspace
 +    pub is_member: bool,
 +    /// List of packages this package depends on
 +    pub dependencies: Vec<PackageDependency>,
 +    /// Rust edition for this package
 +    pub edition: Edition,
 +    /// Features provided by the crate, mapped to the features required by that feature.
 +    pub features: FxHashMap<String, Vec<String>>,
 +    /// List of features enabled on this package
 +    pub active_features: Vec<String>,
 +    /// String representation of package id
 +    pub id: String,
 +    /// The contents of [package.metadata.rust-analyzer]
 +    pub metadata: RustAnalyzerPackageMetaData,
 +}
 +
 +#[derive(Deserialize, Default, Debug, Clone, Eq, PartialEq)]
 +pub struct RustAnalyzerPackageMetaData {
 +    pub rustc_private: bool,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct PackageDependency {
 +    pub pkg: Package,
 +    pub name: String,
 +    pub kind: DepKind,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
 +pub enum DepKind {
 +    /// Available to the library, binary, and dev targets in the package (but not the build script).
 +    Normal,
 +    /// Available only to test and bench targets (and the library target, when built with `cfg(test)`).
 +    Dev,
 +    /// Available only to the build script target.
 +    Build,
 +}
 +
 +impl DepKind {
 +    fn iter(list: &[cargo_metadata::DepKindInfo]) -> impl Iterator<Item = Self> + '_ {
 +        let mut dep_kinds = Vec::new();
 +        if list.is_empty() {
 +            dep_kinds.push(Self::Normal);
 +        }
 +        for info in list {
 +            let kind = match info.kind {
 +                cargo_metadata::DependencyKind::Normal => Self::Normal,
 +                cargo_metadata::DependencyKind::Development => Self::Dev,
 +                cargo_metadata::DependencyKind::Build => Self::Build,
 +                cargo_metadata::DependencyKind::Unknown => continue,
 +            };
 +            dep_kinds.push(kind);
 +        }
 +        dep_kinds.sort_unstable();
 +        dep_kinds.dedup();
 +        dep_kinds.into_iter()
 +    }
 +}
 +
 +/// Information associated with a package's target
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct TargetData {
 +    /// Package that provided this target
 +    pub package: Package,
 +    /// Name as given in the `Cargo.toml` or generated from the file name
 +    pub name: String,
 +    /// Path to the main source file of the target
 +    pub root: AbsPathBuf,
 +    /// Kind of target
 +    pub kind: TargetKind,
 +    /// Is this target a proc-macro
 +    pub is_proc_macro: bool,
 +    /// Required features of the target without which it won't build
 +    pub required_features: Vec<String>,
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 +pub enum TargetKind {
 +    Bin,
 +    /// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...).
 +    Lib,
 +    Example,
 +    Test,
 +    Bench,
 +    BuildScript,
 +    Other,
 +}
 +
 +impl TargetKind {
 +    fn new(kinds: &[String]) -> TargetKind {
 +        for kind in kinds {
 +            return match kind.as_str() {
 +                "bin" => TargetKind::Bin,
 +                "test" => TargetKind::Test,
 +                "bench" => TargetKind::Bench,
 +                "example" => TargetKind::Example,
 +                "custom-build" => TargetKind::BuildScript,
 +                "proc-macro" => TargetKind::Lib,
 +                _ if kind.contains("lib") => TargetKind::Lib,
 +                _ => continue,
 +            };
 +        }
 +        TargetKind::Other
 +    }
 +}
 +
 +// Deserialize helper for the cargo metadata
 +#[derive(Deserialize, Default)]
 +struct PackageMetadata {
 +    #[serde(rename = "rust-analyzer")]
 +    rust_analyzer: Option<RustAnalyzerPackageMetaData>,
 +}
 +
 +impl CargoWorkspace {
 +    pub fn fetch_metadata(
 +        cargo_toml: &ManifestPath,
 +        current_dir: &AbsPath,
 +        config: &CargoConfig,
 +        progress: &dyn Fn(String),
 +    ) -> Result<cargo_metadata::Metadata> {
 +        let target = config
 +            .target
 +            .clone()
 +            .or_else(|| cargo_config_build_target(cargo_toml, &config.extra_env))
 +            .or_else(|| rustc_discover_host_triple(cargo_toml, &config.extra_env));
 +
 +        let mut meta = MetadataCommand::new();
 +        meta.cargo_path(toolchain::cargo());
 +        meta.manifest_path(cargo_toml.to_path_buf());
 +        match &config.features {
 +            CargoFeatures::All => {
 +                meta.features(CargoOpt::AllFeatures);
 +            }
 +            CargoFeatures::Selected { features, no_default_features } => {
 +                if *no_default_features {
-         for meta_pkg in &meta.packages {
 +                    meta.features(CargoOpt::NoDefaultFeatures);
 +                }
 +                if !features.is_empty() {
 +                    meta.features(CargoOpt::SomeFeatures(features.clone()));
 +                }
 +            }
 +        }
 +        meta.current_dir(current_dir.as_os_str());
 +
 +        if let Some(target) = target {
 +            meta.other_options(vec![String::from("--filter-platform"), target]);
 +        }
 +
 +        // FIXME: Fetching metadata is a slow process, as it might require
 +        // calling crates.io. We should be reporting progress here, but it's
 +        // unclear whether cargo itself supports it.
 +        progress("metadata".to_string());
 +
 +        (|| -> Result<cargo_metadata::Metadata, cargo_metadata::Error> {
 +            let mut command = meta.cargo_command();
 +            command.envs(&config.extra_env);
 +            let output = command.output()?;
 +            if !output.status.success() {
 +                return Err(cargo_metadata::Error::CargoMetadata {
 +                    stderr: String::from_utf8(output.stderr)?,
 +                });
 +            }
 +            let stdout = from_utf8(&output.stdout)?
 +                .lines()
 +                .find(|line| line.starts_with('{'))
 +                .ok_or(cargo_metadata::Error::NoJson)?;
 +            cargo_metadata::MetadataCommand::parse(stdout)
 +        })()
 +        .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))
 +    }
 +
 +    pub fn new(mut meta: cargo_metadata::Metadata) -> CargoWorkspace {
 +        let mut pkg_by_id = FxHashMap::default();
 +        let mut packages = Arena::default();
 +        let mut targets = Arena::default();
 +
 +        let ws_members = &meta.workspace_members;
 +
 +        meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
-                 id,
-                 edition,
++        for meta_pkg in meta.packages {
 +            let cargo_metadata::Package {
-                 manifest_path,
 +                name,
-                 metadata,
 +                version,
-             let meta = from_value::<PackageMetadata>(metadata.clone()).unwrap_or_default();
++                id,
++                source,
++                targets: meta_targets,
++                features,
++                manifest_path,
 +                repository,
++                edition,
++                metadata,
 +                ..
 +            } = meta_pkg;
-             let is_local = meta_pkg.source.is_none();
-             let is_member = ws_members.contains(id);
++            let meta = from_value::<PackageMetadata>(metadata).unwrap_or_default();
 +            let edition = match edition {
 +                cargo_metadata::Edition::E2015 => Edition::Edition2015,
 +                cargo_metadata::Edition::E2018 => Edition::Edition2018,
 +                cargo_metadata::Edition::E2021 => Edition::Edition2021,
 +                _ => {
 +                    tracing::error!("Unsupported edition `{:?}`", edition);
 +                    Edition::CURRENT
 +                }
 +            };
 +            // We treat packages without source as "local" packages. That includes all members of
 +            // the current workspace, as well as any path dependency outside the workspace.
-                 name: name.clone(),
-                 version: version.clone(),
-                 manifest: AbsPathBuf::assert(PathBuf::from(&manifest_path)).try_into().unwrap(),
++            let is_local = source.is_none();
++            let is_member = ws_members.contains(&id);
 +
 +            let pkg = packages.alloc(PackageData {
 +                id: id.repr.clone(),
-                 repository: repository.clone(),
++                name,
++                version,
++                manifest: AbsPathBuf::assert(manifest_path.into()).try_into().unwrap(),
 +                targets: Vec::new(),
 +                is_local,
 +                is_member,
 +                edition,
-                 features: meta_pkg.features.clone().into_iter().collect(),
++                repository,
 +                dependencies: Vec::new(),
-             for meta_tgt in &meta_pkg.targets {
-                 let is_proc_macro = meta_tgt.kind.as_slice() == ["proc-macro"];
++                features: features.into_iter().collect(),
 +                active_features: Vec::new(),
 +                metadata: meta.rust_analyzer.unwrap_or_default(),
 +            });
 +            let pkg_data = &mut packages[pkg];
 +            pkg_by_id.insert(id, pkg);
-                     name: meta_tgt.name.clone(),
-                     root: AbsPathBuf::assert(PathBuf::from(&meta_tgt.src_path)),
-                     kind: TargetKind::new(meta_tgt.kind.as_slice()),
-                     is_proc_macro,
-                     required_features: meta_tgt.required_features.clone(),
++            for meta_tgt in meta_targets {
++                let cargo_metadata::Target { name, kind, required_features, src_path, .. } =
++                    meta_tgt;
 +                let tgt = targets.alloc(TargetData {
 +                    package: pkg,
++                    name,
++                    root: AbsPathBuf::assert(src_path.into()),
++                    kind: TargetKind::new(&kind),
++                    is_proc_macro: &*kind == ["proc-macro"],
++                    required_features,
 +                });
 +                pkg_data.targets.push(tgt);
 +            }
 +        }
 +        let resolve = meta.resolve.expect("metadata executed with deps");
 +        for mut node in resolve.nodes {
 +            let &source = pkg_by_id.get(&node.id).unwrap();
 +            node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg));
 +            let dependencies = node
 +                .deps
 +                .iter()
 +                .flat_map(|dep| DepKind::iter(&dep.dep_kinds).map(move |kind| (dep, kind)));
 +            for (dep_node, kind) in dependencies {
 +                let &pkg = pkg_by_id.get(&dep_node.pkg).unwrap();
 +                let dep = PackageDependency { name: dep_node.name.clone(), pkg, kind };
 +                packages[source].dependencies.push(dep);
 +            }
 +            packages[source].active_features.extend(node.features);
 +        }
 +
 +        let workspace_root =
 +            AbsPathBuf::assert(PathBuf::from(meta.workspace_root.into_os_string()));
 +
 +        CargoWorkspace { packages, targets, workspace_root }
 +    }
 +
 +    pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a {
 +        self.packages.iter().map(|(id, _pkg)| id)
 +    }
 +
 +    pub fn target_by_root(&self, root: &AbsPath) -> Option<Target> {
 +        self.packages()
 +            .filter(|&pkg| self[pkg].is_member)
 +            .find_map(|pkg| self[pkg].targets.iter().find(|&&it| &self[it].root == root))
 +            .copied()
 +    }
 +
 +    pub fn workspace_root(&self) -> &AbsPath {
 +        &self.workspace_root
 +    }
 +
 +    pub fn package_flag(&self, package: &PackageData) -> String {
 +        if self.is_unique(&*package.name) {
 +            package.name.clone()
 +        } else {
 +            format!("{}:{}", package.name, package.version)
 +        }
 +    }
 +
 +    pub fn parent_manifests(&self, manifest_path: &ManifestPath) -> Option<Vec<ManifestPath>> {
 +        let mut found = false;
 +        let parent_manifests = self
 +            .packages()
 +            .filter_map(|pkg| {
 +                if !found && &self[pkg].manifest == manifest_path {
 +                    found = true
 +                }
 +                self[pkg].dependencies.iter().find_map(|dep| {
 +                    (&self[dep.pkg].manifest == manifest_path).then(|| self[pkg].manifest.clone())
 +                })
 +            })
 +            .collect::<Vec<ManifestPath>>();
 +
 +        // some packages has this pkg as dep. return their manifests
 +        if parent_manifests.len() > 0 {
 +            return Some(parent_manifests);
 +        }
 +
 +        // this pkg is inside this cargo workspace, fallback to workspace root
 +        if found {
 +            return Some(vec![
 +                ManifestPath::try_from(self.workspace_root().join("Cargo.toml")).ok()?
 +            ]);
 +        }
 +
 +        // not in this workspace
 +        None
 +    }
 +
 +    fn is_unique(&self, name: &str) -> bool {
 +        self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
 +    }
 +}
 +
 +fn rustc_discover_host_triple(
 +    cargo_toml: &ManifestPath,
 +    extra_env: &FxHashMap<String, String>,
 +) -> Option<String> {
 +    let mut rustc = Command::new(toolchain::rustc());
 +    rustc.envs(extra_env);
 +    rustc.current_dir(cargo_toml.parent()).arg("-vV");
 +    tracing::debug!("Discovering host platform by {:?}", rustc);
 +    match utf8_stdout(rustc) {
 +        Ok(stdout) => {
 +            let field = "host: ";
 +            let target = stdout.lines().find_map(|l| l.strip_prefix(field));
 +            if let Some(target) = target {
 +                Some(target.to_string())
 +            } else {
 +                // If we fail to resolve the host platform, it's not the end of the world.
 +                tracing::info!("rustc -vV did not report host platform, got:\n{}", stdout);
 +                None
 +            }
 +        }
 +        Err(e) => {
 +            tracing::warn!("Failed to discover host platform: {}", e);
 +            None
 +        }
 +    }
 +}
 +
 +fn cargo_config_build_target(
 +    cargo_toml: &ManifestPath,
 +    extra_env: &FxHashMap<String, String>,
 +) -> Option<String> {
 +    let mut cargo_config = Command::new(toolchain::cargo());
 +    cargo_config.envs(extra_env);
 +    cargo_config
 +        .current_dir(cargo_toml.parent())
 +        .args(&["-Z", "unstable-options", "config", "get", "build.target"])
 +        .env("RUSTC_BOOTSTRAP", "1");
 +    // if successful we receive `build.target = "target-triple"`
 +    tracing::debug!("Discovering cargo config target by {:?}", cargo_config);
 +    match utf8_stdout(cargo_config) {
 +        Ok(stdout) => stdout
 +            .strip_prefix("build.target = \"")
 +            .and_then(|stdout| stdout.strip_suffix('"'))
 +            .map(ToOwned::to_owned),
 +        Err(_) => None,
 +    }
 +}
index ce78ce85697afd23170359c5ebf572ca69a93e5a,0000000000000000000000000000000000000000..575581fa543a309495a5c3806d26703d03bf1298
mode 100644,000000..100644
--- /dev/null
@@@ -1,159 -1,0 +1,173 @@@
-         bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display())
 +//! In rust-analyzer, we maintain a strict separation between pure abstract
 +//! semantic project model and a concrete model of a particular build system.
 +//!
 +//! Pure model is represented by the [`base_db::CrateGraph`] from another crate.
 +//!
 +//! In this crate, we are concerned with "real world" project models.
 +//!
 +//! Specifically, here we have a representation for a Cargo project
 +//! ([`CargoWorkspace`]) and for manually specified layout ([`ProjectJson`]).
 +//!
 +//! Roughly, the things we do here are:
 +//!
 +//! * Project discovery (where's the relevant Cargo.toml for the current dir).
 +//! * Custom build steps (`build.rs` code generation and compilation of
 +//!   procedural macros).
 +//! * Lowering of concrete model to a [`base_db::CrateGraph`]
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +mod manifest_path;
 +mod cargo_workspace;
 +mod cfg_flag;
 +mod project_json;
 +mod sysroot;
 +mod workspace;
 +mod rustc_cfg;
 +mod build_scripts;
 +
 +#[cfg(test)]
 +mod tests;
 +
 +use std::{
 +    fs::{self, read_dir, ReadDir},
 +    io,
 +    process::Command,
 +};
 +
 +use anyhow::{bail, format_err, Context, Result};
 +use paths::{AbsPath, AbsPathBuf};
 +use rustc_hash::FxHashSet;
 +
 +pub use crate::{
 +    build_scripts::WorkspaceBuildScripts,
 +    cargo_workspace::{
 +        CargoConfig, CargoFeatures, CargoWorkspace, Package, PackageData, PackageDependency,
 +        RustcSource, Target, TargetData, TargetKind, UnsetTestCrates,
 +    },
 +    manifest_path::ManifestPath,
 +    project_json::{ProjectJson, ProjectJsonData},
 +    sysroot::Sysroot,
 +    workspace::{CfgOverrides, PackageRoot, ProjectWorkspace},
 +};
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
 +pub enum ProjectManifest {
 +    ProjectJson(ManifestPath),
 +    CargoToml(ManifestPath),
 +}
 +
 +impl ProjectManifest {
 +    pub fn from_manifest_file(path: AbsPathBuf) -> Result<ProjectManifest> {
 +        let path = ManifestPath::try_from(path)
 +            .map_err(|path| format_err!("bad manifest path: {}", path.display()))?;
 +        if path.file_name().unwrap_or_default() == "rust-project.json" {
 +            return Ok(ProjectManifest::ProjectJson(path));
 +        }
 +        if path.file_name().unwrap_or_default() == "Cargo.toml" {
 +            return Ok(ProjectManifest::CargoToml(path));
 +        }
-             bail!("more than one project")
++        bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display());
 +    }
 +
 +    pub fn discover_single(path: &AbsPath) -> Result<ProjectManifest> {
 +        let mut candidates = ProjectManifest::discover(path)?;
 +        let res = match candidates.pop() {
 +            None => bail!("no projects"),
 +            Some(it) => it,
 +        };
 +
 +        if !candidates.is_empty() {
++            bail!("more than one project");
 +        }
 +        Ok(res)
 +    }
 +
 +    pub fn discover(path: &AbsPath) -> io::Result<Vec<ProjectManifest>> {
 +        if let Some(project_json) = find_in_parent_dirs(path, "rust-project.json") {
 +            return Ok(vec![ProjectManifest::ProjectJson(project_json)]);
 +        }
 +        return find_cargo_toml(path)
 +            .map(|paths| paths.into_iter().map(ProjectManifest::CargoToml).collect());
 +
 +        fn find_cargo_toml(path: &AbsPath) -> io::Result<Vec<ManifestPath>> {
 +            match find_in_parent_dirs(path, "Cargo.toml") {
 +                Some(it) => Ok(vec![it]),
 +                None => Ok(find_cargo_toml_in_child_dir(read_dir(path)?)),
 +            }
 +        }
 +
 +        fn find_in_parent_dirs(path: &AbsPath, target_file_name: &str) -> Option<ManifestPath> {
 +            if path.file_name().unwrap_or_default() == target_file_name {
 +                if let Ok(manifest) = ManifestPath::try_from(path.to_path_buf()) {
 +                    return Some(manifest);
 +                }
 +            }
 +
 +            let mut curr = Some(path);
 +
 +            while let Some(path) = curr {
 +                let candidate = path.join(target_file_name);
 +                if fs::metadata(&candidate).is_ok() {
 +                    if let Ok(manifest) = ManifestPath::try_from(candidate) {
 +                        return Some(manifest);
 +                    }
 +                }
 +                curr = path.parent();
 +            }
 +
 +            None
 +        }
 +
 +        fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<ManifestPath> {
 +            // Only one level down to avoid cycles the easy way and stop a runaway scan with large projects
 +            entities
 +                .filter_map(Result::ok)
 +                .map(|it| it.path().join("Cargo.toml"))
 +                .filter(|it| it.exists())
 +                .map(AbsPathBuf::assert)
 +                .filter_map(|it| it.try_into().ok())
 +                .collect()
 +        }
 +    }
 +
 +    pub fn discover_all(paths: &[AbsPathBuf]) -> Vec<ProjectManifest> {
 +        let mut res = paths
 +            .iter()
 +            .filter_map(|it| ProjectManifest::discover(it.as_ref()).ok())
 +            .flatten()
 +            .collect::<FxHashSet<_>>()
 +            .into_iter()
 +            .collect::<Vec<_>>();
 +        res.sort();
 +        res
 +    }
 +}
 +
 +fn utf8_stdout(mut cmd: Command) -> Result<String> {
 +    let output = cmd.output().with_context(|| format!("{:?} failed", cmd))?;
 +    if !output.status.success() {
 +        match String::from_utf8(output.stderr) {
 +            Ok(stderr) if !stderr.is_empty() => {
 +                bail!("{:?} failed, {}\nstderr:\n{}", cmd, output.status, stderr)
 +            }
 +            _ => bail!("{:?} failed, {}", cmd, output.status),
 +        }
 +    }
 +    let stdout = String::from_utf8(output.stdout)?;
 +    Ok(stdout.trim().to_string())
 +}
++
++#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
++pub enum InvocationStrategy {
++    Once,
++    #[default]
++    PerWorkspace,
++}
++
++#[derive(Clone, Debug, Default, PartialEq, Eq)]
++pub enum InvocationLocation {
++    Root(AbsPathBuf),
++    #[default]
++    Workspace,
++}
index bc37e3d132a6ce6f70da3ab54cf3abe4a89f3091,0000000000000000000000000000000000000000..fa8d76f3f45297922192f0ce6f0cca467552a7ed
mode 100644,000000..100644
--- /dev/null
@@@ -1,260 -1,0 +1,262 @@@
-     pub fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + 'a {
 +//! Loads "sysroot" crate.
 +//!
 +//! One confusing point here is that normally sysroot is a bunch of `.rlib`s,
 +//! but we can't process `.rlib` and need source code instead. The source code
 +//! is typically installed with `rustup component add rust-src` command.
 +
 +use std::{env, fs, iter, ops, path::PathBuf, process::Command};
 +
 +use anyhow::{format_err, Result};
 +use la_arena::{Arena, Idx};
 +use paths::{AbsPath, AbsPathBuf};
 +use rustc_hash::FxHashMap;
 +
 +use crate::{utf8_stdout, ManifestPath};
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct Sysroot {
 +    root: AbsPathBuf,
 +    src_root: AbsPathBuf,
 +    crates: Arena<SysrootCrateData>,
 +}
 +
 +pub(crate) type SysrootCrate = Idx<SysrootCrateData>;
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct SysrootCrateData {
 +    pub name: String,
 +    pub root: ManifestPath,
 +    pub deps: Vec<SysrootCrate>,
 +}
 +
 +impl ops::Index<SysrootCrate> for Sysroot {
 +    type Output = SysrootCrateData;
 +    fn index(&self, index: SysrootCrate) -> &SysrootCrateData {
 +        &self.crates[index]
 +    }
 +}
 +
 +impl Sysroot {
 +    /// Returns sysroot "root" directory, where `bin/`, `etc/`, `lib/`, `libexec/`
 +    /// subfolder live, like:
 +    /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu`
 +    pub fn root(&self) -> &AbsPath {
 +        &self.root
 +    }
 +
 +    /// Returns the sysroot "source" directory, where stdlib sources are located, like:
 +    /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library`
 +    pub fn src_root(&self) -> &AbsPath {
 +        &self.src_root
 +    }
 +
 +    pub fn public_deps(&self) -> impl Iterator<Item = (&'static str, SysrootCrate, bool)> + '_ {
 +        // core is added as a dependency before std in order to
 +        // mimic rustcs dependency order
 +        ["core", "alloc", "std"]
 +            .into_iter()
 +            .zip(iter::repeat(true))
 +            .chain(iter::once(("test", false)))
 +            .filter_map(move |(name, prelude)| Some((name, self.by_name(name)?, prelude)))
 +    }
 +
 +    pub fn proc_macro(&self) -> Option<SysrootCrate> {
 +        self.by_name("proc_macro")
 +    }
 +
-         tracing::debug!("Discovering sysroot for {}", dir.display());
++    pub fn crates(&self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + '_ {
 +        self.crates.iter().map(|(id, _data)| id)
 +    }
 +}
 +
 +impl Sysroot {
++    /// Attempts to discover the toolchain's sysroot from the given `dir`.
 +    pub fn discover(dir: &AbsPath, extra_env: &FxHashMap<String, String>) -> Result<Sysroot> {
-         tracing::debug!("Discovering rustc source for {}", cargo_toml.display());
++        tracing::debug!("discovering sysroot for {}", dir.display());
 +        let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
 +        let sysroot_src_dir =
 +            discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env)?;
 +        let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
 +        Ok(res)
 +    }
 +
 +    pub fn discover_rustc(
 +        cargo_toml: &ManifestPath,
 +        extra_env: &FxHashMap<String, String>,
 +    ) -> Option<ManifestPath> {
-         discover_sysroot_dir(current_dir, extra_env)
-             .ok()
-             .and_then(|sysroot_dir| get_rustc_src(&sysroot_dir))
++        tracing::debug!("discovering rustc source for {}", cargo_toml.display());
 +        let current_dir = cargo_toml.parent();
-     tracing::debug!("Checking for rustc source code: {}", rustc_src.display());
++        let sysroot_dir = discover_sysroot_dir(current_dir, extra_env).ok()?;
++        get_rustc_src(&sysroot_dir)
 +    }
 +
 +    pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf) -> Result<Sysroot> {
 +        let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| {
 +            format_err!("can't load standard library from sysroot {}", sysroot_dir.display())
 +        })?;
 +        let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
 +        Ok(res)
 +    }
 +
 +    pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Result<Sysroot> {
 +        let mut sysroot =
 +            Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() };
 +
 +        for path in SYSROOT_CRATES.trim().lines() {
 +            let name = path.split('/').last().unwrap();
 +            let root = [format!("{}/src/lib.rs", path), format!("lib{}/lib.rs", path)]
 +                .into_iter()
 +                .map(|it| sysroot.src_root.join(it))
 +                .filter_map(|it| ManifestPath::try_from(it).ok())
 +                .find(|it| fs::metadata(it).is_ok());
 +
 +            if let Some(root) = root {
 +                sysroot.crates.alloc(SysrootCrateData {
 +                    name: name.into(),
 +                    root,
 +                    deps: Vec::new(),
 +                });
 +            }
 +        }
 +
 +        if let Some(std) = sysroot.by_name("std") {
 +            for dep in STD_DEPS.trim().lines() {
 +                if let Some(dep) = sysroot.by_name(dep) {
 +                    sysroot.crates[std].deps.push(dep)
 +                }
 +            }
 +        }
 +
 +        if let Some(alloc) = sysroot.by_name("alloc") {
 +            if let Some(core) = sysroot.by_name("core") {
 +                sysroot.crates[alloc].deps.push(core);
 +            }
 +        }
 +
 +        if let Some(proc_macro) = sysroot.by_name("proc_macro") {
 +            if let Some(std) = sysroot.by_name("std") {
 +                sysroot.crates[proc_macro].deps.push(std);
 +            }
 +        }
 +
 +        if sysroot.by_name("core").is_none() {
 +            let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
 +                " (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
 +            } else {
 +                ""
 +            };
 +            anyhow::bail!(
 +                "could not find libcore in sysroot path `{}`{}",
 +                sysroot.src_root.as_path().display(),
 +                var_note,
 +            );
 +        }
 +
 +        Ok(sysroot)
 +    }
 +
 +    fn by_name(&self, name: &str) -> Option<SysrootCrate> {
 +        let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?;
 +        Some(id)
 +    }
 +}
 +
 +fn discover_sysroot_dir(
 +    current_dir: &AbsPath,
 +    extra_env: &FxHashMap<String, String>,
 +) -> Result<AbsPathBuf> {
 +    let mut rustc = Command::new(toolchain::rustc());
 +    rustc.envs(extra_env);
 +    rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
 +    tracing::debug!("Discovering sysroot by {:?}", rustc);
 +    let stdout = utf8_stdout(rustc)?;
 +    Ok(AbsPathBuf::assert(PathBuf::from(stdout)))
 +}
 +
 +fn discover_sysroot_src_dir(sysroot_path: &AbsPathBuf) -> Option<AbsPathBuf> {
 +    if let Ok(path) = env::var("RUST_SRC_PATH") {
 +        if let Ok(path) = AbsPathBuf::try_from(path.as_str()) {
 +            let core = path.join("core");
 +            if fs::metadata(&core).is_ok() {
 +                tracing::debug!("Discovered sysroot by RUST_SRC_PATH: {}", path.display());
 +                return Some(path);
 +            }
 +            tracing::debug!("RUST_SRC_PATH is set, but is invalid (no core: {:?}), ignoring", core);
 +        } else {
 +            tracing::debug!("RUST_SRC_PATH is set, but is invalid, ignoring");
 +        }
 +    }
 +
 +    get_rust_src(sysroot_path)
 +}
++
 +fn discover_sysroot_src_dir_or_add_component(
 +    sysroot_path: &AbsPathBuf,
 +    current_dir: &AbsPath,
 +    extra_env: &FxHashMap<String, String>,
 +) -> Result<AbsPathBuf> {
 +    discover_sysroot_src_dir(sysroot_path)
 +        .or_else(|| {
 +            let mut rustup = Command::new(toolchain::rustup());
 +            rustup.envs(extra_env);
 +            rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]);
++            tracing::info!("adding rust-src component by {:?}", rustup);
 +            utf8_stdout(rustup).ok()?;
 +            get_rust_src(sysroot_path)
 +        })
 +        .ok_or_else(|| {
 +            format_err!(
 +                "\
 +can't load standard library from sysroot
 +{}
 +(discovered via `rustc --print sysroot`)
 +try installing the Rust source the same way you installed rustc",
 +                sysroot_path.display(),
 +            )
 +        })
 +}
 +
 +fn get_rustc_src(sysroot_path: &AbsPath) -> Option<ManifestPath> {
 +    let rustc_src = sysroot_path.join("lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml");
 +    let rustc_src = ManifestPath::try_from(rustc_src).ok()?;
-     tracing::debug!("Checking sysroot: {}", rust_src.display());
++    tracing::debug!("checking for rustc source code: {}", rustc_src.display());
 +    if fs::metadata(&rustc_src).is_ok() {
 +        Some(rustc_src)
 +    } else {
 +        None
 +    }
 +}
 +
 +fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
 +    let rust_src = sysroot_path.join("lib/rustlib/src/rust/library");
++    tracing::debug!("checking sysroot library: {}", rust_src.display());
 +    if fs::metadata(&rust_src).is_ok() {
 +        Some(rust_src)
 +    } else {
 +        None
 +    }
 +}
 +
 +const SYSROOT_CRATES: &str = "
 +alloc
 +core
 +panic_abort
 +panic_unwind
 +proc_macro
 +profiler_builtins
 +std
 +stdarch/crates/std_detect
 +term
 +test
 +unwind";
 +
 +const STD_DEPS: &str = "
 +alloc
 +core
 +panic_abort
 +panic_unwind
 +profiler_builtins
 +std_detect
 +term
 +test
 +unwind";
index 72ddf809288aa35338ac2a283db0ed30336cd677,0000000000000000000000000000000000000000..2780c62ed118afd022829408b3167148ea65e2f5
mode 100644,000000..100644
--- /dev/null
@@@ -1,1070 -1,0 +1,1127 @@@
- use std::{collections::VecDeque, fmt, fs, process::Command};
 +//! Handles lowering of build-system specific workspace information (`cargo
 +//! metadata` or `rust-project.json`) into representation stored in the salsa
 +//! database -- `CrateGraph`.
 +
-     utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath, Package, ProjectJson, ProjectManifest,
-     Sysroot, TargetKind, WorkspaceBuildScripts,
++use std::{collections::VecDeque, fmt, fs, process::Command, sync::Arc};
 +
 +use anyhow::{format_err, Context, Result};
 +use base_db::{
 +    CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env,
 +    FileId, LangCrateOrigin, ProcMacroLoadResult,
 +};
 +use cfg::{CfgDiff, CfgOptions};
 +use paths::{AbsPath, AbsPathBuf};
 +use rustc_hash::{FxHashMap, FxHashSet};
 +use semver::Version;
 +use stdx::{always, hash::NoHashHashMap};
 +
 +use crate::{
 +    build_scripts::BuildScriptOutput,
 +    cargo_workspace::{DepKind, PackageData, RustcSource},
 +    cfg_flag::CfgFlag,
 +    rustc_cfg,
 +    sysroot::SysrootCrate,
-                 WorkspaceBuildScripts::run(config, cargo, progress, toolchain).with_context(|| {
-                     format!("Failed to run build scripts for {}", &cargo.workspace_root().display())
-                 })
++    utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath, Package,
++    ProjectJson, ProjectManifest, Sysroot, TargetKind, WorkspaceBuildScripts,
 +};
 +
 +/// A set of cfg-overrides per crate.
 +///
 +/// `Wildcard(..)` is useful e.g. disabling `#[cfg(test)]` on all crates,
 +/// without having to first obtain a list of all crates.
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum CfgOverrides {
 +    /// A single global set of overrides matching all crates.
 +    Wildcard(CfgDiff),
 +    /// A set of overrides matching specific crates.
 +    Selective(FxHashMap<String, CfgDiff>),
 +}
 +
 +impl Default for CfgOverrides {
 +    fn default() -> Self {
 +        Self::Selective(FxHashMap::default())
 +    }
 +}
 +
 +impl CfgOverrides {
 +    pub fn len(&self) -> usize {
 +        match self {
 +            CfgOverrides::Wildcard(_) => 1,
 +            CfgOverrides::Selective(hash_map) => hash_map.len(),
 +        }
 +    }
 +}
 +
 +/// `PackageRoot` describes a package root folder.
 +/// Which may be an external dependency, or a member of
 +/// the current workspace.
 +#[derive(Debug, Clone, Eq, PartialEq, Hash)]
 +pub struct PackageRoot {
 +    /// Is from the local filesystem and may be edited
 +    pub is_local: bool,
 +    pub include: Vec<AbsPathBuf>,
 +    pub exclude: Vec<AbsPathBuf>,
 +}
 +
 +#[derive(Clone, Eq, PartialEq)]
 +pub enum ProjectWorkspace {
 +    /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
 +    Cargo {
 +        cargo: CargoWorkspace,
 +        build_scripts: WorkspaceBuildScripts,
 +        sysroot: Option<Sysroot>,
 +        rustc: Option<CargoWorkspace>,
 +        /// Holds cfg flags for the current target. We get those by running
 +        /// `rustc --print cfg`.
 +        ///
 +        /// FIXME: make this a per-crate map, as, eg, build.rs might have a
 +        /// different target.
 +        rustc_cfg: Vec<CfgFlag>,
 +        cfg_overrides: CfgOverrides,
 +        toolchain: Option<Version>,
 +    },
 +    /// Project workspace was manually specified using a `rust-project.json` file.
 +    Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
 +
 +    // FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
 +    // That's not the end user experience we should strive for.
 +    // Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working.
 +    // That needs some changes on the salsa-level though.
 +    // In particular, we should split the unified CrateGraph (which currently has maximal durability) into proper crate graph, and a set of ad hoc roots (with minimal durability).
 +    // Then, we need to hide the graph behind the queries such that most queries look only at the proper crate graph, and fall back to ad hoc roots only if there's no results.
 +    // After this, we should be able to tweak the logic in reload.rs to add newly opened files, which don't belong to any existing crates, to the set of the detached files.
 +    // //
 +    /// Project with a set of disjoint files, not belonging to any particular workspace.
 +    /// Backed by basic sysroot crates for basic completion and highlighting.
 +    DetachedFiles { files: Vec<AbsPathBuf>, sysroot: Sysroot, rustc_cfg: Vec<CfgFlag> },
 +}
 +
 +impl fmt::Debug for ProjectWorkspace {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        // Make sure this isn't too verbose.
 +        match self {
 +            ProjectWorkspace::Cargo {
 +                cargo,
 +                build_scripts: _,
 +                sysroot,
 +                rustc,
 +                rustc_cfg,
 +                cfg_overrides,
 +                toolchain,
 +            } => f
 +                .debug_struct("Cargo")
 +                .field("root", &cargo.workspace_root().file_name())
 +                .field("n_packages", &cargo.packages().len())
 +                .field("sysroot", &sysroot.is_some())
 +                .field(
 +                    "n_rustc_compiler_crates",
 +                    &rustc.as_ref().map_or(0, |rc| rc.packages().len()),
 +                )
 +                .field("n_rustc_cfg", &rustc_cfg.len())
 +                .field("n_cfg_overrides", &cfg_overrides.len())
 +                .field("toolchain", &toolchain)
 +                .finish(),
 +            ProjectWorkspace::Json { project, sysroot, rustc_cfg } => {
 +                let mut debug_struct = f.debug_struct("Json");
 +                debug_struct.field("n_crates", &project.n_crates());
 +                if let Some(sysroot) = sysroot {
 +                    debug_struct.field("n_sysroot_crates", &sysroot.crates().len());
 +                }
 +                debug_struct.field("n_rustc_cfg", &rustc_cfg.len());
 +                debug_struct.finish()
 +            }
 +            ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => f
 +                .debug_struct("DetachedFiles")
 +                .field("n_files", &files.len())
 +                .field("n_sysroot_crates", &sysroot.crates().len())
 +                .field("n_rustc_cfg", &rustc_cfg.len())
 +                .finish(),
 +        }
 +    }
 +}
 +
 +impl ProjectWorkspace {
 +    pub fn load(
 +        manifest: ProjectManifest,
 +        config: &CargoConfig,
 +        progress: &dyn Fn(String),
 +    ) -> Result<ProjectWorkspace> {
 +        let res = match manifest {
 +            ProjectManifest::ProjectJson(project_json) => {
 +                let file = fs::read_to_string(&project_json).with_context(|| {
 +                    format!("Failed to read json file {}", project_json.display())
 +                })?;
 +                let data = serde_json::from_str(&file).with_context(|| {
 +                    format!("Failed to deserialize json file {}", project_json.display())
 +                })?;
 +                let project_location = project_json.parent().to_path_buf();
 +                let project_json = ProjectJson::new(&project_location, data);
 +                ProjectWorkspace::load_inline(
 +                    project_json,
 +                    config.target.as_deref(),
 +                    &config.extra_env,
 +                )?
 +            }
 +            ProjectManifest::CargoToml(cargo_toml) => {
 +                let cargo_version = utf8_stdout({
 +                    let mut cmd = Command::new(toolchain::cargo());
 +                    cmd.envs(&config.extra_env);
 +                    cmd.arg("--version");
 +                    cmd
 +                })?;
 +                let toolchain = cargo_version
 +                    .get("cargo ".len()..)
 +                    .and_then(|it| Version::parse(it.split_whitespace().next()?).ok());
 +
 +                let meta = CargoWorkspace::fetch_metadata(
 +                    &cargo_toml,
 +                    cargo_toml.parent(),
 +                    config,
 +                    progress,
 +                )
 +                .with_context(|| {
 +                    format!(
 +                        "Failed to read Cargo metadata from Cargo.toml file {}, {:?}",
 +                        cargo_toml.display(),
 +                        toolchain
 +                    )
 +                })?;
 +                let cargo = CargoWorkspace::new(meta);
 +
 +                let sysroot = match &config.sysroot {
 +                    Some(RustcSource::Path(path)) => {
 +                        Some(Sysroot::with_sysroot_dir(path.clone()).with_context(|| {
 +                            format!(
 +                                "Failed to find sysroot for Cargo.toml file {}.",
 +                                cargo_toml.display()
 +                            )
 +                        })?)
 +                    }
 +                    Some(RustcSource::Discover) => Some(
 +                        Sysroot::discover(cargo_toml.parent(), &config.extra_env).with_context(
 +                            || {
 +                                format!(
 +                            "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
 +                            cargo_toml.display()
 +                        )
 +                            },
 +                        )?,
 +                    ),
 +                    None => None,
 +                };
++                if let Some(sysroot) = &sysroot {
++                    tracing::info!(src_root = %sysroot.src_root().display(), root = %sysroot.root().display(), "Using sysroot");
++                }
 +
 +                let rustc_dir = match &config.rustc_source {
 +                    Some(RustcSource::Path(path)) => ManifestPath::try_from(path.clone()).ok(),
 +                    Some(RustcSource::Discover) => {
 +                        Sysroot::discover_rustc(&cargo_toml, &config.extra_env)
 +                    }
 +                    None => None,
 +                };
++                if let Some(rustc_dir) = &rustc_dir {
++                    tracing::info!(rustc_dir = %rustc_dir.display(), "Using rustc source");
++                }
 +
 +                let rustc = match rustc_dir {
 +                    Some(rustc_dir) => Some({
 +                        let meta = CargoWorkspace::fetch_metadata(
 +                            &rustc_dir,
 +                            cargo_toml.parent(),
 +                            config,
 +                            progress,
 +                        )
 +                        .with_context(|| {
 +                            "Failed to read Cargo metadata for Rust sources".to_string()
 +                        })?;
 +                        CargoWorkspace::new(meta)
 +                    }),
 +                    None => None,
 +                };
 +
 +                let rustc_cfg =
 +                    rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), &config.extra_env);
 +
 +                let cfg_overrides = config.cfg_overrides();
 +                ProjectWorkspace::Cargo {
 +                    cargo,
 +                    build_scripts: WorkspaceBuildScripts::default(),
 +                    sysroot,
 +                    rustc,
 +                    rustc_cfg,
 +                    cfg_overrides,
 +                    toolchain,
 +                }
 +            }
 +        };
 +
 +        Ok(res)
 +    }
 +
 +    pub fn load_inline(
 +        project_json: ProjectJson,
 +        target: Option<&str>,
 +        extra_env: &FxHashMap<String, String>,
 +    ) -> Result<ProjectWorkspace> {
 +        let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
 +            (Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)?),
 +            (Some(sysroot), None) => {
 +                // assume sysroot is structured like rustup's and guess `sysroot_src`
 +                let sysroot_src =
 +                    sysroot.join("lib").join("rustlib").join("src").join("rust").join("library");
 +
 +                Some(Sysroot::load(sysroot, sysroot_src)?)
 +            }
 +            (None, Some(sysroot_src)) => {
 +                // assume sysroot is structured like rustup's and guess `sysroot`
 +                let mut sysroot = sysroot_src.clone();
 +                for _ in 0..5 {
 +                    sysroot.pop();
 +                }
 +                Some(Sysroot::load(sysroot, sysroot_src)?)
 +            }
 +            (None, None) => None,
 +        };
++        if let Some(sysroot) = &sysroot {
++            tracing::info!(src_root = %sysroot.src_root().display(), root = %sysroot.root().display(), "Using sysroot");
++        }
 +
 +        let rustc_cfg = rustc_cfg::get(None, target, extra_env);
 +        Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
 +    }
 +
 +    pub fn load_detached_files(detached_files: Vec<AbsPathBuf>) -> Result<ProjectWorkspace> {
 +        let sysroot = Sysroot::discover(
 +            detached_files
 +                .first()
 +                .and_then(|it| it.parent())
 +                .ok_or_else(|| format_err!("No detached files to load"))?,
 +            &Default::default(),
 +        )?;
 +        let rustc_cfg = rustc_cfg::get(None, None, &Default::default());
 +        Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
 +    }
 +
++    /// Runs the build scripts for this [`ProjectWorkspace`].
 +    pub fn run_build_scripts(
 +        &self,
 +        config: &CargoConfig,
 +        progress: &dyn Fn(String),
 +    ) -> Result<WorkspaceBuildScripts> {
 +        match self {
 +            ProjectWorkspace::Cargo { cargo, toolchain, .. } => {
++                WorkspaceBuildScripts::run_for_workspace(config, cargo, progress, toolchain)
++                    .with_context(|| {
++                        format!(
++                            "Failed to run build scripts for {}",
++                            &cargo.workspace_root().display()
++                        )
++                    })
 +            }
 +            ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFiles { .. } => {
 +                Ok(WorkspaceBuildScripts::default())
 +            }
 +        }
 +    }
 +
++    /// Runs the build scripts for the given [`ProjectWorkspace`]s. Depending on the invocation
++    /// strategy this may run a single build process for all project workspaces.
++    pub fn run_all_build_scripts(
++        workspaces: &[ProjectWorkspace],
++        config: &CargoConfig,
++        progress: &dyn Fn(String),
++    ) -> Vec<Result<WorkspaceBuildScripts>> {
++        if matches!(config.invocation_strategy, InvocationStrategy::PerWorkspace)
++            || config.run_build_script_command.is_none()
++        {
++            return workspaces.iter().map(|it| it.run_build_scripts(config, progress)).collect();
++        }
++
++        let cargo_ws: Vec<_> = workspaces
++            .iter()
++            .filter_map(|it| match it {
++                ProjectWorkspace::Cargo { cargo, .. } => Some(cargo),
++                _ => None,
++            })
++            .collect();
++        let ref mut outputs = match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress) {
++            Ok(it) => Ok(it.into_iter()),
++            // io::Error is not Clone?
++            Err(e) => Err(Arc::new(e)),
++        };
++
++        workspaces
++            .iter()
++            .map(|it| match it {
++                ProjectWorkspace::Cargo { cargo, .. } => match outputs {
++                    Ok(outputs) => Ok(outputs.next().unwrap()),
++                    Err(e) => Err(e.clone()).with_context(|| {
++                        format!(
++                            "Failed to run build scripts for {}",
++                            &cargo.workspace_root().display()
++                        )
++                    }),
++                },
++                _ => Ok(WorkspaceBuildScripts::default()),
++            })
++            .collect()
++    }
++
 +    pub fn set_build_scripts(&mut self, bs: WorkspaceBuildScripts) {
 +        match self {
 +            ProjectWorkspace::Cargo { build_scripts, .. } => *build_scripts = bs,
 +            _ => {
 +                always!(bs == WorkspaceBuildScripts::default());
 +            }
 +        }
 +    }
 +
 +    /// Returns the roots for the current `ProjectWorkspace`
 +    /// The return type contains the path and whether or not
 +    /// the root is a member of the current workspace
 +    pub fn to_roots(&self) -> Vec<PackageRoot> {
 +        let mk_sysroot = |sysroot: Option<&Sysroot>| {
 +            sysroot.map(|sysroot| PackageRoot {
 +                is_local: false,
 +                include: vec![sysroot.src_root().to_path_buf()],
 +                exclude: Vec::new(),
 +            })
 +        };
 +        match self {
 +            ProjectWorkspace::Json { project, sysroot, rustc_cfg: _ } => project
 +                .crates()
 +                .map(|(_, krate)| PackageRoot {
 +                    is_local: krate.is_workspace_member,
 +                    include: krate.include.clone(),
 +                    exclude: krate.exclude.clone(),
 +                })
 +                .collect::<FxHashSet<_>>()
 +                .into_iter()
 +                .chain(mk_sysroot(sysroot.as_ref()))
 +                .collect::<Vec<_>>(),
 +            ProjectWorkspace::Cargo {
 +                cargo,
 +                sysroot,
 +                rustc,
 +                rustc_cfg: _,
 +                cfg_overrides: _,
 +                build_scripts,
 +                toolchain: _,
 +            } => {
 +                cargo
 +                    .packages()
 +                    .map(|pkg| {
 +                        let is_local = cargo[pkg].is_local;
 +                        let pkg_root = cargo[pkg].manifest.parent().to_path_buf();
 +
 +                        let mut include = vec![pkg_root.clone()];
 +                        let out_dir =
 +                            build_scripts.get_output(pkg).and_then(|it| it.out_dir.clone());
 +                        include.extend(out_dir);
 +
 +                        // In case target's path is manually set in Cargo.toml to be
 +                        // outside the package root, add its parent as an extra include.
 +                        // An example of this situation would look like this:
 +                        //
 +                        // ```toml
 +                        // [lib]
 +                        // path = "../../src/lib.rs"
 +                        // ```
 +                        let extra_targets = cargo[pkg]
 +                            .targets
 +                            .iter()
 +                            .filter(|&&tgt| cargo[tgt].kind == TargetKind::Lib)
 +                            .filter_map(|&tgt| cargo[tgt].root.parent())
 +                            .map(|tgt| tgt.normalize().to_path_buf())
 +                            .filter(|path| !path.starts_with(&pkg_root));
 +                        include.extend(extra_targets);
 +
 +                        let mut exclude = vec![pkg_root.join(".git")];
 +                        if is_local {
 +                            exclude.push(pkg_root.join("target"));
 +                        } else {
 +                            exclude.push(pkg_root.join("tests"));
 +                            exclude.push(pkg_root.join("examples"));
 +                            exclude.push(pkg_root.join("benches"));
 +                        }
 +                        PackageRoot { is_local, include, exclude }
 +                    })
 +                    .chain(mk_sysroot(sysroot.as_ref()))
 +                    .chain(rustc.iter().flat_map(|rustc| {
 +                        rustc.packages().map(move |krate| PackageRoot {
 +                            is_local: false,
 +                            include: vec![rustc[krate].manifest.parent().to_path_buf()],
 +                            exclude: Vec::new(),
 +                        })
 +                    }))
 +                    .collect()
 +            }
 +            ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files
 +                .iter()
 +                .map(|detached_file| PackageRoot {
 +                    is_local: true,
 +                    include: vec![detached_file.clone()],
 +                    exclude: Vec::new(),
 +                })
 +                .chain(mk_sysroot(Some(sysroot)))
 +                .collect(),
 +        }
 +    }
 +
 +    pub fn n_packages(&self) -> usize {
 +        match self {
 +            ProjectWorkspace::Json { project, .. } => project.n_crates(),
 +            ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => {
 +                let rustc_package_len = rustc.as_ref().map_or(0, |it| it.packages().len());
 +                let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len());
 +                cargo.packages().len() + sysroot_package_len + rustc_package_len
 +            }
 +            ProjectWorkspace::DetachedFiles { sysroot, files, .. } => {
 +                sysroot.crates().len() + files.len()
 +            }
 +        }
 +    }
 +
 +    pub fn to_crate_graph(
 +        &self,
 +        load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
 +        load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
 +        extra_env: &FxHashMap<String, String>,
 +    ) -> CrateGraph {
 +        let _p = profile::span("ProjectWorkspace::to_crate_graph");
 +
 +        let mut crate_graph = match self {
 +            ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph(
 +                rustc_cfg.clone(),
 +                load_proc_macro,
 +                load,
 +                project,
 +                sysroot,
 +                extra_env,
 +            ),
 +            ProjectWorkspace::Cargo {
 +                cargo,
 +                sysroot,
 +                rustc,
 +                rustc_cfg,
 +                cfg_overrides,
 +                build_scripts,
 +                toolchain: _,
 +            } => cargo_to_crate_graph(
 +                rustc_cfg.clone(),
 +                cfg_overrides,
 +                load_proc_macro,
 +                load,
 +                cargo,
 +                build_scripts,
 +                sysroot.as_ref(),
 +                rustc,
 +            ),
 +            ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => {
 +                detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot)
 +            }
 +        };
 +        if crate_graph.patch_cfg_if() {
 +            tracing::debug!("Patched std to depend on cfg-if")
 +        } else {
 +            tracing::debug!("Did not patch std to depend on cfg-if")
 +        }
 +        crate_graph
 +    }
 +}
 +
 +fn project_json_to_crate_graph(
 +    rustc_cfg: Vec<CfgFlag>,
 +    load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
 +    load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
 +    project: &ProjectJson,
 +    sysroot: &Option<Sysroot>,
 +    extra_env: &FxHashMap<String, String>,
 +) -> CrateGraph {
 +    let mut crate_graph = CrateGraph::default();
 +    let sysroot_deps = sysroot
 +        .as_ref()
 +        .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load));
 +
 +    let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default();
 +    let crates: NoHashHashMap<CrateId, CrateId> = project
 +        .crates()
 +        .filter_map(|(crate_id, krate)| {
 +            let file_path = &krate.root_module;
 +            let file_id = load(file_path)?;
 +            Some((crate_id, krate, file_id))
 +        })
 +        .map(|(crate_id, krate, file_id)| {
 +            let env = krate.env.clone().into_iter().collect();
 +            let proc_macro = match krate.proc_macro_dylib_path.clone() {
 +                Some(it) => load_proc_macro(
 +                    krate.display_name.as_ref().map(|it| it.canonical_name()).unwrap_or(""),
 +                    &it,
 +                ),
 +                None => Err("no proc macro dylib present".into()),
 +            };
 +
 +            let target_cfgs = match krate.target.as_deref() {
 +                Some(target) => cfg_cache
 +                    .entry(target)
 +                    .or_insert_with(|| rustc_cfg::get(None, Some(target), extra_env)),
 +                None => &rustc_cfg,
 +            };
 +
 +            let mut cfg_options = CfgOptions::default();
 +            cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned());
 +            (
 +                crate_id,
 +                crate_graph.add_crate_root(
 +                    file_id,
 +                    krate.edition,
 +                    krate.display_name.clone(),
 +                    krate.version.clone(),
 +                    cfg_options.clone(),
 +                    cfg_options,
 +                    env,
 +                    proc_macro,
 +                    krate.is_proc_macro,
 +                    if krate.display_name.is_some() {
 +                        CrateOrigin::CratesIo {
 +                            repo: krate.repository.clone(),
 +                            name: krate
 +                                .display_name
 +                                .clone()
 +                                .map(|n| n.canonical_name().to_string()),
 +                        }
 +                    } else {
 +                        CrateOrigin::CratesIo { repo: None, name: None }
 +                    },
 +                ),
 +            )
 +        })
 +        .collect();
 +
 +    for (from, krate) in project.crates() {
 +        if let Some(&from) = crates.get(&from) {
 +            if let Some((public_deps, libproc_macro)) = &sysroot_deps {
 +                public_deps.add(from, &mut crate_graph);
 +                if krate.is_proc_macro {
 +                    if let Some(proc_macro) = libproc_macro {
 +                        add_dep(
 +                            &mut crate_graph,
 +                            from,
 +                            CrateName::new("proc_macro").unwrap(),
 +                            *proc_macro,
 +                        );
 +                    }
 +                }
 +            }
 +
 +            for dep in &krate.deps {
 +                if let Some(&to) = crates.get(&dep.crate_id) {
 +                    add_dep(&mut crate_graph, from, dep.name.clone(), to)
 +                }
 +            }
 +        }
 +    }
 +    crate_graph
 +}
 +
 +fn cargo_to_crate_graph(
 +    rustc_cfg: Vec<CfgFlag>,
 +    override_cfg: &CfgOverrides,
 +    load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
 +    load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
 +    cargo: &CargoWorkspace,
 +    build_scripts: &WorkspaceBuildScripts,
 +    sysroot: Option<&Sysroot>,
 +    rustc: &Option<CargoWorkspace>,
 +) -> CrateGraph {
 +    let _p = profile::span("cargo_to_crate_graph");
 +    let mut crate_graph = CrateGraph::default();
 +    let (public_deps, libproc_macro) = match sysroot {
 +        Some(sysroot) => sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load),
 +        None => (SysrootPublicDeps::default(), None),
 +    };
 +
 +    let mut cfg_options = CfgOptions::default();
 +    cfg_options.extend(rustc_cfg);
 +
 +    let mut pkg_to_lib_crate = FxHashMap::default();
 +
 +    cfg_options.insert_atom("debug_assertions".into());
 +
 +    let mut pkg_crates = FxHashMap::default();
 +    // Does any crate signal to rust-analyzer that they need the rustc_private crates?
 +    let mut has_private = false;
 +    // Next, create crates for each package, target pair
 +    for pkg in cargo.packages() {
 +        let mut cfg_options = cfg_options.clone();
 +
 +        let overrides = match override_cfg {
 +            CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff),
 +            CfgOverrides::Selective(cfg_overrides) => cfg_overrides.get(&cargo[pkg].name),
 +        };
 +
 +        // Add test cfg for local crates
 +        if cargo[pkg].is_local {
 +            cfg_options.insert_atom("test".into());
 +        }
 +
 +        if let Some(overrides) = overrides {
 +            // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
 +            // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
 +            // working on rust-lang/rust as that's the only time it appears outside sysroot).
 +            //
 +            // A more ideal solution might be to reanalyze crates based on where the cursor is and
 +            // figure out the set of cfgs that would have to apply to make it active.
 +
 +            cfg_options.apply_diff(overrides.clone());
 +        };
 +
 +        has_private |= cargo[pkg].metadata.rustc_private;
 +        let mut lib_tgt = None;
 +        for &tgt in cargo[pkg].targets.iter() {
 +            if cargo[tgt].kind != TargetKind::Lib && !cargo[pkg].is_member {
 +                // For non-workspace-members, Cargo does not resolve dev-dependencies, so we don't
 +                // add any targets except the library target, since those will not work correctly if
 +                // they use dev-dependencies.
 +                // In fact, they can break quite badly if multiple client workspaces get merged:
 +                // https://github.com/rust-lang/rust-analyzer/issues/11300
 +                continue;
 +            }
 +
 +            if let Some(file_id) = load(&cargo[tgt].root) {
 +                let crate_id = add_target_crate_root(
 +                    &mut crate_graph,
 +                    &cargo[pkg],
 +                    build_scripts.get_output(pkg),
 +                    cfg_options.clone(),
 +                    &mut |path| load_proc_macro(&cargo[tgt].name, path),
 +                    file_id,
 +                    &cargo[tgt].name,
 +                    cargo[tgt].is_proc_macro,
 +                );
 +                if cargo[tgt].kind == TargetKind::Lib {
 +                    lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
 +                    pkg_to_lib_crate.insert(pkg, crate_id);
 +                }
 +                // Even crates that don't set proc-macro = true are allowed to depend on proc_macro
 +                // (just none of the APIs work when called outside of a proc macro).
 +                if let Some(proc_macro) = libproc_macro {
 +                    add_dep_with_prelude(
 +                        &mut crate_graph,
 +                        crate_id,
 +                        CrateName::new("proc_macro").unwrap(),
 +                        proc_macro,
 +                        cargo[tgt].is_proc_macro,
 +                    );
 +                }
 +
 +                pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, cargo[tgt].kind));
 +            }
 +        }
 +
 +        // Set deps to the core, std and to the lib target of the current package
 +        for &(from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
 +            // Add sysroot deps first so that a lib target named `core` etc. can overwrite them.
 +            public_deps.add(from, &mut crate_graph);
 +
 +            if let Some((to, name)) = lib_tgt.clone() {
 +                if to != from && kind != TargetKind::BuildScript {
 +                    // (build script can not depend on its library target)
 +
 +                    // For root projects with dashes in their name,
 +                    // cargo metadata does not do any normalization,
 +                    // so we do it ourselves currently
 +                    let name = CrateName::normalize_dashes(&name);
 +                    add_dep(&mut crate_graph, from, name, to);
 +                }
 +            }
 +        }
 +    }
 +
 +    // Now add a dep edge from all targets of upstream to the lib
 +    // target of downstream.
 +    for pkg in cargo.packages() {
 +        for dep in cargo[pkg].dependencies.iter() {
 +            let name = CrateName::new(&dep.name).unwrap();
 +            if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
 +                for &(from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
 +                    if dep.kind == DepKind::Build && kind != TargetKind::BuildScript {
 +                        // Only build scripts may depend on build dependencies.
 +                        continue;
 +                    }
 +                    if dep.kind != DepKind::Build && kind == TargetKind::BuildScript {
 +                        // Build scripts may only depend on build dependencies.
 +                        continue;
 +                    }
 +
 +                    add_dep(&mut crate_graph, from, name.clone(), to)
 +                }
 +            }
 +        }
 +    }
 +
 +    if has_private {
 +        // If the user provided a path to rustc sources, we add all the rustc_private crates
 +        // and create dependencies on them for the crates which opt-in to that
 +        if let Some(rustc_workspace) = rustc {
 +            handle_rustc_crates(
 +                &mut crate_graph,
 +                rustc_workspace,
 +                load,
 +                &cfg_options,
 +                override_cfg,
 +                load_proc_macro,
 +                &mut pkg_to_lib_crate,
 +                &public_deps,
 +                cargo,
 +                &pkg_crates,
 +                build_scripts,
 +            );
 +        }
 +    }
 +    crate_graph
 +}
 +
 +fn detached_files_to_crate_graph(
 +    rustc_cfg: Vec<CfgFlag>,
 +    load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
 +    detached_files: &[AbsPathBuf],
 +    sysroot: &Sysroot,
 +) -> CrateGraph {
 +    let _p = profile::span("detached_files_to_crate_graph");
 +    let mut crate_graph = CrateGraph::default();
 +    let (public_deps, _libproc_macro) =
 +        sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load);
 +
 +    let mut cfg_options = CfgOptions::default();
 +    cfg_options.extend(rustc_cfg);
 +
 +    for detached_file in detached_files {
 +        let file_id = match load(detached_file) {
 +            Some(file_id) => file_id,
 +            None => {
 +                tracing::error!("Failed to load detached file {:?}", detached_file);
 +                continue;
 +            }
 +        };
 +        let display_name = detached_file
 +            .file_stem()
 +            .and_then(|os_str| os_str.to_str())
 +            .map(|file_stem| CrateDisplayName::from_canonical_name(file_stem.to_string()));
 +        let detached_file_crate = crate_graph.add_crate_root(
 +            file_id,
 +            Edition::CURRENT,
 +            display_name.clone(),
 +            None,
 +            cfg_options.clone(),
 +            cfg_options.clone(),
 +            Env::default(),
 +            Ok(Vec::new()),
 +            false,
 +            CrateOrigin::CratesIo {
 +                repo: None,
 +                name: display_name.map(|n| n.canonical_name().to_string()),
 +            },
 +        );
 +
 +        public_deps.add(detached_file_crate, &mut crate_graph);
 +    }
 +    crate_graph
 +}
 +
 +fn handle_rustc_crates(
 +    crate_graph: &mut CrateGraph,
 +    rustc_workspace: &CargoWorkspace,
 +    load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
 +    cfg_options: &CfgOptions,
 +    override_cfg: &CfgOverrides,
 +    load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
 +    pkg_to_lib_crate: &mut FxHashMap<Package, CrateId>,
 +    public_deps: &SysrootPublicDeps,
 +    cargo: &CargoWorkspace,
 +    pkg_crates: &FxHashMap<Package, Vec<(CrateId, TargetKind)>>,
 +    build_scripts: &WorkspaceBuildScripts,
 +) {
 +    let mut rustc_pkg_crates = FxHashMap::default();
 +    // The root package of the rustc-dev component is rustc_driver, so we match that
 +    let root_pkg =
 +        rustc_workspace.packages().find(|package| rustc_workspace[*package].name == "rustc_driver");
 +    // The rustc workspace might be incomplete (such as if rustc-dev is not
 +    // installed for the current toolchain) and `rustc_source` is set to discover.
 +    if let Some(root_pkg) = root_pkg {
 +        // Iterate through every crate in the dependency subtree of rustc_driver using BFS
 +        let mut queue = VecDeque::new();
 +        queue.push_back(root_pkg);
 +        while let Some(pkg) = queue.pop_front() {
 +            // Don't duplicate packages if they are dependent on a diamond pattern
 +            // N.B. if this line is omitted, we try to analyze over 4_800_000 crates
 +            // which is not ideal
 +            if rustc_pkg_crates.contains_key(&pkg) {
 +                continue;
 +            }
 +            for dep in &rustc_workspace[pkg].dependencies {
 +                queue.push_back(dep.pkg);
 +            }
 +
 +            let mut cfg_options = cfg_options.clone();
 +
 +            let overrides = match override_cfg {
 +                CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff),
 +                CfgOverrides::Selective(cfg_overrides) => {
 +                    cfg_overrides.get(&rustc_workspace[pkg].name)
 +                }
 +            };
 +
 +            if let Some(overrides) = overrides {
 +                // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
 +                // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
 +                // working on rust-lang/rust as that's the only time it appears outside sysroot).
 +                //
 +                // A more ideal solution might be to reanalyze crates based on where the cursor is and
 +                // figure out the set of cfgs that would have to apply to make it active.
 +
 +                cfg_options.apply_diff(overrides.clone());
 +            };
 +
 +            for &tgt in rustc_workspace[pkg].targets.iter() {
 +                if rustc_workspace[tgt].kind != TargetKind::Lib {
 +                    continue;
 +                }
 +                if let Some(file_id) = load(&rustc_workspace[tgt].root) {
 +                    let crate_id = add_target_crate_root(
 +                        crate_graph,
 +                        &rustc_workspace[pkg],
 +                        build_scripts.get_output(pkg),
 +                        cfg_options.clone(),
 +                        &mut |path| load_proc_macro(&rustc_workspace[tgt].name, path),
 +                        file_id,
 +                        &rustc_workspace[tgt].name,
 +                        rustc_workspace[tgt].is_proc_macro,
 +                    );
 +                    pkg_to_lib_crate.insert(pkg, crate_id);
 +                    // Add dependencies on core / std / alloc for this crate
 +                    public_deps.add(crate_id, crate_graph);
 +                    rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
 +                }
 +            }
 +        }
 +    }
 +    // Now add a dep edge from all targets of upstream to the lib
 +    // target of downstream.
 +    for pkg in rustc_pkg_crates.keys().copied() {
 +        for dep in rustc_workspace[pkg].dependencies.iter() {
 +            let name = CrateName::new(&dep.name).unwrap();
 +            if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
 +                for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() {
 +                    add_dep(crate_graph, from, name.clone(), to);
 +                }
 +            }
 +        }
 +    }
 +    // Add a dependency on the rustc_private crates for all targets of each package
 +    // which opts in
 +    for dep in rustc_workspace.packages() {
 +        let name = CrateName::normalize_dashes(&rustc_workspace[dep].name);
 +
 +        if let Some(&to) = pkg_to_lib_crate.get(&dep) {
 +            for pkg in cargo.packages() {
 +                let package = &cargo[pkg];
 +                if !package.metadata.rustc_private {
 +                    continue;
 +                }
 +                for (from, _) in pkg_crates.get(&pkg).into_iter().flatten() {
 +                    // Avoid creating duplicate dependencies
 +                    // This avoids the situation where `from` depends on e.g. `arrayvec`, but
 +                    // `rust_analyzer` thinks that it should use the one from the `rustc_source`
 +                    // instead of the one from `crates.io`
 +                    if !crate_graph[*from].dependencies.iter().any(|d| d.name == name) {
 +                        add_dep(crate_graph, *from, name.clone(), to);
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn add_target_crate_root(
 +    crate_graph: &mut CrateGraph,
 +    pkg: &PackageData,
 +    build_data: Option<&BuildScriptOutput>,
 +    cfg_options: CfgOptions,
 +    load_proc_macro: &mut dyn FnMut(&AbsPath) -> ProcMacroLoadResult,
 +    file_id: FileId,
 +    cargo_name: &str,
 +    is_proc_macro: bool,
 +) -> CrateId {
 +    let edition = pkg.edition;
 +    let mut potential_cfg_options = cfg_options.clone();
 +    potential_cfg_options.extend(
 +        pkg.features
 +            .iter()
 +            .map(|feat| CfgFlag::KeyValue { key: "feature".into(), value: feat.0.into() }),
 +    );
 +    let cfg_options = {
 +        let mut opts = cfg_options;
 +        for feature in pkg.active_features.iter() {
 +            opts.insert_key_value("feature".into(), feature.into());
 +        }
 +        if let Some(cfgs) = build_data.as_ref().map(|it| &it.cfgs) {
 +            opts.extend(cfgs.iter().cloned());
 +        }
 +        opts
 +    };
 +
 +    let mut env = Env::default();
 +    inject_cargo_env(pkg, &mut env);
 +
 +    if let Some(envs) = build_data.map(|it| &it.envs) {
 +        for (k, v) in envs {
 +            env.set(k, v.clone());
 +        }
 +    }
 +
 +    let proc_macro = match build_data.as_ref().map(|it| it.proc_macro_dylib_path.as_ref()) {
 +        Some(Some(it)) => load_proc_macro(it),
 +        Some(None) => Err("no proc macro dylib present".into()),
 +        None => Err("crate has not (yet) been built".into()),
 +    };
 +
 +    let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string());
 +    crate_graph.add_crate_root(
 +        file_id,
 +        edition,
 +        Some(display_name),
 +        Some(pkg.version.to_string()),
 +        cfg_options,
 +        potential_cfg_options,
 +        env,
 +        proc_macro,
 +        is_proc_macro,
 +        CrateOrigin::CratesIo { repo: pkg.repository.clone(), name: Some(pkg.name.clone()) },
 +    )
 +}
 +
 +#[derive(Default)]
 +struct SysrootPublicDeps {
 +    deps: Vec<(CrateName, CrateId, bool)>,
 +}
 +
 +impl SysrootPublicDeps {
 +    /// Makes `from` depend on the public sysroot crates.
 +    fn add(&self, from: CrateId, crate_graph: &mut CrateGraph) {
 +        for (name, krate, prelude) in &self.deps {
 +            add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude);
 +        }
 +    }
 +}
 +
 +fn sysroot_to_crate_graph(
 +    crate_graph: &mut CrateGraph,
 +    sysroot: &Sysroot,
 +    rustc_cfg: Vec<CfgFlag>,
 +    load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
 +) -> (SysrootPublicDeps, Option<CrateId>) {
 +    let _p = profile::span("sysroot_to_crate_graph");
 +    let mut cfg_options = CfgOptions::default();
 +    cfg_options.extend(rustc_cfg);
 +    let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot
 +        .crates()
 +        .filter_map(|krate| {
 +            let file_id = load(&sysroot[krate].root)?;
 +
 +            let env = Env::default();
 +            let display_name = CrateDisplayName::from_canonical_name(sysroot[krate].name.clone());
 +            let crate_id = crate_graph.add_crate_root(
 +                file_id,
 +                Edition::CURRENT,
 +                Some(display_name),
 +                None,
 +                cfg_options.clone(),
 +                cfg_options.clone(),
 +                env,
 +                Err("no proc macro loaded for sysroot crate".into()),
 +                false,
 +                CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)),
 +            );
 +            Some((krate, crate_id))
 +        })
 +        .collect();
 +
 +    for from in sysroot.crates() {
 +        for &to in sysroot[from].deps.iter() {
 +            let name = CrateName::new(&sysroot[to].name).unwrap();
 +            if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) {
 +                add_dep(crate_graph, from, name, to);
 +            }
 +        }
 +    }
 +
 +    let public_deps = SysrootPublicDeps {
 +        deps: sysroot
 +            .public_deps()
 +            .map(|(name, idx, prelude)| {
 +                (CrateName::new(name).unwrap(), sysroot_crates[&idx], prelude)
 +            })
 +            .collect::<Vec<_>>(),
 +    };
 +
 +    let libproc_macro = sysroot.proc_macro().and_then(|it| sysroot_crates.get(&it).copied());
 +    (public_deps, libproc_macro)
 +}
 +
 +fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
 +    add_dep_inner(graph, from, Dependency::new(name, to))
 +}
 +
 +fn add_dep_with_prelude(
 +    graph: &mut CrateGraph,
 +    from: CrateId,
 +    name: CrateName,
 +    to: CrateId,
 +    prelude: bool,
 +) {
 +    add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude))
 +}
 +
 +fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) {
 +    if let Err(err) = graph.add_dep(from, dep) {
 +        tracing::error!("{}", err)
 +    }
 +}
 +
 +/// Recreates the compile-time environment variables that Cargo sets.
 +///
 +/// Should be synced with
 +/// <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates>
 +///
 +/// FIXME: ask Cargo to provide this data instead of re-deriving.
 +fn inject_cargo_env(package: &PackageData, env: &mut Env) {
 +    // FIXME: Missing variables:
 +    // CARGO_BIN_NAME, CARGO_BIN_EXE_<name>
 +
 +    let manifest_dir = package.manifest.parent();
 +    env.set("CARGO_MANIFEST_DIR", manifest_dir.as_os_str().to_string_lossy().into_owned());
 +
 +    // Not always right, but works for common cases.
 +    env.set("CARGO", "cargo".into());
 +
 +    env.set("CARGO_PKG_VERSION", package.version.to_string());
 +    env.set("CARGO_PKG_VERSION_MAJOR", package.version.major.to_string());
 +    env.set("CARGO_PKG_VERSION_MINOR", package.version.minor.to_string());
 +    env.set("CARGO_PKG_VERSION_PATCH", package.version.patch.to_string());
 +    env.set("CARGO_PKG_VERSION_PRE", package.version.pre.to_string());
 +
 +    env.set("CARGO_PKG_AUTHORS", String::new());
 +
 +    env.set("CARGO_PKG_NAME", package.name.clone());
 +    // FIXME: This isn't really correct (a package can have many crates with different names), but
 +    // it's better than leaving the variable unset.
 +    env.set("CARGO_CRATE_NAME", CrateName::normalize_dashes(&package.name).to_string());
 +    env.set("CARGO_PKG_DESCRIPTION", String::new());
 +    env.set("CARGO_PKG_HOMEPAGE", String::new());
 +    env.set("CARGO_PKG_REPOSITORY", String::new());
 +    env.set("CARGO_PKG_LICENSE", String::new());
 +
 +    env.set("CARGO_PKG_LICENSE_FILE", String::new());
 +}
index e1675a030c0f6f19f36b5d4bf12e975db471ba9d,0000000000000000000000000000000000000000..6ede194babc2067529fdec2f810fbee62cc1c06d
mode 100644,000000..100644
--- /dev/null
@@@ -1,234 -1,0 +1,234 @@@
-         let crate_id = match &*global_state_snapshot.analysis.crate_for(file_id)? {
 +//! See `CargoTargetSpec`
 +
 +use std::mem;
 +
 +use cfg::{CfgAtom, CfgExpr};
 +use ide::{FileId, RunnableKind, TestId};
 +use project_model::{self, CargoFeatures, ManifestPath, TargetKind};
 +use vfs::AbsPathBuf;
 +
 +use crate::{global_state::GlobalStateSnapshot, Result};
 +
 +/// Abstract representation of Cargo target.
 +///
 +/// We use it to cook up the set of cli args we need to pass to Cargo to
 +/// build/test/run the target.
 +#[derive(Clone)]
 +pub(crate) struct CargoTargetSpec {
 +    pub(crate) workspace_root: AbsPathBuf,
 +    pub(crate) cargo_toml: ManifestPath,
 +    pub(crate) package: String,
 +    pub(crate) target: String,
 +    pub(crate) target_kind: TargetKind,
 +    pub(crate) required_features: Vec<String>,
 +}
 +
 +impl CargoTargetSpec {
 +    pub(crate) fn runnable_args(
 +        snap: &GlobalStateSnapshot,
 +        spec: Option<CargoTargetSpec>,
 +        kind: &RunnableKind,
 +        cfg: &Option<CfgExpr>,
 +    ) -> Result<(Vec<String>, Vec<String>)> {
 +        let mut args = Vec::new();
 +        let mut extra_args = Vec::new();
 +
 +        match kind {
 +            RunnableKind::Test { test_id, attr } => {
 +                args.push("test".to_owned());
 +                extra_args.push(test_id.to_string());
 +                if let TestId::Path(_) = test_id {
 +                    extra_args.push("--exact".to_owned());
 +                }
 +                extra_args.push("--nocapture".to_owned());
 +                if attr.ignore {
 +                    extra_args.push("--ignored".to_owned());
 +                }
 +            }
 +            RunnableKind::TestMod { path } => {
 +                args.push("test".to_owned());
 +                extra_args.push(path.clone());
 +                extra_args.push("--nocapture".to_owned());
 +            }
 +            RunnableKind::Bench { test_id } => {
 +                args.push("bench".to_owned());
 +                extra_args.push(test_id.to_string());
 +                if let TestId::Path(_) = test_id {
 +                    extra_args.push("--exact".to_owned());
 +                }
 +                extra_args.push("--nocapture".to_owned());
 +            }
 +            RunnableKind::DocTest { test_id } => {
 +                args.push("test".to_owned());
 +                args.push("--doc".to_owned());
 +                extra_args.push(test_id.to_string());
 +                extra_args.push("--nocapture".to_owned());
 +            }
 +            RunnableKind::Bin => {
 +                let subcommand = match spec {
 +                    Some(CargoTargetSpec { target_kind: TargetKind::Test, .. }) => "test",
 +                    _ => "run",
 +                };
 +                args.push(subcommand.to_owned());
 +            }
 +        }
 +
 +        let target_required_features = if let Some(mut spec) = spec {
 +            let required_features = mem::take(&mut spec.required_features);
 +            spec.push_to(&mut args, kind);
 +            required_features
 +        } else {
 +            Vec::new()
 +        };
 +
 +        let cargo_config = snap.config.cargo();
 +
 +        match &cargo_config.features {
 +            CargoFeatures::All => {
 +                args.push("--all-features".to_owned());
 +                for feature in target_required_features {
 +                    args.push("--features".to_owned());
 +                    args.push(feature);
 +                }
 +            }
 +            CargoFeatures::Selected { features, no_default_features } => {
 +                let mut feats = Vec::new();
 +                if let Some(cfg) = cfg.as_ref() {
 +                    required_features(cfg, &mut feats);
 +                }
 +
 +                feats.extend(features.iter().cloned());
 +                feats.extend(target_required_features);
 +
 +                feats.dedup();
 +                for feature in feats {
 +                    args.push("--features".to_owned());
 +                    args.push(feature);
 +                }
 +
 +                if *no_default_features {
 +                    args.push("--no-default-features".to_owned());
 +                }
 +            }
 +        }
 +        Ok((args, extra_args))
 +    }
 +
 +    pub(crate) fn for_file(
 +        global_state_snapshot: &GlobalStateSnapshot,
 +        file_id: FileId,
 +    ) -> Result<Option<CargoTargetSpec>> {
++        let crate_id = match &*global_state_snapshot.analysis.crates_for(file_id)? {
 +            &[crate_id, ..] => crate_id,
 +            _ => return Ok(None),
 +        };
 +        let (cargo_ws, target) = match global_state_snapshot.cargo_target_for_crate_root(crate_id) {
 +            Some(it) => it,
 +            None => return Ok(None),
 +        };
 +
 +        let target_data = &cargo_ws[target];
 +        let package_data = &cargo_ws[target_data.package];
 +        let res = CargoTargetSpec {
 +            workspace_root: cargo_ws.workspace_root().to_path_buf(),
 +            cargo_toml: package_data.manifest.clone(),
 +            package: cargo_ws.package_flag(package_data),
 +            target: target_data.name.clone(),
 +            target_kind: target_data.kind,
 +            required_features: target_data.required_features.clone(),
 +        };
 +
 +        Ok(Some(res))
 +    }
 +
 +    pub(crate) fn push_to(self, buf: &mut Vec<String>, kind: &RunnableKind) {
 +        buf.push("--package".to_owned());
 +        buf.push(self.package);
 +
 +        // Can't mix --doc with other target flags
 +        if let RunnableKind::DocTest { .. } = kind {
 +            return;
 +        }
 +        match self.target_kind {
 +            TargetKind::Bin => {
 +                buf.push("--bin".to_owned());
 +                buf.push(self.target);
 +            }
 +            TargetKind::Test => {
 +                buf.push("--test".to_owned());
 +                buf.push(self.target);
 +            }
 +            TargetKind::Bench => {
 +                buf.push("--bench".to_owned());
 +                buf.push(self.target);
 +            }
 +            TargetKind::Example => {
 +                buf.push("--example".to_owned());
 +                buf.push(self.target);
 +            }
 +            TargetKind::Lib => {
 +                buf.push("--lib".to_owned());
 +            }
 +            TargetKind::Other | TargetKind::BuildScript => (),
 +        }
 +    }
 +}
 +
 +/// Fill minimal features needed
 +fn required_features(cfg_expr: &CfgExpr, features: &mut Vec<String>) {
 +    match cfg_expr {
 +        CfgExpr::Atom(CfgAtom::KeyValue { key, value }) if key == "feature" => {
 +            features.push(value.to_string())
 +        }
 +        CfgExpr::All(preds) => {
 +            preds.iter().for_each(|cfg| required_features(cfg, features));
 +        }
 +        CfgExpr::Any(preds) => {
 +            for cfg in preds {
 +                let len_features = features.len();
 +                required_features(cfg, features);
 +                if len_features != features.len() {
 +                    break;
 +                }
 +            }
 +        }
 +        _ => {}
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use super::*;
 +
 +    use cfg::CfgExpr;
 +    use mbe::syntax_node_to_token_tree;
 +    use syntax::{
 +        ast::{self, AstNode},
 +        SmolStr,
 +    };
 +
 +    fn check(cfg: &str, expected_features: &[&str]) {
 +        let cfg_expr = {
 +            let source_file = ast::SourceFile::parse(cfg).ok().unwrap();
 +            let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
 +            let (tt, _) = syntax_node_to_token_tree(tt.syntax());
 +            CfgExpr::parse(&tt)
 +        };
 +
 +        let mut features = vec![];
 +        required_features(&cfg_expr, &mut features);
 +
 +        let expected_features =
 +            expected_features.iter().map(|&it| SmolStr::new(it)).collect::<Vec<_>>();
 +
 +        assert_eq!(features, expected_features);
 +    }
 +
 +    #[test]
 +    fn test_cfg_expr_minimal_features_needed() {
 +        check(r#"#![cfg(feature = "baz")]"#, &["baz"]);
 +        check(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#, &["baz", "foo"]);
 +        check(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#, &["baz"]);
 +        check(r#"#![cfg(foo)]"#, &[]);
 +    }
 +}
index 2c29b3ee3a6f7d82e76892855c48ef70b56a5206,0000000000000000000000000000000000000000..8b77ccde0ee4aaf94a4a9cfb0da3830fd44e951e
mode 100644,000000..100644
--- /dev/null
@@@ -1,449 -1,0 +1,418 @@@
-     LineCol, MonikerDescriptorKind, MonikerResult, StaticIndex, StaticIndexedFile, TextRange,
-     TokenId,
 +//! SCIP generator
 +
 +use std::{
 +    collections::{HashMap, HashSet},
 +    time::Instant,
 +};
 +
 +use crate::line_index::{LineEndings, LineIndex, OffsetEncoding};
 +use hir::Name;
 +use ide::{
-         for file in si.files {
++    LineCol, MonikerDescriptorKind, StaticIndex, StaticIndexedFile, TextRange, TokenId,
++    TokenStaticData,
 +};
 +use ide_db::LineIndexDatabase;
 +use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace};
 +use scip::types as scip_types;
 +use std::env;
 +
 +use crate::cli::{
 +    flags,
 +    load_cargo::{load_workspace, LoadCargoConfig},
 +    Result,
 +};
 +
 +impl flags::Scip {
 +    pub fn run(self) -> Result<()> {
 +        eprintln!("Generating SCIP start...");
 +        let now = Instant::now();
 +        let cargo_config = CargoConfig::default();
 +
 +        let no_progress = &|s| (eprintln!("rust-analyzer: Loading {}", s));
 +        let load_cargo_config = LoadCargoConfig {
 +            load_out_dirs_from_check: true,
 +            with_proc_macro: true,
 +            prefill_caches: true,
 +        };
 +        let path = vfs::AbsPathBuf::assert(env::current_dir()?.join(&self.path));
 +        let rootpath = path.normalize();
 +        let manifest = ProjectManifest::discover_single(&path)?;
 +
 +        let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?;
 +
 +        let (host, vfs, _) =
 +            load_workspace(workspace, &cargo_config.extra_env, &load_cargo_config)?;
 +        let db = host.raw_database();
 +        let analysis = host.analysis();
 +
 +        let si = StaticIndex::compute(&analysis);
 +
 +        let mut index = scip_types::Index {
 +            metadata: Some(scip_types::Metadata {
 +                version: scip_types::ProtocolVersion::UnspecifiedProtocolVersion.into(),
 +                tool_info: Some(scip_types::ToolInfo {
 +                    name: "rust-analyzer".to_owned(),
 +                    version: "0.1".to_owned(),
 +                    arguments: vec![],
 +                    ..Default::default()
 +                })
 +                .into(),
 +                project_root: format!(
 +                    "file://{}",
 +                    path.normalize()
 +                        .as_os_str()
 +                        .to_str()
 +                        .ok_or(anyhow::anyhow!("Unable to normalize project_root path"))?
 +                        .to_string()
 +                ),
 +                text_document_encoding: scip_types::TextEncoding::UTF8.into(),
 +                ..Default::default()
 +            })
 +            .into(),
 +            ..Default::default()
 +        };
 +
 +        let mut symbols_emitted: HashSet<TokenId> = HashSet::default();
 +        let mut tokens_to_symbol: HashMap<TokenId, String> = HashMap::new();
 +
-             let StaticIndexedFile { file_id, tokens, .. } = file;
++        for StaticIndexedFile { file_id, tokens, .. } in si.files {
 +            let mut local_count = 0;
 +            let mut new_local_symbol = || {
 +                let new_symbol = scip::types::Symbol::new_local(local_count);
 +                local_count += 1;
 +
 +                new_symbol
 +            };
 +
-                 occurrence.symbol = match tokens_to_symbol.get(&id) {
-                     Some(symbol) => symbol.clone(),
-                     None => {
-                         let symbol = match &token.moniker {
-                             Some(moniker) => moniker_to_symbol(&moniker),
-                             None => new_local_symbol(),
-                         };
-                         let symbol = scip::symbol::format_symbol(symbol);
-                         tokens_to_symbol.insert(id, symbol.clone());
-                         symbol
-                     }
-                 };
 +            let relative_path = match get_relative_filepath(&vfs, &rootpath, file_id) {
 +                Some(relative_path) => relative_path,
 +                None => continue,
 +            };
 +
 +            let line_index = LineIndex {
 +                index: db.line_index(file_id),
 +                encoding: OffsetEncoding::Utf8,
 +                endings: LineEndings::Unix,
 +            };
 +
 +            let mut doc = scip_types::Document {
 +                relative_path,
 +                language: "rust".to_string(),
 +                ..Default::default()
 +            };
 +
 +            tokens.into_iter().for_each(|(range, id)| {
 +                let token = si.tokens.get(id).unwrap();
 +
 +                let mut occurrence = scip_types::Occurrence::default();
 +                occurrence.range = text_range_to_scip_range(&line_index, range);
-                     if !symbols_emitted.contains(&id) {
-                         symbols_emitted.insert(id);
++                occurrence.symbol = tokens_to_symbol
++                    .entry(id)
++                    .or_insert_with(|| {
++                        let symbol = token_to_symbol(&token).unwrap_or_else(&mut new_local_symbol);
++                        scip::symbol::format_symbol(symbol)
++                    })
++                    .clone();
 +
 +                if let Some(def) = token.definition {
 +                    if def.range == range {
 +                        occurrence.symbol_roles |= scip_types::SymbolRole::Definition as i32;
 +                    }
 +
- fn moniker_to_symbol(moniker: &MonikerResult) -> scip_types::Symbol {
++                    if symbols_emitted.insert(id) {
 +                        let mut symbol_info = scip_types::SymbolInformation::default();
 +                        symbol_info.symbol = occurrence.symbol.clone();
 +                        if let Some(hover) = &token.hover {
 +                            if !hover.markup.as_str().is_empty() {
 +                                symbol_info.documentation = vec![hover.markup.as_str().to_string()];
 +                            }
 +                        }
 +
 +                        doc.symbols.push(symbol_info)
 +                    }
 +                }
 +
 +                doc.occurrences.push(occurrence);
 +            });
 +
 +            if doc.occurrences.is_empty() {
 +                continue;
 +            }
 +
 +            index.documents.push(doc);
 +        }
 +
 +        scip::write_message_to_file("index.scip", index)
 +            .map_err(|err| anyhow::anyhow!("Failed to write scip to file: {}", err))?;
 +
 +        eprintln!("Generating SCIP finished {:?}", now.elapsed());
 +        Ok(())
 +    }
 +}
 +
 +fn get_relative_filepath(
 +    vfs: &vfs::Vfs,
 +    rootpath: &vfs::AbsPathBuf,
 +    file_id: ide::FileId,
 +) -> Option<String> {
 +    Some(vfs.file_path(file_id).as_path()?.strip_prefix(&rootpath)?.as_ref().to_str()?.to_string())
 +}
 +
 +// SCIP Ranges have a (very large) optimization that ranges if they are on the same line
 +// only encode as a vector of [start_line, start_col, end_col].
 +//
 +// This transforms a line index into the optimized SCIP Range.
 +fn text_range_to_scip_range(line_index: &LineIndex, range: TextRange) -> Vec<i32> {
 +    let LineCol { line: start_line, col: start_col } = line_index.index.line_col(range.start());
 +    let LineCol { line: end_line, col: end_col } = line_index.index.line_col(range.end());
 +
 +    if start_line == end_line {
 +        vec![start_line as i32, start_col as i32, end_col as i32]
 +    } else {
 +        vec![start_line as i32, start_col as i32, end_line as i32, end_col as i32]
 +    }
 +}
 +
 +fn new_descriptor_str(
 +    name: &str,
 +    suffix: scip_types::descriptor::Suffix,
 +) -> scip_types::Descriptor {
 +    scip_types::Descriptor {
 +        name: name.to_string(),
 +        disambiguator: "".to_string(),
 +        suffix: suffix.into(),
 +        ..Default::default()
 +    }
 +}
 +
 +fn new_descriptor(name: Name, suffix: scip_types::descriptor::Suffix) -> scip_types::Descriptor {
 +    let mut name = name.to_string();
 +    if name.contains("'") {
 +        name = format!("`{}`", name);
 +    }
 +
 +    new_descriptor_str(name.as_str(), suffix)
 +}
 +
 +/// Loosely based on `def_to_moniker`
 +///
 +/// Only returns a Symbol when it's a non-local symbol.
 +///     So if the visibility isn't outside of a document, then it will return None
-     scip_types::Symbol {
++fn token_to_symbol(token: &TokenStaticData) -> Option<scip_types::Symbol> {
 +    use scip_types::descriptor::Suffix::*;
 +
++    let moniker = token.moniker.as_ref()?;
++
 +    let package_name = moniker.package_information.name.clone();
 +    let version = moniker.package_information.version.clone();
 +    let descriptors = moniker
 +        .identifier
 +        .description
 +        .iter()
 +        .map(|desc| {
 +            new_descriptor(
 +                desc.name.clone(),
 +                match desc.desc {
 +                    MonikerDescriptorKind::Namespace => Namespace,
 +                    MonikerDescriptorKind::Type => Type,
 +                    MonikerDescriptorKind::Term => Term,
 +                    MonikerDescriptorKind::Method => Method,
 +                    MonikerDescriptorKind::TypeParameter => TypeParameter,
 +                    MonikerDescriptorKind::Parameter => Parameter,
 +                    MonikerDescriptorKind::Macro => Macro,
 +                    MonikerDescriptorKind::Meta => Meta,
 +                },
 +            )
 +        })
 +        .collect();
 +
-     }
++    Some(scip_types::Symbol {
 +        scheme: "rust-analyzer".into(),
 +        package: Some(scip_types::Package {
 +            manager: "cargo".to_string(),
 +            name: package_name,
 +            version,
 +            ..Default::default()
 +        })
 +        .into(),
 +        descriptors,
 +        ..Default::default()
-     use hir::Semantics;
-     use ide::{AnalysisHost, FilePosition};
-     use ide_db::defs::IdentClass;
-     use ide_db::{base_db::fixture::ChangeFixture, helpers::pick_best_token};
++    })
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::*;
-     use syntax::SyntaxKind::*;
-     use syntax::{AstNode, T};
++    use ide::{AnalysisHost, FilePosition, StaticIndex, TextSize};
++    use ide_db::base_db::fixture::ChangeFixture;
 +    use scip::symbol::format_symbol;
-         let db = host.raw_database();
-         let sema = &Semantics::new(db);
-         let file = sema.parse(file_id).syntax().clone();
-         let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
-             IDENT
-             | INT_NUMBER
-             | LIFETIME_IDENT
-             | T![self]
-             | T![super]
-             | T![crate]
-             | T![Self]
-             | COMMENT => 2,
-             kind if kind.is_trivia() => 0,
-             _ => 1,
-         })
-         .expect("OK OK");
-         let navs = sema
-             .descend_into_macros(original_token.clone())
-             .into_iter()
-             .filter_map(|token| {
-                 IdentClass::classify_token(sema, &token).map(IdentClass::definitions).map(|it| {
-                     it.into_iter().flat_map(|def| {
-                         let module = def.module(db).unwrap();
-                         let current_crate = module.krate();
-                         match MonikerResult::from_def(sema.db, def, current_crate) {
-                             Some(moniker_result) => Some(moniker_to_symbol(&moniker_result)),
-                             None => None,
-                         }
-                     })
-                 })
-             })
-             .flatten()
-             .collect::<Vec<_>>();
 +
 +    fn position(ra_fixture: &str) -> (AnalysisHost, FilePosition) {
 +        let mut host = AnalysisHost::default();
 +        let change_fixture = ChangeFixture::parse(ra_fixture);
 +        host.raw_database_mut().apply_change(change_fixture.change);
 +        let (file_id, range_or_offset) =
 +            change_fixture.file_position.expect("expected a marker ($0)");
 +        let offset = range_or_offset.expect_offset();
 +        (host, FilePosition { file_id, offset })
 +    }
 +
 +    /// If expected == "", then assert that there are no symbols (this is basically local symbol)
 +    #[track_caller]
 +    fn check_symbol(ra_fixture: &str, expected: &str) {
 +        let (host, position) = position(ra_fixture);
 +
++        let analysis = host.analysis();
++        let si = StaticIndex::compute(&analysis);
++
 +        let FilePosition { file_id, offset } = position;
 +
-             assert_eq!(0, navs.len(), "must have no symbols {:?}", navs);
++        let mut found_symbol = None;
++        for file in &si.files {
++            if file.file_id != file_id {
++                continue;
++            }
++            for &(range, id) in &file.tokens {
++                if range.contains(offset - TextSize::from(1)) {
++                    let token = si.tokens.get(id).unwrap();
++                    found_symbol = token_to_symbol(token);
++                    break;
++                }
++            }
++        }
 +
 +        if expected == "" {
-         assert_eq!(1, navs.len(), "must have one symbol {:?}", navs);
-         let res = navs.get(0).unwrap();
-         let formatted = format_symbol(res.clone());
++            assert!(found_symbol.is_none(), "must have no symbols {:?}", found_symbol);
 +            return;
 +        }
 +
++        assert!(found_symbol.is_some(), "must have one symbol {:?}", found_symbol);
++        let res = found_symbol.unwrap();
++        let formatted = format_symbol(res);
 +        assert_eq!(formatted, expected);
 +    }
 +
 +    #[test]
 +    fn basic() {
 +        check_symbol(
 +            r#"
 +//- /lib.rs crate:main deps:foo
 +use foo::example_mod::func;
 +fn main() {
 +    func$0();
 +}
 +//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
 +pub mod example_mod {
 +    pub fn func() {}
 +}
 +"#,
 +            "rust-analyzer cargo foo 0.1.0 example_mod/func().",
 +        );
 +    }
 +
 +    #[test]
 +    fn symbol_for_trait() {
 +        check_symbol(
 +            r#"
 +//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
 +pub mod module {
 +    pub trait MyTrait {
 +        pub fn func$0() {}
 +    }
 +}
 +"#,
 +            "rust-analyzer cargo foo 0.1.0 module/MyTrait#func().",
 +        );
 +    }
 +
 +    #[test]
 +    fn symbol_for_trait_constant() {
 +        check_symbol(
 +            r#"
 +    //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
 +    pub mod module {
 +        pub trait MyTrait {
 +            const MY_CONST$0: u8;
 +        }
 +    }
 +    "#,
 +            "rust-analyzer cargo foo 0.1.0 module/MyTrait#MY_CONST.",
 +        );
 +    }
 +
 +    #[test]
 +    fn symbol_for_trait_type() {
 +        check_symbol(
 +            r#"
 +    //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
 +    pub mod module {
 +        pub trait MyTrait {
 +            type MyType$0;
 +        }
 +    }
 +    "#,
 +            // "foo::module::MyTrait::MyType",
 +            "rust-analyzer cargo foo 0.1.0 module/MyTrait#[MyType]",
 +        );
 +    }
 +
 +    #[test]
 +    fn symbol_for_trait_impl_function() {
 +        check_symbol(
 +            r#"
 +    //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
 +    pub mod module {
 +        pub trait MyTrait {
 +            pub fn func() {}
 +        }
 +
 +        struct MyStruct {}
 +
 +        impl MyTrait for MyStruct {
 +            pub fn func$0() {}
 +        }
 +    }
 +    "#,
 +            // "foo::module::MyStruct::MyTrait::func",
 +            "rust-analyzer cargo foo 0.1.0 module/MyStruct#MyTrait#func().",
 +        );
 +    }
 +
 +    #[test]
 +    fn symbol_for_field() {
 +        check_symbol(
 +            r#"
 +    //- /lib.rs crate:main deps:foo
 +    use foo::St;
 +    fn main() {
 +        let x = St { a$0: 2 };
 +    }
 +    //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
 +    pub struct St {
 +        pub a: i32,
 +    }
 +    "#,
 +            "rust-analyzer cargo foo 0.1.0 St#a.",
 +        );
 +    }
 +
 +    #[test]
 +    fn local_symbol_for_local() {
 +        check_symbol(
 +            r#"
 +    //- /lib.rs crate:main deps:foo
 +    use foo::module::func;
 +    fn main() {
 +        func();
 +    }
 +    //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
 +    pub mod module {
 +        pub fn func() {
 +            let x$0 = 2;
 +        }
 +    }
 +    "#,
 +            "",
 +        );
 +    }
 +}
index 577a8640a4c00acd659e6dfe6b6e3cadb5e95aca,0000000000000000000000000000000000000000..85322f12a834cce2ea6507e7020e07f8fbe610ac
mode 100644,000000..100644
--- /dev/null
@@@ -1,2114 -1,0 +1,2193 @@@
 +//! Config used by the language server.
 +//!
 +//! We currently get this config from `initialize` LSP request, which is not the
 +//! best way to do it, but was the simplest thing we could implement.
 +//!
 +//! Of particular interest is the `feature_flags` hash map: while other fields
 +//! configure the server itself, feature flags are passed into analysis, and
 +//! tweak things like automatic insertion of `()` in completions.
 +
 +use std::{fmt, iter, path::PathBuf};
 +
 +use flycheck::FlycheckConfig;
 +use ide::{
 +    AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
 +    HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig,
 +    JoinLinesConfig, Snippet, SnippetScope,
 +};
 +use ide_db::{
 +    imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
 +    SnippetCap,
 +};
 +use itertools::Itertools;
 +use lsp_types::{ClientCapabilities, MarkupKind};
 +use project_model::{
 +    CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource,
 +    UnsetTestCrates,
 +};
 +use rustc_hash::{FxHashMap, FxHashSet};
 +use serde::{de::DeserializeOwned, Deserialize};
 +use vfs::AbsPathBuf;
 +
 +use crate::{
 +    caps::completion_item_edit_resolve,
 +    diagnostics::DiagnosticsMapConfig,
 +    line_index::OffsetEncoding,
 +    lsp_ext::{self, supports_utf8, WorkspaceSymbolSearchKind, WorkspaceSymbolSearchScope},
 +};
 +
 +mod patch_old_style;
 +
 +// Conventions for configuration keys to preserve maximal extendability without breakage:
 +//  - Toggles (be it binary true/false or with more options in-between) should almost always suffix as `_enable`
 +//    This has the benefit of namespaces being extensible, and if the suffix doesn't fit later it can be changed without breakage.
 +//  - In general be wary of using the namespace of something verbatim, it prevents us from adding subkeys in the future
 +//  - Don't use abbreviations unless really necessary
 +//  - foo_command = overrides the subcommand, foo_overrideCommand allows full overwriting, extra args only applies for foo_command
 +
 +// Defines the server-side configuration of the rust-analyzer. We generate
 +// *parts* of VS Code's `package.json` config from this. Run `cargo test` to
 +// re-generate that file.
 +//
 +// However, editor specific config, which the server doesn't know about, should
 +// be specified directly in `package.json`.
 +//
 +// To deprecate an option by replacing it with another name use `new_name | `old_name` so that we keep
 +// parsing the old name.
 +config_data! {
 +    struct ConfigData {
 +        /// Placeholder expression to use for missing expressions in assists.
 +        assist_expressionFillDefault: ExprFillDefaultDef              = "\"todo\"",
 +
 +        /// Warm up caches on project load.
 +        cachePriming_enable: bool = "true",
 +        /// How many worker threads to handle priming caches. The default `0` means to pick automatically.
 +        cachePriming_numThreads: ParallelCachePrimingNumThreads = "0",
 +
 +        /// Automatically refresh project info via `cargo metadata` on
 +        /// `Cargo.toml` or `.cargo/config.toml` changes.
 +        cargo_autoreload: bool           = "true",
 +        /// Run build scripts (`build.rs`) for more precise code analysis.
 +        cargo_buildScripts_enable: bool  = "true",
++        /// Specifies the working directory for running build scripts.
++        /// - "workspace": run build scripts for a workspace in the workspace's root directory.
++        ///   This is incompatible with `#rust-analyzer.cargo.buildScripts.invocationStrategy#` set to `once`.
++        /// - "root": run build scripts in the project's root directory.
++        /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
++        /// is set.
++        cargo_buildScripts_invocationLocation: InvocationLocation = "\"workspace\"",
++        /// Specifies the invocation strategy to use when running the build scripts command.
++        /// If `per_workspace` is set, the command will be executed for each workspace.
++        /// If `once` is set, the command will be executed once.
++        /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
++        /// is set.
++        cargo_buildScripts_invocationStrategy: InvocationStrategy = "\"per_workspace\"",
 +        /// Override the command rust-analyzer uses to run build scripts and
 +        /// build procedural macros. The command is required to output json
 +        /// and should therefore include `--message-format=json` or a similar
 +        /// option.
 +        ///
 +        /// By default, a cargo invocation will be constructed for the configured
 +        /// targets and features, with the following base command line:
 +        ///
 +        /// ```bash
 +        /// cargo check --quiet --workspace --message-format=json --all-targets
 +        /// ```
 +        /// .
 +        cargo_buildScripts_overrideCommand: Option<Vec<String>> = "null",
 +        /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
 +        /// avoid checking unnecessary things.
 +        cargo_buildScripts_useRustcWrapper: bool = "true",
 +        /// Extra environment variables that will be set when running cargo, rustc
 +        /// or other commands within the workspace. Useful for setting RUSTFLAGS.
 +        cargo_extraEnv: FxHashMap<String, String> = "{}",
 +        /// List of features to activate.
 +        ///
 +        /// Set this to `"all"` to pass `--all-features` to cargo.
 +        cargo_features: CargoFeaturesDef      = "[]",
 +        /// Whether to pass `--no-default-features` to cargo.
 +        cargo_noDefaultFeatures: bool    = "false",
 +        /// Relative path to the sysroot, or "discover" to try to automatically find it via
 +        /// "rustc --print sysroot".
 +        ///
 +        /// Unsetting this disables sysroot loading.
 +        ///
 +        /// This option does not take effect until rust-analyzer is restarted.
 +        cargo_sysroot: Option<String>    = "\"discover\"",
 +        /// Compilation target override (target triple).
 +        cargo_target: Option<String>     = "null",
 +        /// Unsets `#[cfg(test)]` for the specified crates.
 +        cargo_unsetTest: Vec<String>   = "[\"core\"]",
 +
 +        /// Check all targets and tests (`--all-targets`).
 +        checkOnSave_allTargets: bool                     = "true",
 +        /// Cargo command to use for `cargo check`.
 +        checkOnSave_command: String                      = "\"check\"",
 +        /// Run specified `cargo check` command for diagnostics on save.
 +        checkOnSave_enable: bool                         = "true",
 +        /// Extra arguments for `cargo check`.
 +        checkOnSave_extraArgs: Vec<String>               = "[]",
 +        /// Extra environment variables that will be set when running `cargo check`.
 +        /// Extends `#rust-analyzer.cargo.extraEnv#`.
 +        checkOnSave_extraEnv: FxHashMap<String, String> = "{}",
 +        /// List of features to activate. Defaults to
 +        /// `#rust-analyzer.cargo.features#`.
 +        ///
 +        /// Set to `"all"` to pass `--all-features` to Cargo.
 +        checkOnSave_features: Option<CargoFeaturesDef>      = "null",
++        /// Specifies the working directory for running checks.
++        /// - "workspace": run checks for workspaces in the corresponding workspaces' root directories.
++        // FIXME: Ideally we would support this in some way
++        ///   This falls back to "root" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`.
++        /// - "root": run checks in the project's root directory.
++        /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
++        /// is set.
++        checkOnSave_invocationLocation: InvocationLocation = "\"workspace\"",
++        /// Specifies the invocation strategy to use when running the checkOnSave command.
++        /// If `per_workspace` is set, the command will be executed for each workspace.
++        /// If `once` is set, the command will be executed once.
++        /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
++        /// is set.
++        checkOnSave_invocationStrategy: InvocationStrategy = "\"per_workspace\"",
 +        /// Whether to pass `--no-default-features` to Cargo. Defaults to
 +        /// `#rust-analyzer.cargo.noDefaultFeatures#`.
 +        checkOnSave_noDefaultFeatures: Option<bool>      = "null",
 +        /// Override the command rust-analyzer uses instead of `cargo check` for
 +        /// diagnostics on save. The command is required to output json and
 +        /// should therefor include `--message-format=json` or a similar option.
 +        ///
 +        /// If you're changing this because you're using some tool wrapping
 +        /// Cargo, you might also want to change
 +        /// `#rust-analyzer.cargo.buildScripts.overrideCommand#`.
 +        ///
 +        /// If there are multiple linked projects, this command is invoked for
 +        /// each of them, with the working directory being the project root
 +        /// (i.e., the folder containing the `Cargo.toml`).
 +        ///
 +        /// An example command would be:
 +        ///
 +        /// ```bash
 +        /// cargo check --workspace --message-format=json --all-targets
 +        /// ```
 +        /// .
 +        checkOnSave_overrideCommand: Option<Vec<String>> = "null",
 +        /// Check for a specific target. Defaults to
 +        /// `#rust-analyzer.cargo.target#`.
 +        checkOnSave_target: Option<String>               = "null",
 +
 +        /// Toggles the additional completions that automatically add imports when completed.
 +        /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
 +        completion_autoimport_enable: bool       = "true",
 +        /// Toggles the additional completions that automatically show method calls and field accesses
 +        /// with `self` prefixed to them when inside a method.
 +        completion_autoself_enable: bool        = "true",
 +        /// Whether to add parenthesis and argument snippets when completing function.
 +        completion_callable_snippets: CallableCompletionDef  = "\"fill_arguments\"",
 +        /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc.
 +        completion_postfix_enable: bool         = "true",
 +        /// Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.
 +        completion_privateEditable_enable: bool = "false",
 +        /// Custom completion snippets.
 +        // NOTE: Keep this list in sync with the feature docs of user snippets.
 +        completion_snippets_custom: FxHashMap<String, SnippetDef> = r#"{
 +            "Arc::new": {
 +                "postfix": "arc",
 +                "body": "Arc::new(${receiver})",
 +                "requires": "std::sync::Arc",
 +                "description": "Put the expression into an `Arc`",
 +                "scope": "expr"
 +            },
 +            "Rc::new": {
 +                "postfix": "rc",
 +                "body": "Rc::new(${receiver})",
 +                "requires": "std::rc::Rc",
 +                "description": "Put the expression into an `Rc`",
 +                "scope": "expr"
 +            },
 +            "Box::pin": {
 +                "postfix": "pinbox",
 +                "body": "Box::pin(${receiver})",
 +                "requires": "std::boxed::Box",
 +                "description": "Put the expression into a pinned `Box`",
 +                "scope": "expr"
 +            },
 +            "Ok": {
 +                "postfix": "ok",
 +                "body": "Ok(${receiver})",
 +                "description": "Wrap the expression in a `Result::Ok`",
 +                "scope": "expr"
 +            },
 +            "Err": {
 +                "postfix": "err",
 +                "body": "Err(${receiver})",
 +                "description": "Wrap the expression in a `Result::Err`",
 +                "scope": "expr"
 +            },
 +            "Some": {
 +                "postfix": "some",
 +                "body": "Some(${receiver})",
 +                "description": "Wrap the expression in an `Option::Some`",
 +                "scope": "expr"
 +            }
 +        }"#,
 +
 +        /// List of rust-analyzer diagnostics to disable.
 +        diagnostics_disabled: FxHashSet<String> = "[]",
 +        /// Whether to show native rust-analyzer diagnostics.
 +        diagnostics_enable: bool                = "true",
 +        /// Whether to show experimental rust-analyzer diagnostics that might
 +        /// have more false positives than usual.
 +        diagnostics_experimental_enable: bool    = "false",
 +        /// Map of prefixes to be substituted when parsing diagnostic file paths.
 +        /// This should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`.
 +        diagnostics_remapPrefix: FxHashMap<String, String> = "{}",
 +        /// List of warnings that should be displayed with hint severity.
 +        ///
 +        /// The warnings will be indicated by faded text or three dots in code
 +        /// and will not show up in the `Problems Panel`.
 +        diagnostics_warningsAsHint: Vec<String> = "[]",
 +        /// List of warnings that should be displayed with info severity.
 +        ///
 +        /// The warnings will be indicated by a blue squiggly underline in code
 +        /// and a blue icon in the `Problems Panel`.
 +        diagnostics_warningsAsInfo: Vec<String> = "[]",
 +
 +        /// These directories will be ignored by rust-analyzer. They are
 +        /// relative to the workspace root, and globs are not supported. You may
 +        /// also need to add the folders to Code's `files.watcherExclude`.
 +        files_excludeDirs: Vec<PathBuf> = "[]",
 +        /// Controls file watching implementation.
 +        files_watcher: FilesWatcherDef = "\"client\"",
 +        /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
 +        highlightRelated_breakPoints_enable: bool = "true",
 +        /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).
 +        highlightRelated_exitPoints_enable: bool = "true",
 +        /// Enables highlighting of related references while the cursor is on any identifier.
 +        highlightRelated_references_enable: bool = "true",
 +        /// Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.
 +        highlightRelated_yieldPoints_enable: bool = "true",
 +
 +        /// Whether to show `Debug` action. Only applies when
 +        /// `#rust-analyzer.hover.actions.enable#` is set.
 +        hover_actions_debug_enable: bool           = "true",
 +        /// Whether to show HoverActions in Rust files.
 +        hover_actions_enable: bool          = "true",
 +        /// Whether to show `Go to Type Definition` action. Only applies when
 +        /// `#rust-analyzer.hover.actions.enable#` is set.
 +        hover_actions_gotoTypeDef_enable: bool     = "true",
 +        /// Whether to show `Implementations` action. Only applies when
 +        /// `#rust-analyzer.hover.actions.enable#` is set.
 +        hover_actions_implementations_enable: bool = "true",
 +        /// Whether to show `References` action. Only applies when
 +        /// `#rust-analyzer.hover.actions.enable#` is set.
 +        hover_actions_references_enable: bool      = "false",
 +        /// Whether to show `Run` action. Only applies when
 +        /// `#rust-analyzer.hover.actions.enable#` is set.
 +        hover_actions_run_enable: bool             = "true",
 +
 +        /// Whether to show documentation on hover.
 +        hover_documentation_enable: bool           = "true",
 +        /// Whether to show keyword hover popups. Only applies when
 +        /// `#rust-analyzer.hover.documentation.enable#` is set.
 +        hover_documentation_keywords_enable: bool  = "true",
 +        /// Use markdown syntax for links in hover.
 +        hover_links_enable: bool = "true",
 +
 +        /// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.
 +        imports_granularity_enforce: bool              = "false",
 +        /// How imports should be grouped into use statements.
 +        imports_granularity_group: ImportGranularityDef  = "\"crate\"",
 +        /// Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-import[following order]. Groups are separated by newlines.
 +        imports_group_enable: bool                           = "true",
 +        /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
 +        imports_merge_glob: bool           = "true",
 +        /// Prefer to unconditionally use imports of the core and alloc crate, over the std crate.
 +        imports_prefer_no_std: bool                     = "false",
 +        /// The path structure for newly inserted paths to use.
 +        imports_prefix: ImportPrefixDef               = "\"plain\"",
 +
 +        /// Whether to show inlay type hints for binding modes.
 +        inlayHints_bindingModeHints_enable: bool                   = "false",
 +        /// Whether to show inlay type hints for method chains.
 +        inlayHints_chainingHints_enable: bool                      = "true",
 +        /// Whether to show inlay hints after a closing `}` to indicate what item it belongs to.
 +        inlayHints_closingBraceHints_enable: bool                  = "true",
 +        /// Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1
 +        /// to always show them).
 +        inlayHints_closingBraceHints_minLines: usize               = "25",
 +        /// Whether to show inlay type hints for return types of closures.
 +        inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef  = "\"never\"",
 +        /// Whether to show inlay type hints for elided lifetimes in function signatures.
 +        inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = "\"never\"",
 +        /// Whether to prefer using parameter names as the name for elided lifetime hints if possible.
 +        inlayHints_lifetimeElisionHints_useParameterNames: bool    = "false",
 +        /// Maximum length for inlay hints. Set to null to have an unlimited length.
 +        inlayHints_maxLength: Option<usize>                        = "25",
 +        /// Whether to show function parameter name inlay hints at the call
 +        /// site.
 +        inlayHints_parameterHints_enable: bool                     = "true",
 +        /// Whether to show inlay type hints for compiler inserted reborrows.
 +        inlayHints_reborrowHints_enable: ReborrowHintsDef          = "\"never\"",
 +        /// Whether to render leading colons for type hints, and trailing colons for parameter hints.
 +        inlayHints_renderColons: bool                              = "true",
 +        /// Whether to show inlay type hints for variables.
 +        inlayHints_typeHints_enable: bool                          = "true",
 +        /// Whether to hide inlay type hints for `let` statements that initialize to a closure.
 +        /// Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.
 +        inlayHints_typeHints_hideClosureInitialization: bool       = "false",
 +        /// Whether to hide inlay type hints for constructors.
 +        inlayHints_typeHints_hideNamedConstructor: bool            = "false",
 +
 +        /// Join lines merges consecutive declaration and initialization of an assignment.
 +        joinLines_joinAssignments: bool = "true",
 +        /// Join lines inserts else between consecutive ifs.
 +        joinLines_joinElseIf: bool = "true",
 +        /// Join lines removes trailing commas.
 +        joinLines_removeTrailingComma: bool = "true",
 +        /// Join lines unwraps trivial blocks.
 +        joinLines_unwrapTrivialBlock: bool = "true",
 +
 +
 +        /// Whether to show `Debug` lens. Only applies when
 +        /// `#rust-analyzer.lens.enable#` is set.
 +        lens_debug_enable: bool            = "true",
 +        /// Whether to show CodeLens in Rust files.
 +        lens_enable: bool           = "true",
 +        /// Internal config: use custom client-side commands even when the
 +        /// client doesn't set the corresponding capability.
 +        lens_forceCustomCommands: bool = "true",
 +        /// Whether to show `Implementations` lens. Only applies when
 +        /// `#rust-analyzer.lens.enable#` is set.
 +        lens_implementations_enable: bool  = "true",
 +        /// Where to render annotations.
 +        lens_location: AnnotationLocation = "\"above_name\"",
 +        /// Whether to show `References` lens for Struct, Enum, and Union.
 +        /// Only applies when `#rust-analyzer.lens.enable#` is set.
 +        lens_references_adt_enable: bool = "false",
 +        /// Whether to show `References` lens for Enum Variants.
 +        /// Only applies when `#rust-analyzer.lens.enable#` is set.
 +        lens_references_enumVariant_enable: bool = "false",
 +        /// Whether to show `Method References` lens. Only applies when
 +        /// `#rust-analyzer.lens.enable#` is set.
 +        lens_references_method_enable: bool = "false",
 +        /// Whether to show `References` lens for Trait.
 +        /// Only applies when `#rust-analyzer.lens.enable#` is set.
 +        lens_references_trait_enable: bool = "false",
 +        /// Whether to show `Run` lens. Only applies when
 +        /// `#rust-analyzer.lens.enable#` is set.
 +        lens_run_enable: bool              = "true",
 +
 +        /// Disable project auto-discovery in favor of explicitly specified set
 +        /// of projects.
 +        ///
 +        /// Elements must be paths pointing to `Cargo.toml`,
 +        /// `rust-project.json`, or JSON objects in `rust-project.json` format.
 +        linkedProjects: Vec<ManifestOrProjectJson> = "[]",
 +
 +        /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.
 +        lru_capacity: Option<usize>                 = "null",
 +
 +        /// Whether to show `can't find Cargo.toml` error message.
 +        notifications_cargoTomlNotFound: bool      = "true",
 +
 +        /// Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.
 +        procMacro_attributes_enable: bool = "true",
 +        /// Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.
 +        procMacro_enable: bool                     = "true",
 +        /// These proc-macros will be ignored when trying to expand them.
 +        ///
 +        /// This config takes a map of crate names with the exported proc-macro names to ignore as values.
 +        procMacro_ignored: FxHashMap<Box<str>, Box<[Box<str>]>>          = "{}",
 +        /// Internal config, path to proc-macro server executable (typically,
 +        /// this is rust-analyzer itself, but we override this in tests).
 +        procMacro_server: Option<PathBuf>          = "null",
 +
 +        /// Exclude imports from find-all-references.
 +        references_excludeImports: bool = "false",
 +
 +        /// Command to be executed instead of 'cargo' for runnables.
 +        runnables_command: Option<String> = "null",
 +        /// Additional arguments to be passed to cargo for runnables such as
 +        /// tests or binaries. For example, it may be `--release`.
 +        runnables_extraArgs: Vec<String>   = "[]",
 +
 +        /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private
 +        /// projects, or "discover" to try to automatically find it if the `rustc-dev` component
 +        /// is installed.
 +        ///
 +        /// Any project which uses rust-analyzer with the rustcPrivate
 +        /// crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.
 +        ///
 +        /// This option does not take effect until rust-analyzer is restarted.
 +        rustc_source: Option<String> = "null",
 +
 +        /// Additional arguments to `rustfmt`.
 +        rustfmt_extraArgs: Vec<String>               = "[]",
 +        /// Advanced option, fully override the command rust-analyzer uses for
 +        /// formatting.
 +        rustfmt_overrideCommand: Option<Vec<String>> = "null",
 +        /// Enables the use of rustfmt's unstable range formatting command for the
 +        /// `textDocument/rangeFormatting` request. The rustfmt option is unstable and only
 +        /// available on a nightly build.
 +        rustfmt_rangeFormatting_enable: bool = "false",
 +
 +        /// Inject additional highlighting into doc comments.
 +        ///
 +        /// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra
 +        /// doc links.
 +        semanticHighlighting_doc_comment_inject_enable: bool = "true",
 +        /// Use semantic tokens for operators.
 +        ///
 +        /// When disabled, rust-analyzer will emit semantic tokens only for operator tokens when
 +        /// they are tagged with modifiers.
 +        semanticHighlighting_operator_enable: bool = "true",
 +        /// Use specialized semantic tokens for operators.
 +        ///
 +        /// When enabled, rust-analyzer will emit special token types for operator tokens instead
 +        /// of the generic `operator` token type.
 +        semanticHighlighting_operator_specialization_enable: bool = "false",
 +        /// Use semantic tokens for punctuations.
 +        ///
 +        /// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when
 +        /// they are tagged with modifiers or have a special role.
 +        semanticHighlighting_punctuation_enable: bool = "false",
 +        /// When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro
 +        /// calls.
 +        semanticHighlighting_punctuation_separate_macro_bang: bool = "false",
 +        /// Use specialized semantic tokens for punctuations.
 +        ///
 +        /// When enabled, rust-analyzer will emit special token types for punctuation tokens instead
 +        /// of the generic `punctuation` token type.
 +        semanticHighlighting_punctuation_specialization_enable: bool = "false",
 +        /// Use semantic tokens for strings.
 +        ///
 +        /// In some editors (e.g. vscode) semantic tokens override other highlighting grammars.
 +        /// By disabling semantic tokens for strings, other grammars can be used to highlight
 +        /// their contents.
 +        semanticHighlighting_strings_enable: bool = "true",
 +
 +        /// Show full signature of the callable. Only shows parameters if disabled.
 +        signatureInfo_detail: SignatureDetail                           = "\"full\"",
 +        /// Show documentation.
 +        signatureInfo_documentation_enable: bool                       = "true",
 +
 +        /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.
 +        typing_autoClosingAngleBrackets_enable: bool = "false",
 +
 +        /// Workspace symbol search kind.
 +        workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = "\"only_types\"",
 +        /// Limits the number of items returned from a workspace symbol search (Defaults to 128).
 +        /// Some clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.
 +        /// Other clients requires all results upfront and might require a higher limit.
 +        workspace_symbol_search_limit: usize = "128",
 +        /// Workspace symbol search scope.
 +        workspace_symbol_search_scope: WorkspaceSymbolSearchScopeDef = "\"workspace\"",
 +    }
 +}
 +
 +impl Default for ConfigData {
 +    fn default() -> Self {
 +        ConfigData::from_json(serde_json::Value::Null, &mut Vec::new())
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +pub struct Config {
 +    pub discovered_projects: Option<Vec<ProjectManifest>>,
 +    caps: lsp_types::ClientCapabilities,
 +    root_path: AbsPathBuf,
 +    data: ConfigData,
 +    detached_files: Vec<AbsPathBuf>,
 +    snippets: Vec<Snippet>,
 +}
 +
 +type ParallelCachePrimingNumThreads = u8;
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum LinkedProject {
 +    ProjectManifest(ProjectManifest),
 +    InlineJsonProject(ProjectJson),
 +}
 +
 +impl From<ProjectManifest> for LinkedProject {
 +    fn from(v: ProjectManifest) -> Self {
 +        LinkedProject::ProjectManifest(v)
 +    }
 +}
 +
 +impl From<ProjectJson> for LinkedProject {
 +    fn from(v: ProjectJson) -> Self {
 +        LinkedProject::InlineJsonProject(v)
 +    }
 +}
 +
 +pub struct CallInfoConfig {
 +    pub params_only: bool,
 +    pub docs: bool,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub struct LensConfig {
 +    // runnables
 +    pub run: bool,
 +    pub debug: bool,
 +
 +    // implementations
 +    pub implementations: bool,
 +
 +    // references
 +    pub method_refs: bool,
 +    pub refs_adt: bool,   // for Struct, Enum, Union and Trait
 +    pub refs_trait: bool, // for Struct, Enum, Union and Trait
 +    pub enum_variant_refs: bool,
 +
 +    // annotations
 +    pub location: AnnotationLocation,
 +}
 +
 +#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
 +#[serde(rename_all = "snake_case")]
 +pub enum AnnotationLocation {
 +    AboveName,
 +    AboveWholeItem,
 +}
 +
 +impl From<AnnotationLocation> for ide::AnnotationLocation {
 +    fn from(location: AnnotationLocation) -> Self {
 +        match location {
 +            AnnotationLocation::AboveName => ide::AnnotationLocation::AboveName,
 +            AnnotationLocation::AboveWholeItem => ide::AnnotationLocation::AboveWholeItem,
 +        }
 +    }
 +}
 +
 +impl LensConfig {
 +    pub fn any(&self) -> bool {
 +        self.run
 +            || self.debug
 +            || self.implementations
 +            || self.method_refs
 +            || self.refs_adt
 +            || self.refs_trait
 +            || self.enum_variant_refs
 +    }
 +
 +    pub fn none(&self) -> bool {
 +        !self.any()
 +    }
 +
 +    pub fn runnable(&self) -> bool {
 +        self.run || self.debug
 +    }
 +
 +    pub fn references(&self) -> bool {
 +        self.method_refs || self.refs_adt || self.refs_trait || self.enum_variant_refs
 +    }
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub struct HoverActionsConfig {
 +    pub implementations: bool,
 +    pub references: bool,
 +    pub run: bool,
 +    pub debug: bool,
 +    pub goto_type_def: bool,
 +}
 +
 +impl HoverActionsConfig {
 +    pub const NO_ACTIONS: Self = Self {
 +        implementations: false,
 +        references: false,
 +        run: false,
 +        debug: false,
 +        goto_type_def: false,
 +    };
 +
 +    pub fn any(&self) -> bool {
 +        self.implementations || self.references || self.runnable() || self.goto_type_def
 +    }
 +
 +    pub fn none(&self) -> bool {
 +        !self.any()
 +    }
 +
 +    pub fn runnable(&self) -> bool {
 +        self.run || self.debug
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +pub struct FilesConfig {
 +    pub watcher: FilesWatcher,
 +    pub exclude: Vec<AbsPathBuf>,
 +}
 +
 +#[derive(Debug, Clone)]
 +pub enum FilesWatcher {
 +    Client,
 +    Server,
 +}
 +
 +#[derive(Debug, Clone)]
 +pub struct NotificationsConfig {
 +    pub cargo_toml_not_found: bool,
 +}
 +
 +#[derive(Debug, Clone)]
 +pub enum RustfmtConfig {
 +    Rustfmt { extra_args: Vec<String>, enable_range_formatting: bool },
 +    CustomCommand { command: String, args: Vec<String> },
 +}
 +
 +/// Configuration for runnable items, such as `main` function or tests.
 +#[derive(Debug, Clone)]
 +pub struct RunnablesConfig {
 +    /// Custom command to be executed instead of `cargo` for runnables.
 +    pub override_cargo: Option<String>,
 +    /// Additional arguments for the `cargo`, e.g. `--release`.
 +    pub cargo_extra_args: Vec<String>,
 +}
 +
 +/// Configuration for workspace symbol search requests.
 +#[derive(Debug, Clone)]
 +pub struct WorkspaceSymbolConfig {
 +    /// In what scope should the symbol be searched in.
 +    pub search_scope: WorkspaceSymbolSearchScope,
 +    /// What kind of symbol is being searched for.
 +    pub search_kind: WorkspaceSymbolSearchKind,
 +    /// How many items are returned at most.
 +    pub search_limit: usize,
 +}
 +
 +pub struct ClientCommandsConfig {
 +    pub run_single: bool,
 +    pub debug_single: bool,
 +    pub show_reference: bool,
 +    pub goto_location: bool,
 +    pub trigger_parameter_hints: bool,
 +}
 +
 +#[derive(Debug)]
 +pub struct ConfigUpdateError {
 +    errors: Vec<(String, serde_json::Error)>,
 +}
 +
 +impl fmt::Display for ConfigUpdateError {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        let errors = self.errors.iter().format_with("\n", |(key, e), f| {
 +            f(key)?;
 +            f(&": ")?;
 +            f(e)
 +        });
 +        write!(
 +            f,
 +            "rust-analyzer found {} invalid config value{}:\n{}",
 +            self.errors.len(),
 +            if self.errors.len() == 1 { "" } else { "s" },
 +            errors
 +        )
 +    }
 +}
 +
 +impl Config {
 +    pub fn new(root_path: AbsPathBuf, caps: ClientCapabilities) -> Self {
 +        Config {
 +            caps,
 +            data: ConfigData::default(),
 +            detached_files: Vec::new(),
 +            discovered_projects: None,
 +            root_path,
 +            snippets: Default::default(),
 +        }
 +    }
 +
 +    pub fn update(&mut self, mut json: serde_json::Value) -> Result<(), ConfigUpdateError> {
 +        tracing::info!("updating config from JSON: {:#}", json);
 +        if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) {
 +            return Ok(());
 +        }
 +        let mut errors = Vec::new();
 +        self.detached_files =
 +            get_field::<Vec<PathBuf>>(&mut json, &mut errors, "detachedFiles", None, "[]")
 +                .into_iter()
 +                .map(AbsPathBuf::assert)
 +                .collect();
 +        patch_old_style::patch_json_for_outdated_configs(&mut json);
 +        self.data = ConfigData::from_json(json, &mut errors);
 +        tracing::debug!("deserialized config data: {:#?}", self.data);
 +        self.snippets.clear();
 +        for (name, def) in self.data.completion_snippets_custom.iter() {
 +            if def.prefix.is_empty() && def.postfix.is_empty() {
 +                continue;
 +            }
 +            let scope = match def.scope {
 +                SnippetScopeDef::Expr => SnippetScope::Expr,
 +                SnippetScopeDef::Type => SnippetScope::Type,
 +                SnippetScopeDef::Item => SnippetScope::Item,
 +            };
 +            match Snippet::new(
 +                &def.prefix,
 +                &def.postfix,
 +                &def.body,
 +                def.description.as_ref().unwrap_or(name),
 +                &def.requires,
 +                scope,
 +            ) {
 +                Some(snippet) => self.snippets.push(snippet),
 +                None => errors.push((
 +                    format!("snippet {name} is invalid"),
 +                    <serde_json::Error as serde::de::Error>::custom(
 +                        "snippet path is invalid or triggers are missing",
 +                    ),
 +                )),
 +            }
 +        }
 +
 +        self.validate(&mut errors);
 +
 +        if errors.is_empty() {
 +            Ok(())
 +        } else {
 +            Err(ConfigUpdateError { errors })
 +        }
 +    }
 +
 +    fn validate(&self, error_sink: &mut Vec<(String, serde_json::Error)>) {
 +        use serde::de::Error;
 +        if self.data.checkOnSave_command.is_empty() {
 +            error_sink.push((
 +                "/checkOnSave/command".to_string(),
 +                serde_json::Error::custom("expected a non-empty string"),
 +            ));
 +        }
 +    }
 +
 +    pub fn json_schema() -> serde_json::Value {
 +        ConfigData::json_schema()
 +    }
 +
 +    pub fn root_path(&self) -> &AbsPathBuf {
 +        &self.root_path
 +    }
 +
 +    pub fn caps(&self) -> &lsp_types::ClientCapabilities {
 +        &self.caps
 +    }
 +
 +    pub fn detached_files(&self) -> &[AbsPathBuf] {
 +        &self.detached_files
 +    }
 +}
 +
 +macro_rules! try_ {
 +    ($expr:expr) => {
 +        || -> _ { Some($expr) }()
 +    };
 +}
 +macro_rules! try_or {
 +    ($expr:expr, $or:expr) => {
 +        try_!($expr).unwrap_or($or)
 +    };
 +}
 +
 +macro_rules! try_or_def {
 +    ($expr:expr) => {
 +        try_!($expr).unwrap_or_default()
 +    };
 +}
 +
 +impl Config {
 +    pub fn linked_projects(&self) -> Vec<LinkedProject> {
 +        match self.data.linkedProjects.as_slice() {
 +            [] => match self.discovered_projects.as_ref() {
 +                Some(discovered_projects) => {
 +                    let exclude_dirs: Vec<_> = self
 +                        .data
 +                        .files_excludeDirs
 +                        .iter()
 +                        .map(|p| self.root_path.join(p))
 +                        .collect();
 +                    discovered_projects
 +                        .iter()
 +                        .filter(|p| {
 +                            let (ProjectManifest::ProjectJson(path)
 +                            | ProjectManifest::CargoToml(path)) = p;
 +                            !exclude_dirs.iter().any(|p| path.starts_with(p))
 +                        })
 +                        .cloned()
 +                        .map(LinkedProject::from)
 +                        .collect()
 +                }
 +                None => Vec::new(),
 +            },
 +            linked_projects => linked_projects
 +                .iter()
 +                .filter_map(|linked_project| match linked_project {
 +                    ManifestOrProjectJson::Manifest(it) => {
 +                        let path = self.root_path.join(it);
 +                        ProjectManifest::from_manifest_file(path)
 +                            .map_err(|e| tracing::error!("failed to load linked project: {}", e))
 +                            .ok()
 +                            .map(Into::into)
 +                    }
 +                    ManifestOrProjectJson::ProjectJson(it) => {
 +                        Some(ProjectJson::new(&self.root_path, it.clone()).into())
 +                    }
 +                })
 +                .collect(),
 +        }
 +    }
 +
 +    pub fn did_save_text_document_dynamic_registration(&self) -> bool {
 +        let caps = try_or_def!(self.caps.text_document.as_ref()?.synchronization.clone()?);
 +        caps.did_save == Some(true) && caps.dynamic_registration == Some(true)
 +    }
 +
 +    pub fn did_change_watched_files_dynamic_registration(&self) -> bool {
 +        try_or_def!(
 +            self.caps.workspace.as_ref()?.did_change_watched_files.as_ref()?.dynamic_registration?
 +        )
 +    }
 +
 +    pub fn prefill_caches(&self) -> bool {
 +        self.data.cachePriming_enable
 +    }
 +
 +    pub fn location_link(&self) -> bool {
 +        try_or_def!(self.caps.text_document.as_ref()?.definition?.link_support?)
 +    }
 +
 +    pub fn line_folding_only(&self) -> bool {
 +        try_or_def!(self.caps.text_document.as_ref()?.folding_range.as_ref()?.line_folding_only?)
 +    }
 +
 +    pub fn hierarchical_symbols(&self) -> bool {
 +        try_or_def!(
 +            self.caps
 +                .text_document
 +                .as_ref()?
 +                .document_symbol
 +                .as_ref()?
 +                .hierarchical_document_symbol_support?
 +        )
 +    }
 +
 +    pub fn code_action_literals(&self) -> bool {
 +        try_!(self
 +            .caps
 +            .text_document
 +            .as_ref()?
 +            .code_action
 +            .as_ref()?
 +            .code_action_literal_support
 +            .as_ref()?)
 +        .is_some()
 +    }
 +
 +    pub fn work_done_progress(&self) -> bool {
 +        try_or_def!(self.caps.window.as_ref()?.work_done_progress?)
 +    }
 +
 +    pub fn will_rename(&self) -> bool {
 +        try_or_def!(self.caps.workspace.as_ref()?.file_operations.as_ref()?.will_rename?)
 +    }
 +
 +    pub fn change_annotation_support(&self) -> bool {
 +        try_!(self
 +            .caps
 +            .workspace
 +            .as_ref()?
 +            .workspace_edit
 +            .as_ref()?
 +            .change_annotation_support
 +            .as_ref()?)
 +        .is_some()
 +    }
 +
 +    pub fn code_action_resolve(&self) -> bool {
 +        try_or_def!(self
 +            .caps
 +            .text_document
 +            .as_ref()?
 +            .code_action
 +            .as_ref()?
 +            .resolve_support
 +            .as_ref()?
 +            .properties
 +            .as_slice())
 +        .iter()
 +        .any(|it| it == "edit")
 +    }
 +
 +    pub fn signature_help_label_offsets(&self) -> bool {
 +        try_or_def!(
 +            self.caps
 +                .text_document
 +                .as_ref()?
 +                .signature_help
 +                .as_ref()?
 +                .signature_information
 +                .as_ref()?
 +                .parameter_information
 +                .as_ref()?
 +                .label_offset_support?
 +        )
 +    }
 +
 +    pub fn completion_label_details_support(&self) -> bool {
 +        try_!(self
 +            .caps
 +            .text_document
 +            .as_ref()?
 +            .completion
 +            .as_ref()?
 +            .completion_item
 +            .as_ref()?
 +            .label_details_support
 +            .as_ref()?)
 +        .is_some()
 +    }
 +
 +    pub fn offset_encoding(&self) -> OffsetEncoding {
 +        if supports_utf8(&self.caps) {
 +            OffsetEncoding::Utf8
 +        } else {
 +            OffsetEncoding::Utf16
 +        }
 +    }
 +
 +    fn experimental(&self, index: &'static str) -> bool {
 +        try_or_def!(self.caps.experimental.as_ref()?.get(index)?.as_bool()?)
 +    }
 +
 +    pub fn code_action_group(&self) -> bool {
 +        self.experimental("codeActionGroup")
 +    }
 +
 +    pub fn server_status_notification(&self) -> bool {
 +        self.experimental("serverStatusNotification")
 +    }
 +
 +    pub fn publish_diagnostics(&self) -> bool {
 +        self.data.diagnostics_enable
 +    }
 +
 +    pub fn diagnostics(&self) -> DiagnosticsConfig {
 +        DiagnosticsConfig {
 +            proc_attr_macros_enabled: self.expand_proc_attr_macros(),
 +            proc_macros_enabled: self.data.procMacro_enable,
 +            disable_experimental: !self.data.diagnostics_experimental_enable,
 +            disabled: self.data.diagnostics_disabled.clone(),
 +            expr_fill_default: match self.data.assist_expressionFillDefault {
 +                ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo,
 +                ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
 +            },
 +            insert_use: self.insert_use_config(),
 +            prefer_no_std: self.data.imports_prefer_no_std,
 +        }
 +    }
 +
 +    pub fn diagnostics_map(&self) -> DiagnosticsMapConfig {
 +        DiagnosticsMapConfig {
 +            remap_prefix: self.data.diagnostics_remapPrefix.clone(),
 +            warnings_as_info: self.data.diagnostics_warningsAsInfo.clone(),
 +            warnings_as_hint: self.data.diagnostics_warningsAsHint.clone(),
 +        }
 +    }
 +
 +    pub fn extra_env(&self) -> &FxHashMap<String, String> {
 +        &self.data.cargo_extraEnv
 +    }
 +
 +    pub fn check_on_save_extra_env(&self) -> FxHashMap<String, String> {
 +        let mut extra_env = self.data.cargo_extraEnv.clone();
 +        extra_env.extend(self.data.checkOnSave_extraEnv.clone());
 +        extra_env
 +    }
 +
 +    pub fn lru_capacity(&self) -> Option<usize> {
 +        self.data.lru_capacity
 +    }
 +
 +    pub fn proc_macro_srv(&self) -> Option<(AbsPathBuf, /* is path explicitly set */ bool)> {
 +        if !self.data.procMacro_enable {
 +            return None;
 +        }
 +        Some(match &self.data.procMacro_server {
 +            Some(it) => (
 +                AbsPathBuf::try_from(it.clone()).unwrap_or_else(|path| self.root_path.join(path)),
 +                true,
 +            ),
 +            None => (AbsPathBuf::assert(std::env::current_exe().ok()?), false),
 +        })
 +    }
 +
 +    pub fn dummy_replacements(&self) -> &FxHashMap<Box<str>, Box<[Box<str>]>> {
 +        &self.data.procMacro_ignored
 +    }
 +
 +    pub fn expand_proc_attr_macros(&self) -> bool {
 +        self.data.procMacro_enable && self.data.procMacro_attributes_enable
 +    }
 +
 +    pub fn files(&self) -> FilesConfig {
 +        FilesConfig {
 +            watcher: match self.data.files_watcher {
 +                FilesWatcherDef::Client if self.did_change_watched_files_dynamic_registration() => {
 +                    FilesWatcher::Client
 +                }
 +                _ => FilesWatcher::Server,
 +            },
 +            exclude: self.data.files_excludeDirs.iter().map(|it| self.root_path.join(it)).collect(),
 +        }
 +    }
 +
 +    pub fn notifications(&self) -> NotificationsConfig {
 +        NotificationsConfig { cargo_toml_not_found: self.data.notifications_cargoTomlNotFound }
 +    }
 +
 +    pub fn cargo_autoreload(&self) -> bool {
 +        self.data.cargo_autoreload
 +    }
 +
 +    pub fn run_build_scripts(&self) -> bool {
 +        self.data.cargo_buildScripts_enable || self.data.procMacro_enable
 +    }
 +
 +    pub fn cargo(&self) -> CargoConfig {
 +        let rustc_source = self.data.rustc_source.as_ref().map(|rustc_src| {
 +            if rustc_src == "discover" {
 +                RustcSource::Discover
 +            } else {
 +                RustcSource::Path(self.root_path.join(rustc_src))
 +            }
 +        });
 +        let sysroot = self.data.cargo_sysroot.as_ref().map(|sysroot| {
 +            if sysroot == "discover" {
 +                RustcSource::Discover
 +            } else {
 +                RustcSource::Path(self.root_path.join(sysroot))
 +            }
 +        });
 +
 +        CargoConfig {
 +            features: match &self.data.cargo_features {
 +                CargoFeaturesDef::All => CargoFeatures::All,
 +                CargoFeaturesDef::Selected(features) => CargoFeatures::Selected {
 +                    features: features.clone(),
 +                    no_default_features: self.data.cargo_noDefaultFeatures,
 +                },
 +            },
 +            target: self.data.cargo_target.clone(),
 +            sysroot,
 +            rustc_source,
 +            unset_test_crates: UnsetTestCrates::Only(self.data.cargo_unsetTest.clone()),
 +            wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper,
++            invocation_strategy: match self.data.cargo_buildScripts_invocationStrategy {
++                InvocationStrategy::Once => project_model::InvocationStrategy::Once,
++                InvocationStrategy::PerWorkspace => project_model::InvocationStrategy::PerWorkspace,
++            },
++            invocation_location: match self.data.cargo_buildScripts_invocationLocation {
++                InvocationLocation::Root => {
++                    project_model::InvocationLocation::Root(self.root_path.clone())
++                }
++                InvocationLocation::Workspace => project_model::InvocationLocation::Workspace,
++            },
 +            run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(),
 +            extra_env: self.data.cargo_extraEnv.clone(),
 +        }
 +    }
 +
 +    pub fn rustfmt(&self) -> RustfmtConfig {
 +        match &self.data.rustfmt_overrideCommand {
 +            Some(args) if !args.is_empty() => {
 +                let mut args = args.clone();
 +                let command = args.remove(0);
 +                RustfmtConfig::CustomCommand { command, args }
 +            }
 +            Some(_) | None => RustfmtConfig::Rustfmt {
 +                extra_args: self.data.rustfmt_extraArgs.clone(),
 +                enable_range_formatting: self.data.rustfmt_rangeFormatting_enable,
 +            },
 +        }
 +    }
 +
 +    pub fn flycheck(&self) -> Option<FlycheckConfig> {
 +        if !self.data.checkOnSave_enable {
 +            return None;
 +        }
 +        let flycheck_config = match &self.data.checkOnSave_overrideCommand {
 +            Some(args) if !args.is_empty() => {
 +                let mut args = args.clone();
 +                let command = args.remove(0);
 +                FlycheckConfig::CustomCommand {
 +                    command,
 +                    args,
 +                    extra_env: self.check_on_save_extra_env(),
++                    invocation_strategy: match self.data.checkOnSave_invocationStrategy {
++                        InvocationStrategy::Once => flycheck::InvocationStrategy::Once,
++                        InvocationStrategy::PerWorkspace => {
++                            flycheck::InvocationStrategy::PerWorkspace
++                        }
++                    },
++                    invocation_location: match self.data.checkOnSave_invocationLocation {
++                        InvocationLocation::Root => {
++                            flycheck::InvocationLocation::Root(self.root_path.clone())
++                        }
++                        InvocationLocation::Workspace => flycheck::InvocationLocation::Workspace,
++                    },
 +                }
 +            }
 +            Some(_) | None => FlycheckConfig::CargoCommand {
 +                command: self.data.checkOnSave_command.clone(),
 +                target_triple: self
 +                    .data
 +                    .checkOnSave_target
 +                    .clone()
 +                    .or_else(|| self.data.cargo_target.clone()),
 +                all_targets: self.data.checkOnSave_allTargets,
 +                no_default_features: self
 +                    .data
 +                    .checkOnSave_noDefaultFeatures
 +                    .unwrap_or(self.data.cargo_noDefaultFeatures),
 +                all_features: matches!(
 +                    self.data.checkOnSave_features.as_ref().unwrap_or(&self.data.cargo_features),
 +                    CargoFeaturesDef::All
 +                ),
 +                features: match self
 +                    .data
 +                    .checkOnSave_features
 +                    .clone()
 +                    .unwrap_or_else(|| self.data.cargo_features.clone())
 +                {
 +                    CargoFeaturesDef::All => vec![],
 +                    CargoFeaturesDef::Selected(it) => it,
 +                },
 +                extra_args: self.data.checkOnSave_extraArgs.clone(),
 +                extra_env: self.check_on_save_extra_env(),
 +            },
 +        };
 +        Some(flycheck_config)
 +    }
 +
 +    pub fn runnables(&self) -> RunnablesConfig {
 +        RunnablesConfig {
 +            override_cargo: self.data.runnables_command.clone(),
 +            cargo_extra_args: self.data.runnables_extraArgs.clone(),
 +        }
 +    }
 +
 +    pub fn inlay_hints(&self) -> InlayHintsConfig {
 +        InlayHintsConfig {
 +            render_colons: self.data.inlayHints_renderColons,
 +            type_hints: self.data.inlayHints_typeHints_enable,
 +            parameter_hints: self.data.inlayHints_parameterHints_enable,
 +            chaining_hints: self.data.inlayHints_chainingHints_enable,
 +            closure_return_type_hints: match self.data.inlayHints_closureReturnTypeHints_enable {
 +                ClosureReturnTypeHintsDef::Always => ide::ClosureReturnTypeHints::Always,
 +                ClosureReturnTypeHintsDef::Never => ide::ClosureReturnTypeHints::Never,
 +                ClosureReturnTypeHintsDef::WithBlock => ide::ClosureReturnTypeHints::WithBlock,
 +            },
 +            lifetime_elision_hints: match self.data.inlayHints_lifetimeElisionHints_enable {
 +                LifetimeElisionDef::Always => ide::LifetimeElisionHints::Always,
 +                LifetimeElisionDef::Never => ide::LifetimeElisionHints::Never,
 +                LifetimeElisionDef::SkipTrivial => ide::LifetimeElisionHints::SkipTrivial,
 +            },
 +            hide_named_constructor_hints: self.data.inlayHints_typeHints_hideNamedConstructor,
 +            hide_closure_initialization_hints: self
 +                .data
 +                .inlayHints_typeHints_hideClosureInitialization,
 +            reborrow_hints: match self.data.inlayHints_reborrowHints_enable {
 +                ReborrowHintsDef::Always => ide::ReborrowHints::Always,
 +                ReborrowHintsDef::Never => ide::ReborrowHints::Never,
 +                ReborrowHintsDef::Mutable => ide::ReborrowHints::MutableOnly,
 +            },
 +            binding_mode_hints: self.data.inlayHints_bindingModeHints_enable,
 +            param_names_for_lifetime_elision_hints: self
 +                .data
 +                .inlayHints_lifetimeElisionHints_useParameterNames,
 +            max_length: self.data.inlayHints_maxLength,
 +            closing_brace_hints_min_lines: if self.data.inlayHints_closingBraceHints_enable {
 +                Some(self.data.inlayHints_closingBraceHints_minLines)
 +            } else {
 +                None
 +            },
 +        }
 +    }
 +
 +    fn insert_use_config(&self) -> InsertUseConfig {
 +        InsertUseConfig {
 +            granularity: match self.data.imports_granularity_group {
 +                ImportGranularityDef::Preserve => ImportGranularity::Preserve,
 +                ImportGranularityDef::Item => ImportGranularity::Item,
 +                ImportGranularityDef::Crate => ImportGranularity::Crate,
 +                ImportGranularityDef::Module => ImportGranularity::Module,
 +            },
 +            enforce_granularity: self.data.imports_granularity_enforce,
 +            prefix_kind: match self.data.imports_prefix {
 +                ImportPrefixDef::Plain => PrefixKind::Plain,
 +                ImportPrefixDef::ByCrate => PrefixKind::ByCrate,
 +                ImportPrefixDef::BySelf => PrefixKind::BySelf,
 +            },
 +            group: self.data.imports_group_enable,
 +            skip_glob_imports: !self.data.imports_merge_glob,
 +        }
 +    }
 +
 +    pub fn completion(&self) -> CompletionConfig {
 +        CompletionConfig {
 +            enable_postfix_completions: self.data.completion_postfix_enable,
 +            enable_imports_on_the_fly: self.data.completion_autoimport_enable
 +                && completion_item_edit_resolve(&self.caps),
 +            enable_self_on_the_fly: self.data.completion_autoself_enable,
 +            enable_private_editable: self.data.completion_privateEditable_enable,
 +            callable: match self.data.completion_callable_snippets {
 +                CallableCompletionDef::FillArguments => Some(CallableSnippets::FillArguments),
 +                CallableCompletionDef::AddParentheses => Some(CallableSnippets::AddParentheses),
 +                CallableCompletionDef::None => None,
 +            },
 +            insert_use: self.insert_use_config(),
 +            prefer_no_std: self.data.imports_prefer_no_std,
 +            snippet_cap: SnippetCap::new(try_or_def!(
 +                self.caps
 +                    .text_document
 +                    .as_ref()?
 +                    .completion
 +                    .as_ref()?
 +                    .completion_item
 +                    .as_ref()?
 +                    .snippet_support?
 +            )),
 +            snippets: self.snippets.clone(),
 +        }
 +    }
 +
 +    pub fn find_all_refs_exclude_imports(&self) -> bool {
 +        self.data.references_excludeImports
 +    }
 +
 +    pub fn snippet_cap(&self) -> bool {
 +        self.experimental("snippetTextEdit")
 +    }
 +
 +    pub fn assist(&self) -> AssistConfig {
 +        AssistConfig {
 +            snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")),
 +            allowed: None,
 +            insert_use: self.insert_use_config(),
 +            prefer_no_std: self.data.imports_prefer_no_std,
 +        }
 +    }
 +
 +    pub fn join_lines(&self) -> JoinLinesConfig {
 +        JoinLinesConfig {
 +            join_else_if: self.data.joinLines_joinElseIf,
 +            remove_trailing_comma: self.data.joinLines_removeTrailingComma,
 +            unwrap_trivial_blocks: self.data.joinLines_unwrapTrivialBlock,
 +            join_assignments: self.data.joinLines_joinAssignments,
 +        }
 +    }
 +
 +    pub fn call_info(&self) -> CallInfoConfig {
 +        CallInfoConfig {
 +            params_only: matches!(self.data.signatureInfo_detail, SignatureDetail::Parameters),
 +            docs: self.data.signatureInfo_documentation_enable,
 +        }
 +    }
 +
 +    pub fn lens(&self) -> LensConfig {
 +        LensConfig {
 +            run: self.data.lens_enable && self.data.lens_run_enable,
 +            debug: self.data.lens_enable && self.data.lens_debug_enable,
 +            implementations: self.data.lens_enable && self.data.lens_implementations_enable,
 +            method_refs: self.data.lens_enable && self.data.lens_references_method_enable,
 +            refs_adt: self.data.lens_enable && self.data.lens_references_adt_enable,
 +            refs_trait: self.data.lens_enable && self.data.lens_references_trait_enable,
 +            enum_variant_refs: self.data.lens_enable
 +                && self.data.lens_references_enumVariant_enable,
 +            location: self.data.lens_location,
 +        }
 +    }
 +
 +    pub fn hover_actions(&self) -> HoverActionsConfig {
 +        let enable = self.experimental("hoverActions") && self.data.hover_actions_enable;
 +        HoverActionsConfig {
 +            implementations: enable && self.data.hover_actions_implementations_enable,
 +            references: enable && self.data.hover_actions_references_enable,
 +            run: enable && self.data.hover_actions_run_enable,
 +            debug: enable && self.data.hover_actions_debug_enable,
 +            goto_type_def: enable && self.data.hover_actions_gotoTypeDef_enable,
 +        }
 +    }
 +
 +    pub fn highlighting_config(&self) -> HighlightConfig {
 +        HighlightConfig {
 +            strings: self.data.semanticHighlighting_strings_enable,
 +            punctuation: self.data.semanticHighlighting_punctuation_enable,
 +            specialize_punctuation: self
 +                .data
 +                .semanticHighlighting_punctuation_specialization_enable,
 +            macro_bang: self.data.semanticHighlighting_punctuation_separate_macro_bang,
 +            operator: self.data.semanticHighlighting_operator_enable,
 +            specialize_operator: self.data.semanticHighlighting_operator_specialization_enable,
 +            inject_doc_comment: self.data.semanticHighlighting_doc_comment_inject_enable,
 +            syntactic_name_ref_highlighting: false,
 +        }
 +    }
 +
 +    pub fn hover(&self) -> HoverConfig {
 +        HoverConfig {
 +            links_in_hover: self.data.hover_links_enable,
 +            documentation: self.data.hover_documentation_enable.then(|| {
 +                let is_markdown = try_or_def!(self
 +                    .caps
 +                    .text_document
 +                    .as_ref()?
 +                    .hover
 +                    .as_ref()?
 +                    .content_format
 +                    .as_ref()?
 +                    .as_slice())
 +                .contains(&MarkupKind::Markdown);
 +                if is_markdown {
 +                    HoverDocFormat::Markdown
 +                } else {
 +                    HoverDocFormat::PlainText
 +                }
 +            }),
 +            keywords: self.data.hover_documentation_keywords_enable,
 +        }
 +    }
 +
 +    pub fn workspace_symbol(&self) -> WorkspaceSymbolConfig {
 +        WorkspaceSymbolConfig {
 +            search_scope: match self.data.workspace_symbol_search_scope {
 +                WorkspaceSymbolSearchScopeDef::Workspace => WorkspaceSymbolSearchScope::Workspace,
 +                WorkspaceSymbolSearchScopeDef::WorkspaceAndDependencies => {
 +                    WorkspaceSymbolSearchScope::WorkspaceAndDependencies
 +                }
 +            },
 +            search_kind: match self.data.workspace_symbol_search_kind {
 +                WorkspaceSymbolSearchKindDef::OnlyTypes => WorkspaceSymbolSearchKind::OnlyTypes,
 +                WorkspaceSymbolSearchKindDef::AllSymbols => WorkspaceSymbolSearchKind::AllSymbols,
 +            },
 +            search_limit: self.data.workspace_symbol_search_limit,
 +        }
 +    }
 +
 +    pub fn semantic_tokens_refresh(&self) -> bool {
 +        try_or_def!(self.caps.workspace.as_ref()?.semantic_tokens.as_ref()?.refresh_support?)
 +    }
 +
 +    pub fn code_lens_refresh(&self) -> bool {
 +        try_or_def!(self.caps.workspace.as_ref()?.code_lens.as_ref()?.refresh_support?)
 +    }
 +
 +    pub fn insert_replace_support(&self) -> bool {
 +        try_or_def!(
 +            self.caps
 +                .text_document
 +                .as_ref()?
 +                .completion
 +                .as_ref()?
 +                .completion_item
 +                .as_ref()?
 +                .insert_replace_support?
 +        )
 +    }
 +
 +    pub fn client_commands(&self) -> ClientCommandsConfig {
 +        let commands =
 +            try_or!(self.caps.experimental.as_ref()?.get("commands")?, &serde_json::Value::Null);
 +        let commands: Option<lsp_ext::ClientCommandOptions> =
 +            serde_json::from_value(commands.clone()).ok();
 +        let force = commands.is_none() && self.data.lens_forceCustomCommands;
 +        let commands = commands.map(|it| it.commands).unwrap_or_default();
 +
 +        let get = |name: &str| commands.iter().any(|it| it == name) || force;
 +
 +        ClientCommandsConfig {
 +            run_single: get("rust-analyzer.runSingle"),
 +            debug_single: get("rust-analyzer.debugSingle"),
 +            show_reference: get("rust-analyzer.showReferences"),
 +            goto_location: get("rust-analyzer.gotoLocation"),
 +            trigger_parameter_hints: get("editor.action.triggerParameterHints"),
 +        }
 +    }
 +
 +    pub fn highlight_related(&self) -> HighlightRelatedConfig {
 +        HighlightRelatedConfig {
 +            references: self.data.highlightRelated_references_enable,
 +            break_points: self.data.highlightRelated_breakPoints_enable,
 +            exit_points: self.data.highlightRelated_exitPoints_enable,
 +            yield_points: self.data.highlightRelated_yieldPoints_enable,
 +        }
 +    }
 +
 +    pub fn prime_caches_num_threads(&self) -> u8 {
 +        match self.data.cachePriming_numThreads {
 +            0 => num_cpus::get_physical().try_into().unwrap_or(u8::MAX),
 +            n => n,
 +        }
 +    }
 +
 +    pub fn typing_autoclose_angle(&self) -> bool {
 +        self.data.typing_autoClosingAngleBrackets_enable
 +    }
 +}
 +// Deserialization definitions
 +
 +macro_rules! create_bool_or_string_de {
 +    ($ident:ident<$bool:literal, $string:literal>) => {
 +        fn $ident<'de, D>(d: D) -> Result<(), D::Error>
 +        where
 +            D: serde::Deserializer<'de>,
 +        {
 +            struct V;
 +            impl<'de> serde::de::Visitor<'de> for V {
 +                type Value = ();
 +
 +                fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
 +                    formatter.write_str(concat!(
 +                        stringify!($bool),
 +                        " or \"",
 +                        stringify!($string),
 +                        "\""
 +                    ))
 +                }
 +
 +                fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
 +                where
 +                    E: serde::de::Error,
 +                {
 +                    match v {
 +                        $bool => Ok(()),
 +                        _ => Err(serde::de::Error::invalid_value(
 +                            serde::de::Unexpected::Bool(v),
 +                            &self,
 +                        )),
 +                    }
 +                }
 +
 +                fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
 +                where
 +                    E: serde::de::Error,
 +                {
 +                    match v {
 +                        $string => Ok(()),
 +                        _ => Err(serde::de::Error::invalid_value(
 +                            serde::de::Unexpected::Str(v),
 +                            &self,
 +                        )),
 +                    }
 +                }
 +
 +                fn visit_enum<A>(self, a: A) -> Result<Self::Value, A::Error>
 +                where
 +                    A: serde::de::EnumAccess<'de>,
 +                {
 +                    use serde::de::VariantAccess;
 +                    let (variant, va) = a.variant::<&'de str>()?;
 +                    va.unit_variant()?;
 +                    match variant {
 +                        $string => Ok(()),
 +                        _ => Err(serde::de::Error::invalid_value(
 +                            serde::de::Unexpected::Str(variant),
 +                            &self,
 +                        )),
 +                    }
 +                }
 +            }
 +            d.deserialize_any(V)
 +        }
 +    };
 +}
 +create_bool_or_string_de!(true_or_always<true, "always">);
 +create_bool_or_string_de!(false_or_never<false, "never">);
 +
 +macro_rules! named_unit_variant {
 +    ($variant:ident) => {
 +        pub(super) fn $variant<'de, D>(deserializer: D) -> Result<(), D::Error>
 +        where
 +            D: serde::Deserializer<'de>,
 +        {
 +            struct V;
 +            impl<'de> serde::de::Visitor<'de> for V {
 +                type Value = ();
 +                fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +                    f.write_str(concat!("\"", stringify!($variant), "\""))
 +                }
 +                fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
 +                    if value == stringify!($variant) {
 +                        Ok(())
 +                    } else {
 +                        Err(E::invalid_value(serde::de::Unexpected::Str(value), &self))
 +                    }
 +                }
 +            }
 +            deserializer.deserialize_str(V)
 +        }
 +    };
 +}
 +
 +mod de_unit_v {
 +    named_unit_variant!(all);
 +    named_unit_variant!(skip_trivial);
 +    named_unit_variant!(mutable);
 +    named_unit_variant!(with_block);
 +}
 +
 +#[derive(Deserialize, Debug, Clone, Copy)]
 +#[serde(rename_all = "snake_case")]
 +enum SnippetScopeDef {
 +    Expr,
 +    Item,
 +    Type,
 +}
 +
 +impl Default for SnippetScopeDef {
 +    fn default() -> Self {
 +        SnippetScopeDef::Expr
 +    }
 +}
 +
 +#[derive(Deserialize, Debug, Clone, Default)]
 +#[serde(default)]
 +struct SnippetDef {
 +    #[serde(deserialize_with = "single_or_array")]
 +    prefix: Vec<String>,
 +    #[serde(deserialize_with = "single_or_array")]
 +    postfix: Vec<String>,
 +    description: Option<String>,
 +    #[serde(deserialize_with = "single_or_array")]
 +    body: Vec<String>,
 +    #[serde(deserialize_with = "single_or_array")]
 +    requires: Vec<String>,
 +    scope: SnippetScopeDef,
 +}
 +
 +fn single_or_array<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
 +where
 +    D: serde::Deserializer<'de>,
 +{
 +    struct SingleOrVec;
 +
 +    impl<'de> serde::de::Visitor<'de> for SingleOrVec {
 +        type Value = Vec<String>;
 +
 +        fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +            formatter.write_str("string or array of strings")
 +        }
 +
 +        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
 +        where
 +            E: serde::de::Error,
 +        {
 +            Ok(vec![value.to_owned()])
 +        }
 +
 +        fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
 +        where
 +            A: serde::de::SeqAccess<'de>,
 +        {
 +            Deserialize::deserialize(serde::de::value::SeqAccessDeserializer::new(seq))
 +        }
 +    }
 +
 +    deserializer.deserialize_any(SingleOrVec)
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(untagged)]
 +enum ManifestOrProjectJson {
 +    Manifest(PathBuf),
 +    ProjectJson(ProjectJsonData),
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum ExprFillDefaultDef {
 +    Todo,
 +    Default,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum ImportGranularityDef {
 +    Preserve,
 +    Item,
 +    Crate,
 +    Module,
 +}
 +
 +#[derive(Deserialize, Debug, Copy, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum CallableCompletionDef {
 +    FillArguments,
 +    AddParentheses,
 +    None,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(untagged)]
 +enum CargoFeaturesDef {
 +    #[serde(deserialize_with = "de_unit_v::all")]
 +    All,
 +    Selected(Vec<String>),
 +}
 +
++#[derive(Deserialize, Debug, Clone)]
++#[serde(rename_all = "snake_case")]
++enum InvocationStrategy {
++    Once,
++    PerWorkspace,
++}
++
++#[derive(Deserialize, Debug, Clone)]
++#[serde(rename_all = "snake_case")]
++enum InvocationLocation {
++    Root,
++    Workspace,
++}
++
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(untagged)]
 +enum LifetimeElisionDef {
 +    #[serde(deserialize_with = "true_or_always")]
 +    Always,
 +    #[serde(deserialize_with = "false_or_never")]
 +    Never,
 +    #[serde(deserialize_with = "de_unit_v::skip_trivial")]
 +    SkipTrivial,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(untagged)]
 +enum ClosureReturnTypeHintsDef {
 +    #[serde(deserialize_with = "true_or_always")]
 +    Always,
 +    #[serde(deserialize_with = "false_or_never")]
 +    Never,
 +    #[serde(deserialize_with = "de_unit_v::with_block")]
 +    WithBlock,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(untagged)]
 +enum ReborrowHintsDef {
 +    #[serde(deserialize_with = "true_or_always")]
 +    Always,
 +    #[serde(deserialize_with = "false_or_never")]
 +    Never,
 +    #[serde(deserialize_with = "de_unit_v::mutable")]
 +    Mutable,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum FilesWatcherDef {
 +    Client,
 +    Notify,
 +    Server,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum ImportPrefixDef {
 +    Plain,
 +    #[serde(alias = "self")]
 +    BySelf,
 +    #[serde(alias = "crate")]
 +    ByCrate,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum WorkspaceSymbolSearchScopeDef {
 +    Workspace,
 +    WorkspaceAndDependencies,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum SignatureDetail {
 +    Full,
 +    Parameters,
 +}
 +
 +#[derive(Deserialize, Debug, Clone)]
 +#[serde(rename_all = "snake_case")]
 +enum WorkspaceSymbolSearchKindDef {
 +    OnlyTypes,
 +    AllSymbols,
 +}
 +
 +macro_rules! _config_data {
 +    (struct $name:ident {
 +        $(
 +            $(#[doc=$doc:literal])*
 +            $field:ident $(| $alias:ident)*: $ty:ty = $default:expr,
 +        )*
 +    }) => {
 +        #[allow(non_snake_case)]
 +        #[derive(Debug, Clone)]
 +        struct $name { $($field: $ty,)* }
 +        impl $name {
 +            fn from_json(mut json: serde_json::Value, error_sink: &mut Vec<(String, serde_json::Error)>) -> $name {
 +                $name {$(
 +                    $field: get_field(
 +                        &mut json,
 +                        error_sink,
 +                        stringify!($field),
 +                        None$(.or(Some(stringify!($alias))))*,
 +                        $default,
 +                    ),
 +                )*}
 +            }
 +
 +            fn json_schema() -> serde_json::Value {
 +                schema(&[
 +                    $({
 +                        let field = stringify!($field);
 +                        let ty = stringify!($ty);
 +
 +                        (field, ty, &[$($doc),*], $default)
 +                    },)*
 +                ])
 +            }
 +
 +            #[cfg(test)]
 +            fn manual() -> String {
 +                manual(&[
 +                    $({
 +                        let field = stringify!($field);
 +                        let ty = stringify!($ty);
 +
 +                        (field, ty, &[$($doc),*], $default)
 +                    },)*
 +                ])
 +            }
 +        }
 +
 +        #[test]
 +        fn fields_are_sorted() {
 +            [$(stringify!($field)),*].windows(2).for_each(|w| assert!(w[0] <= w[1], "{} <= {} does not hold", w[0], w[1]));
 +        }
 +    };
 +}
 +use _config_data as config_data;
 +
 +fn get_field<T: DeserializeOwned>(
 +    json: &mut serde_json::Value,
 +    error_sink: &mut Vec<(String, serde_json::Error)>,
 +    field: &'static str,
 +    alias: Option<&'static str>,
 +    default: &str,
 +) -> T {
 +    let default = serde_json::from_str(default).unwrap();
 +    // XXX: check alias first, to work-around the VS Code where it pre-fills the
 +    // defaults instead of sending an empty object.
 +    alias
 +        .into_iter()
 +        .chain(iter::once(field))
 +        .find_map(move |field| {
 +            let mut pointer = field.replace('_', "/");
 +            pointer.insert(0, '/');
 +            json.pointer_mut(&pointer).and_then(|it| match serde_json::from_value(it.take()) {
 +                Ok(it) => Some(it),
 +                Err(e) => {
 +                    tracing::warn!("Failed to deserialize config field at {}: {:?}", pointer, e);
 +                    error_sink.push((pointer, e));
 +                    None
 +                }
 +            })
 +        })
 +        .unwrap_or(default)
 +}
 +
 +fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json::Value {
 +    for ((f1, ..), (f2, ..)) in fields.iter().zip(&fields[1..]) {
 +        fn key(f: &str) -> &str {
 +            f.splitn(2, '_').next().unwrap()
 +        }
 +        assert!(key(f1) <= key(f2), "wrong field order: {:?} {:?}", f1, f2);
 +    }
 +
 +    let map = fields
 +        .iter()
 +        .map(|(field, ty, doc, default)| {
 +            let name = field.replace('_', ".");
 +            let name = format!("rust-analyzer.{}", name);
 +            let props = field_props(field, ty, doc, default);
 +            (name, props)
 +        })
 +        .collect::<serde_json::Map<_, _>>();
 +    map.into()
 +}
 +
 +fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json::Value {
 +    let doc = doc_comment_to_string(doc);
 +    let doc = doc.trim_end_matches('\n');
 +    assert!(
 +        doc.ends_with('.') && doc.starts_with(char::is_uppercase),
 +        "bad docs for {}: {:?}",
 +        field,
 +        doc
 +    );
 +    let default = default.parse::<serde_json::Value>().unwrap();
 +
 +    let mut map = serde_json::Map::default();
 +    macro_rules! set {
 +        ($($key:literal: $value:tt),*$(,)?) => {{$(
 +            map.insert($key.into(), serde_json::json!($value));
 +        )*}};
 +    }
 +    set!("markdownDescription": doc);
 +    set!("default": default);
 +
 +    match ty {
 +        "bool" => set!("type": "boolean"),
 +        "usize" => set!("type": "integer", "minimum": 0),
 +        "String" => set!("type": "string"),
 +        "Vec<String>" => set! {
 +            "type": "array",
 +            "items": { "type": "string" },
 +        },
 +        "Vec<PathBuf>" => set! {
 +            "type": "array",
 +            "items": { "type": "string" },
 +        },
 +        "FxHashSet<String>" => set! {
 +            "type": "array",
 +            "items": { "type": "string" },
 +            "uniqueItems": true,
 +        },
 +        "FxHashMap<Box<str>, Box<[Box<str>]>>" => set! {
 +            "type": "object",
 +        },
 +        "FxHashMap<String, SnippetDef>" => set! {
 +            "type": "object",
 +        },
 +        "FxHashMap<String, String>" => set! {
 +            "type": "object",
 +        },
 +        "Option<usize>" => set! {
 +            "type": ["null", "integer"],
 +            "minimum": 0,
 +        },
 +        "Option<String>" => set! {
 +            "type": ["null", "string"],
 +        },
 +        "Option<PathBuf>" => set! {
 +            "type": ["null", "string"],
 +        },
 +        "Option<bool>" => set! {
 +            "type": ["null", "boolean"],
 +        },
 +        "Option<Vec<String>>" => set! {
 +            "type": ["null", "array"],
 +            "items": { "type": "string" },
 +        },
 +        "MergeBehaviorDef" => set! {
 +            "type": "string",
 +            "enum": ["none", "crate", "module"],
 +            "enumDescriptions": [
 +                "Do not merge imports at all.",
 +                "Merge imports from the same crate into a single `use` statement.",
 +                "Merge imports from the same module into a single `use` statement."
 +            ],
 +        },
 +        "ExprFillDefaultDef" => set! {
 +            "type": "string",
 +            "enum": ["todo", "default"],
 +            "enumDescriptions": [
 +                "Fill missing expressions with the `todo` macro",
 +                "Fill missing expressions with reasonable defaults, `new` or `default` constructors."
 +            ],
 +        },
 +        "ImportGranularityDef" => set! {
 +            "type": "string",
 +            "enum": ["preserve", "crate", "module", "item"],
 +            "enumDescriptions": [
 +                "Do not change the granularity of any imports and preserve the original structure written by the developer.",
 +                "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.",
 +                "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.",
 +                "Flatten imports so that each has its own use statement."
 +            ],
 +        },
 +        "ImportPrefixDef" => set! {
 +            "type": "string",
 +            "enum": [
 +                "plain",
 +                "self",
 +                "crate"
 +            ],
 +            "enumDescriptions": [
 +                "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.",
 +                "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.",
 +                "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from."
 +            ],
 +        },
 +        "Vec<ManifestOrProjectJson>" => set! {
 +            "type": "array",
 +            "items": { "type": ["string", "object"] },
 +        },
 +        "WorkspaceSymbolSearchScopeDef" => set! {
 +            "type": "string",
 +            "enum": ["workspace", "workspace_and_dependencies"],
 +            "enumDescriptions": [
 +                "Search in current workspace only.",
 +                "Search in current workspace and dependencies."
 +            ],
 +        },
 +        "WorkspaceSymbolSearchKindDef" => set! {
 +            "type": "string",
 +            "enum": ["only_types", "all_symbols"],
 +            "enumDescriptions": [
 +                "Search for types only.",
 +                "Search for all symbols kinds."
 +            ],
 +        },
 +        "ParallelCachePrimingNumThreads" => set! {
 +            "type": "number",
 +            "minimum": 0,
 +            "maximum": 255
 +        },
 +        "LifetimeElisionDef" => set! {
 +            "type": "string",
 +            "enum": [
 +                "always",
 +                "never",
 +                "skip_trivial"
 +            ],
 +            "enumDescriptions": [
 +                "Always show lifetime elision hints.",
 +                "Never show lifetime elision hints.",
 +                "Only show lifetime elision hints if a return type is involved."
 +            ]
 +        },
 +        "ClosureReturnTypeHintsDef" => set! {
 +            "type": "string",
 +            "enum": [
 +                "always",
 +                "never",
 +                "with_block"
 +            ],
 +            "enumDescriptions": [
 +                "Always show type hints for return types of closures.",
 +                "Never show type hints for return types of closures.",
 +                "Only show type hints for return types of closures with blocks."
 +            ]
 +        },
 +        "ReborrowHintsDef" => set! {
 +            "type": "string",
 +            "enum": [
 +                "always",
 +                "never",
 +                "mutable"
 +            ],
 +            "enumDescriptions": [
 +                "Always show reborrow hints.",
 +                "Never show reborrow hints.",
 +                "Only show mutable reborrow hints."
 +            ]
 +        },
 +        "CargoFeaturesDef" => set! {
 +            "anyOf": [
 +                {
 +                    "type": "string",
 +                    "enum": [
 +                        "all"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Pass `--all-features` to cargo",
 +                    ]
 +                },
 +                {
 +                    "type": "array",
 +                    "items": { "type": "string" }
 +                }
 +            ],
 +        },
 +        "Option<CargoFeaturesDef>" => set! {
 +            "anyOf": [
 +                {
 +                    "type": "string",
 +                    "enum": [
 +                        "all"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Pass `--all-features` to cargo",
 +                    ]
 +                },
 +                {
 +                    "type": "array",
 +                    "items": { "type": "string" }
 +                },
 +                { "type": "null" }
 +            ],
 +        },
 +        "CallableCompletionDef" => set! {
 +            "type": "string",
 +            "enum": [
 +                "fill_arguments",
 +                "add_parentheses",
 +                "none",
 +            ],
 +            "enumDescriptions": [
 +                "Add call parentheses and pre-fill arguments.",
 +                "Add call parentheses.",
 +                "Do no snippet completions for callables."
 +            ]
 +        },
 +        "SignatureDetail" => set! {
 +            "type": "string",
 +            "enum": ["full", "parameters"],
 +            "enumDescriptions": [
 +                "Show the entire signature.",
 +                "Show only the parameters."
 +            ],
 +        },
 +        "FilesWatcherDef" => set! {
 +            "type": "string",
 +            "enum": ["client", "server"],
 +            "enumDescriptions": [
 +                "Use the client (editor) to watch files for changes",
 +                "Use server-side file watching",
 +            ],
 +        },
 +        "AnnotationLocation" => set! {
 +            "type": "string",
 +            "enum": ["above_name", "above_whole_item"],
 +            "enumDescriptions": [
 +                "Render annotations above the name of the item.",
 +                "Render annotations above the whole item, including documentation comments and attributes."
 +            ],
 +        },
++        "InvocationStrategy" => set! {
++            "type": "string",
++            "enum": ["per_workspace", "once"],
++            "enumDescriptions": [
++                "The command will be executed for each workspace.",
++                "The command will be executed once."
++            ],
++        },
++        "InvocationLocation" => set! {
++            "type": "string",
++            "enum": ["workspace", "root"],
++            "enumDescriptions": [
++                "The command will be executed in the corresponding workspace root.",
++                "The command will be executed in the project root."
++            ],
++        },
 +        _ => panic!("missing entry for {}: {}", ty, default),
 +    }
 +
 +    map.into()
 +}
 +
 +#[cfg(test)]
 +fn manual(fields: &[(&'static str, &'static str, &[&str], &str)]) -> String {
 +    fields
 +        .iter()
 +        .map(|(field, _ty, doc, default)| {
 +            let name = format!("rust-analyzer.{}", field.replace('_', "."));
 +            let doc = doc_comment_to_string(*doc);
 +            if default.contains('\n') {
 +                format!(
 +                    r#"[[{}]]{}::
 ++
 +--
 +Default:
 +----
 +{}
 +----
 +{}
 +--
 +"#,
 +                    name, name, default, doc
 +                )
 +            } else {
 +                format!("[[{}]]{} (default: `{}`)::\n+\n--\n{}--\n", name, name, default, doc)
 +            }
 +        })
 +        .collect::<String>()
 +}
 +
 +fn doc_comment_to_string(doc: &[&str]) -> String {
 +    doc.iter().map(|it| it.strip_prefix(' ').unwrap_or(it)).map(|it| format!("{}\n", it)).collect()
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use std::fs;
 +
 +    use test_utils::{ensure_file_contents, project_root};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn generate_package_json_config() {
 +        let s = Config::json_schema();
 +        let schema = format!("{:#}", s);
 +        let mut schema = schema
 +            .trim_start_matches('{')
 +            .trim_end_matches('}')
 +            .replace("  ", "    ")
 +            .replace('\n', "\n            ")
 +            .trim_start_matches('\n')
 +            .trim_end()
 +            .to_string();
 +        schema.push_str(",\n");
 +
 +        // Transform the asciidoc form link to markdown style.
 +        //
 +        // https://link[text] => [text](https://link)
 +        let url_matches = schema.match_indices("https://");
 +        let mut url_offsets = url_matches.map(|(idx, _)| idx).collect::<Vec<usize>>();
 +        url_offsets.reverse();
 +        for idx in url_offsets {
 +            let link = &schema[idx..];
 +            // matching on whitespace to ignore normal links
 +            if let Some(link_end) = link.find(|c| c == ' ' || c == '[') {
 +                if link.chars().nth(link_end) == Some('[') {
 +                    if let Some(link_text_end) = link.find(']') {
 +                        let link_text = link[link_end..(link_text_end + 1)].to_string();
 +
 +                        schema.replace_range((idx + link_end)..(idx + link_text_end + 1), "");
 +                        schema.insert(idx, '(');
 +                        schema.insert(idx + link_end + 1, ')');
 +                        schema.insert_str(idx, &link_text);
 +                    }
 +                }
 +            }
 +        }
 +
 +        let package_json_path = project_root().join("editors/code/package.json");
 +        let mut package_json = fs::read_to_string(&package_json_path).unwrap();
 +
 +        let start_marker = "                \"$generated-start\": {},\n";
 +        let end_marker = "                \"$generated-end\": {}\n";
 +
 +        let start = package_json.find(start_marker).unwrap() + start_marker.len();
 +        let end = package_json.find(end_marker).unwrap();
 +
 +        let p = remove_ws(&package_json[start..end]);
 +        let s = remove_ws(&schema);
 +        if !p.contains(&s) {
 +            package_json.replace_range(start..end, &schema);
 +            ensure_file_contents(&package_json_path, &package_json)
 +        }
 +    }
 +
 +    #[test]
 +    fn generate_config_documentation() {
 +        let docs_path = project_root().join("docs/user/generated_config.adoc");
 +        let expected = ConfigData::manual();
 +        ensure_file_contents(&docs_path, &expected);
 +    }
 +
 +    fn remove_ws(text: &str) -> String {
 +        text.replace(char::is_whitespace, "")
 +    }
 +}
index f16559148e651644ebd4f0d0029e18460d8f91af,0000000000000000000000000000000000000000..57899b599146693e176c6135107b05dcff363fe1
mode 100644,000000..100644
--- /dev/null
@@@ -1,266 -1,0 +1,266 @@@
-         if let Ok(response) = result_to_response::<R>(req.id.clone(), result) {
 +//! See [RequestDispatcher].
 +use std::{fmt, panic, thread};
 +
 +use ide::Cancelled;
 +use lsp_server::ExtractError;
 +use serde::{de::DeserializeOwned, Serialize};
 +
 +use crate::{
 +    global_state::{GlobalState, GlobalStateSnapshot},
 +    main_loop::Task,
 +    version::version,
 +    LspError, Result,
 +};
 +
 +/// A visitor for routing a raw JSON request to an appropriate handler function.
 +///
 +/// Most requests are read-only and async and are handled on the threadpool
 +/// (`on` method).
 +///
 +/// Some read-only requests are latency sensitive, and are immediately handled
 +/// on the main loop thread (`on_sync`). These are typically typing-related
 +/// requests.
 +///
 +/// Some requests modify the state, and are run on the main thread to get
 +/// `&mut` (`on_sync_mut`).
 +///
 +/// Read-only requests are wrapped into `catch_unwind` -- they don't modify the
 +/// state, so it's OK to recover from their failures.
 +pub(crate) struct RequestDispatcher<'a> {
 +    pub(crate) req: Option<lsp_server::Request>,
 +    pub(crate) global_state: &'a mut GlobalState,
 +}
 +
 +impl<'a> RequestDispatcher<'a> {
 +    /// Dispatches the request onto the current thread, given full access to
 +    /// mutable global state. Unlike all other methods here, this one isn't
 +    /// guarded by `catch_unwind`, so, please, don't make bugs :-)
 +    pub(crate) fn on_sync_mut<R>(
 +        &mut self,
 +        f: fn(&mut GlobalState, R::Params) -> Result<R::Result>,
 +    ) -> &mut Self
 +    where
 +        R: lsp_types::request::Request,
 +        R::Params: DeserializeOwned + panic::UnwindSafe + fmt::Debug,
 +        R::Result: Serialize,
 +    {
 +        let (req, params, panic_context) = match self.parse::<R>() {
 +            Some(it) => it,
 +            None => return self,
 +        };
 +        let result = {
 +            let _pctx = stdx::panic_context::enter(panic_context);
 +            f(self.global_state, params)
 +        };
-         if let Ok(response) = thread_result_to_response::<R>(req.id.clone(), result) {
++        if let Ok(response) = result_to_response::<R>(req.id, result) {
 +            self.global_state.respond(response);
 +        }
 +
 +        self
 +    }
 +
 +    /// Dispatches the request onto the current thread.
 +    pub(crate) fn on_sync<R>(
 +        &mut self,
 +        f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
 +    ) -> &mut Self
 +    where
 +        R: lsp_types::request::Request,
 +        R::Params: DeserializeOwned + panic::UnwindSafe + fmt::Debug,
 +        R::Result: Serialize,
 +    {
 +        let (req, params, panic_context) = match self.parse::<R>() {
 +            Some(it) => it,
 +            None => return self,
 +        };
 +        let global_state_snapshot = self.global_state.snapshot();
 +
 +        let result = panic::catch_unwind(move || {
 +            let _pctx = stdx::panic_context::enter(panic_context);
 +            f(global_state_snapshot, params)
 +        });
 +
++        if let Ok(response) = thread_result_to_response::<R>(req.id, result) {
 +            self.global_state.respond(response);
 +        }
 +
 +        self
 +    }
 +
 +    /// Dispatches the request onto thread pool
 +    pub(crate) fn on<R>(
 +        &mut self,
 +        f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
 +    ) -> &mut Self
 +    where
 +        R: lsp_types::request::Request + 'static,
 +        R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
 +        R::Result: Serialize,
 +    {
 +        let (req, params, panic_context) = match self.parse::<R>() {
 +            Some(it) => it,
 +            None => return self,
 +        };
 +
 +        self.global_state.task_pool.handle.spawn({
 +            let world = self.global_state.snapshot();
 +            move || {
 +                let result = panic::catch_unwind(move || {
 +                    let _pctx = stdx::panic_context::enter(panic_context);
 +                    f(world, params)
 +                });
 +                match thread_result_to_response::<R>(req.id.clone(), result) {
 +                    Ok(response) => Task::Response(response),
 +                    Err(_) => Task::Retry(req),
 +                }
 +            }
 +        });
 +
 +        self
 +    }
 +
 +    pub(crate) fn finish(&mut self) {
 +        if let Some(req) = self.req.take() {
 +            tracing::error!("unknown request: {:?}", req);
 +            let response = lsp_server::Response::new_err(
 +                req.id,
 +                lsp_server::ErrorCode::MethodNotFound as i32,
 +                "unknown request".to_string(),
 +            );
 +            self.global_state.respond(response);
 +        }
 +    }
 +
 +    fn parse<R>(&mut self) -> Option<(lsp_server::Request, R::Params, String)>
 +    where
 +        R: lsp_types::request::Request,
 +        R::Params: DeserializeOwned + fmt::Debug,
 +    {
 +        let req = match &self.req {
 +            Some(req) if req.method == R::METHOD => self.req.take()?,
 +            _ => return None,
 +        };
 +
 +        let res = crate::from_json(R::METHOD, &req.params);
 +        match res {
 +            Ok(params) => {
 +                let panic_context =
 +                    format!("\nversion: {}\nrequest: {} {:#?}", version(), R::METHOD, params);
 +                Some((req, params, panic_context))
 +            }
 +            Err(err) => {
 +                let response = lsp_server::Response::new_err(
 +                    req.id,
 +                    lsp_server::ErrorCode::InvalidParams as i32,
 +                    err.to_string(),
 +                );
 +                self.global_state.respond(response);
 +                None
 +            }
 +        }
 +    }
 +}
 +
 +fn thread_result_to_response<R>(
 +    id: lsp_server::RequestId,
 +    result: thread::Result<Result<R::Result>>,
 +) -> Result<lsp_server::Response, Cancelled>
 +where
 +    R: lsp_types::request::Request,
 +    R::Params: DeserializeOwned,
 +    R::Result: Serialize,
 +{
 +    match result {
 +        Ok(result) => result_to_response::<R>(id, result),
 +        Err(panic) => {
 +            let panic_message = panic
 +                .downcast_ref::<String>()
 +                .map(String::as_str)
 +                .or_else(|| panic.downcast_ref::<&str>().copied());
 +
 +            let mut message = "request handler panicked".to_string();
 +            if let Some(panic_message) = panic_message {
 +                message.push_str(": ");
 +                message.push_str(panic_message)
 +            };
 +
 +            Ok(lsp_server::Response::new_err(
 +                id,
 +                lsp_server::ErrorCode::InternalError as i32,
 +                message,
 +            ))
 +        }
 +    }
 +}
 +
 +fn result_to_response<R>(
 +    id: lsp_server::RequestId,
 +    result: Result<R::Result>,
 +) -> Result<lsp_server::Response, Cancelled>
 +where
 +    R: lsp_types::request::Request,
 +    R::Params: DeserializeOwned,
 +    R::Result: Serialize,
 +{
 +    let res = match result {
 +        Ok(resp) => lsp_server::Response::new_ok(id, &resp),
 +        Err(e) => match e.downcast::<LspError>() {
 +            Ok(lsp_error) => lsp_server::Response::new_err(id, lsp_error.code, lsp_error.message),
 +            Err(e) => match e.downcast::<Cancelled>() {
 +                Ok(cancelled) => return Err(*cancelled),
 +                Err(e) => lsp_server::Response::new_err(
 +                    id,
 +                    lsp_server::ErrorCode::InternalError as i32,
 +                    e.to_string(),
 +                ),
 +            },
 +        },
 +    };
 +    Ok(res)
 +}
 +
 +pub(crate) struct NotificationDispatcher<'a> {
 +    pub(crate) not: Option<lsp_server::Notification>,
 +    pub(crate) global_state: &'a mut GlobalState,
 +}
 +
 +impl<'a> NotificationDispatcher<'a> {
 +    pub(crate) fn on<N>(
 +        &mut self,
 +        f: fn(&mut GlobalState, N::Params) -> Result<()>,
 +    ) -> Result<&mut Self>
 +    where
 +        N: lsp_types::notification::Notification,
 +        N::Params: DeserializeOwned + Send,
 +    {
 +        let not = match self.not.take() {
 +            Some(it) => it,
 +            None => return Ok(self),
 +        };
 +        let params = match not.extract::<N::Params>(N::METHOD) {
 +            Ok(it) => it,
 +            Err(ExtractError::JsonError { method, error }) => {
 +                panic!("Invalid request\nMethod: {method}\n error: {error}",)
 +            }
 +            Err(ExtractError::MethodMismatch(not)) => {
 +                self.not = Some(not);
 +                return Ok(self);
 +            }
 +        };
 +        let _pctx = stdx::panic_context::enter(format!(
 +            "\nversion: {}\nnotification: {}",
 +            version(),
 +            N::METHOD
 +        ));
 +        f(self.global_state, params)?;
 +        Ok(self)
 +    }
 +
 +    pub(crate) fn finish(&mut self) {
 +        if let Some(not) = &self.not {
 +            if !not.method.starts_with("$/") {
 +                tracing::error!("unhandled notification: {:?}", not);
 +            }
 +        }
 +    }
 +}
index 000ff88e458f6e4256a227138490369d9cbbbfb1,0000000000000000000000000000000000000000..3fb06c31f7ca792c068e1dcf81e1dab7c7f8af9c
mode 100644,000000..100644
--- /dev/null
@@@ -1,428 -1,0 +1,434 @@@
-     pub(crate) flycheck: Vec<FlycheckHandle>,
 +//! The context or environment in which the language server functions. In our
 +//! server implementation this is know as the `WorldState`.
 +//!
 +//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
 +
 +use std::{sync::Arc, time::Instant};
 +
 +use crossbeam_channel::{unbounded, Receiver, Sender};
 +use flycheck::FlycheckHandle;
 +use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId};
 +use ide_db::base_db::{CrateId, FileLoader, SourceDatabase};
 +use lsp_types::{SemanticTokens, Url};
 +use parking_lot::{Mutex, RwLock};
 +use proc_macro_api::ProcMacroServer;
 +use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
 +use rustc_hash::FxHashMap;
 +use stdx::hash::NoHashHashMap;
 +use vfs::AnchoredPathBuf;
 +
 +use crate::{
 +    config::Config,
 +    diagnostics::{CheckFixes, DiagnosticCollection},
 +    from_proto,
 +    line_index::{LineEndings, LineIndex},
 +    lsp_ext,
 +    main_loop::Task,
 +    mem_docs::MemDocs,
 +    op_queue::OpQueue,
 +    reload::{self, SourceRootConfig},
 +    task_pool::TaskPool,
 +    to_proto::url_from_abs_path,
 +    Result,
 +};
 +
 +// Enforces drop order
 +pub(crate) struct Handle<H, C> {
 +    pub(crate) handle: H,
 +    pub(crate) receiver: C,
 +}
 +
 +pub(crate) type ReqHandler = fn(&mut GlobalState, lsp_server::Response);
 +pub(crate) type ReqQueue = lsp_server::ReqQueue<(String, Instant), ReqHandler>;
 +
 +/// `GlobalState` is the primary mutable state of the language server
 +///
 +/// The most interesting components are `vfs`, which stores a consistent
 +/// snapshot of the file systems, and `analysis_host`, which stores our
 +/// incremental salsa database.
 +///
 +/// Note that this struct has more than one impl in various modules!
 +pub(crate) struct GlobalState {
 +    sender: Sender<lsp_server::Message>,
 +    req_queue: ReqQueue,
 +    pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
 +    pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>,
 +    pub(crate) config: Arc<Config>,
 +    pub(crate) analysis_host: AnalysisHost,
 +    pub(crate) diagnostics: DiagnosticCollection,
 +    pub(crate) mem_docs: MemDocs,
 +    pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
 +    pub(crate) shutdown_requested: bool,
 +    pub(crate) proc_macro_changed: bool,
 +    pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>,
 +    pub(crate) source_root_config: SourceRootConfig,
 +    pub(crate) proc_macro_clients: Vec<Result<ProcMacroServer, String>>,
 +
-             flycheck: Vec::new(),
++    pub(crate) flycheck: Arc<[FlycheckHandle]>,
 +    pub(crate) flycheck_sender: Sender<flycheck::Message>,
 +    pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
 +
 +    pub(crate) vfs: Arc<RwLock<(vfs::Vfs, NoHashHashMap<FileId, LineEndings>)>>,
 +    pub(crate) vfs_config_version: u32,
 +    pub(crate) vfs_progress_config_version: u32,
 +    pub(crate) vfs_progress_n_total: usize,
 +    pub(crate) vfs_progress_n_done: usize,
 +
 +    /// `workspaces` field stores the data we actually use, while the `OpQueue`
 +    /// stores the result of the last fetch.
 +    ///
 +    /// If the fetch (partially) fails, we do not update the current value.
 +    ///
 +    /// The handling of build data is subtle. We fetch workspace in two phases:
 +    ///
 +    /// *First*, we run `cargo metadata`, which gives us fast results for
 +    /// initial analysis.
 +    ///
 +    /// *Second*, we run `cargo check` which runs build scripts and compiles
 +    /// proc macros.
 +    ///
 +    /// We need both for the precise analysis, but we want rust-analyzer to be
 +    /// at least partially available just after the first phase. That's because
 +    /// first phase is much faster, and is much less likely to fail.
 +    ///
 +    /// This creates a complication -- by the time the second phase completes,
 +    /// the results of the fist phase could be invalid. That is, while we run
 +    /// `cargo check`, the user edits `Cargo.toml`, we notice this, and the new
 +    /// `cargo metadata` completes before `cargo check`.
 +    ///
 +    /// An additional complication is that we want to avoid needless work. When
 +    /// the user just adds comments or whitespace to Cargo.toml, we do not want
 +    /// to invalidate any salsa caches.
 +    pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
 +    pub(crate) fetch_workspaces_queue: OpQueue<Vec<anyhow::Result<ProjectWorkspace>>>,
 +    pub(crate) fetch_build_data_queue:
 +        OpQueue<(Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>)>,
 +
 +    pub(crate) prime_caches_queue: OpQueue<()>,
 +}
 +
 +/// An immutable snapshot of the world's state at a point in time.
 +pub(crate) struct GlobalStateSnapshot {
 +    pub(crate) config: Arc<Config>,
 +    pub(crate) analysis: Analysis,
 +    pub(crate) check_fixes: CheckFixes,
 +    mem_docs: MemDocs,
 +    pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
 +    vfs: Arc<RwLock<(vfs::Vfs, NoHashHashMap<FileId, LineEndings>)>>,
 +    pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
 +    pub(crate) proc_macros_loaded: bool,
++    pub(crate) flycheck: Arc<[FlycheckHandle]>,
 +}
 +
 +impl std::panic::UnwindSafe for GlobalStateSnapshot {}
 +
 +impl GlobalState {
 +    pub(crate) fn new(sender: Sender<lsp_server::Message>, config: Config) -> GlobalState {
 +        let loader = {
 +            let (sender, receiver) = unbounded::<vfs::loader::Message>();
 +            let handle: vfs_notify::NotifyHandle =
 +                vfs::loader::Handle::spawn(Box::new(move |msg| sender.send(msg).unwrap()));
 +            let handle = Box::new(handle) as Box<dyn vfs::loader::Handle>;
 +            Handle { handle, receiver }
 +        };
 +
 +        let task_pool = {
 +            let (sender, receiver) = unbounded();
 +            let handle = TaskPool::new(sender);
 +            Handle { handle, receiver }
 +        };
 +
 +        let analysis_host = AnalysisHost::new(config.lru_capacity());
 +        let (flycheck_sender, flycheck_receiver) = unbounded();
 +        let mut this = GlobalState {
 +            sender,
 +            req_queue: ReqQueue::default(),
 +            task_pool,
 +            loader,
 +            config: Arc::new(config.clone()),
 +            analysis_host,
 +            diagnostics: Default::default(),
 +            mem_docs: MemDocs::default(),
 +            semantic_tokens_cache: Arc::new(Default::default()),
 +            shutdown_requested: false,
 +            proc_macro_changed: false,
 +            last_reported_status: None,
 +            source_root_config: SourceRootConfig::default(),
 +            proc_macro_clients: vec![],
 +
++            flycheck: Arc::new([]),
 +            flycheck_sender,
 +            flycheck_receiver,
 +
 +            vfs: Arc::new(RwLock::new((vfs::Vfs::default(), NoHashHashMap::default()))),
 +            vfs_config_version: 0,
 +            vfs_progress_config_version: 0,
 +            vfs_progress_n_total: 0,
 +            vfs_progress_n_done: 0,
 +
 +            workspaces: Arc::new(Vec::new()),
 +            fetch_workspaces_queue: OpQueue::default(),
 +            prime_caches_queue: OpQueue::default(),
 +
 +            fetch_build_data_queue: OpQueue::default(),
 +        };
 +        // Apply any required database inputs from the config.
 +        this.update_configuration(config);
 +        this
 +    }
 +
 +    pub(crate) fn process_changes(&mut self) -> bool {
 +        let _p = profile::span("GlobalState::process_changes");
 +        // A file was added or deleted
 +        let mut has_structure_changes = false;
 +        let mut workspace_structure_change = None;
 +
 +        let (change, changed_files) = {
 +            let mut change = Change::new();
 +            let (vfs, line_endings_map) = &mut *self.vfs.write();
 +            let mut changed_files = vfs.take_changes();
 +            if changed_files.is_empty() {
 +                return false;
 +            }
 +
 +            // important: this needs to be a stable sort, the order between changes is relevant
 +            // for the same file ids
 +            changed_files.sort_by_key(|file| file.file_id);
 +            // We need to fix up the changed events a bit, if we have a create or modify for a file
 +            // id that is followed by a delete we actually no longer observe the file text from the
 +            // create or modify which may cause problems later on
 +            changed_files.dedup_by(|a, b| {
 +                use vfs::ChangeKind::*;
 +
 +                if a.file_id != b.file_id {
 +                    return false;
 +                }
 +
 +                match (a.change_kind, b.change_kind) {
 +                    // duplicate can be merged
 +                    (Create, Create) | (Modify, Modify) | (Delete, Delete) => true,
 +                    // just leave the create, modify is irrelevant
 +                    (Create, Modify) => {
 +                        std::mem::swap(a, b);
 +                        true
 +                    }
 +                    // modify becomes irrelevant if the file is deleted
 +                    (Modify, Delete) => true,
 +                    // we should fully remove this occurrence,
 +                    // but leaving just a delete works as well
 +                    (Create, Delete) => true,
 +                    // this is equivalent to a modify
 +                    (Delete, Create) => {
 +                        a.change_kind = Modify;
 +                        true
 +                    }
 +                    // can't really occur
 +                    (Modify, Create) => false,
 +                    (Delete, Modify) => false,
 +                }
 +            });
 +
 +            for file in &changed_files {
 +                if let Some(path) = vfs.file_path(file.file_id).as_path() {
 +                    let path = path.to_path_buf();
 +                    if reload::should_refresh_for_change(&path, file.change_kind) {
 +                        workspace_structure_change = Some(path);
 +                    }
 +                    if file.is_created_or_deleted() {
 +                        has_structure_changes = true;
 +                    }
 +                }
 +
 +                // Clear native diagnostics when their file gets deleted
 +                if !file.exists() {
 +                    self.diagnostics.clear_native_for(file.file_id);
 +                }
 +
 +                let text = if file.exists() {
 +                    let bytes = vfs.file_contents(file.file_id).to_vec();
 +                    String::from_utf8(bytes).ok().and_then(|text| {
 +                        let (text, line_endings) = LineEndings::normalize(text);
 +                        line_endings_map.insert(file.file_id, line_endings);
 +                        Some(Arc::new(text))
 +                    })
 +                } else {
 +                    None
 +                };
 +                change.change_file(file.file_id, text);
 +            }
 +            if has_structure_changes {
 +                let roots = self.source_root_config.partition(vfs);
 +                change.set_roots(roots);
 +            }
 +            (change, changed_files)
 +        };
 +
 +        self.analysis_host.apply_change(change);
 +
 +        {
 +            let raw_database = self.analysis_host.raw_database();
 +            // FIXME: ideally we should only trigger a workspace fetch for non-library changes
 +            // but somethings going wrong with the source root business when we add a new local
 +            // crate see https://github.com/rust-lang/rust-analyzer/issues/13029
 +            if let Some(path) = workspace_structure_change {
 +                self.fetch_workspaces_queue
 +                    .request_op(format!("workspace vfs file change: {}", path.display()));
 +            }
 +            self.proc_macro_changed =
 +                changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| {
 +                    let crates = raw_database.relevant_crates(file.file_id);
 +                    let crate_graph = raw_database.crate_graph();
 +
 +                    crates.iter().any(|&krate| crate_graph[krate].is_proc_macro)
 +                });
 +        }
 +
 +        true
 +    }
 +
 +    pub(crate) fn snapshot(&self) -> GlobalStateSnapshot {
 +        GlobalStateSnapshot {
 +            config: Arc::clone(&self.config),
 +            workspaces: Arc::clone(&self.workspaces),
 +            analysis: self.analysis_host.analysis(),
 +            vfs: Arc::clone(&self.vfs),
 +            check_fixes: Arc::clone(&self.diagnostics.check_fixes),
 +            mem_docs: self.mem_docs.clone(),
 +            semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache),
 +            proc_macros_loaded: !self.fetch_build_data_queue.last_op_result().0.is_empty(),
++            flycheck: self.flycheck.clone(),
 +        }
 +    }
 +
 +    pub(crate) fn send_request<R: lsp_types::request::Request>(
 +        &mut self,
 +        params: R::Params,
 +        handler: ReqHandler,
 +    ) {
 +        let request = self.req_queue.outgoing.register(R::METHOD.to_string(), params, handler);
 +        self.send(request.into());
 +    }
 +
 +    pub(crate) fn complete_request(&mut self, response: lsp_server::Response) {
 +        let handler = self
 +            .req_queue
 +            .outgoing
 +            .complete(response.id.clone())
 +            .expect("received response for unknown request");
 +        handler(self, response)
 +    }
 +
 +    pub(crate) fn send_notification<N: lsp_types::notification::Notification>(
 +        &mut self,
 +        params: N::Params,
 +    ) {
 +        let not = lsp_server::Notification::new(N::METHOD.to_string(), params);
 +        self.send(not.into());
 +    }
 +
 +    pub(crate) fn register_request(
 +        &mut self,
 +        request: &lsp_server::Request,
 +        request_received: Instant,
 +    ) {
 +        self.req_queue
 +            .incoming
 +            .register(request.id.clone(), (request.method.clone(), request_received));
 +    }
 +
 +    pub(crate) fn respond(&mut self, response: lsp_server::Response) {
 +        if let Some((method, start)) = self.req_queue.incoming.complete(response.id.clone()) {
 +            if let Some(err) = &response.error {
 +                if err.message.starts_with("server panicked") {
 +                    self.poke_rust_analyzer_developer(format!("{}, check the log", err.message))
 +                }
 +            }
 +
 +            let duration = start.elapsed();
 +            tracing::debug!("handled {} - ({}) in {:0.2?}", method, response.id, duration);
 +            self.send(response.into());
 +        }
 +    }
 +
 +    pub(crate) fn cancel(&mut self, request_id: lsp_server::RequestId) {
 +        if let Some(response) = self.req_queue.incoming.cancel(request_id) {
 +            self.send(response.into());
 +        }
 +    }
 +
 +    pub(crate) fn is_completed(&self, request: &lsp_server::Request) -> bool {
 +        self.req_queue.incoming.is_completed(&request.id)
 +    }
 +
 +    fn send(&mut self, message: lsp_server::Message) {
 +        self.sender.send(message).unwrap()
 +    }
 +}
 +
 +impl Drop for GlobalState {
 +    fn drop(&mut self) {
 +        self.analysis_host.request_cancellation();
 +    }
 +}
 +
 +impl GlobalStateSnapshot {
 +    pub(crate) fn url_to_file_id(&self, url: &Url) -> Result<FileId> {
 +        url_to_file_id(&self.vfs.read().0, url)
 +    }
 +
 +    pub(crate) fn file_id_to_url(&self, id: FileId) -> Url {
 +        file_id_to_url(&self.vfs.read().0, id)
 +    }
 +
 +    pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancellable<LineIndex> {
 +        let endings = self.vfs.read().1[&file_id];
 +        let index = self.analysis.file_line_index(file_id)?;
 +        let res = LineIndex { index, endings, encoding: self.config.offset_encoding() };
 +        Ok(res)
 +    }
 +
 +    pub(crate) fn url_file_version(&self, url: &Url) -> Option<i32> {
 +        let path = from_proto::vfs_path(url).ok()?;
 +        Some(self.mem_docs.get(&path)?.version)
 +    }
 +
 +    pub(crate) fn anchored_path(&self, path: &AnchoredPathBuf) -> Url {
 +        let mut base = self.vfs.read().0.file_path(path.anchor);
 +        base.pop();
 +        let path = base.join(&path.path).unwrap();
 +        let path = path.as_path().unwrap();
 +        url_from_abs_path(path)
 +    }
 +
++    pub(crate) fn file_id_to_file_path(&self, file_id: FileId) -> vfs::VfsPath {
++        self.vfs.read().0.file_path(file_id)
++    }
++
 +    pub(crate) fn cargo_target_for_crate_root(
 +        &self,
 +        crate_id: CrateId,
 +    ) -> Option<(&CargoWorkspace, Target)> {
 +        let file_id = self.analysis.crate_root(crate_id).ok()?;
 +        let path = self.vfs.read().0.file_path(file_id);
 +        let path = path.as_path()?;
 +        self.workspaces.iter().find_map(|ws| match ws {
 +            ProjectWorkspace::Cargo { cargo, .. } => {
 +                cargo.target_by_root(path).map(|it| (cargo, it))
 +            }
 +            ProjectWorkspace::Json { .. } => None,
 +            ProjectWorkspace::DetachedFiles { .. } => None,
 +        })
 +    }
 +}
 +
 +pub(crate) fn file_id_to_url(vfs: &vfs::Vfs, id: FileId) -> Url {
 +    let path = vfs.file_path(id);
 +    let path = path.as_path().unwrap();
 +    url_from_abs_path(path)
 +}
 +
 +pub(crate) fn url_to_file_id(vfs: &vfs::Vfs, url: &Url) -> Result<FileId> {
 +    let path = from_proto::vfs_path(url)?;
 +    let res = vfs.file_id(&path).ok_or_else(|| format!("file not found: {}", path))?;
 +    Ok(res)
 +}
index 8c3ea77d0611587c2f7f7b94083f5d4764d0cf6b,0000000000000000000000000000000000000000..34795a8eb40ab7844e11af047f8127b16a814247
mode 100644,000000..100644
--- /dev/null
@@@ -1,1920 -1,0 +1,1926 @@@
-         let crate_id = match snap.analysis.crate_for(file_id)?.first() {
 +//! This module is responsible for implementing handlers for Language Server
 +//! Protocol. The majority of requests are fulfilled by calling into the
 +//! `ide` crate.
 +
 +use std::{
 +    io::Write as _,
 +    process::{self, Stdio},
 +};
 +
 +use anyhow::Context;
 +use ide::{
 +    AnnotationConfig, AssistKind, AssistResolveStrategy, FileId, FilePosition, FileRange,
 +    HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind,
 +    SingleResolve, SourceChange, TextEdit,
 +};
 +use ide_db::SymbolKind;
 +use lsp_server::ErrorCode;
 +use lsp_types::{
 +    CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem,
 +    CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams,
 +    CodeLens, CompletionItem, Diagnostic, DiagnosticTag, DocumentFormattingParams, FoldingRange,
 +    FoldingRangeParams, HoverContents, InlayHint, InlayHintParams, Location, LocationLink,
 +    NumberOrString, Position, PrepareRenameResponse, Range, RenameParams,
 +    SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams,
 +    SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation,
 +    SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
 +};
 +use project_model::{ManifestPath, ProjectWorkspace, TargetKind};
 +use serde_json::json;
 +use stdx::{format_to, never};
 +use syntax::{algo, ast, AstNode, TextRange, TextSize, T};
 +use vfs::AbsPathBuf;
 +
 +use crate::{
 +    cargo_target_spec::CargoTargetSpec,
 +    config::{RustfmtConfig, WorkspaceSymbolConfig},
 +    diff::diff,
 +    from_proto,
 +    global_state::{GlobalState, GlobalStateSnapshot},
 +    line_index::LineEndings,
 +    lsp_ext::{self, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams},
 +    lsp_utils::{all_edits_are_disjoint, invalid_params_error},
 +    to_proto, LspError, Result,
 +};
 +
 +pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result<()> {
 +    state.proc_macro_clients.clear();
 +    state.proc_macro_changed = false;
 +    state.fetch_workspaces_queue.request_op("reload workspace request".to_string());
 +    state.fetch_build_data_queue.request_op("reload workspace request".to_string());
 +    Ok(())
 +}
 +
 +pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> Result<()> {
 +    let _p = profile::span("handle_stop_flycheck");
 +    state.flycheck.iter().for_each(|flycheck| flycheck.cancel());
 +    Ok(())
 +}
 +
 +pub(crate) fn handle_analyzer_status(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::AnalyzerStatusParams,
 +) -> Result<String> {
 +    let _p = profile::span("handle_analyzer_status");
 +
 +    let mut buf = String::new();
 +
 +    let mut file_id = None;
 +    if let Some(tdi) = params.text_document {
 +        match from_proto::file_id(&snap, &tdi.uri) {
 +            Ok(it) => file_id = Some(it),
 +            Err(_) => format_to!(buf, "file {} not found in vfs", tdi.uri),
 +        }
 +    }
 +
 +    if snap.workspaces.is_empty() {
 +        buf.push_str("No workspaces\n")
 +    } else {
 +        buf.push_str("Workspaces:\n");
 +        format_to!(
 +            buf,
 +            "Loaded {:?} packages across {} workspace{}.\n",
 +            snap.workspaces.iter().map(|w| w.n_packages()).sum::<usize>(),
 +            snap.workspaces.len(),
 +            if snap.workspaces.len() == 1 { "" } else { "s" }
 +        );
 +    }
 +    buf.push_str("\nAnalysis:\n");
 +    buf.push_str(
 +        &snap
 +            .analysis
 +            .status(file_id)
 +            .unwrap_or_else(|_| "Analysis retrieval was cancelled".to_owned()),
 +    );
 +    Ok(buf)
 +}
 +
 +pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> Result<String> {
 +    let _p = profile::span("handle_memory_usage");
 +    let mut mem = state.analysis_host.per_query_memory_usage();
 +    mem.push(("Remaining".into(), profile::memory_usage().allocated));
 +
 +    let mut out = String::new();
 +    for (name, bytes) in mem {
 +        format_to!(out, "{:>8} {}\n", bytes, name);
 +    }
 +    Ok(out)
 +}
 +
 +pub(crate) fn handle_shuffle_crate_graph(state: &mut GlobalState, _: ()) -> Result<()> {
 +    state.analysis_host.shuffle_crate_graph();
 +    Ok(())
 +}
 +
 +pub(crate) fn handle_syntax_tree(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::SyntaxTreeParams,
 +) -> Result<String> {
 +    let _p = profile::span("handle_syntax_tree");
 +    let id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(id)?;
 +    let text_range = params.range.and_then(|r| from_proto::text_range(&line_index, r).ok());
 +    let res = snap.analysis.syntax_tree(id, text_range)?;
 +    Ok(res)
 +}
 +
 +pub(crate) fn handle_view_hir(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<String> {
 +    let _p = profile::span("handle_view_hir");
 +    let position = from_proto::file_position(&snap, params)?;
 +    let res = snap.analysis.view_hir(position)?;
 +    Ok(res)
 +}
 +
 +pub(crate) fn handle_view_file_text(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentIdentifier,
 +) -> Result<String> {
 +    let file_id = from_proto::file_id(&snap, &params.uri)?;
 +    Ok(snap.analysis.file_text(file_id)?.to_string())
 +}
 +
 +pub(crate) fn handle_view_item_tree(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::ViewItemTreeParams,
 +) -> Result<String> {
 +    let _p = profile::span("handle_view_item_tree");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let res = snap.analysis.view_item_tree(file_id)?;
 +    Ok(res)
 +}
 +
 +pub(crate) fn handle_view_crate_graph(
 +    snap: GlobalStateSnapshot,
 +    params: ViewCrateGraphParams,
 +) -> Result<String> {
 +    let _p = profile::span("handle_view_crate_graph");
 +    let dot = snap.analysis.view_crate_graph(params.full)??;
 +    Ok(dot)
 +}
 +
 +pub(crate) fn handle_expand_macro(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::ExpandMacroParams,
 +) -> Result<Option<lsp_ext::ExpandedMacro>> {
 +    let _p = profile::span("handle_expand_macro");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let offset = from_proto::offset(&line_index, params.position)?;
 +
 +    let res = snap.analysis.expand_macro(FilePosition { file_id, offset })?;
 +    Ok(res.map(|it| lsp_ext::ExpandedMacro { name: it.name, expansion: it.expansion }))
 +}
 +
 +pub(crate) fn handle_selection_range(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::SelectionRangeParams,
 +) -> Result<Option<Vec<lsp_types::SelectionRange>>> {
 +    let _p = profile::span("handle_selection_range");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let res: Result<Vec<lsp_types::SelectionRange>> = params
 +        .positions
 +        .into_iter()
 +        .map(|position| {
 +            let offset = from_proto::offset(&line_index, position)?;
 +            let mut ranges = Vec::new();
 +            {
 +                let mut range = TextRange::new(offset, offset);
 +                loop {
 +                    ranges.push(range);
 +                    let frange = FileRange { file_id, range };
 +                    let next = snap.analysis.extend_selection(frange)?;
 +                    if next == range {
 +                        break;
 +                    } else {
 +                        range = next
 +                    }
 +                }
 +            }
 +            let mut range = lsp_types::SelectionRange {
 +                range: to_proto::range(&line_index, *ranges.last().unwrap()),
 +                parent: None,
 +            };
 +            for &r in ranges.iter().rev().skip(1) {
 +                range = lsp_types::SelectionRange {
 +                    range: to_proto::range(&line_index, r),
 +                    parent: Some(Box::new(range)),
 +                }
 +            }
 +            Ok(range)
 +        })
 +        .collect();
 +
 +    Ok(Some(res?))
 +}
 +
 +pub(crate) fn handle_matching_brace(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::MatchingBraceParams,
 +) -> Result<Vec<Position>> {
 +    let _p = profile::span("handle_matching_brace");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    params
 +        .positions
 +        .into_iter()
 +        .map(|position| {
 +            let offset = from_proto::offset(&line_index, position);
 +            offset.map(|offset| {
 +                let offset = match snap.analysis.matching_brace(FilePosition { file_id, offset }) {
 +                    Ok(Some(matching_brace_offset)) => matching_brace_offset,
 +                    Err(_) | Ok(None) => offset,
 +                };
 +                to_proto::position(&line_index, offset)
 +            })
 +        })
 +        .collect()
 +}
 +
 +pub(crate) fn handle_join_lines(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::JoinLinesParams,
 +) -> Result<Vec<lsp_types::TextEdit>> {
 +    let _p = profile::span("handle_join_lines");
 +
 +    let config = snap.config.join_lines();
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let mut res = TextEdit::default();
 +    for range in params.ranges {
 +        let range = from_proto::text_range(&line_index, range)?;
 +        let edit = snap.analysis.join_lines(&config, FileRange { file_id, range })?;
 +        match res.union(edit) {
 +            Ok(()) => (),
 +            Err(_edit) => {
 +                // just ignore overlapping edits
 +            }
 +        }
 +    }
 +
 +    Ok(to_proto::text_edit_vec(&line_index, res))
 +}
 +
 +pub(crate) fn handle_on_enter(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<Option<Vec<lsp_ext::SnippetTextEdit>>> {
 +    let _p = profile::span("handle_on_enter");
 +    let position = from_proto::file_position(&snap, params)?;
 +    let edit = match snap.analysis.on_enter(position)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +    let line_index = snap.file_line_index(position.file_id)?;
 +    let edit = to_proto::snippet_text_edit_vec(&line_index, true, edit);
 +    Ok(Some(edit))
 +}
 +
 +pub(crate) fn handle_on_type_formatting(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::DocumentOnTypeFormattingParams,
 +) -> Result<Option<Vec<lsp_ext::SnippetTextEdit>>> {
 +    let _p = profile::span("handle_on_type_formatting");
 +    let mut position = from_proto::file_position(&snap, params.text_document_position)?;
 +    let line_index = snap.file_line_index(position.file_id)?;
 +
 +    // in `ide`, the `on_type` invariant is that
 +    // `text.char_at(position) == typed_char`.
 +    position.offset -= TextSize::of('.');
 +    let char_typed = params.ch.chars().next().unwrap_or('\0');
 +
 +    let text = snap.analysis.file_text(position.file_id)?;
 +    if stdx::never!(!text[usize::from(position.offset)..].starts_with(char_typed)) {
 +        return Ok(None);
 +    }
 +
 +    // We have an assist that inserts ` ` after typing `->` in `fn foo() ->{`,
 +    // but it requires precise cursor positioning to work, and one can't
 +    // position the cursor with on_type formatting. So, let's just toggle this
 +    // feature off here, hoping that we'll enable it one day, 😿.
 +    if char_typed == '>' {
 +        return Ok(None);
 +    }
 +
 +    let edit =
 +        snap.analysis.on_char_typed(position, char_typed, snap.config.typing_autoclose_angle())?;
 +    let edit = match edit {
 +        Some(it) => it,
 +        None => return Ok(None),
 +    };
 +
 +    // This should be a single-file edit
 +    let (_, text_edit) = edit.source_file_edits.into_iter().next().unwrap();
 +
 +    let change = to_proto::snippet_text_edit_vec(&line_index, edit.is_snippet, text_edit);
 +    Ok(Some(change))
 +}
 +
 +pub(crate) fn handle_document_symbol(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::DocumentSymbolParams,
 +) -> Result<Option<lsp_types::DocumentSymbolResponse>> {
 +    let _p = profile::span("handle_document_symbol");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let mut parents: Vec<(lsp_types::DocumentSymbol, Option<usize>)> = Vec::new();
 +
 +    for symbol in snap.analysis.file_structure(file_id)? {
 +        let mut tags = Vec::new();
 +        if symbol.deprecated {
 +            tags.push(SymbolTag::DEPRECATED)
 +        };
 +
 +        #[allow(deprecated)]
 +        let doc_symbol = lsp_types::DocumentSymbol {
 +            name: symbol.label,
 +            detail: symbol.detail,
 +            kind: to_proto::structure_node_kind(symbol.kind),
 +            tags: Some(tags),
 +            deprecated: Some(symbol.deprecated),
 +            range: to_proto::range(&line_index, symbol.node_range),
 +            selection_range: to_proto::range(&line_index, symbol.navigation_range),
 +            children: None,
 +        };
 +        parents.push((doc_symbol, symbol.parent));
 +    }
 +
 +    // Builds hierarchy from a flat list, in reverse order (so that indices
 +    // makes sense)
 +    let document_symbols = {
 +        let mut acc = Vec::new();
 +        while let Some((mut node, parent_idx)) = parents.pop() {
 +            if let Some(children) = &mut node.children {
 +                children.reverse();
 +            }
 +            let parent = match parent_idx {
 +                None => &mut acc,
 +                Some(i) => parents[i].0.children.get_or_insert_with(Vec::new),
 +            };
 +            parent.push(node);
 +        }
 +        acc.reverse();
 +        acc
 +    };
 +
 +    let res = if snap.config.hierarchical_symbols() {
 +        document_symbols.into()
 +    } else {
 +        let url = to_proto::url(&snap, file_id);
 +        let mut symbol_information = Vec::<SymbolInformation>::new();
 +        for symbol in document_symbols {
 +            flatten_document_symbol(&symbol, None, &url, &mut symbol_information);
 +        }
 +        symbol_information.into()
 +    };
 +    return Ok(Some(res));
 +
 +    fn flatten_document_symbol(
 +        symbol: &lsp_types::DocumentSymbol,
 +        container_name: Option<String>,
 +        url: &Url,
 +        res: &mut Vec<SymbolInformation>,
 +    ) {
 +        let mut tags = Vec::new();
 +
 +        #[allow(deprecated)]
 +        if let Some(true) = symbol.deprecated {
 +            tags.push(SymbolTag::DEPRECATED)
 +        }
 +
 +        #[allow(deprecated)]
 +        res.push(SymbolInformation {
 +            name: symbol.name.clone(),
 +            kind: symbol.kind,
 +            tags: Some(tags),
 +            deprecated: symbol.deprecated,
 +            location: Location::new(url.clone(), symbol.range),
 +            container_name,
 +        });
 +
 +        for child in symbol.children.iter().flatten() {
 +            flatten_document_symbol(child, Some(symbol.name.clone()), url, res);
 +        }
 +    }
 +}
 +
 +pub(crate) fn handle_workspace_symbol(
 +    snap: GlobalStateSnapshot,
 +    params: WorkspaceSymbolParams,
 +) -> Result<Option<Vec<SymbolInformation>>> {
 +    let _p = profile::span("handle_workspace_symbol");
 +
 +    let config = snap.config.workspace_symbol();
 +    let (all_symbols, libs) = decide_search_scope_and_kind(&params, &config);
 +    let limit = config.search_limit;
 +
 +    let query = {
 +        let query: String = params.query.chars().filter(|&c| c != '#' && c != '*').collect();
 +        let mut q = Query::new(query);
 +        if !all_symbols {
 +            q.only_types();
 +        }
 +        if libs {
 +            q.libs();
 +        }
 +        q.limit(limit);
 +        q
 +    };
 +    let mut res = exec_query(&snap, query)?;
 +    if res.is_empty() && !all_symbols {
 +        let mut query = Query::new(params.query);
 +        query.limit(limit);
 +        res = exec_query(&snap, query)?;
 +    }
 +
 +    return Ok(Some(res));
 +
 +    fn decide_search_scope_and_kind(
 +        params: &WorkspaceSymbolParams,
 +        config: &WorkspaceSymbolConfig,
 +    ) -> (bool, bool) {
 +        // Support old-style parsing of markers in the query.
 +        let mut all_symbols = params.query.contains('#');
 +        let mut libs = params.query.contains('*');
 +
 +        // If no explicit marker was set, check request params. If that's also empty
 +        // use global config.
 +        if !all_symbols {
 +            let search_kind = match params.search_kind {
 +                Some(ref search_kind) => search_kind,
 +                None => &config.search_kind,
 +            };
 +            all_symbols = match search_kind {
 +                lsp_ext::WorkspaceSymbolSearchKind::OnlyTypes => false,
 +                lsp_ext::WorkspaceSymbolSearchKind::AllSymbols => true,
 +            }
 +        }
 +
 +        if !libs {
 +            let search_scope = match params.search_scope {
 +                Some(ref search_scope) => search_scope,
 +                None => &config.search_scope,
 +            };
 +            libs = match search_scope {
 +                lsp_ext::WorkspaceSymbolSearchScope::Workspace => false,
 +                lsp_ext::WorkspaceSymbolSearchScope::WorkspaceAndDependencies => true,
 +            }
 +        }
 +
 +        (all_symbols, libs)
 +    }
 +
 +    fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> {
 +        let mut res = Vec::new();
 +        for nav in snap.analysis.symbol_search(query)? {
 +            let container_name = nav.container_name.as_ref().map(|v| v.to_string());
 +
 +            #[allow(deprecated)]
 +            let info = SymbolInformation {
 +                name: nav.name.to_string(),
 +                kind: nav
 +                    .kind
 +                    .map(to_proto::symbol_kind)
 +                    .unwrap_or(lsp_types::SymbolKind::VARIABLE),
 +                tags: None,
 +                location: to_proto::location_from_nav(snap, nav)?,
 +                container_name,
 +                deprecated: None,
 +            };
 +            res.push(info);
 +        }
 +        Ok(res)
 +    }
 +}
 +
 +pub(crate) fn handle_will_rename_files(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::RenameFilesParams,
 +) -> Result<Option<lsp_types::WorkspaceEdit>> {
 +    let _p = profile::span("handle_will_rename_files");
 +
 +    let source_changes: Vec<SourceChange> = params
 +        .files
 +        .into_iter()
 +        .filter_map(|file_rename| {
 +            let from = Url::parse(&file_rename.old_uri).ok()?;
 +            let to = Url::parse(&file_rename.new_uri).ok()?;
 +
 +            let from_path = from.to_file_path().ok()?;
 +            let to_path = to.to_file_path().ok()?;
 +
 +            // Limit to single-level moves for now.
 +            match (from_path.parent(), to_path.parent()) {
 +                (Some(p1), Some(p2)) if p1 == p2 => {
 +                    if from_path.is_dir() {
 +                        // add '/' to end of url -- from `file://path/to/folder` to `file://path/to/folder/`
 +                        let mut old_folder_name = from_path.file_stem()?.to_str()?.to_string();
 +                        old_folder_name.push('/');
 +                        let from_with_trailing_slash = from.join(&old_folder_name).ok()?;
 +
 +                        let imitate_from_url = from_with_trailing_slash.join("mod.rs").ok()?;
 +                        let new_file_name = to_path.file_name()?.to_str()?;
 +                        Some((
 +                            snap.url_to_file_id(&imitate_from_url).ok()?,
 +                            new_file_name.to_string(),
 +                        ))
 +                    } else {
 +                        let old_name = from_path.file_stem()?.to_str()?;
 +                        let new_name = to_path.file_stem()?.to_str()?;
 +                        match (old_name, new_name) {
 +                            ("mod", _) => None,
 +                            (_, "mod") => None,
 +                            _ => Some((snap.url_to_file_id(&from).ok()?, new_name.to_string())),
 +                        }
 +                    }
 +                }
 +                _ => None,
 +            }
 +        })
 +        .filter_map(|(file_id, new_name)| {
 +            snap.analysis.will_rename_file(file_id, &new_name).ok()?
 +        })
 +        .collect();
 +
 +    // Drop file system edits since we're just renaming things on the same level
 +    let mut source_changes = source_changes.into_iter();
 +    let mut source_change = source_changes.next().unwrap_or_default();
 +    source_change.file_system_edits.clear();
 +    // no collect here because we want to merge text edits on same file ids
 +    source_change.extend(source_changes.flat_map(|it| it.source_file_edits));
 +    if source_change.source_file_edits.is_empty() {
 +        Ok(None)
 +    } else {
 +        to_proto::workspace_edit(&snap, source_change).map(Some)
 +    }
 +}
 +
 +pub(crate) fn handle_goto_definition(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::GotoDefinitionParams,
 +) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
 +    let _p = profile::span("handle_goto_definition");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +    let nav_info = match snap.analysis.goto_definition(position)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +    let src = FileRange { file_id: position.file_id, range: nav_info.range };
 +    let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_goto_declaration(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::request::GotoDeclarationParams,
 +) -> Result<Option<lsp_types::request::GotoDeclarationResponse>> {
 +    let _p = profile::span("handle_goto_declaration");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params.clone())?;
 +    let nav_info = match snap.analysis.goto_declaration(position)? {
 +        None => return handle_goto_definition(snap, params),
 +        Some(it) => it,
 +    };
 +    let src = FileRange { file_id: position.file_id, range: nav_info.range };
 +    let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_goto_implementation(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::request::GotoImplementationParams,
 +) -> Result<Option<lsp_types::request::GotoImplementationResponse>> {
 +    let _p = profile::span("handle_goto_implementation");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +    let nav_info = match snap.analysis.goto_implementation(position)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +    let src = FileRange { file_id: position.file_id, range: nav_info.range };
 +    let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_goto_type_definition(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::request::GotoTypeDefinitionParams,
 +) -> Result<Option<lsp_types::request::GotoTypeDefinitionResponse>> {
 +    let _p = profile::span("handle_goto_type_definition");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +    let nav_info = match snap.analysis.goto_type_definition(position)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +    let src = FileRange { file_id: position.file_id, range: nav_info.range };
 +    let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_parent_module(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
 +    let _p = profile::span("handle_parent_module");
 +    if let Ok(file_path) = &params.text_document.uri.to_file_path() {
 +        if file_path.file_name().unwrap_or_default() == "Cargo.toml" {
 +            // search workspaces for parent packages or fallback to workspace root
 +            let abs_path_buf = match AbsPathBuf::try_from(file_path.to_path_buf()).ok() {
 +                Some(abs_path_buf) => abs_path_buf,
 +                None => return Ok(None),
 +            };
 +
 +            let manifest_path = match ManifestPath::try_from(abs_path_buf).ok() {
 +                Some(manifest_path) => manifest_path,
 +                None => return Ok(None),
 +            };
 +
 +            let links: Vec<LocationLink> = snap
 +                .workspaces
 +                .iter()
 +                .filter_map(|ws| match ws {
 +                    ProjectWorkspace::Cargo { cargo, .. } => cargo.parent_manifests(&manifest_path),
 +                    _ => None,
 +                })
 +                .flatten()
 +                .map(|parent_manifest_path| LocationLink {
 +                    origin_selection_range: None,
 +                    target_uri: to_proto::url_from_abs_path(&parent_manifest_path),
 +                    target_range: Range::default(),
 +                    target_selection_range: Range::default(),
 +                })
 +                .collect::<_>();
 +            return Ok(Some(links.into()));
 +        }
 +
 +        // check if invoked at the crate root
 +        let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
-     let crate_ids = snap.analysis.crate_for(file_id)?;
++        let crate_id = match snap.analysis.crates_for(file_id)?.first() {
 +            Some(&crate_id) => crate_id,
 +            None => return Ok(None),
 +        };
 +        let cargo_spec = match CargoTargetSpec::for_file(&snap, file_id)? {
 +            Some(it) => it,
 +            None => return Ok(None),
 +        };
 +
 +        if snap.analysis.crate_root(crate_id)? == file_id {
 +            let cargo_toml_url = to_proto::url_from_abs_path(&cargo_spec.cargo_toml);
 +            let res = vec![LocationLink {
 +                origin_selection_range: None,
 +                target_uri: cargo_toml_url,
 +                target_range: Range::default(),
 +                target_selection_range: Range::default(),
 +            }]
 +            .into();
 +            return Ok(Some(res));
 +        }
 +    }
 +
 +    // locate parent module by semantics
 +    let position = from_proto::file_position(&snap, params)?;
 +    let navs = snap.analysis.parent_module(position)?;
 +    let res = to_proto::goto_definition_response(&snap, None, navs)?;
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_runnables(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::RunnablesParams,
 +) -> Result<Vec<lsp_ext::Runnable>> {
 +    let _p = profile::span("handle_runnables");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let offset = params.position.and_then(|it| from_proto::offset(&line_index, it).ok());
 +    let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?;
 +
 +    let expect_test = match offset {
 +        Some(offset) => {
 +            let source_file = snap.analysis.parse(file_id)?;
 +            algo::find_node_at_offset::<ast::MacroCall>(source_file.syntax(), offset)
 +                .and_then(|it| it.path()?.segment()?.name_ref())
 +                .map_or(false, |it| it.text() == "expect" || it.text() == "expect_file")
 +        }
 +        None => false,
 +    };
 +
 +    let mut res = Vec::new();
 +    for runnable in snap.analysis.runnables(file_id)? {
 +        if should_skip_for_offset(&runnable, offset) {
 +            continue;
 +        }
 +        if should_skip_target(&runnable, cargo_spec.as_ref()) {
 +            continue;
 +        }
 +        let mut runnable = to_proto::runnable(&snap, runnable)?;
 +        if expect_test {
 +            runnable.label = format!("{} + expect", runnable.label);
 +            runnable.args.expect_test = Some(true);
 +        }
 +        res.push(runnable);
 +    }
 +
 +    // Add `cargo check` and `cargo test` for all targets of the whole package
 +    let config = snap.config.runnables();
 +    match cargo_spec {
 +        Some(spec) => {
 +            for cmd in ["check", "test"] {
 +                res.push(lsp_ext::Runnable {
 +                    label: format!("cargo {} -p {} --all-targets", cmd, spec.package),
 +                    location: None,
 +                    kind: lsp_ext::RunnableKind::Cargo,
 +                    args: lsp_ext::CargoRunnable {
 +                        workspace_root: Some(spec.workspace_root.clone().into()),
 +                        override_cargo: config.override_cargo.clone(),
 +                        cargo_args: vec![
 +                            cmd.to_string(),
 +                            "--package".to_string(),
 +                            spec.package.clone(),
 +                            "--all-targets".to_string(),
 +                        ],
 +                        cargo_extra_args: config.cargo_extra_args.clone(),
 +                        executable_args: Vec::new(),
 +                        expect_test: None,
 +                    },
 +                })
 +            }
 +        }
 +        None => {
 +            if !snap.config.linked_projects().is_empty()
 +                || !snap
 +                    .config
 +                    .discovered_projects
 +                    .as_ref()
 +                    .map(|projects| projects.is_empty())
 +                    .unwrap_or(true)
 +            {
 +                res.push(lsp_ext::Runnable {
 +                    label: "cargo check --workspace".to_string(),
 +                    location: None,
 +                    kind: lsp_ext::RunnableKind::Cargo,
 +                    args: lsp_ext::CargoRunnable {
 +                        workspace_root: None,
 +                        override_cargo: config.override_cargo,
 +                        cargo_args: vec!["check".to_string(), "--workspace".to_string()],
 +                        cargo_extra_args: config.cargo_extra_args,
 +                        executable_args: Vec::new(),
 +                        expect_test: None,
 +                    },
 +                });
 +            }
 +        }
 +    }
 +    Ok(res)
 +}
 +
 +fn should_skip_for_offset(runnable: &Runnable, offset: Option<TextSize>) -> bool {
 +    match offset {
 +        None => false,
 +        _ if matches!(&runnable.kind, RunnableKind::TestMod { .. }) => false,
 +        Some(offset) => !runnable.nav.full_range.contains_inclusive(offset),
 +    }
 +}
 +
 +pub(crate) fn handle_related_tests(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<Vec<lsp_ext::TestInfo>> {
 +    let _p = profile::span("handle_related_tests");
 +    let position = from_proto::file_position(&snap, params)?;
 +
 +    let tests = snap.analysis.related_tests(position, None)?;
 +    let mut res = Vec::new();
 +    for it in tests {
 +        if let Ok(runnable) = to_proto::runnable(&snap, it) {
 +            res.push(lsp_ext::TestInfo { runnable })
 +        }
 +    }
 +
 +    Ok(res)
 +}
 +
 +pub(crate) fn handle_completion(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::CompletionParams,
 +) -> Result<Option<lsp_types::CompletionResponse>> {
 +    let _p = profile::span("handle_completion");
 +    let text_document_position = params.text_document_position.clone();
 +    let position = from_proto::file_position(&snap, params.text_document_position)?;
 +    let completion_trigger_character =
 +        params.context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next());
 +
 +    if Some(':') == completion_trigger_character {
 +        let source_file = snap.analysis.parse(position.file_id)?;
 +        let left_token = source_file.syntax().token_at_offset(position.offset).left_biased();
 +        let completion_triggered_after_single_colon = match left_token {
 +            Some(left_token) => left_token.kind() == T![:],
 +            None => true,
 +        };
 +        if completion_triggered_after_single_colon {
 +            return Ok(None);
 +        }
 +    }
 +
 +    let completion_config = &snap.config.completion();
 +    let items = match snap.analysis.completions(
 +        completion_config,
 +        position,
 +        completion_trigger_character,
 +    )? {
 +        None => return Ok(None),
 +        Some(items) => items,
 +    };
 +    let line_index = snap.file_line_index(position.file_id)?;
 +
 +    let items =
 +        to_proto::completion_items(&snap.config, &line_index, text_document_position, items);
 +
 +    let completion_list = lsp_types::CompletionList { is_incomplete: true, items };
 +    Ok(Some(completion_list.into()))
 +}
 +
 +pub(crate) fn handle_completion_resolve(
 +    snap: GlobalStateSnapshot,
 +    mut original_completion: CompletionItem,
 +) -> Result<CompletionItem> {
 +    let _p = profile::span("handle_completion_resolve");
 +
 +    if !all_edits_are_disjoint(&original_completion, &[]) {
 +        return Err(invalid_params_error(
 +            "Received a completion with overlapping edits, this is not LSP-compliant".to_string(),
 +        )
 +        .into());
 +    }
 +
 +    let data = match original_completion.data.take() {
 +        Some(it) => it,
 +        None => return Ok(original_completion),
 +    };
 +
 +    let resolve_data: lsp_ext::CompletionResolveData = serde_json::from_value(data)?;
 +
 +    let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let offset = from_proto::offset(&line_index, resolve_data.position.position)?;
 +
 +    let additional_edits = snap
 +        .analysis
 +        .resolve_completion_edits(
 +            &snap.config.completion(),
 +            FilePosition { file_id, offset },
 +            resolve_data
 +                .imports
 +                .into_iter()
 +                .map(|import| (import.full_import_path, import.imported_name)),
 +        )?
 +        .into_iter()
 +        .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel)))
 +        .collect::<Vec<_>>();
 +
 +    if !all_edits_are_disjoint(&original_completion, &additional_edits) {
 +        return Err(LspError::new(
 +            ErrorCode::InternalError as i32,
 +            "Import edit overlaps with the original completion edits, this is not LSP-compliant"
 +                .into(),
 +        )
 +        .into());
 +    }
 +
 +    if let Some(original_additional_edits) = original_completion.additional_text_edits.as_mut() {
 +        original_additional_edits.extend(additional_edits.into_iter())
 +    } else {
 +        original_completion.additional_text_edits = Some(additional_edits);
 +    }
 +
 +    Ok(original_completion)
 +}
 +
 +pub(crate) fn handle_folding_range(
 +    snap: GlobalStateSnapshot,
 +    params: FoldingRangeParams,
 +) -> Result<Option<Vec<FoldingRange>>> {
 +    let _p = profile::span("handle_folding_range");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let folds = snap.analysis.folding_ranges(file_id)?;
 +    let text = snap.analysis.file_text(file_id)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let line_folding_only = snap.config.line_folding_only();
 +    let res = folds
 +        .into_iter()
 +        .map(|it| to_proto::folding_range(&*text, &line_index, line_folding_only, it))
 +        .collect();
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_signature_help(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::SignatureHelpParams,
 +) -> Result<Option<lsp_types::SignatureHelp>> {
 +    let _p = profile::span("handle_signature_help");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +    let help = match snap.analysis.signature_help(position)? {
 +        Some(it) => it,
 +        None => return Ok(None),
 +    };
 +    let config = snap.config.call_info();
 +    let res = to_proto::signature_help(help, config, snap.config.signature_help_label_offsets());
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_hover(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::HoverParams,
 +) -> Result<Option<lsp_ext::Hover>> {
 +    let _p = profile::span("handle_hover");
 +    let range = match params.position {
 +        PositionOrRange::Position(position) => Range::new(position, position),
 +        PositionOrRange::Range(range) => range,
 +    };
 +
 +    let file_range = from_proto::file_range(&snap, params.text_document, range)?;
 +    let info = match snap.analysis.hover(&snap.config.hover(), file_range)? {
 +        None => return Ok(None),
 +        Some(info) => info,
 +    };
 +
 +    let line_index = snap.file_line_index(file_range.file_id)?;
 +    let range = to_proto::range(&line_index, info.range);
 +    let markup_kind =
 +        snap.config.hover().documentation.map_or(ide::HoverDocFormat::Markdown, |kind| kind);
 +    let hover = lsp_ext::Hover {
 +        hover: lsp_types::Hover {
 +            contents: HoverContents::Markup(to_proto::markup_content(
 +                info.info.markup,
 +                markup_kind,
 +            )),
 +            range: Some(range),
 +        },
 +        actions: if snap.config.hover_actions().none() {
 +            Vec::new()
 +        } else {
 +            prepare_hover_actions(&snap, &info.info.actions)
 +        },
 +    };
 +
 +    Ok(Some(hover))
 +}
 +
 +pub(crate) fn handle_prepare_rename(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<Option<PrepareRenameResponse>> {
 +    let _p = profile::span("handle_prepare_rename");
 +    let position = from_proto::file_position(&snap, params)?;
 +
 +    let change = snap.analysis.prepare_rename(position)?.map_err(to_proto::rename_error)?;
 +
 +    let line_index = snap.file_line_index(position.file_id)?;
 +    let range = to_proto::range(&line_index, change.range);
 +    Ok(Some(PrepareRenameResponse::Range(range)))
 +}
 +
 +pub(crate) fn handle_rename(
 +    snap: GlobalStateSnapshot,
 +    params: RenameParams,
 +) -> Result<Option<WorkspaceEdit>> {
 +    let _p = profile::span("handle_rename");
 +    let position = from_proto::file_position(&snap, params.text_document_position)?;
 +
 +    let mut change =
 +        snap.analysis.rename(position, &*params.new_name)?.map_err(to_proto::rename_error)?;
 +
 +    // this is kind of a hack to prevent double edits from happening when moving files
 +    // When a module gets renamed by renaming the mod declaration this causes the file to move
 +    // which in turn will trigger a WillRenameFiles request to the server for which we reply with a
 +    // a second identical set of renames, the client will then apply both edits causing incorrect edits
 +    // with this we only emit source_file_edits in the WillRenameFiles response which will do the rename instead
 +    // See https://github.com/microsoft/vscode-languageserver-node/issues/752 for more info
 +    if !change.file_system_edits.is_empty() && snap.config.will_rename() {
 +        change.source_file_edits.clear();
 +    }
 +    let workspace_edit = to_proto::workspace_edit(&snap, change)?;
 +    Ok(Some(workspace_edit))
 +}
 +
 +pub(crate) fn handle_references(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::ReferenceParams,
 +) -> Result<Option<Vec<Location>>> {
 +    let _p = profile::span("handle_references");
 +    let position = from_proto::file_position(&snap, params.text_document_position)?;
 +
 +    let exclude_imports = snap.config.find_all_refs_exclude_imports();
 +
 +    let refs = match snap.analysis.find_all_refs(position, None)? {
 +        None => return Ok(None),
 +        Some(refs) => refs,
 +    };
 +
 +    let include_declaration = params.context.include_declaration;
 +    let locations = refs
 +        .into_iter()
 +        .flat_map(|refs| {
 +            let decl = if include_declaration {
 +                refs.declaration.map(|decl| FileRange {
 +                    file_id: decl.nav.file_id,
 +                    range: decl.nav.focus_or_full_range(),
 +                })
 +            } else {
 +                None
 +            };
 +            refs.references
 +                .into_iter()
 +                .flat_map(|(file_id, refs)| {
 +                    refs.into_iter()
 +                        .filter(|&(_, category)| {
 +                            !exclude_imports || category != Some(ReferenceCategory::Import)
 +                        })
 +                        .map(move |(range, _)| FileRange { file_id, range })
 +                })
 +                .chain(decl)
 +        })
 +        .filter_map(|frange| to_proto::location(&snap, frange).ok())
 +        .collect();
 +
 +    Ok(Some(locations))
 +}
 +
 +pub(crate) fn handle_formatting(
 +    snap: GlobalStateSnapshot,
 +    params: DocumentFormattingParams,
 +) -> Result<Option<Vec<lsp_types::TextEdit>>> {
 +    let _p = profile::span("handle_formatting");
 +
 +    run_rustfmt(&snap, params.text_document, None)
 +}
 +
 +pub(crate) fn handle_range_formatting(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::DocumentRangeFormattingParams,
 +) -> Result<Option<Vec<lsp_types::TextEdit>>> {
 +    let _p = profile::span("handle_range_formatting");
 +
 +    run_rustfmt(&snap, params.text_document, Some(params.range))
 +}
 +
 +pub(crate) fn handle_code_action(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::CodeActionParams,
 +) -> Result<Option<Vec<lsp_ext::CodeAction>>> {
 +    let _p = profile::span("handle_code_action");
 +
 +    if !snap.config.code_action_literals() {
 +        // We intentionally don't support command-based actions, as those either
 +        // require either custom client-code or server-initiated edits. Server
 +        // initiated edits break causality, so we avoid those.
 +        return Ok(None);
 +    }
 +
 +    let line_index =
 +        snap.file_line_index(from_proto::file_id(&snap, &params.text_document.uri)?)?;
 +    let frange = from_proto::file_range(&snap, params.text_document.clone(), params.range)?;
 +
 +    let mut assists_config = snap.config.assist();
 +    assists_config.allowed = params
 +        .context
 +        .only
 +        .clone()
 +        .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect());
 +
 +    let mut res: Vec<lsp_ext::CodeAction> = Vec::new();
 +
 +    let code_action_resolve_cap = snap.config.code_action_resolve();
 +    let resolve = if code_action_resolve_cap {
 +        AssistResolveStrategy::None
 +    } else {
 +        AssistResolveStrategy::All
 +    };
 +    let assists = snap.analysis.assists_with_fixes(
 +        &assists_config,
 +        &snap.config.diagnostics(),
 +        resolve,
 +        frange,
 +    )?;
 +    for (index, assist) in assists.into_iter().enumerate() {
 +        let resolve_data =
 +            if code_action_resolve_cap { Some((index, params.clone())) } else { None };
 +        let code_action = to_proto::code_action(&snap, assist, resolve_data)?;
 +        res.push(code_action)
 +    }
 +
 +    // Fixes from `cargo check`.
 +    for fix in
 +        snap.check_fixes.values().filter_map(|it| it.get(&frange.file_id)).into_iter().flatten()
 +    {
 +        // FIXME: this mapping is awkward and shouldn't exist. Refactor
 +        // `snap.check_fixes` to not convert to LSP prematurely.
 +        let intersect_fix_range = fix
 +            .ranges
 +            .iter()
 +            .copied()
 +            .filter_map(|range| from_proto::text_range(&line_index, range).ok())
 +            .any(|fix_range| fix_range.intersect(frange.range).is_some());
 +        if intersect_fix_range {
 +            res.push(fix.action.clone());
 +        }
 +    }
 +
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_code_action_resolve(
 +    snap: GlobalStateSnapshot,
 +    mut code_action: lsp_ext::CodeAction,
 +) -> Result<lsp_ext::CodeAction> {
 +    let _p = profile::span("handle_code_action_resolve");
 +    let params = match code_action.data.take() {
 +        Some(it) => it,
 +        None => return Err(invalid_params_error("code action without data".to_string()).into()),
 +    };
 +
 +    let file_id = from_proto::file_id(&snap, &params.code_action_params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let range = from_proto::text_range(&line_index, params.code_action_params.range)?;
 +    let frange = FileRange { file_id, range };
 +
 +    let mut assists_config = snap.config.assist();
 +    assists_config.allowed = params
 +        .code_action_params
 +        .context
 +        .only
 +        .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect());
 +
 +    let (assist_index, assist_resolve) = match parse_action_id(&params.id) {
 +        Ok(parsed_data) => parsed_data,
 +        Err(e) => {
 +            return Err(invalid_params_error(format!(
 +                "Failed to parse action id string '{}': {}",
 +                params.id, e
 +            ))
 +            .into())
 +        }
 +    };
 +
 +    let expected_assist_id = assist_resolve.assist_id.clone();
 +    let expected_kind = assist_resolve.assist_kind;
 +
 +    let assists = snap.analysis.assists_with_fixes(
 +        &assists_config,
 +        &snap.config.diagnostics(),
 +        AssistResolveStrategy::Single(assist_resolve),
 +        frange,
 +    )?;
 +
 +    let assist = match assists.get(assist_index) {
 +        Some(assist) => assist,
 +        None => return Err(invalid_params_error(format!(
 +            "Failed to find the assist for index {} provided by the resolve request. Resolve request assist id: {}",
 +            assist_index, params.id,
 +        ))
 +        .into())
 +    };
 +    if assist.id.0 != expected_assist_id || assist.id.1 != expected_kind {
 +        return Err(invalid_params_error(format!(
 +            "Mismatching assist at index {} for the resolve parameters given. Resolve request assist id: {}, actual id: {:?}.",
 +            assist_index, params.id, assist.id
 +        ))
 +        .into());
 +    }
 +    let ca = to_proto::code_action(&snap, assist.clone(), None)?;
 +    code_action.edit = ca.edit;
 +    code_action.command = ca.command;
 +    Ok(code_action)
 +}
 +
 +fn parse_action_id(action_id: &str) -> Result<(usize, SingleResolve), String> {
 +    let id_parts = action_id.split(':').collect::<Vec<_>>();
 +    match id_parts.as_slice() {
 +        [assist_id_string, assist_kind_string, index_string] => {
 +            let assist_kind: AssistKind = assist_kind_string.parse()?;
 +            let index: usize = match index_string.parse() {
 +                Ok(index) => index,
 +                Err(e) => return Err(format!("Incorrect index string: {}", e)),
 +            };
 +            Ok((index, SingleResolve { assist_id: assist_id_string.to_string(), assist_kind }))
 +        }
 +        _ => Err("Action id contains incorrect number of segments".to_string()),
 +    }
 +}
 +
 +pub(crate) fn handle_code_lens(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::CodeLensParams,
 +) -> Result<Option<Vec<CodeLens>>> {
 +    let _p = profile::span("handle_code_lens");
 +
 +    let lens_config = snap.config.lens();
 +    if lens_config.none() {
 +        // early return before any db query!
 +        return Ok(Some(Vec::default()));
 +    }
 +
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let cargo_target_spec = CargoTargetSpec::for_file(&snap, file_id)?;
 +
 +    let annotations = snap.analysis.annotations(
 +        &AnnotationConfig {
 +            binary_target: cargo_target_spec
 +                .map(|spec| {
 +                    matches!(
 +                        spec.target_kind,
 +                        TargetKind::Bin | TargetKind::Example | TargetKind::Test
 +                    )
 +                })
 +                .unwrap_or(false),
 +            annotate_runnables: lens_config.runnable(),
 +            annotate_impls: lens_config.implementations,
 +            annotate_references: lens_config.refs_adt,
 +            annotate_method_references: lens_config.method_refs,
 +            annotate_enum_variant_references: lens_config.enum_variant_refs,
 +            location: lens_config.location.into(),
 +        },
 +        file_id,
 +    )?;
 +
 +    let mut res = Vec::new();
 +    for a in annotations {
 +        to_proto::code_lens(&mut res, &snap, a)?;
 +    }
 +
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_code_lens_resolve(
 +    snap: GlobalStateSnapshot,
 +    code_lens: CodeLens,
 +) -> Result<CodeLens> {
 +    let annotation = from_proto::annotation(&snap, code_lens.clone())?;
 +    let annotation = snap.analysis.resolve_annotation(annotation)?;
 +
 +    let mut acc = Vec::new();
 +    to_proto::code_lens(&mut acc, &snap, annotation)?;
 +
 +    let res = match acc.pop() {
 +        Some(it) if acc.is_empty() => it,
 +        _ => {
 +            never!();
 +            code_lens
 +        }
 +    };
 +
 +    Ok(res)
 +}
 +
 +pub(crate) fn handle_document_highlight(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::DocumentHighlightParams,
 +) -> Result<Option<Vec<lsp_types::DocumentHighlight>>> {
 +    let _p = profile::span("handle_document_highlight");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +    let line_index = snap.file_line_index(position.file_id)?;
 +
 +    let refs = match snap.analysis.highlight_related(snap.config.highlight_related(), position)? {
 +        None => return Ok(None),
 +        Some(refs) => refs,
 +    };
 +    let res = refs
 +        .into_iter()
 +        .map(|ide::HighlightedRange { range, category }| lsp_types::DocumentHighlight {
 +            range: to_proto::range(&line_index, range),
 +            kind: category.and_then(to_proto::document_highlight_kind),
 +        })
 +        .collect();
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_ssr(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::SsrParams,
 +) -> Result<lsp_types::WorkspaceEdit> {
 +    let _p = profile::span("handle_ssr");
 +    let selections = params
 +        .selections
 +        .iter()
 +        .map(|range| from_proto::file_range(&snap, params.position.text_document.clone(), *range))
 +        .collect::<Result<Vec<_>, _>>()?;
 +    let position = from_proto::file_position(&snap, params.position)?;
 +    let source_change = snap.analysis.structural_search_replace(
 +        &params.query,
 +        params.parse_only,
 +        position,
 +        selections,
 +    )??;
 +    to_proto::workspace_edit(&snap, source_change)
 +}
 +
 +pub(crate) fn publish_diagnostics(
 +    snap: &GlobalStateSnapshot,
 +    file_id: FileId,
 +) -> Result<Vec<Diagnostic>> {
 +    let _p = profile::span("publish_diagnostics");
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let diagnostics: Vec<Diagnostic> = snap
 +        .analysis
 +        .diagnostics(&snap.config.diagnostics(), AssistResolveStrategy::None, file_id)?
 +        .into_iter()
 +        .map(|d| Diagnostic {
 +            range: to_proto::range(&line_index, d.range),
 +            severity: Some(to_proto::diagnostic_severity(d.severity)),
 +            code: Some(NumberOrString::String(d.code.as_str().to_string())),
 +            code_description: Some(lsp_types::CodeDescription {
 +                href: lsp_types::Url::parse(&format!(
 +                    "https://rust-analyzer.github.io/manual.html#{}",
 +                    d.code.as_str()
 +                ))
 +                .unwrap(),
 +            }),
 +            source: Some("rust-analyzer".to_string()),
 +            message: d.message,
 +            related_information: None,
 +            tags: if d.unused { Some(vec![DiagnosticTag::UNNECESSARY]) } else { None },
 +            data: None,
 +        })
 +        .collect();
 +    Ok(diagnostics)
 +}
 +
 +pub(crate) fn handle_inlay_hints(
 +    snap: GlobalStateSnapshot,
 +    params: InlayHintParams,
 +) -> Result<Option<Vec<InlayHint>>> {
 +    let _p = profile::span("handle_inlay_hints");
 +    let document_uri = &params.text_document.uri;
 +    let file_id = from_proto::file_id(&snap, document_uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let range = from_proto::file_range(
 +        &snap,
 +        TextDocumentIdentifier::new(document_uri.to_owned()),
 +        params.range,
 +    )?;
 +    let inlay_hints_config = snap.config.inlay_hints();
 +    Ok(Some(
 +        snap.analysis
 +            .inlay_hints(&inlay_hints_config, file_id, Some(range))?
 +            .into_iter()
 +            .map(|it| {
 +                to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it)
 +            })
 +            .collect::<Result<Vec<_>>>()?,
 +    ))
 +}
 +
 +pub(crate) fn handle_inlay_hints_resolve(
 +    snap: GlobalStateSnapshot,
 +    mut hint: InlayHint,
 +) -> Result<InlayHint> {
 +    let _p = profile::span("handle_inlay_hints_resolve");
 +    let data = match hint.data.take() {
 +        Some(it) => it,
 +        None => return Ok(hint),
 +    };
 +
 +    let resolve_data: lsp_ext::InlayHintResolveData = serde_json::from_value(data)?;
 +
 +    let file_range = from_proto::file_range(
 +        &snap,
 +        resolve_data.text_document,
 +        match resolve_data.position {
 +            PositionOrRange::Position(pos) => Range::new(pos, pos),
 +            PositionOrRange::Range(range) => range,
 +        },
 +    )?;
 +    let info = match snap.analysis.hover(&snap.config.hover(), file_range)? {
 +        None => return Ok(hint),
 +        Some(info) => info,
 +    };
 +
 +    let markup_kind =
 +        snap.config.hover().documentation.map_or(ide::HoverDocFormat::Markdown, |kind| kind);
 +
 +    // FIXME: hover actions?
 +    hint.tooltip = Some(lsp_types::InlayHintTooltip::MarkupContent(to_proto::markup_content(
 +        info.info.markup,
 +        markup_kind,
 +    )));
 +    Ok(hint)
 +}
 +
 +pub(crate) fn handle_call_hierarchy_prepare(
 +    snap: GlobalStateSnapshot,
 +    params: CallHierarchyPrepareParams,
 +) -> Result<Option<Vec<CallHierarchyItem>>> {
 +    let _p = profile::span("handle_call_hierarchy_prepare");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +
 +    let nav_info = match snap.analysis.call_hierarchy(position)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +
 +    let RangeInfo { range: _, info: navs } = nav_info;
 +    let res = navs
 +        .into_iter()
 +        .filter(|it| it.kind == Some(SymbolKind::Function))
 +        .map(|it| to_proto::call_hierarchy_item(&snap, it))
 +        .collect::<Result<Vec<_>>>()?;
 +
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_call_hierarchy_incoming(
 +    snap: GlobalStateSnapshot,
 +    params: CallHierarchyIncomingCallsParams,
 +) -> Result<Option<Vec<CallHierarchyIncomingCall>>> {
 +    let _p = profile::span("handle_call_hierarchy_incoming");
 +    let item = params.item;
 +
 +    let doc = TextDocumentIdentifier::new(item.uri);
 +    let frange = from_proto::file_range(&snap, doc, item.selection_range)?;
 +    let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
 +
 +    let call_items = match snap.analysis.incoming_calls(fpos)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +
 +    let mut res = vec![];
 +
 +    for call_item in call_items.into_iter() {
 +        let file_id = call_item.target.file_id;
 +        let line_index = snap.file_line_index(file_id)?;
 +        let item = to_proto::call_hierarchy_item(&snap, call_item.target)?;
 +        res.push(CallHierarchyIncomingCall {
 +            from: item,
 +            from_ranges: call_item
 +                .ranges
 +                .into_iter()
 +                .map(|it| to_proto::range(&line_index, it))
 +                .collect(),
 +        });
 +    }
 +
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_call_hierarchy_outgoing(
 +    snap: GlobalStateSnapshot,
 +    params: CallHierarchyOutgoingCallsParams,
 +) -> Result<Option<Vec<CallHierarchyOutgoingCall>>> {
 +    let _p = profile::span("handle_call_hierarchy_outgoing");
 +    let item = params.item;
 +
 +    let doc = TextDocumentIdentifier::new(item.uri);
 +    let frange = from_proto::file_range(&snap, doc, item.selection_range)?;
 +    let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
 +
 +    let call_items = match snap.analysis.outgoing_calls(fpos)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +
 +    let mut res = vec![];
 +
 +    for call_item in call_items.into_iter() {
 +        let file_id = call_item.target.file_id;
 +        let line_index = snap.file_line_index(file_id)?;
 +        let item = to_proto::call_hierarchy_item(&snap, call_item.target)?;
 +        res.push(CallHierarchyOutgoingCall {
 +            to: item,
 +            from_ranges: call_item
 +                .ranges
 +                .into_iter()
 +                .map(|it| to_proto::range(&line_index, it))
 +                .collect(),
 +        });
 +    }
 +
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_semantic_tokens_full(
 +    snap: GlobalStateSnapshot,
 +    params: SemanticTokensParams,
 +) -> Result<Option<SemanticTokensResult>> {
 +    let _p = profile::span("handle_semantic_tokens_full");
 +
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let text = snap.analysis.file_text(file_id)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let mut highlight_config = snap.config.highlighting_config();
 +    // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
 +    highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded;
 +
 +    let highlights = snap.analysis.highlight(highlight_config, file_id)?;
 +    let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 +
 +    // Unconditionally cache the tokens
 +    snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens.clone());
 +
 +    Ok(Some(semantic_tokens.into()))
 +}
 +
 +pub(crate) fn handle_semantic_tokens_full_delta(
 +    snap: GlobalStateSnapshot,
 +    params: SemanticTokensDeltaParams,
 +) -> Result<Option<SemanticTokensFullDeltaResult>> {
 +    let _p = profile::span("handle_semantic_tokens_full_delta");
 +
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let text = snap.analysis.file_text(file_id)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let mut highlight_config = snap.config.highlighting_config();
 +    // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
 +    highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded;
 +
 +    let highlights = snap.analysis.highlight(highlight_config, file_id)?;
 +    let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 +
 +    let mut cache = snap.semantic_tokens_cache.lock();
 +    let cached_tokens = cache.entry(params.text_document.uri).or_default();
 +
 +    if let Some(prev_id) = &cached_tokens.result_id {
 +        if *prev_id == params.previous_result_id {
 +            let delta = to_proto::semantic_token_delta(cached_tokens, &semantic_tokens);
 +            *cached_tokens = semantic_tokens;
 +            return Ok(Some(delta.into()));
 +        }
 +    }
 +
 +    *cached_tokens = semantic_tokens.clone();
 +
 +    Ok(Some(semantic_tokens.into()))
 +}
 +
 +pub(crate) fn handle_semantic_tokens_range(
 +    snap: GlobalStateSnapshot,
 +    params: SemanticTokensRangeParams,
 +) -> Result<Option<SemanticTokensRangeResult>> {
 +    let _p = profile::span("handle_semantic_tokens_range");
 +
 +    let frange = from_proto::file_range(&snap, params.text_document, params.range)?;
 +    let text = snap.analysis.file_text(frange.file_id)?;
 +    let line_index = snap.file_line_index(frange.file_id)?;
 +
 +    let highlights = snap.analysis.highlight_range(snap.config.highlighting_config(), frange)?;
 +    let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 +    Ok(Some(semantic_tokens.into()))
 +}
 +
 +pub(crate) fn handle_open_docs(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<Option<lsp_types::Url>> {
 +    let _p = profile::span("handle_open_docs");
 +    let position = from_proto::file_position(&snap, params)?;
 +
 +    let remote = snap.analysis.external_docs(position)?;
 +
 +    Ok(remote.and_then(|remote| Url::parse(&remote).ok()))
 +}
 +
 +pub(crate) fn handle_open_cargo_toml(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::OpenCargoTomlParams,
 +) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
 +    let _p = profile::span("handle_open_cargo_toml");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +
 +    let cargo_spec = match CargoTargetSpec::for_file(&snap, file_id)? {
 +        Some(it) => it,
 +        None => return Ok(None),
 +    };
 +
 +    let cargo_toml_url = to_proto::url_from_abs_path(&cargo_spec.cargo_toml);
 +    let res: lsp_types::GotoDefinitionResponse =
 +        Location::new(cargo_toml_url, Range::default()).into();
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_move_item(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::MoveItemParams,
 +) -> Result<Vec<lsp_ext::SnippetTextEdit>> {
 +    let _p = profile::span("handle_move_item");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let range = from_proto::file_range(&snap, params.text_document, params.range)?;
 +
 +    let direction = match params.direction {
 +        lsp_ext::MoveItemDirection::Up => ide::Direction::Up,
 +        lsp_ext::MoveItemDirection::Down => ide::Direction::Down,
 +    };
 +
 +    match snap.analysis.move_item(range, direction)? {
 +        Some(text_edit) => {
 +            let line_index = snap.file_line_index(file_id)?;
 +            Ok(to_proto::snippet_text_edit_vec(&line_index, true, text_edit))
 +        }
 +        None => Ok(vec![]),
 +    }
 +}
 +
 +fn to_command_link(command: lsp_types::Command, tooltip: String) -> lsp_ext::CommandLink {
 +    lsp_ext::CommandLink { tooltip: Some(tooltip), command }
 +}
 +
 +fn show_impl_command_link(
 +    snap: &GlobalStateSnapshot,
 +    position: &FilePosition,
 +) -> Option<lsp_ext::CommandLinkGroup> {
 +    if snap.config.hover_actions().implementations && snap.config.client_commands().show_reference {
 +        if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) {
 +            let uri = to_proto::url(snap, position.file_id);
 +            let line_index = snap.file_line_index(position.file_id).ok()?;
 +            let position = to_proto::position(&line_index, position.offset);
 +            let locations: Vec<_> = nav_data
 +                .info
 +                .into_iter()
 +                .filter_map(|nav| to_proto::location_from_nav(snap, nav).ok())
 +                .collect();
 +            let title = to_proto::implementation_title(locations.len());
 +            let command = to_proto::command::show_references(title, &uri, position, locations);
 +
 +            return Some(lsp_ext::CommandLinkGroup {
 +                commands: vec![to_command_link(command, "Go to implementations".into())],
 +                ..Default::default()
 +            });
 +        }
 +    }
 +    None
 +}
 +
 +fn show_ref_command_link(
 +    snap: &GlobalStateSnapshot,
 +    position: &FilePosition,
 +) -> Option<lsp_ext::CommandLinkGroup> {
 +    if snap.config.hover_actions().references && snap.config.client_commands().show_reference {
 +        if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) {
 +            let uri = to_proto::url(snap, position.file_id);
 +            let line_index = snap.file_line_index(position.file_id).ok()?;
 +            let position = to_proto::position(&line_index, position.offset);
 +            let locations: Vec<_> = ref_search_res
 +                .into_iter()
 +                .flat_map(|res| res.references)
 +                .flat_map(|(file_id, ranges)| {
 +                    ranges.into_iter().filter_map(move |(range, _)| {
 +                        to_proto::location(snap, FileRange { file_id, range }).ok()
 +                    })
 +                })
 +                .collect();
 +            let title = to_proto::reference_title(locations.len());
 +            let command = to_proto::command::show_references(title, &uri, position, locations);
 +
 +            return Some(lsp_ext::CommandLinkGroup {
 +                commands: vec![to_command_link(command, "Go to references".into())],
 +                ..Default::default()
 +            });
 +        }
 +    }
 +    None
 +}
 +
 +fn runnable_action_links(
 +    snap: &GlobalStateSnapshot,
 +    runnable: Runnable,
 +) -> Option<lsp_ext::CommandLinkGroup> {
 +    let hover_actions_config = snap.config.hover_actions();
 +    if !hover_actions_config.runnable() {
 +        return None;
 +    }
 +
 +    let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?;
 +    if should_skip_target(&runnable, cargo_spec.as_ref()) {
 +        return None;
 +    }
 +
 +    let client_commands_config = snap.config.client_commands();
 +    if !(client_commands_config.run_single || client_commands_config.debug_single) {
 +        return None;
 +    }
 +
 +    let title = runnable.title();
 +    let r = to_proto::runnable(snap, runnable).ok()?;
 +
 +    let mut group = lsp_ext::CommandLinkGroup::default();
 +
 +    if hover_actions_config.run && client_commands_config.run_single {
 +        let run_command = to_proto::command::run_single(&r, &title);
 +        group.commands.push(to_command_link(run_command, r.label.clone()));
 +    }
 +
 +    if hover_actions_config.debug && client_commands_config.debug_single {
 +        let dbg_command = to_proto::command::debug_single(&r);
 +        group.commands.push(to_command_link(dbg_command, r.label));
 +    }
 +
 +    Some(group)
 +}
 +
 +fn goto_type_action_links(
 +    snap: &GlobalStateSnapshot,
 +    nav_targets: &[HoverGotoTypeData],
 +) -> Option<lsp_ext::CommandLinkGroup> {
 +    if !snap.config.hover_actions().goto_type_def
 +        || nav_targets.is_empty()
 +        || !snap.config.client_commands().goto_location
 +    {
 +        return None;
 +    }
 +
 +    Some(lsp_ext::CommandLinkGroup {
 +        title: Some("Go to ".into()),
 +        commands: nav_targets
 +            .iter()
 +            .filter_map(|it| {
 +                to_proto::command::goto_location(snap, &it.nav)
 +                    .map(|cmd| to_command_link(cmd, it.mod_path.clone()))
 +            })
 +            .collect(),
 +    })
 +}
 +
 +fn prepare_hover_actions(
 +    snap: &GlobalStateSnapshot,
 +    actions: &[HoverAction],
 +) -> Vec<lsp_ext::CommandLinkGroup> {
 +    actions
 +        .iter()
 +        .filter_map(|it| match it {
 +            HoverAction::Implementation(position) => show_impl_command_link(snap, position),
 +            HoverAction::Reference(position) => show_ref_command_link(snap, position),
 +            HoverAction::Runnable(r) => runnable_action_links(snap, r.clone()),
 +            HoverAction::GoToType(targets) => goto_type_action_links(snap, targets),
 +        })
 +        .collect()
 +}
 +
 +fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>) -> bool {
 +    match runnable.kind {
 +        RunnableKind::Bin => {
 +            // Do not suggest binary run on other target than binary
 +            match &cargo_spec {
 +                Some(spec) => !matches!(
 +                    spec.target_kind,
 +                    TargetKind::Bin | TargetKind::Example | TargetKind::Test
 +                ),
 +                None => true,
 +            }
 +        }
 +        _ => false,
 +    }
 +}
 +
 +fn run_rustfmt(
 +    snap: &GlobalStateSnapshot,
 +    text_document: TextDocumentIdentifier,
 +    range: Option<lsp_types::Range>,
 +) -> Result<Option<Vec<lsp_types::TextEdit>>> {
 +    let file_id = from_proto::file_id(snap, &text_document.uri)?;
 +    let file = snap.analysis.file_text(file_id)?;
-             if let Some(&crate_id) = crate_ids.first() {
-                 // Assume all crates are in the same edition
-                 let edition = snap.analysis.crate_edition(crate_id)?;
++
++    // find the edition of the package the file belongs to
++    // (if it belongs to multiple we'll just pick the first one and pray)
++    let edition = snap
++        .analysis
++        .relevant_crates_for(file_id)?
++        .into_iter()
++        .find_map(|crate_id| snap.cargo_target_for_crate_root(crate_id))
++        .map(|(ws, target)| ws[ws[target].package].edition);
 +
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let mut command = match snap.config.rustfmt() {
 +        RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => {
 +            let mut cmd = process::Command::new(toolchain::rustfmt());
 +            cmd.envs(snap.config.extra_env());
 +            cmd.args(extra_args);
 +            // try to chdir to the file so we can respect `rustfmt.toml`
 +            // FIXME: use `rustfmt --config-path` once
 +            // https://github.com/rust-lang/rustfmt/issues/4660 gets fixed
 +            match text_document.uri.to_file_path() {
 +                Ok(mut path) => {
 +                    // pop off file name
 +                    if path.pop() && path.is_dir() {
 +                        cmd.current_dir(path);
 +                    }
 +                }
 +                Err(_) => {
 +                    tracing::error!(
 +                        "Unable to get file path for {}, rustfmt.toml might be ignored",
 +                        text_document.uri
 +                    );
 +                }
 +            }
++            if let Some(edition) = edition {
 +                cmd.arg("--edition");
 +                cmd.arg(edition.to_string());
 +            }
 +
 +            if let Some(range) = range {
 +                if !enable_range_formatting {
 +                    return Err(LspError::new(
 +                        ErrorCode::InvalidRequest as i32,
 +                        String::from(
 +                            "rustfmt range formatting is unstable. \
 +                            Opt-in by using a nightly build of rustfmt and setting \
 +                            `rustfmt.rangeFormatting.enable` to true in your LSP configuration",
 +                        ),
 +                    )
 +                    .into());
 +                }
 +
 +                let frange = from_proto::file_range(snap, text_document, range)?;
 +                let start_line = line_index.index.line_col(frange.range.start()).line;
 +                let end_line = line_index.index.line_col(frange.range.end()).line;
 +
 +                cmd.arg("--unstable-features");
 +                cmd.arg("--file-lines");
 +                cmd.arg(
 +                    json!([{
 +                        "file": "stdin",
 +                        "range": [start_line, end_line]
 +                    }])
 +                    .to_string(),
 +                );
 +            }
 +
 +            cmd
 +        }
 +        RustfmtConfig::CustomCommand { command, args } => {
 +            let mut cmd = process::Command::new(command);
 +            cmd.envs(snap.config.extra_env());
 +            cmd.args(args);
 +            cmd
 +        }
 +    };
 +
 +    let mut rustfmt = command
 +        .stdin(Stdio::piped())
 +        .stdout(Stdio::piped())
 +        .stderr(Stdio::piped())
 +        .spawn()
 +        .context(format!("Failed to spawn {:?}", command))?;
 +
 +    rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?;
 +
 +    let output = rustfmt.wait_with_output()?;
 +    let captured_stdout = String::from_utf8(output.stdout)?;
 +    let captured_stderr = String::from_utf8(output.stderr).unwrap_or_default();
 +
 +    if !output.status.success() {
 +        let rustfmt_not_installed =
 +            captured_stderr.contains("not installed") || captured_stderr.contains("not available");
 +
 +        return match output.status.code() {
 +            Some(1) if !rustfmt_not_installed => {
 +                // While `rustfmt` doesn't have a specific exit code for parse errors this is the
 +                // likely cause exiting with 1. Most Language Servers swallow parse errors on
 +                // formatting because otherwise an error is surfaced to the user on top of the
 +                // syntax error diagnostics they're already receiving. This is especially jarring
 +                // if they have format on save enabled.
 +                tracing::warn!(
 +                    ?command,
 +                    %captured_stderr,
 +                    "rustfmt exited with status 1"
 +                );
 +                Ok(None)
 +            }
 +            _ => {
 +                // Something else happened - e.g. `rustfmt` is missing or caught a signal
 +                Err(LspError::new(
 +                    -32900,
 +                    format!(
 +                        r#"rustfmt exited with:
 +                           Status: {}
 +                           stdout: {}
 +                           stderr: {}"#,
 +                        output.status, captured_stdout, captured_stderr,
 +                    ),
 +                )
 +                .into())
 +            }
 +        };
 +    }
 +
 +    let (new_text, new_line_endings) = LineEndings::normalize(captured_stdout);
 +
 +    if line_index.endings != new_line_endings {
 +        // If line endings are different, send the entire file.
 +        // Diffing would not work here, as the line endings might be the only
 +        // difference.
 +        Ok(Some(to_proto::text_edit_vec(
 +            &line_index,
 +            TextEdit::replace(TextRange::up_to(TextSize::of(&*file)), new_text),
 +        )))
 +    } else if *file == new_text {
 +        // The document is already formatted correctly -- no edits needed.
 +        Ok(None)
 +    } else {
 +        Ok(Some(to_proto::text_edit_vec(&line_index, diff(&file, &new_text))))
 +    }
 +}
index 5a37cbe2e334baa95346e4d522b600f2597a7545,0000000000000000000000000000000000000000..b3cea64d4175e129672af57cf90ba647db346c21
mode 100644,000000..100644
--- /dev/null
@@@ -1,407 -1,0 +1,411 @@@
-         let token = lsp_types::ProgressToken::String(format!("rustAnalyzer/{}", title));
 +//! Utilities for LSP-related boilerplate code.
 +use std::{ops::Range, sync::Arc};
 +
 +use lsp_server::Notification;
 +
 +use crate::{
 +    from_proto,
 +    global_state::GlobalState,
 +    line_index::{LineEndings, LineIndex, OffsetEncoding},
 +    LspError,
 +};
 +
 +pub(crate) fn invalid_params_error(message: String) -> LspError {
 +    LspError { code: lsp_server::ErrorCode::InvalidParams as i32, message }
 +}
 +
 +pub(crate) fn notification_is<N: lsp_types::notification::Notification>(
 +    notification: &Notification,
 +) -> bool {
 +    notification.method == N::METHOD
 +}
 +
 +#[derive(Debug, Eq, PartialEq)]
 +pub(crate) enum Progress {
 +    Begin,
 +    Report,
 +    End,
 +}
 +
 +impl Progress {
 +    pub(crate) fn fraction(done: usize, total: usize) -> f64 {
 +        assert!(done <= total);
 +        done as f64 / total.max(1) as f64
 +    }
 +}
 +
 +impl GlobalState {
 +    pub(crate) fn show_message(&mut self, typ: lsp_types::MessageType, message: String) {
 +        let message = message;
 +        self.send_notification::<lsp_types::notification::ShowMessage>(
 +            lsp_types::ShowMessageParams { typ, message },
 +        )
 +    }
 +
 +    /// Sends a notification to the client containing the error `message`.
 +    /// If `additional_info` is [`Some`], appends a note to the notification telling to check the logs.
 +    /// This will always log `message` + `additional_info` to the server's error log.
 +    pub(crate) fn show_and_log_error(&mut self, message: String, additional_info: Option<String>) {
 +        let mut message = message;
 +        match additional_info {
 +            Some(additional_info) => {
 +                tracing::error!("{}\n\n{}", &message, &additional_info);
 +                if tracing::enabled!(tracing::Level::ERROR) {
 +                    message.push_str("\n\nCheck the server logs for additional info.");
 +                }
 +            }
 +            None => tracing::error!("{}", &message),
 +        }
 +
 +        self.send_notification::<lsp_types::notification::ShowMessage>(
 +            lsp_types::ShowMessageParams { typ: lsp_types::MessageType::ERROR, message },
 +        )
 +    }
 +
 +    /// rust-analyzer is resilient -- if it fails, this doesn't usually affect
 +    /// the user experience. Part of that is that we deliberately hide panics
 +    /// from the user.
 +    ///
 +    /// We do however want to pester rust-analyzer developers with panics and
 +    /// other "you really gotta fix that" messages. The current strategy is to
 +    /// be noisy for "from source" builds or when profiling is enabled.
 +    ///
 +    /// It's unclear if making from source `cargo xtask install` builds more
 +    /// panicky is a good idea, let's see if we can keep our awesome bleeding
 +    /// edge users from being upset!
 +    pub(crate) fn poke_rust_analyzer_developer(&mut self, message: String) {
 +        let from_source_build = option_env!("POKE_RA_DEVS").is_some();
 +        let profiling_enabled = std::env::var("RA_PROFILE").is_ok();
 +        if from_source_build || profiling_enabled {
 +            self.show_message(lsp_types::MessageType::ERROR, message)
 +        }
 +    }
 +
 +    pub(crate) fn report_progress(
 +        &mut self,
 +        title: &str,
 +        state: Progress,
 +        message: Option<String>,
 +        fraction: Option<f64>,
++        cancel_token: Option<String>,
 +    ) {
 +        if !self.config.work_done_progress() {
 +            return;
 +        }
 +        let percentage = fraction.map(|f| {
 +            assert!((0.0..=1.0).contains(&f));
 +            (f * 100.0) as u32
 +        });
-                     cancellable: None,
++        let cancellable = Some(cancel_token.is_some());
++        let token = lsp_types::ProgressToken::String(
++            cancel_token.unwrap_or_else(|| format!("rustAnalyzer/{}", title)),
++        );
 +        let work_done_progress = match state {
 +            Progress::Begin => {
 +                self.send_request::<lsp_types::request::WorkDoneProgressCreate>(
 +                    lsp_types::WorkDoneProgressCreateParams { token: token.clone() },
 +                    |_, _| (),
 +                );
 +
 +                lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin {
 +                    title: title.into(),
-                     cancellable: None,
++                    cancellable,
 +                    message,
 +                    percentage,
 +                })
 +            }
 +            Progress::Report => {
 +                lsp_types::WorkDoneProgress::Report(lsp_types::WorkDoneProgressReport {
++                    cancellable,
 +                    message,
 +                    percentage,
 +                })
 +            }
 +            Progress::End => {
 +                lsp_types::WorkDoneProgress::End(lsp_types::WorkDoneProgressEnd { message })
 +            }
 +        };
 +        self.send_notification::<lsp_types::notification::Progress>(lsp_types::ProgressParams {
 +            token,
 +            value: lsp_types::ProgressParamsValue::WorkDone(work_done_progress),
 +        });
 +    }
 +}
 +
 +pub(crate) fn apply_document_changes(
 +    old_text: &mut String,
 +    content_changes: Vec<lsp_types::TextDocumentContentChangeEvent>,
 +) {
 +    let mut line_index = LineIndex {
 +        index: Arc::new(ide::LineIndex::new(old_text)),
 +        // We don't care about line endings or offset encoding here.
 +        endings: LineEndings::Unix,
 +        encoding: OffsetEncoding::Utf16,
 +    };
 +
 +    // The changes we got must be applied sequentially, but can cross lines so we
 +    // have to keep our line index updated.
 +    // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we
 +    // remember the last valid line in the index and only rebuild it if needed.
 +    // The VFS will normalize the end of lines to `\n`.
 +    enum IndexValid {
 +        All,
 +        UpToLineExclusive(u32),
 +    }
 +
 +    impl IndexValid {
 +        fn covers(&self, line: u32) -> bool {
 +            match *self {
 +                IndexValid::UpToLineExclusive(to) => to > line,
 +                _ => true,
 +            }
 +        }
 +    }
 +
 +    let mut index_valid = IndexValid::All;
 +    for change in content_changes {
 +        match change.range {
 +            Some(range) => {
 +                if !index_valid.covers(range.end.line) {
 +                    line_index.index = Arc::new(ide::LineIndex::new(old_text));
 +                }
 +                index_valid = IndexValid::UpToLineExclusive(range.start.line);
 +                if let Ok(range) = from_proto::text_range(&line_index, range) {
 +                    old_text.replace_range(Range::<usize>::from(range), &change.text);
 +                }
 +            }
 +            None => {
 +                *old_text = change.text;
 +                index_valid = IndexValid::UpToLineExclusive(0);
 +            }
 +        }
 +    }
 +}
 +
 +/// Checks that the edits inside the completion and the additional edits do not overlap.
 +/// LSP explicitly forbids the additional edits to overlap both with the main edit and themselves.
 +pub(crate) fn all_edits_are_disjoint(
 +    completion: &lsp_types::CompletionItem,
 +    additional_edits: &[lsp_types::TextEdit],
 +) -> bool {
 +    let mut edit_ranges = Vec::new();
 +    match completion.text_edit.as_ref() {
 +        Some(lsp_types::CompletionTextEdit::Edit(edit)) => {
 +            edit_ranges.push(edit.range);
 +        }
 +        Some(lsp_types::CompletionTextEdit::InsertAndReplace(edit)) => {
 +            let replace = edit.replace;
 +            let insert = edit.insert;
 +            if replace.start != insert.start
 +                || insert.start > insert.end
 +                || insert.end > replace.end
 +            {
 +                // insert has to be a prefix of replace but it is not
 +                return false;
 +            }
 +            edit_ranges.push(replace);
 +        }
 +        None => {}
 +    }
 +    if let Some(additional_changes) = completion.additional_text_edits.as_ref() {
 +        edit_ranges.extend(additional_changes.iter().map(|edit| edit.range));
 +    };
 +    edit_ranges.extend(additional_edits.iter().map(|edit| edit.range));
 +    edit_ranges.sort_by_key(|range| (range.start, range.end));
 +    edit_ranges
 +        .iter()
 +        .zip(edit_ranges.iter().skip(1))
 +        .all(|(previous, next)| previous.end <= next.start)
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use lsp_types::{
 +        CompletionItem, CompletionTextEdit, InsertReplaceEdit, Position, Range,
 +        TextDocumentContentChangeEvent,
 +    };
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_apply_document_changes() {
 +        macro_rules! c {
 +            [$($sl:expr, $sc:expr; $el:expr, $ec:expr => $text:expr),+] => {
 +                vec![$(TextDocumentContentChangeEvent {
 +                    range: Some(Range {
 +                        start: Position { line: $sl, character: $sc },
 +                        end: Position { line: $el, character: $ec },
 +                    }),
 +                    range_length: None,
 +                    text: String::from($text),
 +                }),+]
 +            };
 +        }
 +
 +        let mut text = String::new();
 +        apply_document_changes(&mut text, vec![]);
 +        assert_eq!(text, "");
 +        apply_document_changes(
 +            &mut text,
 +            vec![TextDocumentContentChangeEvent {
 +                range: None,
 +                range_length: None,
 +                text: String::from("the"),
 +            }],
 +        );
 +        assert_eq!(text, "the");
 +        apply_document_changes(&mut text, c![0, 3; 0, 3 => " quick"]);
 +        assert_eq!(text, "the quick");
 +        apply_document_changes(&mut text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]);
 +        assert_eq!(text, "quick foxes");
 +        apply_document_changes(&mut text, c![0, 11; 0, 11 => "\ndream"]);
 +        assert_eq!(text, "quick foxes\ndream");
 +        apply_document_changes(&mut text, c![1, 0; 1, 0 => "have "]);
 +        assert_eq!(text, "quick foxes\nhave dream");
 +        apply_document_changes(
 +            &mut text,
 +            c![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"],
 +        );
 +        assert_eq!(text, "the quick foxes\nhave quiet dreams\n");
 +        apply_document_changes(&mut text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]);
 +        assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n");
 +        apply_document_changes(
 +            &mut text,
 +            c![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"],
 +        );
 +        assert_eq!(text, "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n");
 +        apply_document_changes(&mut text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]);
 +        assert_eq!(text, "the quick \nthey have quiet dreams\n");
 +
 +        text = String::from("❤️");
 +        apply_document_changes(&mut text, c![0, 0; 0, 0 => "a"]);
 +        assert_eq!(text, "a❤️");
 +
 +        text = String::from("a\nb");
 +        apply_document_changes(&mut text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]);
 +        assert_eq!(text, "adcb");
 +
 +        text = String::from("a\nb");
 +        apply_document_changes(&mut text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]);
 +        assert_eq!(text, "ațc\ncb");
 +    }
 +
 +    #[test]
 +    fn empty_completion_disjoint_tests() {
 +        let empty_completion =
 +            CompletionItem::new_simple("label".to_string(), "detail".to_string());
 +
 +        let disjoint_edit_1 = lsp_types::TextEdit::new(
 +            Range::new(Position::new(2, 2), Position::new(3, 3)),
 +            "new_text".to_string(),
 +        );
 +        let disjoint_edit_2 = lsp_types::TextEdit::new(
 +            Range::new(Position::new(3, 3), Position::new(4, 4)),
 +            "new_text".to_string(),
 +        );
 +
 +        let joint_edit = lsp_types::TextEdit::new(
 +            Range::new(Position::new(1, 1), Position::new(5, 5)),
 +            "new_text".to_string(),
 +        );
 +
 +        assert!(
 +            all_edits_are_disjoint(&empty_completion, &[]),
 +            "Empty completion has all its edits disjoint"
 +        );
 +        assert!(
 +            all_edits_are_disjoint(
 +                &empty_completion,
 +                &[disjoint_edit_1.clone(), disjoint_edit_2.clone()]
 +            ),
 +            "Empty completion is disjoint to whatever disjoint extra edits added"
 +        );
 +
 +        assert!(
 +            !all_edits_are_disjoint(
 +                &empty_completion,
 +                &[disjoint_edit_1, disjoint_edit_2, joint_edit]
 +            ),
 +            "Empty completion does not prevent joint extra edits from failing the validation"
 +        );
 +    }
 +
 +    #[test]
 +    fn completion_with_joint_edits_disjoint_tests() {
 +        let disjoint_edit = lsp_types::TextEdit::new(
 +            Range::new(Position::new(1, 1), Position::new(2, 2)),
 +            "new_text".to_string(),
 +        );
 +        let disjoint_edit_2 = lsp_types::TextEdit::new(
 +            Range::new(Position::new(2, 2), Position::new(3, 3)),
 +            "new_text".to_string(),
 +        );
 +        let joint_edit = lsp_types::TextEdit::new(
 +            Range::new(Position::new(1, 1), Position::new(5, 5)),
 +            "new_text".to_string(),
 +        );
 +
 +        let mut completion_with_joint_edits =
 +            CompletionItem::new_simple("label".to_string(), "detail".to_string());
 +        completion_with_joint_edits.additional_text_edits =
 +            Some(vec![disjoint_edit.clone(), joint_edit.clone()]);
 +        assert!(
 +            !all_edits_are_disjoint(&completion_with_joint_edits, &[]),
 +            "Completion with disjoint edits fails the validation even with empty extra edits"
 +        );
 +
 +        completion_with_joint_edits.text_edit =
 +            Some(CompletionTextEdit::Edit(disjoint_edit.clone()));
 +        completion_with_joint_edits.additional_text_edits = Some(vec![joint_edit.clone()]);
 +        assert!(
 +            !all_edits_are_disjoint(&completion_with_joint_edits, &[]),
 +            "Completion with disjoint edits fails the validation even with empty extra edits"
 +        );
 +
 +        completion_with_joint_edits.text_edit =
 +            Some(CompletionTextEdit::InsertAndReplace(InsertReplaceEdit {
 +                new_text: "new_text".to_string(),
 +                insert: disjoint_edit.range,
 +                replace: disjoint_edit_2.range,
 +            }));
 +        completion_with_joint_edits.additional_text_edits = Some(vec![joint_edit]);
 +        assert!(
 +            !all_edits_are_disjoint(&completion_with_joint_edits, &[]),
 +            "Completion with disjoint edits fails the validation even with empty extra edits"
 +        );
 +    }
 +
 +    #[test]
 +    fn completion_with_disjoint_edits_disjoint_tests() {
 +        let disjoint_edit = lsp_types::TextEdit::new(
 +            Range::new(Position::new(1, 1), Position::new(2, 2)),
 +            "new_text".to_string(),
 +        );
 +        let disjoint_edit_2 = lsp_types::TextEdit::new(
 +            Range::new(Position::new(2, 2), Position::new(3, 3)),
 +            "new_text".to_string(),
 +        );
 +        let joint_edit = lsp_types::TextEdit::new(
 +            Range::new(Position::new(1, 1), Position::new(5, 5)),
 +            "new_text".to_string(),
 +        );
 +
 +        let mut completion_with_disjoint_edits =
 +            CompletionItem::new_simple("label".to_string(), "detail".to_string());
 +        completion_with_disjoint_edits.text_edit = Some(CompletionTextEdit::Edit(disjoint_edit));
 +        let completion_with_disjoint_edits = completion_with_disjoint_edits;
 +
 +        assert!(
 +            all_edits_are_disjoint(&completion_with_disjoint_edits, &[]),
 +            "Completion with disjoint edits is valid"
 +        );
 +        assert!(
 +            !all_edits_are_disjoint(&completion_with_disjoint_edits, &[joint_edit]),
 +            "Completion with disjoint edits and joint extra edit is invalid"
 +        );
 +        assert!(
 +            all_edits_are_disjoint(&completion_with_disjoint_edits, &[disjoint_edit_2]),
 +            "Completion with disjoint edits and joint extra edit is valid"
 +        );
 +    }
 +}
index 15922dac651cce834818de41cc479e50248632d6,0000000000000000000000000000000000000000..2c928a580405c04c107851f2abb6185feeb171c5
mode 100644,000000..100644
--- /dev/null
@@@ -1,916 -1,0 +1,950 @@@
- use ide_db::base_db::{SourceDatabase, SourceDatabaseExt, VfsPath};
 +//! The main loop of `rust-analyzer` responsible for dispatching LSP
 +//! requests/replies and notifications back to the client.
 +use std::{
 +    fmt,
 +    ops::Deref,
 +    sync::Arc,
 +    time::{Duration, Instant},
 +};
 +
 +use always_assert::always;
 +use crossbeam_channel::{select, Receiver};
 +use flycheck::FlycheckHandle;
-         tracing::debug!("handle_event({:?})", event);
++use ide_db::base_db::{SourceDatabaseExt, VfsPath};
 +use itertools::Itertools;
 +use lsp_server::{Connection, Notification, Request};
 +use lsp_types::notification::Notification as _;
 +use vfs::{ChangeKind, FileId};
 +
 +use crate::{
 +    config::Config,
 +    dispatch::{NotificationDispatcher, RequestDispatcher},
 +    from_proto,
 +    global_state::{file_id_to_url, url_to_file_id, GlobalState},
 +    handlers, lsp_ext,
 +    lsp_utils::{apply_document_changes, notification_is, Progress},
 +    mem_docs::DocumentData,
 +    reload::{self, BuildDataProgress, ProjectWorkspaceProgress},
 +    Result,
 +};
 +
 +pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
 +    tracing::info!("initial config: {:#?}", config);
 +
 +    // Windows scheduler implements priority boosts: if thread waits for an
 +    // event (like a condvar), and event fires, priority of the thread is
 +    // temporary bumped. This optimization backfires in our case: each time the
 +    // `main_loop` schedules a task to run on a threadpool, the worker threads
 +    // gets a higher priority, and (on a machine with fewer cores) displaces the
 +    // main loop! We work-around this by marking the main loop as a
 +    // higher-priority thread.
 +    //
 +    // https://docs.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities
 +    // https://docs.microsoft.com/en-us/windows/win32/procthread/priority-boosts
 +    // https://github.com/rust-lang/rust-analyzer/issues/2835
 +    #[cfg(windows)]
 +    unsafe {
 +        use winapi::um::processthreadsapi::*;
 +        let thread = GetCurrentThread();
 +        let thread_priority_above_normal = 1;
 +        SetThreadPriority(thread, thread_priority_above_normal);
 +    }
 +
 +    GlobalState::new(connection.sender, config).run(connection.receiver)
 +}
 +
 +enum Event {
 +    Lsp(lsp_server::Message),
 +    Task(Task),
 +    Vfs(vfs::loader::Message),
 +    Flycheck(flycheck::Message),
 +}
 +
 +#[derive(Debug)]
 +pub(crate) enum Task {
 +    Response(lsp_server::Response),
 +    Retry(lsp_server::Request),
 +    Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
 +    PrimeCaches(PrimeCachesProgress),
 +    FetchWorkspace(ProjectWorkspaceProgress),
 +    FetchBuildData(BuildDataProgress),
 +}
 +
 +#[derive(Debug)]
 +pub(crate) enum PrimeCachesProgress {
 +    Begin,
 +    Report(ide::ParallelPrimeCachesProgress),
 +    End { cancelled: bool },
 +}
 +
 +impl fmt::Debug for Event {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        let debug_verbose_not = |not: &Notification, f: &mut fmt::Formatter<'_>| {
 +            f.debug_struct("Notification").field("method", &not.method).finish()
 +        };
 +
 +        match self {
 +            Event::Lsp(lsp_server::Message::Notification(not)) => {
 +                if notification_is::<lsp_types::notification::DidOpenTextDocument>(not)
 +                    || notification_is::<lsp_types::notification::DidChangeTextDocument>(not)
 +                {
 +                    return debug_verbose_not(not, f);
 +                }
 +            }
 +            Event::Task(Task::Response(resp)) => {
 +                return f
 +                    .debug_struct("Response")
 +                    .field("id", &resp.id)
 +                    .field("error", &resp.error)
 +                    .finish();
 +            }
 +            _ => (),
 +        }
 +        match self {
 +            Event::Lsp(it) => fmt::Debug::fmt(it, f),
 +            Event::Task(it) => fmt::Debug::fmt(it, f),
 +            Event::Vfs(it) => fmt::Debug::fmt(it, f),
 +            Event::Flycheck(it) => fmt::Debug::fmt(it, f),
 +        }
 +    }
 +}
 +
 +impl GlobalState {
 +    fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> {
 +        if self.config.linked_projects().is_empty()
 +            && self.config.detached_files().is_empty()
 +            && self.config.notifications().cargo_toml_not_found
 +        {
 +            self.show_and_log_error("rust-analyzer failed to discover workspace".to_string(), None);
 +        };
 +
 +        if self.config.did_save_text_document_dynamic_registration() {
 +            let save_registration_options = lsp_types::TextDocumentSaveRegistrationOptions {
 +                include_text: Some(false),
 +                text_document_registration_options: lsp_types::TextDocumentRegistrationOptions {
 +                    document_selector: Some(vec![
 +                        lsp_types::DocumentFilter {
 +                            language: None,
 +                            scheme: None,
 +                            pattern: Some("**/*.rs".into()),
 +                        },
 +                        lsp_types::DocumentFilter {
 +                            language: None,
 +                            scheme: None,
 +                            pattern: Some("**/Cargo.toml".into()),
 +                        },
 +                        lsp_types::DocumentFilter {
 +                            language: None,
 +                            scheme: None,
 +                            pattern: Some("**/Cargo.lock".into()),
 +                        },
 +                    ]),
 +                },
 +            };
 +
 +            let registration = lsp_types::Registration {
 +                id: "textDocument/didSave".to_string(),
 +                method: "textDocument/didSave".to_string(),
 +                register_options: Some(serde_json::to_value(save_registration_options).unwrap()),
 +            };
 +            self.send_request::<lsp_types::request::RegisterCapability>(
 +                lsp_types::RegistrationParams { registrations: vec![registration] },
 +                |_, _| (),
 +            );
 +        }
 +
 +        self.fetch_workspaces_queue.request_op("startup".to_string());
 +        if let Some(cause) = self.fetch_workspaces_queue.should_start_op() {
 +            self.fetch_workspaces(cause);
 +        }
 +
 +        while let Some(event) = self.next_event(&inbox) {
 +            if let Event::Lsp(lsp_server::Message::Notification(not)) = &event {
 +                if not.method == lsp_types::notification::Exit::METHOD {
 +                    return Ok(());
 +                }
 +            }
 +            self.handle_event(event)?
 +        }
 +
 +        Err("client exited without proper shutdown sequence".into())
 +    }
 +
 +    fn next_event(&self, inbox: &Receiver<lsp_server::Message>) -> Option<Event> {
 +        select! {
 +            recv(inbox) -> msg =>
 +                msg.ok().map(Event::Lsp),
 +
 +            recv(self.task_pool.receiver) -> task =>
 +                Some(Event::Task(task.unwrap())),
 +
 +            recv(self.loader.receiver) -> task =>
 +                Some(Event::Vfs(task.unwrap())),
 +
 +            recv(self.flycheck_receiver) -> task =>
 +                Some(Event::Flycheck(task.unwrap())),
 +        }
 +    }
 +
 +    fn handle_event(&mut self, event: Event) -> Result<()> {
 +        let loop_start = Instant::now();
 +        // NOTE: don't count blocking select! call as a loop-turn time
 +        let _p = profile::span("GlobalState::handle_event");
 +
-                     self.report_progress("Indexing", state, message, Some(fraction));
++        tracing::debug!("{:?} handle_event({:?})", loop_start, event);
 +        let task_queue_len = self.task_pool.handle.len();
 +        if task_queue_len > 0 {
 +            tracing::info!("task queue len: {}", task_queue_len);
 +        }
 +
 +        let was_quiescent = self.is_quiescent();
 +        match event {
 +            Event::Lsp(msg) => match msg {
 +                lsp_server::Message::Request(req) => self.on_new_request(loop_start, req),
 +                lsp_server::Message::Notification(not) => {
 +                    self.on_notification(not)?;
 +                }
 +                lsp_server::Message::Response(resp) => self.complete_request(resp),
 +            },
 +            Event::Task(task) => {
 +                let _p = profile::span("GlobalState::handle_event/task");
 +                let mut prime_caches_progress = Vec::new();
 +
 +                self.handle_task(&mut prime_caches_progress, task);
 +                // Coalesce multiple task events into one loop turn
 +                while let Ok(task) = self.task_pool.receiver.try_recv() {
 +                    self.handle_task(&mut prime_caches_progress, task);
 +                }
 +
 +                for progress in prime_caches_progress {
 +                    let (state, message, fraction);
 +                    match progress {
 +                        PrimeCachesProgress::Begin => {
 +                            state = Progress::Begin;
 +                            message = None;
 +                            fraction = 0.0;
 +                        }
 +                        PrimeCachesProgress::Report(report) => {
 +                            state = Progress::Report;
 +
 +                            message = match &report.crates_currently_indexing[..] {
 +                                [crate_name] => Some(format!(
 +                                    "{}/{} ({})",
 +                                    report.crates_done, report.crates_total, crate_name
 +                                )),
 +                                [crate_name, rest @ ..] => Some(format!(
 +                                    "{}/{} ({} + {} more)",
 +                                    report.crates_done,
 +                                    report.crates_total,
 +                                    crate_name,
 +                                    rest.len()
 +                                )),
 +                                _ => None,
 +                            };
 +
 +                            fraction = Progress::fraction(report.crates_done, report.crates_total);
 +                        }
 +                        PrimeCachesProgress::End { cancelled } => {
 +                            state = Progress::End;
 +                            message = None;
 +                            fraction = 1.0;
 +
 +                            self.prime_caches_queue.op_completed(());
 +                            if cancelled {
 +                                self.prime_caches_queue
 +                                    .request_op("restart after cancellation".to_string());
 +                            }
 +                        }
 +                    };
 +
-                 self.report_progress("Fetching", state, msg, None);
++                    self.report_progress("Indexing", state, message, Some(fraction), None);
 +                }
 +            }
 +            Event::Vfs(message) => {
 +                let _p = profile::span("GlobalState::handle_event/vfs");
 +                self.handle_vfs_msg(message);
 +                // Coalesce many VFS event into a single loop turn
 +                while let Ok(message) = self.loader.receiver.try_recv() {
 +                    self.handle_vfs_msg(message);
 +                }
 +            }
 +            Event::Flycheck(message) => {
 +                let _p = profile::span("GlobalState::handle_event/flycheck");
 +                self.handle_flycheck_msg(message);
 +                // Coalesce many flycheck updates into a single loop turn
 +                while let Ok(message) = self.flycheck_receiver.try_recv() {
 +                    self.handle_flycheck_msg(message);
 +                }
 +            }
 +        }
 +
 +        let state_changed = self.process_changes();
 +        let memdocs_added_or_removed = self.mem_docs.take_changes();
 +
 +        if self.is_quiescent() {
 +            let became_quiescent = !(was_quiescent
 +                || self.fetch_workspaces_queue.op_requested()
 +                || self.fetch_build_data_queue.op_requested());
 +
 +            if became_quiescent {
 +                // Project has loaded properly, kick off initial flycheck
 +                self.flycheck.iter().for_each(FlycheckHandle::restart);
 +                if self.config.prefill_caches() {
 +                    self.prime_caches_queue.request_op("became quiescent".to_string());
 +                }
 +            }
 +
 +            if !was_quiescent || state_changed {
 +                // Refresh semantic tokens if the client supports it.
 +                if self.config.semantic_tokens_refresh() {
 +                    self.semantic_tokens_cache.lock().clear();
 +                    self.send_request::<lsp_types::request::SemanticTokensRefresh>((), |_, _| ());
 +                }
 +
 +                // Refresh code lens if the client supports it.
 +                if self.config.code_lens_refresh() {
 +                    self.send_request::<lsp_types::request::CodeLensRefresh>((), |_, _| ());
 +                }
 +            }
 +
 +            if !was_quiescent || state_changed || memdocs_added_or_removed {
 +                if self.config.publish_diagnostics() {
 +                    self.update_diagnostics()
 +                }
 +            }
 +        }
 +
 +        if let Some(diagnostic_changes) = self.diagnostics.take_changes() {
 +            for file_id in diagnostic_changes {
 +                let db = self.analysis_host.raw_database();
 +                let source_root = db.file_source_root(file_id);
 +                if db.source_root(source_root).is_library {
 +                    // Only publish diagnostics for files in the workspace, not from crates.io deps
 +                    // or the sysroot.
 +                    // While theoretically these should never have errors, we have quite a few false
 +                    // positives particularly in the stdlib, and those diagnostics would stay around
 +                    // forever if we emitted them here.
 +                    continue;
 +                }
 +
 +                let uri = file_id_to_url(&self.vfs.read().0, file_id);
 +                let mut diagnostics =
 +                    self.diagnostics.diagnostics_for(file_id).cloned().collect::<Vec<_>>();
 +
 +                // VSCode assumes diagnostic messages to be non-empty strings, so we need to patch
 +                // empty diagnostics. Neither the docs of VSCode nor the LSP spec say whether
 +                // diagnostic messages are actually allowed to be empty or not and patching this
 +                // in the VSCode client does not work as the assertion happens in the protocol
 +                // conversion. So this hack is here to stay, and will be considered a hack
 +                // until the LSP decides to state that empty messages are allowed.
 +
 +                // See https://github.com/rust-lang/rust-analyzer/issues/11404
 +                // See https://github.com/rust-lang/rust-analyzer/issues/13130
 +                let patch_empty = |message: &mut String| {
 +                    if message.is_empty() {
 +                        *message = " ".to_string();
 +                    }
 +                };
 +
 +                for d in &mut diagnostics {
 +                    patch_empty(&mut d.message);
 +                    if let Some(dri) = &mut d.related_information {
 +                        for dri in dri {
 +                            patch_empty(&mut dri.message);
 +                        }
 +                    }
 +                }
 +
 +                let version = from_proto::vfs_path(&uri)
 +                    .map(|path| self.mem_docs.get(&path).map(|it| it.version))
 +                    .unwrap_or_default();
 +
 +                self.send_notification::<lsp_types::notification::PublishDiagnostics>(
 +                    lsp_types::PublishDiagnosticsParams { uri, diagnostics, version },
 +                );
 +            }
 +        }
 +
 +        if self.config.cargo_autoreload() {
 +            if let Some(cause) = self.fetch_workspaces_queue.should_start_op() {
 +                self.fetch_workspaces(cause);
 +            }
 +        }
 +
 +        if !self.fetch_workspaces_queue.op_in_progress() {
 +            if let Some(cause) = self.fetch_build_data_queue.should_start_op() {
 +                self.fetch_build_data(cause);
 +            }
 +        }
 +
 +        if let Some(cause) = self.prime_caches_queue.should_start_op() {
 +            tracing::debug!(%cause, "will prime caches");
 +            let num_worker_threads = self.config.prime_caches_num_threads();
 +
 +            self.task_pool.handle.spawn_with_sender({
 +                let analysis = self.snapshot().analysis;
 +                move |sender| {
 +                    sender.send(Task::PrimeCaches(PrimeCachesProgress::Begin)).unwrap();
 +                    let res = analysis.parallel_prime_caches(num_worker_threads, |progress| {
 +                        let report = PrimeCachesProgress::Report(progress);
 +                        sender.send(Task::PrimeCaches(report)).unwrap();
 +                    });
 +                    sender
 +                        .send(Task::PrimeCaches(PrimeCachesProgress::End {
 +                            cancelled: res.is_err(),
 +                        }))
 +                        .unwrap();
 +                }
 +            });
 +        }
 +
 +        let status = self.current_status();
 +        if self.last_reported_status.as_ref() != Some(&status) {
 +            self.last_reported_status = Some(status.clone());
 +
 +            if let (lsp_ext::Health::Error, Some(message)) = (status.health, &status.message) {
 +                self.show_message(lsp_types::MessageType::ERROR, message.clone());
 +            }
 +
 +            if self.config.server_status_notification() {
 +                self.send_notification::<lsp_ext::ServerStatusNotification>(status);
 +            }
 +        }
 +
 +        let loop_duration = loop_start.elapsed();
 +        if loop_duration > Duration::from_millis(100) && was_quiescent {
 +            tracing::warn!("overly long loop turn: {:?}", loop_duration);
 +            self.poke_rust_analyzer_developer(format!(
 +                "overly long loop turn: {:?}",
 +                loop_duration
 +            ));
 +        }
 +        Ok(())
 +    }
 +
 +    fn handle_task(&mut self, prime_caches_progress: &mut Vec<PrimeCachesProgress>, task: Task) {
 +        match task {
 +            Task::Response(response) => self.respond(response),
 +            // Only retry requests that haven't been cancelled. Otherwise we do unnecessary work.
 +            Task::Retry(req) if !self.is_completed(&req) => self.on_request(req),
 +            Task::Retry(_) => (),
 +            Task::Diagnostics(diagnostics_per_file) => {
 +                for (file_id, diagnostics) in diagnostics_per_file {
 +                    self.diagnostics.set_native_diagnostics(file_id, diagnostics)
 +                }
 +            }
 +            Task::PrimeCaches(progress) => match progress {
 +                PrimeCachesProgress::Begin => prime_caches_progress.push(progress),
 +                PrimeCachesProgress::Report(_) => {
 +                    match prime_caches_progress.last_mut() {
 +                        Some(last @ PrimeCachesProgress::Report(_)) => {
 +                            // Coalesce subsequent update events.
 +                            *last = progress;
 +                        }
 +                        _ => prime_caches_progress.push(progress),
 +                    }
 +                }
 +                PrimeCachesProgress::End { .. } => prime_caches_progress.push(progress),
 +            },
 +            Task::FetchWorkspace(progress) => {
 +                let (state, msg) = match progress {
 +                    ProjectWorkspaceProgress::Begin => (Progress::Begin, None),
 +                    ProjectWorkspaceProgress::Report(msg) => (Progress::Report, Some(msg)),
 +                    ProjectWorkspaceProgress::End(workspaces) => {
 +                        self.fetch_workspaces_queue.op_completed(workspaces);
 +
 +                        let old = Arc::clone(&self.workspaces);
 +                        self.switch_workspaces("fetched workspace".to_string());
 +                        let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces);
 +
 +                        if self.config.run_build_scripts() && workspaces_updated {
 +                            self.fetch_build_data_queue.request_op(format!("workspace updated"));
 +                        }
 +
 +                        (Progress::End, None)
 +                    }
 +                };
 +
-                     self.report_progress("Loading", state, msg, None);
++                self.report_progress("Fetching", state, msg, None, None);
 +            }
 +            Task::FetchBuildData(progress) => {
 +                let (state, msg) = match progress {
 +                    BuildDataProgress::Begin => (Some(Progress::Begin), None),
 +                    BuildDataProgress::Report(msg) => (Some(Progress::Report), Some(msg)),
 +                    BuildDataProgress::End(build_data_result) => {
 +                        self.fetch_build_data_queue.op_completed(build_data_result);
 +
 +                        self.switch_workspaces("fetched build data".to_string());
 +
 +                        (Some(Progress::End), None)
 +                    }
 +                };
 +
 +                if let Some(state) = state {
-                             tracing::error!("File with cargo diagnostic not found in VFS: {}", err);
++                    self.report_progress("Loading", state, msg, None, None);
 +                }
 +            }
 +        }
 +    }
 +
 +    fn handle_vfs_msg(&mut self, message: vfs::loader::Message) {
 +        match message {
 +            vfs::loader::Message::Loaded { files } => {
 +                let vfs = &mut self.vfs.write().0;
 +                for (path, contents) in files {
 +                    let path = VfsPath::from(path);
 +                    if !self.mem_docs.contains(&path) {
 +                        vfs.set_file_contents(path, contents);
 +                    }
 +                }
 +            }
 +            vfs::loader::Message::Progress { n_total, n_done, config_version } => {
 +                always!(config_version <= self.vfs_config_version);
 +
 +                self.vfs_progress_config_version = config_version;
 +                self.vfs_progress_n_total = n_total;
 +                self.vfs_progress_n_done = n_done;
 +
 +                let state = if n_done == 0 {
 +                    Progress::Begin
 +                } else if n_done < n_total {
 +                    Progress::Report
 +                } else {
 +                    assert_eq!(n_done, n_total);
 +                    Progress::End
 +                };
 +                self.report_progress(
 +                    "Roots Scanned",
 +                    state,
 +                    Some(format!("{}/{}", n_done, n_total)),
 +                    Some(Progress::fraction(n_done, n_total)),
++                    None,
 +                )
 +            }
 +        }
 +    }
 +
 +    fn handle_flycheck_msg(&mut self, message: flycheck::Message) {
 +        match message {
 +            flycheck::Message::AddDiagnostic { id, workspace_root, diagnostic } => {
 +                let snap = self.snapshot();
 +                let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
 +                    &self.config.diagnostics_map(),
 +                    &diagnostic,
 +                    &workspace_root,
 +                    &snap,
 +                );
 +                for diag in diagnostics {
 +                    match url_to_file_id(&self.vfs.read().0, &diag.url) {
 +                        Ok(file_id) => self.diagnostics.add_check_diagnostic(
 +                            id,
 +                            file_id,
 +                            diag.diagnostic,
 +                            diag.fix,
 +                        ),
 +                        Err(err) => {
-                 self.report_progress(&title, state, message, None);
++                            tracing::error!(
++                                "flycheck {id}: File with cargo diagnostic not found in VFS: {}",
++                                err
++                            );
 +                        }
 +                    };
 +                }
 +            }
 +
 +            flycheck::Message::Progress { id, progress } => {
 +                let (state, message) = match progress {
 +                    flycheck::Progress::DidStart => {
 +                        self.diagnostics.clear_check(id);
 +                        (Progress::Begin, None)
 +                    }
 +                    flycheck::Progress::DidCheckCrate(target) => (Progress::Report, Some(target)),
 +                    flycheck::Progress::DidCancel => (Progress::End, None),
 +                    flycheck::Progress::DidFailToRestart(err) => {
 +                        self.show_and_log_error(
 +                            "cargo check failed".to_string(),
 +                            Some(err.to_string()),
 +                        );
 +                        return;
 +                    }
 +                    flycheck::Progress::DidFinish(result) => {
 +                        if let Err(err) = result {
 +                            self.show_and_log_error(
 +                                "cargo check failed".to_string(),
 +                                Some(err.to_string()),
 +                            );
 +                        }
 +                        (Progress::End, None)
 +                    }
 +                };
 +
 +                // When we're running multiple flychecks, we have to include a disambiguator in
 +                // the title, or the editor complains. Note that this is a user-facing string.
 +                let title = if self.flycheck.len() == 1 {
 +                    match self.config.flycheck() {
 +                        Some(config) => format!("{}", config),
 +                        None => "cargo check".to_string(),
 +                    }
 +                } else {
 +                    format!("cargo check (#{})", id + 1)
 +                };
-             .on::<lsp_types::notification::WorkDoneProgressCancel>(|_this, _params| {
++                self.report_progress(
++                    &title,
++                    state,
++                    message,
++                    None,
++                    Some(format!("rust-analyzer/checkOnSave/{}", id)),
++                );
 +            }
 +        }
 +    }
 +
 +    /// Registers and handles a request. This should only be called once per incoming request.
 +    fn on_new_request(&mut self, request_received: Instant, req: Request) {
 +        self.register_request(&req, request_received);
 +        self.on_request(req);
 +    }
 +
 +    /// Handles a request.
 +    fn on_request(&mut self, req: Request) {
 +        if self.shutdown_requested {
 +            self.respond(lsp_server::Response::new_err(
 +                req.id,
 +                lsp_server::ErrorCode::InvalidRequest as i32,
 +                "Shutdown already requested.".to_owned(),
 +            ));
 +            return;
 +        }
 +
 +        // Avoid flashing a bunch of unresolved references during initial load.
 +        if self.workspaces.is_empty() && !self.is_quiescent() {
 +            self.respond(lsp_server::Response::new_err(
 +                req.id,
 +                lsp_server::ErrorCode::ContentModified as i32,
 +                "waiting for cargo metadata or cargo check".to_owned(),
 +            ));
 +            return;
 +        }
 +
 +        RequestDispatcher { req: Some(req), global_state: self }
 +            .on_sync_mut::<lsp_types::request::Shutdown>(|s, ()| {
 +                s.shutdown_requested = true;
 +                Ok(())
 +            })
 +            .on_sync_mut::<lsp_ext::ReloadWorkspace>(handlers::handle_workspace_reload)
 +            .on_sync_mut::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage)
 +            .on_sync_mut::<lsp_ext::ShuffleCrateGraph>(handlers::handle_shuffle_crate_graph)
 +            .on_sync_mut::<lsp_ext::CancelFlycheck>(handlers::handle_cancel_flycheck)
 +            .on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines)
 +            .on_sync::<lsp_ext::OnEnter>(handlers::handle_on_enter)
 +            .on_sync::<lsp_types::request::SelectionRangeRequest>(handlers::handle_selection_range)
 +            .on_sync::<lsp_ext::MatchingBrace>(handlers::handle_matching_brace)
 +            .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
 +            .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
 +            .on::<lsp_ext::ViewHir>(handlers::handle_view_hir)
 +            .on::<lsp_ext::ViewFileText>(handlers::handle_view_file_text)
 +            .on::<lsp_ext::ViewCrateGraph>(handlers::handle_view_crate_graph)
 +            .on::<lsp_ext::ViewItemTree>(handlers::handle_view_item_tree)
 +            .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
 +            .on::<lsp_ext::ParentModule>(handlers::handle_parent_module)
 +            .on::<lsp_ext::Runnables>(handlers::handle_runnables)
 +            .on::<lsp_ext::RelatedTests>(handlers::handle_related_tests)
 +            .on::<lsp_ext::CodeActionRequest>(handlers::handle_code_action)
 +            .on::<lsp_ext::CodeActionResolveRequest>(handlers::handle_code_action_resolve)
 +            .on::<lsp_ext::HoverRequest>(handlers::handle_hover)
 +            .on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs)
 +            .on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
 +            .on::<lsp_ext::MoveItem>(handlers::handle_move_item)
 +            .on::<lsp_ext::WorkspaceSymbol>(handlers::handle_workspace_symbol)
 +            .on::<lsp_ext::OnTypeFormatting>(handlers::handle_on_type_formatting)
 +            .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)
 +            .on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition)
 +            .on::<lsp_types::request::GotoDeclaration>(handlers::handle_goto_declaration)
 +            .on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation)
 +            .on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
 +            .on::<lsp_types::request::InlayHintRequest>(handlers::handle_inlay_hints)
 +            .on::<lsp_types::request::InlayHintResolveRequest>(handlers::handle_inlay_hints_resolve)
 +            .on::<lsp_types::request::Completion>(handlers::handle_completion)
 +            .on::<lsp_types::request::ResolveCompletionItem>(handlers::handle_completion_resolve)
 +            .on::<lsp_types::request::CodeLensRequest>(handlers::handle_code_lens)
 +            .on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve)
 +            .on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range)
 +            .on::<lsp_types::request::SignatureHelpRequest>(handlers::handle_signature_help)
 +            .on::<lsp_types::request::PrepareRenameRequest>(handlers::handle_prepare_rename)
 +            .on::<lsp_types::request::Rename>(handlers::handle_rename)
 +            .on::<lsp_types::request::References>(handlers::handle_references)
 +            .on::<lsp_types::request::Formatting>(handlers::handle_formatting)
 +            .on::<lsp_types::request::RangeFormatting>(handlers::handle_range_formatting)
 +            .on::<lsp_types::request::DocumentHighlightRequest>(handlers::handle_document_highlight)
 +            .on::<lsp_types::request::CallHierarchyPrepare>(handlers::handle_call_hierarchy_prepare)
 +            .on::<lsp_types::request::CallHierarchyIncomingCalls>(
 +                handlers::handle_call_hierarchy_incoming,
 +            )
 +            .on::<lsp_types::request::CallHierarchyOutgoingCalls>(
 +                handlers::handle_call_hierarchy_outgoing,
 +            )
 +            .on::<lsp_types::request::SemanticTokensFullRequest>(
 +                handlers::handle_semantic_tokens_full,
 +            )
 +            .on::<lsp_types::request::SemanticTokensFullDeltaRequest>(
 +                handlers::handle_semantic_tokens_full_delta,
 +            )
 +            .on::<lsp_types::request::SemanticTokensRangeRequest>(
 +                handlers::handle_semantic_tokens_range,
 +            )
 +            .on::<lsp_types::request::WillRenameFiles>(handlers::handle_will_rename_files)
 +            .on::<lsp_ext::Ssr>(handlers::handle_ssr)
 +            .finish();
 +    }
 +
 +    /// Handles an incoming notification.
 +    fn on_notification(&mut self, not: Notification) -> Result<()> {
 +        NotificationDispatcher { not: Some(not), global_state: self }
 +            .on::<lsp_types::notification::Cancel>(|this, params| {
 +                let id: lsp_server::RequestId = match params.id {
 +                    lsp_types::NumberOrString::Number(id) => id.into(),
 +                    lsp_types::NumberOrString::String(id) => id.into(),
 +                };
 +                this.cancel(id);
 +                Ok(())
 +            })?
-                         tracing::error!("duplicate DidOpenTextDocument: {}", path)
++            .on::<lsp_types::notification::WorkDoneProgressCancel>(|this, params| {
++                if let lsp_types::NumberOrString::String(s) = &params.token {
++                    if let Some(id) = s.strip_prefix("rust-analyzer/checkOnSave/") {
++                        if let Ok(id) = u32::from_str_radix(id, 10) {
++                            if let Some(flycheck) = this.flycheck.get(id as usize) {
++                                flycheck.cancel();
++                            }
++                        }
++                    }
++                }
 +                // Just ignore this. It is OK to continue sending progress
 +                // notifications for this token, as the client can't know when
 +                // we accepted notification.
 +                Ok(())
 +            })?
 +            .on::<lsp_types::notification::DidOpenTextDocument>(|this, params| {
 +                if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
 +                    let already_exists = this
 +                        .mem_docs
 +                        .insert(path.clone(), DocumentData::new(params.text_document.version))
 +                        .is_err();
 +                    if already_exists {
-                 let mut updated = false;
++                        tracing::error!("duplicate DidOpenTextDocument: {}", path);
 +                    }
 +                    this.vfs
 +                        .write()
 +                        .0
 +                        .set_file_contents(path, Some(params.text_document.text.into_bytes()));
 +                }
 +                Ok(())
 +            })?
 +            .on::<lsp_types::notification::DidChangeTextDocument>(|this, params| {
 +                if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
 +                    match this.mem_docs.get_mut(&path) {
 +                        Some(doc) => {
 +                            // The version passed in DidChangeTextDocument is the version after all edits are applied
 +                            // so we should apply it before the vfs is notified.
 +                            doc.version = params.text_document.version;
 +                        }
 +                        None => {
 +                            tracing::error!("unexpected DidChangeTextDocument: {}", path);
 +                            return Ok(());
 +                        }
 +                    };
 +
 +                    let vfs = &mut this.vfs.write().0;
 +                    let file_id = vfs.file_id(&path).unwrap();
 +                    let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap();
 +                    apply_document_changes(&mut text, params.content_changes);
 +
 +                    vfs.set_file_contents(path, Some(text.into_bytes()));
 +                }
 +                Ok(())
 +            })?
 +            .on::<lsp_types::notification::DidCloseTextDocument>(|this, params| {
 +                if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
 +                    if this.mem_docs.remove(&path).is_err() {
 +                        tracing::error!("orphan DidCloseTextDocument: {}", path);
 +                    }
 +
 +                    this.semantic_tokens_cache.lock().remove(&params.text_document.uri);
 +
 +                    if let Some(path) = path.as_path() {
 +                        this.loader.handle.invalidate(path.to_path_buf());
 +                    }
 +                }
 +                Ok(())
 +            })?
 +            .on::<lsp_types::notification::DidSaveTextDocument>(|this, params| {
-                     let (vfs, _) = &*this.vfs.read();
-                     // Trigger flychecks for all workspaces that depend on the saved file
-                     if let Some(file_id) = vfs.file_id(&vfs_path) {
-                         let analysis = this.analysis_host.analysis();
-                         // Crates containing or depending on the saved file
-                         let crate_ids: Vec<_> = analysis
-                             .crate_for(file_id)?
-                             .into_iter()
-                             .flat_map(|id| {
-                                 this.analysis_host
-                                     .raw_database()
-                                     .crate_graph()
-                                     .transitive_rev_deps(id)
-                             })
-                             .sorted()
-                             .unique()
-                             .collect();
-                         let crate_root_paths: Vec<_> = crate_ids
-                             .iter()
-                             .filter_map(|&crate_id| {
-                                 analysis
-                                     .crate_root(crate_id)
-                                     .map(|file_id| {
-                                         vfs.file_path(file_id).as_path().map(ToOwned::to_owned)
-                                     })
-                                     .transpose()
-                             })
-                             .collect::<ide::Cancellable<_>>()?;
-                         let crate_root_paths: Vec<_> =
-                             crate_root_paths.iter().map(Deref::deref).collect();
-                         // Find all workspaces that have at least one target containing the saved file
-                         let workspace_ids =
-                             this.workspaces.iter().enumerate().filter(|(_, ws)| match ws {
-                                 project_model::ProjectWorkspace::Cargo { cargo, .. } => {
-                                     cargo.packages().any(|pkg| {
-                                         cargo[pkg].targets.iter().any(|&it| {
-                                             crate_root_paths.contains(&cargo[it].root.as_path())
-                                         })
-                                     })
-                                 }
-                                 project_model::ProjectWorkspace::Json { project, .. } => project
-                                     .crates()
-                                     .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)),
-                                 project_model::ProjectWorkspace::DetachedFiles { .. } => false,
-                             });
-                         // Find and trigger corresponding flychecks
-                         for flycheck in &this.flycheck {
-                             for (id, _) in workspace_ids.clone() {
-                                 if id == flycheck.id() {
-                                     updated = true;
-                                     flycheck.restart();
-                                     continue;
-                                 }
-                             }
-                         }
-                     }
 +                if let Ok(vfs_path) = from_proto::vfs_path(&params.text_document.uri) {
-                 if !updated {
-                     for flycheck in &this.flycheck {
-                         flycheck.restart();
-                     }
 +                    // Re-fetch workspaces if a workspace related file has changed
 +                    if let Some(abs_path) = vfs_path.as_path() {
 +                        if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) {
 +                            this.fetch_workspaces_queue
 +                                .request_op(format!("DidSaveTextDocument {}", abs_path.display()));
 +                        }
 +                    }
++
++                    let file_id = this.vfs.read().0.file_id(&vfs_path);
++                    if let Some(file_id) = file_id {
++                        let world = this.snapshot();
++                        let mut updated = false;
++                        let task = move || -> std::result::Result<(), ide::Cancelled> {
++                            // Trigger flychecks for all workspaces that depend on the saved file
++                            // Crates containing or depending on the saved file
++                            let crate_ids: Vec<_> = world
++                                .analysis
++                                .crates_for(file_id)?
++                                .into_iter()
++                                .flat_map(|id| world.analysis.transitive_rev_deps(id))
++                                .flatten()
++                                .sorted()
++                                .unique()
++                                .collect();
++
++                            let crate_root_paths: Vec<_> = crate_ids
++                                .iter()
++                                .filter_map(|&crate_id| {
++                                    world
++                                        .analysis
++                                        .crate_root(crate_id)
++                                        .map(|file_id| {
++                                            world
++                                                .file_id_to_file_path(file_id)
++                                                .as_path()
++                                                .map(ToOwned::to_owned)
++                                        })
++                                        .transpose()
++                                })
++                                .collect::<ide::Cancellable<_>>()?;
++                            let crate_root_paths: Vec<_> =
++                                crate_root_paths.iter().map(Deref::deref).collect();
++
++                            // Find all workspaces that have at least one target containing the saved file
++                            let workspace_ids =
++                                world.workspaces.iter().enumerate().filter(|(_, ws)| match ws {
++                                    project_model::ProjectWorkspace::Cargo { cargo, .. } => {
++                                        cargo.packages().any(|pkg| {
++                                            cargo[pkg].targets.iter().any(|&it| {
++                                                crate_root_paths.contains(&cargo[it].root.as_path())
++                                            })
++                                        })
++                                    }
++                                    project_model::ProjectWorkspace::Json { project, .. } => {
++                                        project.crates().any(|(c, _)| {
++                                            crate_ids.iter().any(|&crate_id| crate_id == c)
++                                        })
++                                    }
++                                    project_model::ProjectWorkspace::DetachedFiles { .. } => false,
++                                });
++
++                            // Find and trigger corresponding flychecks
++                            for flycheck in world.flycheck.iter() {
++                                for (id, _) in workspace_ids.clone() {
++                                    if id == flycheck.id() {
++                                        updated = true;
++                                        flycheck.restart();
++                                        continue;
++                                    }
++                                }
++                            }
++                            // No specific flycheck was triggered, so let's trigger all of them.
++                            if !updated {
++                                for flycheck in world.flycheck.iter() {
++                                    flycheck.restart();
++                                }
++                            }
++                            Ok(())
++                        };
++                        this.task_pool.handle.spawn_with_sender(move |_| {
++                            if let Err(e) = std::panic::catch_unwind(task) {
++                                tracing::error!("DidSaveTextDocument flycheck task panicked: {e:?}")
++                            }
++                        });
++                        return Ok(());
++                    }
 +                }
 +
 +                // No specific flycheck was triggered, so let's trigger all of them.
++                for flycheck in this.flycheck.iter() {
++                    flycheck.restart();
 +                }
 +                Ok(())
 +            })?
 +            .on::<lsp_types::notification::DidChangeConfiguration>(|this, _params| {
 +                // As stated in https://github.com/microsoft/language-server-protocol/issues/676,
 +                // this notification's parameters should be ignored and the actual config queried separately.
 +                this.send_request::<lsp_types::request::WorkspaceConfiguration>(
 +                    lsp_types::ConfigurationParams {
 +                        items: vec![lsp_types::ConfigurationItem {
 +                            scope_uri: None,
 +                            section: Some("rust-analyzer".to_string()),
 +                        }],
 +                    },
 +                    |this, resp| {
 +                        tracing::debug!("config update response: '{:?}", resp);
 +                        let lsp_server::Response { error, result, .. } = resp;
 +
 +                        match (error, result) {
 +                            (Some(err), _) => {
 +                                tracing::error!("failed to fetch the server settings: {:?}", err)
 +                            }
 +                            (None, Some(mut configs)) => {
 +                                if let Some(json) = configs.get_mut(0) {
 +                                    // Note that json can be null according to the spec if the client can't
 +                                    // provide a configuration. This is handled in Config::update below.
 +                                    let mut config = Config::clone(&*this.config);
 +                                    if let Err(error) = config.update(json.take()) {
 +                                        this.show_message(
 +                                            lsp_types::MessageType::WARNING,
 +                                            error.to_string(),
 +                                        );
 +                                    }
 +                                    this.update_configuration(config);
 +                                }
 +                            }
 +                            (None, None) => tracing::error!(
 +                                "received empty server settings response from the client"
 +                            ),
 +                        }
 +                    },
 +                );
 +
 +                Ok(())
 +            })?
 +            .on::<lsp_types::notification::DidChangeWatchedFiles>(|this, params| {
 +                for change in params.changes {
 +                    if let Ok(path) = from_proto::abs_path(&change.uri) {
 +                        this.loader.handle.invalidate(path);
 +                    }
 +                }
 +                Ok(())
 +            })?
 +            .finish();
 +        Ok(())
 +    }
 +
 +    fn update_diagnostics(&mut self) {
 +        let subscriptions = self
 +            .mem_docs
 +            .iter()
 +            .map(|path| self.vfs.read().0.file_id(path).unwrap())
 +            .collect::<Vec<_>>();
 +
 +        tracing::trace!("updating notifications for {:?}", subscriptions);
 +
 +        let snapshot = self.snapshot();
 +        self.task_pool.handle.spawn(move || {
 +            let diagnostics = subscriptions
 +                .into_iter()
 +                .filter_map(|file_id| {
 +                    handlers::publish_diagnostics(&snapshot, file_id)
 +                        .ok()
 +                        .map(|diags| (file_id, diags))
 +                })
 +                .collect::<Vec<_>>();
 +            Task::Diagnostics(diagnostics)
 +        })
 +    }
 +}
index f8734893944624e169bc8969da9759707945b9ad,0000000000000000000000000000000000000000..e1f651786dee411fc43456fdf30d797cda70f735
mode 100644,000000..100644
--- /dev/null
@@@ -1,738 -1,0 +1,751 @@@
-             let mut res = Vec::new();
-             for ws in workspaces.iter() {
-                 res.push(ws.run_build_scripts(&config, &progress));
-             }
 +//! Project loading & configuration updates.
 +//!
 +//! This is quite tricky. The main problem is time and changes -- there's no
 +//! fixed "project" rust-analyzer is working with, "current project" is itself
 +//! mutable state. For example, when the user edits `Cargo.toml` by adding a new
 +//! dependency, project model changes. What's more, switching project model is
 +//! not instantaneous -- it takes time to run `cargo metadata` and (for proc
 +//! macros) `cargo check`.
 +//!
 +//! The main guiding principle here is, as elsewhere in rust-analyzer,
 +//! robustness. We try not to assume that the project model exists or is
 +//! correct. Instead, we try to provide a best-effort service. Even if the
 +//! project is currently loading and we don't have a full project model, we
 +//! still want to respond to various  requests.
 +use std::{mem, sync::Arc};
 +
 +use flycheck::{FlycheckConfig, FlycheckHandle};
 +use hir::db::DefDatabase;
 +use ide::Change;
 +use ide_db::base_db::{
 +    CrateGraph, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind,
 +    ProcMacroLoadResult, SourceRoot, VfsPath,
 +};
 +use proc_macro_api::{MacroDylib, ProcMacroServer};
 +use project_model::{ProjectWorkspace, WorkspaceBuildScripts};
 +use syntax::SmolStr;
 +use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};
 +
 +use crate::{
 +    config::{Config, FilesWatcher, LinkedProject},
 +    global_state::GlobalState,
 +    lsp_ext,
 +    main_loop::Task,
 +    op_queue::Cause,
 +};
 +
 +#[derive(Debug)]
 +pub(crate) enum ProjectWorkspaceProgress {
 +    Begin,
 +    Report(String),
 +    End(Vec<anyhow::Result<ProjectWorkspace>>),
 +}
 +
 +#[derive(Debug)]
 +pub(crate) enum BuildDataProgress {
 +    Begin,
 +    Report(String),
 +    End((Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>)),
 +}
 +
 +impl GlobalState {
 +    pub(crate) fn is_quiescent(&self) -> bool {
 +        !(self.fetch_workspaces_queue.op_in_progress()
 +            || self.fetch_build_data_queue.op_in_progress()
 +            || self.vfs_progress_config_version < self.vfs_config_version
 +            || self.vfs_progress_n_done < self.vfs_progress_n_total)
 +    }
 +
 +    pub(crate) fn update_configuration(&mut self, config: Config) {
 +        let _p = profile::span("GlobalState::update_configuration");
 +        let old_config = mem::replace(&mut self.config, Arc::new(config));
 +        if self.config.lru_capacity() != old_config.lru_capacity() {
 +            self.analysis_host.update_lru_capacity(self.config.lru_capacity());
 +        }
 +        if self.config.linked_projects() != old_config.linked_projects() {
 +            self.fetch_workspaces_queue.request_op("linked projects changed".to_string())
 +        } else if self.config.flycheck() != old_config.flycheck() {
 +            self.reload_flycheck();
 +        }
 +
 +        if self.analysis_host.raw_database().enable_proc_attr_macros()
 +            != self.config.expand_proc_attr_macros()
 +        {
 +            self.analysis_host
 +                .raw_database_mut()
 +                .set_enable_proc_attr_macros(self.config.expand_proc_attr_macros());
 +        }
 +    }
 +
 +    pub(crate) fn current_status(&self) -> lsp_ext::ServerStatusParams {
 +        let mut status = lsp_ext::ServerStatusParams {
 +            health: lsp_ext::Health::Ok,
 +            quiescent: self.is_quiescent(),
 +            message: None,
 +        };
 +
 +        if self.proc_macro_changed {
 +            status.health = lsp_ext::Health::Warning;
 +            status.message =
 +                Some("Reload required due to source changes of a procedural macro.".into())
 +        }
 +        if let Err(_) = self.fetch_build_data_error() {
 +            status.health = lsp_ext::Health::Warning;
 +            status.message =
 +                Some("Failed to run build scripts of some packages, check the logs.".to_string());
 +        }
 +        if !self.config.cargo_autoreload()
 +            && self.is_quiescent()
 +            && self.fetch_workspaces_queue.op_requested()
 +        {
 +            status.health = lsp_ext::Health::Warning;
 +            status.message = Some("Workspace reload required".to_string())
 +        }
 +
 +        if let Err(error) = self.fetch_workspace_error() {
 +            status.health = lsp_ext::Health::Error;
 +            status.message = Some(error)
 +        }
 +        status
 +    }
 +
 +    pub(crate) fn fetch_workspaces(&mut self, cause: Cause) {
 +        tracing::info!(%cause, "will fetch workspaces");
 +
 +        self.task_pool.handle.spawn_with_sender({
 +            let linked_projects = self.config.linked_projects();
 +            let detached_files = self.config.detached_files().to_vec();
 +            let cargo_config = self.config.cargo();
 +
 +            move |sender| {
 +                let progress = {
 +                    let sender = sender.clone();
 +                    move |msg| {
 +                        sender
 +                            .send(Task::FetchWorkspace(ProjectWorkspaceProgress::Report(msg)))
 +                            .unwrap()
 +                    }
 +                };
 +
 +                sender.send(Task::FetchWorkspace(ProjectWorkspaceProgress::Begin)).unwrap();
 +
 +                let mut workspaces = linked_projects
 +                    .iter()
 +                    .map(|project| match project {
 +                        LinkedProject::ProjectManifest(manifest) => {
 +                            project_model::ProjectWorkspace::load(
 +                                manifest.clone(),
 +                                &cargo_config,
 +                                &progress,
 +                            )
 +                        }
 +                        LinkedProject::InlineJsonProject(it) => {
 +                            project_model::ProjectWorkspace::load_inline(
 +                                it.clone(),
 +                                cargo_config.target.as_deref(),
 +                                &cargo_config.extra_env,
 +                            )
 +                        }
 +                    })
 +                    .collect::<Vec<_>>();
 +
 +                if !detached_files.is_empty() {
 +                    workspaces
 +                        .push(project_model::ProjectWorkspace::load_detached_files(detached_files));
 +                }
 +
 +                tracing::info!("did fetch workspaces {:?}", workspaces);
 +                sender
 +                    .send(Task::FetchWorkspace(ProjectWorkspaceProgress::End(workspaces)))
 +                    .unwrap();
 +            }
 +        });
 +    }
 +
 +    pub(crate) fn fetch_build_data(&mut self, cause: Cause) {
 +        tracing::info!(%cause, "will fetch build data");
 +        let workspaces = Arc::clone(&self.workspaces);
 +        let config = self.config.cargo();
 +        self.task_pool.handle.spawn_with_sender(move |sender| {
 +            sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap();
 +
 +            let progress = {
 +                let sender = sender.clone();
 +                move |msg| {
 +                    sender.send(Task::FetchBuildData(BuildDataProgress::Report(msg))).unwrap()
 +                }
 +            };
-                 self.flycheck = Vec::new();
++            let res = ProjectWorkspace::run_all_build_scripts(&workspaces, &config, &progress);
++
 +            sender.send(Task::FetchBuildData(BuildDataProgress::End((workspaces, res)))).unwrap();
 +        });
 +    }
 +
 +    pub(crate) fn switch_workspaces(&mut self, cause: Cause) {
 +        let _p = profile::span("GlobalState::switch_workspaces");
 +        tracing::info!(%cause, "will switch workspaces");
 +
 +        if let Err(error_message) = self.fetch_workspace_error() {
 +            self.show_and_log_error(error_message, None);
 +            if !self.workspaces.is_empty() {
 +                // It only makes sense to switch to a partially broken workspace
 +                // if we don't have any workspace at all yet.
 +                return;
 +            }
 +        }
 +
 +        if let Err(error) = self.fetch_build_data_error() {
 +            self.show_and_log_error("failed to run build scripts".to_string(), Some(error));
 +        }
 +
 +        let workspaces = self
 +            .fetch_workspaces_queue
 +            .last_op_result()
 +            .iter()
 +            .filter_map(|res| res.as_ref().ok().cloned())
 +            .collect::<Vec<_>>();
 +
 +        fn eq_ignore_build_data<'a>(
 +            left: &'a ProjectWorkspace,
 +            right: &'a ProjectWorkspace,
 +        ) -> bool {
 +            let key = |p: &'a ProjectWorkspace| match p {
 +                ProjectWorkspace::Cargo {
 +                    cargo,
 +                    sysroot,
 +                    rustc,
 +                    rustc_cfg,
 +                    cfg_overrides,
 +
 +                    build_scripts: _,
 +                    toolchain: _,
 +                } => Some((cargo, sysroot, rustc, rustc_cfg, cfg_overrides)),
 +                _ => None,
 +            };
 +            match (key(left), key(right)) {
 +                (Some(lk), Some(rk)) => lk == rk,
 +                _ => left == right,
 +            }
 +        }
 +
 +        let same_workspaces = workspaces.len() == self.workspaces.len()
 +            && workspaces
 +                .iter()
 +                .zip(self.workspaces.iter())
 +                .all(|(l, r)| eq_ignore_build_data(l, r));
 +
 +        if same_workspaces {
 +            let (workspaces, build_scripts) = self.fetch_build_data_queue.last_op_result();
 +            if Arc::ptr_eq(workspaces, &self.workspaces) {
 +                tracing::debug!("set build scripts to workspaces");
 +
 +                let workspaces = workspaces
 +                    .iter()
 +                    .cloned()
 +                    .zip(build_scripts)
 +                    .map(|(mut ws, bs)| {
 +                        ws.set_build_scripts(bs.as_ref().ok().cloned().unwrap_or_default());
 +                        ws
 +                    })
 +                    .collect::<Vec<_>>();
 +
 +                // Workspaces are the same, but we've updated build data.
 +                self.workspaces = Arc::new(workspaces);
 +            } else {
 +                tracing::info!("build scripts do not match the version of the active workspace");
 +                // Current build scripts do not match the version of the active
 +                // workspace, so there's nothing for us to update.
 +                return;
 +            }
 +        } else {
 +            tracing::debug!("abandon build scripts for workspaces");
 +
 +            // Here, we completely changed the workspace (Cargo.toml edit), so
 +            // we don't care about build-script results, they are stale.
 +            self.workspaces = Arc::new(workspaces)
 +        }
 +
 +        if let FilesWatcher::Client = self.config.files().watcher {
 +            let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions {
 +                watchers: self
 +                    .workspaces
 +                    .iter()
 +                    .flat_map(|ws| ws.to_roots())
 +                    .filter(|it| it.is_local)
 +                    .flat_map(|root| {
 +                        root.include.into_iter().flat_map(|it| {
 +                            [
 +                                format!("{}/**/*.rs", it.display()),
 +                                format!("{}/**/Cargo.toml", it.display()),
 +                                format!("{}/**/Cargo.lock", it.display()),
 +                            ]
 +                        })
 +                    })
 +                    .map(|glob_pattern| lsp_types::FileSystemWatcher { glob_pattern, kind: None })
 +                    .collect(),
 +            };
 +            let registration = lsp_types::Registration {
 +                id: "workspace/didChangeWatchedFiles".to_string(),
 +                method: "workspace/didChangeWatchedFiles".to_string(),
 +                register_options: Some(serde_json::to_value(registration_options).unwrap()),
 +            };
 +            self.send_request::<lsp_types::request::RegisterCapability>(
 +                lsp_types::RegistrationParams { registrations: vec![registration] },
 +                |_, _| (),
 +            );
 +        }
 +
 +        let mut change = Change::new();
 +
 +        let files_config = self.config.files();
 +        let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
 +
 +        let standalone_server_name =
 +            format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
 +
 +        if self.proc_macro_clients.is_empty() {
 +            if let Some((path, path_manually_set)) = self.config.proc_macro_srv() {
 +                tracing::info!("Spawning proc-macro servers");
 +                self.proc_macro_clients = self
 +                    .workspaces
 +                    .iter()
 +                    .map(|ws| {
 +                        let (path, args) = if path_manually_set {
 +                            tracing::debug!(
 +                                "Pro-macro server path explicitly set: {}",
 +                                path.display()
 +                            );
 +                            (path.clone(), vec![])
 +                        } else {
 +                            let mut sysroot_server = None;
 +                            if let ProjectWorkspace::Cargo { sysroot, .. }
 +                            | ProjectWorkspace::Json { sysroot, .. } = ws
 +                            {
 +                                if let Some(sysroot) = sysroot.as_ref() {
 +                                    let server_path = sysroot
 +                                        .root()
 +                                        .join("libexec")
 +                                        .join(&standalone_server_name);
 +                                    if std::fs::metadata(&server_path).is_ok() {
 +                                        tracing::debug!(
 +                                            "Sysroot proc-macro server exists at {}",
 +                                            server_path.display()
 +                                        );
 +                                        sysroot_server = Some(server_path);
 +                                    } else {
 +                                        tracing::debug!(
 +                                            "Sysroot proc-macro server does not exist at {}",
 +                                            server_path.display()
 +                                        );
 +                                    }
 +                                }
 +                            }
 +                            sysroot_server.map_or_else(
 +                                || (path.clone(), vec!["proc-macro".to_owned()]),
 +                                |path| (path, vec![]),
 +                            )
 +                        };
 +
 +                        tracing::info!(?args, "Using proc-macro server at {}", path.display(),);
 +                        ProcMacroServer::spawn(path.clone(), args).map_err(|err| {
 +                            let error = format!(
 +                                "Failed to run proc-macro server from path {}, error: {:?}",
 +                                path.display(),
 +                                err
 +                            );
 +                            tracing::error!(error);
 +                            error
 +                        })
 +                    })
 +                    .collect()
 +            };
 +        }
 +
 +        let watch = match files_config.watcher {
 +            FilesWatcher::Client => vec![],
 +            FilesWatcher::Server => project_folders.watch,
 +        };
 +        self.vfs_config_version += 1;
 +        self.loader.handle.set_config(vfs::loader::Config {
 +            load: project_folders.load,
 +            watch,
 +            version: self.vfs_config_version,
 +        });
 +
 +        // Create crate graph from all the workspaces
 +        let crate_graph = {
 +            let dummy_replacements = self.config.dummy_replacements();
 +
 +            let vfs = &mut self.vfs.write().0;
 +            let loader = &mut self.loader;
 +            let mem_docs = &self.mem_docs;
 +            let mut load = move |path: &AbsPath| {
 +                let _p = profile::span("GlobalState::load");
 +                let vfs_path = vfs::VfsPath::from(path.to_path_buf());
 +                if !mem_docs.contains(&vfs_path) {
 +                    let contents = loader.handle.load_sync(path);
 +                    vfs.set_file_contents(vfs_path.clone(), contents);
 +                }
 +                let res = vfs.file_id(&vfs_path);
 +                if res.is_none() {
 +                    tracing::warn!("failed to load {}", path.display())
 +                }
 +                res
 +            };
 +
 +            let mut crate_graph = CrateGraph::default();
 +            for (idx, ws) in self.workspaces.iter().enumerate() {
 +                let proc_macro_client = match self.proc_macro_clients.get(idx) {
 +                    Some(res) => res.as_ref().map_err(|e| &**e),
 +                    None => Err("Proc macros are disabled"),
 +                };
 +                let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| {
 +                    load_proc_macro(
 +                        proc_macro_client,
 +                        path,
 +                        dummy_replacements.get(crate_name).map(|v| &**v).unwrap_or_default(),
 +                    )
 +                };
 +                crate_graph.extend(ws.to_crate_graph(
 +                    &mut load_proc_macro,
 +                    &mut load,
 +                    &self.config.cargo().extra_env,
 +                ));
 +            }
 +            crate_graph
 +        };
 +        change.set_crate_graph(crate_graph);
 +
 +        self.source_root_config = project_folders.source_root_config;
 +
 +        self.analysis_host.apply_change(change);
 +        self.process_changes();
 +        self.reload_flycheck();
 +        tracing::info!("did switch workspaces");
 +    }
 +
 +    fn fetch_workspace_error(&self) -> Result<(), String> {
 +        let mut buf = String::new();
 +
 +        for ws in self.fetch_workspaces_queue.last_op_result() {
 +            if let Err(err) = ws {
 +                stdx::format_to!(buf, "rust-analyzer failed to load workspace: {:#}\n", err);
 +            }
 +        }
 +
 +        if buf.is_empty() {
 +            return Ok(());
 +        }
 +
 +        Err(buf)
 +    }
 +
 +    fn fetch_build_data_error(&self) -> Result<(), String> {
 +        let mut buf = String::new();
 +
 +        for ws in &self.fetch_build_data_queue.last_op_result().1 {
 +            match ws {
 +                Ok(data) => match data.error() {
 +                    Some(stderr) => stdx::format_to!(buf, "{:#}\n", stderr),
 +                    _ => (),
 +                },
 +                // io errors
 +                Err(err) => stdx::format_to!(buf, "{:#}\n", err),
 +            }
 +        }
 +
 +        if buf.is_empty() {
 +            Ok(())
 +        } else {
 +            Err(buf)
 +        }
 +    }
 +
 +    fn reload_flycheck(&mut self) {
 +        let _p = profile::span("GlobalState::reload_flycheck");
 +        let config = match self.config.flycheck() {
 +            Some(it) => it,
 +            None => {
-         self.flycheck = self
-             .workspaces
-             .iter()
-             .enumerate()
-             .filter_map(|(id, w)| match w {
-                 ProjectWorkspace::Cargo { cargo, .. } => Some((id, cargo.workspace_root())),
-                 ProjectWorkspace::Json { project, .. } => {
-                     // Enable flychecks for json projects if a custom flycheck command was supplied
-                     // in the workspace configuration.
-                     match config {
-                         FlycheckConfig::CustomCommand { .. } => Some((id, project.path())),
-                         _ => None,
-                     }
-                 }
-                 ProjectWorkspace::DetachedFiles { .. } => None,
-             })
-             .map(|(id, root)| {
-                 let sender = sender.clone();
-                 FlycheckHandle::spawn(
-                     id,
-                     Box::new(move |msg| sender.send(msg).unwrap()),
-                     config.clone(),
-                     root.to_path_buf(),
-                 )
-             })
-             .collect();
++                self.flycheck = Arc::new([]);
 +                self.diagnostics.clear_check_all();
 +                return;
 +            }
 +        };
 +
 +        let sender = self.flycheck_sender.clone();
++        let invocation_strategy = match config {
++            FlycheckConfig::CargoCommand { .. } => flycheck::InvocationStrategy::PerWorkspace,
++            FlycheckConfig::CustomCommand { invocation_strategy, .. } => invocation_strategy,
++        };
++
++        self.flycheck = match invocation_strategy {
++            flycheck::InvocationStrategy::Once => vec![FlycheckHandle::spawn(
++                0,
++                Box::new(move |msg| sender.send(msg).unwrap()),
++                config.clone(),
++                self.config.root_path().clone(),
++            )],
++            flycheck::InvocationStrategy::PerWorkspace => {
++                self.workspaces
++                    .iter()
++                    .enumerate()
++                    .filter_map(|(id, w)| match w {
++                        ProjectWorkspace::Cargo { cargo, .. } => Some((id, cargo.workspace_root())),
++                        ProjectWorkspace::Json { project, .. } => {
++                            // Enable flychecks for json projects if a custom flycheck command was supplied
++                            // in the workspace configuration.
++                            match config {
++                                FlycheckConfig::CustomCommand { .. } => Some((id, project.path())),
++                                _ => None,
++                            }
++                        }
++                        ProjectWorkspace::DetachedFiles { .. } => None,
++                    })
++                    .map(|(id, root)| {
++                        let sender = sender.clone();
++                        FlycheckHandle::spawn(
++                            id,
++                            Box::new(move |msg| sender.send(msg).unwrap()),
++                            config.clone(),
++                            root.to_path_buf(),
++                        )
++                    })
++                    .collect()
++            }
++        }
++        .into();
 +    }
 +}
 +
 +#[derive(Default)]
 +pub(crate) struct ProjectFolders {
 +    pub(crate) load: Vec<vfs::loader::Entry>,
 +    pub(crate) watch: Vec<usize>,
 +    pub(crate) source_root_config: SourceRootConfig,
 +}
 +
 +impl ProjectFolders {
 +    pub(crate) fn new(
 +        workspaces: &[ProjectWorkspace],
 +        global_excludes: &[AbsPathBuf],
 +    ) -> ProjectFolders {
 +        let mut res = ProjectFolders::default();
 +        let mut fsc = FileSetConfig::builder();
 +        let mut local_filesets = vec![];
 +
 +        for root in workspaces.iter().flat_map(|ws| ws.to_roots()) {
 +            let file_set_roots: Vec<VfsPath> =
 +                root.include.iter().cloned().map(VfsPath::from).collect();
 +
 +            let entry = {
 +                let mut dirs = vfs::loader::Directories::default();
 +                dirs.extensions.push("rs".into());
 +                dirs.include.extend(root.include);
 +                dirs.exclude.extend(root.exclude);
 +                for excl in global_excludes {
 +                    if dirs
 +                        .include
 +                        .iter()
 +                        .any(|incl| incl.starts_with(excl) || excl.starts_with(incl))
 +                    {
 +                        dirs.exclude.push(excl.clone());
 +                    }
 +                }
 +
 +                vfs::loader::Entry::Directories(dirs)
 +            };
 +
 +            if root.is_local {
 +                res.watch.push(res.load.len());
 +            }
 +            res.load.push(entry);
 +
 +            if root.is_local {
 +                local_filesets.push(fsc.len());
 +            }
 +            fsc.add_file_set(file_set_roots)
 +        }
 +
 +        let fsc = fsc.build();
 +        res.source_root_config = SourceRootConfig { fsc, local_filesets };
 +
 +        res
 +    }
 +}
 +
 +#[derive(Default, Debug)]
 +pub(crate) struct SourceRootConfig {
 +    pub(crate) fsc: FileSetConfig,
 +    pub(crate) local_filesets: Vec<usize>,
 +}
 +
 +impl SourceRootConfig {
 +    pub(crate) fn partition(&self, vfs: &vfs::Vfs) -> Vec<SourceRoot> {
 +        let _p = profile::span("SourceRootConfig::partition");
 +        self.fsc
 +            .partition(vfs)
 +            .into_iter()
 +            .enumerate()
 +            .map(|(idx, file_set)| {
 +                let is_local = self.local_filesets.contains(&idx);
 +                if is_local {
 +                    SourceRoot::new_local(file_set)
 +                } else {
 +                    SourceRoot::new_library(file_set)
 +                }
 +            })
 +            .collect()
 +    }
 +}
 +
 +/// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace`
 +/// with an identity dummy expander.
 +pub(crate) fn load_proc_macro(
 +    server: Result<&ProcMacroServer, &str>,
 +    path: &AbsPath,
 +    dummy_replace: &[Box<str>],
 +) -> ProcMacroLoadResult {
 +    let res: Result<Vec<_>, String> = (|| {
 +        let dylib = MacroDylib::new(path.to_path_buf())
 +            .map_err(|io| format!("Proc-macro dylib loading failed: {io}"))?;
 +        let server = server.map_err(ToOwned::to_owned)?;
 +        let vec = server.load_dylib(dylib).map_err(|e| format!("{e}"))?;
 +        if vec.is_empty() {
 +            return Err("proc macro library returned no proc macros".to_string());
 +        }
 +        Ok(vec
 +            .into_iter()
 +            .map(|expander| expander_to_proc_macro(expander, dummy_replace))
 +            .collect())
 +    })();
 +    return match res {
 +        Ok(proc_macros) => {
 +            tracing::info!(
 +                "Loaded proc-macros for {}: {:?}",
 +                path.display(),
 +                proc_macros.iter().map(|it| it.name.clone()).collect::<Vec<_>>()
 +            );
 +            Ok(proc_macros)
 +        }
 +        Err(e) => {
 +            tracing::warn!("proc-macro loading for {} failed: {e}", path.display());
 +            Err(e)
 +        }
 +    };
 +
 +    fn expander_to_proc_macro(
 +        expander: proc_macro_api::ProcMacro,
 +        dummy_replace: &[Box<str>],
 +    ) -> ProcMacro {
 +        let name = SmolStr::from(expander.name());
 +        let kind = match expander.kind() {
 +            proc_macro_api::ProcMacroKind::CustomDerive => ProcMacroKind::CustomDerive,
 +            proc_macro_api::ProcMacroKind::FuncLike => ProcMacroKind::FuncLike,
 +            proc_macro_api::ProcMacroKind::Attr => ProcMacroKind::Attr,
 +        };
 +        let expander: Arc<dyn ProcMacroExpander> =
 +            if dummy_replace.iter().any(|replace| &**replace == name) {
 +                match kind {
 +                    ProcMacroKind::Attr => Arc::new(IdentityExpander),
 +                    _ => Arc::new(EmptyExpander),
 +                }
 +            } else {
 +                Arc::new(Expander(expander))
 +            };
 +        ProcMacro { name, kind, expander }
 +    }
 +
 +    #[derive(Debug)]
 +    struct Expander(proc_macro_api::ProcMacro);
 +
 +    impl ProcMacroExpander for Expander {
 +        fn expand(
 +            &self,
 +            subtree: &tt::Subtree,
 +            attrs: Option<&tt::Subtree>,
 +            env: &Env,
 +        ) -> Result<tt::Subtree, ProcMacroExpansionError> {
 +            let env = env.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect();
 +            match self.0.expand(subtree, attrs, env) {
 +                Ok(Ok(subtree)) => Ok(subtree),
 +                Ok(Err(err)) => Err(ProcMacroExpansionError::Panic(err.0)),
 +                Err(err) => Err(ProcMacroExpansionError::System(err.to_string())),
 +            }
 +        }
 +    }
 +
 +    /// Dummy identity expander, used for attribute proc-macros that are deliberately ignored by the user.
 +    #[derive(Debug)]
 +    struct IdentityExpander;
 +
 +    impl ProcMacroExpander for IdentityExpander {
 +        fn expand(
 +            &self,
 +            subtree: &tt::Subtree,
 +            _: Option<&tt::Subtree>,
 +            _: &Env,
 +        ) -> Result<tt::Subtree, ProcMacroExpansionError> {
 +            Ok(subtree.clone())
 +        }
 +    }
 +
 +    /// Empty expander, used for proc-macros that are deliberately ignored by the user.
 +    #[derive(Debug)]
 +    struct EmptyExpander;
 +
 +    impl ProcMacroExpander for EmptyExpander {
 +        fn expand(
 +            &self,
 +            _: &tt::Subtree,
 +            _: Option<&tt::Subtree>,
 +            _: &Env,
 +        ) -> Result<tt::Subtree, ProcMacroExpansionError> {
 +            Ok(tt::Subtree::default())
 +        }
 +    }
 +}
 +
 +pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool {
 +    const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
 +    const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"];
 +
 +    let file_name = match path.file_name().unwrap_or_default().to_str() {
 +        Some(it) => it,
 +        None => return false,
 +    };
 +
 +    if let "Cargo.toml" | "Cargo.lock" = file_name {
 +        return true;
 +    }
 +    if change_kind == ChangeKind::Modify {
 +        return false;
 +    }
 +
 +    // .cargo/config{.toml}
 +    if path.extension().unwrap_or_default() != "rs" {
 +        let is_cargo_config = matches!(file_name, "config.toml" | "config")
 +            && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")).unwrap_or(false);
 +        return is_cargo_config;
 +    }
 +
 +    if IMPLICIT_TARGET_FILES.iter().any(|it| path.as_ref().ends_with(it)) {
 +        return true;
 +    }
 +    let parent = match path.parent() {
 +        Some(it) => it,
 +        None => return false,
 +    };
 +    if IMPLICIT_TARGET_DIRS.iter().any(|it| parent.as_ref().ends_with(it)) {
 +        return true;
 +    }
 +    if file_name == "main.rs" {
 +        let grand_parent = match parent.parent() {
 +            Some(it) => it,
 +            None => return false,
 +        };
 +        if IMPLICIT_TARGET_DIRS.iter().any(|it| grand_parent.as_ref().ends_with(it)) {
 +            return true;
 +        }
 +    }
 +    false
 +}
index 229e7419b736febecf341b114dc86b121e6e006d,0000000000000000000000000000000000000000..660c057e99c5671636e8cd0d5d3a75b2545fe08e
mode 100644,000000..100644
--- /dev/null
@@@ -1,894 -1,0 +1,893 @@@
-     let comma = match syntax
 +//! Structural editing for ast.
 +
 +use std::iter::{empty, successors};
 +
 +use parser::{SyntaxKind, T};
 +use rowan::SyntaxElement;
 +
 +use crate::{
 +    algo::{self, neighbor},
 +    ast::{self, edit::IndentLevel, make, HasGenericParams},
 +    ted::{self, Position},
 +    AstNode, AstToken, Direction,
 +    SyntaxKind::{ATTR, COMMENT, WHITESPACE},
 +    SyntaxNode, SyntaxToken,
 +};
 +
 +use super::HasName;
 +
 +pub trait GenericParamsOwnerEdit: ast::HasGenericParams {
 +    fn get_or_create_generic_param_list(&self) -> ast::GenericParamList;
 +    fn get_or_create_where_clause(&self) -> ast::WhereClause;
 +}
 +
 +impl GenericParamsOwnerEdit for ast::Fn {
 +    fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
 +        match self.generic_param_list() {
 +            Some(it) => it,
 +            None => {
 +                let position = if let Some(name) = self.name() {
 +                    Position::after(name.syntax)
 +                } else if let Some(fn_token) = self.fn_token() {
 +                    Position::after(fn_token)
 +                } else if let Some(param_list) = self.param_list() {
 +                    Position::before(param_list.syntax)
 +                } else {
 +                    Position::last_child_of(self.syntax())
 +                };
 +                create_generic_param_list(position)
 +            }
 +        }
 +    }
 +
 +    fn get_or_create_where_clause(&self) -> ast::WhereClause {
 +        if self.where_clause().is_none() {
 +            let position = if let Some(ty) = self.ret_type() {
 +                Position::after(ty.syntax())
 +            } else if let Some(param_list) = self.param_list() {
 +                Position::after(param_list.syntax())
 +            } else {
 +                Position::last_child_of(self.syntax())
 +            };
 +            create_where_clause(position);
 +        }
 +        self.where_clause().unwrap()
 +    }
 +}
 +
 +impl GenericParamsOwnerEdit for ast::Impl {
 +    fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
 +        match self.generic_param_list() {
 +            Some(it) => it,
 +            None => {
 +                let position = match self.impl_token() {
 +                    Some(imp_token) => Position::after(imp_token),
 +                    None => Position::last_child_of(self.syntax()),
 +                };
 +                create_generic_param_list(position)
 +            }
 +        }
 +    }
 +
 +    fn get_or_create_where_clause(&self) -> ast::WhereClause {
 +        if self.where_clause().is_none() {
 +            let position = match self.assoc_item_list() {
 +                Some(items) => Position::before(items.syntax()),
 +                None => Position::last_child_of(self.syntax()),
 +            };
 +            create_where_clause(position);
 +        }
 +        self.where_clause().unwrap()
 +    }
 +}
 +
 +impl GenericParamsOwnerEdit for ast::Trait {
 +    fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
 +        match self.generic_param_list() {
 +            Some(it) => it,
 +            None => {
 +                let position = if let Some(name) = self.name() {
 +                    Position::after(name.syntax)
 +                } else if let Some(trait_token) = self.trait_token() {
 +                    Position::after(trait_token)
 +                } else {
 +                    Position::last_child_of(self.syntax())
 +                };
 +                create_generic_param_list(position)
 +            }
 +        }
 +    }
 +
 +    fn get_or_create_where_clause(&self) -> ast::WhereClause {
 +        if self.where_clause().is_none() {
 +            let position = match self.assoc_item_list() {
 +                Some(items) => Position::before(items.syntax()),
 +                None => Position::last_child_of(self.syntax()),
 +            };
 +            create_where_clause(position);
 +        }
 +        self.where_clause().unwrap()
 +    }
 +}
 +
 +impl GenericParamsOwnerEdit for ast::Struct {
 +    fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
 +        match self.generic_param_list() {
 +            Some(it) => it,
 +            None => {
 +                let position = if let Some(name) = self.name() {
 +                    Position::after(name.syntax)
 +                } else if let Some(struct_token) = self.struct_token() {
 +                    Position::after(struct_token)
 +                } else {
 +                    Position::last_child_of(self.syntax())
 +                };
 +                create_generic_param_list(position)
 +            }
 +        }
 +    }
 +
 +    fn get_or_create_where_clause(&self) -> ast::WhereClause {
 +        if self.where_clause().is_none() {
 +            let tfl = self.field_list().and_then(|fl| match fl {
 +                ast::FieldList::RecordFieldList(_) => None,
 +                ast::FieldList::TupleFieldList(it) => Some(it),
 +            });
 +            let position = if let Some(tfl) = tfl {
 +                Position::after(tfl.syntax())
 +            } else if let Some(gpl) = self.generic_param_list() {
 +                Position::after(gpl.syntax())
 +            } else if let Some(name) = self.name() {
 +                Position::after(name.syntax())
 +            } else {
 +                Position::last_child_of(self.syntax())
 +            };
 +            create_where_clause(position);
 +        }
 +        self.where_clause().unwrap()
 +    }
 +}
 +
 +impl GenericParamsOwnerEdit for ast::Enum {
 +    fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
 +        match self.generic_param_list() {
 +            Some(it) => it,
 +            None => {
 +                let position = if let Some(name) = self.name() {
 +                    Position::after(name.syntax)
 +                } else if let Some(enum_token) = self.enum_token() {
 +                    Position::after(enum_token)
 +                } else {
 +                    Position::last_child_of(self.syntax())
 +                };
 +                create_generic_param_list(position)
 +            }
 +        }
 +    }
 +
 +    fn get_or_create_where_clause(&self) -> ast::WhereClause {
 +        if self.where_clause().is_none() {
 +            let position = if let Some(gpl) = self.generic_param_list() {
 +                Position::after(gpl.syntax())
 +            } else if let Some(name) = self.name() {
 +                Position::after(name.syntax())
 +            } else {
 +                Position::last_child_of(self.syntax())
 +            };
 +            create_where_clause(position);
 +        }
 +        self.where_clause().unwrap()
 +    }
 +}
 +
 +fn create_where_clause(position: Position) {
 +    let where_clause = make::where_clause(empty()).clone_for_update();
 +    ted::insert(position, where_clause.syntax());
 +}
 +
 +fn create_generic_param_list(position: Position) -> ast::GenericParamList {
 +    let gpl = make::generic_param_list(empty()).clone_for_update();
 +    ted::insert_raw(position, gpl.syntax());
 +    gpl
 +}
 +
 +pub trait AttrsOwnerEdit: ast::HasAttrs {
 +    fn remove_attrs_and_docs(&self) {
 +        remove_attrs_and_docs(self.syntax());
 +
 +        fn remove_attrs_and_docs(node: &SyntaxNode) {
 +            let mut remove_next_ws = false;
 +            for child in node.children_with_tokens() {
 +                match child.kind() {
 +                    ATTR | COMMENT => {
 +                        remove_next_ws = true;
 +                        child.detach();
 +                        continue;
 +                    }
 +                    WHITESPACE if remove_next_ws => {
 +                        child.detach();
 +                    }
 +                    _ => (),
 +                }
 +                remove_next_ws = false;
 +            }
 +        }
 +    }
 +}
 +
 +impl<T: ast::HasAttrs> AttrsOwnerEdit for T {}
 +
 +impl ast::GenericParamList {
 +    pub fn add_generic_param(&self, generic_param: ast::GenericParam) {
 +        match self.generic_params().last() {
 +            Some(last_param) => {
 +                let position = Position::after(last_param.syntax());
 +                let elements = vec![
 +                    make::token(T![,]).into(),
 +                    make::tokens::single_space().into(),
 +                    generic_param.syntax().clone().into(),
 +                ];
 +                ted::insert_all(position, elements);
 +            }
 +            None => {
 +                let after_l_angle = Position::after(self.l_angle_token().unwrap());
 +                ted::insert(after_l_angle, generic_param.syntax());
 +            }
 +        }
 +    }
 +
 +    /// Constructs a matching [`ast::GenericArgList`]
 +    pub fn to_generic_args(&self) -> ast::GenericArgList {
 +        let args = self.generic_params().filter_map(|param| match param {
 +            ast::GenericParam::LifetimeParam(it) => {
 +                Some(ast::GenericArg::LifetimeArg(make::lifetime_arg(it.lifetime()?)))
 +            }
 +            ast::GenericParam::TypeParam(it) => {
 +                Some(ast::GenericArg::TypeArg(make::type_arg(make::ext::ty_name(it.name()?))))
 +            }
 +            ast::GenericParam::ConstParam(it) => {
 +                // Name-only const params get parsed as `TypeArg`s
 +                Some(ast::GenericArg::TypeArg(make::type_arg(make::ext::ty_name(it.name()?))))
 +            }
 +        });
 +
 +        make::generic_arg_list(args)
 +    }
 +}
 +
 +impl ast::WhereClause {
 +    pub fn add_predicate(&self, predicate: ast::WherePred) {
 +        if let Some(pred) = self.predicates().last() {
 +            if !pred.syntax().siblings_with_tokens(Direction::Next).any(|it| it.kind() == T![,]) {
 +                ted::append_child_raw(self.syntax(), make::token(T![,]));
 +            }
 +        }
 +        ted::append_child(self.syntax(), predicate.syntax());
 +    }
 +}
 +
 +impl ast::TypeParam {
 +    pub fn remove_default(&self) {
 +        if let Some((eq, last)) = self
 +            .syntax()
 +            .children_with_tokens()
 +            .find(|it| it.kind() == T![=])
 +            .zip(self.syntax().last_child_or_token())
 +        {
 +            ted::remove_all(eq..=last);
 +
 +            // remove any trailing ws
 +            if let Some(last) = self.syntax().last_token().filter(|it| it.kind() == WHITESPACE) {
 +                last.detach();
 +            }
 +        }
 +    }
 +}
 +
 +impl ast::ConstParam {
 +    pub fn remove_default(&self) {
 +        if let Some((eq, last)) = self
 +            .syntax()
 +            .children_with_tokens()
 +            .find(|it| it.kind() == T![=])
 +            .zip(self.syntax().last_child_or_token())
 +        {
 +            ted::remove_all(eq..=last);
 +
 +            // remove any trailing ws
 +            if let Some(last) = self.syntax().last_token().filter(|it| it.kind() == WHITESPACE) {
 +                last.detach();
 +            }
 +        }
 +    }
 +}
 +
 +pub trait Removable: AstNode {
 +    fn remove(&self);
 +}
 +
 +impl Removable for ast::TypeBoundList {
 +    fn remove(&self) {
 +        match self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) {
 +            Some(colon) => ted::remove_all(colon..=self.syntax().clone().into()),
 +            None => ted::remove(self.syntax()),
 +        }
 +    }
 +}
 +
 +impl ast::PathSegment {
 +    pub fn get_or_create_generic_arg_list(&self) -> ast::GenericArgList {
 +        if self.generic_arg_list().is_none() {
 +            let arg_list = make::generic_arg_list(empty()).clone_for_update();
 +            ted::append_child(self.syntax(), arg_list.syntax());
 +        }
 +        self.generic_arg_list().unwrap()
 +    }
 +}
 +
 +impl Removable for ast::UseTree {
 +    fn remove(&self) {
 +        for dir in [Direction::Next, Direction::Prev] {
 +            if let Some(next_use_tree) = neighbor(self, dir) {
 +                let separators = self
 +                    .syntax()
 +                    .siblings_with_tokens(dir)
 +                    .skip(1)
 +                    .take_while(|it| it.as_node() != Some(next_use_tree.syntax()));
 +                ted::remove_all_iter(separators);
 +                break;
 +            }
 +        }
 +        ted::remove(self.syntax());
 +    }
 +}
 +
 +impl ast::UseTree {
 +    pub fn get_or_create_use_tree_list(&self) -> ast::UseTreeList {
 +        match self.use_tree_list() {
 +            Some(it) => it,
 +            None => {
 +                let position = Position::last_child_of(self.syntax());
 +                let use_tree_list = make::use_tree_list(empty()).clone_for_update();
 +                let mut elements = Vec::with_capacity(2);
 +                if self.coloncolon_token().is_none() {
 +                    elements.push(make::token(T![::]).into());
 +                }
 +                elements.push(use_tree_list.syntax().clone().into());
 +                ted::insert_all_raw(position, elements);
 +                use_tree_list
 +            }
 +        }
 +    }
 +
 +    /// Splits off the given prefix, making it the path component of the use tree,
 +    /// appending the rest of the path to all UseTreeList items.
 +    ///
 +    /// # Examples
 +    ///
 +    /// `prefix$0::suffix` -> `prefix::{suffix}`
 +    ///
 +    /// `prefix$0` -> `prefix::{self}`
 +    ///
 +    /// `prefix$0::*` -> `prefix::{*}`
 +    pub fn split_prefix(&self, prefix: &ast::Path) {
 +        debug_assert_eq!(self.path(), Some(prefix.top_path()));
 +        let path = self.path().unwrap();
 +        if &path == prefix && self.use_tree_list().is_none() {
 +            if self.star_token().is_some() {
 +                // path$0::* -> *
 +                self.coloncolon_token().map(ted::remove);
 +                ted::remove(prefix.syntax());
 +            } else {
 +                // path$0 -> self
 +                let self_suffix =
 +                    make::path_unqualified(make::path_segment_self()).clone_for_update();
 +                ted::replace(path.syntax(), self_suffix.syntax());
 +            }
 +        } else if split_path_prefix(prefix).is_none() {
 +            return;
 +        }
 +        // At this point, prefix path is detached; _self_ use tree has suffix path.
 +        // Next, transform 'suffix' use tree into 'prefix::{suffix}'
 +        let subtree = self.clone_subtree().clone_for_update();
 +        ted::remove_all_iter(self.syntax().children_with_tokens());
 +        ted::insert(Position::first_child_of(self.syntax()), prefix.syntax());
 +        self.get_or_create_use_tree_list().add_use_tree(subtree);
 +
 +        fn split_path_prefix(prefix: &ast::Path) -> Option<()> {
 +            let parent = prefix.parent_path()?;
 +            let segment = parent.segment()?;
 +            if algo::has_errors(segment.syntax()) {
 +                return None;
 +            }
 +            for p in successors(parent.parent_path(), |it| it.parent_path()) {
 +                p.segment()?;
 +            }
 +            prefix.parent_path().and_then(|p| p.coloncolon_token()).map(ted::remove);
 +            ted::remove(prefix.syntax());
 +            Some(())
 +        }
 +    }
 +}
 +
 +impl ast::UseTreeList {
 +    pub fn add_use_tree(&self, use_tree: ast::UseTree) {
 +        let (position, elements) = match self.use_trees().last() {
 +            Some(last_tree) => (
 +                Position::after(last_tree.syntax()),
 +                vec![
 +                    make::token(T![,]).into(),
 +                    make::tokens::single_space().into(),
 +                    use_tree.syntax.into(),
 +                ],
 +            ),
 +            None => {
 +                let position = match self.l_curly_token() {
 +                    Some(l_curly) => Position::after(l_curly),
 +                    None => Position::last_child_of(self.syntax()),
 +                };
 +                (position, vec![use_tree.syntax.into()])
 +            }
 +        };
 +        ted::insert_all_raw(position, elements);
 +    }
 +}
 +
 +impl Removable for ast::Use {
 +    fn remove(&self) {
 +        let next_ws = self
 +            .syntax()
 +            .next_sibling_or_token()
 +            .and_then(|it| it.into_token())
 +            .and_then(ast::Whitespace::cast);
 +        if let Some(next_ws) = next_ws {
 +            let ws_text = next_ws.syntax().text();
 +            if let Some(rest) = ws_text.strip_prefix('\n') {
 +                if rest.is_empty() {
 +                    ted::remove(next_ws.syntax());
 +                } else {
 +                    ted::replace(next_ws.syntax(), make::tokens::whitespace(rest));
 +                }
 +            }
 +        }
 +        ted::remove(self.syntax());
 +    }
 +}
 +
 +impl ast::Impl {
 +    pub fn get_or_create_assoc_item_list(&self) -> ast::AssocItemList {
 +        if self.assoc_item_list().is_none() {
 +            let assoc_item_list = make::assoc_item_list().clone_for_update();
 +            ted::append_child(self.syntax(), assoc_item_list.syntax());
 +        }
 +        self.assoc_item_list().unwrap()
 +    }
 +}
 +
 +impl ast::AssocItemList {
 +    pub fn add_item(&self, item: ast::AssocItem) {
 +        let (indent, position, whitespace) = match self.assoc_items().last() {
 +            Some(last_item) => (
 +                IndentLevel::from_node(last_item.syntax()),
 +                Position::after(last_item.syntax()),
 +                "\n\n",
 +            ),
 +            None => match self.l_curly_token() {
 +                Some(l_curly) => {
 +                    normalize_ws_between_braces(self.syntax());
 +                    (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly), "\n")
 +                }
 +                None => (IndentLevel::single(), Position::last_child_of(self.syntax()), "\n"),
 +            },
 +        };
 +        let elements: Vec<SyntaxElement<_>> = vec![
 +            make::tokens::whitespace(&format!("{}{}", whitespace, indent)).into(),
 +            item.syntax().clone().into(),
 +        ];
 +        ted::insert_all(position, elements);
 +    }
 +}
 +
 +impl ast::Fn {
 +    pub fn get_or_create_body(&self) -> ast::BlockExpr {
 +        if self.body().is_none() {
 +            let body = make::ext::empty_block_expr().clone_for_update();
 +            match self.semicolon_token() {
 +                Some(semi) => {
 +                    ted::replace(semi, body.syntax());
 +                    ted::insert(Position::before(body.syntax), make::tokens::single_space());
 +                }
 +                None => ted::append_child(self.syntax(), body.syntax()),
 +            }
 +        }
 +        self.body().unwrap()
 +    }
 +}
 +
 +impl Removable for ast::MatchArm {
 +    fn remove(&self) {
 +        if let Some(sibling) = self.syntax().prev_sibling_or_token() {
 +            if sibling.kind() == SyntaxKind::WHITESPACE {
 +                ted::remove(sibling);
 +            }
 +        }
 +        if let Some(sibling) = self.syntax().next_sibling_or_token() {
 +            if sibling.kind() == T![,] {
 +                ted::remove(sibling);
 +            }
 +        }
 +        ted::remove(self.syntax());
 +    }
 +}
 +
 +impl ast::MatchArmList {
 +    pub fn add_arm(&self, arm: ast::MatchArm) {
 +        normalize_ws_between_braces(self.syntax());
 +        let mut elements = Vec::new();
 +        let position = match self.arms().last() {
 +            Some(last_arm) => {
 +                if needs_comma(&last_arm) {
 +                    ted::append_child(last_arm.syntax(), make::token(SyntaxKind::COMMA));
 +                }
 +                Position::after(last_arm.syntax().clone())
 +            }
 +            None => match self.l_curly_token() {
 +                Some(it) => Position::after(it),
 +                None => Position::last_child_of(self.syntax()),
 +            },
 +        };
 +        let indent = IndentLevel::from_node(self.syntax()) + 1;
 +        elements.push(make::tokens::whitespace(&format!("\n{}", indent)).into());
 +        elements.push(arm.syntax().clone().into());
 +        if needs_comma(&arm) {
 +            ted::append_child(arm.syntax(), make::token(SyntaxKind::COMMA));
 +        }
 +        ted::insert_all(position, elements);
 +
 +        fn needs_comma(arm: &ast::MatchArm) -> bool {
 +            arm.expr().map_or(false, |e| !e.is_block_like()) && arm.comma_token().is_none()
 +        }
 +    }
 +}
 +
 +impl ast::RecordExprFieldList {
 +    pub fn add_field(&self, field: ast::RecordExprField) {
 +        let is_multiline = self.syntax().text().contains_char('\n');
 +        let whitespace = if is_multiline {
 +            let indent = IndentLevel::from_node(self.syntax()) + 1;
 +            make::tokens::whitespace(&format!("\n{}", indent))
 +        } else {
 +            make::tokens::single_space()
 +        };
 +
 +        if is_multiline {
 +            normalize_ws_between_braces(self.syntax());
 +        }
 +
 +        let position = match self.fields().last() {
 +            Some(last_field) => {
 +                let comma = get_or_insert_comma_after(last_field.syntax());
 +                Position::after(comma)
 +            }
 +            None => match self.l_curly_token() {
 +                Some(it) => Position::after(it),
 +                None => Position::last_child_of(self.syntax()),
 +            },
 +        };
 +
 +        ted::insert_all(position, vec![whitespace.into(), field.syntax().clone().into()]);
 +        if is_multiline {
 +            ted::insert(Position::after(field.syntax()), ast::make::token(T![,]));
 +        }
 +    }
 +}
 +
 +impl ast::RecordExprField {
 +    /// This will either replace the initializer, or in the case that this is a shorthand convert
 +    /// the initializer into the name ref and insert the expr as the new initializer.
 +    pub fn replace_expr(&self, expr: ast::Expr) {
 +        if self.name_ref().is_some() {
 +            match self.expr() {
 +                Some(prev) => ted::replace(prev.syntax(), expr.syntax()),
 +                None => ted::append_child(self.syntax(), expr.syntax()),
 +            }
 +            return;
 +        }
 +        // this is a shorthand
 +        if let Some(ast::Expr::PathExpr(path_expr)) = self.expr() {
 +            if let Some(path) = path_expr.path() {
 +                if let Some(name_ref) = path.as_single_name_ref() {
 +                    path_expr.syntax().detach();
 +                    let children = vec![
 +                        name_ref.syntax().clone().into(),
 +                        ast::make::token(T![:]).into(),
 +                        ast::make::tokens::single_space().into(),
 +                        expr.syntax().clone().into(),
 +                    ];
 +                    ted::insert_all_raw(Position::last_child_of(self.syntax()), children);
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +impl ast::RecordPatFieldList {
 +    pub fn add_field(&self, field: ast::RecordPatField) {
 +        let is_multiline = self.syntax().text().contains_char('\n');
 +        let whitespace = if is_multiline {
 +            let indent = IndentLevel::from_node(self.syntax()) + 1;
 +            make::tokens::whitespace(&format!("\n{}", indent))
 +        } else {
 +            make::tokens::single_space()
 +        };
 +
 +        if is_multiline {
 +            normalize_ws_between_braces(self.syntax());
 +        }
 +
 +        let position = match self.fields().last() {
 +            Some(last_field) => {
 +                let syntax = last_field.syntax();
 +                let comma = get_or_insert_comma_after(syntax);
 +                Position::after(comma)
 +            }
 +            None => match self.l_curly_token() {
 +                Some(it) => Position::after(it),
 +                None => Position::last_child_of(self.syntax()),
 +            },
 +        };
 +
 +        ted::insert_all(position, vec![whitespace.into(), field.syntax().clone().into()]);
 +        if is_multiline {
 +            ted::insert(Position::after(field.syntax()), ast::make::token(T![,]));
 +        }
 +    }
 +}
 +
 +fn get_or_insert_comma_after(syntax: &SyntaxNode) -> SyntaxToken {
-     };
-     comma
++    match syntax
 +        .siblings_with_tokens(Direction::Next)
 +        .filter_map(|it| it.into_token())
 +        .find(|it| it.kind() == T![,])
 +    {
 +        Some(it) => it,
 +        None => {
 +            let comma = ast::make::token(T![,]);
 +            ted::insert(Position::after(syntax), &comma);
 +            comma
 +        }
++    }
 +}
 +
 +impl ast::StmtList {
 +    pub fn push_front(&self, statement: ast::Stmt) {
 +        ted::insert(Position::after(self.l_curly_token().unwrap()), statement.syntax());
 +    }
 +}
 +
 +impl ast::VariantList {
 +    pub fn add_variant(&self, variant: ast::Variant) {
 +        let (indent, position) = match self.variants().last() {
 +            Some(last_item) => (
 +                IndentLevel::from_node(last_item.syntax()),
 +                Position::after(get_or_insert_comma_after(last_item.syntax())),
 +            ),
 +            None => match self.l_curly_token() {
 +                Some(l_curly) => {
 +                    normalize_ws_between_braces(self.syntax());
 +                    (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly))
 +                }
 +                None => (IndentLevel::single(), Position::last_child_of(self.syntax())),
 +            },
 +        };
 +        let elements: Vec<SyntaxElement<_>> = vec![
 +            make::tokens::whitespace(&format!("{}{}", "\n", indent)).into(),
 +            variant.syntax().clone().into(),
 +            ast::make::token(T![,]).into(),
 +        ];
 +        ted::insert_all(position, elements);
 +    }
 +}
 +
 +fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> {
 +    let l = node
 +        .children_with_tokens()
 +        .filter_map(|it| it.into_token())
 +        .find(|it| it.kind() == T!['{'])?;
 +    let r = node
 +        .children_with_tokens()
 +        .filter_map(|it| it.into_token())
 +        .find(|it| it.kind() == T!['}'])?;
 +
 +    let indent = IndentLevel::from_node(node);
 +
 +    match l.next_sibling_or_token() {
 +        Some(ws) if ws.kind() == SyntaxKind::WHITESPACE => {
 +            if ws.next_sibling_or_token()?.into_token()? == r {
 +                ted::replace(ws, make::tokens::whitespace(&format!("\n{}", indent)));
 +            }
 +        }
 +        Some(ws) if ws.kind() == T!['}'] => {
 +            ted::insert(Position::after(l), make::tokens::whitespace(&format!("\n{}", indent)));
 +        }
 +        _ => (),
 +    }
 +    Some(())
 +}
 +
 +pub trait Indent: AstNode + Clone + Sized {
 +    fn indent_level(&self) -> IndentLevel {
 +        IndentLevel::from_node(self.syntax())
 +    }
 +    fn indent(&self, by: IndentLevel) {
 +        by.increase_indent(self.syntax());
 +    }
 +    fn dedent(&self, by: IndentLevel) {
 +        by.decrease_indent(self.syntax());
 +    }
 +    fn reindent_to(&self, target_level: IndentLevel) {
 +        let current_level = IndentLevel::from_node(self.syntax());
 +        self.dedent(current_level);
 +        self.indent(target_level);
 +    }
 +}
 +
 +impl<N: AstNode + Clone> Indent for N {}
 +
 +#[cfg(test)]
 +mod tests {
 +    use std::fmt;
 +
 +    use stdx::trim_indent;
 +    use test_utils::assert_eq_text;
 +
 +    use crate::SourceFile;
 +
 +    use super::*;
 +
 +    fn ast_mut_from_text<N: AstNode>(text: &str) -> N {
 +        let parse = SourceFile::parse(text);
 +        parse.tree().syntax().descendants().find_map(N::cast).unwrap().clone_for_update()
 +    }
 +
 +    #[test]
 +    fn test_create_generic_param_list() {
 +        fn check_create_gpl<N: GenericParamsOwnerEdit + fmt::Display>(before: &str, after: &str) {
 +            let gpl_owner = ast_mut_from_text::<N>(before);
 +            gpl_owner.get_or_create_generic_param_list();
 +            assert_eq!(gpl_owner.to_string(), after);
 +        }
 +
 +        check_create_gpl::<ast::Fn>("fn foo", "fn foo<>");
 +        check_create_gpl::<ast::Fn>("fn foo() {}", "fn foo<>() {}");
 +
 +        check_create_gpl::<ast::Impl>("impl", "impl<>");
 +        check_create_gpl::<ast::Impl>("impl Struct {}", "impl<> Struct {}");
 +        check_create_gpl::<ast::Impl>("impl Trait for Struct {}", "impl<> Trait for Struct {}");
 +
 +        check_create_gpl::<ast::Trait>("trait Trait<>", "trait Trait<>");
 +        check_create_gpl::<ast::Trait>("trait Trait<> {}", "trait Trait<> {}");
 +
 +        check_create_gpl::<ast::Struct>("struct A", "struct A<>");
 +        check_create_gpl::<ast::Struct>("struct A;", "struct A<>;");
 +        check_create_gpl::<ast::Struct>("struct A();", "struct A<>();");
 +        check_create_gpl::<ast::Struct>("struct A {}", "struct A<> {}");
 +
 +        check_create_gpl::<ast::Enum>("enum E", "enum E<>");
 +        check_create_gpl::<ast::Enum>("enum E {", "enum E<> {");
 +    }
 +
 +    #[test]
 +    fn test_increase_indent() {
 +        let arm_list = ast_mut_from_text::<ast::Fn>(
 +            "fn foo() {
 +    ;
 +    ;
 +}",
 +        );
 +        arm_list.indent(IndentLevel(2));
 +        assert_eq!(
 +            arm_list.to_string(),
 +            "fn foo() {
 +            ;
 +            ;
 +        }",
 +        );
 +    }
 +
 +    #[test]
 +    fn add_variant_to_empty_enum() {
 +        let variant = make::variant(make::name("Bar"), None).clone_for_update();
 +
 +        check_add_variant(
 +            r#"
 +enum Foo {}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar,
 +}
 +"#,
 +            variant,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_variant_to_non_empty_enum() {
 +        let variant = make::variant(make::name("Baz"), None).clone_for_update();
 +
 +        check_add_variant(
 +            r#"
 +enum Foo {
 +    Bar,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar,
 +    Baz,
 +}
 +"#,
 +            variant,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_variant_with_tuple_field_list() {
 +        let variant = make::variant(
 +            make::name("Baz"),
 +            Some(ast::FieldList::TupleFieldList(make::tuple_field_list(std::iter::once(
 +                make::tuple_field(None, make::ty("bool")),
 +            )))),
 +        )
 +        .clone_for_update();
 +
 +        check_add_variant(
 +            r#"
 +enum Foo {
 +    Bar,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar,
 +    Baz(bool),
 +}
 +"#,
 +            variant,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_variant_with_record_field_list() {
 +        let variant = make::variant(
 +            make::name("Baz"),
 +            Some(ast::FieldList::RecordFieldList(make::record_field_list(std::iter::once(
 +                make::record_field(None, make::name("x"), make::ty("bool")),
 +            )))),
 +        )
 +        .clone_for_update();
 +
 +        check_add_variant(
 +            r#"
 +enum Foo {
 +    Bar,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar,
 +    Baz { x: bool },
 +}
 +"#,
 +            variant,
 +        );
 +    }
 +
 +    fn check_add_variant(before: &str, expected: &str, variant: ast::Variant) {
 +        let enum_ = ast_mut_from_text::<ast::Enum>(before);
 +        enum_.variant_list().map(|it| it.add_variant(variant));
 +        let after = enum_.to_string();
 +        assert_eq_text!(&trim_indent(expected.trim()), &trim_indent(&after.trim()));
 +    }
 +}
index 4f5e273a520a14212256f1ac7a898b354e942216,0000000000000000000000000000000000000000..84c66b27e69faa531336463f2a2366409bb468e5
mode 100644,000000..100644
--- /dev/null
@@@ -1,358 -1,0 +1,358 @@@
-         &*self.errors
 +//! Syntax Tree library used throughout the rust-analyzer.
 +//!
 +//! Properties:
 +//!   - easy and fast incremental re-parsing
 +//!   - graceful handling of errors
 +//!   - full-fidelity representation (*any* text can be precisely represented as
 +//!     a syntax tree)
 +//!
 +//! For more information, see the [RFC]. Current implementation is inspired by
 +//! the [Swift] one.
 +//!
 +//! The most interesting modules here are `syntax_node` (which defines concrete
 +//! syntax tree) and `ast` (which defines abstract syntax tree on top of the
 +//! CST). The actual parser live in a separate `parser` crate, though the
 +//! lexer lives in this crate.
 +//!
 +//! See `api_walkthrough` test in this file for a quick API tour!
 +//!
 +//! [RFC]: <https://github.com/rust-lang/rfcs/pull/2256>
 +//! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md>
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +#[allow(unused)]
 +macro_rules! eprintln {
 +    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
 +}
 +
 +mod syntax_node;
 +mod syntax_error;
 +mod parsing;
 +mod validation;
 +mod ptr;
 +mod token_text;
 +#[cfg(test)]
 +mod tests;
 +
 +pub mod algo;
 +pub mod ast;
 +#[doc(hidden)]
 +pub mod fuzz;
 +pub mod utils;
 +pub mod ted;
 +pub mod hacks;
 +
 +use std::{marker::PhantomData, sync::Arc};
 +
 +use stdx::format_to;
 +use text_edit::Indel;
 +
 +pub use crate::{
 +    ast::{AstNode, AstToken},
 +    ptr::{AstPtr, SyntaxNodePtr},
 +    syntax_error::SyntaxError,
 +    syntax_node::{
 +        PreorderWithTokens, RustLanguage, SyntaxElement, SyntaxElementChildren, SyntaxNode,
 +        SyntaxNodeChildren, SyntaxToken, SyntaxTreeBuilder,
 +    },
 +    token_text::TokenText,
 +};
 +pub use parser::{SyntaxKind, T};
 +pub use rowan::{
 +    api::Preorder, Direction, GreenNode, NodeOrToken, SyntaxText, TextRange, TextSize,
 +    TokenAtOffset, WalkEvent,
 +};
 +pub use smol_str::SmolStr;
 +
 +/// `Parse` is the result of the parsing: a syntax tree and a collection of
 +/// errors.
 +///
 +/// Note that we always produce a syntax tree, even for completely invalid
 +/// files.
 +#[derive(Debug, PartialEq, Eq)]
 +pub struct Parse<T> {
 +    green: GreenNode,
 +    errors: Arc<Vec<SyntaxError>>,
 +    _ty: PhantomData<fn() -> T>,
 +}
 +
 +impl<T> Clone for Parse<T> {
 +    fn clone(&self) -> Parse<T> {
 +        Parse { green: self.green.clone(), errors: self.errors.clone(), _ty: PhantomData }
 +    }
 +}
 +
 +impl<T> Parse<T> {
 +    fn new(green: GreenNode, errors: Vec<SyntaxError>) -> Parse<T> {
 +        Parse { green, errors: Arc::new(errors), _ty: PhantomData }
 +    }
 +
 +    pub fn syntax_node(&self) -> SyntaxNode {
 +        SyntaxNode::new_root(self.green.clone())
 +    }
 +    pub fn errors(&self) -> &[SyntaxError] {
++        &self.errors
 +    }
 +}
 +
 +impl<T: AstNode> Parse<T> {
 +    pub fn to_syntax(self) -> Parse<SyntaxNode> {
 +        Parse { green: self.green, errors: self.errors, _ty: PhantomData }
 +    }
 +
 +    pub fn tree(&self) -> T {
 +        T::cast(self.syntax_node()).unwrap()
 +    }
 +
 +    pub fn ok(self) -> Result<T, Arc<Vec<SyntaxError>>> {
 +        if self.errors.is_empty() {
 +            Ok(self.tree())
 +        } else {
 +            Err(self.errors)
 +        }
 +    }
 +}
 +
 +impl Parse<SyntaxNode> {
 +    pub fn cast<N: AstNode>(self) -> Option<Parse<N>> {
 +        if N::cast(self.syntax_node()).is_some() {
 +            Some(Parse { green: self.green, errors: self.errors, _ty: PhantomData })
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +impl Parse<SourceFile> {
 +    pub fn debug_dump(&self) -> String {
 +        let mut buf = format!("{:#?}", self.tree().syntax());
 +        for err in self.errors.iter() {
 +            format_to!(buf, "error {:?}: {}\n", err.range(), err);
 +        }
 +        buf
 +    }
 +
 +    pub fn reparse(&self, indel: &Indel) -> Parse<SourceFile> {
 +        self.incremental_reparse(indel).unwrap_or_else(|| self.full_reparse(indel))
 +    }
 +
 +    fn incremental_reparse(&self, indel: &Indel) -> Option<Parse<SourceFile>> {
 +        // FIXME: validation errors are not handled here
 +        parsing::incremental_reparse(self.tree().syntax(), indel, self.errors.to_vec()).map(
 +            |(green_node, errors, _reparsed_range)| Parse {
 +                green: green_node,
 +                errors: Arc::new(errors),
 +                _ty: PhantomData,
 +            },
 +        )
 +    }
 +
 +    fn full_reparse(&self, indel: &Indel) -> Parse<SourceFile> {
 +        let mut text = self.tree().syntax().text().to_string();
 +        indel.apply(&mut text);
 +        SourceFile::parse(&text)
 +    }
 +}
 +
 +/// `SourceFile` represents a parse tree for a single Rust file.
 +pub use crate::ast::SourceFile;
 +
 +impl SourceFile {
 +    pub fn parse(text: &str) -> Parse<SourceFile> {
 +        let (green, mut errors) = parsing::parse_text(text);
 +        let root = SyntaxNode::new_root(green.clone());
 +
 +        errors.extend(validation::validate(&root));
 +
 +        assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
 +        Parse { green, errors: Arc::new(errors), _ty: PhantomData }
 +    }
 +}
 +
 +/// Matches a `SyntaxNode` against an `ast` type.
 +///
 +/// # Example:
 +///
 +/// ```ignore
 +/// match_ast! {
 +///     match node {
 +///         ast::CallExpr(it) => { ... },
 +///         ast::MethodCallExpr(it) => { ... },
 +///         ast::MacroCall(it) => { ... },
 +///         _ => None,
 +///     }
 +/// }
 +/// ```
 +#[macro_export]
 +macro_rules! match_ast {
 +    (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
 +
 +    (match ($node:expr) {
 +        $( $( $path:ident )::+ ($it:pat) => $res:expr, )*
 +        _ => $catch_all:expr $(,)?
 +    }) => {{
 +        $( if let Some($it) = $($path::)+cast($node.clone()) { $res } else )*
 +        { $catch_all }
 +    }};
 +}
 +
 +/// This test does not assert anything and instead just shows off the crate's
 +/// API.
 +#[test]
 +fn api_walkthrough() {
 +    use ast::{HasModuleItem, HasName};
 +
 +    let source_code = "
 +        fn foo() {
 +            1 + 1
 +        }
 +    ";
 +    // `SourceFile` is the main entry point.
 +    //
 +    // The `parse` method returns a `Parse` -- a pair of syntax tree and a list
 +    // of errors. That is, syntax tree is constructed even in presence of errors.
 +    let parse = SourceFile::parse(source_code);
 +    assert!(parse.errors().is_empty());
 +
 +    // The `tree` method returns an owned syntax node of type `SourceFile`.
 +    // Owned nodes are cheap: inside, they are `Rc` handles to the underling data.
 +    let file: SourceFile = parse.tree();
 +
 +    // `SourceFile` is the root of the syntax tree. We can iterate file's items.
 +    // Let's fetch the `foo` function.
 +    let mut func = None;
 +    for item in file.items() {
 +        match item {
 +            ast::Item::Fn(f) => func = Some(f),
 +            _ => unreachable!(),
 +        }
 +    }
 +    let func: ast::Fn = func.unwrap();
 +
 +    // Each AST node has a bunch of getters for children. All getters return
 +    // `Option`s though, to account for incomplete code. Some getters are common
 +    // for several kinds of node. In this case, a trait like `ast::NameOwner`
 +    // usually exists. By convention, all ast types should be used with `ast::`
 +    // qualifier.
 +    let name: Option<ast::Name> = func.name();
 +    let name = name.unwrap();
 +    assert_eq!(name.text(), "foo");
 +
 +    // Let's get the `1 + 1` expression!
 +    let body: ast::BlockExpr = func.body().unwrap();
 +    let stmt_list: ast::StmtList = body.stmt_list().unwrap();
 +    let expr: ast::Expr = stmt_list.tail_expr().unwrap();
 +
 +    // Enums are used to group related ast nodes together, and can be used for
 +    // matching. However, because there are no public fields, it's possible to
 +    // match only the top level enum: that is the price we pay for increased API
 +    // flexibility
 +    let bin_expr: &ast::BinExpr = match &expr {
 +        ast::Expr::BinExpr(e) => e,
 +        _ => unreachable!(),
 +    };
 +
 +    // Besides the "typed" AST API, there's an untyped CST one as well.
 +    // To switch from AST to CST, call `.syntax()` method:
 +    let expr_syntax: &SyntaxNode = expr.syntax();
 +
 +    // Note how `expr` and `bin_expr` are in fact the same node underneath:
 +    assert!(expr_syntax == bin_expr.syntax());
 +
 +    // To go from CST to AST, `AstNode::cast` function is used:
 +    let _expr: ast::Expr = match ast::Expr::cast(expr_syntax.clone()) {
 +        Some(e) => e,
 +        None => unreachable!(),
 +    };
 +
 +    // The two properties each syntax node has is a `SyntaxKind`:
 +    assert_eq!(expr_syntax.kind(), SyntaxKind::BIN_EXPR);
 +
 +    // And text range:
 +    assert_eq!(expr_syntax.text_range(), TextRange::new(32.into(), 37.into()));
 +
 +    // You can get node's text as a `SyntaxText` object, which will traverse the
 +    // tree collecting token's text:
 +    let text: SyntaxText = expr_syntax.text();
 +    assert_eq!(text.to_string(), "1 + 1");
 +
 +    // There's a bunch of traversal methods on `SyntaxNode`:
 +    assert_eq!(expr_syntax.parent().as_ref(), Some(stmt_list.syntax()));
 +    assert_eq!(stmt_list.syntax().first_child_or_token().map(|it| it.kind()), Some(T!['{']));
 +    assert_eq!(
 +        expr_syntax.next_sibling_or_token().map(|it| it.kind()),
 +        Some(SyntaxKind::WHITESPACE)
 +    );
 +
 +    // As well as some iterator helpers:
 +    let f = expr_syntax.ancestors().find_map(ast::Fn::cast);
 +    assert_eq!(f, Some(func));
 +    assert!(expr_syntax.siblings_with_tokens(Direction::Next).any(|it| it.kind() == T!['}']));
 +    assert_eq!(
 +        expr_syntax.descendants_with_tokens().count(),
 +        8, // 5 tokens `1`, ` `, `+`, ` `, `!`
 +           // 2 child literal expressions: `1`, `1`
 +           // 1 the node itself: `1 + 1`
 +    );
 +
 +    // There's also a `preorder` method with a more fine-grained iteration control:
 +    let mut buf = String::new();
 +    let mut indent = 0;
 +    for event in expr_syntax.preorder_with_tokens() {
 +        match event {
 +            WalkEvent::Enter(node) => {
 +                let text = match &node {
 +                    NodeOrToken::Node(it) => it.text().to_string(),
 +                    NodeOrToken::Token(it) => it.text().to_string(),
 +                };
 +                format_to!(buf, "{:indent$}{:?} {:?}\n", " ", text, node.kind(), indent = indent);
 +                indent += 2;
 +            }
 +            WalkEvent::Leave(_) => indent -= 2,
 +        }
 +    }
 +    assert_eq!(indent, 0);
 +    assert_eq!(
 +        buf.trim(),
 +        r#"
 +"1 + 1" BIN_EXPR
 +  "1" LITERAL
 +    "1" INT_NUMBER
 +  " " WHITESPACE
 +  "+" PLUS
 +  " " WHITESPACE
 +  "1" LITERAL
 +    "1" INT_NUMBER
 +"#
 +        .trim()
 +    );
 +
 +    // To recursively process the tree, there are three approaches:
 +    // 1. explicitly call getter methods on AST nodes.
 +    // 2. use descendants and `AstNode::cast`.
 +    // 3. use descendants and `match_ast!`.
 +    //
 +    // Here's how the first one looks like:
 +    let exprs_cast: Vec<String> = file
 +        .syntax()
 +        .descendants()
 +        .filter_map(ast::Expr::cast)
 +        .map(|expr| expr.syntax().text().to_string())
 +        .collect();
 +
 +    // An alternative is to use a macro.
 +    let mut exprs_visit = Vec::new();
 +    for node in file.syntax().descendants() {
 +        match_ast! {
 +            match node {
 +                ast::Expr(it) => {
 +                    let res = it.syntax().text().to_string();
 +                    exprs_visit.push(res);
 +                },
 +                _ => (),
 +            }
 +        }
 +    }
 +    assert_eq!(exprs_cast, exprs_visit);
 +}
index 59b1c147d7f174e08339de3225c5e3541b2af1c9,0000000000000000000000000000000000000000..69d2e62b2567357541b81ab43bb83ea2ff1ac7f3
mode 100644,000000..100644
--- /dev/null
@@@ -1,763 -1,0 +1,732 @@@
- //!     infallible:
 +//! This is a fixture we use for tests that need lang items.
 +//!
 +//! We want to include the minimal subset of core for each test, so this file
 +//! supports "conditional compilation". Tests use the following syntax to include minicore:
 +//!
 +//!  //- minicore: flag1, flag2
 +//!
 +//! We then strip all the code marked with other flags.
 +//!
 +//! Available flags:
 +//!     add:
 +//!     as_ref: sized
 +//!     bool_impl: option, fn
 +//!     clone: sized
 +//!     coerce_unsized: unsize
 +//!     copy: clone
 +//!     default: sized
 +//!     deref_mut: deref
 +//!     deref: sized
 +//!     derive:
 +//!     drop:
 +//!     eq: sized
 +//!     fmt: result
 +//!     fn:
 +//!     from: sized
 +//!     future: pin
 +//!     generator: pin
 +//!     hash:
 +//!     index: sized
- //!     try: infallible
 +//!     iterator: option
 +//!     iterators: iterator, fn
 +//!     option:
 +//!     ord: eq, option
 +//!     pin:
 +//!     range:
 +//!     result:
 +//!     sized:
 +//!     slice:
-     // region:infallible
-     pub enum Infallible {}
-     // endregion:infallible
++//!     try:
 +//!     unsize: sized
 +
 +pub mod marker {
 +    // region:sized
 +    #[lang = "sized"]
 +    #[fundamental]
 +    #[rustc_specialization_trait]
 +    pub trait Sized {}
 +    // endregion:sized
 +
 +    // region:unsize
 +    #[lang = "unsize"]
 +    pub trait Unsize<T: ?Sized> {}
 +    // endregion:unsize
 +
 +    // region:copy
 +    #[lang = "copy"]
 +    pub trait Copy: Clone {}
 +    // region:derive
 +    #[rustc_builtin_macro]
 +    pub macro Copy($item:item) {}
 +    // endregion:derive
 +
 +    mod copy_impls {
 +        use super::Copy;
 +
 +        macro_rules! impl_copy {
 +            ($($t:ty)*) => {
 +                $(
 +                    impl Copy for $t {}
 +                )*
 +            }
 +        }
 +
 +        impl_copy! {
 +            usize u8 u16 u32 u64 u128
 +            isize i8 i16 i32 i64 i128
 +            f32 f64
 +            bool char
 +        }
 +
 +        impl<T: ?Sized> Copy for *const T {}
 +        impl<T: ?Sized> Copy for *mut T {}
 +        impl<T: ?Sized> Copy for &T {}
 +    }
 +    // endregion:copy
 +}
 +
 +// region:default
 +pub mod default {
 +    pub trait Default: Sized {
 +        fn default() -> Self;
 +    }
 +    // region:derive
 +    #[rustc_builtin_macro]
 +    pub macro Default($item:item) {}
 +    // endregion:derive
 +}
 +// endregion:default
 +
 +// region:hash
 +pub mod hash {
 +    pub trait Hasher {}
 +
 +    pub trait Hash {
 +        fn hash<H: Hasher>(&self, state: &mut H);
 +    }
 +}
 +// endregion:hash
 +
 +// region:clone
 +pub mod clone {
 +    #[lang = "clone"]
 +    pub trait Clone: Sized {
 +        fn clone(&self) -> Self;
 +    }
 +    // region:derive
 +    #[rustc_builtin_macro]
 +    pub macro Clone($item:item) {}
 +    // endregion:derive
 +}
 +// endregion:clone
 +
 +pub mod convert {
 +    // region:from
 +    pub trait From<T>: Sized {
 +        fn from(_: T) -> Self;
 +    }
 +    pub trait Into<T>: Sized {
 +        fn into(self) -> T;
 +    }
 +
 +    impl<T, U> Into<U> for T
 +    where
 +        U: From<T>,
 +    {
 +        fn into(self) -> U {
 +            U::from(self)
 +        }
 +    }
 +
 +    impl<T> From<T> for T {
 +        fn from(t: T) -> T {
 +            t
 +        }
 +    }
 +    // endregion:from
 +
 +    // region:as_ref
 +    pub trait AsRef<T: ?Sized> {
 +        fn as_ref(&self) -> &T;
 +    }
 +    // endregion:as_ref
-         pub trait FromResidual<R = <Self as Try>::Residual> {
 +}
 +
 +pub mod ops {
 +    // region:coerce_unsized
 +    mod unsize {
 +        use crate::marker::Unsize;
 +
 +        #[lang = "coerce_unsized"]
 +        pub trait CoerceUnsized<T: ?Sized> {}
 +
 +        impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
 +        impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {}
 +        impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {}
 +        impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {}
 +
 +        impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
 +        impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {}
 +
 +        impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
 +        impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
 +        impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
 +    }
 +    pub use self::unsize::CoerceUnsized;
 +    // endregion:coerce_unsized
 +
 +    // region:deref
 +    mod deref {
 +        #[lang = "deref"]
 +        pub trait Deref {
 +            #[lang = "deref_target"]
 +            type Target: ?Sized;
 +            fn deref(&self) -> &Self::Target;
 +        }
 +
 +        impl<T: ?Sized> Deref for &T {
 +            type Target = T;
 +            fn deref(&self) -> &T {
 +                loop {}
 +            }
 +        }
 +        impl<T: ?Sized> Deref for &mut T {
 +            type Target = T;
 +            fn deref(&self) -> &T {
 +                loop {}
 +            }
 +        }
 +        // region:deref_mut
 +        #[lang = "deref_mut"]
 +        pub trait DerefMut: Deref {
 +            fn deref_mut(&mut self) -> &mut Self::Target;
 +        }
 +        // endregion:deref_mut
 +    }
 +    pub use self::deref::{
 +        Deref,
 +        DerefMut, // :deref_mut
 +    };
 +    // endregion:deref
 +
 +    // region:drop
 +    #[lang = "drop"]
 +    pub trait Drop {
 +        fn drop(&mut self);
 +    }
 +    // endregion:drop
 +
 +    // region:index
 +    mod index {
 +        #[lang = "index"]
 +        pub trait Index<Idx: ?Sized> {
 +            type Output: ?Sized;
 +            fn index(&self, index: Idx) -> &Self::Output;
 +        }
 +        #[lang = "index_mut"]
 +        pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
 +            fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
 +        }
 +
 +        // region:slice
 +        impl<T, I> Index<I> for [T]
 +        where
 +            I: SliceIndex<[T]>,
 +        {
 +            type Output = I::Output;
 +            fn index(&self, index: I) -> &I::Output {
 +                loop {}
 +            }
 +        }
 +        impl<T, I> IndexMut<I> for [T]
 +        where
 +            I: SliceIndex<[T]>,
 +        {
 +            fn index_mut(&mut self, index: I) -> &mut I::Output {
 +                loop {}
 +            }
 +        }
 +
 +        pub unsafe trait SliceIndex<T: ?Sized> {
 +            type Output: ?Sized;
 +        }
 +        unsafe impl<T> SliceIndex<[T]> for usize {
 +            type Output = T;
 +        }
 +        // endregion:slice
 +    }
 +    pub use self::index::{Index, IndexMut};
 +    // endregion:index
 +
 +    // region:drop
 +    pub mod mem {
 +        pub fn drop<T>(_x: T) {}
 +    }
 +    // endregion:drop
 +
 +    // region:range
 +    mod range {
 +        #[lang = "RangeFull"]
 +        pub struct RangeFull;
 +
 +        #[lang = "Range"]
 +        pub struct Range<Idx> {
 +            pub start: Idx,
 +            pub end: Idx,
 +        }
 +
 +        #[lang = "RangeFrom"]
 +        pub struct RangeFrom<Idx> {
 +            pub start: Idx,
 +        }
 +
 +        #[lang = "RangeTo"]
 +        pub struct RangeTo<Idx> {
 +            pub end: Idx,
 +        }
 +
 +        #[lang = "RangeInclusive"]
 +        pub struct RangeInclusive<Idx> {
 +            pub(crate) start: Idx,
 +            pub(crate) end: Idx,
 +            pub(crate) exhausted: bool,
 +        }
 +
 +        #[lang = "RangeToInclusive"]
 +        pub struct RangeToInclusive<Idx> {
 +            pub end: Idx,
 +        }
 +    }
 +    pub use self::range::{Range, RangeFrom, RangeFull, RangeTo};
 +    pub use self::range::{RangeInclusive, RangeToInclusive};
 +    // endregion:range
 +
 +    // region:fn
 +    mod function {
 +        #[lang = "fn"]
 +        #[fundamental]
 +        pub trait Fn<Args>: FnMut<Args> {}
 +
 +        #[lang = "fn_mut"]
 +        #[fundamental]
 +        pub trait FnMut<Args>: FnOnce<Args> {}
 +
 +        #[lang = "fn_once"]
 +        #[fundamental]
 +        pub trait FnOnce<Args> {
 +            #[lang = "fn_once_output"]
 +            type Output;
 +        }
 +    }
 +    pub use self::function::{Fn, FnMut, FnOnce};
 +    // endregion:fn
 +    // region:try
 +    mod try_ {
 +        pub enum ControlFlow<B, C = ()> {
 +            Continue(C),
 +            Break(B),
 +        }
-             type Residual = ControlFlow<B, crate::convert::Infallible>;
++        pub trait FromResidual<R = Self::Residual> {
 +            #[lang = "from_residual"]
 +            fn from_residual(residual: R) -> Self;
 +        }
 +        #[lang = "try"]
 +        pub trait Try: FromResidual<Self::Residual> {
 +            type Output;
 +            type Residual;
 +            #[lang = "from_output"]
 +            fn from_output(output: Self::Output) -> Self;
 +            #[lang = "branch"]
 +            fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
 +        }
 +
 +        impl<B, C> Try for ControlFlow<B, C> {
 +            type Output = C;
-             fn from_residual(residual: ControlFlow<B, crate::convert::Infallible>) -> Self {}
++            type Residual = ControlFlow<B, convert::Infallible>;
 +            fn from_output(output: Self::Output) -> Self {}
 +            fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {}
 +        }
 +
 +        impl<B, C> FromResidual for ControlFlow<B, C> {
-     // region:try
-     impl<T> crate::ops::Try for Option<T> {
-         type Output = T;
-         type Residual = Option<crate::convert::Infallible>;
-         #[inline]
-         fn from_output(output: Self::Output) -> Self {
-             Some(output)
-         }
-         #[inline]
-         fn branch(self) -> crate::ops::ControlFlow<Self::Residual, Self::Output> {
-             match self {
-                 Some(v) => crate::ops::ControlFlow::Continue(v),
-                 None => crate::ops::ControlFlow::Break(None),
-             }
-         }
-     }
-     impl<T> crate::ops::FromResidual for Option<T> {
-         #[inline]
-         fn from_residual(residual: Option<crate::convert::Infallible>) -> Self {
-             match residual {
-                 None => None,
-             }
-         }
-     }
-     // endregion:try
++            fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {}
 +        }
 +    }
 +    pub use self::try_::{ControlFlow, FromResidual, Try};
 +    // endregion:try
 +
 +    // region:add
 +    #[lang = "add"]
 +    pub trait Add<Rhs = Self> {
 +        type Output;
 +        fn add(self, rhs: Rhs) -> Self::Output;
 +    }
 +    // endregion:add
 +
 +    // region:generator
 +    mod generator {
 +        use crate::pin::Pin;
 +
 +        #[lang = "generator"]
 +        pub trait Generator<R = ()> {
 +            type Yield;
 +            #[lang = "generator_return"]
 +            type Return;
 +            fn resume(self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return>;
 +        }
 +
 +        #[lang = "generator_state"]
 +        pub enum GeneratorState<Y, R> {
 +            Yielded(Y),
 +            Complete(R),
 +        }
 +    }
 +    pub use self::generator::{Generator, GeneratorState};
 +    // endregion:generator
 +}
 +
 +// region:eq
 +pub mod cmp {
 +    #[lang = "eq"]
 +    pub trait PartialEq<Rhs: ?Sized = Self> {
 +        fn eq(&self, other: &Rhs) -> bool;
 +        fn ne(&self, other: &Rhs) -> bool {
 +            !self.eq(other)
 +        }
 +    }
 +
 +    pub trait Eq: PartialEq<Self> {}
 +
 +    // region:derive
 +    #[rustc_builtin_macro]
 +    pub macro PartialEq($item:item) {}
 +    #[rustc_builtin_macro]
 +    pub macro Eq($item:item) {}
 +    // endregion:derive
 +
 +    // region:ord
 +    #[lang = "partial_ord"]
 +    pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
 +        fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;
 +    }
 +
 +    pub trait Ord: Eq + PartialOrd<Self> {
 +        fn cmp(&self, other: &Self) -> Ordering;
 +    }
 +
 +    pub enum Ordering {
 +        Less = -1,
 +        Equal = 0,
 +        Greater = 1,
 +    }
 +
 +    // region:derive
 +    #[rustc_builtin_macro]
 +    pub macro PartialOrd($item:item) {}
 +    #[rustc_builtin_macro]
 +    pub macro Ord($item:item) {}
 +    // endregion:derive
 +
 +    // endregion:ord
 +}
 +// endregion:eq
 +
 +// region:fmt
 +pub mod fmt {
 +    pub struct Error;
 +    pub type Result = Result<(), Error>;
 +    pub struct Formatter<'a>;
 +    pub trait Debug {
 +        fn fmt(&self, f: &mut Formatter<'_>) -> Result;
 +    }
 +}
 +// endregion:fmt
 +
 +// region:slice
 +pub mod slice {
 +    #[lang = "slice"]
 +    impl<T> [T] {
 +        pub fn len(&self) -> usize {
 +            loop {}
 +        }
 +    }
 +}
 +// endregion:slice
 +
 +// region:option
 +pub mod option {
 +    pub enum Option<T> {
 +        #[lang = "None"]
 +        None,
 +        #[lang = "Some"]
 +        Some(T),
 +    }
 +
 +    impl<T> Option<T> {
 +        pub const fn unwrap(self) -> T {
 +            match self {
 +                Some(val) => val,
 +                None => panic!("called `Option::unwrap()` on a `None` value"),
 +            }
 +        }
 +    }
 +}
 +// endregion:option
 +
 +// region:result
 +pub mod result {
 +    pub enum Result<T, E> {
 +        #[lang = "Ok"]
 +        Ok(T),
 +        #[lang = "Err"]
 +        Err(E),
 +    }
 +}
 +// endregion:result
 +
 +// region:pin
 +pub mod pin {
 +    #[lang = "pin"]
 +    #[fundamental]
 +    pub struct Pin<P> {
 +        pointer: P,
 +    }
 +    impl<P> Pin<P> {
 +        pub fn new(pointer: P) -> Pin<P> {
 +            loop {}
 +        }
 +    }
 +    // region:deref
 +    impl<P: crate::ops::Deref> crate::ops::Deref for Pin<P> {
 +        type Target = P::Target;
 +        fn deref(&self) -> &P::Target {
 +            loop {}
 +        }
 +    }
 +    // endregion:deref
 +}
 +// endregion:pin
 +
 +// region:future
 +pub mod future {
 +    use crate::{
 +        pin::Pin,
 +        task::{Context, Poll},
 +    };
 +
 +    #[lang = "future_trait"]
 +    pub trait Future {
 +        type Output;
 +        #[lang = "poll"]
 +        fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
 +    }
 +
 +    pub trait IntoFuture {
 +        type Output;
 +        type IntoFuture: Future<Output = Self::Output>;
 +        #[lang = "into_future"]
 +        fn into_future(self) -> Self::IntoFuture;
 +    }
 +
 +    impl<F: Future> IntoFuture for F {
 +        type Output = F::Output;
 +        type IntoFuture = F;
 +        fn into_future(self) -> F {
 +            self
 +        }
 +    }
 +}
 +pub mod task {
 +    pub enum Poll<T> {
 +        #[lang = "Ready"]
 +        Ready(T),
 +        #[lang = "Pending"]
 +        Pending,
 +    }
 +
 +    pub struct Context<'a> {
 +        waker: &'a (),
 +    }
 +}
 +// endregion:future
 +
 +// region:iterator
 +pub mod iter {
 +    // region:iterators
 +    mod adapters {
 +        pub struct Take<I> {
 +            iter: I,
 +            n: usize,
 +        }
 +        impl<I> Iterator for Take<I>
 +        where
 +            I: Iterator,
 +        {
 +            type Item = <I as Iterator>::Item;
 +
 +            fn next(&mut self) -> Option<<I as Iterator>::Item> {
 +                loop {}
 +            }
 +        }
 +
 +        pub struct FilterMap<I, F> {
 +            iter: I,
 +            f: F,
 +        }
 +        impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
 +        where
 +            F: FnMut(I::Item) -> Option<B>,
 +        {
 +            type Item = B;
 +
 +            #[inline]
 +            fn next(&mut self) -> Option<B> {
 +                loop {}
 +            }
 +        }
 +    }
 +    pub use self::adapters::{FilterMap, Take};
 +
 +    mod sources {
 +        mod repeat {
 +            pub fn repeat<T>(elt: T) -> Repeat<T> {
 +                loop {}
 +            }
 +
 +            pub struct Repeat<A> {
 +                element: A,
 +            }
 +
 +            impl<A> Iterator for Repeat<A> {
 +                type Item = A;
 +
 +                fn next(&mut self) -> Option<A> {
 +                    loop {}
 +                }
 +            }
 +        }
 +        pub use self::repeat::{repeat, Repeat};
 +    }
 +    pub use self::sources::{repeat, Repeat};
 +    // endregion:iterators
 +
 +    mod traits {
 +        mod iterator {
 +            use super::super::Take;
 +
 +            pub trait Iterator {
 +                type Item;
 +                #[lang = "next"]
 +                fn next(&mut self) -> Option<Self::Item>;
 +                fn nth(&mut self, n: usize) -> Option<Self::Item> {
 +                    loop {}
 +                }
 +                fn by_ref(&mut self) -> &mut Self
 +                where
 +                    Self: Sized,
 +                {
 +                    self
 +                }
 +                // region:iterators
 +                fn take(self, n: usize) -> crate::iter::Take<Self> {
 +                    loop {}
 +                }
 +                fn filter_map<B, F>(self, f: F) -> crate::iter::FilterMap<Self, F>
 +                where
 +                    Self: Sized,
 +                    F: FnMut(Self::Item) -> Option<B>,
 +                {
 +                    loop {}
 +                }
 +                // endregion:iterators
 +            }
 +            impl<I: Iterator + ?Sized> Iterator for &mut I {
 +                type Item = I::Item;
 +                fn next(&mut self) -> Option<I::Item> {
 +                    (**self).next()
 +                }
 +            }
 +        }
 +        pub use self::iterator::Iterator;
 +
 +        mod collect {
 +            pub trait IntoIterator {
 +                type Item;
 +                type IntoIter: Iterator<Item = Self::Item>;
 +                #[lang = "into_iter"]
 +                fn into_iter(self) -> Self::IntoIter;
 +            }
 +            impl<I: Iterator> IntoIterator for I {
 +                type Item = I::Item;
 +                type IntoIter = I;
 +                fn into_iter(self) -> I {
 +                    self
 +                }
 +            }
 +        }
 +        pub use self::collect::IntoIterator;
 +    }
 +    pub use self::traits::{IntoIterator, Iterator};
 +}
 +// endregion:iterator
 +
 +// region:derive
 +mod macros {
 +    pub(crate) mod builtin {
 +        #[rustc_builtin_macro]
 +        pub macro derive($item:item) {
 +            /* compiler built-in */
 +        }
 +    }
 +}
 +// endregion:derive
 +
 +// region:bool_impl
 +#[lang = "bool"]
 +impl bool {
 +    pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
 +        if self {
 +            Some(f())
 +        } else {
 +            None
 +        }
 +    }
 +}
 +// endregion:bool_impl
 +
 +pub mod prelude {
 +    pub mod v1 {
 +        pub use crate::{
 +            clone::Clone,                       // :clone
 +            cmp::{Eq, PartialEq},               // :eq
 +            cmp::{Ord, PartialOrd},             // :ord
 +            convert::AsRef,                     // :as_ref
 +            convert::{From, Into},              // :from
 +            default::Default,                   // :default
 +            iter::{IntoIterator, Iterator},     // :iterator
 +            macros::builtin::derive,            // :derive
 +            marker::Copy,                       // :copy
 +            marker::Sized,                      // :sized
 +            mem::drop,                          // :drop
 +            ops::Drop,                          // :drop
 +            ops::{Fn, FnMut, FnOnce},           // :fn
 +            option::Option::{self, None, Some}, // :option
 +            result::Result::{self, Err, Ok},    // :result
 +        };
 +    }
 +
 +    pub mod rust_2015 {
 +        pub use super::v1::*;
 +    }
 +
 +    pub mod rust_2018 {
 +        pub use super::v1::*;
 +    }
 +
 +    pub mod rust_2021 {
 +        pub use super::v1::*;
 +    }
 +}
 +
 +#[prelude_import]
 +#[allow(unused)]
 +use prelude::v1::*;
index acf0aaea859a28c988bbcf682f01b07a64789fcc,0000000000000000000000000000000000000000..502833de72c161716d30f0456e4f2e3e6563d3ae
mode 100644,000000..100644
--- /dev/null
@@@ -1,708 -1,0 +1,746 @@@
 +[[rust-analyzer.assist.expressionFillDefault]]rust-analyzer.assist.expressionFillDefault (default: `"todo"`)::
 ++
 +--
 +Placeholder expression to use for missing expressions in assists.
 +--
 +[[rust-analyzer.cachePriming.enable]]rust-analyzer.cachePriming.enable (default: `true`)::
 ++
 +--
 +Warm up caches on project load.
 +--
 +[[rust-analyzer.cachePriming.numThreads]]rust-analyzer.cachePriming.numThreads (default: `0`)::
 ++
 +--
 +How many worker threads to handle priming caches. The default `0` means to pick automatically.
 +--
 +[[rust-analyzer.cargo.autoreload]]rust-analyzer.cargo.autoreload (default: `true`)::
 ++
 +--
 +Automatically refresh project info via `cargo metadata` on
 +`Cargo.toml` or `.cargo/config.toml` changes.
 +--
 +[[rust-analyzer.cargo.buildScripts.enable]]rust-analyzer.cargo.buildScripts.enable (default: `true`)::
 ++
 +--
 +Run build scripts (`build.rs`) for more precise code analysis.
 +--
++[[rust-analyzer.cargo.buildScripts.invocationLocation]]rust-analyzer.cargo.buildScripts.invocationLocation (default: `"workspace"`)::
+++
++--
++Specifies the working directory for running build scripts.
++- "workspace": run build scripts for a workspace in the workspace's root directory.
++  This is incompatible with `#rust-analyzer.cargo.buildScripts.invocationStrategy#` set to `once`.
++- "root": run build scripts in the project's root directory.
++This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
++is set.
++--
++[[rust-analyzer.cargo.buildScripts.invocationStrategy]]rust-analyzer.cargo.buildScripts.invocationStrategy (default: `"per_workspace"`)::
+++
++--
++Specifies the invocation strategy to use when running the build scripts command.
++If `per_workspace` is set, the command will be executed for each workspace.
++If `once` is set, the command will be executed once.
++This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
++is set.
++--
 +[[rust-analyzer.cargo.buildScripts.overrideCommand]]rust-analyzer.cargo.buildScripts.overrideCommand (default: `null`)::
 ++
 +--
 +Override the command rust-analyzer uses to run build scripts and
 +build procedural macros. The command is required to output json
 +and should therefore include `--message-format=json` or a similar
 +option.
 +
 +By default, a cargo invocation will be constructed for the configured
 +targets and features, with the following base command line:
 +
 +```bash
 +cargo check --quiet --workspace --message-format=json --all-targets
 +```
 +.
 +--
 +[[rust-analyzer.cargo.buildScripts.useRustcWrapper]]rust-analyzer.cargo.buildScripts.useRustcWrapper (default: `true`)::
 ++
 +--
 +Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
 +avoid checking unnecessary things.
 +--
 +[[rust-analyzer.cargo.extraEnv]]rust-analyzer.cargo.extraEnv (default: `{}`)::
 ++
 +--
 +Extra environment variables that will be set when running cargo, rustc
 +or other commands within the workspace. Useful for setting RUSTFLAGS.
 +--
 +[[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`)::
 ++
 +--
 +List of features to activate.
 +
 +Set this to `"all"` to pass `--all-features` to cargo.
 +--
 +[[rust-analyzer.cargo.noDefaultFeatures]]rust-analyzer.cargo.noDefaultFeatures (default: `false`)::
 ++
 +--
 +Whether to pass `--no-default-features` to cargo.
 +--
 +[[rust-analyzer.cargo.sysroot]]rust-analyzer.cargo.sysroot (default: `"discover"`)::
 ++
 +--
 +Relative path to the sysroot, or "discover" to try to automatically find it via
 +"rustc --print sysroot".
 +
 +Unsetting this disables sysroot loading.
 +
 +This option does not take effect until rust-analyzer is restarted.
 +--
 +[[rust-analyzer.cargo.target]]rust-analyzer.cargo.target (default: `null`)::
 ++
 +--
 +Compilation target override (target triple).
 +--
 +[[rust-analyzer.cargo.unsetTest]]rust-analyzer.cargo.unsetTest (default: `["core"]`)::
 ++
 +--
 +Unsets `#[cfg(test)]` for the specified crates.
 +--
 +[[rust-analyzer.checkOnSave.allTargets]]rust-analyzer.checkOnSave.allTargets (default: `true`)::
 ++
 +--
 +Check all targets and tests (`--all-targets`).
 +--
 +[[rust-analyzer.checkOnSave.command]]rust-analyzer.checkOnSave.command (default: `"check"`)::
 ++
 +--
 +Cargo command to use for `cargo check`.
 +--
 +[[rust-analyzer.checkOnSave.enable]]rust-analyzer.checkOnSave.enable (default: `true`)::
 ++
 +--
 +Run specified `cargo check` command for diagnostics on save.
 +--
 +[[rust-analyzer.checkOnSave.extraArgs]]rust-analyzer.checkOnSave.extraArgs (default: `[]`)::
 ++
 +--
 +Extra arguments for `cargo check`.
 +--
 +[[rust-analyzer.checkOnSave.extraEnv]]rust-analyzer.checkOnSave.extraEnv (default: `{}`)::
 ++
 +--
 +Extra environment variables that will be set when running `cargo check`.
 +Extends `#rust-analyzer.cargo.extraEnv#`.
 +--
 +[[rust-analyzer.checkOnSave.features]]rust-analyzer.checkOnSave.features (default: `null`)::
 ++
 +--
 +List of features to activate. Defaults to
 +`#rust-analyzer.cargo.features#`.
 +
 +Set to `"all"` to pass `--all-features` to Cargo.
 +--
++[[rust-analyzer.checkOnSave.invocationLocation]]rust-analyzer.checkOnSave.invocationLocation (default: `"workspace"`)::
+++
++--
++Specifies the working directory for running checks.
++- "workspace": run checks for workspaces in the corresponding workspaces' root directories.
++  This falls back to "root" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`.
++- "root": run checks in the project's root directory.
++This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
++is set.
++--
++[[rust-analyzer.checkOnSave.invocationStrategy]]rust-analyzer.checkOnSave.invocationStrategy (default: `"per_workspace"`)::
+++
++--
++Specifies the invocation strategy to use when running the checkOnSave command.
++If `per_workspace` is set, the command will be executed for each workspace.
++If `once` is set, the command will be executed once.
++This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
++is set.
++--
 +[[rust-analyzer.checkOnSave.noDefaultFeatures]]rust-analyzer.checkOnSave.noDefaultFeatures (default: `null`)::
 ++
 +--
 +Whether to pass `--no-default-features` to Cargo. Defaults to
 +`#rust-analyzer.cargo.noDefaultFeatures#`.
 +--
 +[[rust-analyzer.checkOnSave.overrideCommand]]rust-analyzer.checkOnSave.overrideCommand (default: `null`)::
 ++
 +--
 +Override the command rust-analyzer uses instead of `cargo check` for
 +diagnostics on save. The command is required to output json and
 +should therefor include `--message-format=json` or a similar option.
 +
 +If you're changing this because you're using some tool wrapping
 +Cargo, you might also want to change
 +`#rust-analyzer.cargo.buildScripts.overrideCommand#`.
 +
 +If there are multiple linked projects, this command is invoked for
 +each of them, with the working directory being the project root
 +(i.e., the folder containing the `Cargo.toml`).
 +
 +An example command would be:
 +
 +```bash
 +cargo check --workspace --message-format=json --all-targets
 +```
 +.
 +--
 +[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `null`)::
 ++
 +--
 +Check for a specific target. Defaults to
 +`#rust-analyzer.cargo.target#`.
 +--
 +[[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`)::
 ++
 +--
 +Toggles the additional completions that automatically add imports when completed.
 +Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
 +--
 +[[rust-analyzer.completion.autoself.enable]]rust-analyzer.completion.autoself.enable (default: `true`)::
 ++
 +--
 +Toggles the additional completions that automatically show method calls and field accesses
 +with `self` prefixed to them when inside a method.
 +--
 +[[rust-analyzer.completion.callable.snippets]]rust-analyzer.completion.callable.snippets (default: `"fill_arguments"`)::
 ++
 +--
 +Whether to add parenthesis and argument snippets when completing function.
 +--
 +[[rust-analyzer.completion.postfix.enable]]rust-analyzer.completion.postfix.enable (default: `true`)::
 ++
 +--
 +Whether to show postfix snippets like `dbg`, `if`, `not`, etc.
 +--
 +[[rust-analyzer.completion.privateEditable.enable]]rust-analyzer.completion.privateEditable.enable (default: `false`)::
 ++
 +--
 +Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.
 +--
 +[[rust-analyzer.completion.snippets.custom]]rust-analyzer.completion.snippets.custom::
 ++
 +--
 +Default:
 +----
 +{
 +            "Arc::new": {
 +                "postfix": "arc",
 +                "body": "Arc::new(${receiver})",
 +                "requires": "std::sync::Arc",
 +                "description": "Put the expression into an `Arc`",
 +                "scope": "expr"
 +            },
 +            "Rc::new": {
 +                "postfix": "rc",
 +                "body": "Rc::new(${receiver})",
 +                "requires": "std::rc::Rc",
 +                "description": "Put the expression into an `Rc`",
 +                "scope": "expr"
 +            },
 +            "Box::pin": {
 +                "postfix": "pinbox",
 +                "body": "Box::pin(${receiver})",
 +                "requires": "std::boxed::Box",
 +                "description": "Put the expression into a pinned `Box`",
 +                "scope": "expr"
 +            },
 +            "Ok": {
 +                "postfix": "ok",
 +                "body": "Ok(${receiver})",
 +                "description": "Wrap the expression in a `Result::Ok`",
 +                "scope": "expr"
 +            },
 +            "Err": {
 +                "postfix": "err",
 +                "body": "Err(${receiver})",
 +                "description": "Wrap the expression in a `Result::Err`",
 +                "scope": "expr"
 +            },
 +            "Some": {
 +                "postfix": "some",
 +                "body": "Some(${receiver})",
 +                "description": "Wrap the expression in an `Option::Some`",
 +                "scope": "expr"
 +            }
 +        }
 +----
 +Custom completion snippets.
 +
 +--
 +[[rust-analyzer.diagnostics.disabled]]rust-analyzer.diagnostics.disabled (default: `[]`)::
 ++
 +--
 +List of rust-analyzer diagnostics to disable.
 +--
 +[[rust-analyzer.diagnostics.enable]]rust-analyzer.diagnostics.enable (default: `true`)::
 ++
 +--
 +Whether to show native rust-analyzer diagnostics.
 +--
 +[[rust-analyzer.diagnostics.experimental.enable]]rust-analyzer.diagnostics.experimental.enable (default: `false`)::
 ++
 +--
 +Whether to show experimental rust-analyzer diagnostics that might
 +have more false positives than usual.
 +--
 +[[rust-analyzer.diagnostics.remapPrefix]]rust-analyzer.diagnostics.remapPrefix (default: `{}`)::
 ++
 +--
 +Map of prefixes to be substituted when parsing diagnostic file paths.
 +This should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`.
 +--
 +[[rust-analyzer.diagnostics.warningsAsHint]]rust-analyzer.diagnostics.warningsAsHint (default: `[]`)::
 ++
 +--
 +List of warnings that should be displayed with hint severity.
 +
 +The warnings will be indicated by faded text or three dots in code
 +and will not show up in the `Problems Panel`.
 +--
 +[[rust-analyzer.diagnostics.warningsAsInfo]]rust-analyzer.diagnostics.warningsAsInfo (default: `[]`)::
 ++
 +--
 +List of warnings that should be displayed with info severity.
 +
 +The warnings will be indicated by a blue squiggly underline in code
 +and a blue icon in the `Problems Panel`.
 +--
 +[[rust-analyzer.files.excludeDirs]]rust-analyzer.files.excludeDirs (default: `[]`)::
 ++
 +--
 +These directories will be ignored by rust-analyzer. They are
 +relative to the workspace root, and globs are not supported. You may
 +also need to add the folders to Code's `files.watcherExclude`.
 +--
 +[[rust-analyzer.files.watcher]]rust-analyzer.files.watcher (default: `"client"`)::
 ++
 +--
 +Controls file watching implementation.
 +--
 +[[rust-analyzer.highlightRelated.breakPoints.enable]]rust-analyzer.highlightRelated.breakPoints.enable (default: `true`)::
 ++
 +--
 +Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
 +--
 +[[rust-analyzer.highlightRelated.exitPoints.enable]]rust-analyzer.highlightRelated.exitPoints.enable (default: `true`)::
 ++
 +--
 +Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).
 +--
 +[[rust-analyzer.highlightRelated.references.enable]]rust-analyzer.highlightRelated.references.enable (default: `true`)::
 ++
 +--
 +Enables highlighting of related references while the cursor is on any identifier.
 +--
 +[[rust-analyzer.highlightRelated.yieldPoints.enable]]rust-analyzer.highlightRelated.yieldPoints.enable (default: `true`)::
 ++
 +--
 +Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.
 +--
 +[[rust-analyzer.hover.actions.debug.enable]]rust-analyzer.hover.actions.debug.enable (default: `true`)::
 ++
 +--
 +Whether to show `Debug` action. Only applies when
 +`#rust-analyzer.hover.actions.enable#` is set.
 +--
 +[[rust-analyzer.hover.actions.enable]]rust-analyzer.hover.actions.enable (default: `true`)::
 ++
 +--
 +Whether to show HoverActions in Rust files.
 +--
 +[[rust-analyzer.hover.actions.gotoTypeDef.enable]]rust-analyzer.hover.actions.gotoTypeDef.enable (default: `true`)::
 ++
 +--
 +Whether to show `Go to Type Definition` action. Only applies when
 +`#rust-analyzer.hover.actions.enable#` is set.
 +--
 +[[rust-analyzer.hover.actions.implementations.enable]]rust-analyzer.hover.actions.implementations.enable (default: `true`)::
 ++
 +--
 +Whether to show `Implementations` action. Only applies when
 +`#rust-analyzer.hover.actions.enable#` is set.
 +--
 +[[rust-analyzer.hover.actions.references.enable]]rust-analyzer.hover.actions.references.enable (default: `false`)::
 ++
 +--
 +Whether to show `References` action. Only applies when
 +`#rust-analyzer.hover.actions.enable#` is set.
 +--
 +[[rust-analyzer.hover.actions.run.enable]]rust-analyzer.hover.actions.run.enable (default: `true`)::
 ++
 +--
 +Whether to show `Run` action. Only applies when
 +`#rust-analyzer.hover.actions.enable#` is set.
 +--
 +[[rust-analyzer.hover.documentation.enable]]rust-analyzer.hover.documentation.enable (default: `true`)::
 ++
 +--
 +Whether to show documentation on hover.
 +--
 +[[rust-analyzer.hover.documentation.keywords.enable]]rust-analyzer.hover.documentation.keywords.enable (default: `true`)::
 ++
 +--
 +Whether to show keyword hover popups. Only applies when
 +`#rust-analyzer.hover.documentation.enable#` is set.
 +--
 +[[rust-analyzer.hover.links.enable]]rust-analyzer.hover.links.enable (default: `true`)::
 ++
 +--
 +Use markdown syntax for links in hover.
 +--
 +[[rust-analyzer.imports.granularity.enforce]]rust-analyzer.imports.granularity.enforce (default: `false`)::
 ++
 +--
 +Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.
 +--
 +[[rust-analyzer.imports.granularity.group]]rust-analyzer.imports.granularity.group (default: `"crate"`)::
 ++
 +--
 +How imports should be grouped into use statements.
 +--
 +[[rust-analyzer.imports.group.enable]]rust-analyzer.imports.group.enable (default: `true`)::
 ++
 +--
 +Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-import[following order]. Groups are separated by newlines.
 +--
 +[[rust-analyzer.imports.merge.glob]]rust-analyzer.imports.merge.glob (default: `true`)::
 ++
 +--
 +Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
 +--
 +[[rust-analyzer.imports.prefer.no.std]]rust-analyzer.imports.prefer.no.std (default: `false`)::
 ++
 +--
 +Prefer to unconditionally use imports of the core and alloc crate, over the std crate.
 +--
 +[[rust-analyzer.imports.prefix]]rust-analyzer.imports.prefix (default: `"plain"`)::
 ++
 +--
 +The path structure for newly inserted paths to use.
 +--
 +[[rust-analyzer.inlayHints.bindingModeHints.enable]]rust-analyzer.inlayHints.bindingModeHints.enable (default: `false`)::
 ++
 +--
 +Whether to show inlay type hints for binding modes.
 +--
 +[[rust-analyzer.inlayHints.chainingHints.enable]]rust-analyzer.inlayHints.chainingHints.enable (default: `true`)::
 ++
 +--
 +Whether to show inlay type hints for method chains.
 +--
 +[[rust-analyzer.inlayHints.closingBraceHints.enable]]rust-analyzer.inlayHints.closingBraceHints.enable (default: `true`)::
 ++
 +--
 +Whether to show inlay hints after a closing `}` to indicate what item it belongs to.
 +--
 +[[rust-analyzer.inlayHints.closingBraceHints.minLines]]rust-analyzer.inlayHints.closingBraceHints.minLines (default: `25`)::
 ++
 +--
 +Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1
 +to always show them).
 +--
 +[[rust-analyzer.inlayHints.closureReturnTypeHints.enable]]rust-analyzer.inlayHints.closureReturnTypeHints.enable (default: `"never"`)::
 ++
 +--
 +Whether to show inlay type hints for return types of closures.
 +--
 +[[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`)::
 ++
 +--
 +Whether to show inlay type hints for elided lifetimes in function signatures.
 +--
 +[[rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames]]rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames (default: `false`)::
 ++
 +--
 +Whether to prefer using parameter names as the name for elided lifetime hints if possible.
 +--
 +[[rust-analyzer.inlayHints.maxLength]]rust-analyzer.inlayHints.maxLength (default: `25`)::
 ++
 +--
 +Maximum length for inlay hints. Set to null to have an unlimited length.
 +--
 +[[rust-analyzer.inlayHints.parameterHints.enable]]rust-analyzer.inlayHints.parameterHints.enable (default: `true`)::
 ++
 +--
 +Whether to show function parameter name inlay hints at the call
 +site.
 +--
 +[[rust-analyzer.inlayHints.reborrowHints.enable]]rust-analyzer.inlayHints.reborrowHints.enable (default: `"never"`)::
 ++
 +--
 +Whether to show inlay type hints for compiler inserted reborrows.
 +--
 +[[rust-analyzer.inlayHints.renderColons]]rust-analyzer.inlayHints.renderColons (default: `true`)::
 ++
 +--
 +Whether to render leading colons for type hints, and trailing colons for parameter hints.
 +--
 +[[rust-analyzer.inlayHints.typeHints.enable]]rust-analyzer.inlayHints.typeHints.enable (default: `true`)::
 ++
 +--
 +Whether to show inlay type hints for variables.
 +--
 +[[rust-analyzer.inlayHints.typeHints.hideClosureInitialization]]rust-analyzer.inlayHints.typeHints.hideClosureInitialization (default: `false`)::
 ++
 +--
 +Whether to hide inlay type hints for `let` statements that initialize to a closure.
 +Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.
 +--
 +[[rust-analyzer.inlayHints.typeHints.hideNamedConstructor]]rust-analyzer.inlayHints.typeHints.hideNamedConstructor (default: `false`)::
 ++
 +--
 +Whether to hide inlay type hints for constructors.
 +--
 +[[rust-analyzer.joinLines.joinAssignments]]rust-analyzer.joinLines.joinAssignments (default: `true`)::
 ++
 +--
 +Join lines merges consecutive declaration and initialization of an assignment.
 +--
 +[[rust-analyzer.joinLines.joinElseIf]]rust-analyzer.joinLines.joinElseIf (default: `true`)::
 ++
 +--
 +Join lines inserts else between consecutive ifs.
 +--
 +[[rust-analyzer.joinLines.removeTrailingComma]]rust-analyzer.joinLines.removeTrailingComma (default: `true`)::
 ++
 +--
 +Join lines removes trailing commas.
 +--
 +[[rust-analyzer.joinLines.unwrapTrivialBlock]]rust-analyzer.joinLines.unwrapTrivialBlock (default: `true`)::
 ++
 +--
 +Join lines unwraps trivial blocks.
 +--
 +[[rust-analyzer.lens.debug.enable]]rust-analyzer.lens.debug.enable (default: `true`)::
 ++
 +--
 +Whether to show `Debug` lens. Only applies when
 +`#rust-analyzer.lens.enable#` is set.
 +--
 +[[rust-analyzer.lens.enable]]rust-analyzer.lens.enable (default: `true`)::
 ++
 +--
 +Whether to show CodeLens in Rust files.
 +--
 +[[rust-analyzer.lens.forceCustomCommands]]rust-analyzer.lens.forceCustomCommands (default: `true`)::
 ++
 +--
 +Internal config: use custom client-side commands even when the
 +client doesn't set the corresponding capability.
 +--
 +[[rust-analyzer.lens.implementations.enable]]rust-analyzer.lens.implementations.enable (default: `true`)::
 ++
 +--
 +Whether to show `Implementations` lens. Only applies when
 +`#rust-analyzer.lens.enable#` is set.
 +--
 +[[rust-analyzer.lens.location]]rust-analyzer.lens.location (default: `"above_name"`)::
 ++
 +--
 +Where to render annotations.
 +--
 +[[rust-analyzer.lens.references.adt.enable]]rust-analyzer.lens.references.adt.enable (default: `false`)::
 ++
 +--
 +Whether to show `References` lens for Struct, Enum, and Union.
 +Only applies when `#rust-analyzer.lens.enable#` is set.
 +--
 +[[rust-analyzer.lens.references.enumVariant.enable]]rust-analyzer.lens.references.enumVariant.enable (default: `false`)::
 ++
 +--
 +Whether to show `References` lens for Enum Variants.
 +Only applies when `#rust-analyzer.lens.enable#` is set.
 +--
 +[[rust-analyzer.lens.references.method.enable]]rust-analyzer.lens.references.method.enable (default: `false`)::
 ++
 +--
 +Whether to show `Method References` lens. Only applies when
 +`#rust-analyzer.lens.enable#` is set.
 +--
 +[[rust-analyzer.lens.references.trait.enable]]rust-analyzer.lens.references.trait.enable (default: `false`)::
 ++
 +--
 +Whether to show `References` lens for Trait.
 +Only applies when `#rust-analyzer.lens.enable#` is set.
 +--
 +[[rust-analyzer.lens.run.enable]]rust-analyzer.lens.run.enable (default: `true`)::
 ++
 +--
 +Whether to show `Run` lens. Only applies when
 +`#rust-analyzer.lens.enable#` is set.
 +--
 +[[rust-analyzer.linkedProjects]]rust-analyzer.linkedProjects (default: `[]`)::
 ++
 +--
 +Disable project auto-discovery in favor of explicitly specified set
 +of projects.
 +
 +Elements must be paths pointing to `Cargo.toml`,
 +`rust-project.json`, or JSON objects in `rust-project.json` format.
 +--
 +[[rust-analyzer.lru.capacity]]rust-analyzer.lru.capacity (default: `null`)::
 ++
 +--
 +Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.
 +--
 +[[rust-analyzer.notifications.cargoTomlNotFound]]rust-analyzer.notifications.cargoTomlNotFound (default: `true`)::
 ++
 +--
 +Whether to show `can't find Cargo.toml` error message.
 +--
 +[[rust-analyzer.procMacro.attributes.enable]]rust-analyzer.procMacro.attributes.enable (default: `true`)::
 ++
 +--
 +Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.
 +--
 +[[rust-analyzer.procMacro.enable]]rust-analyzer.procMacro.enable (default: `true`)::
 ++
 +--
 +Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.
 +--
 +[[rust-analyzer.procMacro.ignored]]rust-analyzer.procMacro.ignored (default: `{}`)::
 ++
 +--
 +These proc-macros will be ignored when trying to expand them.
 +
 +This config takes a map of crate names with the exported proc-macro names to ignore as values.
 +--
 +[[rust-analyzer.procMacro.server]]rust-analyzer.procMacro.server (default: `null`)::
 ++
 +--
 +Internal config, path to proc-macro server executable (typically,
 +this is rust-analyzer itself, but we override this in tests).
 +--
 +[[rust-analyzer.references.excludeImports]]rust-analyzer.references.excludeImports (default: `false`)::
 ++
 +--
 +Exclude imports from find-all-references.
 +--
 +[[rust-analyzer.runnables.command]]rust-analyzer.runnables.command (default: `null`)::
 ++
 +--
 +Command to be executed instead of 'cargo' for runnables.
 +--
 +[[rust-analyzer.runnables.extraArgs]]rust-analyzer.runnables.extraArgs (default: `[]`)::
 ++
 +--
 +Additional arguments to be passed to cargo for runnables such as
 +tests or binaries. For example, it may be `--release`.
 +--
 +[[rust-analyzer.rustc.source]]rust-analyzer.rustc.source (default: `null`)::
 ++
 +--
 +Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private
 +projects, or "discover" to try to automatically find it if the `rustc-dev` component
 +is installed.
 +
 +Any project which uses rust-analyzer with the rustcPrivate
 +crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.
 +
 +This option does not take effect until rust-analyzer is restarted.
 +--
 +[[rust-analyzer.rustfmt.extraArgs]]rust-analyzer.rustfmt.extraArgs (default: `[]`)::
 ++
 +--
 +Additional arguments to `rustfmt`.
 +--
 +[[rust-analyzer.rustfmt.overrideCommand]]rust-analyzer.rustfmt.overrideCommand (default: `null`)::
 ++
 +--
 +Advanced option, fully override the command rust-analyzer uses for
 +formatting.
 +--
 +[[rust-analyzer.rustfmt.rangeFormatting.enable]]rust-analyzer.rustfmt.rangeFormatting.enable (default: `false`)::
 ++
 +--
 +Enables the use of rustfmt's unstable range formatting command for the
 +`textDocument/rangeFormatting` request. The rustfmt option is unstable and only
 +available on a nightly build.
 +--
 +[[rust-analyzer.semanticHighlighting.doc.comment.inject.enable]]rust-analyzer.semanticHighlighting.doc.comment.inject.enable (default: `true`)::
 ++
 +--
 +Inject additional highlighting into doc comments.
 +
 +When enabled, rust-analyzer will highlight rust source in doc comments as well as intra
 +doc links.
 +--
 +[[rust-analyzer.semanticHighlighting.operator.enable]]rust-analyzer.semanticHighlighting.operator.enable (default: `true`)::
 ++
 +--
 +Use semantic tokens for operators.
 +
 +When disabled, rust-analyzer will emit semantic tokens only for operator tokens when
 +they are tagged with modifiers.
 +--
 +[[rust-analyzer.semanticHighlighting.operator.specialization.enable]]rust-analyzer.semanticHighlighting.operator.specialization.enable (default: `false`)::
 ++
 +--
 +Use specialized semantic tokens for operators.
 +
 +When enabled, rust-analyzer will emit special token types for operator tokens instead
 +of the generic `operator` token type.
 +--
 +[[rust-analyzer.semanticHighlighting.punctuation.enable]]rust-analyzer.semanticHighlighting.punctuation.enable (default: `false`)::
 ++
 +--
 +Use semantic tokens for punctuations.
 +
 +When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when
 +they are tagged with modifiers or have a special role.
 +--
 +[[rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang]]rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang (default: `false`)::
 ++
 +--
 +When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro
 +calls.
 +--
 +[[rust-analyzer.semanticHighlighting.punctuation.specialization.enable]]rust-analyzer.semanticHighlighting.punctuation.specialization.enable (default: `false`)::
 ++
 +--
 +Use specialized semantic tokens for punctuations.
 +
 +When enabled, rust-analyzer will emit special token types for punctuation tokens instead
 +of the generic `punctuation` token type.
 +--
 +[[rust-analyzer.semanticHighlighting.strings.enable]]rust-analyzer.semanticHighlighting.strings.enable (default: `true`)::
 ++
 +--
 +Use semantic tokens for strings.
 +
 +In some editors (e.g. vscode) semantic tokens override other highlighting grammars.
 +By disabling semantic tokens for strings, other grammars can be used to highlight
 +their contents.
 +--
 +[[rust-analyzer.signatureInfo.detail]]rust-analyzer.signatureInfo.detail (default: `"full"`)::
 ++
 +--
 +Show full signature of the callable. Only shows parameters if disabled.
 +--
 +[[rust-analyzer.signatureInfo.documentation.enable]]rust-analyzer.signatureInfo.documentation.enable (default: `true`)::
 ++
 +--
 +Show documentation.
 +--
 +[[rust-analyzer.typing.autoClosingAngleBrackets.enable]]rust-analyzer.typing.autoClosingAngleBrackets.enable (default: `false`)::
 ++
 +--
 +Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.
 +--
 +[[rust-analyzer.workspace.symbol.search.kind]]rust-analyzer.workspace.symbol.search.kind (default: `"only_types"`)::
 ++
 +--
 +Workspace symbol search kind.
 +--
 +[[rust-analyzer.workspace.symbol.search.limit]]rust-analyzer.workspace.symbol.search.limit (default: `128`)::
 ++
 +--
 +Limits the number of items returned from a workspace symbol search (Defaults to 128).
 +Some clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.
 +Other clients requires all results upfront and might require a higher limit.
 +--
 +[[rust-analyzer.workspace.symbol.search.scope]]rust-analyzer.workspace.symbol.search.scope (default: `"workspace"`)::
 ++
 +--
 +Workspace symbol search scope.
 +--
index 3ff4b6897a16b5f73a3fb47ae0b4dde77440abc2,0000000000000000000000000000000000000000..a72865d4fe44e1672847cd66548375621bc7db47
mode 100644,000000..100644
--- /dev/null
@@@ -1,6761 -1,0 +1,6761 @@@
-                 "vscode-languageclient": "^8.0.0-next.14"
 +{
 +    "name": "rust-analyzer",
 +    "version": "0.5.0-dev",
 +    "lockfileVersion": 2,
 +    "requires": true,
 +    "packages": {
 +        "": {
 +            "name": "rust-analyzer",
 +            "version": "0.5.0-dev",
 +            "license": "MIT OR Apache-2.0",
 +            "dependencies": {
 +                "d3": "^7.6.1",
 +                "d3-graphviz": "^4.1.1",
-             "version": "8.0.0-next.7",
-             "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.0-next.7.tgz",
-             "integrity": "sha512-JX/F31LEsims0dAlOTKFE4E+AJMiJvdRSRViifFJSqSN7EzeYyWlfuDchF7g91oRNPZOIWfibTkDf3/UMsQGzQ==",
++                "vscode-languageclient": "^8.0.2"
 +            },
 +            "devDependencies": {
 +                "@types/node": "~16.11.7",
 +                "@types/vscode": "~1.66.0",
 +                "@typescript-eslint/eslint-plugin": "^5.30.5",
 +                "@typescript-eslint/parser": "^5.30.5",
 +                "@vscode/test-electron": "^2.1.5",
 +                "cross-env": "^7.0.3",
 +                "esbuild": "^0.14.48",
 +                "eslint": "^8.19.0",
 +                "eslint-config-prettier": "^8.5.0",
 +                "ovsx": "^0.5.1",
 +                "prettier": "^2.7.1",
 +                "tslib": "^2.4.0",
 +                "typescript": "^4.7.4",
 +                "vsce": "^2.9.2"
 +            },
 +            "engines": {
 +                "vscode": "^1.66.0"
 +            }
 +        },
 +        "node_modules/@eslint/eslintrc": {
 +            "version": "1.3.0",
 +            "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
 +            "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==",
 +            "dev": true,
 +            "dependencies": {
 +                "ajv": "^6.12.4",
 +                "debug": "^4.3.2",
 +                "espree": "^9.3.2",
 +                "globals": "^13.15.0",
 +                "ignore": "^5.2.0",
 +                "import-fresh": "^3.2.1",
 +                "js-yaml": "^4.1.0",
 +                "minimatch": "^3.1.2",
 +                "strip-json-comments": "^3.1.1"
 +            },
 +            "engines": {
 +                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 +            }
 +        },
 +        "node_modules/@hpcc-js/wasm": {
 +            "version": "1.12.8",
 +            "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-1.12.8.tgz",
 +            "integrity": "sha512-n4q9ARKco2hpCLsuVaW6Az3cDVaua7B3DSONHkc49WtEzgY/btvcDG5Zr1P6PZDv0sQ7oPnAi9Y+W2DI++MgcQ==",
 +            "dependencies": {
 +                "yargs": "^17.3.1"
 +            },
 +            "bin": {
 +                "dot-wasm": "bin/cli.js"
 +            }
 +        },
 +        "node_modules/@humanwhocodes/config-array": {
 +            "version": "0.9.5",
 +            "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz",
 +            "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==",
 +            "dev": true,
 +            "dependencies": {
 +                "@humanwhocodes/object-schema": "^1.2.1",
 +                "debug": "^4.1.1",
 +                "minimatch": "^3.0.4"
 +            },
 +            "engines": {
 +                "node": ">=10.10.0"
 +            }
 +        },
 +        "node_modules/@humanwhocodes/object-schema": {
 +            "version": "1.2.1",
 +            "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
 +            "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
 +            "dev": true
 +        },
 +        "node_modules/@nodelib/fs.scandir": {
 +            "version": "2.1.5",
 +            "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
 +            "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
 +            "dev": true,
 +            "dependencies": {
 +                "@nodelib/fs.stat": "2.0.5",
 +                "run-parallel": "^1.1.9"
 +            },
 +            "engines": {
 +                "node": ">= 8"
 +            }
 +        },
 +        "node_modules/@nodelib/fs.stat": {
 +            "version": "2.0.5",
 +            "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
 +            "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">= 8"
 +            }
 +        },
 +        "node_modules/@nodelib/fs.walk": {
 +            "version": "1.2.8",
 +            "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
 +            "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
 +            "dev": true,
 +            "dependencies": {
 +                "@nodelib/fs.scandir": "2.1.5",
 +                "fastq": "^1.6.0"
 +            },
 +            "engines": {
 +                "node": ">= 8"
 +            }
 +        },
 +        "node_modules/@tootallnate/once": {
 +            "version": "1.1.2",
 +            "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
 +            "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">= 6"
 +            }
 +        },
 +        "node_modules/@types/json-schema": {
 +            "version": "7.0.11",
 +            "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
 +            "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
 +            "dev": true
 +        },
 +        "node_modules/@types/node": {
 +            "version": "16.11.43",
 +            "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.43.tgz",
 +            "integrity": "sha512-GqWykok+3uocgfAJM8imbozrqLnPyTrpFlrryURQlw1EesPUCx5XxTiucWDSFF9/NUEXDuD4bnvHm8xfVGWTpQ==",
 +            "dev": true
 +        },
 +        "node_modules/@types/vscode": {
 +            "version": "1.66.0",
 +            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.66.0.tgz",
 +            "integrity": "sha512-ZfJck4M7nrGasfs4A4YbUoxis3Vu24cETw3DERsNYtDZmYSYtk6ljKexKFKhImO/ZmY6ZMsmegu2FPkXoUFImA==",
 +            "dev": true
 +        },
 +        "node_modules/@typescript-eslint/eslint-plugin": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz",
 +            "integrity": "sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig==",
 +            "dev": true,
 +            "dependencies": {
 +                "@typescript-eslint/scope-manager": "5.30.5",
 +                "@typescript-eslint/type-utils": "5.30.5",
 +                "@typescript-eslint/utils": "5.30.5",
 +                "debug": "^4.3.4",
 +                "functional-red-black-tree": "^1.0.1",
 +                "ignore": "^5.2.0",
 +                "regexpp": "^3.2.0",
 +                "semver": "^7.3.7",
 +                "tsutils": "^3.21.0"
 +            },
 +            "engines": {
 +                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 +            },
 +            "funding": {
 +                "type": "opencollective",
 +                "url": "https://opencollective.com/typescript-eslint"
 +            },
 +            "peerDependencies": {
 +                "@typescript-eslint/parser": "^5.0.0",
 +                "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
 +            },
 +            "peerDependenciesMeta": {
 +                "typescript": {
 +                    "optional": true
 +                }
 +            }
 +        },
 +        "node_modules/@typescript-eslint/parser": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.5.tgz",
 +            "integrity": "sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q==",
 +            "dev": true,
 +            "dependencies": {
 +                "@typescript-eslint/scope-manager": "5.30.5",
 +                "@typescript-eslint/types": "5.30.5",
 +                "@typescript-eslint/typescript-estree": "5.30.5",
 +                "debug": "^4.3.4"
 +            },
 +            "engines": {
 +                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 +            },
 +            "funding": {
 +                "type": "opencollective",
 +                "url": "https://opencollective.com/typescript-eslint"
 +            },
 +            "peerDependencies": {
 +                "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
 +            },
 +            "peerDependenciesMeta": {
 +                "typescript": {
 +                    "optional": true
 +                }
 +            }
 +        },
 +        "node_modules/@typescript-eslint/scope-manager": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz",
 +            "integrity": "sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg==",
 +            "dev": true,
 +            "dependencies": {
 +                "@typescript-eslint/types": "5.30.5",
 +                "@typescript-eslint/visitor-keys": "5.30.5"
 +            },
 +            "engines": {
 +                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 +            },
 +            "funding": {
 +                "type": "opencollective",
 +                "url": "https://opencollective.com/typescript-eslint"
 +            }
 +        },
 +        "node_modules/@typescript-eslint/type-utils": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz",
 +            "integrity": "sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw==",
 +            "dev": true,
 +            "dependencies": {
 +                "@typescript-eslint/utils": "5.30.5",
 +                "debug": "^4.3.4",
 +                "tsutils": "^3.21.0"
 +            },
 +            "engines": {
 +                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 +            },
 +            "funding": {
 +                "type": "opencollective",
 +                "url": "https://opencollective.com/typescript-eslint"
 +            },
 +            "peerDependencies": {
 +                "eslint": "*"
 +            },
 +            "peerDependenciesMeta": {
 +                "typescript": {
 +                    "optional": true
 +                }
 +            }
 +        },
 +        "node_modules/@typescript-eslint/types": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz",
 +            "integrity": "sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw==",
 +            "dev": true,
 +            "engines": {
 +                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 +            },
 +            "funding": {
 +                "type": "opencollective",
 +                "url": "https://opencollective.com/typescript-eslint"
 +            }
 +        },
 +        "node_modules/@typescript-eslint/typescript-estree": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz",
 +            "integrity": "sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ==",
 +            "dev": true,
 +            "dependencies": {
 +                "@typescript-eslint/types": "5.30.5",
 +                "@typescript-eslint/visitor-keys": "5.30.5",
 +                "debug": "^4.3.4",
 +                "globby": "^11.1.0",
 +                "is-glob": "^4.0.3",
 +                "semver": "^7.3.7",
 +                "tsutils": "^3.21.0"
 +            },
 +            "engines": {
 +                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 +            },
 +            "funding": {
 +                "type": "opencollective",
 +                "url": "https://opencollective.com/typescript-eslint"
 +            },
 +            "peerDependenciesMeta": {
 +                "typescript": {
 +                    "optional": true
 +                }
 +            }
 +        },
 +        "node_modules/@typescript-eslint/utils": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.5.tgz",
 +            "integrity": "sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA==",
 +            "dev": true,
 +            "dependencies": {
 +                "@types/json-schema": "^7.0.9",
 +                "@typescript-eslint/scope-manager": "5.30.5",
 +                "@typescript-eslint/types": "5.30.5",
 +                "@typescript-eslint/typescript-estree": "5.30.5",
 +                "eslint-scope": "^5.1.1",
 +                "eslint-utils": "^3.0.0"
 +            },
 +            "engines": {
 +                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 +            },
 +            "funding": {
 +                "type": "opencollective",
 +                "url": "https://opencollective.com/typescript-eslint"
 +            },
 +            "peerDependencies": {
 +                "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
 +            }
 +        },
 +        "node_modules/@typescript-eslint/visitor-keys": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz",
 +            "integrity": "sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA==",
 +            "dev": true,
 +            "dependencies": {
 +                "@typescript-eslint/types": "5.30.5",
 +                "eslint-visitor-keys": "^3.3.0"
 +            },
 +            "engines": {
 +                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 +            },
 +            "funding": {
 +                "type": "opencollective",
 +                "url": "https://opencollective.com/typescript-eslint"
 +            }
 +        },
 +        "node_modules/@vscode/test-electron": {
 +            "version": "2.1.5",
 +            "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.1.5.tgz",
 +            "integrity": "sha512-O/ioqFpV+RvKbRykX2ItYPnbcZ4Hk5V0rY4uhQjQTLhGL9WZUvS7exzuYQCCI+ilSqJpctvxq2llTfGXf9UnnA==",
 +            "dev": true,
 +            "dependencies": {
 +                "http-proxy-agent": "^4.0.1",
 +                "https-proxy-agent": "^5.0.0",
 +                "rimraf": "^3.0.2",
 +                "unzipper": "^0.10.11"
 +            },
 +            "engines": {
 +                "node": ">=8.9.3"
 +            }
 +        },
 +        "node_modules/acorn": {
 +            "version": "8.7.1",
 +            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
 +            "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==",
 +            "dev": true,
 +            "bin": {
 +                "acorn": "bin/acorn"
 +            },
 +            "engines": {
 +                "node": ">=0.4.0"
 +            }
 +        },
 +        "node_modules/acorn-jsx": {
 +            "version": "5.3.2",
 +            "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
 +            "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
 +            "dev": true,
 +            "peerDependencies": {
 +                "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
 +            }
 +        },
 +        "node_modules/agent-base": {
 +            "version": "6.0.2",
 +            "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
 +            "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
 +            "dev": true,
 +            "dependencies": {
 +                "debug": "4"
 +            },
 +            "engines": {
 +                "node": ">= 6.0.0"
 +            }
 +        },
 +        "node_modules/ajv": {
 +            "version": "6.12.6",
 +            "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
 +            "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
 +            "dev": true,
 +            "dependencies": {
 +                "fast-deep-equal": "^3.1.1",
 +                "fast-json-stable-stringify": "^2.0.0",
 +                "json-schema-traverse": "^0.4.1",
 +                "uri-js": "^4.2.2"
 +            },
 +            "funding": {
 +                "type": "github",
 +                "url": "https://github.com/sponsors/epoberezkin"
 +            }
 +        },
 +        "node_modules/ansi-regex": {
 +            "version": "5.0.1",
 +            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
 +            "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/ansi-styles": {
 +            "version": "4.3.0",
 +            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
 +            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
 +            "dependencies": {
 +                "color-convert": "^2.0.1"
 +            },
 +            "engines": {
 +                "node": ">=8"
 +            },
 +            "funding": {
 +                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
 +            }
 +        },
 +        "node_modules/argparse": {
 +            "version": "2.0.1",
 +            "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
 +            "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
 +            "dev": true
 +        },
 +        "node_modules/array-union": {
 +            "version": "2.1.0",
 +            "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
 +            "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/azure-devops-node-api": {
 +            "version": "11.2.0",
 +            "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz",
 +            "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==",
 +            "dev": true,
 +            "dependencies": {
 +                "tunnel": "0.0.6",
 +                "typed-rest-client": "^1.8.4"
 +            }
 +        },
 +        "node_modules/balanced-match": {
 +            "version": "1.0.2",
 +            "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
 +            "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
 +        },
 +        "node_modules/base64-js": {
 +            "version": "1.5.1",
 +            "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
 +            "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
 +            "dev": true,
 +            "funding": [
 +                {
 +                    "type": "github",
 +                    "url": "https://github.com/sponsors/feross"
 +                },
 +                {
 +                    "type": "patreon",
 +                    "url": "https://www.patreon.com/feross"
 +                },
 +                {
 +                    "type": "consulting",
 +                    "url": "https://feross.org/support"
 +                }
 +            ]
 +        },
 +        "node_modules/big-integer": {
 +            "version": "1.6.51",
 +            "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
 +            "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=0.6"
 +            }
 +        },
 +        "node_modules/binary": {
 +            "version": "0.3.0",
 +            "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz",
 +            "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==",
 +            "dev": true,
 +            "dependencies": {
 +                "buffers": "~0.1.1",
 +                "chainsaw": "~0.1.0"
 +            },
 +            "engines": {
 +                "node": "*"
 +            }
 +        },
 +        "node_modules/bl": {
 +            "version": "4.1.0",
 +            "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
 +            "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
 +            "dev": true,
 +            "dependencies": {
 +                "buffer": "^5.5.0",
 +                "inherits": "^2.0.4",
 +                "readable-stream": "^3.4.0"
 +            }
 +        },
 +        "node_modules/bl/node_modules/readable-stream": {
 +            "version": "3.6.0",
 +            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
 +            "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
 +            "dev": true,
 +            "dependencies": {
 +                "inherits": "^2.0.3",
 +                "string_decoder": "^1.1.1",
 +                "util-deprecate": "^1.0.1"
 +            },
 +            "engines": {
 +                "node": ">= 6"
 +            }
 +        },
 +        "node_modules/bluebird": {
 +            "version": "3.4.7",
 +            "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
 +            "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==",
 +            "dev": true
 +        },
 +        "node_modules/boolbase": {
 +            "version": "1.0.0",
 +            "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
 +            "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
 +            "dev": true
 +        },
 +        "node_modules/brace-expansion": {
 +            "version": "1.1.11",
 +            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
 +            "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
 +            "dependencies": {
 +                "balanced-match": "^1.0.0",
 +                "concat-map": "0.0.1"
 +            }
 +        },
 +        "node_modules/braces": {
 +            "version": "3.0.2",
 +            "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
 +            "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
 +            "dev": true,
 +            "dependencies": {
 +                "fill-range": "^7.0.1"
 +            },
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/buffer": {
 +            "version": "5.7.1",
 +            "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
 +            "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
 +            "dev": true,
 +            "funding": [
 +                {
 +                    "type": "github",
 +                    "url": "https://github.com/sponsors/feross"
 +                },
 +                {
 +                    "type": "patreon",
 +                    "url": "https://www.patreon.com/feross"
 +                },
 +                {
 +                    "type": "consulting",
 +                    "url": "https://feross.org/support"
 +                }
 +            ],
 +            "dependencies": {
 +                "base64-js": "^1.3.1",
 +                "ieee754": "^1.1.13"
 +            }
 +        },
 +        "node_modules/buffer-crc32": {
 +            "version": "0.2.13",
 +            "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
 +            "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
 +            "dev": true,
 +            "engines": {
 +                "node": "*"
 +            }
 +        },
 +        "node_modules/buffer-indexof-polyfill": {
 +            "version": "1.0.2",
 +            "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz",
 +            "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=0.10"
 +            }
 +        },
 +        "node_modules/buffers": {
 +            "version": "0.1.1",
 +            "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
 +            "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=0.2.0"
 +            }
 +        },
 +        "node_modules/call-bind": {
 +            "version": "1.0.2",
 +            "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
 +            "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
 +            "dev": true,
 +            "dependencies": {
 +                "function-bind": "^1.1.1",
 +                "get-intrinsic": "^1.0.2"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/ljharb"
 +            }
 +        },
 +        "node_modules/callsites": {
 +            "version": "3.1.0",
 +            "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
 +            "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=6"
 +            }
 +        },
 +        "node_modules/chainsaw": {
 +            "version": "0.1.0",
 +            "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
 +            "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==",
 +            "dev": true,
 +            "dependencies": {
 +                "traverse": ">=0.3.0 <0.4"
 +            },
 +            "engines": {
 +                "node": "*"
 +            }
 +        },
 +        "node_modules/chalk": {
 +            "version": "4.1.2",
 +            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
 +            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
 +            "dev": true,
 +            "dependencies": {
 +                "ansi-styles": "^4.1.0",
 +                "supports-color": "^7.1.0"
 +            },
 +            "engines": {
 +                "node": ">=10"
 +            },
 +            "funding": {
 +                "url": "https://github.com/chalk/chalk?sponsor=1"
 +            }
 +        },
 +        "node_modules/cheerio": {
 +            "version": "1.0.0-rc.12",
 +            "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
 +            "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
 +            "dev": true,
 +            "dependencies": {
 +                "cheerio-select": "^2.1.0",
 +                "dom-serializer": "^2.0.0",
 +                "domhandler": "^5.0.3",
 +                "domutils": "^3.0.1",
 +                "htmlparser2": "^8.0.1",
 +                "parse5": "^7.0.0",
 +                "parse5-htmlparser2-tree-adapter": "^7.0.0"
 +            },
 +            "engines": {
 +                "node": ">= 6"
 +            },
 +            "funding": {
 +                "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
 +            }
 +        },
 +        "node_modules/cheerio-select": {
 +            "version": "2.1.0",
 +            "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
 +            "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
 +            "dev": true,
 +            "dependencies": {
 +                "boolbase": "^1.0.0",
 +                "css-select": "^5.1.0",
 +                "css-what": "^6.1.0",
 +                "domelementtype": "^2.3.0",
 +                "domhandler": "^5.0.3",
 +                "domutils": "^3.0.1"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/fb55"
 +            }
 +        },
 +        "node_modules/chownr": {
 +            "version": "1.1.4",
 +            "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
 +            "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
 +            "dev": true
 +        },
 +        "node_modules/ci-info": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
 +            "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
 +            "dev": true
 +        },
 +        "node_modules/cliui": {
 +            "version": "7.0.4",
 +            "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
 +            "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
 +            "dependencies": {
 +                "string-width": "^4.2.0",
 +                "strip-ansi": "^6.0.0",
 +                "wrap-ansi": "^7.0.0"
 +            }
 +        },
 +        "node_modules/color-convert": {
 +            "version": "2.0.1",
 +            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
 +            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
 +            "dependencies": {
 +                "color-name": "~1.1.4"
 +            },
 +            "engines": {
 +                "node": ">=7.0.0"
 +            }
 +        },
 +        "node_modules/color-name": {
 +            "version": "1.1.4",
 +            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
 +            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
 +        },
 +        "node_modules/commander": {
 +            "version": "7.2.0",
 +            "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
 +            "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
 +            "engines": {
 +                "node": ">= 10"
 +            }
 +        },
 +        "node_modules/concat-map": {
 +            "version": "0.0.1",
 +            "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
 +            "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
 +        },
 +        "node_modules/core-util-is": {
 +            "version": "1.0.3",
 +            "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
 +            "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
 +            "dev": true
 +        },
 +        "node_modules/cross-env": {
 +            "version": "7.0.3",
 +            "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
 +            "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
 +            "dev": true,
 +            "dependencies": {
 +                "cross-spawn": "^7.0.1"
 +            },
 +            "bin": {
 +                "cross-env": "src/bin/cross-env.js",
 +                "cross-env-shell": "src/bin/cross-env-shell.js"
 +            },
 +            "engines": {
 +                "node": ">=10.14",
 +                "npm": ">=6",
 +                "yarn": ">=1"
 +            }
 +        },
 +        "node_modules/cross-spawn": {
 +            "version": "7.0.3",
 +            "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
 +            "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
 +            "dev": true,
 +            "dependencies": {
 +                "path-key": "^3.1.0",
 +                "shebang-command": "^2.0.0",
 +                "which": "^2.0.1"
 +            },
 +            "engines": {
 +                "node": ">= 8"
 +            }
 +        },
 +        "node_modules/css-select": {
 +            "version": "5.1.0",
 +            "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
 +            "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
 +            "dev": true,
 +            "dependencies": {
 +                "boolbase": "^1.0.0",
 +                "css-what": "^6.1.0",
 +                "domhandler": "^5.0.2",
 +                "domutils": "^3.0.1",
 +                "nth-check": "^2.0.1"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/fb55"
 +            }
 +        },
 +        "node_modules/css-what": {
 +            "version": "6.1.0",
 +            "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
 +            "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">= 6"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/fb55"
 +            }
 +        },
 +        "node_modules/d3": {
 +            "version": "7.6.1",
 +            "resolved": "https://registry.npmjs.org/d3/-/d3-7.6.1.tgz",
 +            "integrity": "sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw==",
 +            "dependencies": {
 +                "d3-array": "3",
 +                "d3-axis": "3",
 +                "d3-brush": "3",
 +                "d3-chord": "3",
 +                "d3-color": "3",
 +                "d3-contour": "4",
 +                "d3-delaunay": "6",
 +                "d3-dispatch": "3",
 +                "d3-drag": "3",
 +                "d3-dsv": "3",
 +                "d3-ease": "3",
 +                "d3-fetch": "3",
 +                "d3-force": "3",
 +                "d3-format": "3",
 +                "d3-geo": "3",
 +                "d3-hierarchy": "3",
 +                "d3-interpolate": "3",
 +                "d3-path": "3",
 +                "d3-polygon": "3",
 +                "d3-quadtree": "3",
 +                "d3-random": "3",
 +                "d3-scale": "4",
 +                "d3-scale-chromatic": "3",
 +                "d3-selection": "3",
 +                "d3-shape": "3",
 +                "d3-time": "3",
 +                "d3-time-format": "4",
 +                "d3-timer": "3",
 +                "d3-transition": "3",
 +                "d3-zoom": "3"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-array": {
 +            "version": "3.2.0",
 +            "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.0.tgz",
 +            "integrity": "sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==",
 +            "dependencies": {
 +                "internmap": "1 - 2"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-axis": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz",
 +            "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-brush": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz",
 +            "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==",
 +            "dependencies": {
 +                "d3-dispatch": "1 - 3",
 +                "d3-drag": "2 - 3",
 +                "d3-interpolate": "1 - 3",
 +                "d3-selection": "3",
 +                "d3-transition": "3"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-brush/node_modules/d3-selection": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
 +            "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-chord": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz",
 +            "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==",
 +            "dependencies": {
 +                "d3-path": "1 - 3"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-color": {
 +            "version": "3.1.0",
 +            "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
 +            "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-contour": {
 +            "version": "4.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.0.tgz",
 +            "integrity": "sha512-7aQo0QHUTu/Ko3cP9YK9yUTxtoDEiDGwnBHyLxG5M4vqlBkO/uixMRele3nfsfj6UXOcuReVpVXzAboGraYIJw==",
 +            "dependencies": {
 +                "d3-array": "^3.2.0"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-delaunay": {
 +            "version": "6.0.2",
 +            "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz",
 +            "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==",
 +            "dependencies": {
 +                "delaunator": "5"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-dispatch": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
 +            "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-drag": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
 +            "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
 +            "dependencies": {
 +                "d3-dispatch": "1 - 3",
 +                "d3-selection": "3"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-drag/node_modules/d3-selection": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
 +            "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-dsv": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz",
 +            "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==",
 +            "dependencies": {
 +                "commander": "7",
 +                "iconv-lite": "0.6",
 +                "rw": "1"
 +            },
 +            "bin": {
 +                "csv2json": "bin/dsv2json.js",
 +                "csv2tsv": "bin/dsv2dsv.js",
 +                "dsv2dsv": "bin/dsv2dsv.js",
 +                "dsv2json": "bin/dsv2json.js",
 +                "json2csv": "bin/json2dsv.js",
 +                "json2dsv": "bin/json2dsv.js",
 +                "json2tsv": "bin/json2dsv.js",
 +                "tsv2csv": "bin/dsv2dsv.js",
 +                "tsv2json": "bin/dsv2json.js"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-ease": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
 +            "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-fetch": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz",
 +            "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==",
 +            "dependencies": {
 +                "d3-dsv": "1 - 3"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-force": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
 +            "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
 +            "dependencies": {
 +                "d3-dispatch": "1 - 3",
 +                "d3-quadtree": "1 - 3",
 +                "d3-timer": "1 - 3"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-format": {
 +            "version": "3.1.0",
 +            "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
 +            "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-geo": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.0.1.tgz",
 +            "integrity": "sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==",
 +            "dependencies": {
 +                "d3-array": "2.5.0 - 3"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-graphviz": {
 +            "version": "4.1.1",
 +            "resolved": "https://registry.npmjs.org/d3-graphviz/-/d3-graphviz-4.1.1.tgz",
 +            "integrity": "sha512-s0IVbKf8rs4eJI2xo5Umr7nXDX/LEZw/x2WtKxmlyQxR0qUY49UiLhBNOX7VDHZywMle43NKEXnU6fn22fpJvQ==",
 +            "dependencies": {
 +                "@hpcc-js/wasm": "1.12.8",
 +                "d3-dispatch": "^2.0.0",
 +                "d3-format": "^2.0.0",
 +                "d3-interpolate": "^2.0.1",
 +                "d3-path": "^2.0.0",
 +                "d3-timer": "^2.0.0",
 +                "d3-transition": "^2.0.0",
 +                "d3-zoom": "^2.0.0"
 +            },
 +            "peerDependencies": {
 +                "d3-selection": "^2.0.0"
 +            }
 +        },
 +        "node_modules/d3-graphviz/node_modules/d3-color": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz",
 +            "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ=="
 +        },
 +        "node_modules/d3-graphviz/node_modules/d3-dispatch": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz",
 +            "integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA=="
 +        },
 +        "node_modules/d3-graphviz/node_modules/d3-drag": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-2.0.0.tgz",
 +            "integrity": "sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==",
 +            "dependencies": {
 +                "d3-dispatch": "1 - 2",
 +                "d3-selection": "2"
 +            }
 +        },
 +        "node_modules/d3-graphviz/node_modules/d3-ease": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz",
 +            "integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ=="
 +        },
 +        "node_modules/d3-graphviz/node_modules/d3-format": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz",
 +            "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA=="
 +        },
 +        "node_modules/d3-graphviz/node_modules/d3-interpolate": {
 +            "version": "2.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz",
 +            "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==",
 +            "dependencies": {
 +                "d3-color": "1 - 2"
 +            }
 +        },
 +        "node_modules/d3-graphviz/node_modules/d3-path": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz",
 +            "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA=="
 +        },
 +        "node_modules/d3-graphviz/node_modules/d3-timer": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz",
 +            "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA=="
 +        },
 +        "node_modules/d3-graphviz/node_modules/d3-transition": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz",
 +            "integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==",
 +            "dependencies": {
 +                "d3-color": "1 - 2",
 +                "d3-dispatch": "1 - 2",
 +                "d3-ease": "1 - 2",
 +                "d3-interpolate": "1 - 2",
 +                "d3-timer": "1 - 2"
 +            },
 +            "peerDependencies": {
 +                "d3-selection": "2"
 +            }
 +        },
 +        "node_modules/d3-graphviz/node_modules/d3-zoom": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz",
 +            "integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==",
 +            "dependencies": {
 +                "d3-dispatch": "1 - 2",
 +                "d3-drag": "2",
 +                "d3-interpolate": "1 - 2",
 +                "d3-selection": "2",
 +                "d3-transition": "2"
 +            }
 +        },
 +        "node_modules/d3-hierarchy": {
 +            "version": "3.1.2",
 +            "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
 +            "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-interpolate": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
 +            "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
 +            "dependencies": {
 +                "d3-color": "1 - 3"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-path": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz",
 +            "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-polygon": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz",
 +            "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-quadtree": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
 +            "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-random": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz",
 +            "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-scale": {
 +            "version": "4.0.2",
 +            "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
 +            "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
 +            "dependencies": {
 +                "d3-array": "2.10.0 - 3",
 +                "d3-format": "1 - 3",
 +                "d3-interpolate": "1.2.0 - 3",
 +                "d3-time": "2.1.1 - 3",
 +                "d3-time-format": "2 - 4"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-scale-chromatic": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz",
 +            "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==",
 +            "dependencies": {
 +                "d3-color": "1 - 3",
 +                "d3-interpolate": "1 - 3"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-selection": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz",
 +            "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA=="
 +        },
 +        "node_modules/d3-shape": {
 +            "version": "3.1.0",
 +            "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.1.0.tgz",
 +            "integrity": "sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==",
 +            "dependencies": {
 +                "d3-path": "1 - 3"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-time": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz",
 +            "integrity": "sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==",
 +            "dependencies": {
 +                "d3-array": "2 - 3"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-time-format": {
 +            "version": "4.1.0",
 +            "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
 +            "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
 +            "dependencies": {
 +                "d3-time": "1 - 3"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-timer": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
 +            "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3-transition": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
 +            "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
 +            "dependencies": {
 +                "d3-color": "1 - 3",
 +                "d3-dispatch": "1 - 3",
 +                "d3-ease": "1 - 3",
 +                "d3-interpolate": "1 - 3",
 +                "d3-timer": "1 - 3"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            },
 +            "peerDependencies": {
 +                "d3-selection": "2 - 3"
 +            }
 +        },
 +        "node_modules/d3-zoom": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
 +            "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
 +            "dependencies": {
 +                "d3-dispatch": "1 - 3",
 +                "d3-drag": "2 - 3",
 +                "d3-interpolate": "1 - 3",
 +                "d3-selection": "2 - 3",
 +                "d3-transition": "2 - 3"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/d3/node_modules/d3-selection": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
 +            "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/debug": {
 +            "version": "4.3.4",
 +            "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
 +            "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
 +            "dev": true,
 +            "dependencies": {
 +                "ms": "2.1.2"
 +            },
 +            "engines": {
 +                "node": ">=6.0"
 +            },
 +            "peerDependenciesMeta": {
 +                "supports-color": {
 +                    "optional": true
 +                }
 +            }
 +        },
 +        "node_modules/decompress-response": {
 +            "version": "6.0.0",
 +            "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
 +            "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
 +            "dev": true,
 +            "dependencies": {
 +                "mimic-response": "^3.1.0"
 +            },
 +            "engines": {
 +                "node": ">=10"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/sindresorhus"
 +            }
 +        },
 +        "node_modules/deep-extend": {
 +            "version": "0.6.0",
 +            "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
 +            "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=4.0.0"
 +            }
 +        },
 +        "node_modules/deep-is": {
 +            "version": "0.1.4",
 +            "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
 +            "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
 +            "dev": true
 +        },
 +        "node_modules/delaunator": {
 +            "version": "5.0.0",
 +            "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz",
 +            "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==",
 +            "dependencies": {
 +                "robust-predicates": "^3.0.0"
 +            }
 +        },
 +        "node_modules/detect-libc": {
 +            "version": "2.0.1",
 +            "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
 +            "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/dir-glob": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
 +            "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
 +            "dev": true,
 +            "dependencies": {
 +                "path-type": "^4.0.0"
 +            },
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/doctrine": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
 +            "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
 +            "dev": true,
 +            "dependencies": {
 +                "esutils": "^2.0.2"
 +            },
 +            "engines": {
 +                "node": ">=6.0.0"
 +            }
 +        },
 +        "node_modules/dom-serializer": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
 +            "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
 +            "dev": true,
 +            "dependencies": {
 +                "domelementtype": "^2.3.0",
 +                "domhandler": "^5.0.2",
 +                "entities": "^4.2.0"
 +            },
 +            "funding": {
 +                "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
 +            }
 +        },
 +        "node_modules/domelementtype": {
 +            "version": "2.3.0",
 +            "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
 +            "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
 +            "dev": true,
 +            "funding": [
 +                {
 +                    "type": "github",
 +                    "url": "https://github.com/sponsors/fb55"
 +                }
 +            ]
 +        },
 +        "node_modules/domhandler": {
 +            "version": "5.0.3",
 +            "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
 +            "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
 +            "dev": true,
 +            "dependencies": {
 +                "domelementtype": "^2.3.0"
 +            },
 +            "engines": {
 +                "node": ">= 4"
 +            },
 +            "funding": {
 +                "url": "https://github.com/fb55/domhandler?sponsor=1"
 +            }
 +        },
 +        "node_modules/domutils": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
 +            "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
 +            "dev": true,
 +            "dependencies": {
 +                "dom-serializer": "^2.0.0",
 +                "domelementtype": "^2.3.0",
 +                "domhandler": "^5.0.1"
 +            },
 +            "funding": {
 +                "url": "https://github.com/fb55/domutils?sponsor=1"
 +            }
 +        },
 +        "node_modules/duplexer2": {
 +            "version": "0.1.4",
 +            "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
 +            "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==",
 +            "dev": true,
 +            "dependencies": {
 +                "readable-stream": "^2.0.2"
 +            }
 +        },
 +        "node_modules/emoji-regex": {
 +            "version": "8.0.0",
 +            "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
 +            "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
 +        },
 +        "node_modules/end-of-stream": {
 +            "version": "1.4.4",
 +            "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
 +            "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
 +            "dev": true,
 +            "dependencies": {
 +                "once": "^1.4.0"
 +            }
 +        },
 +        "node_modules/entities": {
 +            "version": "4.3.1",
 +            "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz",
 +            "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=0.12"
 +            },
 +            "funding": {
 +                "url": "https://github.com/fb55/entities?sponsor=1"
 +            }
 +        },
 +        "node_modules/esbuild": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz",
 +            "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==",
 +            "dev": true,
 +            "hasInstallScript": true,
 +            "bin": {
 +                "esbuild": "bin/esbuild"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            },
 +            "optionalDependencies": {
 +                "esbuild-android-64": "0.14.48",
 +                "esbuild-android-arm64": "0.14.48",
 +                "esbuild-darwin-64": "0.14.48",
 +                "esbuild-darwin-arm64": "0.14.48",
 +                "esbuild-freebsd-64": "0.14.48",
 +                "esbuild-freebsd-arm64": "0.14.48",
 +                "esbuild-linux-32": "0.14.48",
 +                "esbuild-linux-64": "0.14.48",
 +                "esbuild-linux-arm": "0.14.48",
 +                "esbuild-linux-arm64": "0.14.48",
 +                "esbuild-linux-mips64le": "0.14.48",
 +                "esbuild-linux-ppc64le": "0.14.48",
 +                "esbuild-linux-riscv64": "0.14.48",
 +                "esbuild-linux-s390x": "0.14.48",
 +                "esbuild-netbsd-64": "0.14.48",
 +                "esbuild-openbsd-64": "0.14.48",
 +                "esbuild-sunos-64": "0.14.48",
 +                "esbuild-windows-32": "0.14.48",
 +                "esbuild-windows-64": "0.14.48",
 +                "esbuild-windows-arm64": "0.14.48"
 +            }
 +        },
 +        "node_modules/esbuild-android-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz",
 +            "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==",
 +            "cpu": [
 +                "x64"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "android"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-android-arm64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz",
 +            "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==",
 +            "cpu": [
 +                "arm64"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "android"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-darwin-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz",
 +            "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==",
 +            "cpu": [
 +                "x64"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "darwin"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-darwin-arm64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz",
 +            "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==",
 +            "cpu": [
 +                "arm64"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "darwin"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-freebsd-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz",
 +            "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==",
 +            "cpu": [
 +                "x64"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "freebsd"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-freebsd-arm64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz",
 +            "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==",
 +            "cpu": [
 +                "arm64"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "freebsd"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-linux-32": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz",
 +            "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==",
 +            "cpu": [
 +                "ia32"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "linux"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-linux-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz",
 +            "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==",
 +            "cpu": [
 +                "x64"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "linux"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-linux-arm": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz",
 +            "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==",
 +            "cpu": [
 +                "arm"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "linux"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-linux-arm64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz",
 +            "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==",
 +            "cpu": [
 +                "arm64"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "linux"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-linux-mips64le": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz",
 +            "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==",
 +            "cpu": [
 +                "mips64el"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "linux"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-linux-ppc64le": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz",
 +            "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==",
 +            "cpu": [
 +                "ppc64"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "linux"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-linux-riscv64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz",
 +            "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==",
 +            "cpu": [
 +                "riscv64"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "linux"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-linux-s390x": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz",
 +            "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==",
 +            "cpu": [
 +                "s390x"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "linux"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-netbsd-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz",
 +            "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==",
 +            "cpu": [
 +                "x64"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "netbsd"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-openbsd-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz",
 +            "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==",
 +            "cpu": [
 +                "x64"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "openbsd"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-sunos-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz",
 +            "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==",
 +            "cpu": [
 +                "x64"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "sunos"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-windows-32": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz",
 +            "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==",
 +            "cpu": [
 +                "ia32"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "win32"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-windows-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz",
 +            "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==",
 +            "cpu": [
 +                "x64"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "win32"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/esbuild-windows-arm64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz",
 +            "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==",
 +            "cpu": [
 +                "arm64"
 +            ],
 +            "dev": true,
 +            "optional": true,
 +            "os": [
 +                "win32"
 +            ],
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/escalade": {
 +            "version": "3.1.1",
 +            "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
 +            "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
 +            "engines": {
 +                "node": ">=6"
 +            }
 +        },
 +        "node_modules/escape-string-regexp": {
 +            "version": "4.0.0",
 +            "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
 +            "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=10"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/sindresorhus"
 +            }
 +        },
 +        "node_modules/eslint": {
 +            "version": "8.19.0",
 +            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz",
 +            "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==",
 +            "dev": true,
 +            "dependencies": {
 +                "@eslint/eslintrc": "^1.3.0",
 +                "@humanwhocodes/config-array": "^0.9.2",
 +                "ajv": "^6.10.0",
 +                "chalk": "^4.0.0",
 +                "cross-spawn": "^7.0.2",
 +                "debug": "^4.3.2",
 +                "doctrine": "^3.0.0",
 +                "escape-string-regexp": "^4.0.0",
 +                "eslint-scope": "^7.1.1",
 +                "eslint-utils": "^3.0.0",
 +                "eslint-visitor-keys": "^3.3.0",
 +                "espree": "^9.3.2",
 +                "esquery": "^1.4.0",
 +                "esutils": "^2.0.2",
 +                "fast-deep-equal": "^3.1.3",
 +                "file-entry-cache": "^6.0.1",
 +                "functional-red-black-tree": "^1.0.1",
 +                "glob-parent": "^6.0.1",
 +                "globals": "^13.15.0",
 +                "ignore": "^5.2.0",
 +                "import-fresh": "^3.0.0",
 +                "imurmurhash": "^0.1.4",
 +                "is-glob": "^4.0.0",
 +                "js-yaml": "^4.1.0",
 +                "json-stable-stringify-without-jsonify": "^1.0.1",
 +                "levn": "^0.4.1",
 +                "lodash.merge": "^4.6.2",
 +                "minimatch": "^3.1.2",
 +                "natural-compare": "^1.4.0",
 +                "optionator": "^0.9.1",
 +                "regexpp": "^3.2.0",
 +                "strip-ansi": "^6.0.1",
 +                "strip-json-comments": "^3.1.0",
 +                "text-table": "^0.2.0",
 +                "v8-compile-cache": "^2.0.3"
 +            },
 +            "bin": {
 +                "eslint": "bin/eslint.js"
 +            },
 +            "engines": {
 +                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 +            },
 +            "funding": {
 +                "url": "https://opencollective.com/eslint"
 +            }
 +        },
 +        "node_modules/eslint-config-prettier": {
 +            "version": "8.5.0",
 +            "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
 +            "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
 +            "dev": true,
 +            "bin": {
 +                "eslint-config-prettier": "bin/cli.js"
 +            },
 +            "peerDependencies": {
 +                "eslint": ">=7.0.0"
 +            }
 +        },
 +        "node_modules/eslint-scope": {
 +            "version": "5.1.1",
 +            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
 +            "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
 +            "dev": true,
 +            "dependencies": {
 +                "esrecurse": "^4.3.0",
 +                "estraverse": "^4.1.1"
 +            },
 +            "engines": {
 +                "node": ">=8.0.0"
 +            }
 +        },
 +        "node_modules/eslint-utils": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
 +            "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
 +            "dev": true,
 +            "dependencies": {
 +                "eslint-visitor-keys": "^2.0.0"
 +            },
 +            "engines": {
 +                "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/mysticatea"
 +            },
 +            "peerDependencies": {
 +                "eslint": ">=5"
 +            }
 +        },
 +        "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
 +            "version": "2.1.0",
 +            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
 +            "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=10"
 +            }
 +        },
 +        "node_modules/eslint-visitor-keys": {
 +            "version": "3.3.0",
 +            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
 +            "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
 +            "dev": true,
 +            "engines": {
 +                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 +            }
 +        },
 +        "node_modules/eslint/node_modules/eslint-scope": {
 +            "version": "7.1.1",
 +            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
 +            "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
 +            "dev": true,
 +            "dependencies": {
 +                "esrecurse": "^4.3.0",
 +                "estraverse": "^5.2.0"
 +            },
 +            "engines": {
 +                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 +            }
 +        },
 +        "node_modules/eslint/node_modules/estraverse": {
 +            "version": "5.3.0",
 +            "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
 +            "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=4.0"
 +            }
 +        },
 +        "node_modules/espree": {
 +            "version": "9.3.2",
 +            "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz",
 +            "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==",
 +            "dev": true,
 +            "dependencies": {
 +                "acorn": "^8.7.1",
 +                "acorn-jsx": "^5.3.2",
 +                "eslint-visitor-keys": "^3.3.0"
 +            },
 +            "engines": {
 +                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
 +            }
 +        },
 +        "node_modules/esquery": {
 +            "version": "1.4.0",
 +            "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
 +            "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
 +            "dev": true,
 +            "dependencies": {
 +                "estraverse": "^5.1.0"
 +            },
 +            "engines": {
 +                "node": ">=0.10"
 +            }
 +        },
 +        "node_modules/esquery/node_modules/estraverse": {
 +            "version": "5.3.0",
 +            "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
 +            "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=4.0"
 +            }
 +        },
 +        "node_modules/esrecurse": {
 +            "version": "4.3.0",
 +            "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
 +            "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
 +            "dev": true,
 +            "dependencies": {
 +                "estraverse": "^5.2.0"
 +            },
 +            "engines": {
 +                "node": ">=4.0"
 +            }
 +        },
 +        "node_modules/esrecurse/node_modules/estraverse": {
 +            "version": "5.3.0",
 +            "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
 +            "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=4.0"
 +            }
 +        },
 +        "node_modules/estraverse": {
 +            "version": "4.3.0",
 +            "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
 +            "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=4.0"
 +            }
 +        },
 +        "node_modules/esutils": {
 +            "version": "2.0.3",
 +            "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
 +            "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=0.10.0"
 +            }
 +        },
 +        "node_modules/expand-template": {
 +            "version": "2.0.3",
 +            "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
 +            "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=6"
 +            }
 +        },
 +        "node_modules/fast-deep-equal": {
 +            "version": "3.1.3",
 +            "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
 +            "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
 +            "dev": true
 +        },
 +        "node_modules/fast-glob": {
 +            "version": "3.2.11",
 +            "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
 +            "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==",
 +            "dev": true,
 +            "dependencies": {
 +                "@nodelib/fs.stat": "^2.0.2",
 +                "@nodelib/fs.walk": "^1.2.3",
 +                "glob-parent": "^5.1.2",
 +                "merge2": "^1.3.0",
 +                "micromatch": "^4.0.4"
 +            },
 +            "engines": {
 +                "node": ">=8.6.0"
 +            }
 +        },
 +        "node_modules/fast-glob/node_modules/glob-parent": {
 +            "version": "5.1.2",
 +            "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
 +            "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
 +            "dev": true,
 +            "dependencies": {
 +                "is-glob": "^4.0.1"
 +            },
 +            "engines": {
 +                "node": ">= 6"
 +            }
 +        },
 +        "node_modules/fast-json-stable-stringify": {
 +            "version": "2.1.0",
 +            "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
 +            "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
 +            "dev": true
 +        },
 +        "node_modules/fast-levenshtein": {
 +            "version": "2.0.6",
 +            "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
 +            "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
 +            "dev": true
 +        },
 +        "node_modules/fastq": {
 +            "version": "1.13.0",
 +            "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
 +            "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
 +            "dev": true,
 +            "dependencies": {
 +                "reusify": "^1.0.4"
 +            }
 +        },
 +        "node_modules/fd-slicer": {
 +            "version": "1.1.0",
 +            "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
 +            "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
 +            "dev": true,
 +            "dependencies": {
 +                "pend": "~1.2.0"
 +            }
 +        },
 +        "node_modules/file-entry-cache": {
 +            "version": "6.0.1",
 +            "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
 +            "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
 +            "dev": true,
 +            "dependencies": {
 +                "flat-cache": "^3.0.4"
 +            },
 +            "engines": {
 +                "node": "^10.12.0 || >=12.0.0"
 +            }
 +        },
 +        "node_modules/fill-range": {
 +            "version": "7.0.1",
 +            "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
 +            "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
 +            "dev": true,
 +            "dependencies": {
 +                "to-regex-range": "^5.0.1"
 +            },
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/flat-cache": {
 +            "version": "3.0.4",
 +            "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
 +            "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
 +            "dev": true,
 +            "dependencies": {
 +                "flatted": "^3.1.0",
 +                "rimraf": "^3.0.2"
 +            },
 +            "engines": {
 +                "node": "^10.12.0 || >=12.0.0"
 +            }
 +        },
 +        "node_modules/flatted": {
 +            "version": "3.2.6",
 +            "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz",
 +            "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==",
 +            "dev": true
 +        },
 +        "node_modules/follow-redirects": {
 +            "version": "1.15.1",
 +            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
 +            "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
 +            "dev": true,
 +            "funding": [
 +                {
 +                    "type": "individual",
 +                    "url": "https://github.com/sponsors/RubenVerborgh"
 +                }
 +            ],
 +            "engines": {
 +                "node": ">=4.0"
 +            },
 +            "peerDependenciesMeta": {
 +                "debug": {
 +                    "optional": true
 +                }
 +            }
 +        },
 +        "node_modules/fs-constants": {
 +            "version": "1.0.0",
 +            "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
 +            "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
 +            "dev": true
 +        },
 +        "node_modules/fs.realpath": {
 +            "version": "1.0.0",
 +            "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
 +            "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
 +            "dev": true
 +        },
 +        "node_modules/fstream": {
 +            "version": "1.0.12",
 +            "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
 +            "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
 +            "dev": true,
 +            "dependencies": {
 +                "graceful-fs": "^4.1.2",
 +                "inherits": "~2.0.0",
 +                "mkdirp": ">=0.5 0",
 +                "rimraf": "2"
 +            },
 +            "engines": {
 +                "node": ">=0.6"
 +            }
 +        },
 +        "node_modules/fstream/node_modules/rimraf": {
 +            "version": "2.7.1",
 +            "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
 +            "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
 +            "dev": true,
 +            "dependencies": {
 +                "glob": "^7.1.3"
 +            },
 +            "bin": {
 +                "rimraf": "bin.js"
 +            }
 +        },
 +        "node_modules/function-bind": {
 +            "version": "1.1.1",
 +            "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
 +            "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
 +            "dev": true
 +        },
 +        "node_modules/functional-red-black-tree": {
 +            "version": "1.0.1",
 +            "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
 +            "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
 +            "dev": true
 +        },
 +        "node_modules/get-caller-file": {
 +            "version": "2.0.5",
 +            "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
 +            "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
 +            "engines": {
 +                "node": "6.* || 8.* || >= 10.*"
 +            }
 +        },
 +        "node_modules/get-intrinsic": {
 +            "version": "1.1.2",
 +            "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz",
 +            "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==",
 +            "dev": true,
 +            "dependencies": {
 +                "function-bind": "^1.1.1",
 +                "has": "^1.0.3",
 +                "has-symbols": "^1.0.3"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/ljharb"
 +            }
 +        },
 +        "node_modules/github-from-package": {
 +            "version": "0.0.0",
 +            "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
 +            "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
 +            "dev": true
 +        },
 +        "node_modules/glob": {
 +            "version": "7.2.3",
 +            "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
 +            "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
 +            "dev": true,
 +            "dependencies": {
 +                "fs.realpath": "^1.0.0",
 +                "inflight": "^1.0.4",
 +                "inherits": "2",
 +                "minimatch": "^3.1.1",
 +                "once": "^1.3.0",
 +                "path-is-absolute": "^1.0.0"
 +            },
 +            "engines": {
 +                "node": "*"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/isaacs"
 +            }
 +        },
 +        "node_modules/glob-parent": {
 +            "version": "6.0.2",
 +            "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
 +            "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
 +            "dev": true,
 +            "dependencies": {
 +                "is-glob": "^4.0.3"
 +            },
 +            "engines": {
 +                "node": ">=10.13.0"
 +            }
 +        },
 +        "node_modules/globals": {
 +            "version": "13.16.0",
 +            "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz",
 +            "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==",
 +            "dev": true,
 +            "dependencies": {
 +                "type-fest": "^0.20.2"
 +            },
 +            "engines": {
 +                "node": ">=8"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/sindresorhus"
 +            }
 +        },
 +        "node_modules/globby": {
 +            "version": "11.1.0",
 +            "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
 +            "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
 +            "dev": true,
 +            "dependencies": {
 +                "array-union": "^2.1.0",
 +                "dir-glob": "^3.0.1",
 +                "fast-glob": "^3.2.9",
 +                "ignore": "^5.2.0",
 +                "merge2": "^1.4.1",
 +                "slash": "^3.0.0"
 +            },
 +            "engines": {
 +                "node": ">=10"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/sindresorhus"
 +            }
 +        },
 +        "node_modules/graceful-fs": {
 +            "version": "4.2.10",
 +            "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
 +            "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
 +            "dev": true
 +        },
 +        "node_modules/has": {
 +            "version": "1.0.3",
 +            "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
 +            "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
 +            "dev": true,
 +            "dependencies": {
 +                "function-bind": "^1.1.1"
 +            },
 +            "engines": {
 +                "node": ">= 0.4.0"
 +            }
 +        },
 +        "node_modules/has-flag": {
 +            "version": "4.0.0",
 +            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
 +            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/has-symbols": {
 +            "version": "1.0.3",
 +            "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
 +            "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">= 0.4"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/ljharb"
 +            }
 +        },
 +        "node_modules/hosted-git-info": {
 +            "version": "4.1.0",
 +            "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
 +            "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
 +            "dev": true,
 +            "dependencies": {
 +                "lru-cache": "^6.0.0"
 +            },
 +            "engines": {
 +                "node": ">=10"
 +            }
 +        },
 +        "node_modules/htmlparser2": {
 +            "version": "8.0.1",
 +            "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz",
 +            "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==",
 +            "dev": true,
 +            "funding": [
 +                "https://github.com/fb55/htmlparser2?sponsor=1",
 +                {
 +                    "type": "github",
 +                    "url": "https://github.com/sponsors/fb55"
 +                }
 +            ],
 +            "dependencies": {
 +                "domelementtype": "^2.3.0",
 +                "domhandler": "^5.0.2",
 +                "domutils": "^3.0.1",
 +                "entities": "^4.3.0"
 +            }
 +        },
 +        "node_modules/http-proxy-agent": {
 +            "version": "4.0.1",
 +            "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
 +            "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
 +            "dev": true,
 +            "dependencies": {
 +                "@tootallnate/once": "1",
 +                "agent-base": "6",
 +                "debug": "4"
 +            },
 +            "engines": {
 +                "node": ">= 6"
 +            }
 +        },
 +        "node_modules/https-proxy-agent": {
 +            "version": "5.0.1",
 +            "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
 +            "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
 +            "dev": true,
 +            "dependencies": {
 +                "agent-base": "6",
 +                "debug": "4"
 +            },
 +            "engines": {
 +                "node": ">= 6"
 +            }
 +        },
 +        "node_modules/iconv-lite": {
 +            "version": "0.6.3",
 +            "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
 +            "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
 +            "dependencies": {
 +                "safer-buffer": ">= 2.1.2 < 3.0.0"
 +            },
 +            "engines": {
 +                "node": ">=0.10.0"
 +            }
 +        },
 +        "node_modules/ieee754": {
 +            "version": "1.2.1",
 +            "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
 +            "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
 +            "dev": true,
 +            "funding": [
 +                {
 +                    "type": "github",
 +                    "url": "https://github.com/sponsors/feross"
 +                },
 +                {
 +                    "type": "patreon",
 +                    "url": "https://www.patreon.com/feross"
 +                },
 +                {
 +                    "type": "consulting",
 +                    "url": "https://feross.org/support"
 +                }
 +            ]
 +        },
 +        "node_modules/ignore": {
 +            "version": "5.2.0",
 +            "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
 +            "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">= 4"
 +            }
 +        },
 +        "node_modules/import-fresh": {
 +            "version": "3.3.0",
 +            "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
 +            "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
 +            "dev": true,
 +            "dependencies": {
 +                "parent-module": "^1.0.0",
 +                "resolve-from": "^4.0.0"
 +            },
 +            "engines": {
 +                "node": ">=6"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/sindresorhus"
 +            }
 +        },
 +        "node_modules/imurmurhash": {
 +            "version": "0.1.4",
 +            "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
 +            "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=0.8.19"
 +            }
 +        },
 +        "node_modules/inflight": {
 +            "version": "1.0.6",
 +            "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
 +            "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
 +            "dev": true,
 +            "dependencies": {
 +                "once": "^1.3.0",
 +                "wrappy": "1"
 +            }
 +        },
 +        "node_modules/inherits": {
 +            "version": "2.0.4",
 +            "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
 +            "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
 +            "dev": true
 +        },
 +        "node_modules/ini": {
 +            "version": "1.3.8",
 +            "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
 +            "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
 +            "dev": true
 +        },
 +        "node_modules/internmap": {
 +            "version": "2.0.3",
 +            "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
 +            "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/is-ci": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
 +            "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
 +            "dev": true,
 +            "dependencies": {
 +                "ci-info": "^2.0.0"
 +            },
 +            "bin": {
 +                "is-ci": "bin.js"
 +            }
 +        },
 +        "node_modules/is-extglob": {
 +            "version": "2.1.1",
 +            "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
 +            "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=0.10.0"
 +            }
 +        },
 +        "node_modules/is-fullwidth-code-point": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
 +            "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/is-glob": {
 +            "version": "4.0.3",
 +            "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
 +            "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
 +            "dev": true,
 +            "dependencies": {
 +                "is-extglob": "^2.1.1"
 +            },
 +            "engines": {
 +                "node": ">=0.10.0"
 +            }
 +        },
 +        "node_modules/is-number": {
 +            "version": "7.0.0",
 +            "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
 +            "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=0.12.0"
 +            }
 +        },
 +        "node_modules/isarray": {
 +            "version": "1.0.0",
 +            "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
 +            "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
 +            "dev": true
 +        },
 +        "node_modules/isexe": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
 +            "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
 +            "dev": true
 +        },
 +        "node_modules/js-yaml": {
 +            "version": "4.1.0",
 +            "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
 +            "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
 +            "dev": true,
 +            "dependencies": {
 +                "argparse": "^2.0.1"
 +            },
 +            "bin": {
 +                "js-yaml": "bin/js-yaml.js"
 +            }
 +        },
 +        "node_modules/json-schema-traverse": {
 +            "version": "0.4.1",
 +            "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
 +            "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
 +            "dev": true
 +        },
 +        "node_modules/json-stable-stringify-without-jsonify": {
 +            "version": "1.0.1",
 +            "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
 +            "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
 +            "dev": true
 +        },
 +        "node_modules/keytar": {
 +            "version": "7.9.0",
 +            "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz",
 +            "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==",
 +            "dev": true,
 +            "hasInstallScript": true,
 +            "dependencies": {
 +                "node-addon-api": "^4.3.0",
 +                "prebuild-install": "^7.0.1"
 +            }
 +        },
 +        "node_modules/leven": {
 +            "version": "3.1.0",
 +            "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
 +            "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=6"
 +            }
 +        },
 +        "node_modules/levn": {
 +            "version": "0.4.1",
 +            "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
 +            "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
 +            "dev": true,
 +            "dependencies": {
 +                "prelude-ls": "^1.2.1",
 +                "type-check": "~0.4.0"
 +            },
 +            "engines": {
 +                "node": ">= 0.8.0"
 +            }
 +        },
 +        "node_modules/linkify-it": {
 +            "version": "3.0.3",
 +            "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
 +            "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
 +            "dev": true,
 +            "dependencies": {
 +                "uc.micro": "^1.0.1"
 +            }
 +        },
 +        "node_modules/listenercount": {
 +            "version": "1.0.1",
 +            "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz",
 +            "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==",
 +            "dev": true
 +        },
 +        "node_modules/lodash.merge": {
 +            "version": "4.6.2",
 +            "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
 +            "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
 +            "dev": true
 +        },
 +        "node_modules/lru-cache": {
 +            "version": "6.0.0",
 +            "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
 +            "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
 +            "dependencies": {
 +                "yallist": "^4.0.0"
 +            },
 +            "engines": {
 +                "node": ">=10"
 +            }
 +        },
 +        "node_modules/markdown-it": {
 +            "version": "12.3.2",
 +            "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
 +            "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
 +            "dev": true,
 +            "dependencies": {
 +                "argparse": "^2.0.1",
 +                "entities": "~2.1.0",
 +                "linkify-it": "^3.0.1",
 +                "mdurl": "^1.0.1",
 +                "uc.micro": "^1.0.5"
 +            },
 +            "bin": {
 +                "markdown-it": "bin/markdown-it.js"
 +            }
 +        },
 +        "node_modules/markdown-it/node_modules/entities": {
 +            "version": "2.1.0",
 +            "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
 +            "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
 +            "dev": true,
 +            "funding": {
 +                "url": "https://github.com/fb55/entities?sponsor=1"
 +            }
 +        },
 +        "node_modules/mdurl": {
 +            "version": "1.0.1",
 +            "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
 +            "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
 +            "dev": true
 +        },
 +        "node_modules/merge2": {
 +            "version": "1.4.1",
 +            "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
 +            "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">= 8"
 +            }
 +        },
 +        "node_modules/micromatch": {
 +            "version": "4.0.5",
 +            "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
 +            "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
 +            "dev": true,
 +            "dependencies": {
 +                "braces": "^3.0.2",
 +                "picomatch": "^2.3.1"
 +            },
 +            "engines": {
 +                "node": ">=8.6"
 +            }
 +        },
 +        "node_modules/mime": {
 +            "version": "1.6.0",
 +            "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
 +            "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
 +            "dev": true,
 +            "bin": {
 +                "mime": "cli.js"
 +            },
 +            "engines": {
 +                "node": ">=4"
 +            }
 +        },
 +        "node_modules/mimic-response": {
 +            "version": "3.1.0",
 +            "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
 +            "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=10"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/sindresorhus"
 +            }
 +        },
 +        "node_modules/minimatch": {
 +            "version": "3.1.2",
 +            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
 +            "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
 +            "dependencies": {
 +                "brace-expansion": "^1.1.7"
 +            },
 +            "engines": {
 +                "node": "*"
 +            }
 +        },
 +        "node_modules/minimist": {
 +            "version": "1.2.6",
 +            "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
 +            "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
 +            "dev": true
 +        },
 +        "node_modules/mkdirp": {
 +            "version": "0.5.6",
 +            "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
 +            "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
 +            "dev": true,
 +            "dependencies": {
 +                "minimist": "^1.2.6"
 +            },
 +            "bin": {
 +                "mkdirp": "bin/cmd.js"
 +            }
 +        },
 +        "node_modules/mkdirp-classic": {
 +            "version": "0.5.3",
 +            "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
 +            "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
 +            "dev": true
 +        },
 +        "node_modules/ms": {
 +            "version": "2.1.2",
 +            "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
 +            "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
 +            "dev": true
 +        },
 +        "node_modules/mute-stream": {
 +            "version": "0.0.8",
 +            "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
 +            "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
 +            "dev": true
 +        },
 +        "node_modules/napi-build-utils": {
 +            "version": "1.0.2",
 +            "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
 +            "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
 +            "dev": true
 +        },
 +        "node_modules/natural-compare": {
 +            "version": "1.4.0",
 +            "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
 +            "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
 +            "dev": true
 +        },
 +        "node_modules/node-abi": {
 +            "version": "3.22.0",
 +            "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.22.0.tgz",
 +            "integrity": "sha512-u4uAs/4Zzmp/jjsD9cyFYDXeISfUWaAVWshPmDZOFOv4Xl4SbzTXm53I04C2uRueYJ+0t5PEtLH/owbn2Npf/w==",
 +            "dev": true,
 +            "dependencies": {
 +                "semver": "^7.3.5"
 +            },
 +            "engines": {
 +                "node": ">=10"
 +            }
 +        },
 +        "node_modules/node-addon-api": {
 +            "version": "4.3.0",
 +            "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
 +            "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
 +            "dev": true
 +        },
 +        "node_modules/nth-check": {
 +            "version": "2.1.1",
 +            "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
 +            "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
 +            "dev": true,
 +            "dependencies": {
 +                "boolbase": "^1.0.0"
 +            },
 +            "funding": {
 +                "url": "https://github.com/fb55/nth-check?sponsor=1"
 +            }
 +        },
 +        "node_modules/object-inspect": {
 +            "version": "1.12.2",
 +            "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
 +            "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
 +            "dev": true,
 +            "funding": {
 +                "url": "https://github.com/sponsors/ljharb"
 +            }
 +        },
 +        "node_modules/once": {
 +            "version": "1.4.0",
 +            "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
 +            "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
 +            "dev": true,
 +            "dependencies": {
 +                "wrappy": "1"
 +            }
 +        },
 +        "node_modules/optionator": {
 +            "version": "0.9.1",
 +            "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
 +            "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
 +            "dev": true,
 +            "dependencies": {
 +                "deep-is": "^0.1.3",
 +                "fast-levenshtein": "^2.0.6",
 +                "levn": "^0.4.1",
 +                "prelude-ls": "^1.2.1",
 +                "type-check": "^0.4.0",
 +                "word-wrap": "^1.2.3"
 +            },
 +            "engines": {
 +                "node": ">= 0.8.0"
 +            }
 +        },
 +        "node_modules/ovsx": {
 +            "version": "0.5.1",
 +            "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.5.1.tgz",
 +            "integrity": "sha512-3OWq0l7DuVHi2bd2aQe5+QVQlFIqvrcw3/2vGXL404L6Tr+R4QHtzfnYYghv8CCa85xJHjU0RhcaC7pyXkAUbg==",
 +            "dev": true,
 +            "dependencies": {
 +                "commander": "^6.1.0",
 +                "follow-redirects": "^1.14.6",
 +                "is-ci": "^2.0.0",
 +                "leven": "^3.1.0",
 +                "tmp": "^0.2.1",
 +                "vsce": "^2.6.3"
 +            },
 +            "bin": {
 +                "ovsx": "lib/ovsx"
 +            },
 +            "engines": {
 +                "node": ">= 14"
 +            }
 +        },
 +        "node_modules/ovsx/node_modules/commander": {
 +            "version": "6.2.1",
 +            "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
 +            "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">= 6"
 +            }
 +        },
 +        "node_modules/parent-module": {
 +            "version": "1.0.1",
 +            "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
 +            "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
 +            "dev": true,
 +            "dependencies": {
 +                "callsites": "^3.0.0"
 +            },
 +            "engines": {
 +                "node": ">=6"
 +            }
 +        },
 +        "node_modules/parse-semver": {
 +            "version": "1.1.1",
 +            "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
 +            "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==",
 +            "dev": true,
 +            "dependencies": {
 +                "semver": "^5.1.0"
 +            }
 +        },
 +        "node_modules/parse-semver/node_modules/semver": {
 +            "version": "5.7.1",
 +            "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
 +            "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
 +            "dev": true,
 +            "bin": {
 +                "semver": "bin/semver"
 +            }
 +        },
 +        "node_modules/parse5": {
 +            "version": "7.0.0",
 +            "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz",
 +            "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==",
 +            "dev": true,
 +            "dependencies": {
 +                "entities": "^4.3.0"
 +            },
 +            "funding": {
 +                "url": "https://github.com/inikulin/parse5?sponsor=1"
 +            }
 +        },
 +        "node_modules/parse5-htmlparser2-tree-adapter": {
 +            "version": "7.0.0",
 +            "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
 +            "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
 +            "dev": true,
 +            "dependencies": {
 +                "domhandler": "^5.0.2",
 +                "parse5": "^7.0.0"
 +            },
 +            "funding": {
 +                "url": "https://github.com/inikulin/parse5?sponsor=1"
 +            }
 +        },
 +        "node_modules/path-is-absolute": {
 +            "version": "1.0.1",
 +            "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
 +            "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=0.10.0"
 +            }
 +        },
 +        "node_modules/path-key": {
 +            "version": "3.1.1",
 +            "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
 +            "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/path-type": {
 +            "version": "4.0.0",
 +            "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
 +            "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/pend": {
 +            "version": "1.2.0",
 +            "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
 +            "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
 +            "dev": true
 +        },
 +        "node_modules/picomatch": {
 +            "version": "2.3.1",
 +            "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
 +            "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=8.6"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/jonschlinkert"
 +            }
 +        },
 +        "node_modules/prebuild-install": {
 +            "version": "7.1.1",
 +            "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz",
 +            "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==",
 +            "dev": true,
 +            "dependencies": {
 +                "detect-libc": "^2.0.0",
 +                "expand-template": "^2.0.3",
 +                "github-from-package": "0.0.0",
 +                "minimist": "^1.2.3",
 +                "mkdirp-classic": "^0.5.3",
 +                "napi-build-utils": "^1.0.1",
 +                "node-abi": "^3.3.0",
 +                "pump": "^3.0.0",
 +                "rc": "^1.2.7",
 +                "simple-get": "^4.0.0",
 +                "tar-fs": "^2.0.0",
 +                "tunnel-agent": "^0.6.0"
 +            },
 +            "bin": {
 +                "prebuild-install": "bin.js"
 +            },
 +            "engines": {
 +                "node": ">=10"
 +            }
 +        },
 +        "node_modules/prelude-ls": {
 +            "version": "1.2.1",
 +            "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
 +            "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">= 0.8.0"
 +            }
 +        },
 +        "node_modules/prettier": {
 +            "version": "2.7.1",
 +            "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
 +            "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
 +            "dev": true,
 +            "bin": {
 +                "prettier": "bin-prettier.js"
 +            },
 +            "engines": {
 +                "node": ">=10.13.0"
 +            },
 +            "funding": {
 +                "url": "https://github.com/prettier/prettier?sponsor=1"
 +            }
 +        },
 +        "node_modules/process-nextick-args": {
 +            "version": "2.0.1",
 +            "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
 +            "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
 +            "dev": true
 +        },
 +        "node_modules/pump": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
 +            "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
 +            "dev": true,
 +            "dependencies": {
 +                "end-of-stream": "^1.1.0",
 +                "once": "^1.3.1"
 +            }
 +        },
 +        "node_modules/punycode": {
 +            "version": "2.1.1",
 +            "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
 +            "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=6"
 +            }
 +        },
 +        "node_modules/qs": {
 +            "version": "6.11.0",
 +            "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
 +            "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
 +            "dev": true,
 +            "dependencies": {
 +                "side-channel": "^1.0.4"
 +            },
 +            "engines": {
 +                "node": ">=0.6"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/ljharb"
 +            }
 +        },
 +        "node_modules/queue-microtask": {
 +            "version": "1.2.3",
 +            "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
 +            "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
 +            "dev": true,
 +            "funding": [
 +                {
 +                    "type": "github",
 +                    "url": "https://github.com/sponsors/feross"
 +                },
 +                {
 +                    "type": "patreon",
 +                    "url": "https://www.patreon.com/feross"
 +                },
 +                {
 +                    "type": "consulting",
 +                    "url": "https://feross.org/support"
 +                }
 +            ]
 +        },
 +        "node_modules/rc": {
 +            "version": "1.2.8",
 +            "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
 +            "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
 +            "dev": true,
 +            "dependencies": {
 +                "deep-extend": "^0.6.0",
 +                "ini": "~1.3.0",
 +                "minimist": "^1.2.0",
 +                "strip-json-comments": "~2.0.1"
 +            },
 +            "bin": {
 +                "rc": "cli.js"
 +            }
 +        },
 +        "node_modules/rc/node_modules/strip-json-comments": {
 +            "version": "2.0.1",
 +            "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
 +            "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=0.10.0"
 +            }
 +        },
 +        "node_modules/read": {
 +            "version": "1.0.7",
 +            "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
 +            "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==",
 +            "dev": true,
 +            "dependencies": {
 +                "mute-stream": "~0.0.4"
 +            },
 +            "engines": {
 +                "node": ">=0.8"
 +            }
 +        },
 +        "node_modules/readable-stream": {
 +            "version": "2.3.7",
 +            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
 +            "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
 +            "dev": true,
 +            "dependencies": {
 +                "core-util-is": "~1.0.0",
 +                "inherits": "~2.0.3",
 +                "isarray": "~1.0.0",
 +                "process-nextick-args": "~2.0.0",
 +                "safe-buffer": "~5.1.1",
 +                "string_decoder": "~1.1.1",
 +                "util-deprecate": "~1.0.1"
 +            }
 +        },
 +        "node_modules/regexpp": {
 +            "version": "3.2.0",
 +            "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
 +            "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=8"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/mysticatea"
 +            }
 +        },
 +        "node_modules/require-directory": {
 +            "version": "2.1.1",
 +            "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
 +            "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
 +            "engines": {
 +                "node": ">=0.10.0"
 +            }
 +        },
 +        "node_modules/resolve-from": {
 +            "version": "4.0.0",
 +            "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
 +            "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=4"
 +            }
 +        },
 +        "node_modules/reusify": {
 +            "version": "1.0.4",
 +            "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
 +            "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
 +            "dev": true,
 +            "engines": {
 +                "iojs": ">=1.0.0",
 +                "node": ">=0.10.0"
 +            }
 +        },
 +        "node_modules/rimraf": {
 +            "version": "3.0.2",
 +            "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
 +            "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
 +            "dev": true,
 +            "dependencies": {
 +                "glob": "^7.1.3"
 +            },
 +            "bin": {
 +                "rimraf": "bin.js"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/isaacs"
 +            }
 +        },
 +        "node_modules/robust-predicates": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz",
 +            "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g=="
 +        },
 +        "node_modules/run-parallel": {
 +            "version": "1.2.0",
 +            "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
 +            "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
 +            "dev": true,
 +            "funding": [
 +                {
 +                    "type": "github",
 +                    "url": "https://github.com/sponsors/feross"
 +                },
 +                {
 +                    "type": "patreon",
 +                    "url": "https://www.patreon.com/feross"
 +                },
 +                {
 +                    "type": "consulting",
 +                    "url": "https://feross.org/support"
 +                }
 +            ],
 +            "dependencies": {
 +                "queue-microtask": "^1.2.2"
 +            }
 +        },
 +        "node_modules/rw": {
 +            "version": "1.3.3",
 +            "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
 +            "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="
 +        },
 +        "node_modules/safe-buffer": {
 +            "version": "5.1.2",
 +            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
 +            "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
 +            "dev": true
 +        },
 +        "node_modules/safer-buffer": {
 +            "version": "2.1.2",
 +            "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
 +            "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
 +        },
 +        "node_modules/sax": {
 +            "version": "1.2.4",
 +            "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
 +            "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
 +            "dev": true
 +        },
 +        "node_modules/semver": {
 +            "version": "7.3.7",
 +            "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
 +            "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
 +            "dependencies": {
 +                "lru-cache": "^6.0.0"
 +            },
 +            "bin": {
 +                "semver": "bin/semver.js"
 +            },
 +            "engines": {
 +                "node": ">=10"
 +            }
 +        },
 +        "node_modules/setimmediate": {
 +            "version": "1.0.5",
 +            "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
 +            "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
 +            "dev": true
 +        },
 +        "node_modules/shebang-command": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
 +            "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
 +            "dev": true,
 +            "dependencies": {
 +                "shebang-regex": "^3.0.0"
 +            },
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/shebang-regex": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
 +            "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/side-channel": {
 +            "version": "1.0.4",
 +            "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
 +            "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
 +            "dev": true,
 +            "dependencies": {
 +                "call-bind": "^1.0.0",
 +                "get-intrinsic": "^1.0.2",
 +                "object-inspect": "^1.9.0"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/ljharb"
 +            }
 +        },
 +        "node_modules/simple-concat": {
 +            "version": "1.0.1",
 +            "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
 +            "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
 +            "dev": true,
 +            "funding": [
 +                {
 +                    "type": "github",
 +                    "url": "https://github.com/sponsors/feross"
 +                },
 +                {
 +                    "type": "patreon",
 +                    "url": "https://www.patreon.com/feross"
 +                },
 +                {
 +                    "type": "consulting",
 +                    "url": "https://feross.org/support"
 +                }
 +            ]
 +        },
 +        "node_modules/simple-get": {
 +            "version": "4.0.1",
 +            "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
 +            "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
 +            "dev": true,
 +            "funding": [
 +                {
 +                    "type": "github",
 +                    "url": "https://github.com/sponsors/feross"
 +                },
 +                {
 +                    "type": "patreon",
 +                    "url": "https://www.patreon.com/feross"
 +                },
 +                {
 +                    "type": "consulting",
 +                    "url": "https://feross.org/support"
 +                }
 +            ],
 +            "dependencies": {
 +                "decompress-response": "^6.0.0",
 +                "once": "^1.3.1",
 +                "simple-concat": "^1.0.0"
 +            }
 +        },
 +        "node_modules/slash": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
 +            "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/string_decoder": {
 +            "version": "1.1.1",
 +            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
 +            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
 +            "dev": true,
 +            "dependencies": {
 +                "safe-buffer": "~5.1.0"
 +            }
 +        },
 +        "node_modules/string-width": {
 +            "version": "4.2.3",
 +            "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
 +            "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
 +            "dependencies": {
 +                "emoji-regex": "^8.0.0",
 +                "is-fullwidth-code-point": "^3.0.0",
 +                "strip-ansi": "^6.0.1"
 +            },
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/strip-ansi": {
 +            "version": "6.0.1",
 +            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
 +            "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
 +            "dependencies": {
 +                "ansi-regex": "^5.0.1"
 +            },
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/strip-json-comments": {
 +            "version": "3.1.1",
 +            "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
 +            "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=8"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/sindresorhus"
 +            }
 +        },
 +        "node_modules/supports-color": {
 +            "version": "7.2.0",
 +            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
 +            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
 +            "dev": true,
 +            "dependencies": {
 +                "has-flag": "^4.0.0"
 +            },
 +            "engines": {
 +                "node": ">=8"
 +            }
 +        },
 +        "node_modules/tar-fs": {
 +            "version": "2.1.1",
 +            "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
 +            "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
 +            "dev": true,
 +            "dependencies": {
 +                "chownr": "^1.1.1",
 +                "mkdirp-classic": "^0.5.2",
 +                "pump": "^3.0.0",
 +                "tar-stream": "^2.1.4"
 +            }
 +        },
 +        "node_modules/tar-stream": {
 +            "version": "2.2.0",
 +            "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
 +            "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
 +            "dev": true,
 +            "dependencies": {
 +                "bl": "^4.0.3",
 +                "end-of-stream": "^1.4.1",
 +                "fs-constants": "^1.0.0",
 +                "inherits": "^2.0.3",
 +                "readable-stream": "^3.1.1"
 +            },
 +            "engines": {
 +                "node": ">=6"
 +            }
 +        },
 +        "node_modules/tar-stream/node_modules/readable-stream": {
 +            "version": "3.6.0",
 +            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
 +            "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
 +            "dev": true,
 +            "dependencies": {
 +                "inherits": "^2.0.3",
 +                "string_decoder": "^1.1.1",
 +                "util-deprecate": "^1.0.1"
 +            },
 +            "engines": {
 +                "node": ">= 6"
 +            }
 +        },
 +        "node_modules/text-table": {
 +            "version": "0.2.0",
 +            "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
 +            "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
 +            "dev": true
 +        },
 +        "node_modules/tmp": {
 +            "version": "0.2.1",
 +            "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
 +            "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
 +            "dev": true,
 +            "dependencies": {
 +                "rimraf": "^3.0.0"
 +            },
 +            "engines": {
 +                "node": ">=8.17.0"
 +            }
 +        },
 +        "node_modules/to-regex-range": {
 +            "version": "5.0.1",
 +            "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
 +            "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
 +            "dev": true,
 +            "dependencies": {
 +                "is-number": "^7.0.0"
 +            },
 +            "engines": {
 +                "node": ">=8.0"
 +            }
 +        },
 +        "node_modules/traverse": {
 +            "version": "0.3.9",
 +            "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
 +            "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==",
 +            "dev": true,
 +            "engines": {
 +                "node": "*"
 +            }
 +        },
 +        "node_modules/tslib": {
 +            "version": "2.4.0",
 +            "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
 +            "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
 +            "dev": true
 +        },
 +        "node_modules/tsutils": {
 +            "version": "3.21.0",
 +            "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
 +            "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
 +            "dev": true,
 +            "dependencies": {
 +                "tslib": "^1.8.1"
 +            },
 +            "engines": {
 +                "node": ">= 6"
 +            },
 +            "peerDependencies": {
 +                "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
 +            }
 +        },
 +        "node_modules/tsutils/node_modules/tslib": {
 +            "version": "1.14.1",
 +            "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
 +            "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
 +            "dev": true
 +        },
 +        "node_modules/tunnel": {
 +            "version": "0.0.6",
 +            "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
 +            "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=0.6.11 <=0.7.0 || >=0.7.3"
 +            }
 +        },
 +        "node_modules/tunnel-agent": {
 +            "version": "0.6.0",
 +            "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
 +            "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
 +            "dev": true,
 +            "dependencies": {
 +                "safe-buffer": "^5.0.1"
 +            },
 +            "engines": {
 +                "node": "*"
 +            }
 +        },
 +        "node_modules/type-check": {
 +            "version": "0.4.0",
 +            "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
 +            "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
 +            "dev": true,
 +            "dependencies": {
 +                "prelude-ls": "^1.2.1"
 +            },
 +            "engines": {
 +                "node": ">= 0.8.0"
 +            }
 +        },
 +        "node_modules/type-fest": {
 +            "version": "0.20.2",
 +            "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
 +            "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=10"
 +            },
 +            "funding": {
 +                "url": "https://github.com/sponsors/sindresorhus"
 +            }
 +        },
 +        "node_modules/typed-rest-client": {
 +            "version": "1.8.9",
 +            "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz",
 +            "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==",
 +            "dev": true,
 +            "dependencies": {
 +                "qs": "^6.9.1",
 +                "tunnel": "0.0.6",
 +                "underscore": "^1.12.1"
 +            }
 +        },
 +        "node_modules/typescript": {
 +            "version": "4.7.4",
 +            "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
 +            "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
 +            "dev": true,
 +            "bin": {
 +                "tsc": "bin/tsc",
 +                "tsserver": "bin/tsserver"
 +            },
 +            "engines": {
 +                "node": ">=4.2.0"
 +            }
 +        },
 +        "node_modules/uc.micro": {
 +            "version": "1.0.6",
 +            "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
 +            "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
 +            "dev": true
 +        },
 +        "node_modules/underscore": {
 +            "version": "1.13.4",
 +            "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz",
 +            "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==",
 +            "dev": true
 +        },
 +        "node_modules/unzipper": {
 +            "version": "0.10.11",
 +            "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz",
 +            "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==",
 +            "dev": true,
 +            "dependencies": {
 +                "big-integer": "^1.6.17",
 +                "binary": "~0.3.0",
 +                "bluebird": "~3.4.1",
 +                "buffer-indexof-polyfill": "~1.0.0",
 +                "duplexer2": "~0.1.4",
 +                "fstream": "^1.0.12",
 +                "graceful-fs": "^4.2.2",
 +                "listenercount": "~1.0.1",
 +                "readable-stream": "~2.3.6",
 +                "setimmediate": "~1.0.4"
 +            }
 +        },
 +        "node_modules/uri-js": {
 +            "version": "4.4.1",
 +            "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
 +            "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
 +            "dev": true,
 +            "dependencies": {
 +                "punycode": "^2.1.0"
 +            }
 +        },
 +        "node_modules/url-join": {
 +            "version": "4.0.1",
 +            "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
 +            "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
 +            "dev": true
 +        },
 +        "node_modules/util-deprecate": {
 +            "version": "1.0.2",
 +            "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
 +            "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
 +            "dev": true
 +        },
 +        "node_modules/v8-compile-cache": {
 +            "version": "2.3.0",
 +            "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
 +            "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
 +            "dev": true
 +        },
 +        "node_modules/vsce": {
 +            "version": "2.9.2",
 +            "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.9.2.tgz",
 +            "integrity": "sha512-xyLqL4U82BilUX1t6Ym2opQEa2tLGWYjbgB7+ETeNVXlIJz5sWBJjQJSYJVFOKJSpiOtQclolu88cj7oY6vvPQ==",
 +            "dev": true,
 +            "dependencies": {
 +                "azure-devops-node-api": "^11.0.1",
 +                "chalk": "^2.4.2",
 +                "cheerio": "^1.0.0-rc.9",
 +                "commander": "^6.1.0",
 +                "glob": "^7.0.6",
 +                "hosted-git-info": "^4.0.2",
 +                "keytar": "^7.7.0",
 +                "leven": "^3.1.0",
 +                "markdown-it": "^12.3.2",
 +                "mime": "^1.3.4",
 +                "minimatch": "^3.0.3",
 +                "parse-semver": "^1.1.1",
 +                "read": "^1.0.7",
 +                "semver": "^5.1.0",
 +                "tmp": "^0.2.1",
 +                "typed-rest-client": "^1.8.4",
 +                "url-join": "^4.0.1",
 +                "xml2js": "^0.4.23",
 +                "yauzl": "^2.3.1",
 +                "yazl": "^2.2.2"
 +            },
 +            "bin": {
 +                "vsce": "vsce"
 +            },
 +            "engines": {
 +                "node": ">= 14"
 +            }
 +        },
 +        "node_modules/vsce/node_modules/ansi-styles": {
 +            "version": "3.2.1",
 +            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
 +            "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
 +            "dev": true,
 +            "dependencies": {
 +                "color-convert": "^1.9.0"
 +            },
 +            "engines": {
 +                "node": ">=4"
 +            }
 +        },
 +        "node_modules/vsce/node_modules/chalk": {
 +            "version": "2.4.2",
 +            "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
 +            "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
 +            "dev": true,
 +            "dependencies": {
 +                "ansi-styles": "^3.2.1",
 +                "escape-string-regexp": "^1.0.5",
 +                "supports-color": "^5.3.0"
 +            },
 +            "engines": {
 +                "node": ">=4"
 +            }
 +        },
 +        "node_modules/vsce/node_modules/color-convert": {
 +            "version": "1.9.3",
 +            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
 +            "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
 +            "dev": true,
 +            "dependencies": {
 +                "color-name": "1.1.3"
 +            }
 +        },
 +        "node_modules/vsce/node_modules/color-name": {
 +            "version": "1.1.3",
 +            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
 +            "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
 +            "dev": true
 +        },
 +        "node_modules/vsce/node_modules/commander": {
 +            "version": "6.2.1",
 +            "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
 +            "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">= 6"
 +            }
 +        },
 +        "node_modules/vsce/node_modules/escape-string-regexp": {
 +            "version": "1.0.5",
 +            "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
 +            "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=0.8.0"
 +            }
 +        },
 +        "node_modules/vsce/node_modules/has-flag": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
 +            "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=4"
 +            }
 +        },
 +        "node_modules/vsce/node_modules/semver": {
 +            "version": "5.7.1",
 +            "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
 +            "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
 +            "dev": true,
 +            "bin": {
 +                "semver": "bin/semver"
 +            }
 +        },
 +        "node_modules/vsce/node_modules/supports-color": {
 +            "version": "5.5.0",
 +            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
 +            "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
 +            "dev": true,
 +            "dependencies": {
 +                "has-flag": "^3.0.0"
 +            },
 +            "engines": {
 +                "node": ">=4"
 +            }
 +        },
 +        "node_modules/vscode-jsonrpc": {
-             "version": "8.0.0-next.14",
-             "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.0-next.14.tgz",
-             "integrity": "sha512-NqjkOuDTMu8uo+PhoMsV72VO9Gd3wBi/ZpOrkRUOrWKQo7yUdiIw183g8wjH8BImgbK9ZP51HM7TI0ZhCnI1Mw==",
++            "version": "8.0.2",
++            "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz",
++            "integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==",
 +            "engines": {
 +                "node": ">=14.0.0"
 +            }
 +        },
 +        "node_modules/vscode-languageclient": {
-                 "vscode-languageserver-protocol": "3.17.0-next.16"
++            "version": "8.0.2",
++            "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.2.tgz",
++            "integrity": "sha512-lHlthJtphG9gibGb/y72CKqQUxwPsMXijJVpHEC2bvbFqxmkj9LwQ3aGU9dwjBLqsX1S4KjShYppLvg1UJDF/Q==",
 +            "dependencies": {
 +                "minimatch": "^3.0.4",
 +                "semver": "^7.3.5",
-                 "vscode": "^1.66.0"
++                "vscode-languageserver-protocol": "3.17.2"
 +            },
 +            "engines": {
-             "version": "3.17.0-next.16",
-             "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.16.tgz",
-             "integrity": "sha512-tx4DnXw9u3N7vw+bx6n2NKp6FoxoNwiP/biH83AS30I2AnTGyLd7afSeH6Oewn2E8jvB7K15bs12sMppkKOVeQ==",
++                "vscode": "^1.67.0"
 +            }
 +        },
 +        "node_modules/vscode-languageserver-protocol": {
-                 "vscode-jsonrpc": "8.0.0-next.7",
-                 "vscode-languageserver-types": "3.17.0-next.9"
++            "version": "3.17.2",
++            "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz",
++            "integrity": "sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg==",
 +            "dependencies": {
-             "version": "3.17.0-next.9",
-             "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.9.tgz",
-             "integrity": "sha512-9/PeDNPYduaoXRUzYpqmu4ZV9L01HGo0wH9FUt+sSHR7IXwA7xoXBfNUlv8gB9H0D2WwEmMomSy1NmhjKQyn3A=="
++                "vscode-jsonrpc": "8.0.2",
++                "vscode-languageserver-types": "3.17.2"
 +            }
 +        },
 +        "node_modules/vscode-languageserver-types": {
-             "version": "8.0.0-next.7",
-             "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.0-next.7.tgz",
-             "integrity": "sha512-JX/F31LEsims0dAlOTKFE4E+AJMiJvdRSRViifFJSqSN7EzeYyWlfuDchF7g91oRNPZOIWfibTkDf3/UMsQGzQ=="
++            "version": "3.17.2",
++            "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz",
++            "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA=="
 +        },
 +        "node_modules/which": {
 +            "version": "2.0.2",
 +            "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
 +            "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
 +            "dev": true,
 +            "dependencies": {
 +                "isexe": "^2.0.0"
 +            },
 +            "bin": {
 +                "node-which": "bin/node-which"
 +            },
 +            "engines": {
 +                "node": ">= 8"
 +            }
 +        },
 +        "node_modules/word-wrap": {
 +            "version": "1.2.3",
 +            "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
 +            "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=0.10.0"
 +            }
 +        },
 +        "node_modules/wrap-ansi": {
 +            "version": "7.0.0",
 +            "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
 +            "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
 +            "dependencies": {
 +                "ansi-styles": "^4.0.0",
 +                "string-width": "^4.1.0",
 +                "strip-ansi": "^6.0.0"
 +            },
 +            "engines": {
 +                "node": ">=10"
 +            },
 +            "funding": {
 +                "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
 +            }
 +        },
 +        "node_modules/wrappy": {
 +            "version": "1.0.2",
 +            "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
 +            "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
 +            "dev": true
 +        },
 +        "node_modules/xml2js": {
 +            "version": "0.4.23",
 +            "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
 +            "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
 +            "dev": true,
 +            "dependencies": {
 +                "sax": ">=0.6.0",
 +                "xmlbuilder": "~11.0.0"
 +            },
 +            "engines": {
 +                "node": ">=4.0.0"
 +            }
 +        },
 +        "node_modules/xmlbuilder": {
 +            "version": "11.0.1",
 +            "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
 +            "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
 +            "dev": true,
 +            "engines": {
 +                "node": ">=4.0"
 +            }
 +        },
 +        "node_modules/y18n": {
 +            "version": "5.0.8",
 +            "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
 +            "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
 +            "engines": {
 +                "node": ">=10"
 +            }
 +        },
 +        "node_modules/yallist": {
 +            "version": "4.0.0",
 +            "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
 +            "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
 +        },
 +        "node_modules/yargs": {
 +            "version": "17.5.1",
 +            "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz",
 +            "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==",
 +            "dependencies": {
 +                "cliui": "^7.0.2",
 +                "escalade": "^3.1.1",
 +                "get-caller-file": "^2.0.5",
 +                "require-directory": "^2.1.1",
 +                "string-width": "^4.2.3",
 +                "y18n": "^5.0.5",
 +                "yargs-parser": "^21.0.0"
 +            },
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/yargs-parser": {
 +            "version": "21.0.1",
 +            "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz",
 +            "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==",
 +            "engines": {
 +                "node": ">=12"
 +            }
 +        },
 +        "node_modules/yauzl": {
 +            "version": "2.10.0",
 +            "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
 +            "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
 +            "dev": true,
 +            "dependencies": {
 +                "buffer-crc32": "~0.2.3",
 +                "fd-slicer": "~1.1.0"
 +            }
 +        },
 +        "node_modules/yazl": {
 +            "version": "2.5.1",
 +            "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz",
 +            "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==",
 +            "dev": true,
 +            "dependencies": {
 +                "buffer-crc32": "~0.2.3"
 +            }
 +        }
 +    },
 +    "dependencies": {
 +        "@eslint/eslintrc": {
 +            "version": "1.3.0",
 +            "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
 +            "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==",
 +            "dev": true,
 +            "requires": {
 +                "ajv": "^6.12.4",
 +                "debug": "^4.3.2",
 +                "espree": "^9.3.2",
 +                "globals": "^13.15.0",
 +                "ignore": "^5.2.0",
 +                "import-fresh": "^3.2.1",
 +                "js-yaml": "^4.1.0",
 +                "minimatch": "^3.1.2",
 +                "strip-json-comments": "^3.1.1"
 +            }
 +        },
 +        "@hpcc-js/wasm": {
 +            "version": "1.12.8",
 +            "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-1.12.8.tgz",
 +            "integrity": "sha512-n4q9ARKco2hpCLsuVaW6Az3cDVaua7B3DSONHkc49WtEzgY/btvcDG5Zr1P6PZDv0sQ7oPnAi9Y+W2DI++MgcQ==",
 +            "requires": {
 +                "yargs": "^17.3.1"
 +            }
 +        },
 +        "@humanwhocodes/config-array": {
 +            "version": "0.9.5",
 +            "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz",
 +            "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==",
 +            "dev": true,
 +            "requires": {
 +                "@humanwhocodes/object-schema": "^1.2.1",
 +                "debug": "^4.1.1",
 +                "minimatch": "^3.0.4"
 +            }
 +        },
 +        "@humanwhocodes/object-schema": {
 +            "version": "1.2.1",
 +            "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
 +            "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
 +            "dev": true
 +        },
 +        "@nodelib/fs.scandir": {
 +            "version": "2.1.5",
 +            "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
 +            "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
 +            "dev": true,
 +            "requires": {
 +                "@nodelib/fs.stat": "2.0.5",
 +                "run-parallel": "^1.1.9"
 +            }
 +        },
 +        "@nodelib/fs.stat": {
 +            "version": "2.0.5",
 +            "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
 +            "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
 +            "dev": true
 +        },
 +        "@nodelib/fs.walk": {
 +            "version": "1.2.8",
 +            "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
 +            "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
 +            "dev": true,
 +            "requires": {
 +                "@nodelib/fs.scandir": "2.1.5",
 +                "fastq": "^1.6.0"
 +            }
 +        },
 +        "@tootallnate/once": {
 +            "version": "1.1.2",
 +            "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
 +            "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
 +            "dev": true
 +        },
 +        "@types/json-schema": {
 +            "version": "7.0.11",
 +            "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
 +            "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
 +            "dev": true
 +        },
 +        "@types/node": {
 +            "version": "16.11.43",
 +            "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.43.tgz",
 +            "integrity": "sha512-GqWykok+3uocgfAJM8imbozrqLnPyTrpFlrryURQlw1EesPUCx5XxTiucWDSFF9/NUEXDuD4bnvHm8xfVGWTpQ==",
 +            "dev": true
 +        },
 +        "@types/vscode": {
 +            "version": "1.66.0",
 +            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.66.0.tgz",
 +            "integrity": "sha512-ZfJck4M7nrGasfs4A4YbUoxis3Vu24cETw3DERsNYtDZmYSYtk6ljKexKFKhImO/ZmY6ZMsmegu2FPkXoUFImA==",
 +            "dev": true
 +        },
 +        "@typescript-eslint/eslint-plugin": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz",
 +            "integrity": "sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig==",
 +            "dev": true,
 +            "requires": {
 +                "@typescript-eslint/scope-manager": "5.30.5",
 +                "@typescript-eslint/type-utils": "5.30.5",
 +                "@typescript-eslint/utils": "5.30.5",
 +                "debug": "^4.3.4",
 +                "functional-red-black-tree": "^1.0.1",
 +                "ignore": "^5.2.0",
 +                "regexpp": "^3.2.0",
 +                "semver": "^7.3.7",
 +                "tsutils": "^3.21.0"
 +            }
 +        },
 +        "@typescript-eslint/parser": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.5.tgz",
 +            "integrity": "sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q==",
 +            "dev": true,
 +            "requires": {
 +                "@typescript-eslint/scope-manager": "5.30.5",
 +                "@typescript-eslint/types": "5.30.5",
 +                "@typescript-eslint/typescript-estree": "5.30.5",
 +                "debug": "^4.3.4"
 +            }
 +        },
 +        "@typescript-eslint/scope-manager": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz",
 +            "integrity": "sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg==",
 +            "dev": true,
 +            "requires": {
 +                "@typescript-eslint/types": "5.30.5",
 +                "@typescript-eslint/visitor-keys": "5.30.5"
 +            }
 +        },
 +        "@typescript-eslint/type-utils": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz",
 +            "integrity": "sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw==",
 +            "dev": true,
 +            "requires": {
 +                "@typescript-eslint/utils": "5.30.5",
 +                "debug": "^4.3.4",
 +                "tsutils": "^3.21.0"
 +            }
 +        },
 +        "@typescript-eslint/types": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.5.tgz",
 +            "integrity": "sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw==",
 +            "dev": true
 +        },
 +        "@typescript-eslint/typescript-estree": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz",
 +            "integrity": "sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ==",
 +            "dev": true,
 +            "requires": {
 +                "@typescript-eslint/types": "5.30.5",
 +                "@typescript-eslint/visitor-keys": "5.30.5",
 +                "debug": "^4.3.4",
 +                "globby": "^11.1.0",
 +                "is-glob": "^4.0.3",
 +                "semver": "^7.3.7",
 +                "tsutils": "^3.21.0"
 +            }
 +        },
 +        "@typescript-eslint/utils": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.5.tgz",
 +            "integrity": "sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA==",
 +            "dev": true,
 +            "requires": {
 +                "@types/json-schema": "^7.0.9",
 +                "@typescript-eslint/scope-manager": "5.30.5",
 +                "@typescript-eslint/types": "5.30.5",
 +                "@typescript-eslint/typescript-estree": "5.30.5",
 +                "eslint-scope": "^5.1.1",
 +                "eslint-utils": "^3.0.0"
 +            }
 +        },
 +        "@typescript-eslint/visitor-keys": {
 +            "version": "5.30.5",
 +            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz",
 +            "integrity": "sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA==",
 +            "dev": true,
 +            "requires": {
 +                "@typescript-eslint/types": "5.30.5",
 +                "eslint-visitor-keys": "^3.3.0"
 +            }
 +        },
 +        "@vscode/test-electron": {
 +            "version": "2.1.5",
 +            "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.1.5.tgz",
 +            "integrity": "sha512-O/ioqFpV+RvKbRykX2ItYPnbcZ4Hk5V0rY4uhQjQTLhGL9WZUvS7exzuYQCCI+ilSqJpctvxq2llTfGXf9UnnA==",
 +            "dev": true,
 +            "requires": {
 +                "http-proxy-agent": "^4.0.1",
 +                "https-proxy-agent": "^5.0.0",
 +                "rimraf": "^3.0.2",
 +                "unzipper": "^0.10.11"
 +            }
 +        },
 +        "acorn": {
 +            "version": "8.7.1",
 +            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
 +            "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==",
 +            "dev": true
 +        },
 +        "acorn-jsx": {
 +            "version": "5.3.2",
 +            "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
 +            "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
 +            "dev": true,
 +            "requires": {}
 +        },
 +        "agent-base": {
 +            "version": "6.0.2",
 +            "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
 +            "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
 +            "dev": true,
 +            "requires": {
 +                "debug": "4"
 +            }
 +        },
 +        "ajv": {
 +            "version": "6.12.6",
 +            "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
 +            "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
 +            "dev": true,
 +            "requires": {
 +                "fast-deep-equal": "^3.1.1",
 +                "fast-json-stable-stringify": "^2.0.0",
 +                "json-schema-traverse": "^0.4.1",
 +                "uri-js": "^4.2.2"
 +            }
 +        },
 +        "ansi-regex": {
 +            "version": "5.0.1",
 +            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
 +            "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
 +        },
 +        "ansi-styles": {
 +            "version": "4.3.0",
 +            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
 +            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
 +            "requires": {
 +                "color-convert": "^2.0.1"
 +            }
 +        },
 +        "argparse": {
 +            "version": "2.0.1",
 +            "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
 +            "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
 +            "dev": true
 +        },
 +        "array-union": {
 +            "version": "2.1.0",
 +            "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
 +            "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
 +            "dev": true
 +        },
 +        "azure-devops-node-api": {
 +            "version": "11.2.0",
 +            "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz",
 +            "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==",
 +            "dev": true,
 +            "requires": {
 +                "tunnel": "0.0.6",
 +                "typed-rest-client": "^1.8.4"
 +            }
 +        },
 +        "balanced-match": {
 +            "version": "1.0.2",
 +            "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
 +            "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
 +        },
 +        "base64-js": {
 +            "version": "1.5.1",
 +            "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
 +            "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
 +            "dev": true
 +        },
 +        "big-integer": {
 +            "version": "1.6.51",
 +            "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
 +            "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
 +            "dev": true
 +        },
 +        "binary": {
 +            "version": "0.3.0",
 +            "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz",
 +            "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==",
 +            "dev": true,
 +            "requires": {
 +                "buffers": "~0.1.1",
 +                "chainsaw": "~0.1.0"
 +            }
 +        },
 +        "bl": {
 +            "version": "4.1.0",
 +            "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
 +            "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
 +            "dev": true,
 +            "requires": {
 +                "buffer": "^5.5.0",
 +                "inherits": "^2.0.4",
 +                "readable-stream": "^3.4.0"
 +            },
 +            "dependencies": {
 +                "readable-stream": {
 +                    "version": "3.6.0",
 +                    "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
 +                    "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
 +                    "dev": true,
 +                    "requires": {
 +                        "inherits": "^2.0.3",
 +                        "string_decoder": "^1.1.1",
 +                        "util-deprecate": "^1.0.1"
 +                    }
 +                }
 +            }
 +        },
 +        "bluebird": {
 +            "version": "3.4.7",
 +            "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
 +            "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==",
 +            "dev": true
 +        },
 +        "boolbase": {
 +            "version": "1.0.0",
 +            "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
 +            "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
 +            "dev": true
 +        },
 +        "brace-expansion": {
 +            "version": "1.1.11",
 +            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
 +            "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
 +            "requires": {
 +                "balanced-match": "^1.0.0",
 +                "concat-map": "0.0.1"
 +            }
 +        },
 +        "braces": {
 +            "version": "3.0.2",
 +            "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
 +            "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
 +            "dev": true,
 +            "requires": {
 +                "fill-range": "^7.0.1"
 +            }
 +        },
 +        "buffer": {
 +            "version": "5.7.1",
 +            "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
 +            "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
 +            "dev": true,
 +            "requires": {
 +                "base64-js": "^1.3.1",
 +                "ieee754": "^1.1.13"
 +            }
 +        },
 +        "buffer-crc32": {
 +            "version": "0.2.13",
 +            "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
 +            "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
 +            "dev": true
 +        },
 +        "buffer-indexof-polyfill": {
 +            "version": "1.0.2",
 +            "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz",
 +            "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==",
 +            "dev": true
 +        },
 +        "buffers": {
 +            "version": "0.1.1",
 +            "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
 +            "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==",
 +            "dev": true
 +        },
 +        "call-bind": {
 +            "version": "1.0.2",
 +            "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
 +            "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
 +            "dev": true,
 +            "requires": {
 +                "function-bind": "^1.1.1",
 +                "get-intrinsic": "^1.0.2"
 +            }
 +        },
 +        "callsites": {
 +            "version": "3.1.0",
 +            "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
 +            "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
 +            "dev": true
 +        },
 +        "chainsaw": {
 +            "version": "0.1.0",
 +            "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
 +            "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==",
 +            "dev": true,
 +            "requires": {
 +                "traverse": ">=0.3.0 <0.4"
 +            }
 +        },
 +        "chalk": {
 +            "version": "4.1.2",
 +            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
 +            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
 +            "dev": true,
 +            "requires": {
 +                "ansi-styles": "^4.1.0",
 +                "supports-color": "^7.1.0"
 +            }
 +        },
 +        "cheerio": {
 +            "version": "1.0.0-rc.12",
 +            "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
 +            "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
 +            "dev": true,
 +            "requires": {
 +                "cheerio-select": "^2.1.0",
 +                "dom-serializer": "^2.0.0",
 +                "domhandler": "^5.0.3",
 +                "domutils": "^3.0.1",
 +                "htmlparser2": "^8.0.1",
 +                "parse5": "^7.0.0",
 +                "parse5-htmlparser2-tree-adapter": "^7.0.0"
 +            }
 +        },
 +        "cheerio-select": {
 +            "version": "2.1.0",
 +            "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
 +            "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
 +            "dev": true,
 +            "requires": {
 +                "boolbase": "^1.0.0",
 +                "css-select": "^5.1.0",
 +                "css-what": "^6.1.0",
 +                "domelementtype": "^2.3.0",
 +                "domhandler": "^5.0.3",
 +                "domutils": "^3.0.1"
 +            }
 +        },
 +        "chownr": {
 +            "version": "1.1.4",
 +            "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
 +            "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
 +            "dev": true
 +        },
 +        "ci-info": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
 +            "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
 +            "dev": true
 +        },
 +        "cliui": {
 +            "version": "7.0.4",
 +            "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
 +            "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
 +            "requires": {
 +                "string-width": "^4.2.0",
 +                "strip-ansi": "^6.0.0",
 +                "wrap-ansi": "^7.0.0"
 +            }
 +        },
 +        "color-convert": {
 +            "version": "2.0.1",
 +            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
 +            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
 +            "requires": {
 +                "color-name": "~1.1.4"
 +            }
 +        },
 +        "color-name": {
 +            "version": "1.1.4",
 +            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
 +            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
 +        },
 +        "commander": {
 +            "version": "7.2.0",
 +            "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
 +            "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="
 +        },
 +        "concat-map": {
 +            "version": "0.0.1",
 +            "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
 +            "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
 +        },
 +        "core-util-is": {
 +            "version": "1.0.3",
 +            "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
 +            "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
 +            "dev": true
 +        },
 +        "cross-env": {
 +            "version": "7.0.3",
 +            "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
 +            "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
 +            "dev": true,
 +            "requires": {
 +                "cross-spawn": "^7.0.1"
 +            }
 +        },
 +        "cross-spawn": {
 +            "version": "7.0.3",
 +            "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
 +            "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
 +            "dev": true,
 +            "requires": {
 +                "path-key": "^3.1.0",
 +                "shebang-command": "^2.0.0",
 +                "which": "^2.0.1"
 +            }
 +        },
 +        "css-select": {
 +            "version": "5.1.0",
 +            "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
 +            "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
 +            "dev": true,
 +            "requires": {
 +                "boolbase": "^1.0.0",
 +                "css-what": "^6.1.0",
 +                "domhandler": "^5.0.2",
 +                "domutils": "^3.0.1",
 +                "nth-check": "^2.0.1"
 +            }
 +        },
 +        "css-what": {
 +            "version": "6.1.0",
 +            "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
 +            "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
 +            "dev": true
 +        },
 +        "d3": {
 +            "version": "7.6.1",
 +            "resolved": "https://registry.npmjs.org/d3/-/d3-7.6.1.tgz",
 +            "integrity": "sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw==",
 +            "requires": {
 +                "d3-array": "3",
 +                "d3-axis": "3",
 +                "d3-brush": "3",
 +                "d3-chord": "3",
 +                "d3-color": "3",
 +                "d3-contour": "4",
 +                "d3-delaunay": "6",
 +                "d3-dispatch": "3",
 +                "d3-drag": "3",
 +                "d3-dsv": "3",
 +                "d3-ease": "3",
 +                "d3-fetch": "3",
 +                "d3-force": "3",
 +                "d3-format": "3",
 +                "d3-geo": "3",
 +                "d3-hierarchy": "3",
 +                "d3-interpolate": "3",
 +                "d3-path": "3",
 +                "d3-polygon": "3",
 +                "d3-quadtree": "3",
 +                "d3-random": "3",
 +                "d3-scale": "4",
 +                "d3-scale-chromatic": "3",
 +                "d3-selection": "3",
 +                "d3-shape": "3",
 +                "d3-time": "3",
 +                "d3-time-format": "4",
 +                "d3-timer": "3",
 +                "d3-transition": "3",
 +                "d3-zoom": "3"
 +            },
 +            "dependencies": {
 +                "d3-selection": {
 +                    "version": "3.0.0",
 +                    "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
 +                    "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="
 +                }
 +            }
 +        },
 +        "d3-array": {
 +            "version": "3.2.0",
 +            "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.0.tgz",
 +            "integrity": "sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==",
 +            "requires": {
 +                "internmap": "1 - 2"
 +            }
 +        },
 +        "d3-axis": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz",
 +            "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw=="
 +        },
 +        "d3-brush": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz",
 +            "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==",
 +            "requires": {
 +                "d3-dispatch": "1 - 3",
 +                "d3-drag": "2 - 3",
 +                "d3-interpolate": "1 - 3",
 +                "d3-selection": "3",
 +                "d3-transition": "3"
 +            },
 +            "dependencies": {
 +                "d3-selection": {
 +                    "version": "3.0.0",
 +                    "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
 +                    "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="
 +                }
 +            }
 +        },
 +        "d3-chord": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz",
 +            "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==",
 +            "requires": {
 +                "d3-path": "1 - 3"
 +            }
 +        },
 +        "d3-color": {
 +            "version": "3.1.0",
 +            "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
 +            "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="
 +        },
 +        "d3-contour": {
 +            "version": "4.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.0.tgz",
 +            "integrity": "sha512-7aQo0QHUTu/Ko3cP9YK9yUTxtoDEiDGwnBHyLxG5M4vqlBkO/uixMRele3nfsfj6UXOcuReVpVXzAboGraYIJw==",
 +            "requires": {
 +                "d3-array": "^3.2.0"
 +            }
 +        },
 +        "d3-delaunay": {
 +            "version": "6.0.2",
 +            "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz",
 +            "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==",
 +            "requires": {
 +                "delaunator": "5"
 +            }
 +        },
 +        "d3-dispatch": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
 +            "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="
 +        },
 +        "d3-drag": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
 +            "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
 +            "requires": {
 +                "d3-dispatch": "1 - 3",
 +                "d3-selection": "3"
 +            },
 +            "dependencies": {
 +                "d3-selection": {
 +                    "version": "3.0.0",
 +                    "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
 +                    "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="
 +                }
 +            }
 +        },
 +        "d3-dsv": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz",
 +            "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==",
 +            "requires": {
 +                "commander": "7",
 +                "iconv-lite": "0.6",
 +                "rw": "1"
 +            }
 +        },
 +        "d3-ease": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
 +            "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="
 +        },
 +        "d3-fetch": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz",
 +            "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==",
 +            "requires": {
 +                "d3-dsv": "1 - 3"
 +            }
 +        },
 +        "d3-force": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
 +            "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
 +            "requires": {
 +                "d3-dispatch": "1 - 3",
 +                "d3-quadtree": "1 - 3",
 +                "d3-timer": "1 - 3"
 +            }
 +        },
 +        "d3-format": {
 +            "version": "3.1.0",
 +            "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
 +            "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA=="
 +        },
 +        "d3-geo": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.0.1.tgz",
 +            "integrity": "sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==",
 +            "requires": {
 +                "d3-array": "2.5.0 - 3"
 +            }
 +        },
 +        "d3-graphviz": {
 +            "version": "4.1.1",
 +            "resolved": "https://registry.npmjs.org/d3-graphviz/-/d3-graphviz-4.1.1.tgz",
 +            "integrity": "sha512-s0IVbKf8rs4eJI2xo5Umr7nXDX/LEZw/x2WtKxmlyQxR0qUY49UiLhBNOX7VDHZywMle43NKEXnU6fn22fpJvQ==",
 +            "requires": {
 +                "@hpcc-js/wasm": "1.12.8",
 +                "d3-dispatch": "^2.0.0",
 +                "d3-format": "^2.0.0",
 +                "d3-interpolate": "^2.0.1",
 +                "d3-path": "^2.0.0",
 +                "d3-timer": "^2.0.0",
 +                "d3-transition": "^2.0.0",
 +                "d3-zoom": "^2.0.0"
 +            },
 +            "dependencies": {
 +                "d3-color": {
 +                    "version": "2.0.0",
 +                    "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz",
 +                    "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ=="
 +                },
 +                "d3-dispatch": {
 +                    "version": "2.0.0",
 +                    "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz",
 +                    "integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA=="
 +                },
 +                "d3-drag": {
 +                    "version": "2.0.0",
 +                    "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-2.0.0.tgz",
 +                    "integrity": "sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==",
 +                    "requires": {
 +                        "d3-dispatch": "1 - 2",
 +                        "d3-selection": "2"
 +                    }
 +                },
 +                "d3-ease": {
 +                    "version": "2.0.0",
 +                    "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz",
 +                    "integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ=="
 +                },
 +                "d3-format": {
 +                    "version": "2.0.0",
 +                    "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz",
 +                    "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA=="
 +                },
 +                "d3-interpolate": {
 +                    "version": "2.0.1",
 +                    "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz",
 +                    "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==",
 +                    "requires": {
 +                        "d3-color": "1 - 2"
 +                    }
 +                },
 +                "d3-path": {
 +                    "version": "2.0.0",
 +                    "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz",
 +                    "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA=="
 +                },
 +                "d3-timer": {
 +                    "version": "2.0.0",
 +                    "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz",
 +                    "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA=="
 +                },
 +                "d3-transition": {
 +                    "version": "2.0.0",
 +                    "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz",
 +                    "integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==",
 +                    "requires": {
 +                        "d3-color": "1 - 2",
 +                        "d3-dispatch": "1 - 2",
 +                        "d3-ease": "1 - 2",
 +                        "d3-interpolate": "1 - 2",
 +                        "d3-timer": "1 - 2"
 +                    }
 +                },
 +                "d3-zoom": {
 +                    "version": "2.0.0",
 +                    "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz",
 +                    "integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==",
 +                    "requires": {
 +                        "d3-dispatch": "1 - 2",
 +                        "d3-drag": "2",
 +                        "d3-interpolate": "1 - 2",
 +                        "d3-selection": "2",
 +                        "d3-transition": "2"
 +                    }
 +                }
 +            }
 +        },
 +        "d3-hierarchy": {
 +            "version": "3.1.2",
 +            "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
 +            "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA=="
 +        },
 +        "d3-interpolate": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
 +            "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
 +            "requires": {
 +                "d3-color": "1 - 3"
 +            }
 +        },
 +        "d3-path": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz",
 +            "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w=="
 +        },
 +        "d3-polygon": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz",
 +            "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg=="
 +        },
 +        "d3-quadtree": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
 +            "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw=="
 +        },
 +        "d3-random": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz",
 +            "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ=="
 +        },
 +        "d3-scale": {
 +            "version": "4.0.2",
 +            "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
 +            "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
 +            "requires": {
 +                "d3-array": "2.10.0 - 3",
 +                "d3-format": "1 - 3",
 +                "d3-interpolate": "1.2.0 - 3",
 +                "d3-time": "2.1.1 - 3",
 +                "d3-time-format": "2 - 4"
 +            }
 +        },
 +        "d3-scale-chromatic": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz",
 +            "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==",
 +            "requires": {
 +                "d3-color": "1 - 3",
 +                "d3-interpolate": "1 - 3"
 +            }
 +        },
 +        "d3-selection": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz",
 +            "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA=="
 +        },
 +        "d3-shape": {
 +            "version": "3.1.0",
 +            "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.1.0.tgz",
 +            "integrity": "sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==",
 +            "requires": {
 +                "d3-path": "1 - 3"
 +            }
 +        },
 +        "d3-time": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz",
 +            "integrity": "sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==",
 +            "requires": {
 +                "d3-array": "2 - 3"
 +            }
 +        },
 +        "d3-time-format": {
 +            "version": "4.1.0",
 +            "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
 +            "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
 +            "requires": {
 +                "d3-time": "1 - 3"
 +            }
 +        },
 +        "d3-timer": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
 +            "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="
 +        },
 +        "d3-transition": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
 +            "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
 +            "requires": {
 +                "d3-color": "1 - 3",
 +                "d3-dispatch": "1 - 3",
 +                "d3-ease": "1 - 3",
 +                "d3-interpolate": "1 - 3",
 +                "d3-timer": "1 - 3"
 +            }
 +        },
 +        "d3-zoom": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
 +            "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
 +            "requires": {
 +                "d3-dispatch": "1 - 3",
 +                "d3-drag": "2 - 3",
 +                "d3-interpolate": "1 - 3",
 +                "d3-selection": "2 - 3",
 +                "d3-transition": "2 - 3"
 +            }
 +        },
 +        "debug": {
 +            "version": "4.3.4",
 +            "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
 +            "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
 +            "dev": true,
 +            "requires": {
 +                "ms": "2.1.2"
 +            }
 +        },
 +        "decompress-response": {
 +            "version": "6.0.0",
 +            "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
 +            "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
 +            "dev": true,
 +            "requires": {
 +                "mimic-response": "^3.1.0"
 +            }
 +        },
 +        "deep-extend": {
 +            "version": "0.6.0",
 +            "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
 +            "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
 +            "dev": true
 +        },
 +        "deep-is": {
 +            "version": "0.1.4",
 +            "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
 +            "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
 +            "dev": true
 +        },
 +        "delaunator": {
 +            "version": "5.0.0",
 +            "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz",
 +            "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==",
 +            "requires": {
 +                "robust-predicates": "^3.0.0"
 +            }
 +        },
 +        "detect-libc": {
 +            "version": "2.0.1",
 +            "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
 +            "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==",
 +            "dev": true
 +        },
 +        "dir-glob": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
 +            "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
 +            "dev": true,
 +            "requires": {
 +                "path-type": "^4.0.0"
 +            }
 +        },
 +        "doctrine": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
 +            "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
 +            "dev": true,
 +            "requires": {
 +                "esutils": "^2.0.2"
 +            }
 +        },
 +        "dom-serializer": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
 +            "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
 +            "dev": true,
 +            "requires": {
 +                "domelementtype": "^2.3.0",
 +                "domhandler": "^5.0.2",
 +                "entities": "^4.2.0"
 +            }
 +        },
 +        "domelementtype": {
 +            "version": "2.3.0",
 +            "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
 +            "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
 +            "dev": true
 +        },
 +        "domhandler": {
 +            "version": "5.0.3",
 +            "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
 +            "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
 +            "dev": true,
 +            "requires": {
 +                "domelementtype": "^2.3.0"
 +            }
 +        },
 +        "domutils": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
 +            "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
 +            "dev": true,
 +            "requires": {
 +                "dom-serializer": "^2.0.0",
 +                "domelementtype": "^2.3.0",
 +                "domhandler": "^5.0.1"
 +            }
 +        },
 +        "duplexer2": {
 +            "version": "0.1.4",
 +            "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
 +            "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==",
 +            "dev": true,
 +            "requires": {
 +                "readable-stream": "^2.0.2"
 +            }
 +        },
 +        "emoji-regex": {
 +            "version": "8.0.0",
 +            "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
 +            "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
 +        },
 +        "end-of-stream": {
 +            "version": "1.4.4",
 +            "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
 +            "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
 +            "dev": true,
 +            "requires": {
 +                "once": "^1.4.0"
 +            }
 +        },
 +        "entities": {
 +            "version": "4.3.1",
 +            "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz",
 +            "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==",
 +            "dev": true
 +        },
 +        "esbuild": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz",
 +            "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==",
 +            "dev": true,
 +            "requires": {
 +                "esbuild-android-64": "0.14.48",
 +                "esbuild-android-arm64": "0.14.48",
 +                "esbuild-darwin-64": "0.14.48",
 +                "esbuild-darwin-arm64": "0.14.48",
 +                "esbuild-freebsd-64": "0.14.48",
 +                "esbuild-freebsd-arm64": "0.14.48",
 +                "esbuild-linux-32": "0.14.48",
 +                "esbuild-linux-64": "0.14.48",
 +                "esbuild-linux-arm": "0.14.48",
 +                "esbuild-linux-arm64": "0.14.48",
 +                "esbuild-linux-mips64le": "0.14.48",
 +                "esbuild-linux-ppc64le": "0.14.48",
 +                "esbuild-linux-riscv64": "0.14.48",
 +                "esbuild-linux-s390x": "0.14.48",
 +                "esbuild-netbsd-64": "0.14.48",
 +                "esbuild-openbsd-64": "0.14.48",
 +                "esbuild-sunos-64": "0.14.48",
 +                "esbuild-windows-32": "0.14.48",
 +                "esbuild-windows-64": "0.14.48",
 +                "esbuild-windows-arm64": "0.14.48"
 +            }
 +        },
 +        "esbuild-android-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz",
 +            "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-android-arm64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz",
 +            "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-darwin-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz",
 +            "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-darwin-arm64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz",
 +            "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-freebsd-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz",
 +            "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-freebsd-arm64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz",
 +            "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-linux-32": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz",
 +            "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-linux-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz",
 +            "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-linux-arm": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz",
 +            "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-linux-arm64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz",
 +            "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-linux-mips64le": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz",
 +            "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-linux-ppc64le": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz",
 +            "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-linux-riscv64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz",
 +            "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-linux-s390x": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz",
 +            "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-netbsd-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz",
 +            "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-openbsd-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz",
 +            "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-sunos-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz",
 +            "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-windows-32": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz",
 +            "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-windows-64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz",
 +            "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "esbuild-windows-arm64": {
 +            "version": "0.14.48",
 +            "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz",
 +            "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==",
 +            "dev": true,
 +            "optional": true
 +        },
 +        "escalade": {
 +            "version": "3.1.1",
 +            "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
 +            "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
 +        },
 +        "escape-string-regexp": {
 +            "version": "4.0.0",
 +            "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
 +            "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
 +            "dev": true
 +        },
 +        "eslint": {
 +            "version": "8.19.0",
 +            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz",
 +            "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==",
 +            "dev": true,
 +            "requires": {
 +                "@eslint/eslintrc": "^1.3.0",
 +                "@humanwhocodes/config-array": "^0.9.2",
 +                "ajv": "^6.10.0",
 +                "chalk": "^4.0.0",
 +                "cross-spawn": "^7.0.2",
 +                "debug": "^4.3.2",
 +                "doctrine": "^3.0.0",
 +                "escape-string-regexp": "^4.0.0",
 +                "eslint-scope": "^7.1.1",
 +                "eslint-utils": "^3.0.0",
 +                "eslint-visitor-keys": "^3.3.0",
 +                "espree": "^9.3.2",
 +                "esquery": "^1.4.0",
 +                "esutils": "^2.0.2",
 +                "fast-deep-equal": "^3.1.3",
 +                "file-entry-cache": "^6.0.1",
 +                "functional-red-black-tree": "^1.0.1",
 +                "glob-parent": "^6.0.1",
 +                "globals": "^13.15.0",
 +                "ignore": "^5.2.0",
 +                "import-fresh": "^3.0.0",
 +                "imurmurhash": "^0.1.4",
 +                "is-glob": "^4.0.0",
 +                "js-yaml": "^4.1.0",
 +                "json-stable-stringify-without-jsonify": "^1.0.1",
 +                "levn": "^0.4.1",
 +                "lodash.merge": "^4.6.2",
 +                "minimatch": "^3.1.2",
 +                "natural-compare": "^1.4.0",
 +                "optionator": "^0.9.1",
 +                "regexpp": "^3.2.0",
 +                "strip-ansi": "^6.0.1",
 +                "strip-json-comments": "^3.1.0",
 +                "text-table": "^0.2.0",
 +                "v8-compile-cache": "^2.0.3"
 +            },
 +            "dependencies": {
 +                "eslint-scope": {
 +                    "version": "7.1.1",
 +                    "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
 +                    "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
 +                    "dev": true,
 +                    "requires": {
 +                        "esrecurse": "^4.3.0",
 +                        "estraverse": "^5.2.0"
 +                    }
 +                },
 +                "estraverse": {
 +                    "version": "5.3.0",
 +                    "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
 +                    "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
 +                    "dev": true
 +                }
 +            }
 +        },
 +        "eslint-config-prettier": {
 +            "version": "8.5.0",
 +            "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
 +            "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
 +            "dev": true,
 +            "requires": {}
 +        },
 +        "eslint-scope": {
 +            "version": "5.1.1",
 +            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
 +            "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
 +            "dev": true,
 +            "requires": {
 +                "esrecurse": "^4.3.0",
 +                "estraverse": "^4.1.1"
 +            }
 +        },
 +        "eslint-utils": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
 +            "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
 +            "dev": true,
 +            "requires": {
 +                "eslint-visitor-keys": "^2.0.0"
 +            },
 +            "dependencies": {
 +                "eslint-visitor-keys": {
 +                    "version": "2.1.0",
 +                    "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
 +                    "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
 +                    "dev": true
 +                }
 +            }
 +        },
 +        "eslint-visitor-keys": {
 +            "version": "3.3.0",
 +            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
 +            "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
 +            "dev": true
 +        },
 +        "espree": {
 +            "version": "9.3.2",
 +            "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz",
 +            "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==",
 +            "dev": true,
 +            "requires": {
 +                "acorn": "^8.7.1",
 +                "acorn-jsx": "^5.3.2",
 +                "eslint-visitor-keys": "^3.3.0"
 +            }
 +        },
 +        "esquery": {
 +            "version": "1.4.0",
 +            "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
 +            "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
 +            "dev": true,
 +            "requires": {
 +                "estraverse": "^5.1.0"
 +            },
 +            "dependencies": {
 +                "estraverse": {
 +                    "version": "5.3.0",
 +                    "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
 +                    "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
 +                    "dev": true
 +                }
 +            }
 +        },
 +        "esrecurse": {
 +            "version": "4.3.0",
 +            "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
 +            "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
 +            "dev": true,
 +            "requires": {
 +                "estraverse": "^5.2.0"
 +            },
 +            "dependencies": {
 +                "estraverse": {
 +                    "version": "5.3.0",
 +                    "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
 +                    "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
 +                    "dev": true
 +                }
 +            }
 +        },
 +        "estraverse": {
 +            "version": "4.3.0",
 +            "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
 +            "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
 +            "dev": true
 +        },
 +        "esutils": {
 +            "version": "2.0.3",
 +            "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
 +            "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
 +            "dev": true
 +        },
 +        "expand-template": {
 +            "version": "2.0.3",
 +            "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
 +            "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
 +            "dev": true
 +        },
 +        "fast-deep-equal": {
 +            "version": "3.1.3",
 +            "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
 +            "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
 +            "dev": true
 +        },
 +        "fast-glob": {
 +            "version": "3.2.11",
 +            "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
 +            "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==",
 +            "dev": true,
 +            "requires": {
 +                "@nodelib/fs.stat": "^2.0.2",
 +                "@nodelib/fs.walk": "^1.2.3",
 +                "glob-parent": "^5.1.2",
 +                "merge2": "^1.3.0",
 +                "micromatch": "^4.0.4"
 +            },
 +            "dependencies": {
 +                "glob-parent": {
 +                    "version": "5.1.2",
 +                    "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
 +                    "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
 +                    "dev": true,
 +                    "requires": {
 +                        "is-glob": "^4.0.1"
 +                    }
 +                }
 +            }
 +        },
 +        "fast-json-stable-stringify": {
 +            "version": "2.1.0",
 +            "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
 +            "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
 +            "dev": true
 +        },
 +        "fast-levenshtein": {
 +            "version": "2.0.6",
 +            "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
 +            "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
 +            "dev": true
 +        },
 +        "fastq": {
 +            "version": "1.13.0",
 +            "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
 +            "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
 +            "dev": true,
 +            "requires": {
 +                "reusify": "^1.0.4"
 +            }
 +        },
 +        "fd-slicer": {
 +            "version": "1.1.0",
 +            "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
 +            "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
 +            "dev": true,
 +            "requires": {
 +                "pend": "~1.2.0"
 +            }
 +        },
 +        "file-entry-cache": {
 +            "version": "6.0.1",
 +            "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
 +            "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
 +            "dev": true,
 +            "requires": {
 +                "flat-cache": "^3.0.4"
 +            }
 +        },
 +        "fill-range": {
 +            "version": "7.0.1",
 +            "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
 +            "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
 +            "dev": true,
 +            "requires": {
 +                "to-regex-range": "^5.0.1"
 +            }
 +        },
 +        "flat-cache": {
 +            "version": "3.0.4",
 +            "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
 +            "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
 +            "dev": true,
 +            "requires": {
 +                "flatted": "^3.1.0",
 +                "rimraf": "^3.0.2"
 +            }
 +        },
 +        "flatted": {
 +            "version": "3.2.6",
 +            "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz",
 +            "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==",
 +            "dev": true
 +        },
 +        "follow-redirects": {
 +            "version": "1.15.1",
 +            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
 +            "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
 +            "dev": true
 +        },
 +        "fs-constants": {
 +            "version": "1.0.0",
 +            "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
 +            "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
 +            "dev": true
 +        },
 +        "fs.realpath": {
 +            "version": "1.0.0",
 +            "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
 +            "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
 +            "dev": true
 +        },
 +        "fstream": {
 +            "version": "1.0.12",
 +            "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
 +            "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
 +            "dev": true,
 +            "requires": {
 +                "graceful-fs": "^4.1.2",
 +                "inherits": "~2.0.0",
 +                "mkdirp": ">=0.5 0",
 +                "rimraf": "2"
 +            },
 +            "dependencies": {
 +                "rimraf": {
 +                    "version": "2.7.1",
 +                    "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
 +                    "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
 +                    "dev": true,
 +                    "requires": {
 +                        "glob": "^7.1.3"
 +                    }
 +                }
 +            }
 +        },
 +        "function-bind": {
 +            "version": "1.1.1",
 +            "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
 +            "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
 +            "dev": true
 +        },
 +        "functional-red-black-tree": {
 +            "version": "1.0.1",
 +            "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
 +            "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
 +            "dev": true
 +        },
 +        "get-caller-file": {
 +            "version": "2.0.5",
 +            "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
 +            "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
 +        },
 +        "get-intrinsic": {
 +            "version": "1.1.2",
 +            "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz",
 +            "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==",
 +            "dev": true,
 +            "requires": {
 +                "function-bind": "^1.1.1",
 +                "has": "^1.0.3",
 +                "has-symbols": "^1.0.3"
 +            }
 +        },
 +        "github-from-package": {
 +            "version": "0.0.0",
 +            "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
 +            "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
 +            "dev": true
 +        },
 +        "glob": {
 +            "version": "7.2.3",
 +            "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
 +            "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
 +            "dev": true,
 +            "requires": {
 +                "fs.realpath": "^1.0.0",
 +                "inflight": "^1.0.4",
 +                "inherits": "2",
 +                "minimatch": "^3.1.1",
 +                "once": "^1.3.0",
 +                "path-is-absolute": "^1.0.0"
 +            }
 +        },
 +        "glob-parent": {
 +            "version": "6.0.2",
 +            "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
 +            "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
 +            "dev": true,
 +            "requires": {
 +                "is-glob": "^4.0.3"
 +            }
 +        },
 +        "globals": {
 +            "version": "13.16.0",
 +            "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz",
 +            "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==",
 +            "dev": true,
 +            "requires": {
 +                "type-fest": "^0.20.2"
 +            }
 +        },
 +        "globby": {
 +            "version": "11.1.0",
 +            "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
 +            "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
 +            "dev": true,
 +            "requires": {
 +                "array-union": "^2.1.0",
 +                "dir-glob": "^3.0.1",
 +                "fast-glob": "^3.2.9",
 +                "ignore": "^5.2.0",
 +                "merge2": "^1.4.1",
 +                "slash": "^3.0.0"
 +            }
 +        },
 +        "graceful-fs": {
 +            "version": "4.2.10",
 +            "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
 +            "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
 +            "dev": true
 +        },
 +        "has": {
 +            "version": "1.0.3",
 +            "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
 +            "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
 +            "dev": true,
 +            "requires": {
 +                "function-bind": "^1.1.1"
 +            }
 +        },
 +        "has-flag": {
 +            "version": "4.0.0",
 +            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
 +            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
 +            "dev": true
 +        },
 +        "has-symbols": {
 +            "version": "1.0.3",
 +            "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
 +            "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
 +            "dev": true
 +        },
 +        "hosted-git-info": {
 +            "version": "4.1.0",
 +            "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
 +            "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
 +            "dev": true,
 +            "requires": {
 +                "lru-cache": "^6.0.0"
 +            }
 +        },
 +        "htmlparser2": {
 +            "version": "8.0.1",
 +            "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz",
 +            "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==",
 +            "dev": true,
 +            "requires": {
 +                "domelementtype": "^2.3.0",
 +                "domhandler": "^5.0.2",
 +                "domutils": "^3.0.1",
 +                "entities": "^4.3.0"
 +            }
 +        },
 +        "http-proxy-agent": {
 +            "version": "4.0.1",
 +            "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
 +            "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
 +            "dev": true,
 +            "requires": {
 +                "@tootallnate/once": "1",
 +                "agent-base": "6",
 +                "debug": "4"
 +            }
 +        },
 +        "https-proxy-agent": {
 +            "version": "5.0.1",
 +            "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
 +            "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
 +            "dev": true,
 +            "requires": {
 +                "agent-base": "6",
 +                "debug": "4"
 +            }
 +        },
 +        "iconv-lite": {
 +            "version": "0.6.3",
 +            "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
 +            "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
 +            "requires": {
 +                "safer-buffer": ">= 2.1.2 < 3.0.0"
 +            }
 +        },
 +        "ieee754": {
 +            "version": "1.2.1",
 +            "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
 +            "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
 +            "dev": true
 +        },
 +        "ignore": {
 +            "version": "5.2.0",
 +            "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
 +            "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
 +            "dev": true
 +        },
 +        "import-fresh": {
 +            "version": "3.3.0",
 +            "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
 +            "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
 +            "dev": true,
 +            "requires": {
 +                "parent-module": "^1.0.0",
 +                "resolve-from": "^4.0.0"
 +            }
 +        },
 +        "imurmurhash": {
 +            "version": "0.1.4",
 +            "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
 +            "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
 +            "dev": true
 +        },
 +        "inflight": {
 +            "version": "1.0.6",
 +            "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
 +            "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
 +            "dev": true,
 +            "requires": {
 +                "once": "^1.3.0",
 +                "wrappy": "1"
 +            }
 +        },
 +        "inherits": {
 +            "version": "2.0.4",
 +            "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
 +            "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
 +            "dev": true
 +        },
 +        "ini": {
 +            "version": "1.3.8",
 +            "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
 +            "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
 +            "dev": true
 +        },
 +        "internmap": {
 +            "version": "2.0.3",
 +            "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
 +            "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="
 +        },
 +        "is-ci": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
 +            "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
 +            "dev": true,
 +            "requires": {
 +                "ci-info": "^2.0.0"
 +            }
 +        },
 +        "is-extglob": {
 +            "version": "2.1.1",
 +            "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
 +            "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
 +            "dev": true
 +        },
 +        "is-fullwidth-code-point": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
 +            "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
 +        },
 +        "is-glob": {
 +            "version": "4.0.3",
 +            "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
 +            "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
 +            "dev": true,
 +            "requires": {
 +                "is-extglob": "^2.1.1"
 +            }
 +        },
 +        "is-number": {
 +            "version": "7.0.0",
 +            "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
 +            "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
 +            "dev": true
 +        },
 +        "isarray": {
 +            "version": "1.0.0",
 +            "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
 +            "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
 +            "dev": true
 +        },
 +        "isexe": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
 +            "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
 +            "dev": true
 +        },
 +        "js-yaml": {
 +            "version": "4.1.0",
 +            "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
 +            "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
 +            "dev": true,
 +            "requires": {
 +                "argparse": "^2.0.1"
 +            }
 +        },
 +        "json-schema-traverse": {
 +            "version": "0.4.1",
 +            "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
 +            "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
 +            "dev": true
 +        },
 +        "json-stable-stringify-without-jsonify": {
 +            "version": "1.0.1",
 +            "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
 +            "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
 +            "dev": true
 +        },
 +        "keytar": {
 +            "version": "7.9.0",
 +            "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz",
 +            "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==",
 +            "dev": true,
 +            "requires": {
 +                "node-addon-api": "^4.3.0",
 +                "prebuild-install": "^7.0.1"
 +            }
 +        },
 +        "leven": {
 +            "version": "3.1.0",
 +            "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
 +            "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
 +            "dev": true
 +        },
 +        "levn": {
 +            "version": "0.4.1",
 +            "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
 +            "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
 +            "dev": true,
 +            "requires": {
 +                "prelude-ls": "^1.2.1",
 +                "type-check": "~0.4.0"
 +            }
 +        },
 +        "linkify-it": {
 +            "version": "3.0.3",
 +            "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
 +            "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
 +            "dev": true,
 +            "requires": {
 +                "uc.micro": "^1.0.1"
 +            }
 +        },
 +        "listenercount": {
 +            "version": "1.0.1",
 +            "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz",
 +            "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==",
 +            "dev": true
 +        },
 +        "lodash.merge": {
 +            "version": "4.6.2",
 +            "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
 +            "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
 +            "dev": true
 +        },
 +        "lru-cache": {
 +            "version": "6.0.0",
 +            "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
 +            "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
 +            "requires": {
 +                "yallist": "^4.0.0"
 +            }
 +        },
 +        "markdown-it": {
 +            "version": "12.3.2",
 +            "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
 +            "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
 +            "dev": true,
 +            "requires": {
 +                "argparse": "^2.0.1",
 +                "entities": "~2.1.0",
 +                "linkify-it": "^3.0.1",
 +                "mdurl": "^1.0.1",
 +                "uc.micro": "^1.0.5"
 +            },
 +            "dependencies": {
 +                "entities": {
 +                    "version": "2.1.0",
 +                    "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
 +                    "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
 +                    "dev": true
 +                }
 +            }
 +        },
 +        "mdurl": {
 +            "version": "1.0.1",
 +            "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
 +            "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
 +            "dev": true
 +        },
 +        "merge2": {
 +            "version": "1.4.1",
 +            "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
 +            "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
 +            "dev": true
 +        },
 +        "micromatch": {
 +            "version": "4.0.5",
 +            "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
 +            "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
 +            "dev": true,
 +            "requires": {
 +                "braces": "^3.0.2",
 +                "picomatch": "^2.3.1"
 +            }
 +        },
 +        "mime": {
 +            "version": "1.6.0",
 +            "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
 +            "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
 +            "dev": true
 +        },
 +        "mimic-response": {
 +            "version": "3.1.0",
 +            "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
 +            "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
 +            "dev": true
 +        },
 +        "minimatch": {
 +            "version": "3.1.2",
 +            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
 +            "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
 +            "requires": {
 +                "brace-expansion": "^1.1.7"
 +            }
 +        },
 +        "minimist": {
 +            "version": "1.2.6",
 +            "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
 +            "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
 +            "dev": true
 +        },
 +        "mkdirp": {
 +            "version": "0.5.6",
 +            "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
 +            "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
 +            "dev": true,
 +            "requires": {
 +                "minimist": "^1.2.6"
 +            }
 +        },
 +        "mkdirp-classic": {
 +            "version": "0.5.3",
 +            "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
 +            "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
 +            "dev": true
 +        },
 +        "ms": {
 +            "version": "2.1.2",
 +            "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
 +            "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
 +            "dev": true
 +        },
 +        "mute-stream": {
 +            "version": "0.0.8",
 +            "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
 +            "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
 +            "dev": true
 +        },
 +        "napi-build-utils": {
 +            "version": "1.0.2",
 +            "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
 +            "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
 +            "dev": true
 +        },
 +        "natural-compare": {
 +            "version": "1.4.0",
 +            "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
 +            "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
 +            "dev": true
 +        },
 +        "node-abi": {
 +            "version": "3.22.0",
 +            "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.22.0.tgz",
 +            "integrity": "sha512-u4uAs/4Zzmp/jjsD9cyFYDXeISfUWaAVWshPmDZOFOv4Xl4SbzTXm53I04C2uRueYJ+0t5PEtLH/owbn2Npf/w==",
 +            "dev": true,
 +            "requires": {
 +                "semver": "^7.3.5"
 +            }
 +        },
 +        "node-addon-api": {
 +            "version": "4.3.0",
 +            "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
 +            "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
 +            "dev": true
 +        },
 +        "nth-check": {
 +            "version": "2.1.1",
 +            "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
 +            "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
 +            "dev": true,
 +            "requires": {
 +                "boolbase": "^1.0.0"
 +            }
 +        },
 +        "object-inspect": {
 +            "version": "1.12.2",
 +            "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
 +            "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
 +            "dev": true
 +        },
 +        "once": {
 +            "version": "1.4.0",
 +            "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
 +            "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
 +            "dev": true,
 +            "requires": {
 +                "wrappy": "1"
 +            }
 +        },
 +        "optionator": {
 +            "version": "0.9.1",
 +            "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
 +            "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
 +            "dev": true,
 +            "requires": {
 +                "deep-is": "^0.1.3",
 +                "fast-levenshtein": "^2.0.6",
 +                "levn": "^0.4.1",
 +                "prelude-ls": "^1.2.1",
 +                "type-check": "^0.4.0",
 +                "word-wrap": "^1.2.3"
 +            }
 +        },
 +        "ovsx": {
 +            "version": "0.5.1",
 +            "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.5.1.tgz",
 +            "integrity": "sha512-3OWq0l7DuVHi2bd2aQe5+QVQlFIqvrcw3/2vGXL404L6Tr+R4QHtzfnYYghv8CCa85xJHjU0RhcaC7pyXkAUbg==",
 +            "dev": true,
 +            "requires": {
 +                "commander": "^6.1.0",
 +                "follow-redirects": "^1.14.6",
 +                "is-ci": "^2.0.0",
 +                "leven": "^3.1.0",
 +                "tmp": "^0.2.1",
 +                "vsce": "^2.6.3"
 +            },
 +            "dependencies": {
 +                "commander": {
 +                    "version": "6.2.1",
 +                    "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
 +                    "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
 +                    "dev": true
 +                }
 +            }
 +        },
 +        "parent-module": {
 +            "version": "1.0.1",
 +            "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
 +            "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
 +            "dev": true,
 +            "requires": {
 +                "callsites": "^3.0.0"
 +            }
 +        },
 +        "parse-semver": {
 +            "version": "1.1.1",
 +            "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
 +            "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==",
 +            "dev": true,
 +            "requires": {
 +                "semver": "^5.1.0"
 +            },
 +            "dependencies": {
 +                "semver": {
 +                    "version": "5.7.1",
 +                    "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
 +                    "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
 +                    "dev": true
 +                }
 +            }
 +        },
 +        "parse5": {
 +            "version": "7.0.0",
 +            "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz",
 +            "integrity": "sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==",
 +            "dev": true,
 +            "requires": {
 +                "entities": "^4.3.0"
 +            }
 +        },
 +        "parse5-htmlparser2-tree-adapter": {
 +            "version": "7.0.0",
 +            "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
 +            "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
 +            "dev": true,
 +            "requires": {
 +                "domhandler": "^5.0.2",
 +                "parse5": "^7.0.0"
 +            }
 +        },
 +        "path-is-absolute": {
 +            "version": "1.0.1",
 +            "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
 +            "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
 +            "dev": true
 +        },
 +        "path-key": {
 +            "version": "3.1.1",
 +            "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
 +            "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
 +            "dev": true
 +        },
 +        "path-type": {
 +            "version": "4.0.0",
 +            "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
 +            "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
 +            "dev": true
 +        },
 +        "pend": {
 +            "version": "1.2.0",
 +            "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
 +            "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
 +            "dev": true
 +        },
 +        "picomatch": {
 +            "version": "2.3.1",
 +            "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
 +            "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
 +            "dev": true
 +        },
 +        "prebuild-install": {
 +            "version": "7.1.1",
 +            "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz",
 +            "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==",
 +            "dev": true,
 +            "requires": {
 +                "detect-libc": "^2.0.0",
 +                "expand-template": "^2.0.3",
 +                "github-from-package": "0.0.0",
 +                "minimist": "^1.2.3",
 +                "mkdirp-classic": "^0.5.3",
 +                "napi-build-utils": "^1.0.1",
 +                "node-abi": "^3.3.0",
 +                "pump": "^3.0.0",
 +                "rc": "^1.2.7",
 +                "simple-get": "^4.0.0",
 +                "tar-fs": "^2.0.0",
 +                "tunnel-agent": "^0.6.0"
 +            }
 +        },
 +        "prelude-ls": {
 +            "version": "1.2.1",
 +            "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
 +            "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
 +            "dev": true
 +        },
 +        "prettier": {
 +            "version": "2.7.1",
 +            "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
 +            "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
 +            "dev": true
 +        },
 +        "process-nextick-args": {
 +            "version": "2.0.1",
 +            "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
 +            "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
 +            "dev": true
 +        },
 +        "pump": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
 +            "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
 +            "dev": true,
 +            "requires": {
 +                "end-of-stream": "^1.1.0",
 +                "once": "^1.3.1"
 +            }
 +        },
 +        "punycode": {
 +            "version": "2.1.1",
 +            "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
 +            "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
 +            "dev": true
 +        },
 +        "qs": {
 +            "version": "6.11.0",
 +            "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
 +            "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
 +            "dev": true,
 +            "requires": {
 +                "side-channel": "^1.0.4"
 +            }
 +        },
 +        "queue-microtask": {
 +            "version": "1.2.3",
 +            "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
 +            "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
 +            "dev": true
 +        },
 +        "rc": {
 +            "version": "1.2.8",
 +            "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
 +            "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
 +            "dev": true,
 +            "requires": {
 +                "deep-extend": "^0.6.0",
 +                "ini": "~1.3.0",
 +                "minimist": "^1.2.0",
 +                "strip-json-comments": "~2.0.1"
 +            },
 +            "dependencies": {
 +                "strip-json-comments": {
 +                    "version": "2.0.1",
 +                    "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
 +                    "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
 +                    "dev": true
 +                }
 +            }
 +        },
 +        "read": {
 +            "version": "1.0.7",
 +            "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
 +            "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==",
 +            "dev": true,
 +            "requires": {
 +                "mute-stream": "~0.0.4"
 +            }
 +        },
 +        "readable-stream": {
 +            "version": "2.3.7",
 +            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
 +            "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
 +            "dev": true,
 +            "requires": {
 +                "core-util-is": "~1.0.0",
 +                "inherits": "~2.0.3",
 +                "isarray": "~1.0.0",
 +                "process-nextick-args": "~2.0.0",
 +                "safe-buffer": "~5.1.1",
 +                "string_decoder": "~1.1.1",
 +                "util-deprecate": "~1.0.1"
 +            }
 +        },
 +        "regexpp": {
 +            "version": "3.2.0",
 +            "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
 +            "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
 +            "dev": true
 +        },
 +        "require-directory": {
 +            "version": "2.1.1",
 +            "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
 +            "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="
 +        },
 +        "resolve-from": {
 +            "version": "4.0.0",
 +            "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
 +            "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
 +            "dev": true
 +        },
 +        "reusify": {
 +            "version": "1.0.4",
 +            "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
 +            "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
 +            "dev": true
 +        },
 +        "rimraf": {
 +            "version": "3.0.2",
 +            "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
 +            "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
 +            "dev": true,
 +            "requires": {
 +                "glob": "^7.1.3"
 +            }
 +        },
 +        "robust-predicates": {
 +            "version": "3.0.1",
 +            "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz",
 +            "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g=="
 +        },
 +        "run-parallel": {
 +            "version": "1.2.0",
 +            "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
 +            "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
 +            "dev": true,
 +            "requires": {
 +                "queue-microtask": "^1.2.2"
 +            }
 +        },
 +        "rw": {
 +            "version": "1.3.3",
 +            "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
 +            "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="
 +        },
 +        "safe-buffer": {
 +            "version": "5.1.2",
 +            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
 +            "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
 +            "dev": true
 +        },
 +        "safer-buffer": {
 +            "version": "2.1.2",
 +            "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
 +            "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
 +        },
 +        "sax": {
 +            "version": "1.2.4",
 +            "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
 +            "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
 +            "dev": true
 +        },
 +        "semver": {
 +            "version": "7.3.7",
 +            "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
 +            "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
 +            "requires": {
 +                "lru-cache": "^6.0.0"
 +            }
 +        },
 +        "setimmediate": {
 +            "version": "1.0.5",
 +            "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
 +            "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
 +            "dev": true
 +        },
 +        "shebang-command": {
 +            "version": "2.0.0",
 +            "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
 +            "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
 +            "dev": true,
 +            "requires": {
 +                "shebang-regex": "^3.0.0"
 +            }
 +        },
 +        "shebang-regex": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
 +            "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
 +            "dev": true
 +        },
 +        "side-channel": {
 +            "version": "1.0.4",
 +            "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
 +            "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
 +            "dev": true,
 +            "requires": {
 +                "call-bind": "^1.0.0",
 +                "get-intrinsic": "^1.0.2",
 +                "object-inspect": "^1.9.0"
 +            }
 +        },
 +        "simple-concat": {
 +            "version": "1.0.1",
 +            "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
 +            "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
 +            "dev": true
 +        },
 +        "simple-get": {
 +            "version": "4.0.1",
 +            "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
 +            "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
 +            "dev": true,
 +            "requires": {
 +                "decompress-response": "^6.0.0",
 +                "once": "^1.3.1",
 +                "simple-concat": "^1.0.0"
 +            }
 +        },
 +        "slash": {
 +            "version": "3.0.0",
 +            "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
 +            "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
 +            "dev": true
 +        },
 +        "string_decoder": {
 +            "version": "1.1.1",
 +            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
 +            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
 +            "dev": true,
 +            "requires": {
 +                "safe-buffer": "~5.1.0"
 +            }
 +        },
 +        "string-width": {
 +            "version": "4.2.3",
 +            "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
 +            "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
 +            "requires": {
 +                "emoji-regex": "^8.0.0",
 +                "is-fullwidth-code-point": "^3.0.0",
 +                "strip-ansi": "^6.0.1"
 +            }
 +        },
 +        "strip-ansi": {
 +            "version": "6.0.1",
 +            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
 +            "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
 +            "requires": {
 +                "ansi-regex": "^5.0.1"
 +            }
 +        },
 +        "strip-json-comments": {
 +            "version": "3.1.1",
 +            "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
 +            "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
 +            "dev": true
 +        },
 +        "supports-color": {
 +            "version": "7.2.0",
 +            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
 +            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
 +            "dev": true,
 +            "requires": {
 +                "has-flag": "^4.0.0"
 +            }
 +        },
 +        "tar-fs": {
 +            "version": "2.1.1",
 +            "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
 +            "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
 +            "dev": true,
 +            "requires": {
 +                "chownr": "^1.1.1",
 +                "mkdirp-classic": "^0.5.2",
 +                "pump": "^3.0.0",
 +                "tar-stream": "^2.1.4"
 +            }
 +        },
 +        "tar-stream": {
 +            "version": "2.2.0",
 +            "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
 +            "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
 +            "dev": true,
 +            "requires": {
 +                "bl": "^4.0.3",
 +                "end-of-stream": "^1.4.1",
 +                "fs-constants": "^1.0.0",
 +                "inherits": "^2.0.3",
 +                "readable-stream": "^3.1.1"
 +            },
 +            "dependencies": {
 +                "readable-stream": {
 +                    "version": "3.6.0",
 +                    "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
 +                    "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
 +                    "dev": true,
 +                    "requires": {
 +                        "inherits": "^2.0.3",
 +                        "string_decoder": "^1.1.1",
 +                        "util-deprecate": "^1.0.1"
 +                    }
 +                }
 +            }
 +        },
 +        "text-table": {
 +            "version": "0.2.0",
 +            "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
 +            "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
 +            "dev": true
 +        },
 +        "tmp": {
 +            "version": "0.2.1",
 +            "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
 +            "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
 +            "dev": true,
 +            "requires": {
 +                "rimraf": "^3.0.0"
 +            }
 +        },
 +        "to-regex-range": {
 +            "version": "5.0.1",
 +            "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
 +            "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
 +            "dev": true,
 +            "requires": {
 +                "is-number": "^7.0.0"
 +            }
 +        },
 +        "traverse": {
 +            "version": "0.3.9",
 +            "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
 +            "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==",
 +            "dev": true
 +        },
 +        "tslib": {
 +            "version": "2.4.0",
 +            "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
 +            "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
 +            "dev": true
 +        },
 +        "tsutils": {
 +            "version": "3.21.0",
 +            "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
 +            "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
 +            "dev": true,
 +            "requires": {
 +                "tslib": "^1.8.1"
 +            },
 +            "dependencies": {
 +                "tslib": {
 +                    "version": "1.14.1",
 +                    "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
 +                    "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
 +                    "dev": true
 +                }
 +            }
 +        },
 +        "tunnel": {
 +            "version": "0.0.6",
 +            "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
 +            "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
 +            "dev": true
 +        },
 +        "tunnel-agent": {
 +            "version": "0.6.0",
 +            "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
 +            "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
 +            "dev": true,
 +            "requires": {
 +                "safe-buffer": "^5.0.1"
 +            }
 +        },
 +        "type-check": {
 +            "version": "0.4.0",
 +            "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
 +            "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
 +            "dev": true,
 +            "requires": {
 +                "prelude-ls": "^1.2.1"
 +            }
 +        },
 +        "type-fest": {
 +            "version": "0.20.2",
 +            "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
 +            "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
 +            "dev": true
 +        },
 +        "typed-rest-client": {
 +            "version": "1.8.9",
 +            "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz",
 +            "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==",
 +            "dev": true,
 +            "requires": {
 +                "qs": "^6.9.1",
 +                "tunnel": "0.0.6",
 +                "underscore": "^1.12.1"
 +            }
 +        },
 +        "typescript": {
 +            "version": "4.7.4",
 +            "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
 +            "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
 +            "dev": true
 +        },
 +        "uc.micro": {
 +            "version": "1.0.6",
 +            "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
 +            "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
 +            "dev": true
 +        },
 +        "underscore": {
 +            "version": "1.13.4",
 +            "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz",
 +            "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==",
 +            "dev": true
 +        },
 +        "unzipper": {
 +            "version": "0.10.11",
 +            "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz",
 +            "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==",
 +            "dev": true,
 +            "requires": {
 +                "big-integer": "^1.6.17",
 +                "binary": "~0.3.0",
 +                "bluebird": "~3.4.1",
 +                "buffer-indexof-polyfill": "~1.0.0",
 +                "duplexer2": "~0.1.4",
 +                "fstream": "^1.0.12",
 +                "graceful-fs": "^4.2.2",
 +                "listenercount": "~1.0.1",
 +                "readable-stream": "~2.3.6",
 +                "setimmediate": "~1.0.4"
 +            }
 +        },
 +        "uri-js": {
 +            "version": "4.4.1",
 +            "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
 +            "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
 +            "dev": true,
 +            "requires": {
 +                "punycode": "^2.1.0"
 +            }
 +        },
 +        "url-join": {
 +            "version": "4.0.1",
 +            "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
 +            "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
 +            "dev": true
 +        },
 +        "util-deprecate": {
 +            "version": "1.0.2",
 +            "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
 +            "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
 +            "dev": true
 +        },
 +        "v8-compile-cache": {
 +            "version": "2.3.0",
 +            "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
 +            "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
 +            "dev": true
 +        },
 +        "vsce": {
 +            "version": "2.9.2",
 +            "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.9.2.tgz",
 +            "integrity": "sha512-xyLqL4U82BilUX1t6Ym2opQEa2tLGWYjbgB7+ETeNVXlIJz5sWBJjQJSYJVFOKJSpiOtQclolu88cj7oY6vvPQ==",
 +            "dev": true,
 +            "requires": {
 +                "azure-devops-node-api": "^11.0.1",
 +                "chalk": "^2.4.2",
 +                "cheerio": "^1.0.0-rc.9",
 +                "commander": "^6.1.0",
 +                "glob": "^7.0.6",
 +                "hosted-git-info": "^4.0.2",
 +                "keytar": "^7.7.0",
 +                "leven": "^3.1.0",
 +                "markdown-it": "^12.3.2",
 +                "mime": "^1.3.4",
 +                "minimatch": "^3.0.3",
 +                "parse-semver": "^1.1.1",
 +                "read": "^1.0.7",
 +                "semver": "^5.1.0",
 +                "tmp": "^0.2.1",
 +                "typed-rest-client": "^1.8.4",
 +                "url-join": "^4.0.1",
 +                "xml2js": "^0.4.23",
 +                "yauzl": "^2.3.1",
 +                "yazl": "^2.2.2"
 +            },
 +            "dependencies": {
 +                "ansi-styles": {
 +                    "version": "3.2.1",
 +                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
 +                    "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
 +                    "dev": true,
 +                    "requires": {
 +                        "color-convert": "^1.9.0"
 +                    }
 +                },
 +                "chalk": {
 +                    "version": "2.4.2",
 +                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
 +                    "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
 +                    "dev": true,
 +                    "requires": {
 +                        "ansi-styles": "^3.2.1",
 +                        "escape-string-regexp": "^1.0.5",
 +                        "supports-color": "^5.3.0"
 +                    }
 +                },
 +                "color-convert": {
 +                    "version": "1.9.3",
 +                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
 +                    "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
 +                    "dev": true,
 +                    "requires": {
 +                        "color-name": "1.1.3"
 +                    }
 +                },
 +                "color-name": {
 +                    "version": "1.1.3",
 +                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
 +                    "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
 +                    "dev": true
 +                },
 +                "commander": {
 +                    "version": "6.2.1",
 +                    "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
 +                    "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
 +                    "dev": true
 +                },
 +                "escape-string-regexp": {
 +                    "version": "1.0.5",
 +                    "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
 +                    "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
 +                    "dev": true
 +                },
 +                "has-flag": {
 +                    "version": "3.0.0",
 +                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
 +                    "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
 +                    "dev": true
 +                },
 +                "semver": {
 +                    "version": "5.7.1",
 +                    "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
 +                    "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
 +                    "dev": true
 +                },
 +                "supports-color": {
 +                    "version": "5.5.0",
 +                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
 +                    "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
 +                    "dev": true,
 +                    "requires": {
 +                        "has-flag": "^3.0.0"
 +                    }
 +                }
 +            }
 +        },
 +        "vscode-jsonrpc": {
-             "version": "8.0.0-next.14",
-             "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.0-next.14.tgz",
-             "integrity": "sha512-NqjkOuDTMu8uo+PhoMsV72VO9Gd3wBi/ZpOrkRUOrWKQo7yUdiIw183g8wjH8BImgbK9ZP51HM7TI0ZhCnI1Mw==",
++            "version": "8.0.2",
++            "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz",
++            "integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ=="
 +        },
 +        "vscode-languageclient": {
-                 "vscode-languageserver-protocol": "3.17.0-next.16"
++            "version": "8.0.2",
++            "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.2.tgz",
++            "integrity": "sha512-lHlthJtphG9gibGb/y72CKqQUxwPsMXijJVpHEC2bvbFqxmkj9LwQ3aGU9dwjBLqsX1S4KjShYppLvg1UJDF/Q==",
 +            "requires": {
 +                "minimatch": "^3.0.4",
 +                "semver": "^7.3.5",
-             "version": "3.17.0-next.16",
-             "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.16.tgz",
-             "integrity": "sha512-tx4DnXw9u3N7vw+bx6n2NKp6FoxoNwiP/biH83AS30I2AnTGyLd7afSeH6Oewn2E8jvB7K15bs12sMppkKOVeQ==",
++                "vscode-languageserver-protocol": "3.17.2"
 +            }
 +        },
 +        "vscode-languageserver-protocol": {
-                 "vscode-jsonrpc": "8.0.0-next.7",
-                 "vscode-languageserver-types": "3.17.0-next.9"
++            "version": "3.17.2",
++            "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz",
++            "integrity": "sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg==",
 +            "requires": {
-             "version": "3.17.0-next.9",
-             "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.9.tgz",
-             "integrity": "sha512-9/PeDNPYduaoXRUzYpqmu4ZV9L01HGo0wH9FUt+sSHR7IXwA7xoXBfNUlv8gB9H0D2WwEmMomSy1NmhjKQyn3A=="
++                "vscode-jsonrpc": "8.0.2",
++                "vscode-languageserver-types": "3.17.2"
 +            }
 +        },
 +        "vscode-languageserver-types": {
++            "version": "3.17.2",
++            "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz",
++            "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA=="
 +        },
 +        "which": {
 +            "version": "2.0.2",
 +            "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
 +            "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
 +            "dev": true,
 +            "requires": {
 +                "isexe": "^2.0.0"
 +            }
 +        },
 +        "word-wrap": {
 +            "version": "1.2.3",
 +            "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
 +            "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
 +            "dev": true
 +        },
 +        "wrap-ansi": {
 +            "version": "7.0.0",
 +            "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
 +            "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
 +            "requires": {
 +                "ansi-styles": "^4.0.0",
 +                "string-width": "^4.1.0",
 +                "strip-ansi": "^6.0.0"
 +            }
 +        },
 +        "wrappy": {
 +            "version": "1.0.2",
 +            "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
 +            "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
 +            "dev": true
 +        },
 +        "xml2js": {
 +            "version": "0.4.23",
 +            "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
 +            "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
 +            "dev": true,
 +            "requires": {
 +                "sax": ">=0.6.0",
 +                "xmlbuilder": "~11.0.0"
 +            }
 +        },
 +        "xmlbuilder": {
 +            "version": "11.0.1",
 +            "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
 +            "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
 +            "dev": true
 +        },
 +        "y18n": {
 +            "version": "5.0.8",
 +            "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
 +            "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
 +        },
 +        "yallist": {
 +            "version": "4.0.0",
 +            "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
 +            "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
 +        },
 +        "yargs": {
 +            "version": "17.5.1",
 +            "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz",
 +            "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==",
 +            "requires": {
 +                "cliui": "^7.0.2",
 +                "escalade": "^3.1.1",
 +                "get-caller-file": "^2.0.5",
 +                "require-directory": "^2.1.1",
 +                "string-width": "^4.2.3",
 +                "y18n": "^5.0.5",
 +                "yargs-parser": "^21.0.0"
 +            }
 +        },
 +        "yargs-parser": {
 +            "version": "21.0.1",
 +            "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz",
 +            "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg=="
 +        },
 +        "yauzl": {
 +            "version": "2.10.0",
 +            "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
 +            "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
 +            "dev": true,
 +            "requires": {
 +                "buffer-crc32": "~0.2.3",
 +                "fd-slicer": "~1.1.0"
 +            }
 +        },
 +        "yazl": {
 +            "version": "2.5.1",
 +            "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz",
 +            "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==",
 +            "dev": true,
 +            "requires": {
 +                "buffer-crc32": "~0.2.3"
 +            }
 +        }
 +    }
 +}
index f1dd3aa79ff043b664b519cea469bfe32d520116,0000000000000000000000000000000000000000..6771cad28a792650729ef68041ab0c22a001b370
mode 100644,000000..100644
--- /dev/null
@@@ -1,1685 -1,0 +1,1748 @@@
-         "vscode-languageclient": "^8.0.0-next.14"
 +{
 +    "name": "rust-analyzer",
 +    "displayName": "rust-analyzer",
 +    "description": "Rust language support for Visual Studio Code",
 +    "private": true,
 +    "icon": "icon.png",
 +    "version": "0.5.0-dev",
 +    "releaseTag": null,
 +    "publisher": "rust-lang",
 +    "repository": {
 +        "url": "https://github.com/rust-lang/rust-analyzer.git",
 +        "type": "git"
 +    },
 +    "homepage": "https://rust-analyzer.github.io/",
 +    "license": "MIT OR Apache-2.0",
 +    "keywords": [
 +        "rust"
 +    ],
 +    "categories": [
 +        "Programming Languages"
 +    ],
 +    "engines": {
 +        "vscode": "^1.66.0"
 +    },
 +    "enabledApiProposals": [],
 +    "scripts": {
 +        "vscode:prepublish": "npm run build-base -- --minify",
 +        "package": "vsce package -o rust-analyzer.vsix",
 +        "build-base": "esbuild ./src/main.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node --target=node16",
 +        "build": "npm run build-base -- --sourcemap",
 +        "watch": "npm run build-base -- --sourcemap --watch",
 +        "lint": "prettier --check . && eslint -c .eslintrc.js --ext ts ./src ./tests",
 +        "fix": "prettier --write . && eslint -c .eslintrc.js --ext ts ./src ./tests --fix",
 +        "pretest": "tsc && npm run build",
 +        "test": "cross-env TEST_VARIABLE=test node ./out/tests/runTests.js"
 +    },
 +    "dependencies": {
 +        "d3": "^7.6.1",
 +        "d3-graphviz": "^4.1.1",
++        "vscode-languageclient": "^8.0.2"
 +    },
 +    "devDependencies": {
 +        "@types/node": "~16.11.7",
 +        "@types/vscode": "~1.66.0",
 +        "@typescript-eslint/eslint-plugin": "^5.30.5",
 +        "@typescript-eslint/parser": "^5.30.5",
 +        "@vscode/test-electron": "^2.1.5",
 +        "cross-env": "^7.0.3",
 +        "esbuild": "^0.14.48",
 +        "eslint": "^8.19.0",
 +        "eslint-config-prettier": "^8.5.0",
 +        "ovsx": "^0.5.1",
 +        "prettier": "^2.7.1",
 +        "tslib": "^2.4.0",
 +        "typescript": "^4.7.4",
 +        "vsce": "^2.9.2"
 +    },
 +    "activationEvents": [
 +        "onLanguage:rust",
 +        "onCommand:rust-analyzer.analyzerStatus",
 +        "onCommand:rust-analyzer.memoryUsage",
 +        "onCommand:rust-analyzer.reloadWorkspace",
++        "onCommand:rust-analyzer.startServer",
 +        "workspaceContains:*/Cargo.toml",
 +        "workspaceContains:*/rust-project.json"
 +    ],
 +    "main": "./out/main",
 +    "contributes": {
 +        "taskDefinitions": [
 +            {
 +                "type": "cargo",
 +                "required": [
 +                    "command"
 +                ],
 +                "properties": {
 +                    "label": {
 +                        "type": "string"
 +                    },
 +                    "command": {
 +                        "type": "string"
 +                    },
 +                    "args": {
 +                        "type": "array",
 +                        "items": {
 +                            "type": "string"
 +                        }
 +                    },
 +                    "env": {
 +                        "type": "object",
 +                        "patternProperties": {
 +                            ".+": {
 +                                "type": "string"
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +        ],
 +        "commands": [
 +            {
 +                "command": "rust-analyzer.syntaxTree",
 +                "title": "Show Syntax Tree",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.viewHir",
 +                "title": "View Hir",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.viewFileText",
 +                "title": "View File Text (as seen by the server)",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.viewItemTree",
 +                "title": "Debug ItemTree",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.viewCrateGraph",
 +                "title": "View Crate Graph",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.viewFullCrateGraph",
 +                "title": "View Crate Graph (Full)",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.expandMacro",
 +                "title": "Expand macro recursively",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.matchingBrace",
 +                "title": "Find matching brace",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.parentModule",
 +                "title": "Locate parent module",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.joinLines",
 +                "title": "Join lines",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.run",
 +                "title": "Run",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.copyRunCommandLine",
 +                "title": "Copy Run Command Line",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.debug",
 +                "title": "Debug",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.newDebugConfig",
 +                "title": "Generate launch configuration",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.analyzerStatus",
 +                "title": "Status",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.memoryUsage",
 +                "title": "Memory Usage (Clears Database)",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.shuffleCrateGraph",
 +                "title": "Shuffle Crate Graph",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.reloadWorkspace",
 +                "title": "Reload workspace",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.reload",
 +                "title": "Restart server",
 +                "category": "rust-analyzer"
 +            },
++            {
++                "command": "rust-analyzer.startServer",
++                "title": "Start server",
++                "category": "rust-analyzer"
++            },
++            {
++                "command": "rust-analyzer.stopServer",
++                "title": "Stop server",
++                "category": "rust-analyzer"
++            },
 +            {
 +                "command": "rust-analyzer.onEnter",
 +                "title": "Enhanced enter key",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.ssr",
 +                "title": "Structural Search Replace",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.serverVersion",
 +                "title": "Show RA Version",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.openDocs",
 +                "title": "Open docs under cursor",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.openCargoToml",
 +                "title": "Open Cargo.toml",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.peekTests",
 +                "title": "Peek related tests",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.moveItemUp",
 +                "title": "Move item up",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.moveItemDown",
 +                "title": "Move item down",
 +                "category": "rust-analyzer"
 +            },
 +            {
 +                "command": "rust-analyzer.cancelFlycheck",
 +                "title": "Cancel running flychecks",
 +                "category": "rust-analyzer"
 +            }
 +        ],
 +        "keybindings": [
 +            {
 +                "command": "rust-analyzer.parentModule",
 +                "key": "ctrl+shift+u",
 +                "when": "editorTextFocus && editorLangId == rust"
 +            },
 +            {
 +                "command": "rust-analyzer.matchingBrace",
 +                "key": "ctrl+shift+m",
 +                "when": "editorTextFocus && editorLangId == rust"
 +            },
 +            {
 +                "command": "rust-analyzer.joinLines",
 +                "key": "ctrl+shift+j",
 +                "when": "editorTextFocus && editorLangId == rust"
 +            }
 +        ],
 +        "configuration": {
 +            "type": "object",
 +            "title": "rust-analyzer",
 +            "properties": {
 +                "rust-analyzer.cargoRunner": {
 +                    "type": [
 +                        "null",
 +                        "string"
 +                    ],
 +                    "default": null,
 +                    "description": "Custom cargo runner extension ID."
 +                },
 +                "rust-analyzer.runnableEnv": {
 +                    "anyOf": [
 +                        {
 +                            "type": "null"
 +                        },
 +                        {
 +                            "type": "array",
 +                            "items": {
 +                                "type": "object",
 +                                "properties": {
 +                                    "mask": {
 +                                        "type": "string",
 +                                        "description": "Runnable name mask"
 +                                    },
 +                                    "env": {
 +                                        "type": "object",
 +                                        "description": "Variables in form of { \"key\": \"value\"}"
 +                                    }
 +                                }
 +                            }
 +                        },
 +                        {
 +                            "type": "object",
 +                            "description": "Variables in form of { \"key\": \"value\"}"
 +                        }
 +                    ],
 +                    "default": null,
 +                    "markdownDescription": "Environment variables passed to the runnable launched using `Test` or `Debug` lens or `rust-analyzer.run` command."
 +                },
 +                "rust-analyzer.server.path": {
 +                    "type": [
 +                        "null",
 +                        "string"
 +                    ],
 +                    "scope": "machine-overridable",
 +                    "default": null,
 +                    "markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default)."
 +                },
 +                "rust-analyzer.server.extraEnv": {
 +                    "type": [
 +                        "null",
 +                        "object"
 +                    ],
 +                    "additionalProperties": {
 +                        "type": [
 +                            "string",
 +                            "number"
 +                        ]
 +                    },
 +                    "default": null,
 +                    "markdownDescription": "Extra environment variables that will be passed to the rust-analyzer executable. Useful for passing e.g. `RA_LOG` for debugging."
 +                },
 +                "rust-analyzer.trace.server": {
 +                    "type": "string",
 +                    "scope": "window",
 +                    "enum": [
 +                        "off",
 +                        "messages",
 +                        "verbose"
 +                    ],
 +                    "enumDescriptions": [
 +                        "No traces",
 +                        "Error only",
 +                        "Full log"
 +                    ],
 +                    "default": "off",
 +                    "description": "Trace requests to the rust-analyzer (this is usually overly verbose and not recommended for regular users)."
 +                },
 +                "rust-analyzer.trace.extension": {
 +                    "description": "Enable logging of VS Code extensions itself.",
 +                    "type": "boolean",
 +                    "default": false
 +                },
 +                "rust-analyzer.debug.engine": {
 +                    "type": "string",
 +                    "enum": [
 +                        "auto",
 +                        "vadimcn.vscode-lldb",
 +                        "ms-vscode.cpptools"
 +                    ],
 +                    "default": "auto",
 +                    "description": "Preferred debug engine.",
 +                    "markdownEnumDescriptions": [
 +                        "First try to use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), if it's not installed try to use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools).",
 +                        "Use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)",
 +                        "Use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)"
 +                    ]
 +                },
 +                "rust-analyzer.debug.sourceFileMap": {
 +                    "type": [
 +                        "object",
 +                        "string"
 +                    ],
 +                    "const": "auto",
 +                    "description": "Optional source file mappings passed to the debug engine.",
 +                    "default": {
 +                        "/rustc/<id>": "${env:USERPROFILE}/.rustup/toolchains/<toolchain-id>/lib/rustlib/src/rust"
 +                    }
 +                },
 +                "rust-analyzer.debug.openDebugPane": {
 +                    "markdownDescription": "Whether to open up the `Debug Panel` on debugging start.",
 +                    "type": "boolean",
 +                    "default": false
 +                },
 +                "rust-analyzer.debug.engineSettings": {
 +                    "type": "object",
 +                    "default": {},
 +                    "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`"
 +                },
 +                "rust-analyzer.restartServerOnConfigChange": {
 +                    "markdownDescription": "Whether to restart the server automatically when certain settings that require a restart are changed.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.typing.continueCommentsOnNewline": {
 +                    "markdownDescription": "Whether to prefix newlines after comments with the corresponding comment prefix.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "$generated-start": {},
 +                "rust-analyzer.assist.expressionFillDefault": {
 +                    "markdownDescription": "Placeholder expression to use for missing expressions in assists.",
 +                    "default": "todo",
 +                    "type": "string",
 +                    "enum": [
 +                        "todo",
 +                        "default"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Fill missing expressions with the `todo` macro",
 +                        "Fill missing expressions with reasonable defaults, `new` or `default` constructors."
 +                    ]
 +                },
 +                "rust-analyzer.cachePriming.enable": {
 +                    "markdownDescription": "Warm up caches on project load.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.cachePriming.numThreads": {
 +                    "markdownDescription": "How many worker threads to handle priming caches. The default `0` means to pick automatically.",
 +                    "default": 0,
 +                    "type": "number",
 +                    "minimum": 0,
 +                    "maximum": 255
 +                },
 +                "rust-analyzer.cargo.autoreload": {
 +                    "markdownDescription": "Automatically refresh project info via `cargo metadata` on\n`Cargo.toml` or `.cargo/config.toml` changes.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.cargo.buildScripts.enable": {
 +                    "markdownDescription": "Run build scripts (`build.rs`) for more precise code analysis.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
++                "rust-analyzer.cargo.buildScripts.invocationLocation": {
++                    "markdownDescription": "Specifies the working directory for running build scripts.\n- \"workspace\": run build scripts for a workspace in the workspace's root directory.\n    This is incompatible with `#rust-analyzer.cargo.buildScripts.invocationStrategy#` set to `once`.\n- \"root\": run build scripts in the project's root directory.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.",
++                    "default": "workspace",
++                    "type": "string",
++                    "enum": [
++                        "workspace",
++                        "root"
++                    ],
++                    "enumDescriptions": [
++                        "The command will be executed in the corresponding workspace root.",
++                        "The command will be executed in the project root."
++                    ]
++                },
++                "rust-analyzer.cargo.buildScripts.invocationStrategy": {
++                    "markdownDescription": "Specifies the invocation strategy to use when running the build scripts command.\nIf `per_workspace` is set, the command will be executed for each workspace.\nIf `once` is set, the command will be executed once.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.",
++                    "default": "per_workspace",
++                    "type": "string",
++                    "enum": [
++                        "per_workspace",
++                        "once"
++                    ],
++                    "enumDescriptions": [
++                        "The command will be executed for each workspace.",
++                        "The command will be executed once."
++                    ]
++                },
 +                "rust-analyzer.cargo.buildScripts.overrideCommand": {
 +                    "markdownDescription": "Override the command rust-analyzer uses to run build scripts and\nbuild procedural macros. The command is required to output json\nand should therefore include `--message-format=json` or a similar\noption.\n\nBy default, a cargo invocation will be constructed for the configured\ntargets and features, with the following base command line:\n\n```bash\ncargo check --quiet --workspace --message-format=json --all-targets\n```\n.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "array"
 +                    ],
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.cargo.buildScripts.useRustcWrapper": {
 +                    "markdownDescription": "Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to\navoid checking unnecessary things.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.cargo.extraEnv": {
 +                    "markdownDescription": "Extra environment variables that will be set when running cargo, rustc\nor other commands within the workspace. Useful for setting RUSTFLAGS.",
 +                    "default": {},
 +                    "type": "object"
 +                },
 +                "rust-analyzer.cargo.features": {
 +                    "markdownDescription": "List of features to activate.\n\nSet this to `\"all\"` to pass `--all-features` to cargo.",
 +                    "default": [],
 +                    "anyOf": [
 +                        {
 +                            "type": "string",
 +                            "enum": [
 +                                "all"
 +                            ],
 +                            "enumDescriptions": [
 +                                "Pass `--all-features` to cargo"
 +                            ]
 +                        },
 +                        {
 +                            "type": "array",
 +                            "items": {
 +                                "type": "string"
 +                            }
 +                        }
 +                    ]
 +                },
 +                "rust-analyzer.cargo.noDefaultFeatures": {
 +                    "markdownDescription": "Whether to pass `--no-default-features` to cargo.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.cargo.sysroot": {
 +                    "markdownDescription": "Relative path to the sysroot, or \"discover\" to try to automatically find it via\n\"rustc --print sysroot\".\n\nUnsetting this disables sysroot loading.\n\nThis option does not take effect until rust-analyzer is restarted.",
 +                    "default": "discover",
 +                    "type": [
 +                        "null",
 +                        "string"
 +                    ]
 +                },
 +                "rust-analyzer.cargo.target": {
 +                    "markdownDescription": "Compilation target override (target triple).",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "string"
 +                    ]
 +                },
 +                "rust-analyzer.cargo.unsetTest": {
 +                    "markdownDescription": "Unsets `#[cfg(test)]` for the specified crates.",
 +                    "default": [
 +                        "core"
 +                    ],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.checkOnSave.allTargets": {
 +                    "markdownDescription": "Check all targets and tests (`--all-targets`).",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.checkOnSave.command": {
 +                    "markdownDescription": "Cargo command to use for `cargo check`.",
 +                    "default": "check",
 +                    "type": "string"
 +                },
 +                "rust-analyzer.checkOnSave.enable": {
 +                    "markdownDescription": "Run specified `cargo check` command for diagnostics on save.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.checkOnSave.extraArgs": {
 +                    "markdownDescription": "Extra arguments for `cargo check`.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.checkOnSave.extraEnv": {
 +                    "markdownDescription": "Extra environment variables that will be set when running `cargo check`.\nExtends `#rust-analyzer.cargo.extraEnv#`.",
 +                    "default": {},
 +                    "type": "object"
 +                },
 +                "rust-analyzer.checkOnSave.features": {
 +                    "markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.\n\nSet to `\"all\"` to pass `--all-features` to Cargo.",
 +                    "default": null,
 +                    "anyOf": [
 +                        {
 +                            "type": "string",
 +                            "enum": [
 +                                "all"
 +                            ],
 +                            "enumDescriptions": [
 +                                "Pass `--all-features` to cargo"
 +                            ]
 +                        },
 +                        {
 +                            "type": "array",
 +                            "items": {
 +                                "type": "string"
 +                            }
 +                        },
 +                        {
 +                            "type": "null"
 +                        }
 +                    ]
 +                },
++                "rust-analyzer.checkOnSave.invocationLocation": {
++                    "markdownDescription": "Specifies the working directory for running checks.\n- \"workspace\": run checks for workspaces in the corresponding workspaces' root directories.\n    This falls back to \"root\" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`.\n- \"root\": run checks in the project's root directory.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.",
++                    "default": "workspace",
++                    "type": "string",
++                    "enum": [
++                        "workspace",
++                        "root"
++                    ],
++                    "enumDescriptions": [
++                        "The command will be executed in the corresponding workspace root.",
++                        "The command will be executed in the project root."
++                    ]
++                },
++                "rust-analyzer.checkOnSave.invocationStrategy": {
++                    "markdownDescription": "Specifies the invocation strategy to use when running the checkOnSave command.\nIf `per_workspace` is set, the command will be executed for each workspace.\nIf `once` is set, the command will be executed once.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.",
++                    "default": "per_workspace",
++                    "type": "string",
++                    "enum": [
++                        "per_workspace",
++                        "once"
++                    ],
++                    "enumDescriptions": [
++                        "The command will be executed for each workspace.",
++                        "The command will be executed once."
++                    ]
++                },
 +                "rust-analyzer.checkOnSave.noDefaultFeatures": {
 +                    "markdownDescription": "Whether to pass `--no-default-features` to Cargo. Defaults to\n`#rust-analyzer.cargo.noDefaultFeatures#`.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "boolean"
 +                    ]
 +                },
 +                "rust-analyzer.checkOnSave.overrideCommand": {
 +                    "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefor include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "array"
 +                    ],
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.checkOnSave.target": {
 +                    "markdownDescription": "Check for a specific target. Defaults to\n`#rust-analyzer.cargo.target#`.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "string"
 +                    ]
 +                },
 +                "rust-analyzer.completion.autoimport.enable": {
 +                    "markdownDescription": "Toggles the additional completions that automatically add imports when completed.\nNote that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.completion.autoself.enable": {
 +                    "markdownDescription": "Toggles the additional completions that automatically show method calls and field accesses\nwith `self` prefixed to them when inside a method.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.completion.callable.snippets": {
 +                    "markdownDescription": "Whether to add parenthesis and argument snippets when completing function.",
 +                    "default": "fill_arguments",
 +                    "type": "string",
 +                    "enum": [
 +                        "fill_arguments",
 +                        "add_parentheses",
 +                        "none"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Add call parentheses and pre-fill arguments.",
 +                        "Add call parentheses.",
 +                        "Do no snippet completions for callables."
 +                    ]
 +                },
 +                "rust-analyzer.completion.postfix.enable": {
 +                    "markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.completion.privateEditable.enable": {
 +                    "markdownDescription": "Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.completion.snippets.custom": {
 +                    "markdownDescription": "Custom completion snippets.",
 +                    "default": {
 +                        "Arc::new": {
 +                            "postfix": "arc",
 +                            "body": "Arc::new(${receiver})",
 +                            "requires": "std::sync::Arc",
 +                            "description": "Put the expression into an `Arc`",
 +                            "scope": "expr"
 +                        },
 +                        "Rc::new": {
 +                            "postfix": "rc",
 +                            "body": "Rc::new(${receiver})",
 +                            "requires": "std::rc::Rc",
 +                            "description": "Put the expression into an `Rc`",
 +                            "scope": "expr"
 +                        },
 +                        "Box::pin": {
 +                            "postfix": "pinbox",
 +                            "body": "Box::pin(${receiver})",
 +                            "requires": "std::boxed::Box",
 +                            "description": "Put the expression into a pinned `Box`",
 +                            "scope": "expr"
 +                        },
 +                        "Ok": {
 +                            "postfix": "ok",
 +                            "body": "Ok(${receiver})",
 +                            "description": "Wrap the expression in a `Result::Ok`",
 +                            "scope": "expr"
 +                        },
 +                        "Err": {
 +                            "postfix": "err",
 +                            "body": "Err(${receiver})",
 +                            "description": "Wrap the expression in a `Result::Err`",
 +                            "scope": "expr"
 +                        },
 +                        "Some": {
 +                            "postfix": "some",
 +                            "body": "Some(${receiver})",
 +                            "description": "Wrap the expression in an `Option::Some`",
 +                            "scope": "expr"
 +                        }
 +                    },
 +                    "type": "object"
 +                },
 +                "rust-analyzer.diagnostics.disabled": {
 +                    "markdownDescription": "List of rust-analyzer diagnostics to disable.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    },
 +                    "uniqueItems": true
 +                },
 +                "rust-analyzer.diagnostics.enable": {
 +                    "markdownDescription": "Whether to show native rust-analyzer diagnostics.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.diagnostics.experimental.enable": {
 +                    "markdownDescription": "Whether to show experimental rust-analyzer diagnostics that might\nhave more false positives than usual.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.diagnostics.remapPrefix": {
 +                    "markdownDescription": "Map of prefixes to be substituted when parsing diagnostic file paths.\nThis should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`.",
 +                    "default": {},
 +                    "type": "object"
 +                },
 +                "rust-analyzer.diagnostics.warningsAsHint": {
 +                    "markdownDescription": "List of warnings that should be displayed with hint severity.\n\nThe warnings will be indicated by faded text or three dots in code\nand will not show up in the `Problems Panel`.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.diagnostics.warningsAsInfo": {
 +                    "markdownDescription": "List of warnings that should be displayed with info severity.\n\nThe warnings will be indicated by a blue squiggly underline in code\nand a blue icon in the `Problems Panel`.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.files.excludeDirs": {
 +                    "markdownDescription": "These directories will be ignored by rust-analyzer. They are\nrelative to the workspace root, and globs are not supported. You may\nalso need to add the folders to Code's `files.watcherExclude`.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.files.watcher": {
 +                    "markdownDescription": "Controls file watching implementation.",
 +                    "default": "client",
 +                    "type": "string",
 +                    "enum": [
 +                        "client",
 +                        "server"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Use the client (editor) to watch files for changes",
 +                        "Use server-side file watching"
 +                    ]
 +                },
 +                "rust-analyzer.highlightRelated.breakPoints.enable": {
 +                    "markdownDescription": "Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.highlightRelated.exitPoints.enable": {
 +                    "markdownDescription": "Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.highlightRelated.references.enable": {
 +                    "markdownDescription": "Enables highlighting of related references while the cursor is on any identifier.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.highlightRelated.yieldPoints.enable": {
 +                    "markdownDescription": "Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.actions.debug.enable": {
 +                    "markdownDescription": "Whether to show `Debug` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.actions.enable": {
 +                    "markdownDescription": "Whether to show HoverActions in Rust files.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.actions.gotoTypeDef.enable": {
 +                    "markdownDescription": "Whether to show `Go to Type Definition` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.actions.implementations.enable": {
 +                    "markdownDescription": "Whether to show `Implementations` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.actions.references.enable": {
 +                    "markdownDescription": "Whether to show `References` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.actions.run.enable": {
 +                    "markdownDescription": "Whether to show `Run` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.documentation.enable": {
 +                    "markdownDescription": "Whether to show documentation on hover.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.documentation.keywords.enable": {
 +                    "markdownDescription": "Whether to show keyword hover popups. Only applies when\n`#rust-analyzer.hover.documentation.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.hover.links.enable": {
 +                    "markdownDescription": "Use markdown syntax for links in hover.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.imports.granularity.enforce": {
 +                    "markdownDescription": "Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.imports.granularity.group": {
 +                    "markdownDescription": "How imports should be grouped into use statements.",
 +                    "default": "crate",
 +                    "type": "string",
 +                    "enum": [
 +                        "preserve",
 +                        "crate",
 +                        "module",
 +                        "item"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Do not change the granularity of any imports and preserve the original structure written by the developer.",
 +                        "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.",
 +                        "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.",
 +                        "Flatten imports so that each has its own use statement."
 +                    ]
 +                },
 +                "rust-analyzer.imports.group.enable": {
 +                    "markdownDescription": "Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.imports.merge.glob": {
 +                    "markdownDescription": "Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.imports.prefer.no.std": {
 +                    "markdownDescription": "Prefer to unconditionally use imports of the core and alloc crate, over the std crate.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.imports.prefix": {
 +                    "markdownDescription": "The path structure for newly inserted paths to use.",
 +                    "default": "plain",
 +                    "type": "string",
 +                    "enum": [
 +                        "plain",
 +                        "self",
 +                        "crate"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.",
 +                        "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.",
 +                        "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from."
 +                    ]
 +                },
 +                "rust-analyzer.inlayHints.bindingModeHints.enable": {
 +                    "markdownDescription": "Whether to show inlay type hints for binding modes.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.chainingHints.enable": {
 +                    "markdownDescription": "Whether to show inlay type hints for method chains.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.closingBraceHints.enable": {
 +                    "markdownDescription": "Whether to show inlay hints after a closing `}` to indicate what item it belongs to.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.closingBraceHints.minLines": {
 +                    "markdownDescription": "Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1\nto always show them).",
 +                    "default": 25,
 +                    "type": "integer",
 +                    "minimum": 0
 +                },
 +                "rust-analyzer.inlayHints.closureReturnTypeHints.enable": {
 +                    "markdownDescription": "Whether to show inlay type hints for return types of closures.",
 +                    "default": "never",
 +                    "type": "string",
 +                    "enum": [
 +                        "always",
 +                        "never",
 +                        "with_block"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Always show type hints for return types of closures.",
 +                        "Never show type hints for return types of closures.",
 +                        "Only show type hints for return types of closures with blocks."
 +                    ]
 +                },
 +                "rust-analyzer.inlayHints.lifetimeElisionHints.enable": {
 +                    "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.",
 +                    "default": "never",
 +                    "type": "string",
 +                    "enum": [
 +                        "always",
 +                        "never",
 +                        "skip_trivial"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Always show lifetime elision hints.",
 +                        "Never show lifetime elision hints.",
 +                        "Only show lifetime elision hints if a return type is involved."
 +                    ]
 +                },
 +                "rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames": {
 +                    "markdownDescription": "Whether to prefer using parameter names as the name for elided lifetime hints if possible.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.maxLength": {
 +                    "markdownDescription": "Maximum length for inlay hints. Set to null to have an unlimited length.",
 +                    "default": 25,
 +                    "type": [
 +                        "null",
 +                        "integer"
 +                    ],
 +                    "minimum": 0
 +                },
 +                "rust-analyzer.inlayHints.parameterHints.enable": {
 +                    "markdownDescription": "Whether to show function parameter name inlay hints at the call\nsite.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.reborrowHints.enable": {
 +                    "markdownDescription": "Whether to show inlay type hints for compiler inserted reborrows.",
 +                    "default": "never",
 +                    "type": "string",
 +                    "enum": [
 +                        "always",
 +                        "never",
 +                        "mutable"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Always show reborrow hints.",
 +                        "Never show reborrow hints.",
 +                        "Only show mutable reborrow hints."
 +                    ]
 +                },
 +                "rust-analyzer.inlayHints.renderColons": {
 +                    "markdownDescription": "Whether to render leading colons for type hints, and trailing colons for parameter hints.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.typeHints.enable": {
 +                    "markdownDescription": "Whether to show inlay type hints for variables.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.typeHints.hideClosureInitialization": {
 +                    "markdownDescription": "Whether to hide inlay type hints for `let` statements that initialize to a closure.\nOnly applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.inlayHints.typeHints.hideNamedConstructor": {
 +                    "markdownDescription": "Whether to hide inlay type hints for constructors.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.joinLines.joinAssignments": {
 +                    "markdownDescription": "Join lines merges consecutive declaration and initialization of an assignment.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.joinLines.joinElseIf": {
 +                    "markdownDescription": "Join lines inserts else between consecutive ifs.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.joinLines.removeTrailingComma": {
 +                    "markdownDescription": "Join lines removes trailing commas.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.joinLines.unwrapTrivialBlock": {
 +                    "markdownDescription": "Join lines unwraps trivial blocks.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.debug.enable": {
 +                    "markdownDescription": "Whether to show `Debug` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.enable": {
 +                    "markdownDescription": "Whether to show CodeLens in Rust files.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.forceCustomCommands": {
 +                    "markdownDescription": "Internal config: use custom client-side commands even when the\nclient doesn't set the corresponding capability.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.implementations.enable": {
 +                    "markdownDescription": "Whether to show `Implementations` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.location": {
 +                    "markdownDescription": "Where to render annotations.",
 +                    "default": "above_name",
 +                    "type": "string",
 +                    "enum": [
 +                        "above_name",
 +                        "above_whole_item"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Render annotations above the name of the item.",
 +                        "Render annotations above the whole item, including documentation comments and attributes."
 +                    ]
 +                },
 +                "rust-analyzer.lens.references.adt.enable": {
 +                    "markdownDescription": "Whether to show `References` lens for Struct, Enum, and Union.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.references.enumVariant.enable": {
 +                    "markdownDescription": "Whether to show `References` lens for Enum Variants.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.references.method.enable": {
 +                    "markdownDescription": "Whether to show `Method References` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.references.trait.enable": {
 +                    "markdownDescription": "Whether to show `References` lens for Trait.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.lens.run.enable": {
 +                    "markdownDescription": "Whether to show `Run` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.linkedProjects": {
 +                    "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set\nof projects.\n\nElements must be paths pointing to `Cargo.toml`,\n`rust-project.json`, or JSON objects in `rust-project.json` format.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": [
 +                            "string",
 +                            "object"
 +                        ]
 +                    }
 +                },
 +                "rust-analyzer.lru.capacity": {
 +                    "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "integer"
 +                    ],
 +                    "minimum": 0
 +                },
 +                "rust-analyzer.notifications.cargoTomlNotFound": {
 +                    "markdownDescription": "Whether to show `can't find Cargo.toml` error message.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.procMacro.attributes.enable": {
 +                    "markdownDescription": "Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.procMacro.enable": {
 +                    "markdownDescription": "Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.procMacro.ignored": {
 +                    "markdownDescription": "These proc-macros will be ignored when trying to expand them.\n\nThis config takes a map of crate names with the exported proc-macro names to ignore as values.",
 +                    "default": {},
 +                    "type": "object"
 +                },
 +                "rust-analyzer.procMacro.server": {
 +                    "markdownDescription": "Internal config, path to proc-macro server executable (typically,\nthis is rust-analyzer itself, but we override this in tests).",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "string"
 +                    ]
 +                },
 +                "rust-analyzer.references.excludeImports": {
 +                    "markdownDescription": "Exclude imports from find-all-references.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.runnables.command": {
 +                    "markdownDescription": "Command to be executed instead of 'cargo' for runnables.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "string"
 +                    ]
 +                },
 +                "rust-analyzer.runnables.extraArgs": {
 +                    "markdownDescription": "Additional arguments to be passed to cargo for runnables such as\ntests or binaries. For example, it may be `--release`.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.rustc.source": {
 +                    "markdownDescription": "Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private\nprojects, or \"discover\" to try to automatically find it if the `rustc-dev` component\nis installed.\n\nAny project which uses rust-analyzer with the rustcPrivate\ncrates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.\n\nThis option does not take effect until rust-analyzer is restarted.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "string"
 +                    ]
 +                },
 +                "rust-analyzer.rustfmt.extraArgs": {
 +                    "markdownDescription": "Additional arguments to `rustfmt`.",
 +                    "default": [],
 +                    "type": "array",
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.rustfmt.overrideCommand": {
 +                    "markdownDescription": "Advanced option, fully override the command rust-analyzer uses for\nformatting.",
 +                    "default": null,
 +                    "type": [
 +                        "null",
 +                        "array"
 +                    ],
 +                    "items": {
 +                        "type": "string"
 +                    }
 +                },
 +                "rust-analyzer.rustfmt.rangeFormatting.enable": {
 +                    "markdownDescription": "Enables the use of rustfmt's unstable range formatting command for the\n`textDocument/rangeFormatting` request. The rustfmt option is unstable and only\navailable on a nightly build.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.semanticHighlighting.doc.comment.inject.enable": {
 +                    "markdownDescription": "Inject additional highlighting into doc comments.\n\nWhen enabled, rust-analyzer will highlight rust source in doc comments as well as intra\ndoc links.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.semanticHighlighting.operator.enable": {
 +                    "markdownDescription": "Use semantic tokens for operators.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for operator tokens when\nthey are tagged with modifiers.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.semanticHighlighting.operator.specialization.enable": {
 +                    "markdownDescription": "Use specialized semantic tokens for operators.\n\nWhen enabled, rust-analyzer will emit special token types for operator tokens instead\nof the generic `operator` token type.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.semanticHighlighting.punctuation.enable": {
 +                    "markdownDescription": "Use semantic tokens for punctuations.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when\nthey are tagged with modifiers or have a special role.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang": {
 +                    "markdownDescription": "When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro\ncalls.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.semanticHighlighting.punctuation.specialization.enable": {
 +                    "markdownDescription": "Use specialized semantic tokens for punctuations.\n\nWhen enabled, rust-analyzer will emit special token types for punctuation tokens instead\nof the generic `punctuation` token type.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.semanticHighlighting.strings.enable": {
 +                    "markdownDescription": "Use semantic tokens for strings.\n\nIn some editors (e.g. vscode) semantic tokens override other highlighting grammars.\nBy disabling semantic tokens for strings, other grammars can be used to highlight\ntheir contents.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.signatureInfo.detail": {
 +                    "markdownDescription": "Show full signature of the callable. Only shows parameters if disabled.",
 +                    "default": "full",
 +                    "type": "string",
 +                    "enum": [
 +                        "full",
 +                        "parameters"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Show the entire signature.",
 +                        "Show only the parameters."
 +                    ]
 +                },
 +                "rust-analyzer.signatureInfo.documentation.enable": {
 +                    "markdownDescription": "Show documentation.",
 +                    "default": true,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.typing.autoClosingAngleBrackets.enable": {
 +                    "markdownDescription": "Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "rust-analyzer.workspace.symbol.search.kind": {
 +                    "markdownDescription": "Workspace symbol search kind.",
 +                    "default": "only_types",
 +                    "type": "string",
 +                    "enum": [
 +                        "only_types",
 +                        "all_symbols"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Search for types only.",
 +                        "Search for all symbols kinds."
 +                    ]
 +                },
 +                "rust-analyzer.workspace.symbol.search.limit": {
 +                    "markdownDescription": "Limits the number of items returned from a workspace symbol search (Defaults to 128).\nSome clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.\nOther clients requires all results upfront and might require a higher limit.",
 +                    "default": 128,
 +                    "type": "integer",
 +                    "minimum": 0
 +                },
 +                "rust-analyzer.workspace.symbol.search.scope": {
 +                    "markdownDescription": "Workspace symbol search scope.",
 +                    "default": "workspace",
 +                    "type": "string",
 +                    "enum": [
 +                        "workspace",
 +                        "workspace_and_dependencies"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Search in current workspace only.",
 +                        "Search in current workspace and dependencies."
 +                    ]
 +                },
 +                "$generated-end": {}
 +            }
 +        },
 +        "problemPatterns": [
 +            {
 +                "name": "rustc",
 +                "patterns": [
 +                    {
 +                        "regexp": "^(warning|warn|error)(?:\\[(.*?)\\])?: (.*)$",
 +                        "severity": 1,
 +                        "code": 2,
 +                        "message": 3
 +                    },
 +                    {
 +                        "regexp": "^[\\s->=]*(.*?):(\\d*):(\\d*)\\s*$",
 +                        "file": 1,
 +                        "line": 2,
 +                        "column": 3
 +                    }
 +                ]
 +            },
 +            {
 +                "name": "rustc-json",
 +                "patterns": [
 +                    {
 +                        "regexp": "^.*\"message\":{\"message\":\"([^\"]*).*?\"file_name\":\"([^\"]+).*?\"line_start\":(\\d+).*?\"line_end\":(\\d+).*?\"column_start\":(\\d+).*?\"column_end\":(\\d+).*}$",
 +                        "message": 1,
 +                        "file": 2,
 +                        "line": 3,
 +                        "endLine": 4,
 +                        "column": 5,
 +                        "endColumn": 6
 +                    }
 +                ]
 +            }
 +        ],
 +        "languages": [
 +            {
 +                "id": "ra_syntax_tree",
 +                "extensions": [
 +                    ".rast"
 +                ]
 +            },
 +            {
 +                "id": "rust",
 +                "extensions": [
 +                    ".rs"
 +                ],
 +                "aliases": [
 +                    "Rust",
 +                    "rs"
 +                ],
 +                "configuration": "language-configuration.json"
 +            }
 +        ],
 +        "grammars": [
 +            {
 +                "language": "ra_syntax_tree",
 +                "scopeName": "source.ra_syntax_tree",
 +                "path": "ra_syntax_tree.tmGrammar.json"
 +            }
 +        ],
 +        "problemMatchers": [
 +            {
 +                "name": "rustc",
 +                "owner": "rustc",
 +                "source": "rustc",
 +                "fileLocation": [
 +                    "autoDetect",
 +                    "${workspaceRoot}"
 +                ],
 +                "pattern": "$rustc"
 +            },
 +            {
 +                "name": "rustc-json",
 +                "owner": "rustc",
 +                "source": "rustc",
 +                "fileLocation": [
 +                    "autoDetect",
 +                    "${workspaceRoot}"
 +                ],
 +                "pattern": "$rustc-json"
 +            },
 +            {
 +                "name": "rustc-watch",
 +                "owner": "rustc",
 +                "source": "rustc",
 +                "fileLocation": [
 +                    "autoDetect",
 +                    "${workspaceRoot}"
 +                ],
 +                "background": {
 +                    "beginsPattern": "^\\[Running\\b",
 +                    "endsPattern": "^\\[Finished running\\b"
 +                },
 +                "pattern": "$rustc"
 +            }
 +        ],
 +        "colors": [
 +            {
 +                "id": "rust_analyzer.syntaxTreeBorder",
 +                "description": "Color of the border displayed in the Rust source code for the selected syntax node (see \"Show Syntax Tree\" command)",
 +                "defaults": {
 +                    "dark": "#ffffff",
 +                    "light": "#b700ff",
 +                    "highContrast": "#b700ff"
 +                }
 +            }
 +        ],
 +        "semanticTokenTypes": [
 +            {
 +                "id": "angle",
 +                "description": "Style for < or >",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "arithmetic",
 +                "description": "Style for arithmetic operators",
 +                "superType": "operator"
 +            },
 +            {
 +                "id": "attribute",
 +                "description": "Style for attributes"
 +            },
 +            {
 +                "id": "attributeBracket",
 +                "description": "Style for attribute invocation brackets, that is the `#[` and `]` tokens",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "bitwise",
 +                "description": "Style for bitwise operators",
 +                "superType": "operator"
 +            },
 +            {
 +                "id": "boolean",
 +                "description": "Style for boolean literals",
 +                "superType": "keyword"
 +            },
 +            {
 +                "id": "brace",
 +                "description": "Style for { or }",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "bracket",
 +                "description": "Style for [ or ]",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "builtinAttribute",
 +                "description": "Style for builtin attributes",
 +                "superType": "attribute"
 +            },
 +            {
 +                "id": "builtinType",
 +                "description": "Style for builtin types",
 +                "superType": "type"
 +            },
 +            {
 +                "id": "character",
 +                "description": "Style for character literals",
 +                "superType": "string"
 +            },
 +            {
 +                "id": "colon",
 +                "description": "Style for :",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "comma",
 +                "description": "Style for ,",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "comparison",
 +                "description": "Style for comparison operators",
 +                "superType": "operator"
 +            },
 +            {
 +                "id": "constParameter",
 +                "description": "Style for const generics"
 +            },
 +            {
 +                "id": "derive",
 +                "description": "Style for derives",
 +                "superType": "attribute"
 +            },
 +            {
 +                "id": "dot",
 +                "description": "Style for .",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "escapeSequence",
 +                "description": "Style for char escapes in strings"
 +            },
 +            {
 +                "id": "formatSpecifier",
 +                "description": "Style for {} placeholders in format strings"
 +            },
 +            {
 +                "id": "label",
 +                "description": "Style for labels"
 +            },
 +            {
 +                "id": "lifetime",
 +                "description": "Style for lifetimes"
 +            },
 +            {
 +                "id": "logical",
 +                "description": "Style for logic operators",
 +                "superType": "operator"
 +            },
 +            {
 +                "id": "macroBang",
 +                "description": "Style for the ! token of macro calls",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "operator",
 +                "description": "Style for operators",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "parenthesis",
 +                "description": "Style for ( or )",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "punctuation",
 +                "description": "Style for generic punctuation"
 +            },
 +            {
 +                "id": "selfKeyword",
 +                "description": "Style for the self keyword",
 +                "superType": "keyword"
 +            },
 +            {
 +                "id": "selfTypeKeyword",
 +                "description": "Style for the self type keyword",
 +                "superType": "keyword"
 +            },
 +            {
 +                "id": "semicolon",
 +                "description": "Style for ;",
 +                "superType": "punctuation"
 +            },
 +            {
 +                "id": "typeAlias",
 +                "description": "Style for type aliases",
 +                "superType": "type"
 +            },
 +            {
 +                "id": "union",
 +                "description": "Style for C-style untagged unions",
 +                "superType": "type"
 +            },
 +            {
 +                "id": "unresolvedReference",
 +                "description": "Style for names which can not be resolved due to compilation errors"
 +            }
 +        ],
 +        "semanticTokenModifiers": [
 +            {
 +                "id": "async",
 +                "description": "Style for async functions and the `async` and `await` keywords"
 +            },
 +            {
 +                "id": "attribute",
 +                "description": "Style for elements within attributes"
 +            },
 +            {
 +                "id": "callable",
 +                "description": "Style for locals whose types implements one of the `Fn*` traits"
 +            },
 +            {
 +                "id": "constant",
 +                "description": "Style for compile-time constants"
 +            },
 +            {
 +                "id": "consuming",
 +                "description": "Style for locals that are being consumed when use in a function call"
 +            },
 +            {
 +                "id": "controlFlow",
 +                "description": "Style for control-flow related tokens, this includes the `?` operator"
 +            },
 +            {
 +                "id": "crateRoot",
 +                "description": "Style for names resolving to a crate root"
 +            },
 +            {
 +                "id": "injected",
 +                "description": "Style for doc-string injected highlighting like rust source blocks in documentation"
 +            },
 +            {
 +                "id": "intraDocLink",
 +                "description": "Style for intra doc links in doc-strings"
 +            },
 +            {
 +                "id": "library",
 +                "description": "Style for items that are defined outside of the current crate"
 +            },
 +            {
 +                "id": "mutable",
 +                "description": "Style for mutable locals and statics as well as functions taking `&mut self`"
 +            },
 +            {
 +                "id": "public",
 +                "description": "Style for items that are from the current crate and are `pub`"
 +            },
 +            {
 +                "id": "reference",
 +                "description": "Style for locals behind a reference and functions taking `self` by reference"
 +            },
 +            {
 +                "id": "trait",
 +                "description": "Style for associated trait items"
 +            },
 +            {
 +                "id": "unsafe",
 +                "description": "Style for unsafe operations, like unsafe function calls, as well as the `unsafe` token"
 +            }
 +        ],
 +        "semanticTokenScopes": [
 +            {
 +                "language": "rust",
 +                "scopes": {
 +                    "attribute": [
 +                        "meta.attribute.rust"
 +                    ],
 +                    "boolean": [
 +                        "constant.language.boolean.rust"
 +                    ],
 +                    "builtinType": [
 +                        "support.type.primitive.rust"
 +                    ],
 +                    "constParameter": [
 +                        "constant.other.caps.rust"
 +                    ],
 +                    "enum": [
 +                        "entity.name.type.enum.rust"
 +                    ],
 +                    "formatSpecifier": [
 +                        "punctuation.section.embedded.rust"
 +                    ],
 +                    "function": [
 +                        "entity.name.function.rust"
 +                    ],
 +                    "interface": [
 +                        "entity.name.type.trait.rust"
 +                    ],
 +                    "keyword": [
 +                        "keyword.other.rust"
 +                    ],
 +                    "keyword.controlFlow": [
 +                        "keyword.control.rust"
 +                    ],
 +                    "lifetime": [
 +                        "storage.modifier.lifetime.rust"
 +                    ],
 +                    "macroBang": [
 +                        "entity.name.function.macro.rust"
 +                    ],
 +                    "method": [
 +                        "entity.name.function.rust"
 +                    ],
 +                    "struct": [
 +                        "entity.name.type.struct.rust"
 +                    ],
 +                    "typeAlias": [
 +                        "entity.name.type.declaration.rust"
 +                    ],
 +                    "union": [
 +                        "entity.name.type.union.rust"
 +                    ],
 +                    "variable": [
 +                        "variable.other.rust"
 +                    ],
 +                    "variable.constant": [
 +                        "variable.other.constant.rust"
 +                    ],
 +                    "*.mutable": [
 +                        "markup.underline"
 +                    ]
 +                }
 +            }
 +        ],
 +        "menus": {
 +            "commandPalette": [
 +                {
 +                    "command": "rust-analyzer.syntaxTree",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.viewHir",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.viewFileText",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.expandMacro",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.matchingBrace",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.parentModule",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.joinLines",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.run",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.debug",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.newDebugConfig",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.analyzerStatus",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.memoryUsage",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.reloadWorkspace",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.reload",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.onEnter",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.ssr",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.serverVersion",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.openDocs",
 +                    "when": "inRustProject"
 +                },
 +                {
 +                    "command": "rust-analyzer.openCargoToml",
 +                    "when": "inRustProject"
 +                }
 +            ],
 +            "editor/context": [
 +                {
 +                    "command": "rust-analyzer.peekTests",
 +                    "when": "inRustProject",
 +                    "group": "navigation@1000"
 +                }
 +            ]
 +        }
 +    }
 +}
index e57fb20e2cf8b97992b43581ae22dc58a2b1c87a,0000000000000000000000000000000000000000..176040120f410db9049ec147bdf493788d1ad12f
mode 100644,000000..100644
--- /dev/null
@@@ -1,215 -1,0 +1,215 @@@
-         ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: "rust-analyzer" }, this));
-         ctx.pushCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this));
 +import * as vscode from "vscode";
 +
 +import { Ctx, Disposable } from "./ctx";
 +import { RustEditor, isRustEditor } from "./util";
 +
 +// FIXME: consider implementing this via the Tree View API?
 +// https://code.visualstudio.com/api/extension-guides/tree-view
 +export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable {
 +    private readonly astDecorationType = vscode.window.createTextEditorDecorationType({
 +        borderColor: new vscode.ThemeColor("rust_analyzer.syntaxTreeBorder"),
 +        borderStyle: "solid",
 +        borderWidth: "2px",
 +    });
 +    private rustEditor: undefined | RustEditor;
 +
 +    // Lazy rust token range -> syntax tree file range.
 +    private readonly rust2Ast = new Lazy(() => {
 +        const astEditor = this.findAstTextEditor();
 +        if (!this.rustEditor || !astEditor) return undefined;
 +
 +        const buf: [vscode.Range, vscode.Range][] = [];
 +        for (let i = 0; i < astEditor.document.lineCount; ++i) {
 +            const astLine = astEditor.document.lineAt(i);
 +
 +            // Heuristically look for nodes with quoted text (which are token nodes)
 +            const isTokenNode = astLine.text.lastIndexOf('"') >= 0;
 +            if (!isTokenNode) continue;
 +
 +            const rustRange = this.parseRustTextRange(this.rustEditor.document, astLine.text);
 +            if (!rustRange) continue;
 +
 +            buf.push([rustRange, this.findAstNodeRange(astLine)]);
 +        }
 +        return buf;
 +    });
 +
 +    constructor(ctx: Ctx) {
-         ctx.pushCleanup(this);
++        ctx.pushExtCleanup(
++            vscode.languages.registerHoverProvider({ scheme: "rust-analyzer" }, this)
++        );
++        ctx.pushExtCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this));
 +        vscode.workspace.onDidCloseTextDocument(
 +            this.onDidCloseTextDocument,
 +            this,
 +            ctx.subscriptions
 +        );
 +        vscode.workspace.onDidChangeTextDocument(
 +            this.onDidChangeTextDocument,
 +            this,
 +            ctx.subscriptions
 +        );
 +        vscode.window.onDidChangeVisibleTextEditors(
 +            this.onDidChangeVisibleTextEditors,
 +            this,
 +            ctx.subscriptions
 +        );
 +    }
 +    dispose() {
 +        this.setRustEditor(undefined);
 +    }
 +
 +    private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
 +        if (
 +            this.rustEditor &&
 +            event.document.uri.toString() === this.rustEditor.document.uri.toString()
 +        ) {
 +            this.rust2Ast.reset();
 +        }
 +    }
 +
 +    private onDidCloseTextDocument(doc: vscode.TextDocument) {
 +        if (this.rustEditor && doc.uri.toString() === this.rustEditor.document.uri.toString()) {
 +            this.setRustEditor(undefined);
 +        }
 +    }
 +
 +    private onDidChangeVisibleTextEditors(editors: readonly vscode.TextEditor[]) {
 +        if (!this.findAstTextEditor()) {
 +            this.setRustEditor(undefined);
 +            return;
 +        }
 +        this.setRustEditor(editors.find(isRustEditor));
 +    }
 +
 +    private findAstTextEditor(): undefined | vscode.TextEditor {
 +        return vscode.window.visibleTextEditors.find(
 +            (it) => it.document.uri.scheme === "rust-analyzer"
 +        );
 +    }
 +
 +    private setRustEditor(newRustEditor: undefined | RustEditor) {
 +        if (this.rustEditor && this.rustEditor !== newRustEditor) {
 +            this.rustEditor.setDecorations(this.astDecorationType, []);
 +            this.rust2Ast.reset();
 +        }
 +        this.rustEditor = newRustEditor;
 +    }
 +
 +    // additional positional params are omitted
 +    provideDefinition(
 +        doc: vscode.TextDocument,
 +        pos: vscode.Position
 +    ): vscode.ProviderResult<vscode.DefinitionLink[]> {
 +        if (!this.rustEditor || doc.uri.toString() !== this.rustEditor.document.uri.toString()) {
 +            return;
 +        }
 +
 +        const astEditor = this.findAstTextEditor();
 +        if (!astEditor) return;
 +
 +        const rust2AstRanges = this.rust2Ast
 +            .get()
 +            ?.find(([rustRange, _]) => rustRange.contains(pos));
 +        if (!rust2AstRanges) return;
 +
 +        const [rustFileRange, astFileRange] = rust2AstRanges;
 +
 +        astEditor.revealRange(astFileRange);
 +        astEditor.selection = new vscode.Selection(astFileRange.start, astFileRange.end);
 +
 +        return [
 +            {
 +                targetRange: astFileRange,
 +                targetUri: astEditor.document.uri,
 +                originSelectionRange: rustFileRange,
 +                targetSelectionRange: astFileRange,
 +            },
 +        ];
 +    }
 +
 +    // additional positional params are omitted
 +    provideHover(
 +        doc: vscode.TextDocument,
 +        hoverPosition: vscode.Position
 +    ): vscode.ProviderResult<vscode.Hover> {
 +        if (!this.rustEditor) return;
 +
 +        const astFileLine = doc.lineAt(hoverPosition.line);
 +
 +        const rustFileRange = this.parseRustTextRange(this.rustEditor.document, astFileLine.text);
 +        if (!rustFileRange) return;
 +
 +        this.rustEditor.setDecorations(this.astDecorationType, [rustFileRange]);
 +        this.rustEditor.revealRange(rustFileRange);
 +
 +        const rustSourceCode = this.rustEditor.document.getText(rustFileRange);
 +        const astFileRange = this.findAstNodeRange(astFileLine);
 +
 +        return new vscode.Hover(["```rust\n" + rustSourceCode + "\n```"], astFileRange);
 +    }
 +
 +    private findAstNodeRange(astLine: vscode.TextLine): vscode.Range {
 +        const lineOffset = astLine.range.start;
 +        const begin = lineOffset.translate(undefined, astLine.firstNonWhitespaceCharacterIndex);
 +        const end = lineOffset.translate(undefined, astLine.text.trimEnd().length);
 +        return new vscode.Range(begin, end);
 +    }
 +
 +    private parseRustTextRange(
 +        doc: vscode.TextDocument,
 +        astLine: string
 +    ): undefined | vscode.Range {
 +        const parsedRange = /(\d+)\.\.(\d+)/.exec(astLine);
 +        if (!parsedRange) return;
 +
 +        const [begin, end] = parsedRange.slice(1).map((off) => this.positionAt(doc, +off));
 +
 +        return new vscode.Range(begin, end);
 +    }
 +
 +    // Memoize the last value, otherwise the CPU is at 100% single core
 +    // with quadratic lookups when we build rust2Ast cache
 +    cache?: { doc: vscode.TextDocument; offset: number; line: number };
 +
 +    positionAt(doc: vscode.TextDocument, targetOffset: number): vscode.Position {
 +        if (doc.eol === vscode.EndOfLine.LF) {
 +            return doc.positionAt(targetOffset);
 +        }
 +
 +        // Dirty workaround for crlf line endings
 +        // We are still in this prehistoric era of carriage returns here...
 +
 +        let line = 0;
 +        let offset = 0;
 +
 +        const cache = this.cache;
 +        if (cache?.doc === doc && cache.offset <= targetOffset) {
 +            ({ line, offset } = cache);
 +        }
 +
 +        while (true) {
 +            const lineLenWithLf = doc.lineAt(line).text.length + 1;
 +            if (offset + lineLenWithLf > targetOffset) {
 +                this.cache = { doc, offset, line };
 +                return doc.positionAt(targetOffset + line);
 +            }
 +            offset += lineLenWithLf;
 +            line += 1;
 +        }
 +    }
 +}
 +
 +class Lazy<T> {
 +    val: undefined | T;
 +
 +    constructor(private readonly compute: () => undefined | T) {}
 +
 +    get() {
 +        return this.val ?? (this.val = this.compute());
 +    }
 +
 +    reset() {
 +        this.val = undefined;
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..374c3b8144c3841c2290dc0f0300cb38ce142f47
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,148 @@@
++import * as vscode from "vscode";
++import * as os from "os";
++import { Config } from "./config";
++import { log, isValidExecutable } from "./util";
++import { PersistentState } from "./persistent_state";
++import { exec } from "child_process";
++
++export async function bootstrap(
++    context: vscode.ExtensionContext,
++    config: Config,
++    state: PersistentState
++): Promise<string> {
++    const path = await getServer(context, config, state);
++    if (!path) {
++        throw new Error(
++            "Rust Analyzer Language Server is not available. " +
++                "Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation)."
++        );
++    }
++
++    log.info("Using server binary at", path);
++
++    if (!isValidExecutable(path)) {
++        if (config.serverPath) {
++            throw new Error(`Failed to execute ${path} --version. \`config.server.path\` or \`config.serverPath\` has been set explicitly.\
++            Consider removing this config or making a valid server binary available at that path.`);
++        } else {
++            throw new Error(`Failed to execute ${path} --version`);
++        }
++    }
++
++    return path;
++}
++
++async function patchelf(dest: vscode.Uri): Promise<void> {
++    await vscode.window.withProgress(
++        {
++            location: vscode.ProgressLocation.Notification,
++            title: "Patching rust-analyzer for NixOS",
++        },
++        async (progress, _) => {
++            const expression = `
++            {srcStr, pkgs ? import <nixpkgs> {}}:
++                pkgs.stdenv.mkDerivation {
++                    name = "rust-analyzer";
++                    src = /. + srcStr;
++                    phases = [ "installPhase" "fixupPhase" ];
++                    installPhase = "cp $src $out";
++                    fixupPhase = ''
++                    chmod 755 $out
++                    patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out
++                    '';
++                }
++            `;
++            const origFile = vscode.Uri.file(dest.fsPath + "-orig");
++            await vscode.workspace.fs.rename(dest, origFile, { overwrite: true });
++            try {
++                progress.report({ message: "Patching executable", increment: 20 });
++                await new Promise((resolve, reject) => {
++                    const handle = exec(
++                        `nix-build -E - --argstr srcStr '${origFile.fsPath}' -o '${dest.fsPath}'`,
++                        (err, stdout, stderr) => {
++                            if (err != null) {
++                                reject(Error(stderr));
++                            } else {
++                                resolve(stdout);
++                            }
++                        }
++                    );
++                    handle.stdin?.write(expression);
++                    handle.stdin?.end();
++                });
++            } finally {
++                await vscode.workspace.fs.delete(origFile);
++            }
++        }
++    );
++}
++
++async function getServer(
++    context: vscode.ExtensionContext,
++    config: Config,
++    state: PersistentState
++): Promise<string | undefined> {
++    const explicitPath = serverPath(config);
++    if (explicitPath) {
++        if (explicitPath.startsWith("~/")) {
++            return os.homedir() + explicitPath.slice("~".length);
++        }
++        return explicitPath;
++    }
++    if (config.package.releaseTag === null) return "rust-analyzer";
++
++    const ext = process.platform === "win32" ? ".exe" : "";
++    const bundled = vscode.Uri.joinPath(context.extensionUri, "server", `rust-analyzer${ext}`);
++    const bundledExists = await vscode.workspace.fs.stat(bundled).then(
++        () => true,
++        () => false
++    );
++    if (bundledExists) {
++        let server = bundled;
++        if (await isNixOs()) {
++            await vscode.workspace.fs.createDirectory(config.globalStorageUri).then();
++            const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer${ext}`);
++            let exists = await vscode.workspace.fs.stat(dest).then(
++                () => true,
++                () => false
++            );
++            if (exists && config.package.version !== state.serverVersion) {
++                await vscode.workspace.fs.delete(dest);
++                exists = false;
++            }
++            if (!exists) {
++                await vscode.workspace.fs.copy(bundled, dest);
++                await patchelf(dest);
++            }
++            server = dest;
++        }
++        await state.updateServerVersion(config.package.version);
++        return server.fsPath;
++    }
++
++    await state.updateServerVersion(undefined);
++    await vscode.window.showErrorMessage(
++        "Unfortunately we don't ship binaries for your platform yet. " +
++            "You need to manually clone the rust-analyzer repository and " +
++            "run `cargo xtask install --server` to build the language server from sources. " +
++            "If you feel that your platform should be supported, please create an issue " +
++            "about that [here](https://github.com/rust-lang/rust-analyzer/issues) and we " +
++            "will consider it."
++    );
++    return undefined;
++}
++function serverPath(config: Config): string | null {
++    return process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath;
++}
++
++async function isNixOs(): Promise<boolean> {
++    try {
++        const contents = (
++            await vscode.workspace.fs.readFile(vscode.Uri.file("/etc/os-release"))
++        ).toString();
++        const idString = contents.split("\n").find((a) => a.startsWith("ID=")) || "ID=linux";
++        return idString.indexOf("nixos") !== -1;
++    } catch {
++        return false;
++    }
++}
index 05d4d08f70b62d17436dcb32715011bb53449dd6,0000000000000000000000000000000000000000..fb667619c86be045490827de8a44fe6343243ded
mode 100644,000000..100644
--- /dev/null
@@@ -1,293 -1,0 +1,296 @@@
- import { Workspace } from "./ctx";
- import { substituteVariablesInEnv } from "./config";
- import { outputChannel, traceOutputChannel } from "./main";
 +import * as lc from "vscode-languageclient/node";
 +import * as vscode from "vscode";
 +import * as ra from "../src/lsp_ext";
 +import * as Is from "vscode-languageclient/lib/common/utils/is";
 +import { assert } from "./util";
 +import { WorkspaceEdit } from "vscode";
-     serverPath: string,
-     workspace: Workspace,
-     extraEnv: Env
++import { substituteVSCodeVariables } from "./config";
 +import { randomUUID } from "crypto";
 +
 +export interface Env {
 +    [name: string]: string;
 +}
 +
 +// Command URIs have a form of command:command-name?arguments, where
 +// arguments is a percent-encoded array of data we want to pass along to
 +// the command function. For "Show References" this is a list of all file
 +// URIs with locations of every reference, and it can get quite long.
 +//
 +// To work around it we use an intermediary linkToCommand command. When
 +// we render a command link, a reference to a command with all its arguments
 +// is stored in a map, and instead a linkToCommand link is rendered
 +// with the key to that map.
 +export const LINKED_COMMANDS = new Map<string, ra.CommandLink>();
 +
 +// For now the map is cleaned up periodically (I've set it to every
 +// 10 minutes). In general case we'll probably need to introduce TTLs or
 +// flags to denote ephemeral links (like these in hover popups) and
 +// persistent links and clean those separately. But for now simply keeping
 +// the last few links in the map should be good enough. Likewise, we could
 +// add code to remove a target command from the map after the link is
 +// clicked, but assuming most links in hover sheets won't be clicked anyway
 +// this code won't change the overall memory use much.
 +setInterval(function cleanupOlderCommandLinks() {
 +    // keys are returned in insertion order, we'll keep a few
 +    // of recent keys available, and clean the rest
 +    const keys = [...LINKED_COMMANDS.keys()];
 +    const keysToRemove = keys.slice(0, keys.length - 10);
 +    for (const key of keysToRemove) {
 +        LINKED_COMMANDS.delete(key);
 +    }
 +}, 10 * 60 * 1000);
 +
 +function renderCommand(cmd: ra.CommandLink): string {
 +    const commandId = randomUUID();
 +    LINKED_COMMANDS.set(commandId, cmd);
 +    return `[${cmd.title}](command:rust-analyzer.linkToCommand?${encodeURIComponent(
 +        JSON.stringify([commandId])
 +    )} '${cmd.tooltip}')`;
 +}
 +
 +function renderHoverActions(actions: ra.CommandLinkGroup[]): vscode.MarkdownString {
 +    const text = actions
 +        .map(
 +            (group) =>
 +                (group.title ? group.title + " " : "") +
 +                group.commands.map(renderCommand).join(" | ")
 +        )
 +        .join("___");
 +
 +    const result = new vscode.MarkdownString(text);
 +    result.isTrusted = true;
 +    return result;
 +}
 +
 +export async function createClient(
-     // '.' Is the fallback if no folder is open
-     // TODO?: Workspace folders support Uri's (eg: file://test.txt).
-     // It might be a good idea to test if the uri points to a file.
-     const newEnv = substituteVariablesInEnv(Object.assign({}, process.env, extraEnv));
-     const run: lc.Executable = {
-         command: serverPath,
-         options: { env: newEnv },
-     };
-     const serverOptions: lc.ServerOptions = {
-         run,
-         debug: run,
-     };
-     let initializationOptions = vscode.workspace.getConfiguration("rust-analyzer");
-     if (workspace.kind === "Detached Files") {
-         initializationOptions = {
-             detachedFiles: workspace.files.map((file) => file.uri.fsPath),
-             ...initializationOptions,
-         };
-     }
++    traceOutputChannel: vscode.OutputChannel,
++    outputChannel: vscode.OutputChannel,
++    initializationOptions: vscode.WorkspaceConfiguration,
++    serverOptions: lc.ServerOptions
 +): Promise<lc.LanguageClient> {
-         traceOutputChannel: traceOutputChannel(),
-         outputChannel: outputChannel(),
 +    const clientOptions: lc.LanguageClientOptions = {
 +        documentSelector: [{ scheme: "file", language: "rust" }],
 +        initializationOptions,
 +        diagnosticCollectionName: "rustc",
++        traceOutputChannel,
++        outputChannel,
 +        middleware: {
++            workspace: {
++                // HACK: This is a workaround, when the client has been disposed, VSCode
++                // continues to emit events to the client and the default one for this event
++                // attempt to restart the client for no reason
++                async didChangeWatchedFile(event, next) {
++                    if (client.isRunning()) {
++                        await next(event);
++                    }
++                },
++                async configuration(
++                    params: lc.ConfigurationParams,
++                    token: vscode.CancellationToken,
++                    next: lc.ConfigurationRequest.HandlerSignature
++                ) {
++                    const resp = await next(params, token);
++                    if (resp && Array.isArray(resp)) {
++                        return resp.map((val) => {
++                            return substituteVSCodeVariables(val);
++                        });
++                    } else {
++                        return resp;
++                    }
++                },
++            },
 +            async provideHover(
 +                document: vscode.TextDocument,
 +                position: vscode.Position,
 +                token: vscode.CancellationToken,
 +                _next: lc.ProvideHoverSignature
 +            ) {
 +                const editor = vscode.window.activeTextEditor;
 +                const positionOrRange = editor?.selection?.contains(position)
 +                    ? client.code2ProtocolConverter.asRange(editor.selection)
 +                    : client.code2ProtocolConverter.asPosition(position);
 +                return client
 +                    .sendRequest(
 +                        ra.hover,
 +                        {
 +                            textDocument:
 +                                client.code2ProtocolConverter.asTextDocumentIdentifier(document),
 +                            position: positionOrRange,
 +                        },
 +                        token
 +                    )
 +                    .then(
 +                        (result) => {
 +                            const hover = client.protocol2CodeConverter.asHover(result);
 +                            if (hover) {
 +                                const actions = (<any>result).actions;
 +                                if (actions) {
 +                                    hover.contents.push(renderHoverActions(actions));
 +                                }
 +                            }
 +                            return hover;
 +                        },
 +                        (error) => {
 +                            client.handleFailedRequest(lc.HoverRequest.type, token, error, null);
 +                            return Promise.resolve(null);
 +                        }
 +                    );
 +            },
 +            // Using custom handling of CodeActions to support action groups and snippet edits.
 +            // Note that this means we have to re-implement lazy edit resolving ourselves as well.
 +            async provideCodeActions(
 +                document: vscode.TextDocument,
 +                range: vscode.Range,
 +                context: vscode.CodeActionContext,
 +                token: vscode.CancellationToken,
 +                _next: lc.ProvideCodeActionsSignature
 +            ) {
 +                const params: lc.CodeActionParams = {
 +                    textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
 +                    range: client.code2ProtocolConverter.asRange(range),
 +                    context: await client.code2ProtocolConverter.asCodeActionContext(
 +                        context,
 +                        token
 +                    ),
 +                };
 +                return client.sendRequest(lc.CodeActionRequest.type, params, token).then(
 +                    async (values) => {
 +                        if (values === null) return undefined;
 +                        const result: (vscode.CodeAction | vscode.Command)[] = [];
 +                        const groups = new Map<
 +                            string,
 +                            { index: number; items: vscode.CodeAction[] }
 +                        >();
 +                        for (const item of values) {
 +                            // In our case we expect to get code edits only from diagnostics
 +                            if (lc.CodeAction.is(item)) {
 +                                assert(
 +                                    !item.command,
 +                                    "We don't expect to receive commands in CodeActions"
 +                                );
 +                                const action = await client.protocol2CodeConverter.asCodeAction(
 +                                    item,
 +                                    token
 +                                );
 +                                result.push(action);
 +                                continue;
 +                            }
 +                            assert(
 +                                isCodeActionWithoutEditsAndCommands(item),
 +                                "We don't expect edits or commands here"
 +                            );
 +                            const kind = client.protocol2CodeConverter.asCodeActionKind(
 +                                (item as any).kind
 +                            );
 +                            const action = new vscode.CodeAction(item.title, kind);
 +                            const group = (item as any).group;
 +                            action.command = {
 +                                command: "rust-analyzer.resolveCodeAction",
 +                                title: item.title,
 +                                arguments: [item],
 +                            };
 +
 +                            // Set a dummy edit, so that VS Code doesn't try to resolve this.
 +                            action.edit = new WorkspaceEdit();
 +
 +                            if (group) {
 +                                let entry = groups.get(group);
 +                                if (!entry) {
 +                                    entry = { index: result.length, items: [] };
 +                                    groups.set(group, entry);
 +                                    result.push(action);
 +                                }
 +                                entry.items.push(action);
 +                            } else {
 +                                result.push(action);
 +                            }
 +                        }
 +                        for (const [group, { index, items }] of groups) {
 +                            if (items.length === 1) {
 +                                result[index] = items[0];
 +                            } else {
 +                                const action = new vscode.CodeAction(group);
 +                                action.kind = items[0].kind;
 +                                action.command = {
 +                                    command: "rust-analyzer.applyActionGroup",
 +                                    title: "",
 +                                    arguments: [
 +                                        items.map((item) => {
 +                                            return {
 +                                                label: item.title,
 +                                                arguments: item.command!.arguments![0],
 +                                            };
 +                                        }),
 +                                    ],
 +                                };
 +
 +                                // Set a dummy edit, so that VS Code doesn't try to resolve this.
 +                                action.edit = new WorkspaceEdit();
 +
 +                                result[index] = action;
 +                            }
 +                        }
 +                        return result;
 +                    },
 +                    (_error) => undefined
 +                );
 +            },
 +        },
 +        markdown: {
 +            supportHtml: true,
 +        },
 +    };
 +
 +    const client = new lc.LanguageClient(
 +        "rust-analyzer",
 +        "Rust Analyzer Language Server",
 +        serverOptions,
 +        clientOptions
 +    );
 +
 +    // To turn on all proposed features use: client.registerProposedFeatures();
 +    client.registerFeature(new ExperimentalFeatures());
 +
 +    return client;
 +}
 +
 +class ExperimentalFeatures implements lc.StaticFeature {
++    getState(): lc.FeatureState {
++        return { kind: "static" };
++    }
 +    fillClientCapabilities(capabilities: lc.ClientCapabilities): void {
 +        const caps: any = capabilities.experimental ?? {};
 +        caps.snippetTextEdit = true;
 +        caps.codeActionGroup = true;
 +        caps.hoverActions = true;
 +        caps.serverStatusNotification = true;
 +        caps.commands = {
 +            commands: [
 +                "rust-analyzer.runSingle",
 +                "rust-analyzer.debugSingle",
 +                "rust-analyzer.showReferences",
 +                "rust-analyzer.gotoLocation",
 +                "editor.action.triggerParameterHints",
 +            ],
 +        };
 +        capabilities.experimental = caps;
 +    }
 +    initialize(
 +        _capabilities: lc.ServerCapabilities<any>,
 +        _documentSelector: lc.DocumentSelector | undefined
 +    ): void {}
 +    dispose(): void {}
 +}
 +
 +function isCodeActionWithoutEditsAndCommands(value: any): boolean {
 +    const candidate: lc.CodeAction = value;
 +    return (
 +        candidate &&
 +        Is.string(candidate.title) &&
 +        (candidate.diagnostics === void 0 ||
 +            Is.typedArray(candidate.diagnostics, lc.Diagnostic.is)) &&
 +        (candidate.kind === void 0 || Is.string(candidate.kind)) &&
 +        candidate.edit === void 0 &&
 +        candidate.command === void 0
 +    );
 +}
index b9ad525e361f0e20e5807ac9d2b24ab306d4f716,0000000000000000000000000000000000000000..12ceb4f2df8e1ca360ce86212dc7187cc3adf5e9
mode 100644,000000..100644
--- /dev/null
@@@ -1,948 -1,0 +1,946 @@@
-         provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
 +import * as vscode from "vscode";
 +import * as lc from "vscode-languageclient";
 +import * as ra from "./lsp_ext";
 +import * as path from "path";
 +
 +import { Ctx, Cmd } from "./ctx";
 +import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets";
 +import { spawnSync } from "child_process";
 +import { RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run";
 +import { AstInspector } from "./ast_inspector";
 +import { isRustDocument, isCargoTomlDocument, sleep, isRustEditor } from "./util";
 +import { startDebugSession, makeDebugConfig } from "./debug";
 +import { LanguageClient } from "vscode-languageclient/node";
 +import { LINKED_COMMANDS } from "./client";
 +
 +export * from "./ast_inspector";
 +export * from "./run";
 +
 +export function analyzerStatus(ctx: Ctx): Cmd {
 +    const tdcp = new (class implements vscode.TextDocumentContentProvider {
 +        readonly uri = vscode.Uri.parse("rust-analyzer-status://status");
 +        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 +
-                 params.textDocument =
-                     ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(doc);
++        async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
 +            if (!vscode.window.activeTextEditor) return "";
++            const client = await ctx.getClient();
 +
 +            const params: ra.AnalyzerStatusParams = {};
 +            const doc = ctx.activeRustEditor?.document;
 +            if (doc != null) {
-             return ctx.client.sendRequest(ra.analyzerStatus, params);
++                params.textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(doc);
 +            }
-     ctx.pushCleanup(
++            return await client.sendRequest(ra.analyzerStatus, params);
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
-             return ctx.client.sendRequest(ra.memoryUsage).then((mem: any) => {
-                 return "Per-query memory usage:\n" + mem + "\n(note: database has been cleared)";
-             });
++    ctx.pushExtCleanup(
 +        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-status", tdcp)
 +    );
 +
 +    return async () => {
 +        const document = await vscode.workspace.openTextDocument(tdcp.uri);
 +        tdcp.eventEmitter.fire(tdcp.uri);
 +        void (await vscode.window.showTextDocument(document, {
 +            viewColumn: vscode.ViewColumn.Two,
 +            preserveFocus: true,
 +        }));
 +    };
 +}
 +
 +export function memoryUsage(ctx: Ctx): Cmd {
 +    const tdcp = new (class implements vscode.TextDocumentContentProvider {
 +        readonly uri = vscode.Uri.parse("rust-analyzer-memory://memory");
 +        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 +
 +        provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
 +            if (!vscode.window.activeTextEditor) return "";
 +
-     ctx.pushCleanup(
++            return ctx
++                .getClient()
++                .then((it) => it.sendRequest(ra.memoryUsage))
++                .then((mem: any) => {
++                    return (
++                        "Per-query memory usage:\n" + mem + "\n(note: database has been cleared)"
++                    );
++                });
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
-         const client = ctx.client;
-         if (!client) return;
-         await client.sendRequest(ra.shuffleCrateGraph);
++    ctx.pushExtCleanup(
 +        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-memory", tdcp)
 +    );
 +
 +    return async () => {
 +        tdcp.eventEmitter.fire(tdcp.uri);
 +        const document = await vscode.workspace.openTextDocument(tdcp.uri);
 +        return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
 +    };
 +}
 +
 +export function shuffleCrateGraph(ctx: Ctx): Cmd {
 +    return async () => {
-         const client = ctx.client;
-         if (!editor || !client) return;
++        return ctx.getClient().then((it) => it.sendRequest(ra.shuffleCrateGraph));
 +    };
 +}
 +
 +export function matchingBrace(ctx: Ctx): Cmd {
 +    return async () => {
 +        const editor = ctx.activeRustEditor;
-             textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
-                 editor.document
-             ),
++        if (!editor) return;
++
++        const client = await ctx.getClient();
 +
 +        const response = await client.sendRequest(ra.matchingBrace, {
-         const client = ctx.client;
-         if (!editor || !client) return;
++            textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
 +            positions: editor.selections.map((s) =>
 +                client.code2ProtocolConverter.asPosition(s.active)
 +            ),
 +        });
 +        editor.selections = editor.selections.map((sel, idx) => {
 +            const active = client.protocol2CodeConverter.asPosition(response[idx]);
 +            const anchor = sel.isEmpty ? active : sel.anchor;
 +            return new vscode.Selection(anchor, active);
 +        });
 +        editor.revealRange(editor.selection);
 +    };
 +}
 +
 +export function joinLines(ctx: Ctx): Cmd {
 +    return async () => {
 +        const editor = ctx.activeRustEditor;
-             textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
-                 editor.document
-             ),
++        if (!editor) return;
++
++        const client = await ctx.getClient();
 +
 +        const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, {
 +            ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)),
-         const client = ctx.client;
-         if (!editor || !client) return;
++            textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
 +        });
 +        const textEdits = await client.protocol2CodeConverter.asTextEdits(items);
 +        await editor.edit((builder) => {
 +            textEdits.forEach((edit: any) => {
 +                builder.replace(edit.range, edit.newText);
 +            });
 +        });
 +    };
 +}
 +
 +export function moveItemUp(ctx: Ctx): Cmd {
 +    return moveItem(ctx, ra.Direction.Up);
 +}
 +
 +export function moveItemDown(ctx: Ctx): Cmd {
 +    return moveItem(ctx, ra.Direction.Down);
 +}
 +
 +export function moveItem(ctx: Ctx, direction: ra.Direction): Cmd {
 +    return async () => {
 +        const editor = ctx.activeRustEditor;
-             textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
-                 editor.document
-             ),
++        if (!editor) return;
++        const client = await ctx.getClient();
 +
 +        const lcEdits = await client.sendRequest(ra.moveItem, {
 +            range: client.code2ProtocolConverter.asRange(editor.selection),
-         const client = ctx.client;
++            textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
 +            direction,
 +        });
 +
 +        if (!lcEdits) return;
 +
 +        const edits = await client.protocol2CodeConverter.asTextEdits(lcEdits);
 +        await applySnippetTextEdits(editor, edits);
 +    };
 +}
 +
 +export function onEnter(ctx: Ctx): Cmd {
 +    async function handleKeypress() {
 +        const editor = ctx.activeRustEditor;
-         if (!editor || !client) return false;
 +
-                 textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
++        if (!editor) return false;
 +
++        const client = await ctx.getClient();
 +        const lcEdits = await client
 +            .sendRequest(ra.onEnter, {
-         const client = ctx.client;
-         if (!editor || !client) return;
++                textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                    editor.document
 +                ),
 +                position: client.code2ProtocolConverter.asPosition(editor.selection.active),
 +            })
 +            .catch((_error: any) => {
 +                // client.handleFailedRequest(OnEnterRequest.type, error, null);
 +                return null;
 +            });
 +        if (!lcEdits) return false;
 +
 +        const edits = await client.protocol2CodeConverter.asTextEdits(lcEdits);
 +        await applySnippetTextEdits(editor, edits);
 +        return true;
 +    }
 +
 +    return async () => {
 +        if (await handleKeypress()) return;
 +
 +        await vscode.commands.executeCommand("default:type", { text: "\n" });
 +    };
 +}
 +
 +export function parentModule(ctx: Ctx): Cmd {
 +    return async () => {
 +        const editor = vscode.window.activeTextEditor;
-             textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
-                 editor.document
-             ),
++        if (!editor) return;
 +        if (!(isRustDocument(editor.document) || isCargoTomlDocument(editor.document))) return;
 +
++        const client = await ctx.getClient();
++
 +        const locations = await client.sendRequest(ra.parentModule, {
-         const client = ctx.client;
-         if (!editor || !client) return;
++            textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
 +            position: client.code2ProtocolConverter.asPosition(editor.selection.active),
 +        });
 +        if (!locations) return;
 +
 +        if (locations.length === 1) {
 +            const loc = locations[0];
 +
 +            const uri = client.protocol2CodeConverter.asUri(loc.targetUri);
 +            const range = client.protocol2CodeConverter.asRange(loc.targetRange);
 +
 +            const doc = await vscode.workspace.openTextDocument(uri);
 +            const e = await vscode.window.showTextDocument(doc);
 +            e.selection = new vscode.Selection(range.start, range.start);
 +            e.revealRange(range, vscode.TextEditorRevealType.InCenter);
 +        } else {
 +            const uri = editor.document.uri.toString();
 +            const position = client.code2ProtocolConverter.asPosition(editor.selection.active);
 +            await showReferencesImpl(
 +                client,
 +                uri,
 +                position,
 +                locations.map((loc) => lc.Location.create(loc.targetUri, loc.targetRange))
 +            );
 +        }
 +    };
 +}
 +
 +export function openCargoToml(ctx: Ctx): Cmd {
 +    return async () => {
 +        const editor = ctx.activeRustEditor;
-             textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
-                 editor.document
-             ),
++        if (!editor) return;
 +
++        const client = await ctx.getClient();
 +        const response = await client.sendRequest(ra.openCargoToml, {
-         const client = ctx.client;
-         if (!editor || !client) return;
++            textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
 +        });
 +        if (!response) return;
 +
 +        const uri = client.protocol2CodeConverter.asUri(response.uri);
 +        const range = client.protocol2CodeConverter.asRange(response.range);
 +
 +        const doc = await vscode.workspace.openTextDocument(uri);
 +        const e = await vscode.window.showTextDocument(doc);
 +        e.selection = new vscode.Selection(range.start, range.start);
 +        e.revealRange(range, vscode.TextEditorRevealType.InCenter);
 +    };
 +}
 +
 +export function ssr(ctx: Ctx): Cmd {
 +    return async () => {
 +        const editor = vscode.window.activeTextEditor;
-         const textDocument = ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
++        if (!editor) return;
++
++        const client = await ctx.getClient();
 +
 +        const position = editor.selection.active;
 +        const selections = editor.selections;
-         provideTextDocumentContent(
++        const textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(
 +            editor.document
 +        );
 +
 +        const options: vscode.InputBoxOptions = {
 +            value: "() ==>> ()",
 +            prompt: "Enter request, for example 'Foo($a) ==>> Foo::new($a)' ",
 +            validateInput: async (x: string) => {
 +                try {
 +                    await client.sendRequest(ra.ssr, {
 +                        query: x,
 +                        parseOnly: true,
 +                        textDocument,
 +                        position,
 +                        selections,
 +                    });
 +                } catch (e) {
 +                    return e.toString();
 +                }
 +                return null;
 +            },
 +        };
 +        const request = await vscode.window.showInputBox(options);
 +        if (!request) return;
 +
 +        await vscode.window.withProgress(
 +            {
 +                location: vscode.ProgressLocation.Notification,
 +                title: "Structured search replace in progress...",
 +                cancellable: false,
 +            },
 +            async (_progress, token) => {
 +                const edit = await client.sendRequest(ra.ssr, {
 +                    query: request,
 +                    parseOnly: false,
 +                    textDocument,
 +                    position,
 +                    selections,
 +                });
 +
 +                await vscode.workspace.applyEdit(
 +                    await client.protocol2CodeConverter.asWorkspaceEdit(edit, token)
 +                );
 +            }
 +        );
 +    };
 +}
 +
 +export function serverVersion(ctx: Ctx): Cmd {
 +    return async () => {
++        if (!ctx.serverPath) {
++            void vscode.window.showWarningMessage(`rust-analyzer server is not running`);
++            return;
++        }
 +        const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" });
 +        const versionString = stdout.slice(`rust-analyzer `.length).trim();
 +
 +        void vscode.window.showInformationMessage(`rust-analyzer version: ${versionString}`);
 +    };
 +}
 +
 +// Opens the virtual file that will show the syntax tree
 +//
 +// The contents of the file come from the `TextDocumentContentProvider`
 +export function syntaxTree(ctx: Ctx): Cmd {
 +    const tdcp = new (class implements vscode.TextDocumentContentProvider {
 +        readonly uri = vscode.Uri.parse("rust-analyzer-syntax-tree://syntaxtree/tree.rast");
 +        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 +        constructor() {
 +            vscode.workspace.onDidChangeTextDocument(
 +                this.onDidChangeTextDocument,
 +                this,
 +                ctx.subscriptions
 +            );
 +            vscode.window.onDidChangeActiveTextEditor(
 +                this.onDidChangeActiveTextEditor,
 +                this,
 +                ctx.subscriptions
 +            );
 +        }
 +
 +        private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
 +            if (isRustDocument(event.document)) {
 +                // We need to order this after language server updates, but there's no API for that.
 +                // Hence, good old sleep().
 +                void sleep(10).then(() => this.eventEmitter.fire(this.uri));
 +            }
 +        }
 +        private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
 +            if (editor && isRustEditor(editor)) {
 +                this.eventEmitter.fire(this.uri);
 +            }
 +        }
 +
-         ): vscode.ProviderResult<string> {
++        async provideTextDocumentContent(
 +            uri: vscode.Uri,
 +            ct: vscode.CancellationToken
-                     ? ctx.client.code2ProtocolConverter.asRange(rustEditor.selection)
++        ): Promise<string> {
 +            const rustEditor = ctx.activeRustEditor;
 +            if (!rustEditor) return "";
++            const client = await ctx.getClient();
 +
 +            // When the range based query is enabled we take the range of the selection
 +            const range =
 +                uri.query === "range=true" && !rustEditor.selection.isEmpty
-             return ctx.client.sendRequest(ra.syntaxTree, params, ct);
++                    ? client.code2ProtocolConverter.asRange(rustEditor.selection)
 +                    : null;
 +
 +            const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range };
-     void new AstInspector(ctx);
-     ctx.pushCleanup(
++            return client.sendRequest(ra.syntaxTree, params, ct);
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
-     ctx.pushCleanup(
++    ctx.pushExtCleanup(new AstInspector(ctx));
++    ctx.pushExtCleanup(
 +        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-syntax-tree", tdcp)
 +    );
-         provideTextDocumentContent(
++    ctx.pushExtCleanup(
 +        vscode.languages.setLanguageConfiguration("ra_syntax_tree", {
 +            brackets: [["[", ")"]],
 +        })
 +    );
 +
 +    return async () => {
 +        const editor = vscode.window.activeTextEditor;
 +        const rangeEnabled = !!editor && !editor.selection.isEmpty;
 +
 +        const uri = rangeEnabled ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) : tdcp.uri;
 +
 +        const document = await vscode.workspace.openTextDocument(uri);
 +
 +        tdcp.eventEmitter.fire(uri);
 +
 +        void (await vscode.window.showTextDocument(document, {
 +            viewColumn: vscode.ViewColumn.Two,
 +            preserveFocus: true,
 +        }));
 +    };
 +}
 +
 +// Opens the virtual file that will show the HIR of the function containing the cursor position
 +//
 +// The contents of the file come from the `TextDocumentContentProvider`
 +export function viewHir(ctx: Ctx): Cmd {
 +    const tdcp = new (class implements vscode.TextDocumentContentProvider {
 +        readonly uri = vscode.Uri.parse("rust-analyzer-hir://viewHir/hir.rs");
 +        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 +        constructor() {
 +            vscode.workspace.onDidChangeTextDocument(
 +                this.onDidChangeTextDocument,
 +                this,
 +                ctx.subscriptions
 +            );
 +            vscode.window.onDidChangeActiveTextEditor(
 +                this.onDidChangeActiveTextEditor,
 +                this,
 +                ctx.subscriptions
 +            );
 +        }
 +
 +        private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
 +            if (isRustDocument(event.document)) {
 +                // We need to order this after language server updates, but there's no API for that.
 +                // Hence, good old sleep().
 +                void sleep(10).then(() => this.eventEmitter.fire(this.uri));
 +            }
 +        }
 +        private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
 +            if (editor && isRustEditor(editor)) {
 +                this.eventEmitter.fire(this.uri);
 +            }
 +        }
 +
-         ): vscode.ProviderResult<string> {
++        async provideTextDocumentContent(
 +            _uri: vscode.Uri,
 +            ct: vscode.CancellationToken
-             const client = ctx.client;
-             if (!rustEditor || !client) return "";
++        ): Promise<string> {
 +            const rustEditor = ctx.activeRustEditor;
-     ctx.pushCleanup(
++            if (!rustEditor) return "";
 +
++            const client = await ctx.getClient();
 +            const params = {
 +                textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                    rustEditor.document
 +                ),
 +                position: client.code2ProtocolConverter.asPosition(rustEditor.selection.active),
 +            };
 +            return client.sendRequest(ra.viewHir, params, ct);
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
-         provideTextDocumentContent(
++    ctx.pushExtCleanup(
 +        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-hir", tdcp)
 +    );
 +
 +    return async () => {
 +        const document = await vscode.workspace.openTextDocument(tdcp.uri);
 +        tdcp.eventEmitter.fire(tdcp.uri);
 +        void (await vscode.window.showTextDocument(document, {
 +            viewColumn: vscode.ViewColumn.Two,
 +            preserveFocus: true,
 +        }));
 +    };
 +}
 +
 +export function viewFileText(ctx: Ctx): Cmd {
 +    const tdcp = new (class implements vscode.TextDocumentContentProvider {
 +        readonly uri = vscode.Uri.parse("rust-analyzer-file-text://viewFileText/file.rs");
 +        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 +        constructor() {
 +            vscode.workspace.onDidChangeTextDocument(
 +                this.onDidChangeTextDocument,
 +                this,
 +                ctx.subscriptions
 +            );
 +            vscode.window.onDidChangeActiveTextEditor(
 +                this.onDidChangeActiveTextEditor,
 +                this,
 +                ctx.subscriptions
 +            );
 +        }
 +
 +        private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
 +            if (isRustDocument(event.document)) {
 +                // We need to order this after language server updates, but there's no API for that.
 +                // Hence, good old sleep().
 +                void sleep(10).then(() => this.eventEmitter.fire(this.uri));
 +            }
 +        }
 +        private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
 +            if (editor && isRustEditor(editor)) {
 +                this.eventEmitter.fire(this.uri);
 +            }
 +        }
 +
-         ): vscode.ProviderResult<string> {
++        async provideTextDocumentContent(
 +            _uri: vscode.Uri,
 +            ct: vscode.CancellationToken
-             const client = ctx.client;
-             if (!rustEditor || !client) return "";
++        ): Promise<string> {
 +            const rustEditor = ctx.activeRustEditor;
-     ctx.pushCleanup(
++            if (!rustEditor) return "";
++            const client = await ctx.getClient();
 +
 +            const params = client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                rustEditor.document
 +            );
 +            return client.sendRequest(ra.viewFileText, params, ct);
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
-         provideTextDocumentContent(
++    ctx.pushExtCleanup(
 +        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-file-text", tdcp)
 +    );
 +
 +    return async () => {
 +        const document = await vscode.workspace.openTextDocument(tdcp.uri);
 +        tdcp.eventEmitter.fire(tdcp.uri);
 +        void (await vscode.window.showTextDocument(document, {
 +            viewColumn: vscode.ViewColumn.Two,
 +            preserveFocus: true,
 +        }));
 +    };
 +}
 +
 +export function viewItemTree(ctx: Ctx): Cmd {
 +    const tdcp = new (class implements vscode.TextDocumentContentProvider {
 +        readonly uri = vscode.Uri.parse("rust-analyzer-item-tree://viewItemTree/itemtree.rs");
 +        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 +        constructor() {
 +            vscode.workspace.onDidChangeTextDocument(
 +                this.onDidChangeTextDocument,
 +                this,
 +                ctx.subscriptions
 +            );
 +            vscode.window.onDidChangeActiveTextEditor(
 +                this.onDidChangeActiveTextEditor,
 +                this,
 +                ctx.subscriptions
 +            );
 +        }
 +
 +        private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
 +            if (isRustDocument(event.document)) {
 +                // We need to order this after language server updates, but there's no API for that.
 +                // Hence, good old sleep().
 +                void sleep(10).then(() => this.eventEmitter.fire(this.uri));
 +            }
 +        }
 +        private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
 +            if (editor && isRustEditor(editor)) {
 +                this.eventEmitter.fire(this.uri);
 +            }
 +        }
 +
-         ): vscode.ProviderResult<string> {
++        async provideTextDocumentContent(
 +            _uri: vscode.Uri,
 +            ct: vscode.CancellationToken
-             const client = ctx.client;
-             if (!rustEditor || !client) return "";
++        ): Promise<string> {
 +            const rustEditor = ctx.activeRustEditor;
-     ctx.pushCleanup(
++            if (!rustEditor) return "";
++            const client = await ctx.getClient();
 +
 +            const params = {
 +                textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                    rustEditor.document
 +                ),
 +            };
 +            return client.sendRequest(ra.viewItemTree, params, ct);
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
-         const dot = await ctx.client.sendRequest(ra.viewCrateGraph, params);
++    ctx.pushExtCleanup(
 +        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-item-tree", tdcp)
 +    );
 +
 +    return async () => {
 +        const document = await vscode.workspace.openTextDocument(tdcp.uri);
 +        tdcp.eventEmitter.fire(tdcp.uri);
 +        void (await vscode.window.showTextDocument(document, {
 +            viewColumn: vscode.ViewColumn.Two,
 +            preserveFocus: true,
 +        }));
 +    };
 +}
 +
 +function crateGraph(ctx: Ctx, full: boolean): Cmd {
 +    return async () => {
 +        const nodeModulesPath = vscode.Uri.file(path.join(ctx.extensionPath, "node_modules"));
 +
 +        const panel = vscode.window.createWebviewPanel(
 +            "rust-analyzer.crate-graph",
 +            "rust-analyzer crate graph",
 +            vscode.ViewColumn.Two,
 +            {
 +                enableScripts: true,
 +                retainContextWhenHidden: true,
 +                localResourceRoots: [nodeModulesPath],
 +            }
 +        );
 +        const params = {
 +            full: full,
 +        };
-             const client = ctx.client;
-             if (!editor || !client) return "";
++        const client = await ctx.getClient();
++        const dot = await client.sendRequest(ra.viewCrateGraph, params);
 +        const uri = panel.webview.asWebviewUri(nodeModulesPath);
 +
 +        const html = `
 +            <!DOCTYPE html>
 +            <meta charset="utf-8">
 +            <head>
 +                <style>
 +                    /* Fill the entire view */
 +                    html, body { margin:0; padding:0; overflow:hidden }
 +                    svg { position:fixed; top:0; left:0; height:100%; width:100% }
 +
 +                    /* Disable the graphviz background and fill the polygons */
 +                    .graph > polygon { display:none; }
 +                    :is(.node,.edge) polygon { fill: white; }
 +
 +                    /* Invert the line colours for dark themes */
 +                    body:not(.vscode-light) .edge path { stroke: white; }
 +                </style>
 +            </head>
 +            <body>
 +                <script type="text/javascript" src="${uri}/d3/dist/d3.min.js"></script>
 +                <script type="text/javascript" src="${uri}/@hpcc-js/wasm/dist/index.min.js"></script>
 +                <script type="text/javascript" src="${uri}/d3-graphviz/build/d3-graphviz.min.js"></script>
 +                <div id="graph"></div>
 +                <script>
 +                    let graph = d3.select("#graph")
 +                                  .graphviz()
 +                                  .fit(true)
 +                                  .zoomScaleExtent([0.1, Infinity])
 +                                  .renderDot(\`${dot}\`);
 +
 +                    d3.select(window).on("click", (event) => {
 +                        if (event.ctrlKey) {
 +                            graph.resetZoom(d3.transition().duration(100));
 +                        }
 +                    });
 +                </script>
 +            </body>
 +            `;
 +
 +        panel.webview.html = html;
 +    };
 +}
 +
 +export function viewCrateGraph(ctx: Ctx): Cmd {
 +    return crateGraph(ctx, false);
 +}
 +
 +export function viewFullCrateGraph(ctx: Ctx): Cmd {
 +    return crateGraph(ctx, true);
 +}
 +
 +// Opens the virtual file that will show the syntax tree
 +//
 +// The contents of the file come from the `TextDocumentContentProvider`
 +export function expandMacro(ctx: Ctx): Cmd {
 +    function codeFormat(expanded: ra.ExpandedMacro): string {
 +        let result = `// Recursive expansion of ${expanded.name}! macro\n`;
 +        result += "// " + "=".repeat(result.length - 3);
 +        result += "\n\n";
 +        result += expanded.expansion;
 +
 +        return result;
 +    }
 +
 +    const tdcp = new (class implements vscode.TextDocumentContentProvider {
 +        uri = vscode.Uri.parse("rust-analyzer-expand-macro://expandMacro/[EXPANSION].rs");
 +        eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 +        async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
 +            const editor = vscode.window.activeTextEditor;
-                 textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
++            if (!editor) return "";
++            const client = await ctx.getClient();
 +
 +            const position = editor.selection.active;
 +
 +            const expanded = await client.sendRequest(ra.expandMacro, {
-     ctx.pushCleanup(
++                textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                    editor.document
 +                ),
 +                position,
 +            });
 +
 +            if (expanded == null) return "Not available";
 +
 +            return codeFormat(expanded);
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
-     return async () => ctx.client.sendRequest(ra.reloadWorkspace);
++    ctx.pushExtCleanup(
 +        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-expand-macro", tdcp)
 +    );
 +
 +    return async () => {
 +        const document = await vscode.workspace.openTextDocument(tdcp.uri);
 +        tdcp.eventEmitter.fire(tdcp.uri);
 +        return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
 +    };
 +}
 +
 +export function reloadWorkspace(ctx: Ctx): Cmd {
-     client: LanguageClient,
++    return async () => (await ctx.getClient()).sendRequest(ra.reloadWorkspace);
 +}
 +
 +async function showReferencesImpl(
-         await showReferencesImpl(ctx.client, uri, position, locations);
++    client: LanguageClient | undefined,
 +    uri: string,
 +    position: lc.Position,
 +    locations: lc.Location[]
 +) {
 +    if (client) {
 +        await vscode.commands.executeCommand(
 +            "editor.action.showReferences",
 +            vscode.Uri.parse(uri),
 +            client.protocol2CodeConverter.asPosition(position),
 +            locations.map(client.protocol2CodeConverter.asLocation)
 +        );
 +    }
 +}
 +
 +export function showReferences(ctx: Ctx): Cmd {
 +    return async (uri: string, position: lc.Position, locations: lc.Location[]) => {
-         const client = ctx.client;
-         if (client) {
-             const uri = client.protocol2CodeConverter.asUri(locationLink.targetUri);
-             let range = client.protocol2CodeConverter.asRange(locationLink.targetSelectionRange);
-             // collapse the range to a cursor position
-             range = range.with({ end: range.start });
++        await showReferencesImpl(await ctx.getClient(), uri, position, locations);
 +    };
 +}
 +
 +export function applyActionGroup(_ctx: Ctx): Cmd {
 +    return async (actions: { label: string; arguments: lc.CodeAction }[]) => {
 +        const selectedAction = await vscode.window.showQuickPick(actions);
 +        if (!selectedAction) return;
 +        await vscode.commands.executeCommand(
 +            "rust-analyzer.resolveCodeAction",
 +            selectedAction.arguments
 +        );
 +    };
 +}
 +
 +export function gotoLocation(ctx: Ctx): Cmd {
 +    return async (locationLink: lc.LocationLink) => {
-             await vscode.window.showTextDocument(uri, { selection: range });
-         }
++        const client = await ctx.getClient();
++        const uri = client.protocol2CodeConverter.asUri(locationLink.targetUri);
++        let range = client.protocol2CodeConverter.asRange(locationLink.targetSelectionRange);
++        // collapse the range to a cursor position
++        range = range.with({ end: range.start });
 +
-         const client = ctx.client;
++        await vscode.window.showTextDocument(uri, { selection: range });
 +    };
 +}
 +
 +export function openDocs(ctx: Ctx): Cmd {
 +    return async () => {
-         if (!editor || !client) {
 +        const editor = vscode.window.activeTextEditor;
-         await ctx.client.sendRequest(ra.cancelFlycheck);
++        if (!editor) {
 +            return;
 +        }
++        const client = await ctx.getClient();
 +
 +        const position = editor.selection.active;
 +        const textDocument = { uri: editor.document.uri.toString() };
 +
 +        const doclink = await client.sendRequest(ra.openDocs, { position, textDocument });
 +
 +        if (doclink != null) {
 +            await vscode.commands.executeCommand("vscode.open", vscode.Uri.parse(doclink));
 +        }
 +    };
 +}
 +
 +export function cancelFlycheck(ctx: Ctx): Cmd {
 +    return async () => {
-     const client = ctx.client;
++        const client = await ctx.getClient();
++        await client.sendRequest(ra.cancelFlycheck);
 +    };
 +}
 +
 +export function resolveCodeAction(ctx: Ctx): Cmd {
-         const item = await client.sendRequest(lc.CodeActionResolveRequest.type, params);
-         if (!item.edit) {
 +    return async (params: lc.CodeAction) => {
++        const client = await ctx.getClient();
 +        params.command = undefined;
-         const edit = await client.protocol2CodeConverter.asWorkspaceEdit(itemEdit);
++        const item = await client?.sendRequest(lc.CodeActionResolveRequest.type, params);
++        if (!item?.edit) {
 +            return;
 +        }
 +        const itemEdit = item.edit;
-     const client = ctx.client;
++        const edit = await client?.protocol2CodeConverter.asWorkspaceEdit(itemEdit);
 +        // filter out all text edits and recreate the WorkspaceEdit without them so we can apply
 +        // snippet edits on our own
 +        const lcFileSystemEdit = {
 +            ...itemEdit,
 +            documentChanges: itemEdit.documentChanges?.filter((change) => "kind" in change),
 +        };
 +        const fileSystemEdit = await client.protocol2CodeConverter.asWorkspaceEdit(
 +            lcFileSystemEdit
 +        );
 +        await vscode.workspace.applyEdit(fileSystemEdit);
 +        await applySnippetWorkspaceEdit(edit);
 +        if (item.command != null) {
 +            await vscode.commands.executeCommand(item.command.command, item.command.arguments);
 +        }
 +    };
 +}
 +
 +export function applySnippetWorkspaceEditCommand(_ctx: Ctx): Cmd {
 +    return async (edit: vscode.WorkspaceEdit) => {
 +        await applySnippetWorkspaceEdit(edit);
 +    };
 +}
 +
 +export function run(ctx: Ctx): Cmd {
 +    let prevRunnable: RunnableQuickPick | undefined;
 +
 +    return async () => {
 +        const item = await selectRunnable(ctx, prevRunnable);
 +        if (!item) return;
 +
 +        item.detail = "rerun";
 +        prevRunnable = item;
 +        const task = await createTask(item.runnable, ctx.config);
 +        return await vscode.tasks.executeTask(task);
 +    };
 +}
 +
 +export function peekTests(ctx: Ctx): Cmd {
-         if (!editor || !client) return;
 +    return async () => {
 +        const editor = ctx.activeRustEditor;
- export function linkToCommand(ctx: Ctx): Cmd {
++        if (!editor) return;
++        const client = await ctx.getClient();
 +
 +        await vscode.window.withProgress(
 +            {
 +                location: vscode.ProgressLocation.Notification,
 +                title: "Looking for tests...",
 +                cancellable: false,
 +            },
 +            async (_progress, _token) => {
 +                const uri = editor.document.uri.toString();
 +                const position = client.code2ProtocolConverter.asPosition(editor.selection.active);
 +
 +                const tests = await client.sendRequest(ra.relatedTests, {
 +                    textDocument: { uri: uri },
 +                    position: position,
 +                });
 +                const locations: lc.Location[] = tests.map((it) =>
 +                    lc.Location.create(
 +                        it.runnable.location!.targetUri,
 +                        it.runnable.location!.targetSelectionRange
 +                    )
 +                );
 +
 +                await showReferencesImpl(client, uri, position, locations);
 +            }
 +        );
 +    };
 +}
 +
 +export function runSingle(ctx: Ctx): Cmd {
 +    return async (runnable: ra.Runnable) => {
 +        const editor = ctx.activeRustEditor;
 +        if (!editor) return;
 +
 +        const task = await createTask(runnable, ctx.config);
 +        task.group = vscode.TaskGroup.Build;
 +        task.presentationOptions = {
 +            reveal: vscode.TaskRevealKind.Always,
 +            panel: vscode.TaskPanelKind.Dedicated,
 +            clear: true,
 +        };
 +
 +        return vscode.tasks.executeTask(task);
 +    };
 +}
 +
 +export function copyRunCommandLine(ctx: Ctx) {
 +    let prevRunnable: RunnableQuickPick | undefined;
 +    return async () => {
 +        const item = await selectRunnable(ctx, prevRunnable);
 +        if (!item) return;
 +        const args = createArgs(item.runnable);
 +        const commandLine = ["cargo", ...args].join(" ");
 +        await vscode.env.clipboard.writeText(commandLine);
 +        await vscode.window.showInformationMessage("Cargo invocation copied to the clipboard.");
 +    };
 +}
 +
 +export function debug(ctx: Ctx): Cmd {
 +    let prevDebuggee: RunnableQuickPick | undefined;
 +
 +    return async () => {
 +        const item = await selectRunnable(ctx, prevDebuggee, true);
 +        if (!item) return;
 +
 +        item.detail = "restart";
 +        prevDebuggee = item;
 +        return await startDebugSession(ctx, item.runnable);
 +    };
 +}
 +
 +export function debugSingle(ctx: Ctx): Cmd {
 +    return async (config: ra.Runnable) => {
 +        await startDebugSession(ctx, config);
 +    };
 +}
 +
 +export function newDebugConfig(ctx: Ctx): Cmd {
 +    return async () => {
 +        const item = await selectRunnable(ctx, undefined, true, false);
 +        if (!item) return;
 +
 +        await makeDebugConfig(ctx, item.runnable);
 +    };
 +}
 +
-         if (ctx.client && link) {
++export function linkToCommand(_: Ctx): Cmd {
 +    return async (commandId: string) => {
 +        const link = LINKED_COMMANDS.get(commandId);
++        if (link) {
 +            const { command, arguments: args = [] } = link;
 +            await vscode.commands.executeCommand(command, ...args);
 +        }
 +    };
 +}
index 15846a5e8645e67fd6d2888a81b4b1ca862efefc,0000000000000000000000000000000000000000..632a7d86faa369dcf3da8c1395b1d3c479730412
mode 100644,000000..100644
--- /dev/null
@@@ -1,314 -1,0 +1,395 @@@
- import path = require("path");
++import * as path from "path";
++import * as os from "os";
 +import * as vscode from "vscode";
 +import { Env } from "./client";
 +import { log } from "./util";
 +
 +export type RunnableEnvCfg =
 +    | undefined
 +    | Record<string, string>
 +    | { mask?: string; env: Record<string, string> }[];
 +
 +export class Config {
 +    readonly extensionId = "rust-lang.rust-analyzer";
++    configureLang: vscode.Disposable | undefined;
 +
 +    readonly rootSection = "rust-analyzer";
-     private readonly requiresWorkspaceReloadOpts = [
-         "serverPath",
-         "server",
-         // FIXME: This shouldn't be here, changing this setting should reload
-         // `continueCommentsOnNewline` behavior without restart
-         "typing",
-     ].map((opt) => `${this.rootSection}.${opt}`);
 +    private readonly requiresReloadOpts = [
 +        "cargo",
 +        "procMacro",
++        "serverPath",
++        "server",
 +        "files",
 +        "lens", // works as lens.*
-     ]
-         .map((opt) => `${this.rootSection}.${opt}`)
-         .concat(this.requiresWorkspaceReloadOpts);
++    ].map((opt) => `${this.rootSection}.${opt}`);
 +
 +    readonly package: {
 +        version: string;
 +        releaseTag: string | null;
 +        enableProposedApi: boolean | undefined;
 +    } = vscode.extensions.getExtension(this.extensionId)!.packageJSON;
 +
 +    readonly globalStorageUri: vscode.Uri;
 +
 +    constructor(ctx: vscode.ExtensionContext) {
 +        this.globalStorageUri = ctx.globalStorageUri;
 +        vscode.workspace.onDidChangeConfiguration(
 +            this.onDidChangeConfiguration,
 +            this,
 +            ctx.subscriptions
 +        );
 +        this.refreshLogging();
++        this.configureLanguage();
++    }
++
++    dispose() {
++        this.configureLang?.dispose();
 +    }
 +
 +    private refreshLogging() {
 +        log.setEnabled(this.traceExtension);
 +        log.info("Extension version:", this.package.version);
 +
 +        const cfg = Object.entries(this.cfg).filter(([_, val]) => !(val instanceof Function));
 +        log.info("Using configuration", Object.fromEntries(cfg));
 +    }
 +
 +    private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) {
 +        this.refreshLogging();
 +
++        this.configureLanguage();
++
 +        const requiresReloadOpt = this.requiresReloadOpts.find((opt) =>
 +            event.affectsConfiguration(opt)
 +        );
 +
 +        if (!requiresReloadOpt) return;
 +
-         const requiresWorkspaceReloadOpt = this.requiresWorkspaceReloadOpts.find((opt) =>
-             event.affectsConfiguration(opt)
-         );
-         if (!requiresWorkspaceReloadOpt && this.restartServerOnConfigChange) {
++        if (this.restartServerOnConfigChange) {
 +            await vscode.commands.executeCommand("rust-analyzer.reload");
 +            return;
 +        }
 +
-         const message = requiresWorkspaceReloadOpt
-             ? `Changing "${requiresWorkspaceReloadOpt}" requires a window reload`
-             : `Changing "${requiresReloadOpt}" requires a reload`;
-         const userResponse = await vscode.window.showInformationMessage(message, "Reload now");
-         if (userResponse === "Reload now") {
-             const command = requiresWorkspaceReloadOpt
-                 ? "workbench.action.reloadWindow"
-                 : "rust-analyzer.reload";
-             if (userResponse === "Reload now") {
-                 await vscode.commands.executeCommand(command);
-             }
++        const message = `Changing "${requiresReloadOpt}" requires a server restart`;
++        const userResponse = await vscode.window.showInformationMessage(message, "Restart now");
++
++        if (userResponse) {
++            const command = "rust-analyzer.reload";
++            await vscode.commands.executeCommand(command);
++        }
++    }
++
++    /**
++     * Sets up additional language configuration that's impossible to do via a
++     * separate language-configuration.json file. See [1] for more information.
++     *
++     * [1]: https://github.com/Microsoft/vscode/issues/11514#issuecomment-244707076
++     */
++    private configureLanguage() {
++        if (this.typingContinueCommentsOnNewline && !this.configureLang) {
++            const indentAction = vscode.IndentAction.None;
++
++            this.configureLang = vscode.languages.setLanguageConfiguration("rust", {
++                onEnterRules: [
++                    {
++                        // Doc single-line comment
++                        // e.g. ///|
++                        beforeText: /^\s*\/{3}.*$/,
++                        action: { indentAction, appendText: "/// " },
++                    },
++                    {
++                        // Parent doc single-line comment
++                        // e.g. //!|
++                        beforeText: /^\s*\/{2}\!.*$/,
++                        action: { indentAction, appendText: "//! " },
++                    },
++                    {
++                        // Begins an auto-closed multi-line comment (standard or parent doc)
++                        // e.g. /** | */ or /*! | */
++                        beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
++                        afterText: /^\s*\*\/$/,
++                        action: {
++                            indentAction: vscode.IndentAction.IndentOutdent,
++                            appendText: " * ",
++                        },
++                    },
++                    {
++                        // Begins a multi-line comment (standard or parent doc)
++                        // e.g. /** ...| or /*! ...|
++                        beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
++                        action: { indentAction, appendText: " * " },
++                    },
++                    {
++                        // Continues a multi-line comment
++                        // e.g.  * ...|
++                        beforeText: /^(\ \ )*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
++                        action: { indentAction, appendText: "* " },
++                    },
++                    {
++                        // Dedents after closing a multi-line comment
++                        // e.g.  */|
++                        beforeText: /^(\ \ )*\ \*\/\s*$/,
++                        action: { indentAction, removeText: 1 },
++                    },
++                ],
++            });
++        }
++        if (!this.typingContinueCommentsOnNewline && this.configureLang) {
++            this.configureLang.dispose();
++            this.configureLang = undefined;
 +        }
 +    }
 +
 +    // We don't do runtime config validation here for simplicity. More on stackoverflow:
 +    // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension
 +
 +    private get cfg(): vscode.WorkspaceConfiguration {
 +        return vscode.workspace.getConfiguration(this.rootSection);
 +    }
 +
 +    /**
 +     * Beware that postfix `!` operator erases both `null` and `undefined`.
 +     * This is why the following doesn't work as expected:
 +     *
 +     * ```ts
 +     * const nullableNum = vscode
 +     *  .workspace
 +     *  .getConfiguration
 +     *  .getConfiguration("rust-analyzer")
 +     *  .get<number | null>(path)!;
 +     *
 +     * // What happens is that type of `nullableNum` is `number` but not `null | number`:
 +     * const fullFledgedNum: number = nullableNum;
 +     * ```
 +     * So this getter handles this quirk by not requiring the caller to use postfix `!`
 +     */
 +    private get<T>(path: string): T {
 +        return this.cfg.get<T>(path)!;
 +    }
 +
 +    get serverPath() {
 +        return this.get<null | string>("server.path") ?? this.get<null | string>("serverPath");
 +    }
 +    get serverExtraEnv(): Env {
 +        const extraEnv =
 +            this.get<{ [key: string]: string | number } | null>("server.extraEnv") ?? {};
 +        return Object.fromEntries(
 +            Object.entries(extraEnv).map(([k, v]) => [k, typeof v !== "string" ? v.toString() : v])
 +        );
 +    }
 +    get traceExtension() {
 +        return this.get<boolean>("trace.extension");
 +    }
 +
 +    get cargoRunner() {
 +        return this.get<string | undefined>("cargoRunner");
 +    }
 +
 +    get runnableEnv() {
 +        const item = this.get<any>("runnableEnv");
 +        if (!item) return item;
 +        const fixRecord = (r: Record<string, any>) => {
 +            for (const key in r) {
 +                if (typeof r[key] !== "string") {
 +                    r[key] = String(r[key]);
 +                }
 +            }
 +        };
 +        if (item instanceof Array) {
 +            item.forEach((x) => fixRecord(x.env));
 +        } else {
 +            fixRecord(item);
 +        }
 +        return item;
 +    }
 +
 +    get restartServerOnConfigChange() {
 +        return this.get<boolean>("restartServerOnConfigChange");
 +    }
 +
 +    get typingContinueCommentsOnNewline() {
 +        return this.get<boolean>("typing.continueCommentsOnNewline");
 +    }
 +
 +    get debug() {
 +        let sourceFileMap = this.get<Record<string, string> | "auto">("debug.sourceFileMap");
 +        if (sourceFileMap !== "auto") {
 +            // "/rustc/<id>" used by suggestions only.
 +            const { ["/rustc/<id>"]: _, ...trimmed } =
 +                this.get<Record<string, string>>("debug.sourceFileMap");
 +            sourceFileMap = trimmed;
 +        }
 +
 +        return {
 +            engine: this.get<string>("debug.engine"),
 +            engineSettings: this.get<object>("debug.engineSettings"),
 +            openDebugPane: this.get<boolean>("debug.openDebugPane"),
 +            sourceFileMap: sourceFileMap,
 +        };
 +    }
 +
 +    get hoverActions() {
 +        return {
 +            enable: this.get<boolean>("hover.actions.enable"),
 +            implementations: this.get<boolean>("hover.actions.implementations.enable"),
 +            references: this.get<boolean>("hover.actions.references.enable"),
 +            run: this.get<boolean>("hover.actions.run.enable"),
 +            debug: this.get<boolean>("hover.actions.debug.enable"),
 +            gotoTypeDef: this.get<boolean>("hover.actions.gotoTypeDef.enable"),
 +        };
 +    }
 +}
 +
++const VarRegex = new RegExp(/\$\{(.+?)\}/g);
++
++export function substituteVSCodeVariableInString(val: string): string {
++    return val.replace(VarRegex, (substring: string, varName) => {
++        if (typeof varName === "string") {
++            return computeVscodeVar(varName) || substring;
++        } else {
++            return substring;
++        }
++    });
++}
++
++export function substituteVSCodeVariables(resp: any): any {
++    if (typeof resp === "string") {
++        return substituteVSCodeVariableInString(resp);
++    } else if (resp && Array.isArray(resp)) {
++        return resp.map((val) => {
++            return substituteVSCodeVariables(val);
++        });
++    } else if (resp && typeof resp === "object") {
++        const res: { [key: string]: any } = {};
++        for (const key in resp) {
++            const val = resp[key];
++            res[key] = substituteVSCodeVariables(val);
++        }
++        return res;
++    } else if (typeof resp === "function") {
++        return null;
++    }
++    return resp;
++}
 +export function substituteVariablesInEnv(env: Env): Env {
 +    const missingDeps = new Set<string>();
 +    // vscode uses `env:ENV_NAME` for env vars resolution, and it's easier
 +    // to follow the same convention for our dependency tracking
 +    const definedEnvKeys = new Set(Object.keys(env).map((key) => `env:${key}`));
 +    const envWithDeps = Object.fromEntries(
 +        Object.entries(env).map(([key, value]) => {
 +            const deps = new Set<string>();
 +            const depRe = new RegExp(/\${(?<depName>.+?)}/g);
 +            let match = undefined;
 +            while ((match = depRe.exec(value))) {
 +                const depName = match.groups!.depName;
 +                deps.add(depName);
 +                // `depName` at this point can have a form of `expression` or
 +                // `prefix:expression`
 +                if (!definedEnvKeys.has(depName)) {
 +                    missingDeps.add(depName);
 +                }
 +            }
 +            return [`env:${key}`, { deps: [...deps], value }];
 +        })
 +    );
 +
 +    const resolved = new Set<string>();
 +    for (const dep of missingDeps) {
 +        const match = /(?<prefix>.*?):(?<body>.+)/.exec(dep);
 +        if (match) {
 +            const { prefix, body } = match.groups!;
 +            if (prefix === "env") {
 +                const envName = body;
 +                envWithDeps[dep] = {
 +                    value: process.env[envName] ?? "",
 +                    deps: [],
 +                };
 +                resolved.add(dep);
 +            } else {
 +                // we can't handle other prefixes at the moment
 +                // leave values as is, but still mark them as resolved
 +                envWithDeps[dep] = {
 +                    value: "${" + dep + "}",
 +                    deps: [],
 +                };
 +                resolved.add(dep);
 +            }
 +        } else {
 +            envWithDeps[dep] = {
-                 value: computeVscodeVar(dep),
++                value: computeVscodeVar(dep) || "${" + dep + "}",
 +                deps: [],
 +            };
 +        }
 +    }
 +    const toResolve = new Set(Object.keys(envWithDeps));
 +
 +    let leftToResolveSize;
 +    do {
 +        leftToResolveSize = toResolve.size;
 +        for (const key of toResolve) {
 +            if (envWithDeps[key].deps.every((dep) => resolved.has(dep))) {
 +                envWithDeps[key].value = envWithDeps[key].value.replace(
 +                    /\${(?<depName>.+?)}/g,
 +                    (_wholeMatch, depName) => {
 +                        return envWithDeps[depName].value;
 +                    }
 +                );
 +                resolved.add(key);
 +                toResolve.delete(key);
 +            }
 +        }
 +    } while (toResolve.size > 0 && toResolve.size < leftToResolveSize);
 +
 +    const resolvedEnv: Env = {};
 +    for (const key of Object.keys(env)) {
 +        resolvedEnv[key] = envWithDeps[`env:${key}`].value;
 +    }
 +    return resolvedEnv;
 +}
 +
- function computeVscodeVar(varName: string): string {
++function computeVscodeVar(varName: string): string | null {
++    const workspaceFolder = () => {
++        const folders = vscode.workspace.workspaceFolders ?? [];
++        if (folders.length === 1) {
++            // TODO: support for remote workspaces?
++            return folders[0].uri.fsPath;
++        } else if (folders.length > 1) {
++            // could use currently opened document to detect the correct
++            // workspace. However, that would be determined by the document
++            // user has opened on Editor startup. Could lead to
++            // unpredictable workspace selection in practice.
++            // It's better to pick the first one
++            return folders[0].uri.fsPath;
++        } else {
++            // no workspace opened
++            return "";
++        }
++    };
 +    // https://code.visualstudio.com/docs/editor/variables-reference
 +    const supportedVariables: { [k: string]: () => string } = {
-         workspaceFolder: () => {
-             const folders = vscode.workspace.workspaceFolders ?? [];
-             if (folders.length === 1) {
-                 // TODO: support for remote workspaces?
-                 return folders[0].uri.fsPath;
-             } else if (folders.length > 1) {
-                 // could use currently opened document to detect the correct
-                 // workspace. However, that would be determined by the document
-                 // user has opened on Editor startup. Could lead to
-                 // unpredictable workspace selection in practice.
-                 // It's better to pick the first one
-                 return folders[0].uri.fsPath;
-             } else {
-                 // no workspace opened
-                 return "";
-             }
-         },
++        workspaceFolder,
 +
 +        workspaceFolderBasename: () => {
-             const workspaceFolder = computeVscodeVar("workspaceFolder");
-             if (workspaceFolder) {
-                 return path.basename(workspaceFolder);
-             } else {
-                 return "";
-             }
++            return path.basename(workspaceFolder());
 +        },
 +
 +        cwd: () => process.cwd(),
++        userHome: () => os.homedir(),
 +
 +        // see
 +        // https://github.com/microsoft/vscode/blob/08ac1bb67ca2459496b272d8f4a908757f24f56f/src/vs/workbench/api/common/extHostVariableResolverService.ts#L81
 +        // or
 +        // https://github.com/microsoft/vscode/blob/29eb316bb9f154b7870eb5204ec7f2e7cf649bec/src/vs/server/node/remoteTerminalChannel.ts#L56
 +        execPath: () => process.env.VSCODE_EXEC_PATH ?? process.execPath,
 +
 +        pathSeparator: () => path.sep,
 +    };
 +
 +    if (varName in supportedVariables) {
 +        return supportedVariables[varName]();
 +    } else {
-         // can't resolve, keep the expression as is
-         return "${" + varName + "}";
++        // return "${" + varName + "}";
++        return null;
 +    }
 +}
index 26510011d43970cd415b8f13a731a0af1cc0a120,0000000000000000000000000000000000000000..044a9470aa94782748ced04c732f59aa7412da0e
mode 100644,000000..100644
--- /dev/null
@@@ -1,122 -1,0 +1,254 @@@
- import { Config } from "./config";
 +import * as vscode from "vscode";
 +import * as lc from "vscode-languageclient/node";
 +import * as ra from "./lsp_ext";
 +
- import { isRustEditor, RustEditor } from "./util";
++import { Config, substituteVariablesInEnv, substituteVSCodeVariables } from "./config";
 +import { createClient } from "./client";
-     private constructor(
-         readonly config: Config,
-         private readonly extCtx: vscode.ExtensionContext,
-         readonly client: lc.LanguageClient,
-         readonly serverPath: string,
-         readonly statusBar: vscode.StatusBarItem
-     ) {}
-     static async create(
-         config: Config,
-         extCtx: vscode.ExtensionContext,
-         serverPath: string,
-         workspace: Workspace
-     ): Promise<Ctx> {
-         const client = await createClient(serverPath, workspace, config.serverExtraEnv);
-         const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
-         extCtx.subscriptions.push(statusBar);
-         statusBar.text = "rust-analyzer";
-         statusBar.tooltip = "ready";
-         statusBar.command = "rust-analyzer.analyzerStatus";
-         statusBar.show();
-         const res = new Ctx(config, extCtx, client, serverPath, statusBar);
-         res.pushCleanup(client.start());
-         await client.onReady();
-         client.onNotification(ra.serverStatus, (params) => res.setServerStatus(params));
-         return res;
++import { isRustEditor, log, RustEditor } from "./util";
 +import { ServerStatusParams } from "./lsp_ext";
++import { PersistentState } from "./persistent_state";
++import { bootstrap } from "./bootstrap";
 +
 +export type Workspace =
 +    | {
 +          kind: "Workspace Folder";
 +      }
 +    | {
 +          kind: "Detached Files";
 +          files: vscode.TextDocument[];
 +      };
 +
++export type CommandFactory = {
++    enabled: (ctx: Ctx) => Cmd;
++    disabled?: (ctx: Ctx) => Cmd;
++};
++
 +export class Ctx {
-     get activeRustEditor(): RustEditor | undefined {
-         const editor = vscode.window.activeTextEditor;
-         return editor && isRustEditor(editor) ? editor : undefined;
++    readonly statusBar: vscode.StatusBarItem;
++    readonly config: Config;
++
++    private client: lc.LanguageClient | undefined;
++    private _serverPath: string | undefined;
++    private traceOutputChannel: vscode.OutputChannel | undefined;
++    private outputChannel: vscode.OutputChannel | undefined;
++    private clientSubscriptions: Disposable[];
++    private state: PersistentState;
++    private commandFactories: Record<string, CommandFactory>;
++    private commandDisposables: Disposable[];
++
++    workspace: Workspace;
++
++    constructor(
++        readonly extCtx: vscode.ExtensionContext,
++        workspace: Workspace,
++        commandFactories: Record<string, CommandFactory>
++    ) {
++        extCtx.subscriptions.push(this);
++        this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
++        this.statusBar.text = "rust-analyzer";
++        this.statusBar.tooltip = "ready";
++        this.statusBar.command = "rust-analyzer.analyzerStatus";
++        this.statusBar.show();
++        this.workspace = workspace;
++        this.clientSubscriptions = [];
++        this.commandDisposables = [];
++        this.commandFactories = commandFactories;
++
++        this.state = new PersistentState(extCtx.globalState);
++        this.config = new Config(extCtx);
++
++        this.updateCommands();
 +    }
 +
-     get visibleRustEditors(): RustEditor[] {
-         return vscode.window.visibleTextEditors.filter(isRustEditor);
++    dispose() {
++        this.config.dispose();
++        this.statusBar.dispose();
++        void this.disposeClient();
++        this.commandDisposables.forEach((disposable) => disposable.dispose());
 +    }
 +
-     registerCommand(name: string, factory: (ctx: Ctx) => Cmd) {
-         const fullName = `rust-analyzer.${name}`;
-         const cmd = factory(this);
-         const d = vscode.commands.registerCommand(fullName, cmd);
-         this.pushCleanup(d);
++    clientFetcher() {
++        const self = this;
++        return {
++            get client(): lc.LanguageClient | undefined {
++                return self.client;
++            },
++        };
 +    }
 +
-     get extensionPath(): string {
-         return this.extCtx.extensionPath;
++    async getClient() {
++        if (!this.traceOutputChannel) {
++            this.traceOutputChannel = vscode.window.createOutputChannel(
++                "Rust Analyzer Language Server Trace"
++            );
++            this.pushExtCleanup(this.traceOutputChannel);
++        }
++        if (!this.outputChannel) {
++            this.outputChannel = vscode.window.createOutputChannel("Rust Analyzer Language Server");
++            this.pushExtCleanup(this.outputChannel);
++        }
++
++        if (!this.client) {
++            this._serverPath = await bootstrap(this.extCtx, this.config, this.state).catch(
++                (err) => {
++                    let message = "bootstrap error. ";
++
++                    message +=
++                        'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). ';
++                    message +=
++                        'To enable verbose logs use { "rust-analyzer.trace.extension": true }';
++
++                    log.error("Bootstrap error", err);
++                    throw new Error(message);
++                }
++            );
++            const newEnv = substituteVariablesInEnv(
++                Object.assign({}, process.env, this.config.serverExtraEnv)
++            );
++            const run: lc.Executable = {
++                command: this._serverPath,
++                options: { env: newEnv },
++            };
++            const serverOptions = {
++                run,
++                debug: run,
++            };
++
++            let rawInitializationOptions = vscode.workspace.getConfiguration("rust-analyzer");
++
++            if (this.workspace.kind === "Detached Files") {
++                rawInitializationOptions = {
++                    detachedFiles: this.workspace.files.map((file) => file.uri.fsPath),
++                    ...rawInitializationOptions,
++                };
++            }
++
++            const initializationOptions = substituteVSCodeVariables(rawInitializationOptions);
++
++            this.client = await createClient(
++                this.traceOutputChannel,
++                this.outputChannel,
++                initializationOptions,
++                serverOptions
++            );
++            this.pushClientCleanup(
++                this.client.onNotification(ra.serverStatus, (params) =>
++                    this.setServerStatus(params)
++                )
++            );
++        }
++        return this.client;
 +    }
 +
-     get globalState(): vscode.Memento {
-         return this.extCtx.globalState;
++    async activate() {
++        log.info("Activating language client");
++        const client = await this.getClient();
++        await client.start();
++        this.updateCommands();
++        return client;
++    }
++
++    async deactivate() {
++        log.info("Deactivating language client");
++        await this.client?.stop();
++        this.updateCommands();
++    }
++
++    async stop() {
++        log.info("Stopping language client");
++        await this.disposeClient();
++        this.updateCommands();
++    }
++
++    private async disposeClient() {
++        this.clientSubscriptions?.forEach((disposable) => disposable.dispose());
++        this.clientSubscriptions = [];
++        await this.client?.dispose();
++        this._serverPath = undefined;
++        this.client = undefined;
++    }
++
++    get activeRustEditor(): RustEditor | undefined {
++        const editor = vscode.window.activeTextEditor;
++        return editor && isRustEditor(editor) ? editor : undefined;
 +    }
 +
-     pushCleanup(d: Disposable) {
++    get extensionPath(): string {
++        return this.extCtx.extensionPath;
 +    }
 +
 +    get subscriptions(): Disposable[] {
 +        return this.extCtx.subscriptions;
 +    }
 +
++    get serverPath(): string | undefined {
++        return this._serverPath;
++    }
++
++    private updateCommands() {
++        this.commandDisposables.forEach((disposable) => disposable.dispose());
++        this.commandDisposables = [];
++        const fetchFactory = (factory: CommandFactory, fullName: string) => {
++            return this.client && this.client.isRunning()
++                ? factory.enabled
++                : factory.disabled ||
++                      ((_) => () =>
++                          vscode.window.showErrorMessage(
++                              `command ${fullName} failed: rust-analyzer server is not running`
++                          ));
++        };
++        for (const [name, factory] of Object.entries(this.commandFactories)) {
++            const fullName = `rust-analyzer.${name}`;
++            const callback = fetchFactory(factory, fullName)(this);
++            this.commandDisposables.push(vscode.commands.registerCommand(fullName, callback));
++        }
++    }
++
 +    setServerStatus(status: ServerStatusParams) {
 +        let icon = "";
 +        const statusBar = this.statusBar;
 +        switch (status.health) {
 +            case "ok":
 +                statusBar.tooltip = status.message ?? "Ready";
 +                statusBar.command = undefined;
 +                statusBar.color = undefined;
 +                statusBar.backgroundColor = undefined;
 +                break;
 +            case "warning":
 +                statusBar.tooltip =
 +                    (status.message ? status.message + "\n" : "") + "Click to reload.";
 +
 +                statusBar.command = "rust-analyzer.reloadWorkspace";
 +                statusBar.color = new vscode.ThemeColor("statusBarItem.warningForeground");
 +                statusBar.backgroundColor = new vscode.ThemeColor(
 +                    "statusBarItem.warningBackground"
 +                );
 +                icon = "$(warning) ";
 +                break;
 +            case "error":
 +                statusBar.tooltip =
 +                    (status.message ? status.message + "\n" : "") + "Click to reload.";
 +
 +                statusBar.command = "rust-analyzer.reloadWorkspace";
 +                statusBar.color = new vscode.ThemeColor("statusBarItem.errorForeground");
 +                statusBar.backgroundColor = new vscode.ThemeColor("statusBarItem.errorBackground");
 +                icon = "$(error) ";
 +                break;
 +        }
 +        if (!status.quiescent) icon = "$(sync~spin) ";
 +        statusBar.text = `${icon}rust-analyzer`;
 +    }
 +
++    pushExtCleanup(d: Disposable) {
 +        this.extCtx.subscriptions.push(d);
 +    }
++
++    private pushClientCleanup(d: Disposable) {
++        this.clientSubscriptions.push(d);
++    }
 +}
 +
 +export interface Disposable {
 +    dispose(): void;
 +}
 +export type Cmd = (...args: any[]) => unknown;
index 41bde4195e07d254da0d5532101c140969c17dc2,0000000000000000000000000000000000000000..8c3a676ffb056700e059a276c6efd565d64bf725
mode 100644,000000..100644
--- /dev/null
@@@ -1,415 -1,0 +1,166 @@@
- import * as os from "os";
 +import * as vscode from "vscode";
 +import * as lc from "vscode-languageclient/node";
- import { Ctx } from "./ctx";
- import { Config } from "./config";
- import { log, isValidExecutable, isRustDocument } from "./util";
- import { PersistentState } from "./persistent_state";
 +
 +import * as commands from "./commands";
- import { exec } from "child_process";
- let ctx: Ctx | undefined;
++import { CommandFactory, Ctx, Workspace } from "./ctx";
++import { isRustDocument } from "./util";
 +import { activateTaskProvider } from "./tasks";
 +import { setContextValue } from "./util";
- let TRACE_OUTPUT_CHANNEL: vscode.OutputChannel | null = null;
- export function traceOutputChannel() {
-     if (!TRACE_OUTPUT_CHANNEL) {
-         TRACE_OUTPUT_CHANNEL = vscode.window.createOutputChannel(
-             "Rust Analyzer Language Server Trace"
-         );
-     }
-     return TRACE_OUTPUT_CHANNEL;
- }
- let OUTPUT_CHANNEL: vscode.OutputChannel | null = null;
- export function outputChannel() {
-     if (!OUTPUT_CHANNEL) {
-         OUTPUT_CHANNEL = vscode.window.createOutputChannel("Rust Analyzer Language Server");
-     }
-     return OUTPUT_CHANNEL;
 +
 +const RUST_PROJECT_CONTEXT_NAME = "inRustProject";
 +
- export interface RustAnalyzerExtensionApi {
-     client?: lc.LanguageClient;
++export interface RustAnalyzerExtensionApi {
++    // FIXME: this should be non-optional
++    readonly client?: lc.LanguageClient;
 +}
 +
-     // VS Code doesn't show a notification when an extension fails to activate
-     // so we do it ourselves.
-     return await tryActivate(context).catch((err) => {
-         void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`);
-         throw err;
-     });
- }
++export async function deactivate() {
++    await setContextValue(RUST_PROJECT_CONTEXT_NAME, undefined);
 +}
 +
 +export async function activate(
 +    context: vscode.ExtensionContext
 +): Promise<RustAnalyzerExtensionApi> {
- async function tryActivate(context: vscode.ExtensionContext): Promise<RustAnalyzerExtensionApi> {
++    if (vscode.extensions.getExtension("rust-lang.rust")) {
++        vscode.window
++            .showWarningMessage(
++                `You have both the rust-analyzer (rust-lang.rust-analyzer) and Rust (rust-lang.rust) ` +
++                    "plugins enabled. These are known to conflict and cause various functions of " +
++                    "both plugins to not work correctly. You should disable one of them.",
++                "Got it"
++            )
++            .then(() => {}, console.error);
++    }
 +
-     const config = new Config(context);
-     const state = new PersistentState(context.globalState);
-     const serverPath = await bootstrap(context, config, state).catch((err) => {
-         let message = "bootstrap error. ";
-         message += 'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). ';
-         message += 'To enable verbose logs use { "rust-analyzer.trace.extension": true }';
 +    // We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if
 +    // only those are in use.
 +    // (r-a still somewhat works with Live Share, because commands are tunneled to the host)
 +    const folders = (vscode.workspace.workspaceFolders || []).filter(
 +        (folder) => folder.uri.scheme === "file"
 +    );
 +    const rustDocuments = vscode.workspace.textDocuments.filter((document) =>
 +        isRustDocument(document)
 +    );
 +
 +    if (folders.length === 0 && rustDocuments.length === 0) {
 +        // FIXME: Ideally we would choose not to activate at all (and avoid registering
 +        // non-functional editor commands), but VS Code doesn't seem to have a good way of doing
 +        // that
 +        return {};
 +    }
 +
-         log.error("Bootstrap error", err);
-         throw new Error(message);
++    const workspace: Workspace =
++        folders.length === 0
++            ? {
++                  kind: "Detached Files",
++                  files: rustDocuments,
++              }
++            : { kind: "Workspace Folder" };
 +
-     if (folders.length === 0) {
-         ctx = await Ctx.create(config, context, serverPath, {
-             kind: "Detached Files",
-             files: rustDocuments,
-         });
-     } else {
-         // Note: we try to start the server before we activate type hints so that it
-         // registers its `onDidChangeDocument` handler before us.
-         //
-         // This a horribly, horribly wrong way to deal with this problem.
-         ctx = await Ctx.create(config, context, serverPath, { kind: "Workspace Folder" });
-         ctx.pushCleanup(activateTaskProvider(ctx.config));
-     }
-     await initCommonContext(context, ctx);
-     warnAboutExtensionConflicts();
-     if (config.typingContinueCommentsOnNewline) {
-         ctx.pushCleanup(configureLanguage());
++    const ctx = new Ctx(context, workspace, createCommands());
++    // VS Code doesn't show a notification when an extension fails to activate
++    // so we do it ourselves.
++    const api = await activateServer(ctx).catch((err) => {
++        void vscode.window.showErrorMessage(
++            `Cannot activate rust-analyzer extension: ${err.message}`
++        );
++        throw err;
 +    });
++    await setContextValue(RUST_PROJECT_CONTEXT_NAME, true);
++    return api;
++}
 +
-         (_) =>
-             ctx?.client
-                 ?.sendNotification("workspace/didChangeConfiguration", { settings: "" })
-                 .catch(log.error),
++async function activateServer(ctx: Ctx): Promise<RustAnalyzerExtensionApi> {
++    if (ctx.workspace.kind === "Workspace Folder") {
++        ctx.pushExtCleanup(activateTaskProvider(ctx.config));
 +    }
 +
 +    vscode.workspace.onDidChangeConfiguration(
-     return {
-         client: ctx.client,
-     };
- }
- async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) {
-     // Register a "dumb" onEnter command for the case where server fails to
-     // start.
-     //
-     // FIXME: refactor command registration code such that commands are
-     // **always** registered, even if the server does not start. Use API like
-     // this perhaps?
-     //
-     // ```TypeScript
-     // registerCommand(
-     //    factory: (Ctx) => ((Ctx) => any),
-     //    fallback: () => any = () => vscode.window.showErrorMessage(
-     //        "rust-analyzer is not available"
-     //    ),
-     // )
-     const defaultOnEnter = vscode.commands.registerCommand("rust-analyzer.onEnter", () =>
-         vscode.commands.executeCommand("default:type", { text: "\n" })
-     );
-     context.subscriptions.push(defaultOnEnter);
-     await setContextValue(RUST_PROJECT_CONTEXT_NAME, true);
-     // Commands which invokes manually via command palette, shortcut, etc.
-     // Reloading is inspired by @DanTup maneuver: https://github.com/microsoft/vscode/issues/45774#issuecomment-373423895
-     ctx.registerCommand("reload", (_) => async () => {
-         void vscode.window.showInformationMessage("Reloading rust-analyzer...");
-         await doDeactivate();
-         while (context.subscriptions.length > 0) {
-             try {
-                 context.subscriptions.pop()!.dispose();
-             } catch (err) {
-                 log.error("Dispose error:", err);
-             }
-         }
-         await activate(context).catch(log.error);
-     });
-     ctx.registerCommand("analyzerStatus", commands.analyzerStatus);
-     ctx.registerCommand("memoryUsage", commands.memoryUsage);
-     ctx.registerCommand("shuffleCrateGraph", commands.shuffleCrateGraph);
-     ctx.registerCommand("reloadWorkspace", commands.reloadWorkspace);
-     ctx.registerCommand("matchingBrace", commands.matchingBrace);
-     ctx.registerCommand("joinLines", commands.joinLines);
-     ctx.registerCommand("parentModule", commands.parentModule);
-     ctx.registerCommand("syntaxTree", commands.syntaxTree);
-     ctx.registerCommand("viewHir", commands.viewHir);
-     ctx.registerCommand("viewFileText", commands.viewFileText);
-     ctx.registerCommand("viewItemTree", commands.viewItemTree);
-     ctx.registerCommand("viewCrateGraph", commands.viewCrateGraph);
-     ctx.registerCommand("viewFullCrateGraph", commands.viewFullCrateGraph);
-     ctx.registerCommand("expandMacro", commands.expandMacro);
-     ctx.registerCommand("run", commands.run);
-     ctx.registerCommand("copyRunCommandLine", commands.copyRunCommandLine);
-     ctx.registerCommand("debug", commands.debug);
-     ctx.registerCommand("newDebugConfig", commands.newDebugConfig);
-     ctx.registerCommand("openDocs", commands.openDocs);
-     ctx.registerCommand("openCargoToml", commands.openCargoToml);
-     ctx.registerCommand("peekTests", commands.peekTests);
-     ctx.registerCommand("moveItemUp", commands.moveItemUp);
-     ctx.registerCommand("moveItemDown", commands.moveItemDown);
-     ctx.registerCommand("cancelFlycheck", commands.cancelFlycheck);
-     defaultOnEnter.dispose();
-     ctx.registerCommand("onEnter", commands.onEnter);
-     ctx.registerCommand("ssr", commands.ssr);
-     ctx.registerCommand("serverVersion", commands.serverVersion);
-     // Internal commands which are invoked by the server.
-     ctx.registerCommand("runSingle", commands.runSingle);
-     ctx.registerCommand("debugSingle", commands.debugSingle);
-     ctx.registerCommand("showReferences", commands.showReferences);
-     ctx.registerCommand("applySnippetWorkspaceEdit", commands.applySnippetWorkspaceEditCommand);
-     ctx.registerCommand("resolveCodeAction", commands.resolveCodeAction);
-     ctx.registerCommand("applyActionGroup", commands.applyActionGroup);
-     ctx.registerCommand("gotoLocation", commands.gotoLocation);
-     ctx.registerCommand("linkToCommand", commands.linkToCommand);
- }
- export async function deactivate() {
-     TRACE_OUTPUT_CHANNEL?.dispose();
-     TRACE_OUTPUT_CHANNEL = null;
-     OUTPUT_CHANNEL?.dispose();
-     OUTPUT_CHANNEL = null;
-     await doDeactivate();
- }
- async function doDeactivate() {
-     await setContextValue(RUST_PROJECT_CONTEXT_NAME, undefined);
-     await ctx?.client.stop();
-     ctx = undefined;
- }
- async function bootstrap(
-     context: vscode.ExtensionContext,
-     config: Config,
-     state: PersistentState
- ): Promise<string> {
-     const path = await getServer(context, config, state);
-     if (!path) {
-         throw new Error(
-             "Rust Analyzer Language Server is not available. " +
-                 "Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation)."
-         );
-     }
-     log.info("Using server binary at", path);
-     if (!isValidExecutable(path)) {
-         if (config.serverPath) {
-             throw new Error(`Failed to execute ${path} --version. \`config.server.path\` or \`config.serverPath\` has been set explicitly.\
-             Consider removing this config or making a valid server binary available at that path.`);
-         } else {
-             throw new Error(`Failed to execute ${path} --version`);
-         }
-     }
-     return path;
++        async (_) => {
++            await ctx
++                .clientFetcher()
++                .client?.sendNotification("workspace/didChangeConfiguration", { settings: "" });
++        },
 +        null,
 +        ctx.subscriptions
 +    );
 +
- async function patchelf(dest: vscode.Uri): Promise<void> {
-     await vscode.window.withProgress(
-         {
-             location: vscode.ProgressLocation.Notification,
-             title: "Patching rust-analyzer for NixOS",
++    await ctx.activate();
++    return ctx.clientFetcher();
 +}
 +
-         async (progress, _) => {
-             const expression = `
-             {srcStr, pkgs ? import <nixpkgs> {}}:
-                 pkgs.stdenv.mkDerivation {
-                     name = "rust-analyzer";
-                     src = /. + srcStr;
-                     phases = [ "installPhase" "fixupPhase" ];
-                     installPhase = "cp $src $out";
-                     fixupPhase = ''
-                     chmod 755 $out
-                     patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out
-                     '';
-                 }
-             `;
-             const origFile = vscode.Uri.file(dest.fsPath + "-orig");
-             await vscode.workspace.fs.rename(dest, origFile, { overwrite: true });
-             try {
-                 progress.report({ message: "Patching executable", increment: 20 });
-                 await new Promise((resolve, reject) => {
-                     const handle = exec(
-                         `nix-build -E - --argstr srcStr '${origFile.fsPath}' -o '${dest.fsPath}'`,
-                         (err, stdout, stderr) => {
-                             if (err != null) {
-                                 reject(Error(stderr));
-                             } else {
-                                 resolve(stdout);
-                             }
-                         }
-                     );
-                     handle.stdin?.write(expression);
-                     handle.stdin?.end();
-                 });
-             } finally {
-                 await vscode.workspace.fs.delete(origFile);
-             }
-         }
-     );
- }
- async function getServer(
-     context: vscode.ExtensionContext,
-     config: Config,
-     state: PersistentState
- ): Promise<string | undefined> {
-     const explicitPath = serverPath(config);
-     if (explicitPath) {
-         if (explicitPath.startsWith("~/")) {
-             return os.homedir() + explicitPath.slice("~".length);
-         }
-         return explicitPath;
-     }
-     if (config.package.releaseTag === null) return "rust-analyzer";
-     const ext = process.platform === "win32" ? ".exe" : "";
-     const bundled = vscode.Uri.joinPath(context.extensionUri, "server", `rust-analyzer${ext}`);
-     const bundledExists = await vscode.workspace.fs.stat(bundled).then(
-         () => true,
-         () => false
-     );
-     if (bundledExists) {
-         let server = bundled;
-         if (await isNixOs()) {
-             await vscode.workspace.fs.createDirectory(config.globalStorageUri).then();
-             const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer${ext}`);
-             let exists = await vscode.workspace.fs.stat(dest).then(
-                 () => true,
-                 () => false
-             );
-             if (exists && config.package.version !== state.serverVersion) {
-                 await vscode.workspace.fs.delete(dest);
-                 exists = false;
-             }
-             if (!exists) {
-                 await vscode.workspace.fs.copy(bundled, dest);
-                 await patchelf(dest);
-             }
-             server = dest;
-         }
-         await state.updateServerVersion(config.package.version);
-         return server.fsPath;
-     }
-     await state.updateServerVersion(undefined);
-     await vscode.window.showErrorMessage(
-         "Unfortunately we don't ship binaries for your platform yet. " +
-             "You need to manually clone the rust-analyzer repository and " +
-             "run `cargo xtask install --server` to build the language server from sources. " +
-             "If you feel that your platform should be supported, please create an issue " +
-             "about that [here](https://github.com/rust-lang/rust-analyzer/issues) and we " +
-             "will consider it."
-     );
-     return undefined;
- }
- function serverPath(config: Config): string | null {
-     return process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath;
- }
- async function isNixOs(): Promise<boolean> {
-     try {
-         const contents = (
-             await vscode.workspace.fs.readFile(vscode.Uri.file("/etc/os-release"))
-         ).toString();
-         const idString = contents.split("\n").find((a) => a.startsWith("ID=")) || "ID=linux";
-         return idString.indexOf("nixos") !== -1;
-     } catch {
-         return false;
-     }
- }
- function warnAboutExtensionConflicts() {
-     if (vscode.extensions.getExtension("rust-lang.rust")) {
-         vscode.window
-             .showWarningMessage(
-                 `You have both the rust-analyzer (rust-lang.rust-analyzer) and Rust (rust-lang.rust) ` +
-                     "plugins enabled. These are known to conflict and cause various functions of " +
-                     "both plugins to not work correctly. You should disable one of them.",
-                 "Got it"
-             )
-             .then(() => {}, console.error);
-     }
- }
- /**
-  * Sets up additional language configuration that's impossible to do via a
-  * separate language-configuration.json file. See [1] for more information.
-  *
-  * [1]: https://github.com/Microsoft/vscode/issues/11514#issuecomment-244707076
-  */
- function configureLanguage(): vscode.Disposable {
-     const indentAction = vscode.IndentAction.None;
-     return vscode.languages.setLanguageConfiguration("rust", {
-         onEnterRules: [
-             {
-                 // Doc single-line comment
-                 // e.g. ///|
-                 beforeText: /^\s*\/{3}.*$/,
-                 action: { indentAction, appendText: "/// " },
-             },
-             {
-                 // Parent doc single-line comment
-                 // e.g. //!|
-                 beforeText: /^\s*\/{2}\!.*$/,
-                 action: { indentAction, appendText: "//! " },
++function createCommands(): Record<string, CommandFactory> {
++    return {
++        onEnter: {
++            enabled: commands.onEnter,
++            disabled: (_) => () => vscode.commands.executeCommand("default:type", { text: "\n" }),
 +        },
-             {
-                 // Begins an auto-closed multi-line comment (standard or parent doc)
-                 // e.g. /** | */ or /*! | */
-                 beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
-                 afterText: /^\s*\*\/$/,
-                 action: { indentAction: vscode.IndentAction.IndentOutdent, appendText: " * " },
++        reload: {
++            enabled: (ctx) => async () => {
++                void vscode.window.showInformationMessage("Reloading rust-analyzer...");
++                // FIXME: We should re-use the client, that is ctx.deactivate() if none of the configs have changed
++                await ctx.stop();
++                await ctx.activate();
 +            },
-             {
-                 // Begins a multi-line comment (standard or parent doc)
-                 // e.g. /** ...| or /*! ...|
-                 beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
-                 action: { indentAction, appendText: " * " },
++            disabled: (ctx) => async () => {
++                void vscode.window.showInformationMessage("Reloading rust-analyzer...");
++                await ctx.activate();
 +            },
-             {
-                 // Continues a multi-line comment
-                 // e.g.  * ...|
-                 beforeText: /^(\ \ )*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
-                 action: { indentAction, appendText: "* " },
++        },
++        startServer: {
++            enabled: (ctx) => async () => {
++                await ctx.activate();
 +            },
-             {
-                 // Dedents after closing a multi-line comment
-                 // e.g.  */|
-                 beforeText: /^(\ \ )*\ \*\/\s*$/,
-                 action: { indentAction, removeText: 1 },
++            disabled: (ctx) => async () => {
++                await ctx.activate();
 +            },
-         ],
-     });
++        },
++        stopServer: {
++            enabled: (ctx) => async () => {
++                // FIXME: We should re-use the client, that is ctx.deactivate() if none of the configs have changed
++                await ctx.stop();
++                ctx.setServerStatus({
++                    health: "ok",
++                    quiescent: true,
++                    message: "server is not running",
++                });
 +            },
++        },
++
++        analyzerStatus: { enabled: commands.analyzerStatus },
++        memoryUsage: { enabled: commands.memoryUsage },
++        shuffleCrateGraph: { enabled: commands.shuffleCrateGraph },
++        reloadWorkspace: { enabled: commands.reloadWorkspace },
++        matchingBrace: { enabled: commands.matchingBrace },
++        joinLines: { enabled: commands.joinLines },
++        parentModule: { enabled: commands.parentModule },
++        syntaxTree: { enabled: commands.syntaxTree },
++        viewHir: { enabled: commands.viewHir },
++        viewFileText: { enabled: commands.viewFileText },
++        viewItemTree: { enabled: commands.viewItemTree },
++        viewCrateGraph: { enabled: commands.viewCrateGraph },
++        viewFullCrateGraph: { enabled: commands.viewFullCrateGraph },
++        expandMacro: { enabled: commands.expandMacro },
++        run: { enabled: commands.run },
++        copyRunCommandLine: { enabled: commands.copyRunCommandLine },
++        debug: { enabled: commands.debug },
++        newDebugConfig: { enabled: commands.newDebugConfig },
++        openDocs: { enabled: commands.openDocs },
++        openCargoToml: { enabled: commands.openCargoToml },
++        peekTests: { enabled: commands.peekTests },
++        moveItemUp: { enabled: commands.moveItemUp },
++        moveItemDown: { enabled: commands.moveItemDown },
++        cancelFlycheck: { enabled: commands.cancelFlycheck },
++        ssr: { enabled: commands.ssr },
++        serverVersion: { enabled: commands.serverVersion },
++        // Internal commands which are invoked by the server.
++        applyActionGroup: { enabled: commands.applyActionGroup },
++        applySnippetWorkspaceEdit: { enabled: commands.applySnippetWorkspaceEditCommand },
++        debugSingle: { enabled: commands.debugSingle },
++        gotoLocation: { enabled: commands.gotoLocation },
++        linkToCommand: { enabled: commands.linkToCommand },
++        resolveCodeAction: { enabled: commands.resolveCodeAction },
++        runSingle: { enabled: commands.runSingle },
++        showReferences: { enabled: commands.showReferences },
++    };
 +}
index 22e5eda6827d1a97132a360a44293b9d0306c4bf,0000000000000000000000000000000000000000..dadaa41b1d1620c1e14053cb5b453f6a192c50d6
mode 100644,000000..100644
--- /dev/null
@@@ -1,175 -1,0 +1,175 @@@
-     const client = ctx.client;
-     if (!editor || !client) return;
 +import * as vscode from "vscode";
 +import * as lc from "vscode-languageclient";
 +import * as ra from "./lsp_ext";
 +import * as tasks from "./tasks";
 +
 +import { Ctx } from "./ctx";
 +import { makeDebugConfig } from "./debug";
 +import { Config, RunnableEnvCfg } from "./config";
 +
 +const quickPickButtons = [
 +    { iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configuration." },
 +];
 +
 +export async function selectRunnable(
 +    ctx: Ctx,
 +    prevRunnable?: RunnableQuickPick,
 +    debuggeeOnly = false,
 +    showButtons: boolean = true
 +): Promise<RunnableQuickPick | undefined> {
 +    const editor = ctx.activeRustEditor;
++    if (!editor) return;
 +
++    const client = await ctx.getClient();
 +    const textDocument: lc.TextDocumentIdentifier = {
 +        uri: editor.document.uri.toString(),
 +    };
 +
 +    const runnables = await client.sendRequest(ra.runnables, {
 +        textDocument,
 +        position: client.code2ProtocolConverter.asPosition(editor.selection.active),
 +    });
 +    const items: RunnableQuickPick[] = [];
 +    if (prevRunnable) {
 +        items.push(prevRunnable);
 +    }
 +    for (const r of runnables) {
 +        if (prevRunnable && JSON.stringify(prevRunnable.runnable) === JSON.stringify(r)) {
 +            continue;
 +        }
 +
 +        if (debuggeeOnly && (r.label.startsWith("doctest") || r.label.startsWith("cargo"))) {
 +            continue;
 +        }
 +        items.push(new RunnableQuickPick(r));
 +    }
 +
 +    if (items.length === 0) {
 +        // it is the debug case, run always has at least 'cargo check ...'
 +        // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_runnables
 +        await vscode.window.showErrorMessage("There's no debug target!");
 +        return;
 +    }
 +
 +    return await new Promise((resolve) => {
 +        const disposables: vscode.Disposable[] = [];
 +        const close = (result?: RunnableQuickPick) => {
 +            resolve(result);
 +            disposables.forEach((d) => d.dispose());
 +        };
 +
 +        const quickPick = vscode.window.createQuickPick<RunnableQuickPick>();
 +        quickPick.items = items;
 +        quickPick.title = "Select Runnable";
 +        if (showButtons) {
 +            quickPick.buttons = quickPickButtons;
 +        }
 +        disposables.push(
 +            quickPick.onDidHide(() => close()),
 +            quickPick.onDidAccept(() => close(quickPick.selectedItems[0])),
 +            quickPick.onDidTriggerButton(async (_button) => {
 +                await makeDebugConfig(ctx, quickPick.activeItems[0].runnable);
 +                close();
 +            }),
 +            quickPick.onDidChangeActive((active) => {
 +                if (showButtons && active.length > 0) {
 +                    if (active[0].label.startsWith("cargo")) {
 +                        // save button makes no sense for `cargo test` or `cargo check`
 +                        quickPick.buttons = [];
 +                    } else if (quickPick.buttons.length === 0) {
 +                        quickPick.buttons = quickPickButtons;
 +                    }
 +                }
 +            }),
 +            quickPick
 +        );
 +        quickPick.show();
 +    });
 +}
 +
 +export class RunnableQuickPick implements vscode.QuickPickItem {
 +    public label: string;
 +    public description?: string | undefined;
 +    public detail?: string | undefined;
 +    public picked?: boolean | undefined;
 +
 +    constructor(public runnable: ra.Runnable) {
 +        this.label = runnable.label;
 +    }
 +}
 +
 +export function prepareEnv(
 +    runnable: ra.Runnable,
 +    runnableEnvCfg: RunnableEnvCfg
 +): Record<string, string> {
 +    const env: Record<string, string> = { RUST_BACKTRACE: "short" };
 +
 +    if (runnable.args.expectTest) {
 +        env["UPDATE_EXPECT"] = "1";
 +    }
 +
 +    Object.assign(env, process.env as { [key: string]: string });
 +
 +    if (runnableEnvCfg) {
 +        if (Array.isArray(runnableEnvCfg)) {
 +            for (const it of runnableEnvCfg) {
 +                if (!it.mask || new RegExp(it.mask).test(runnable.label)) {
 +                    Object.assign(env, it.env);
 +                }
 +            }
 +        } else {
 +            Object.assign(env, runnableEnvCfg);
 +        }
 +    }
 +
 +    return env;
 +}
 +
 +export async function createTask(runnable: ra.Runnable, config: Config): Promise<vscode.Task> {
 +    if (runnable.kind !== "cargo") {
 +        // rust-analyzer supports only one kind, "cargo"
 +        // do not use tasks.TASK_TYPE here, these are completely different meanings.
 +
 +        throw `Unexpected runnable kind: ${runnable.kind}`;
 +    }
 +
 +    const args = createArgs(runnable);
 +
 +    const definition: tasks.CargoTaskDefinition = {
 +        type: tasks.TASK_TYPE,
 +        command: args[0], // run, test, etc...
 +        args: args.slice(1),
 +        cwd: runnable.args.workspaceRoot || ".",
 +        env: prepareEnv(runnable, config.runnableEnv),
 +        overrideCargo: runnable.args.overrideCargo,
 +    };
 +
 +    // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 +    const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate()
 +    const cargoTask = await tasks.buildCargoTask(
 +        target,
 +        definition,
 +        runnable.label,
 +        args,
 +        config.cargoRunner,
 +        true
 +    );
 +
 +    cargoTask.presentationOptions.clear = true;
 +    // Sadly, this doesn't prevent focus stealing if the terminal is currently
 +    // hidden, and will become revealed due to task exucution.
 +    cargoTask.presentationOptions.focus = false;
 +
 +    return cargoTask;
 +}
 +
 +export function createArgs(runnable: ra.Runnable): string[] {
 +    const args = [...runnable.args.cargoArgs]; // should be a copy!
 +    if (runnable.args.cargoExtraArgs) {
 +        args.push(...runnable.args.cargoExtraArgs); // Append user-specified cargo options.
 +    }
 +    if (runnable.args.executableArgs.length > 0) {
 +        args.push("--", ...runnable.args.executableArgs);
 +    }
 +    return args;
 +}