]> git.lizzy.rs Git - rust.git/commitdiff
:arrow_up: rust-analyzer
authorLaurențiu Nicola <lnicola@dend.ro>
Tue, 23 Aug 2022 07:05:52 +0000 (10:05 +0300)
committerLaurențiu Nicola <lnicola@dend.ro>
Tue, 23 Aug 2022 07:05:52 +0000 (10:05 +0300)
83 files changed:
1  2 
src/tools/rust-analyzer/.github/workflows/release.yaml
src/tools/rust-analyzer/Cargo.lock
src/tools/rust-analyzer/crates/flycheck/src/lib.rs
src/tools/rust-analyzer/crates/hir-def/src/body.rs
src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs
src/tools/rust-analyzer/crates/hir-def/src/expr.rs
src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
src/tools/rust-analyzer/crates/hir-def/src/lib.rs
src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs
src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs
src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs
src/tools/rust-analyzer/crates/hir-expand/src/db.rs
src/tools/rust-analyzer/crates/hir-expand/src/lib.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/Cargo.toml
src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
src/tools/rust-analyzer/crates/hir/src/lib.rs
src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs
src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
src/tools/rust-analyzer/crates/ide-completion/src/render.rs
src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs
src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
src/tools/rust-analyzer/crates/ide-db/src/rename.rs
src/tools/rust-analyzer/crates/ide-db/src/search.rs
src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
src/tools/rust-analyzer/crates/ide/src/hover.rs
src/tools/rust-analyzer/crates/ide/src/hover/render.rs
src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
src/tools/rust-analyzer/crates/ide/src/static_index.rs
src/tools/rust-analyzer/crates/ide/src/view_hir.rs
src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
src/tools/rust-analyzer/crates/project-model/src/lib.rs
src/tools/rust-analyzer/crates/project-model/src/workspace.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/bin/logger.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/config.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_ext.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
src/tools/rust-analyzer/crates/syntax/src/hacks.rs
src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
src/tools/rust-analyzer/crates/vfs/src/lib.rs
src/tools/rust-analyzer/docs/dev/architecture.md
src/tools/rust-analyzer/docs/dev/lsp-extensions.md
src/tools/rust-analyzer/docs/user/generated_config.adoc
src/tools/rust-analyzer/editors/code/package.json
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/lsp_ext.ts
src/tools/rust-analyzer/editors/code/src/main.ts
src/tools/rust-analyzer/editors/code/src/toolchain.ts

index 3c36c4fb84a2b28e6c2798103f576f7f51f55d23,0000000000000000000000000000000000000000..b2e5db6f689b518e5b6cfdfbe11a7b79294bdbb1
mode 100644,000000..100644
--- /dev/null
@@@ -1,261 -1,0 +1,261 @@@
-           - os: ubuntu-18.04
 +name: release
 +on:
 +  schedule:
 +    - cron: "0 0 * * *" # midnight UTC
 +
 +  workflow_dispatch:
 +
 +  push:
 +    branches:
 +      - release
 +      - trigger-nightly
 +
 +env:
 +  CARGO_INCREMENTAL: 0
 +  CARGO_NET_RETRY: 10
 +  RUSTFLAGS: "-D warnings -W unreachable-pub"
 +  RUSTUP_MAX_RETRIES: 10
 +  FETCH_DEPTH: 0 # pull in the tags for the version string
 +  MACOSX_DEPLOYMENT_TARGET: 10.15
 +  CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
 +  CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc
 +
 +jobs:
 +  dist:
 +    strategy:
 +      matrix:
 +        include:
 +          - os: windows-latest
 +            target: x86_64-pc-windows-msvc
 +            code-target: win32-x64
 +          - os: windows-latest
 +            target: aarch64-pc-windows-msvc
 +            code-target: win32-arm64
-           - os: ubuntu-18.04
++          - os: ubuntu-20.04
 +            target: x86_64-unknown-linux-gnu
 +            code-target: linux-x64
-           - os: ubuntu-18.04
++          - os: ubuntu-20.04
 +            target: aarch64-unknown-linux-gnu
 +            code-target: linux-arm64
++          - os: ubuntu-20.04
 +            target: arm-unknown-linux-gnueabihf
 +            code-target: linux-armhf
 +          - os: macos-11
 +            target: x86_64-apple-darwin
 +            code-target: darwin-x64
 +          - os: macos-11
 +            target: aarch64-apple-darwin
 +            code-target: darwin-arm64
 +
 +    name: dist (${{ matrix.target }})
 +    runs-on: ${{ matrix.os }}
 +
 +    env:
 +      RA_TARGET: ${{ matrix.target }}
 +
 +    steps:
 +      - name: Checkout repository
 +        uses: actions/checkout@v3
 +        with:
 +          fetch-depth: ${{ env.FETCH_DEPTH }}
 +
 +      - name: Install Rust toolchain
 +        run: |
 +          rustup update --no-self-update stable
 +          rustup target add ${{ matrix.target }}
 +          rustup component add rust-src
 +
 +      - name: Install Node.js
 +        uses: actions/setup-node@v1
 +        with:
 +          node-version: 16.x
 +
 +      - name: Update apt repositories
 +        if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf'
 +        run: sudo apt-get update
 +
 +      - name: Install AArch64 target toolchain
 +        if: matrix.target == 'aarch64-unknown-linux-gnu'
 +        run: sudo apt-get install gcc-aarch64-linux-gnu
 +
 +      - name: Install ARM target toolchain
 +        if: matrix.target == 'arm-unknown-linux-gnueabihf'
 +        run: sudo apt-get install gcc-arm-linux-gnueabihf
 +
 +      - name: Dist
 +        run: cargo xtask dist --client-patch-version ${{ github.run_number }}
 +
 +      - run: npm ci
 +        working-directory: editors/code
 +
 +      - name: Package Extension (release)
 +        if: github.ref == 'refs/heads/release'
 +        run: npx vsce package -o "../../dist/rust-analyzer-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }}
 +        working-directory: editors/code
 +
 +      - name: Package Extension (nightly)
 +        if: github.ref != 'refs/heads/release'
 +        run: npx vsce package -o "../../dist/rust-analyzer-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} --pre-release
 +        working-directory: editors/code
 +
 +      - if: matrix.target == 'x86_64-unknown-linux-gnu'
 +        run: rm -rf editors/code/server
 +
 +      - if: matrix.target == 'x86_64-unknown-linux-gnu' && github.ref == 'refs/heads/release'
 +        run: npx vsce package -o ../../dist/rust-analyzer-no-server.vsix
 +        working-directory: editors/code
 +
 +      - if: matrix.target == 'x86_64-unknown-linux-gnu' && github.ref != 'refs/heads/release'
 +        run: npx vsce package -o ../../dist/rust-analyzer-no-server.vsix --pre-release
 +        working-directory: editors/code
 +
 +      - name: Run analysis-stats on rust-analyzer
 +        if: matrix.target == 'x86_64-unknown-linux-gnu'
 +        run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats .
 +
 +      - name: Run analysis-stats on rust std library
 +        if: matrix.target == 'x86_64-unknown-linux-gnu'
 +        run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std
 +
 +      - name: Upload artifacts
 +        uses: actions/upload-artifact@v1
 +        with:
 +          name: dist-${{ matrix.target }}
 +          path: ./dist
 +
 +  dist-x86_64-unknown-linux-musl:
 +    name: dist (x86_64-unknown-linux-musl)
 +    runs-on: ubuntu-latest
 +    env:
 +      RA_TARGET: x86_64-unknown-linux-musl
 +      # For some reason `-crt-static` is not working for clang without lld
 +      RUSTFLAGS: "-C link-arg=-fuse-ld=lld -C target-feature=-crt-static"
 +    container:
 +      image: rust:alpine
 +      volumes:
 +        - /usr/local/cargo/registry:/usr/local/cargo/registry
 +
 +    steps:
 +      - name: Install dependencies
 +        run: apk add --no-cache git clang lld musl-dev nodejs npm
 +
 +      - name: Checkout repository
 +        uses: actions/checkout@v3
 +        with:
 +          fetch-depth: ${{ env.FETCH_DEPTH }}
 +
 +      - name: Dist
 +        run: cargo xtask dist --client-patch-version ${{ github.run_number }}
 +
 +      - run: npm ci
 +        working-directory: editors/code
 +
 +      - name: Package Extension (release)
 +        if: github.ref == 'refs/heads/release'
 +        run: npx vsce package -o "../../dist/rust-analyzer-alpine-x64.vsix" --target alpine-x64
 +        working-directory: editors/code
 +
 +      - name: Package Extension (nightly)
 +        if: github.ref != 'refs/heads/release'
 +        run: npx vsce package -o "../../dist/rust-analyzer-alpine-x64.vsix" --target alpine-x64 --pre-release
 +        working-directory: editors/code
 +
 +      - run: rm -rf editors/code/server
 +
 +      - name: Upload artifacts
 +        uses: actions/upload-artifact@v1
 +        with:
 +          name: dist-x86_64-unknown-linux-musl
 +          path: ./dist
 +
 +  publish:
 +    name: publish
 +    runs-on: ubuntu-latest
 +    needs: ["dist", "dist-x86_64-unknown-linux-musl"]
 +    steps:
 +      - name: Install Nodejs
 +        uses: actions/setup-node@v1
 +        with:
 +          node-version: 16.x
 +
 +      - run: echo "TAG=$(date --iso -u)" >> $GITHUB_ENV
 +        if: github.ref == 'refs/heads/release'
 +      - run: echo "TAG=nightly" >> $GITHUB_ENV
 +        if: github.ref != 'refs/heads/release'
 +      - run: 'echo "TAG: $TAG"'
 +
 +      - name: Checkout repository
 +        uses: actions/checkout@v3
 +        with:
 +          fetch-depth: ${{ env.FETCH_DEPTH }}
 +
 +      - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
 +      - run: 'echo "HEAD_SHA: $HEAD_SHA"'
 +
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-aarch64-apple-darwin
 +          path: dist
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-x86_64-apple-darwin
 +          path: dist
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-x86_64-unknown-linux-gnu
 +          path: dist
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-x86_64-unknown-linux-musl
 +          path: dist
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-aarch64-unknown-linux-gnu
 +          path: dist
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-arm-unknown-linux-gnueabihf
 +          path: dist
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-x86_64-pc-windows-msvc
 +          path: dist
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-aarch64-pc-windows-msvc
 +          path: dist
 +      - run: ls -al ./dist
 +
 +      - name: Publish Release
 +        uses: ./.github/actions/github-release
 +        with:
 +          files: "dist/*"
 +          name: ${{ env.TAG }}
 +          token: ${{ secrets.GITHUB_TOKEN }}
 +
 +      - run: rm dist/rust-analyzer-no-server.vsix
 +
 +      - run: npm ci
 +        working-directory: ./editors/code
 +
 +      - name: Publish Extension (Code Marketplace, release)
 +        if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
 +        working-directory: ./editors/code
 +        # token from https://dev.azure.com/rust-analyzer/
 +        run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
 +
 +      - name: Publish Extension (OpenVSX, release)
 +        if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
 +        working-directory: ./editors/code
 +        # token from https://dev.azure.com/rust-analyzer/
 +        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
 +
 +      - name: Publish Extension (Code Marketplace, nightly)
 +        if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
 +        working-directory: ./editors/code
 +        run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
 +
 +      - name: Publish Extension (OpenVSX, nightly)
 +        if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
 +        working-directory: ./editors/code
 +        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
index 7c6796d70bdc0e5c0a9f3077279707e8cbf182e3,0000000000000000000000000000000000000000..8a61ea1c9241422451a8a3ea1a0b1145159c50c4
mode 100644,000000..100644
--- /dev/null
@@@ -1,2102 -1,0 +1,2093 @@@
- version = "1.0.58"
 +# This file is automatically @generated by Cargo.
 +# It is not intended for manual editing.
 +version = 3
 +
 +[[package]]
 +name = "addr2line"
 +version = "0.17.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
 +dependencies = [
 + "gimli",
 +]
 +
 +[[package]]
 +name = "adler"
 +version = "1.0.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 +
 +[[package]]
 +name = "always-assert"
 +version = "0.1.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "fbf688625d06217d5b1bb0ea9d9c44a1635fd0ee3534466388d18203174f4d11"
 +dependencies = [
 + "log",
 +]
 +
 +[[package]]
 +name = "ansi_term"
 +version = "0.12.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
 +dependencies = [
 + "winapi",
 +]
 +
 +[[package]]
 +name = "anyhow"
- checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
++version = "1.0.62"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.3.65"
++checksum = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305"
 +
 +[[package]]
 +name = "anymap"
 +version = "1.0.0-beta.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8f1f8f5a6f3d50d89e3797d7593a50f96bb2aaa20ca0cc7be1fb673232c91d72"
 +
 +[[package]]
 +name = "arbitrary"
 +version = "1.1.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5a7924531f38b1970ff630f03eb20a2fde69db5c590c93b0f3482e95dcc5fd60"
 +
 +[[package]]
 +name = "arrayvec"
 +version = "0.7.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
 +
 +[[package]]
 +name = "atty"
 +version = "0.2.14"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
 +dependencies = [
 + "hermit-abi",
 + "libc",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "autocfg"
 +version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 +
 +[[package]]
 +name = "backtrace"
- checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61"
++version = "0.3.66"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
-  "object 0.28.4",
++checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
 +dependencies = [
 + "addr2line",
 + "cc",
 + "cfg-if",
 + "libc",
 + "miniz_oxide",
- version = "1.0.9"
++ "object",
 + "rustc-demangle",
 +]
 +
 +[[package]]
 +name = "base-db"
 +version = "0.0.0"
 +dependencies = [
 + "cfg",
 + "profile",
 + "rustc-hash",
 + "salsa",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "tt",
 + "vfs",
 +]
 +
 +[[package]]
 +name = "bitflags"
 +version = "1.3.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 +
 +[[package]]
 +name = "camino"
- checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412"
++version = "1.1.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.83.0"
++checksum = "88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "cargo-platform"
 +version = "0.1.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "cargo_metadata"
 +version = "0.15.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36"
 +dependencies = [
 + "camino",
 + "cargo-platform",
 + "semver",
 + "serde",
 + "serde_json",
 +]
 +
 +[[package]]
 +name = "cc"
 +version = "1.0.73"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
 +
 +[[package]]
 +name = "cfg"
 +version = "0.0.0"
 +dependencies = [
 + "arbitrary",
 + "derive_arbitrary",
 + "expect-test",
 + "mbe",
 + "oorandom",
 + "rustc-hash",
 + "syntax",
 + "tt",
 +]
 +
 +[[package]]
 +name = "cfg-if"
 +version = "1.0.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 +
 +[[package]]
 +name = "chalk-derive"
- checksum = "83553c2ef7717e58aecdf42dd9e3c876229f5a1f35a16435b5ddc4addef81827"
++version = "0.84.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.83.0"
++checksum = "cf29c109d57f8d57b0e7675391be37a9285d86dd93278bd5f14a0ad3c447a6c2"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 + "synstructure",
 +]
 +
 +[[package]]
 +name = "chalk-ir"
- checksum = "2dd42107d579d8ec2a5af20a8de62a37524a67bf6a4c0ff08a950068f0bfea91"
++version = "0.84.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.83.0"
++checksum = "d391763027b5e50a5e15caf6d2857ec585fd68160367bbeac9e1804209620918"
 +dependencies = [
 + "bitflags",
 + "chalk-derive",
 + "lazy_static",
 +]
 +
 +[[package]]
 +name = "chalk-recursive"
- checksum = "c444031541a76c13c145e76d91f1548e9feb2240e7f0c3e77879ceb694994f2d"
++version = "0.84.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.83.0"
++checksum = "afafd92dcdc7fe0ea940ee94bdd8cc5bd18f4a4a84c593d6d7025fe16c150478"
 +dependencies = [
 + "chalk-derive",
 + "chalk-ir",
 + "chalk-solve",
 + "rustc-hash",
 + "tracing",
 +]
 +
 +[[package]]
 +name = "chalk-solve"
- checksum = "c76f2db19c5e8a3d42340cf5b4d90b8c218750536fca35e2bb285ab6653c0bc8"
++version = "0.84.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.8.1"
++checksum = "3af1d111f11c91c48ace02e93e470c5bae6d2631bd112e4545317da53660d7fc"
 +dependencies = [
 + "chalk-derive",
 + "chalk-ir",
 + "ena",
 + "indexmap",
 + "itertools",
 + "petgraph",
 + "rustc-hash",
 + "tracing",
 +]
 +
 +[[package]]
 +name = "countme"
 +version = "3.0.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"
 +dependencies = [
 + "dashmap",
 + "once_cell",
 + "rustc-hash",
 +]
 +
 +[[package]]
 +name = "cov-mark"
 +version = "2.0.0-pre.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0d48d8f76bd9331f19fe2aaf3821a9f9fb32c3963e1e3d6ce82a8c09cef7444a"
 +
 +[[package]]
 +name = "crc32fast"
 +version = "1.3.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
 +dependencies = [
 + "cfg-if",
 +]
 +
 +[[package]]
 +name = "crossbeam"
- checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845"
++version = "0.8.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.5.5"
++checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c"
 +dependencies = [
 + "cfg-if",
 + "crossbeam-channel",
 + "crossbeam-deque",
 + "crossbeam-epoch",
 + "crossbeam-queue",
 + "crossbeam-utils",
 +]
 +
 +[[package]]
 +name = "crossbeam-channel"
- checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c"
++version = "0.5.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.8.1"
++checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
 +dependencies = [
 + "cfg-if",
 + "crossbeam-utils",
 +]
 +
 +[[package]]
 +name = "crossbeam-deque"
- checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
++version = "0.8.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.9.9"
++checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
 +dependencies = [
 + "cfg-if",
 + "crossbeam-epoch",
 + "crossbeam-utils",
 +]
 +
 +[[package]]
 +name = "crossbeam-epoch"
- checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d"
++version = "0.9.10"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.3.5"
++checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1"
 +dependencies = [
 + "autocfg",
 + "cfg-if",
 + "crossbeam-utils",
 + "memoffset",
 + "once_cell",
 + "scopeguard",
 +]
 +
 +[[package]]
 +name = "crossbeam-queue"
- checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2"
++version = "0.3.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.8.10"
++checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7"
 +dependencies = [
 + "cfg-if",
 + "crossbeam-utils",
 +]
 +
 +[[package]]
 +name = "crossbeam-utils"
- checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83"
++version = "0.8.11"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.7.0"
++checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
 +dependencies = [
 + "cfg-if",
 + "once_cell",
 +]
 +
 +[[package]]
 +name = "dashmap"
 +version = "5.3.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3495912c9c1ccf2e18976439f4443f3fee0fd61f424ff99fde6a66b15ecb448f"
 +dependencies = [
 + "cfg-if",
 + "hashbrown",
 + "lock_api",
 + "parking_lot_core 0.9.3",
 +]
 +
 +[[package]]
 +name = "derive_arbitrary"
 +version = "1.1.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c9a577516173adb681466d517d39bd468293bc2c2a16439375ef0f35bba45f3d"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "dissimilar"
 +version = "1.0.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8c97b9233581d84b8e1e689cdd3a47b6f69770084fc246e86a7f78b0d9c1d4a5"
 +
 +[[package]]
 +name = "dot"
 +version = "0.1.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a74b6c4d4a1cff5f454164363c16b72fa12463ca6b31f4b5f2035a65fa3d5906"
 +
 +[[package]]
 +name = "drop_bomb"
 +version = "0.1.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1"
 +
 +[[package]]
 +name = "either"
- checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"
++version = "1.8.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.26.1"
++checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
 +
 +[[package]]
 +name = "ena"
 +version = "0.14.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
 +dependencies = [
 + "log",
 +]
 +
 +[[package]]
 +name = "expect-test"
 +version = "1.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1d4661aca38d826eb7c72fe128e4238220616de4c0cc00db7bfc38e2e1364dd3"
 +dependencies = [
 + "dissimilar",
 + "once_cell",
 +]
 +
 +[[package]]
 +name = "filetime"
 +version = "0.2.17"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c"
 +dependencies = [
 + "cfg-if",
 + "libc",
 + "redox_syscall",
 + "windows-sys 0.36.1",
 +]
 +
 +[[package]]
 +name = "fixedbitset"
 +version = "0.2.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
 +
 +[[package]]
 +name = "flate2"
 +version = "1.0.24"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
 +dependencies = [
 + "crc32fast",
 + "miniz_oxide",
 +]
 +
 +[[package]]
 +name = "flycheck"
 +version = "0.0.0"
 +dependencies = [
 + "cargo_metadata",
 + "crossbeam-channel",
 + "jod-thread",
 + "paths",
 + "serde",
 + "serde_json",
 + "stdx",
 + "toolchain",
 + "tracing",
 +]
 +
 +[[package]]
 +name = "form_urlencoded"
 +version = "1.0.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
 +dependencies = [
 + "matches",
 + "percent-encoding",
 +]
 +
 +[[package]]
 +name = "fs_extra"
 +version = "1.2.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"
 +
 +[[package]]
 +name = "fsevent-sys"
 +version = "4.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
 +dependencies = [
 + "libc",
 +]
 +
 +[[package]]
 +name = "fst"
 +version = "0.4.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
 +
 +[[package]]
 +name = "gimli"
- checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
++version = "0.26.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.12.1"
++checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
 +
 +[[package]]
 +name = "hashbrown"
- checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
++version = "0.12.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.2"
++checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 +
 +[[package]]
 +name = "heck"
 +version = "0.3.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
 +dependencies = [
 + "unicode-segmentation",
 +]
 +
 +[[package]]
 +name = "hermit-abi"
 +version = "0.1.19"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
 +dependencies = [
 + "libc",
 +]
 +
 +[[package]]
 +name = "hir"
 +version = "0.0.0"
 +dependencies = [
 + "arrayvec",
 + "base-db",
 + "cfg",
 + "either",
 + "hir-def",
 + "hir-expand",
 + "hir-ty",
 + "itertools",
 + "once_cell",
 + "profile",
 + "rustc-hash",
 + "smallvec",
 + "stdx",
 + "syntax",
 + "tt",
 +]
 +
 +[[package]]
 +name = "hir-def"
 +version = "0.0.0"
 +dependencies = [
 + "anymap",
 + "arrayvec",
 + "base-db",
 + "bitflags",
 + "cfg",
 + "cov-mark",
 + "dashmap",
 + "drop_bomb",
 + "either",
 + "expect-test",
 + "fst",
 + "hashbrown",
 + "hir-expand",
 + "indexmap",
 + "itertools",
 + "la-arena",
 + "limit",
 + "mbe",
 + "once_cell",
 + "profile",
 + "rustc-hash",
 + "smallvec",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "tracing",
 + "tt",
 +]
 +
 +[[package]]
 +name = "hir-expand"
 +version = "0.0.0"
 +dependencies = [
 + "base-db",
 + "cfg",
 + "cov-mark",
 + "either",
 + "expect-test",
 + "hashbrown",
 + "itertools",
 + "la-arena",
 + "limit",
 + "mbe",
 + "profile",
 + "rustc-hash",
 + "smallvec",
 + "stdx",
 + "syntax",
 + "tracing",
 + "tt",
 +]
 +
 +[[package]]
 +name = "hir-ty"
 +version = "0.0.0"
 +dependencies = [
 + "arrayvec",
 + "base-db",
 + "chalk-ir",
 + "chalk-recursive",
 + "chalk-solve",
 + "cov-mark",
 + "ena",
 + "expect-test",
 + "hir-def",
 + "hir-expand",
 + "itertools",
 + "la-arena",
 + "limit",
 + "once_cell",
 + "profile",
 + "rustc-hash",
 + "scoped-tls",
 + "smallvec",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "tracing",
 + "tracing-subscriber",
 + "tracing-tree",
 + "typed-arena",
 +]
 +
 +[[package]]
 +name = "home"
 +version = "0.5.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
 +dependencies = [
 + "winapi",
 +]
 +
 +[[package]]
 +name = "ide"
 +version = "0.0.0"
 +dependencies = [
 + "cfg",
 + "cov-mark",
 + "crossbeam-channel",
 + "dot",
 + "either",
 + "expect-test",
 + "hir",
 + "ide-assists",
 + "ide-completion",
 + "ide-db",
 + "ide-diagnostics",
 + "ide-ssr",
 + "itertools",
 + "oorandom",
 + "profile",
 + "pulldown-cmark",
 + "pulldown-cmark-to-cmark",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "text-edit",
 + "toolchain",
 + "tracing",
 + "url",
 +]
 +
 +[[package]]
 +name = "ide-assists"
 +version = "0.0.0"
 +dependencies = [
 + "cov-mark",
 + "either",
 + "expect-test",
 + "hir",
 + "ide-db",
 + "itertools",
 + "profile",
 + "sourcegen",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "text-edit",
 +]
 +
 +[[package]]
 +name = "ide-completion"
 +version = "0.0.0"
 +dependencies = [
 + "base-db",
 + "cov-mark",
 + "expect-test",
 + "hir",
 + "ide-db",
 + "itertools",
 + "once_cell",
 + "profile",
 + "smallvec",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "text-edit",
 +]
 +
 +[[package]]
 +name = "ide-db"
 +version = "0.0.0"
 +dependencies = [
 + "arrayvec",
 + "base-db",
 + "cov-mark",
 + "either",
 + "expect-test",
 + "fst",
 + "hir",
 + "indexmap",
 + "itertools",
 + "limit",
 + "once_cell",
 + "parser",
 + "profile",
 + "rayon",
 + "rustc-hash",
 + "sourcegen",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "text-edit",
 + "tracing",
 + "xshell",
 +]
 +
 +[[package]]
 +name = "ide-diagnostics"
 +version = "0.0.0"
 +dependencies = [
 + "cfg",
 + "cov-mark",
 + "either",
 + "expect-test",
 + "hir",
 + "ide-db",
 + "itertools",
 + "profile",
 + "serde_json",
 + "sourcegen",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "text-edit",
 +]
 +
 +[[package]]
 +name = "ide-ssr"
 +version = "0.0.0"
 +dependencies = [
 + "cov-mark",
 + "expect-test",
 + "hir",
 + "ide-db",
 + "itertools",
 + "parser",
 + "syntax",
 + "test-utils",
 + "text-edit",
 +]
 +
 +[[package]]
 +name = "idna"
 +version = "0.2.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
 +dependencies = [
 + "matches",
 + "unicode-bidi",
 + "unicode-normalization",
 +]
 +
 +[[package]]
 +name = "indexmap"
 +version = "1.9.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
 +dependencies = [
 + "autocfg",
 + "hashbrown",
 +]
 +
 +[[package]]
 +name = "inotify"
 +version = "0.9.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
 +dependencies = [
 + "bitflags",
 + "inotify-sys",
 + "libc",
 +]
 +
 +[[package]]
 +name = "inotify-sys"
 +version = "0.1.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
 +dependencies = [
 + "libc",
 +]
 +
 +[[package]]
 +name = "instant"
 +version = "0.1.12"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
 +dependencies = [
 + "cfg-if",
 +]
 +
 +[[package]]
 +name = "itertools"
 +version = "0.10.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
 +dependencies = [
 + "either",
 +]
 +
 +[[package]]
 +name = "itoa"
- checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
++version = "1.0.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.2.126"
++checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
 +
 +[[package]]
 +name = "jod-thread"
 +version = "0.1.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae"
 +
 +[[package]]
 +name = "kqueue"
 +version = "1.0.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4d6112e8f37b59803ac47a42d14f1f3a59bbf72fc6857ffc5be455e28a691f8e"
 +dependencies = [
 + "kqueue-sys",
 + "libc",
 +]
 +
 +[[package]]
 +name = "kqueue-sys"
 +version = "1.0.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587"
 +dependencies = [
 + "bitflags",
 + "libc",
 +]
 +
 +[[package]]
 +name = "la-arena"
 +version = "0.3.0"
 +
 +[[package]]
 +name = "lazy_static"
 +version = "1.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 +
 +[[package]]
 +name = "libc"
- checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
++version = "0.2.132"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.5.4"
++checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
 +
 +[[package]]
 +name = "libloading"
 +version = "0.7.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
 +dependencies = [
 + "cfg-if",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "libmimalloc-sys"
 +version = "0.1.25"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "11ca136052550448f55df7898c6dbe651c6b574fe38a0d9ea687a9f8088a2e2c"
 +dependencies = [
 + "cc",
 +]
 +
 +[[package]]
 +name = "limit"
 +version = "0.0.0"
 +
 +[[package]]
 +name = "lock_api"
 +version = "0.4.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
 +dependencies = [
 + "autocfg",
 + "scopeguard",
 +]
 +
 +[[package]]
 +name = "log"
 +version = "0.4.17"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
 +dependencies = [
 + "cfg-if",
 +]
 +
 +[[package]]
 +name = "lsp-server"
 +version = "0.6.0"
 +dependencies = [
 + "crossbeam-channel",
 + "log",
 + "lsp-types",
 + "serde",
 + "serde_json",
 +]
 +
 +[[package]]
 +name = "lsp-types"
 +version = "0.93.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "70c74e2173b2b31f8655d33724b4b45ac13f439386f66290f539c22b144c2212"
 +dependencies = [
 + "bitflags",
 + "serde",
 + "serde_json",
 + "serde_repr",
 + "url",
 +]
 +
 +[[package]]
 +name = "matchers"
 +version = "0.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
 +dependencies = [
 + "regex-automata",
 +]
 +
 +[[package]]
 +name = "matches"
 +version = "0.1.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
 +
 +[[package]]
 +name = "mbe"
 +version = "0.0.0"
 +dependencies = [
 + "cov-mark",
 + "parser",
 + "rustc-hash",
 + "smallvec",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "tracing",
 + "tt",
 +]
 +
 +[[package]]
 +name = "memchr"
 +version = "2.5.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 +
 +[[package]]
 +name = "memmap2"
- checksum = "d5172b50c23043ff43dd53e51392f36519d9b35a8f3a410d30ece5d1aedd58ae"
++version = "0.5.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "5.0.0-pre.15"
++checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498"
 +dependencies = [
 + "libc",
 +]
 +
 +[[package]]
 +name = "memoffset"
 +version = "0.6.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
 +dependencies = [
 + "autocfg",
 +]
 +
 +[[package]]
 +name = "mimalloc"
 +version = "0.1.29"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2f64ad83c969af2e732e907564deb0d0ed393cec4af80776f77dd77a1a427698"
 +dependencies = [
 + "libmimalloc-sys",
 +]
 +
 +[[package]]
 +name = "miniz_oxide"
 +version = "0.5.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
 +dependencies = [
 + "adler",
 +]
 +
 +[[package]]
 +name = "mio"
 +version = "0.8.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
 +dependencies = [
 + "libc",
 + "log",
 + "wasi",
 + "windows-sys 0.36.1",
 +]
 +
 +[[package]]
 +name = "miow"
 +version = "0.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a7377f7792b3afb6a3cba68daa54ca23c032137010460d667fda53a8d66be00e"
 +dependencies = [
 + "windows-sys 0.28.0",
 +]
 +
 +[[package]]
 +name = "notify"
- checksum = "553f9844ad0b0824605c20fb55a661679782680410abfb1a8144c2e7e437e7a7"
++version = "5.0.0-pre.16"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- [[package]]
- name = "object"
- version = "0.28.4"
- source = "registry+https://github.com/rust-lang/crates.io-index"
- checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
- dependencies = [
-  "memchr",
- ]
++checksum = "530f6314d6904508082f4ea424a0275cf62d341e118b313663f266429cb19693"
 +dependencies = [
 + "bitflags",
 + "crossbeam-channel",
 + "filetime",
 + "fsevent-sys",
 + "inotify",
 + "kqueue",
 + "libc",
 + "mio",
 + "walkdir",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "num_cpus"
 +version = "1.13.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
 +dependencies = [
 + "hermit-abi",
 + "libc",
 +]
 +
- version = "1.13.0"
 +[[package]]
 +name = "object"
 +version = "0.29.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
 +dependencies = [
 + "memchr",
 +]
 +
 +[[package]]
 +name = "once_cell"
- checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
++version = "1.13.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.7"
++checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
 +
 +[[package]]
 +name = "oorandom"
 +version = "11.1.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
 +
 +[[package]]
 +name = "parking_lot"
 +version = "0.11.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
 +dependencies = [
 + "instant",
 + "lock_api",
 + "parking_lot_core 0.8.5",
 +]
 +
 +[[package]]
 +name = "parking_lot"
 +version = "0.12.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
 +dependencies = [
 + "lock_api",
 + "parking_lot_core 0.9.3",
 +]
 +
 +[[package]]
 +name = "parking_lot_core"
 +version = "0.8.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
 +dependencies = [
 + "cfg-if",
 + "instant",
 + "libc",
 + "redox_syscall",
 + "smallvec",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "parking_lot_core"
 +version = "0.9.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
 +dependencies = [
 + "cfg-if",
 + "libc",
 + "redox_syscall",
 + "smallvec",
 + "windows-sys 0.36.1",
 +]
 +
 +[[package]]
 +name = "parser"
 +version = "0.0.0"
 +dependencies = [
 + "drop_bomb",
 + "expect-test",
 + "limit",
 + "rustc-ap-rustc_lexer",
 + "sourcegen",
 +]
 +
 +[[package]]
 +name = "paste"
- checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
++version = "1.0.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
-  "object 0.29.0",
++checksum = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22"
 +
 +[[package]]
 +name = "paths"
 +version = "0.0.0"
 +
 +[[package]]
 +name = "percent-encoding"
 +version = "2.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
 +
 +[[package]]
 +name = "perf-event"
 +version = "0.4.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5396562cd2eaa828445d6d34258ae21ee1eb9d40fe626ca7f51c8dccb4af9d66"
 +dependencies = [
 + "libc",
 + "perf-event-open-sys",
 +]
 +
 +[[package]]
 +name = "perf-event-open-sys"
 +version = "1.0.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ce9bedf5da2c234fdf2391ede2b90fabf585355f33100689bc364a3ea558561a"
 +dependencies = [
 + "libc",
 +]
 +
 +[[package]]
 +name = "petgraph"
 +version = "0.5.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
 +dependencies = [
 + "fixedbitset",
 + "indexmap",
 +]
 +
 +[[package]]
 +name = "pin-project-lite"
 +version = "0.2.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
 +
 +[[package]]
 +name = "proc-macro-api"
 +version = "0.0.0"
 +dependencies = [
 + "memmap2",
-  "object 0.29.0",
++ "object",
 + "paths",
 + "profile",
 + "serde",
 + "serde_json",
 + "snap",
 + "stdx",
 + "tracing",
 + "tt",
 +]
 +
 +[[package]]
 +name = "proc-macro-srv"
 +version = "0.0.0"
 +dependencies = [
 + "crossbeam",
 + "expect-test",
 + "libloading",
 + "mbe",
 + "memmap2",
- version = "1.0.40"
++ "object",
 + "paths",
 + "proc-macro-api",
 + "proc-macro-test",
 + "tt",
 +]
 +
 +[[package]]
 +name = "proc-macro-srv-cli"
 +version = "0.0.0"
 +dependencies = [
 + "proc-macro-srv",
 +]
 +
 +[[package]]
 +name = "proc-macro-test"
 +version = "0.0.0"
 +dependencies = [
 + "cargo_metadata",
 + "proc-macro-test-impl",
 + "toolchain",
 +]
 +
 +[[package]]
 +name = "proc-macro-test-impl"
 +version = "0.0.0"
 +
 +[[package]]
 +name = "proc-macro2"
- checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
++version = "1.0.43"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.9.1"
++checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
 +dependencies = [
 + "unicode-ident",
 +]
 +
 +[[package]]
 +name = "profile"
 +version = "0.0.0"
 +dependencies = [
 + "cfg-if",
 + "countme",
 + "la-arena",
 + "libc",
 + "once_cell",
 + "perf-event",
 + "tikv-jemalloc-ctl",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "project-model"
 +version = "0.0.0"
 +dependencies = [
 + "anyhow",
 + "base-db",
 + "cargo_metadata",
 + "cfg",
 + "expect-test",
 + "la-arena",
 + "paths",
 + "profile",
 + "rustc-hash",
 + "semver",
 + "serde",
 + "serde_json",
 + "stdx",
 + "toolchain",
 + "tracing",
 +]
 +
 +[[package]]
 +name = "pulldown-cmark"
- checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6"
++version = "0.9.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.20"
++checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63"
 +dependencies = [
 + "bitflags",
 + "memchr",
 + "unicase",
 +]
 +
 +[[package]]
 +name = "pulldown-cmark-to-cmark"
 +version = "10.0.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c1353ac408192fa925228d3e60ff746167d03f4f7e54835d78ef79e08225d913"
 +dependencies = [
 + "pulldown-cmark",
 +]
 +
 +[[package]]
 +name = "quote"
- checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
++version = "1.0.21"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.2.13"
++checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
 +dependencies = [
 + "proc-macro2",
 +]
 +
 +[[package]]
 +name = "rayon"
 +version = "1.5.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
 +dependencies = [
 + "autocfg",
 + "crossbeam-deque",
 + "either",
 + "rayon-core",
 +]
 +
 +[[package]]
 +name = "rayon-core"
 +version = "1.9.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
 +dependencies = [
 + "crossbeam-channel",
 + "crossbeam-deque",
 + "crossbeam-utils",
 + "num_cpus",
 +]
 +
 +[[package]]
 +name = "redox_syscall"
- checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
++version = "0.2.16"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.5.6"
++checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
 +dependencies = [
 + "bitflags",
 +]
 +
 +[[package]]
 +name = "regex"
- checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
++version = "1.6.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.6.26"
++checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
 +dependencies = [
 + "regex-syntax",
 +]
 +
 +[[package]]
 +name = "regex-automata"
 +version = "0.1.10"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
 +dependencies = [
 + "regex-syntax",
 +]
 +
 +[[package]]
 +name = "regex-syntax"
- checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
++version = "0.6.27"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.10"
++checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
 +
 +[[package]]
 +name = "rowan"
 +version = "0.15.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e88acf7b001007e9e8c989fe7449f6601d909e5dd2c56399fc158977ad6c56e8"
 +dependencies = [
 + "countme",
 + "hashbrown",
 + "memoffset",
 + "rustc-hash",
 + "text-size",
 +]
 +
 +[[package]]
 +name = "rust-analyzer"
 +version = "0.0.0"
 +dependencies = [
 + "always-assert",
 + "anyhow",
 + "cfg",
 + "crossbeam-channel",
 + "dissimilar",
 + "expect-test",
 + "flycheck",
 + "hir",
 + "hir-def",
 + "hir-ty",
 + "ide",
 + "ide-db",
 + "ide-ssr",
 + "itertools",
 + "jod-thread",
 + "lsp-server",
 + "lsp-types",
 + "mbe",
 + "mimalloc",
 + "num_cpus",
 + "oorandom",
 + "parking_lot 0.12.1",
 + "proc-macro-api",
 + "proc-macro-srv",
 + "profile",
 + "project-model",
 + "rayon",
 + "rustc-hash",
 + "serde",
 + "serde_json",
 + "sourcegen",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "threadpool",
 + "tikv-jemallocator",
 + "toolchain",
 + "tracing",
 + "tracing-log",
 + "tracing-subscriber",
 + "tracing-tree",
 + "tt",
 + "vfs",
 + "vfs-notify",
 + "winapi",
 + "xflags",
 + "xshell",
 +]
 +
 +[[package]]
 +name = "rustc-ap-rustc_lexer"
 +version = "725.0.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f950742ef8a203aa7661aad3ab880438ddeb7f95d4b837c30d65db1a2c5df68e"
 +dependencies = [
 + "unicode-xid",
 +]
 +
 +[[package]]
 +name = "rustc-demangle"
 +version = "0.1.21"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
 +
 +[[package]]
 +name = "rustc-hash"
 +version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 +
 +[[package]]
 +name = "ryu"
- checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
++version = "1.0.11"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.12"
++checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
 +
 +[[package]]
 +name = "salsa"
 +version = "0.17.0-pre.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9b223dccb46c32753144d0b51290da7230bb4aedcd8379d6b4c9a474c18bf17a"
 +dependencies = [
 + "crossbeam-utils",
 + "indexmap",
 + "lock_api",
 + "log",
 + "oorandom",
 + "parking_lot 0.11.2",
 + "rustc-hash",
 + "salsa-macros",
 + "smallvec",
 +]
 +
 +[[package]]
 +name = "salsa-macros"
 +version = "0.17.0-pre.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ac6c2e352df550bf019da7b16164ed2f7fa107c39653d1311d1bba42d1582ff7"
 +dependencies = [
 + "heck",
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "same-file"
 +version = "1.0.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
 +dependencies = [
 + "winapi-util",
 +]
 +
 +[[package]]
 +name = "scoped-tls"
 +version = "1.0.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
 +
 +[[package]]
 +name = "scopeguard"
 +version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 +
 +[[package]]
 +name = "semver"
- checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
++version = "1.0.13"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.138"
++checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "serde"
- checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47"
++version = "1.0.143"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.138"
++checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553"
 +dependencies = [
 + "serde_derive",
 +]
 +
 +[[package]]
 +name = "serde_derive"
- checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c"
++version = "1.0.143"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.82"
++checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "serde_json"
- checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
++version = "1.0.83"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.1.8"
++checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7"
 +dependencies = [
 + "indexmap",
 + "itoa",
 + "ryu",
 + "serde",
 +]
 +
 +[[package]]
 +name = "serde_repr"
- checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed"
++version = "0.1.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.98"
++checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "sharded-slab"
 +version = "0.1.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
 +dependencies = [
 + "lazy_static",
 +]
 +
 +[[package]]
 +name = "smallvec"
 +version = "1.9.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
 +
 +[[package]]
 +name = "smol_str"
 +version = "0.1.23"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7475118a28b7e3a2e157ce0131ba8c5526ea96e90ee601d9f6bb2e286a35ab44"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "snap"
 +version = "1.0.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "45456094d1983e2ee2a18fdfebce3189fa451699d0502cb8e3b49dba5ba41451"
 +
 +[[package]]
 +name = "sourcegen"
 +version = "0.0.0"
 +dependencies = [
 + "xshell",
 +]
 +
 +[[package]]
 +name = "stdx"
 +version = "0.0.0"
 +dependencies = [
 + "always-assert",
 + "backtrace",
 + "libc",
 + "miow",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "syn"
- checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
++version = "1.0.99"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.1.35"
++checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "unicode-ident",
 +]
 +
 +[[package]]
 +name = "synstructure"
 +version = "0.12.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 + "unicode-xid",
 +]
 +
 +[[package]]
 +name = "syntax"
 +version = "0.0.0"
 +dependencies = [
 + "cov-mark",
 + "expect-test",
 + "indexmap",
 + "itertools",
 + "once_cell",
 + "parser",
 + "proc-macro2",
 + "profile",
 + "quote",
 + "rayon",
 + "rowan",
 + "rustc-ap-rustc_lexer",
 + "rustc-hash",
 + "smol_str",
 + "sourcegen",
 + "stdx",
 + "test-utils",
 + "text-edit",
 + "ungrammar",
 +]
 +
 +[[package]]
 +name = "test-utils"
 +version = "0.0.0"
 +dependencies = [
 + "dissimilar",
 + "profile",
 + "rustc-hash",
 + "stdx",
 + "text-size",
 +]
 +
 +[[package]]
 +name = "text-edit"
 +version = "0.0.0"
 +dependencies = [
 + "itertools",
 + "text-size",
 +]
 +
 +[[package]]
 +name = "text-size"
 +version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a"
 +
 +[[package]]
 +name = "thread_local"
 +version = "1.1.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
 +dependencies = [
 + "once_cell",
 +]
 +
 +[[package]]
 +name = "threadpool"
 +version = "1.8.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
 +dependencies = [
 + "num_cpus",
 +]
 +
 +[[package]]
 +name = "tikv-jemalloc-ctl"
 +version = "0.5.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e37706572f4b151dff7a0146e040804e9c26fe3a3118591112f05cf12a4216c1"
 +dependencies = [
 + "libc",
 + "paste",
 + "tikv-jemalloc-sys",
 +]
 +
 +[[package]]
 +name = "tikv-jemalloc-sys"
 +version = "0.5.1+5.3.0-patched"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "931e876f91fed0827f863a2d153897790da0b24d882c721a79cb3beb0b903261"
 +dependencies = [
 + "cc",
 + "fs_extra",
 + "libc",
 +]
 +
 +[[package]]
 +name = "tikv-jemallocator"
 +version = "0.5.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "20612db8a13a6c06d57ec83953694185a367e16945f66565e8028d2c0bd76979"
 +dependencies = [
 + "libc",
 + "tikv-jemalloc-sys",
 +]
 +
 +[[package]]
 +name = "tinyvec"
 +version = "1.6.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
 +dependencies = [
 + "tinyvec_macros",
 +]
 +
 +[[package]]
 +name = "tinyvec_macros"
 +version = "0.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
 +
 +[[package]]
 +name = "toolchain"
 +version = "0.0.0"
 +dependencies = [
 + "home",
 +]
 +
 +[[package]]
 +name = "tracing"
- checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160"
++version = "0.1.36"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.1.28"
++checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
 +dependencies = [
 + "cfg-if",
 + "pin-project-lite",
 + "tracing-attributes",
 + "tracing-core",
 +]
 +
 +[[package]]
 +name = "tracing-attributes"
 +version = "0.1.22"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "tracing-core"
- checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7"
++version = "0.1.29"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.3.14"
++checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
 +dependencies = [
 + "once_cell",
 + "valuable",
 +]
 +
 +[[package]]
 +name = "tracing-log"
 +version = "0.1.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
 +dependencies = [
 + "lazy_static",
 + "log",
 + "tracing-core",
 +]
 +
 +[[package]]
 +name = "tracing-subscriber"
- checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59"
++version = "0.3.15"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b"
 +dependencies = [
 + "matchers",
 + "once_cell",
 + "regex",
 + "sharded-slab",
 + "thread_local",
 + "tracing",
 + "tracing-core",
 + "tracing-log",
 +]
 +
 +[[package]]
 +name = "tracing-tree"
 +version = "0.2.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d07e90b329c621ade432823988574e820212648aa40e7a2497777d58de0fb453"
 +dependencies = [
 + "ansi_term",
 + "atty",
 + "tracing-core",
 + "tracing-log",
 + "tracing-subscriber",
 +]
 +
 +[[package]]
 +name = "tt"
 +version = "0.0.0"
 +dependencies = [
 + "smol_str",
 + "stdx",
 +]
 +
 +[[package]]
 +name = "typed-arena"
 +version = "2.0.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae"
 +
 +[[package]]
 +name = "ungrammar"
 +version = "1.16.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a3e5df347f0bf3ec1d670aad6ca5c6a1859cd9ea61d2113125794654ccced68f"
 +
 +[[package]]
 +name = "unicase"
 +version = "2.6.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
 +dependencies = [
 + "version_check",
 +]
 +
 +[[package]]
 +name = "unicode-bidi"
 +version = "0.3.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
 +
 +[[package]]
 +name = "unicode-ident"
 +version = "1.0.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
 +
 +[[package]]
 +name = "unicode-normalization"
 +version = "0.1.21"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6"
 +dependencies = [
 + "tinyvec",
 +]
 +
 +[[package]]
 +name = "unicode-segmentation"
 +version = "1.9.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
 +
 +[[package]]
 +name = "unicode-xid"
 +version = "0.2.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
 +
 +[[package]]
 +name = "url"
 +version = "2.2.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
 +dependencies = [
 + "form_urlencoded",
 + "idna",
 + "matches",
 + "percent-encoding",
 + "serde",
 +]
 +
 +[[package]]
 +name = "valuable"
 +version = "0.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
 +
 +[[package]]
 +name = "version_check"
 +version = "0.9.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 +
 +[[package]]
 +name = "vfs"
 +version = "0.0.0"
 +dependencies = [
 + "fst",
 + "indexmap",
 + "paths",
 + "rustc-hash",
 +]
 +
 +[[package]]
 +name = "vfs-notify"
 +version = "0.0.0"
 +dependencies = [
 + "crossbeam-channel",
 + "jod-thread",
 + "notify",
 + "paths",
 + "tracing",
 + "vfs",
 + "walkdir",
 +]
 +
 +[[package]]
 +name = "walkdir"
 +version = "2.3.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
 +dependencies = [
 + "same-file",
 + "winapi",
 + "winapi-util",
 +]
 +
 +[[package]]
 +name = "wasi"
 +version = "0.11.0+wasi-snapshot-preview1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 +
 +[[package]]
 +name = "winapi"
 +version = "0.3.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
 +dependencies = [
 + "winapi-i686-pc-windows-gnu",
 + "winapi-x86_64-pc-windows-gnu",
 +]
 +
 +[[package]]
 +name = "winapi-i686-pc-windows-gnu"
 +version = "0.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 +
 +[[package]]
 +name = "winapi-util"
 +version = "0.1.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
 +dependencies = [
 + "winapi",
 +]
 +
 +[[package]]
 +name = "winapi-x86_64-pc-windows-gnu"
 +version = "0.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 +
 +[[package]]
 +name = "windows-sys"
 +version = "0.28.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "82ca39602d5cbfa692c4b67e3bcbb2751477355141c1ed434c94da4186836ff6"
 +dependencies = [
 + "windows_aarch64_msvc 0.28.0",
 + "windows_i686_gnu 0.28.0",
 + "windows_i686_msvc 0.28.0",
 + "windows_x86_64_gnu 0.28.0",
 + "windows_x86_64_msvc 0.28.0",
 +]
 +
 +[[package]]
 +name = "windows-sys"
 +version = "0.36.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
 +dependencies = [
 + "windows_aarch64_msvc 0.36.1",
 + "windows_i686_gnu 0.36.1",
 + "windows_i686_msvc 0.36.1",
 + "windows_x86_64_gnu 0.36.1",
 + "windows_x86_64_msvc 0.36.1",
 +]
 +
 +[[package]]
 +name = "windows_aarch64_msvc"
 +version = "0.28.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2"
 +
 +[[package]]
 +name = "windows_aarch64_msvc"
 +version = "0.36.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
 +
 +[[package]]
 +name = "windows_i686_gnu"
 +version = "0.28.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a"
 +
 +[[package]]
 +name = "windows_i686_gnu"
 +version = "0.36.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
 +
 +[[package]]
 +name = "windows_i686_msvc"
 +version = "0.28.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64"
 +
 +[[package]]
 +name = "windows_i686_msvc"
 +version = "0.36.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
 +
 +[[package]]
 +name = "windows_x86_64_gnu"
 +version = "0.28.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954"
 +
 +[[package]]
 +name = "windows_x86_64_gnu"
 +version = "0.36.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
 +
 +[[package]]
 +name = "windows_x86_64_msvc"
 +version = "0.28.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f"
 +
 +[[package]]
 +name = "windows_x86_64_msvc"
 +version = "0.36.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
 +
 +[[package]]
 +name = "write-json"
 +version = "0.1.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "06069a848f95fceae3e5e03c0ddc8cb78452b56654ee0c8e68f938cf790fb9e3"
 +
 +[[package]]
 +name = "xflags"
 +version = "0.2.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3f14fe1ed41a5a2b5ef3f565586c4a8a559ee55d3953faab360a771135bdee00"
 +dependencies = [
 + "xflags-macros",
 +]
 +
 +[[package]]
 +name = "xflags-macros"
 +version = "0.2.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "45d11d5fc2a97287eded8b170ca80533b3c42646dd7fa386a5eb045817921022"
 +
 +[[package]]
 +name = "xshell"
 +version = "0.2.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "6d47097dc5c85234b1e41851b3422dd6d19b3befdd35b4ae5ce386724aeca981"
 +dependencies = [
 + "xshell-macros",
 +]
 +
 +[[package]]
 +name = "xshell-macros"
 +version = "0.2.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "88301b56c26dd9bf5c43d858538f82d6f3f7764767defbc5d34e59459901c41a"
 +
 +[[package]]
 +name = "xtask"
 +version = "0.1.0"
 +dependencies = [
 + "anyhow",
 + "flate2",
 + "write-json",
 + "xflags",
 + "xshell",
 +]
index 3347940ec6d639015304407bdd708dcff184c2bb,0000000000000000000000000000000000000000..c22945c81fcb93b1971721c6d5f6446cf950142c
mode 100644,000000..100644
--- /dev/null
@@@ -1,403 -1,0 +1,419 @@@
-     pub fn update(&self) {
-         self.sender.send(Restart).unwrap();
 +//! 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 serde::Deserialize;
 +use stdx::{process::streaming_output, JodChild};
 +
 +pub use cargo_metadata::diagnostic::{
 +    Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan,
 +    DiagnosticSpanMacroExpansion,
 +};
 +
 +#[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>,
 +    },
 +    CustomCommand {
 +        command: String,
 +        args: Vec<String>,
 +    },
 +}
 +
 +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.
- struct Restart;
++    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,
 +}
 +
-                 Event::Restart(Restart) => {
++enum Restart {
++    Yes,
++    No,
++}
 +
 +struct FlycheckActor {
 +    id: usize,
 +    sender: Box<dyn Fn(Message) + Send>,
 +    config: FlycheckConfig,
 +    workspace_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");
 +        FlycheckActor { id, sender, config, workspace_root, cargo_handle: None }
 +    }
 +    fn 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);
 +        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>) {
 +        while let Some(event) = self.next_event(&inbox) {
 +            match event {
-                     while let Ok(Restart) = inbox.recv_timeout(Duration::from_millis(50)) {}
++                Event::Restart(Restart::No) => {
++                    self.cancel_check_process();
++                }
++                Event::Restart(Restart::Yes) => {
 +                    // Cancel the previously spawned process
 +                    self.cancel_check_process();
-         // erroneus output.
++                    while let Ok(_) = inbox.recv_timeout(Duration::from_millis(50)) {}
 +
 +                    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::DidStart);
 +                        }
 +                        Err(error) => {
 +                            tracing::error!(
 +                                command = ?self.check_command(),
 +                                %error, "failed to restart flycheck"
 +                            );
 +                        }
 +                    }
 +                }
 +                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::DidFinish(res));
 +                }
 +                Event::CheckEvent(Some(message)) => match message {
 +                    CargoMessage::CompilerArtifact(msg) => {
 +                        self.progress(Progress::DidCheckCrate(msg.target.name));
 +                    }
 +
 +                    CargoMessage::Diagnostic(msg) => {
 +                        self.send(Message::AddDiagnostic {
 +                            id: self.id,
 +                            workspace_root: self.workspace_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();
 +            self.progress(Progress::DidCancel);
 +        }
 +    }
 +
 +    fn check_command(&self) -> Command {
 +        let mut cmd = match &self.config {
 +            FlycheckConfig::CargoCommand {
 +                command,
 +                target_triple,
 +                no_default_features,
 +                all_targets,
 +                all_features,
 +                extra_args,
 +                features,
 +            } => {
 +                let mut cmd = Command::new(toolchain::cargo());
 +                cmd.arg(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());
 +
 +                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.args(extra_args);
 +                cmd
 +            }
 +            FlycheckConfig::CustomCommand { command, args } => {
 +                let mut cmd = Command::new(command);
 +                cmd.args(args);
 +                cmd
 +            }
 +        };
 +        cmd.current_dir(&self.workspace_root);
 +        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 080a307b1f8a4540ef1dd3a6a217a0e0f4c3b017,0000000000000000000000000000000000000000..1d818d96267c177223985d6588e138556227e9c2
mode 100644,000000..100644
--- /dev/null
@@@ -1,471 -1,0 +1,476 @@@
 +//! Defines `Body`: a lowered representation of bodies of functions, statics and
 +//! consts.
 +mod lower;
 +#[cfg(test)]
 +mod tests;
 +pub mod scope;
++mod pretty;
 +
 +use std::{ops::Index, sync::Arc};
 +
 +use base_db::CrateId;
 +use cfg::{CfgExpr, CfgOptions};
 +use drop_bomb::DropBomb;
 +use either::Either;
 +use hir_expand::{hygiene::Hygiene, ExpandError, ExpandResult, HirFileId, InFile, MacroCallId};
 +use la_arena::{Arena, ArenaMap};
 +use limit::Limit;
 +use profile::Count;
 +use rustc_hash::FxHashMap;
 +use syntax::{ast, AstPtr, SyntaxNodePtr};
 +
 +use crate::{
 +    attr::{Attrs, RawAttrs},
 +    db::DefDatabase,
 +    expr::{dummy_expr_id, Expr, ExprId, Label, LabelId, Pat, PatId},
 +    item_scope::BuiltinShadowMode,
 +    macro_id_to_def_id,
 +    nameres::DefMap,
 +    path::{ModPath, Path},
 +    src::HasSource,
 +    AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, ModuleId,
 +    UnresolvedMacro,
 +};
 +
 +pub use lower::LowerCtx;
 +
 +/// A subset of Expander that only deals with cfg attributes. We only need it to
 +/// avoid cyclic queries in crate def map during enum processing.
 +#[derive(Debug)]
 +pub(crate) struct CfgExpander {
 +    cfg_options: CfgOptions,
 +    hygiene: Hygiene,
 +    krate: CrateId,
 +}
 +
 +#[derive(Debug)]
 +pub struct Expander {
 +    cfg_expander: CfgExpander,
 +    def_map: Arc<DefMap>,
 +    current_file_id: HirFileId,
 +    module: LocalModuleId,
 +    recursion_limit: usize,
 +}
 +
 +impl CfgExpander {
 +    pub(crate) fn new(
 +        db: &dyn DefDatabase,
 +        current_file_id: HirFileId,
 +        krate: CrateId,
 +    ) -> CfgExpander {
 +        let hygiene = Hygiene::new(db.upcast(), current_file_id);
 +        let cfg_options = db.crate_graph()[krate].cfg_options.clone();
 +        CfgExpander { cfg_options, hygiene, krate }
 +    }
 +
 +    pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs {
 +        RawAttrs::new(db, owner, &self.hygiene).filter(db, self.krate)
 +    }
 +
 +    pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> bool {
 +        let attrs = self.parse_attrs(db, owner);
 +        attrs.is_cfg_enabled(&self.cfg_options)
 +    }
 +}
 +
 +impl Expander {
 +    pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
 +        let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
 +        let def_map = module.def_map(db);
 +        Expander {
 +            cfg_expander,
 +            def_map,
 +            current_file_id,
 +            module: module.local_id,
 +            recursion_limit: 0,
 +        }
 +    }
 +
 +    pub fn enter_expand<T: ast::AstNode>(
 +        &mut self,
 +        db: &dyn DefDatabase,
 +        macro_call: ast::MacroCall,
 +    ) -> Result<ExpandResult<Option<(Mark, T)>>, UnresolvedMacro> {
 +        if self.recursion_limit(db).check(self.recursion_limit + 1).is_err() {
 +            cov_mark::hit!(your_stack_belongs_to_me);
 +            return Ok(ExpandResult::only_err(ExpandError::Other(
 +                "reached recursion limit during macro expansion".into(),
 +            )));
 +        }
 +
 +        let macro_call = InFile::new(self.current_file_id, &macro_call);
 +
 +        let resolver =
 +            |path| self.resolve_path_as_macro(db, &path).map(|it| macro_id_to_def_id(db, it));
 +
 +        let mut err = None;
 +        let call_id =
 +            macro_call.as_call_id_with_errors(db, self.def_map.krate(), resolver, &mut |e| {
 +                err.get_or_insert(e);
 +            })?;
 +        let call_id = match call_id {
 +            Ok(it) => it,
 +            Err(_) => {
 +                return Ok(ExpandResult { value: None, err });
 +            }
 +        };
 +
 +        Ok(self.enter_expand_inner(db, call_id, err))
 +    }
 +
 +    pub fn enter_expand_id<T: ast::AstNode>(
 +        &mut self,
 +        db: &dyn DefDatabase,
 +        call_id: MacroCallId,
 +    ) -> ExpandResult<Option<(Mark, T)>> {
 +        self.enter_expand_inner(db, call_id, None)
 +    }
 +
 +    fn enter_expand_inner<T: ast::AstNode>(
 +        &mut self,
 +        db: &dyn DefDatabase,
 +        call_id: MacroCallId,
 +        mut err: Option<ExpandError>,
 +    ) -> ExpandResult<Option<(Mark, T)>> {
 +        if err.is_none() {
 +            err = db.macro_expand_error(call_id);
 +        }
 +
 +        let file_id = call_id.as_file();
 +
 +        let raw_node = match db.parse_or_expand(file_id) {
 +            Some(it) => it,
 +            None => {
 +                // Only `None` if the macro expansion produced no usable AST.
 +                if err.is_none() {
 +                    tracing::warn!("no error despite `parse_or_expand` failing");
 +                }
 +
 +                return ExpandResult::only_err(err.unwrap_or_else(|| {
 +                    ExpandError::Other("failed to parse macro invocation".into())
 +                }));
 +            }
 +        };
 +
 +        let node = match T::cast(raw_node) {
 +            Some(it) => it,
 +            None => {
 +                // This can happen without being an error, so only forward previous errors.
 +                return ExpandResult { value: None, err };
 +            }
 +        };
 +
 +        tracing::debug!("macro expansion {:#?}", node.syntax());
 +
 +        self.recursion_limit += 1;
 +        let mark =
 +            Mark { file_id: self.current_file_id, bomb: DropBomb::new("expansion mark dropped") };
 +        self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
 +        self.current_file_id = file_id;
 +
 +        ExpandResult { value: Some((mark, node)), err }
 +    }
 +
 +    pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
 +        self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
 +        self.current_file_id = mark.file_id;
 +        self.recursion_limit -= 1;
 +        mark.bomb.defuse();
 +    }
 +
 +    pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> {
 +        InFile { file_id: self.current_file_id, value }
 +    }
 +
 +    pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs {
 +        self.cfg_expander.parse_attrs(db, owner)
 +    }
 +
 +    pub(crate) fn cfg_options(&self) -> &CfgOptions {
 +        &self.cfg_expander.cfg_options
 +    }
 +
 +    pub fn current_file_id(&self) -> HirFileId {
 +        self.current_file_id
 +    }
 +
 +    fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> {
 +        let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene);
 +        Path::from_src(path, &ctx)
 +    }
 +
 +    fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroId> {
 +        self.def_map.resolve_path(db, self.module, path, BuiltinShadowMode::Other).0.take_macros()
 +    }
 +
 +    fn recursion_limit(&self, db: &dyn DefDatabase) -> Limit {
 +        let limit = db.crate_limits(self.cfg_expander.krate).recursion_limit as _;
 +
 +        #[cfg(not(test))]
 +        return Limit::new(limit);
 +
 +        // Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug
 +        #[cfg(test)]
 +        return Limit::new(std::cmp::min(32, limit));
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub struct Mark {
 +    file_id: HirFileId,
 +    bomb: DropBomb,
 +}
 +
 +/// The body of an item (function, const etc.).
 +#[derive(Debug, Eq, PartialEq)]
 +pub struct Body {
 +    pub exprs: Arena<Expr>,
 +    pub pats: Arena<Pat>,
 +    pub or_pats: FxHashMap<PatId, Arc<[PatId]>>,
 +    pub labels: Arena<Label>,
 +    /// The patterns for the function's parameters. While the parameter types are
 +    /// part of the function signature, the patterns are not (they don't change
 +    /// the external type of the function).
 +    ///
 +    /// If this `Body` is for the body of a constant, this will just be
 +    /// empty.
 +    pub params: Vec<PatId>,
 +    /// The `ExprId` of the actual body expression.
 +    pub body_expr: ExprId,
 +    /// Block expressions in this body that may contain inner items.
 +    block_scopes: Vec<BlockId>,
 +    _c: Count<Self>,
 +}
 +
 +pub type ExprPtr = AstPtr<ast::Expr>;
 +pub type ExprSource = InFile<ExprPtr>;
 +
 +pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
 +pub type PatSource = InFile<PatPtr>;
 +
 +pub type LabelPtr = AstPtr<ast::Label>;
 +pub type LabelSource = InFile<LabelPtr>;
 +/// An item body together with the mapping from syntax nodes to HIR expression
 +/// IDs. This is needed to go from e.g. a position in a file to the HIR
 +/// expression containing it; but for type inference etc., we want to operate on
 +/// a structure that is agnostic to the actual positions of expressions in the
 +/// file, so that we don't recompute types whenever some whitespace is typed.
 +///
 +/// One complication here is that, due to macro expansion, a single `Body` might
 +/// be spread across several files. So, for each ExprId and PatId, we record
 +/// both the HirFileId and the position inside the file. However, we only store
 +/// AST -> ExprId mapping for non-macro files, as it is not clear how to handle
 +/// this properly for macros.
 +#[derive(Default, Debug, Eq, PartialEq)]
 +pub struct BodySourceMap {
 +    expr_map: FxHashMap<ExprSource, ExprId>,
 +    expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
 +
 +    pat_map: FxHashMap<PatSource, PatId>,
 +    pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>,
 +
 +    label_map: FxHashMap<LabelSource, LabelId>,
 +    label_map_back: ArenaMap<LabelId, LabelSource>,
 +
 +    /// We don't create explicit nodes for record fields (`S { record_field: 92 }`).
 +    /// Instead, we use id of expression (`92`) to identify the field.
 +    field_map: FxHashMap<InFile<AstPtr<ast::RecordExprField>>, ExprId>,
 +    field_map_back: FxHashMap<ExprId, InFile<AstPtr<ast::RecordExprField>>>,
 +
 +    expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
 +
 +    /// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in
 +    /// the source map (since they're just as volatile).
 +    diagnostics: Vec<BodyDiagnostic>,
 +}
 +
 +#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
 +pub struct SyntheticSyntax;
 +
 +#[derive(Debug, Eq, PartialEq)]
 +pub enum BodyDiagnostic {
 +    InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions },
 +    MacroError { node: InFile<AstPtr<ast::MacroCall>>, message: String },
 +    UnresolvedProcMacro { node: InFile<AstPtr<ast::MacroCall>>, krate: CrateId },
 +    UnresolvedMacroCall { node: InFile<AstPtr<ast::MacroCall>>, path: ModPath },
 +}
 +
 +impl Body {
 +    pub(crate) fn body_with_source_map_query(
 +        db: &dyn DefDatabase,
 +        def: DefWithBodyId,
 +    ) -> (Arc<Body>, Arc<BodySourceMap>) {
 +        let _p = profile::span("body_with_source_map_query");
 +        let mut params = None;
 +
 +        let (file_id, module, body) = match def {
 +            DefWithBodyId::FunctionId(f) => {
 +                let f = f.lookup(db);
 +                let src = f.source(db);
 +                params = src.value.param_list();
 +                (src.file_id, f.module(db), src.value.body().map(ast::Expr::from))
 +            }
 +            DefWithBodyId::ConstId(c) => {
 +                let c = c.lookup(db);
 +                let src = c.source(db);
 +                (src.file_id, c.module(db), src.value.body())
 +            }
 +            DefWithBodyId::StaticId(s) => {
 +                let s = s.lookup(db);
 +                let src = s.source(db);
 +                (src.file_id, s.module(db), src.value.body())
 +            }
 +        };
 +        let expander = Expander::new(db, file_id, module);
 +        let (mut body, source_map) = Body::new(db, expander, params, body);
 +        body.shrink_to_fit();
 +        (Arc::new(body), Arc::new(source_map))
 +    }
 +
 +    pub(crate) fn body_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<Body> {
 +        db.body_with_source_map(def).0
 +    }
 +
 +    /// Returns an iterator over all block expressions in this body that define inner items.
 +    pub fn blocks<'a>(
 +        &'a self,
 +        db: &'a dyn DefDatabase,
 +    ) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + '_ {
 +        self.block_scopes
 +            .iter()
 +            .map(move |&block| (block, db.block_def_map(block).expect("block ID without DefMap")))
 +    }
 +
 +    pub fn pattern_representative(&self, pat: PatId) -> PatId {
 +        self.or_pats.get(&pat).and_then(|pats| pats.first().copied()).unwrap_or(pat)
 +    }
 +
 +    /// Retrieves all ident patterns this pattern shares the ident with.
 +    pub fn ident_patterns_for<'slf>(&'slf self, pat: &'slf PatId) -> &'slf [PatId] {
 +        match self.or_pats.get(pat) {
 +            Some(pats) => &**pats,
 +            None => std::slice::from_ref(pat),
 +        }
 +    }
 +
++    pub fn pretty_print(&self, db: &dyn DefDatabase, owner: DefWithBodyId) -> String {
++        pretty::print_body_hir(db, self, owner)
++    }
++
 +    fn new(
 +        db: &dyn DefDatabase,
 +        expander: Expander,
 +        params: Option<ast::ParamList>,
 +        body: Option<ast::Expr>,
 +    ) -> (Body, BodySourceMap) {
 +        lower::lower(db, expander, params, body)
 +    }
 +
 +    fn shrink_to_fit(&mut self) {
 +        let Self { _c: _, body_expr: _, block_scopes, or_pats, exprs, labels, params, pats } = self;
 +        block_scopes.shrink_to_fit();
 +        or_pats.shrink_to_fit();
 +        exprs.shrink_to_fit();
 +        labels.shrink_to_fit();
 +        params.shrink_to_fit();
 +        pats.shrink_to_fit();
 +    }
 +}
 +
 +impl Default for Body {
 +    fn default() -> Self {
 +        Self {
 +            body_expr: dummy_expr_id(),
 +            exprs: Default::default(),
 +            pats: Default::default(),
 +            or_pats: Default::default(),
 +            labels: Default::default(),
 +            params: Default::default(),
 +            block_scopes: Default::default(),
 +            _c: Default::default(),
 +        }
 +    }
 +}
 +
 +impl Index<ExprId> for Body {
 +    type Output = Expr;
 +
 +    fn index(&self, expr: ExprId) -> &Expr {
 +        &self.exprs[expr]
 +    }
 +}
 +
 +impl Index<PatId> for Body {
 +    type Output = Pat;
 +
 +    fn index(&self, pat: PatId) -> &Pat {
 +        &self.pats[pat]
 +    }
 +}
 +
 +impl Index<LabelId> for Body {
 +    type Output = Label;
 +
 +    fn index(&self, label: LabelId) -> &Label {
 +        &self.labels[label]
 +    }
 +}
 +
 +// FIXME: Change `node_` prefix to something more reasonable.
 +// Perhaps `expr_syntax` and `expr_id`?
 +impl BodySourceMap {
 +    pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
 +        self.expr_map_back[expr].clone()
 +    }
 +
 +    pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
 +        let src = node.map(AstPtr::new);
 +        self.expr_map.get(&src).cloned()
 +    }
 +
 +    pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<HirFileId> {
 +        let src = node.map(AstPtr::new);
 +        self.expansions.get(&src).cloned()
 +    }
 +
 +    pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
 +        self.pat_map_back[pat].clone()
 +    }
 +
 +    pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
 +        let src = node.map(|it| Either::Left(AstPtr::new(it)));
 +        self.pat_map.get(&src).cloned()
 +    }
 +
 +    pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> {
 +        let src = node.map(|it| Either::Right(AstPtr::new(it)));
 +        self.pat_map.get(&src).cloned()
 +    }
 +
 +    pub fn label_syntax(&self, label: LabelId) -> LabelSource {
 +        self.label_map_back[label].clone()
 +    }
 +
 +    pub fn node_label(&self, node: InFile<&ast::Label>) -> Option<LabelId> {
 +        let src = node.map(AstPtr::new);
 +        self.label_map.get(&src).cloned()
 +    }
 +
 +    pub fn field_syntax(&self, expr: ExprId) -> InFile<AstPtr<ast::RecordExprField>> {
 +        self.field_map_back[&expr].clone()
 +    }
 +    pub fn node_field(&self, node: InFile<&ast::RecordExprField>) -> Option<ExprId> {
 +        let src = node.map(AstPtr::new);
 +        self.field_map.get(&src).cloned()
 +    }
 +
 +    pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprId> {
 +        let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::MacroExpr>).map(AstPtr::upcast);
 +        self.expr_map.get(&src).copied()
 +    }
 +
 +    /// Get a reference to the body source map's diagnostics.
 +    pub fn diagnostics(&self) -> &[BodyDiagnostic] {
 +        &self.diagnostics
 +    }
 +}
index 66f9c24e8724a77e10d73a0f55df2367ebb1e116,0000000000000000000000000000000000000000..f6ec8bf7e9e0b4475302dfb6ed17b3c0e8c44d88
mode 100644,000000..100644
--- /dev/null
@@@ -1,1023 -1,0 +1,1031 @@@
-                 let statements = e.statements().filter_map(|s| self.collect_stmt(s)).collect();
 +//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
 +//! representation.
 +
 +use std::{mem, sync::Arc};
 +
 +use either::Either;
 +use hir_expand::{
 +    ast_id_map::AstIdMap,
 +    hygiene::Hygiene,
 +    name::{name, AsName, Name},
 +    AstId, ExpandError, HirFileId, InFile,
 +};
 +use la_arena::Arena;
 +use once_cell::unsync::OnceCell;
 +use profile::Count;
 +use rustc_hash::FxHashMap;
 +use syntax::{
 +    ast::{
 +        self, ArrayExprKind, AstChildren, HasArgList, HasLoopBody, HasName, LiteralKind,
 +        SlicePatComponents,
 +    },
 +    AstNode, AstPtr, SyntaxNodePtr,
 +};
 +
 +use crate::{
 +    adt::StructKind,
 +    body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
 +    body::{BodyDiagnostic, ExprSource, PatSource},
 +    builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
 +    db::DefDatabase,
 +    expr::{
 +        dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, FloatTypeWrapper, Label, LabelId,
 +        Literal, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
 +    },
 +    intern::Interned,
 +    item_scope::BuiltinShadowMode,
 +    path::{GenericArgs, Path},
 +    type_ref::{Mutability, Rawness, TypeRef},
 +    AdtId, BlockLoc, ModuleDefId, UnresolvedMacro,
 +};
 +
 +pub struct LowerCtx<'a> {
 +    pub db: &'a dyn DefDatabase,
 +    hygiene: Hygiene,
 +    ast_id_map: Option<(HirFileId, OnceCell<Arc<AstIdMap>>)>,
 +}
 +
 +impl<'a> LowerCtx<'a> {
 +    pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
 +        LowerCtx {
 +            db,
 +            hygiene: Hygiene::new(db.upcast(), file_id),
 +            ast_id_map: Some((file_id, OnceCell::new())),
 +        }
 +    }
 +
 +    pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self {
 +        LowerCtx { db, hygiene: hygiene.clone(), ast_id_map: None }
 +    }
 +
 +    pub(crate) fn hygiene(&self) -> &Hygiene {
 +        &self.hygiene
 +    }
 +
 +    pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> {
 +        Path::from_src(ast, self)
 +    }
 +
 +    pub(crate) fn ast_id<N: AstNode>(&self, db: &dyn DefDatabase, item: &N) -> Option<AstId<N>> {
 +        let &(file_id, ref ast_id_map) = self.ast_id_map.as_ref()?;
 +        let ast_id_map = ast_id_map.get_or_init(|| db.ast_id_map(file_id));
 +        Some(InFile::new(file_id, ast_id_map.ast_id(item)))
 +    }
 +}
 +
 +pub(super) fn lower(
 +    db: &dyn DefDatabase,
 +    expander: Expander,
 +    params: Option<ast::ParamList>,
 +    body: Option<ast::Expr>,
 +) -> (Body, BodySourceMap) {
 +    ExprCollector {
 +        db,
 +        source_map: BodySourceMap::default(),
 +        ast_id_map: db.ast_id_map(expander.current_file_id),
 +        body: Body {
 +            exprs: Arena::default(),
 +            pats: Arena::default(),
 +            labels: Arena::default(),
 +            params: Vec::new(),
 +            body_expr: dummy_expr_id(),
 +            block_scopes: Vec::new(),
 +            _c: Count::new(),
 +            or_pats: Default::default(),
 +        },
 +        expander,
 +        name_to_pat_grouping: Default::default(),
 +        is_lowering_inside_or_pat: false,
 +        is_lowering_assignee_expr: false,
 +    }
 +    .collect(params, body)
 +}
 +
 +struct ExprCollector<'a> {
 +    db: &'a dyn DefDatabase,
 +    expander: Expander,
 +    ast_id_map: Arc<AstIdMap>,
 +    body: Body,
 +    source_map: BodySourceMap,
 +    // a poor-mans union-find?
 +    name_to_pat_grouping: FxHashMap<Name, Vec<PatId>>,
 +    is_lowering_inside_or_pat: bool,
 +    is_lowering_assignee_expr: bool,
 +}
 +
 +impl ExprCollector<'_> {
 +    fn collect(
 +        mut self,
 +        param_list: Option<ast::ParamList>,
 +        body: Option<ast::Expr>,
 +    ) -> (Body, BodySourceMap) {
 +        if let Some(param_list) = param_list {
 +            if let Some(self_param) = param_list.self_param() {
 +                let ptr = AstPtr::new(&self_param);
 +                let param_pat = self.alloc_pat(
 +                    Pat::Bind {
 +                        name: name![self],
 +                        mode: BindingAnnotation::new(
 +                            self_param.mut_token().is_some() && self_param.amp_token().is_none(),
 +                            false,
 +                        ),
 +                        subpat: None,
 +                    },
 +                    Either::Right(ptr),
 +                );
 +                self.body.params.push(param_pat);
 +            }
 +
 +            for pat in param_list.params().filter_map(|param| param.pat()) {
 +                let param_pat = self.collect_pat(pat);
 +                self.body.params.push(param_pat);
 +            }
 +        };
 +
 +        self.body.body_expr = self.collect_expr_opt(body);
 +        (self.body, self.source_map)
 +    }
 +
 +    fn ctx(&self) -> LowerCtx<'_> {
 +        LowerCtx::new(self.db, self.expander.current_file_id)
 +    }
 +
 +    fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
 +        let src = self.expander.to_source(ptr);
 +        let id = self.make_expr(expr, Ok(src.clone()));
 +        self.source_map.expr_map.insert(src, id);
 +        id
 +    }
 +    // desugared exprs don't have ptr, that's wrong and should be fixed
 +    // somehow.
 +    fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
 +        self.make_expr(expr, Err(SyntheticSyntax))
 +    }
 +    fn missing_expr(&mut self) -> ExprId {
 +        self.alloc_expr_desugared(Expr::Missing)
 +    }
 +    fn make_expr(&mut self, expr: Expr, src: Result<ExprSource, SyntheticSyntax>) -> ExprId {
 +        let id = self.body.exprs.alloc(expr);
 +        self.source_map.expr_map_back.insert(id, src);
 +        id
 +    }
 +
 +    fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
 +        let src = self.expander.to_source(ptr);
 +        let id = self.make_pat(pat, Ok(src.clone()));
 +        self.source_map.pat_map.insert(src, id);
 +        id
 +    }
 +    fn missing_pat(&mut self) -> PatId {
 +        self.make_pat(Pat::Missing, Err(SyntheticSyntax))
 +    }
 +    fn make_pat(&mut self, pat: Pat, src: Result<PatSource, SyntheticSyntax>) -> PatId {
 +        let id = self.body.pats.alloc(pat);
 +        self.source_map.pat_map_back.insert(id, src);
 +        id
 +    }
 +
 +    fn alloc_label(&mut self, label: Label, ptr: AstPtr<ast::Label>) -> LabelId {
 +        let src = self.expander.to_source(ptr);
 +        let id = self.make_label(label, src.clone());
 +        self.source_map.label_map.insert(src, id);
 +        id
 +    }
 +    fn make_label(&mut self, label: Label, src: LabelSource) -> LabelId {
 +        let id = self.body.labels.alloc(label);
 +        self.source_map.label_map_back.insert(id, src);
 +        id
 +    }
 +
 +    fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
 +        self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr())
 +    }
 +
 +    /// Returns `None` if and only if the expression is `#[cfg]`d out.
 +    fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
 +        let syntax_ptr = AstPtr::new(&expr);
 +        self.check_cfg(&expr)?;
 +
 +        Some(match expr {
 +            ast::Expr::IfExpr(e) => {
 +                let then_branch = self.collect_block_opt(e.then_branch());
 +
 +                let else_branch = e.else_branch().map(|b| match b {
 +                    ast::ElseBranch::Block(it) => self.collect_block(it),
 +                    ast::ElseBranch::IfExpr(elif) => {
 +                        let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
 +                        self.collect_expr(expr)
 +                    }
 +                });
 +
 +                let condition = self.collect_expr_opt(e.condition());
 +
 +                self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
 +            }
 +            ast::Expr::LetExpr(e) => {
 +                let pat = self.collect_pat_opt(e.pat());
 +                let expr = self.collect_expr_opt(e.expr());
 +                self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr)
 +            }
 +            ast::Expr::BlockExpr(e) => match e.modifier() {
 +                Some(ast::BlockModifier::Try(_)) => {
 +                    let body = self.collect_block(e);
 +                    self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
 +                }
 +                Some(ast::BlockModifier::Unsafe(_)) => {
 +                    let body = self.collect_block(e);
 +                    self.alloc_expr(Expr::Unsafe { body }, syntax_ptr)
 +                }
 +                // FIXME: we need to record these effects somewhere...
 +                Some(ast::BlockModifier::Label(label)) => {
 +                    let label = self.collect_label(label);
 +                    let res = self.collect_block(e);
 +                    match &mut self.body.exprs[res] {
 +                        Expr::Block { label: block_label, .. } => {
 +                            *block_label = Some(label);
 +                        }
 +                        _ => unreachable!(),
 +                    }
 +                    res
 +                }
 +                Some(ast::BlockModifier::Async(_)) => {
 +                    let body = self.collect_block(e);
 +                    self.alloc_expr(Expr::Async { body }, syntax_ptr)
 +                }
 +                Some(ast::BlockModifier::Const(_)) => {
 +                    let body = self.collect_block(e);
 +                    self.alloc_expr(Expr::Const { body }, syntax_ptr)
 +                }
 +                None => self.collect_block(e),
 +            },
 +            ast::Expr::LoopExpr(e) => {
 +                let label = e.label().map(|label| self.collect_label(label));
 +                let body = self.collect_block_opt(e.loop_body());
 +                self.alloc_expr(Expr::Loop { body, label }, syntax_ptr)
 +            }
 +            ast::Expr::WhileExpr(e) => {
 +                let label = e.label().map(|label| self.collect_label(label));
 +                let body = self.collect_block_opt(e.loop_body());
 +
 +                let condition = self.collect_expr_opt(e.condition());
 +
 +                self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr)
 +            }
 +            ast::Expr::ForExpr(e) => {
 +                let label = e.label().map(|label| self.collect_label(label));
 +                let iterable = self.collect_expr_opt(e.iterable());
 +                let pat = self.collect_pat_opt(e.pat());
 +                let body = self.collect_block_opt(e.loop_body());
 +                self.alloc_expr(Expr::For { iterable, pat, body, label }, syntax_ptr)
 +            }
 +            ast::Expr::CallExpr(e) => {
 +                let callee = self.collect_expr_opt(e.expr());
 +                let args = if let Some(arg_list) = e.arg_list() {
 +                    arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
 +                } else {
 +                    Box::default()
 +                };
 +                self.alloc_expr(
 +                    Expr::Call { callee, args, is_assignee_expr: self.is_lowering_assignee_expr },
 +                    syntax_ptr,
 +                )
 +            }
 +            ast::Expr::MethodCallExpr(e) => {
 +                let receiver = self.collect_expr_opt(e.receiver());
 +                let args = if let Some(arg_list) = e.arg_list() {
 +                    arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
 +                } else {
 +                    Box::default()
 +                };
 +                let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
 +                let generic_args = e
 +                    .generic_arg_list()
 +                    .and_then(|it| GenericArgs::from_ast(&self.ctx(), it))
 +                    .map(Box::new);
 +                self.alloc_expr(
 +                    Expr::MethodCall { receiver, method_name, args, generic_args },
 +                    syntax_ptr,
 +                )
 +            }
 +            ast::Expr::MatchExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                let arms = if let Some(match_arm_list) = e.match_arm_list() {
 +                    match_arm_list
 +                        .arms()
 +                        .filter_map(|arm| {
 +                            self.check_cfg(&arm).map(|()| MatchArm {
 +                                pat: self.collect_pat_opt(arm.pat()),
 +                                expr: self.collect_expr_opt(arm.expr()),
 +                                guard: arm
 +                                    .guard()
 +                                    .map(|guard| self.collect_expr_opt(guard.condition())),
 +                            })
 +                        })
 +                        .collect()
 +                } else {
 +                    Box::default()
 +                };
 +                self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
 +            }
 +            ast::Expr::PathExpr(e) => {
 +                let path = e
 +                    .path()
 +                    .and_then(|path| self.expander.parse_path(self.db, path))
 +                    .map(Expr::Path)
 +                    .unwrap_or(Expr::Missing);
 +                self.alloc_expr(path, syntax_ptr)
 +            }
 +            ast::Expr::ContinueExpr(e) => self.alloc_expr(
 +                Expr::Continue { label: e.lifetime().map(|l| Name::new_lifetime(&l)) },
 +                syntax_ptr,
 +            ),
 +            ast::Expr::BreakExpr(e) => {
 +                let expr = e.expr().map(|e| self.collect_expr(e));
 +                self.alloc_expr(
 +                    Expr::Break { expr, label: e.lifetime().map(|l| Name::new_lifetime(&l)) },
 +                    syntax_ptr,
 +                )
 +            }
 +            ast::Expr::ParenExpr(e) => {
 +                let inner = self.collect_expr_opt(e.expr());
 +                // make the paren expr point to the inner expression as well
 +                let src = self.expander.to_source(syntax_ptr);
 +                self.source_map.expr_map.insert(src, inner);
 +                inner
 +            }
 +            ast::Expr::ReturnExpr(e) => {
 +                let expr = e.expr().map(|e| self.collect_expr(e));
 +                self.alloc_expr(Expr::Return { expr }, syntax_ptr)
 +            }
 +            ast::Expr::YieldExpr(e) => {
 +                let expr = e.expr().map(|e| self.collect_expr(e));
 +                self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
 +            }
 +            ast::Expr::RecordExpr(e) => {
 +                let path =
 +                    e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
 +                let is_assignee_expr = self.is_lowering_assignee_expr;
 +                let record_lit = if let Some(nfl) = e.record_expr_field_list() {
 +                    let fields = nfl
 +                        .fields()
 +                        .filter_map(|field| {
 +                            self.check_cfg(&field)?;
 +
 +                            let name = field.field_name()?.as_name();
 +
 +                            let expr = match field.expr() {
 +                                Some(e) => self.collect_expr(e),
 +                                None => self.missing_expr(),
 +                            };
 +                            let src = self.expander.to_source(AstPtr::new(&field));
 +                            self.source_map.field_map.insert(src.clone(), expr);
 +                            self.source_map.field_map_back.insert(expr, src);
 +                            Some(RecordLitField { name, expr })
 +                        })
 +                        .collect();
 +                    let spread = nfl.spread().map(|s| self.collect_expr(s));
 +                    let ellipsis = nfl.dotdot_token().is_some();
 +                    Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr }
 +                } else {
 +                    Expr::RecordLit {
 +                        path,
 +                        fields: Box::default(),
 +                        spread: None,
 +                        ellipsis: false,
 +                        is_assignee_expr,
 +                    }
 +                };
 +
 +                self.alloc_expr(record_lit, syntax_ptr)
 +            }
 +            ast::Expr::FieldExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                let name = match e.field_access() {
 +                    Some(kind) => kind.as_name(),
 +                    _ => Name::missing(),
 +                };
 +                self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
 +            }
 +            ast::Expr::AwaitExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                self.alloc_expr(Expr::Await { expr }, syntax_ptr)
 +            }
 +            ast::Expr::TryExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                self.alloc_expr(Expr::Try { expr }, syntax_ptr)
 +            }
 +            ast::Expr::CastExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
 +                self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
 +            }
 +            ast::Expr::RefExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                let raw_tok = e.raw_token().is_some();
 +                let mutability = if raw_tok {
 +                    if e.mut_token().is_some() {
 +                        Mutability::Mut
 +                    } else if e.const_token().is_some() {
 +                        Mutability::Shared
 +                    } else {
 +                        unreachable!("parser only remaps to raw_token() if matching mutability token follows")
 +                    }
 +                } else {
 +                    Mutability::from_mutable(e.mut_token().is_some())
 +                };
 +                let rawness = Rawness::from_raw(raw_tok);
 +                self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)
 +            }
 +            ast::Expr::PrefixExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                match e.op_kind() {
 +                    Some(op) => self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr),
 +                    None => self.alloc_expr(Expr::Missing, syntax_ptr),
 +                }
 +            }
 +            ast::Expr::ClosureExpr(e) => {
 +                let mut args = Vec::new();
 +                let mut arg_types = Vec::new();
 +                if let Some(pl) = e.param_list() {
 +                    for param in pl.params() {
 +                        let pat = self.collect_pat_opt(param.pat());
 +                        let type_ref =
 +                            param.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
 +                        args.push(pat);
 +                        arg_types.push(type_ref);
 +                    }
 +                }
 +                let ret_type = e
 +                    .ret_type()
 +                    .and_then(|r| r.ty())
 +                    .map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
 +                let body = self.collect_expr_opt(e.body());
 +                self.alloc_expr(
 +                    Expr::Closure {
 +                        args: args.into(),
 +                        arg_types: arg_types.into(),
 +                        ret_type,
 +                        body,
 +                    },
 +                    syntax_ptr,
 +                )
 +            }
 +            ast::Expr::BinExpr(e) => {
 +                let op = e.op_kind();
 +                if let Some(ast::BinaryOp::Assignment { op: None }) = op {
 +                    self.is_lowering_assignee_expr = true;
 +                }
 +                let lhs = self.collect_expr_opt(e.lhs());
 +                self.is_lowering_assignee_expr = false;
 +                let rhs = self.collect_expr_opt(e.rhs());
 +                self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
 +            }
 +            ast::Expr::TupleExpr(e) => {
 +                let exprs = e.fields().map(|expr| self.collect_expr(expr)).collect();
 +                self.alloc_expr(
 +                    Expr::Tuple { exprs, is_assignee_expr: self.is_lowering_assignee_expr },
 +                    syntax_ptr,
 +                )
 +            }
 +            ast::Expr::BoxExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                self.alloc_expr(Expr::Box { expr }, syntax_ptr)
 +            }
 +
 +            ast::Expr::ArrayExpr(e) => {
 +                let kind = e.kind();
 +
 +                match kind {
 +                    ArrayExprKind::ElementList(e) => {
 +                        let elements = e.map(|expr| self.collect_expr(expr)).collect();
 +                        self.alloc_expr(
 +                            Expr::Array(Array::ElementList {
 +                                elements,
 +                                is_assignee_expr: self.is_lowering_assignee_expr,
 +                            }),
 +                            syntax_ptr,
 +                        )
 +                    }
 +                    ArrayExprKind::Repeat { initializer, repeat } => {
 +                        let initializer = self.collect_expr_opt(initializer);
 +                        let repeat = self.collect_expr_opt(repeat);
 +                        self.alloc_expr(
 +                            Expr::Array(Array::Repeat { initializer, repeat }),
 +                            syntax_ptr,
 +                        )
 +                    }
 +                }
 +            }
 +
 +            ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr),
 +            ast::Expr::IndexExpr(e) => {
 +                let base = self.collect_expr_opt(e.base());
 +                let index = self.collect_expr_opt(e.index());
 +                self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
 +            }
 +            ast::Expr::RangeExpr(e) => {
 +                let lhs = e.start().map(|lhs| self.collect_expr(lhs));
 +                let rhs = e.end().map(|rhs| self.collect_expr(rhs));
 +                match e.op_kind() {
 +                    Some(range_type) => {
 +                        self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)
 +                    }
 +                    None => self.alloc_expr(Expr::Missing, syntax_ptr),
 +                }
 +            }
 +            ast::Expr::MacroExpr(e) => {
 +                let e = e.macro_call()?;
 +                let macro_ptr = AstPtr::new(&e);
 +                let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
 +                    expansion.map(|it| this.collect_expr(it))
 +                });
 +                match id {
 +                    Some(id) => {
 +                        // Make the macro-call point to its expanded expression so we can query
 +                        // semantics on syntax pointers to the macro
 +                        let src = self.expander.to_source(syntax_ptr);
 +                        self.source_map.expr_map.insert(src, id);
 +                        id
 +                    }
 +                    None => self.alloc_expr(Expr::Missing, syntax_ptr),
 +                }
 +            }
 +            ast::Expr::MacroStmts(e) => {
++                let statements: Box<[_]> =
++                    e.statements().filter_map(|s| self.collect_stmt(s)).collect();
 +                let tail = e.expr().map(|e| self.collect_expr(e));
 +
++                if e.syntax().children().next().is_none() {
++                    // HACK: make sure that macros that expand to nothing aren't treated as a `()`
++                    // expression when used in block tail position.
++                    cov_mark::hit!(empty_macro_in_trailing_position_is_removed);
++                    return None;
++                }
++
 +                self.alloc_expr(Expr::MacroStmts { tail, statements }, syntax_ptr)
 +            }
 +            ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
 +        })
 +    }
 +
 +    fn collect_macro_call<F, T, U>(
 +        &mut self,
 +        mcall: ast::MacroCall,
 +        syntax_ptr: AstPtr<ast::MacroCall>,
 +        record_diagnostics: bool,
 +        collector: F,
 +    ) -> U
 +    where
 +        F: FnOnce(&mut Self, Option<T>) -> U,
 +        T: ast::AstNode,
 +    {
 +        // File containing the macro call. Expansion errors will be attached here.
 +        let outer_file = self.expander.current_file_id;
 +
 +        let macro_call_ptr = self.expander.to_source(AstPtr::new(&mcall));
 +        let res = self.expander.enter_expand(self.db, mcall);
 +
 +        let res = match res {
 +            Ok(res) => res,
 +            Err(UnresolvedMacro { path }) => {
 +                if record_diagnostics {
 +                    self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall {
 +                        node: InFile::new(outer_file, syntax_ptr),
 +                        path,
 +                    });
 +                }
 +                return collector(self, None);
 +            }
 +        };
 +
 +        if record_diagnostics {
 +            match &res.err {
 +                Some(ExpandError::UnresolvedProcMacro(krate)) => {
 +                    self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro {
 +                        node: InFile::new(outer_file, syntax_ptr),
 +                        krate: *krate,
 +                    });
 +                }
 +                Some(err) => {
 +                    self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
 +                        node: InFile::new(outer_file, syntax_ptr),
 +                        message: err.to_string(),
 +                    });
 +                }
 +                None => {}
 +            }
 +        }
 +
 +        match res.value {
 +            Some((mark, expansion)) => {
 +                self.source_map.expansions.insert(macro_call_ptr, self.expander.current_file_id);
 +                let prev_ast_id_map = mem::replace(
 +                    &mut self.ast_id_map,
 +                    self.db.ast_id_map(self.expander.current_file_id),
 +                );
 +
 +                let id = collector(self, Some(expansion));
 +                self.ast_id_map = prev_ast_id_map;
 +                self.expander.exit(self.db, mark);
 +                id
 +            }
 +            None => collector(self, None),
 +        }
 +    }
 +
 +    fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
 +        match expr {
 +            Some(expr) => self.collect_expr(expr),
 +            None => self.missing_expr(),
 +        }
 +    }
 +
 +    fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Statement> {
 +        match s {
 +            ast::Stmt::LetStmt(stmt) => {
 +                if self.check_cfg(&stmt).is_none() {
 +                    return None;
 +                }
 +                let pat = self.collect_pat_opt(stmt.pat());
 +                let type_ref =
 +                    stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
 +                let initializer = stmt.initializer().map(|e| self.collect_expr(e));
 +                let else_branch = stmt
 +                    .let_else()
 +                    .and_then(|let_else| let_else.block_expr())
 +                    .map(|block| self.collect_block(block));
 +                Some(Statement::Let { pat, type_ref, initializer, else_branch })
 +            }
 +            ast::Stmt::ExprStmt(stmt) => {
 +                let expr = stmt.expr();
 +                if let Some(expr) = &expr {
 +                    if self.check_cfg(expr).is_none() {
 +                        return None;
 +                    }
 +                }
 +                let has_semi = stmt.semicolon_token().is_some();
 +                // Note that macro could be expanded to multiple statements
 +                if let Some(expr @ ast::Expr::MacroExpr(mac)) = &expr {
 +                    let mac_call = mac.macro_call()?;
 +                    let syntax_ptr = AstPtr::new(expr);
 +                    let macro_ptr = AstPtr::new(&mac_call);
 +                    let stmt = self.collect_macro_call(
 +                        mac_call,
 +                        macro_ptr,
 +                        false,
 +                        |this, expansion: Option<ast::MacroStmts>| match expansion {
 +                            Some(expansion) => {
 +                                let statements = expansion
 +                                    .statements()
 +                                    .filter_map(|stmt| this.collect_stmt(stmt))
 +                                    .collect();
 +                                let tail = expansion.expr().map(|expr| this.collect_expr(expr));
 +
 +                                let mac_stmts = this.alloc_expr(
 +                                    Expr::MacroStmts { tail, statements },
 +                                    AstPtr::new(&ast::Expr::MacroStmts(expansion)),
 +                                );
 +
 +                                Some(mac_stmts)
 +                            }
 +                            None => None,
 +                        },
 +                    );
 +
 +                    let expr = match stmt {
 +                        Some(expr) => {
 +                            // Make the macro-call point to its expanded expression so we can query
 +                            // semantics on syntax pointers to the macro
 +                            let src = self.expander.to_source(syntax_ptr);
 +                            self.source_map.expr_map.insert(src, expr);
 +                            expr
 +                        }
 +                        None => self.alloc_expr(Expr::Missing, syntax_ptr),
 +                    };
 +                    Some(Statement::Expr { expr, has_semi })
 +                } else {
 +                    let expr = self.collect_expr_opt(expr);
 +                    Some(Statement::Expr { expr, has_semi })
 +                }
 +            }
 +            ast::Stmt::Item(_item) => None,
 +        }
 +    }
 +
 +    fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
 +        let file_local_id = self.ast_id_map.ast_id(&block);
 +        let ast_id = AstId::new(self.expander.current_file_id, file_local_id);
 +        let block_loc =
 +            BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) };
 +        let block_id = self.db.intern_block(block_loc);
 +
 +        let (module, def_map) = match self.db.block_def_map(block_id) {
 +            Some(def_map) => {
 +                self.body.block_scopes.push(block_id);
 +                (def_map.root(), def_map)
 +            }
 +            None => (self.expander.module, self.expander.def_map.clone()),
 +        };
 +        let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
 +        let prev_local_module = mem::replace(&mut self.expander.module, module);
 +
 +        let mut statements: Vec<_> =
 +            block.statements().filter_map(|s| self.collect_stmt(s)).collect();
 +        let tail = block.tail_expr().and_then(|e| self.maybe_collect_expr(e));
 +        let tail = tail.or_else(|| {
 +            let stmt = statements.pop()?;
 +            if let Statement::Expr { expr, has_semi: false } = stmt {
 +                return Some(expr);
 +            }
 +            statements.push(stmt);
 +            None
 +        });
 +
 +        let syntax_node_ptr = AstPtr::new(&block.into());
 +        let expr_id = self.alloc_expr(
 +            Expr::Block {
 +                id: block_id,
 +                statements: statements.into_boxed_slice(),
 +                tail,
 +                label: None,
 +            },
 +            syntax_node_ptr,
 +        );
 +
 +        self.expander.def_map = prev_def_map;
 +        self.expander.module = prev_local_module;
 +        expr_id
 +    }
 +
 +    fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
 +        match expr {
 +            Some(block) => self.collect_block(block),
 +            None => self.missing_expr(),
 +        }
 +    }
 +
 +    fn collect_label(&mut self, ast_label: ast::Label) -> LabelId {
 +        let label = Label {
 +            name: ast_label.lifetime().as_ref().map_or_else(Name::missing, Name::new_lifetime),
 +        };
 +        self.alloc_label(label, AstPtr::new(&ast_label))
 +    }
 +
 +    fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
 +        let pat_id = self.collect_pat_(pat);
 +        for (_, pats) in self.name_to_pat_grouping.drain() {
 +            let pats = Arc::<[_]>::from(pats);
 +            self.body.or_pats.extend(pats.iter().map(|&pat| (pat, pats.clone())));
 +        }
 +        self.is_lowering_inside_or_pat = false;
 +        pat_id
 +    }
 +
 +    fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
 +        match pat {
 +            Some(pat) => self.collect_pat(pat),
 +            None => self.missing_pat(),
 +        }
 +    }
 +
 +    fn collect_pat_(&mut self, pat: ast::Pat) -> PatId {
 +        let pattern = match &pat {
 +            ast::Pat::IdentPat(bp) => {
 +                let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
 +
 +                let key = self.is_lowering_inside_or_pat.then(|| name.clone());
 +                let annotation =
 +                    BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
 +                let subpat = bp.pat().map(|subpat| self.collect_pat_(subpat));
 +                let pattern = if annotation == BindingAnnotation::Unannotated && subpat.is_none() {
 +                    // This could also be a single-segment path pattern. To
 +                    // decide that, we need to try resolving the name.
 +                    let (resolved, _) = self.expander.def_map.resolve_path(
 +                        self.db,
 +                        self.expander.module,
 +                        &name.clone().into(),
 +                        BuiltinShadowMode::Other,
 +                    );
 +                    match resolved.take_values() {
 +                        Some(ModuleDefId::ConstId(_)) => Pat::Path(name.into()),
 +                        Some(ModuleDefId::EnumVariantId(_)) => {
 +                            // this is only really valid for unit variants, but
 +                            // shadowing other enum variants with a pattern is
 +                            // an error anyway
 +                            Pat::Path(name.into())
 +                        }
 +                        Some(ModuleDefId::AdtId(AdtId::StructId(s)))
 +                            if self.db.struct_data(s).variant_data.kind() != StructKind::Record =>
 +                        {
 +                            // Funnily enough, record structs *can* be shadowed
 +                            // by pattern bindings (but unit or tuple structs
 +                            // can't).
 +                            Pat::Path(name.into())
 +                        }
 +                        // shadowing statics is an error as well, so we just ignore that case here
 +                        _ => Pat::Bind { name, mode: annotation, subpat },
 +                    }
 +                } else {
 +                    Pat::Bind { name, mode: annotation, subpat }
 +                };
 +
 +                let ptr = AstPtr::new(&pat);
 +                let pat = self.alloc_pat(pattern, Either::Left(ptr));
 +                if let Some(key) = key {
 +                    self.name_to_pat_grouping.entry(key).or_default().push(pat);
 +                }
 +                return pat;
 +            }
 +            ast::Pat::TupleStructPat(p) => {
 +                let path =
 +                    p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
 +                let (args, ellipsis) = self.collect_tuple_pat(p.fields());
 +                Pat::TupleStruct { path, args, ellipsis }
 +            }
 +            ast::Pat::RefPat(p) => {
 +                let pat = self.collect_pat_opt(p.pat());
 +                let mutability = Mutability::from_mutable(p.mut_token().is_some());
 +                Pat::Ref { pat, mutability }
 +            }
 +            ast::Pat::PathPat(p) => {
 +                let path =
 +                    p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
 +                path.map(Pat::Path).unwrap_or(Pat::Missing)
 +            }
 +            ast::Pat::OrPat(p) => {
 +                self.is_lowering_inside_or_pat = true;
 +                let pats = p.pats().map(|p| self.collect_pat_(p)).collect();
 +                Pat::Or(pats)
 +            }
 +            ast::Pat::ParenPat(p) => return self.collect_pat_opt_(p.pat()),
 +            ast::Pat::TuplePat(p) => {
 +                let (args, ellipsis) = self.collect_tuple_pat(p.fields());
 +                Pat::Tuple { args, ellipsis }
 +            }
 +            ast::Pat::WildcardPat(_) => Pat::Wild,
 +            ast::Pat::RecordPat(p) => {
 +                let path =
 +                    p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
 +                let args = p
 +                    .record_pat_field_list()
 +                    .expect("every struct should have a field list")
 +                    .fields()
 +                    .filter_map(|f| {
 +                        let ast_pat = f.pat()?;
 +                        let pat = self.collect_pat_(ast_pat);
 +                        let name = f.field_name()?.as_name();
 +                        Some(RecordFieldPat { name, pat })
 +                    })
 +                    .collect();
 +
 +                let ellipsis = p
 +                    .record_pat_field_list()
 +                    .expect("every struct should have a field list")
 +                    .rest_pat()
 +                    .is_some();
 +
 +                Pat::Record { path, args, ellipsis }
 +            }
 +            ast::Pat::SlicePat(p) => {
 +                let SlicePatComponents { prefix, slice, suffix } = p.components();
 +
 +                // FIXME properly handle `RestPat`
 +                Pat::Slice {
 +                    prefix: prefix.into_iter().map(|p| self.collect_pat_(p)).collect(),
 +                    slice: slice.map(|p| self.collect_pat_(p)),
 +                    suffix: suffix.into_iter().map(|p| self.collect_pat_(p)).collect(),
 +                }
 +            }
 +            ast::Pat::LiteralPat(lit) => {
 +                if let Some(ast_lit) = lit.literal() {
 +                    let expr = Expr::Literal(ast_lit.kind().into());
 +                    let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
 +                    let expr_id = self.alloc_expr(expr, expr_ptr);
 +                    Pat::Lit(expr_id)
 +                } else {
 +                    Pat::Missing
 +                }
 +            }
 +            ast::Pat::RestPat(_) => {
 +                // `RestPat` requires special handling and should not be mapped
 +                // to a Pat. Here we are using `Pat::Missing` as a fallback for
 +                // when `RestPat` is mapped to `Pat`, which can easily happen
 +                // when the source code being analyzed has a malformed pattern
 +                // which includes `..` in a place where it isn't valid.
 +
 +                Pat::Missing
 +            }
 +            ast::Pat::BoxPat(boxpat) => {
 +                let inner = self.collect_pat_opt_(boxpat.pat());
 +                Pat::Box { inner }
 +            }
 +            ast::Pat::ConstBlockPat(const_block_pat) => {
 +                if let Some(expr) = const_block_pat.block_expr() {
 +                    let expr_id = self.collect_block(expr);
 +                    Pat::ConstBlock(expr_id)
 +                } else {
 +                    Pat::Missing
 +                }
 +            }
 +            ast::Pat::MacroPat(mac) => match mac.macro_call() {
 +                Some(call) => {
 +                    let macro_ptr = AstPtr::new(&call);
 +                    let src = self.expander.to_source(Either::Left(AstPtr::new(&pat)));
 +                    let pat =
 +                        self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
 +                            this.collect_pat_opt_(expanded_pat)
 +                        });
 +                    self.source_map.pat_map.insert(src, pat);
 +                    return pat;
 +                }
 +                None => Pat::Missing,
 +            },
 +            // FIXME: implement
 +            ast::Pat::RangePat(_) => Pat::Missing,
 +        };
 +        let ptr = AstPtr::new(&pat);
 +        self.alloc_pat(pattern, Either::Left(ptr))
 +    }
 +
 +    fn collect_pat_opt_(&mut self, pat: Option<ast::Pat>) -> PatId {
 +        match pat {
 +            Some(pat) => self.collect_pat_(pat),
 +            None => self.missing_pat(),
 +        }
 +    }
 +
 +    fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Box<[PatId]>, Option<usize>) {
 +        // Find the location of the `..`, if there is one. Note that we do not
 +        // consider the possibility of there being multiple `..` here.
 +        let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::RestPat(_)));
 +        // We want to skip the `..` pattern here, since we account for it above.
 +        let args = args
 +            .filter(|p| !matches!(p, ast::Pat::RestPat(_)))
 +            .map(|p| self.collect_pat_(p))
 +            .collect();
 +
 +        (args, ellipsis)
 +    }
 +
 +    /// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when
 +    /// not.
 +    fn check_cfg(&mut self, owner: &dyn ast::HasAttrs) -> Option<()> {
 +        match self.expander.parse_attrs(self.db, owner).cfg() {
 +            Some(cfg) => {
 +                if self.expander.cfg_options().check(&cfg) != Some(false) {
 +                    return Some(());
 +                }
 +
 +                self.source_map.diagnostics.push(BodyDiagnostic::InactiveCode {
 +                    node: InFile::new(
 +                        self.expander.current_file_id,
 +                        SyntaxNodePtr::new(owner.syntax()),
 +                    ),
 +                    cfg,
 +                    opts: self.expander.cfg_options().clone(),
 +                });
 +
 +                None
 +            }
 +            None => Some(()),
 +        }
 +    }
 +}
 +
 +impl From<ast::LiteralKind> for Literal {
 +    fn from(ast_lit_kind: ast::LiteralKind) -> Self {
 +        match ast_lit_kind {
 +            // FIXME: these should have actual values filled in, but unsure on perf impact
 +            LiteralKind::IntNumber(lit) => {
 +                if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
 +                    Literal::Float(
 +                        FloatTypeWrapper::new(lit.float_value().unwrap_or(Default::default())),
 +                        builtin,
 +                    )
 +                } else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinInt::from_suffix) {
 +                    Literal::Int(lit.value().unwrap_or(0) as i128, builtin)
 +                } else {
 +                    let builtin = lit.suffix().and_then(BuiltinUint::from_suffix);
 +                    Literal::Uint(lit.value().unwrap_or(0), builtin)
 +                }
 +            }
 +            LiteralKind::FloatNumber(lit) => {
 +                let ty = lit.suffix().and_then(BuiltinFloat::from_suffix);
 +                Literal::Float(FloatTypeWrapper::new(lit.value().unwrap_or(Default::default())), ty)
 +            }
 +            LiteralKind::ByteString(bs) => {
 +                let text = bs.value().map(Box::from).unwrap_or_else(Default::default);
 +                Literal::ByteString(text)
 +            }
 +            LiteralKind::String(s) => {
 +                let text = s.value().map(Box::from).unwrap_or_else(Default::default);
 +                Literal::String(text)
 +            }
 +            LiteralKind::Byte(b) => {
 +                Literal::Uint(b.value().unwrap_or_default() as u128, Some(BuiltinUint::U8))
 +            }
 +            LiteralKind::Char(c) => Literal::Char(c.value().unwrap_or_default()),
 +            LiteralKind::Bool(val) => Literal::Bool(val),
 +        }
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ddd476efe5c4d764dabd4ff597e732d902fb3dec
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,621 @@@
++//! A pretty-printer for HIR.
++
++use std::fmt::{self, Write};
++
++use crate::{
++    expr::{Array, BindingAnnotation, Literal, Statement},
++    pretty::{print_generic_args, print_path, print_type_ref},
++    type_ref::TypeRef,
++};
++
++use super::*;
++
++pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String {
++    let needs_semi;
++    let header = match owner {
++        DefWithBodyId::FunctionId(it) => {
++            needs_semi = false;
++            let item_tree_id = it.lookup(db).id;
++            format!("fn {}(…) ", item_tree_id.item_tree(db)[item_tree_id.value].name)
++        }
++        DefWithBodyId::StaticId(it) => {
++            needs_semi = true;
++            let item_tree_id = it.lookup(db).id;
++            format!("static {} = ", item_tree_id.item_tree(db)[item_tree_id.value].name)
++        }
++        DefWithBodyId::ConstId(it) => {
++            needs_semi = true;
++            let item_tree_id = it.lookup(db).id;
++            let name = match &item_tree_id.item_tree(db)[item_tree_id.value].name {
++                Some(name) => name.to_string(),
++                None => "_".to_string(),
++            };
++            format!("const {} = ", name)
++        }
++    };
++
++    let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false };
++    p.print_expr(body.body_expr);
++    if needs_semi {
++        p.buf.push(';');
++    }
++    p.buf
++}
++
++macro_rules! w {
++    ($dst:expr, $($arg:tt)*) => {
++        { let _ = write!($dst, $($arg)*); }
++    };
++}
++
++macro_rules! wln {
++    ($dst:expr) => {
++        { let _ = writeln!($dst); }
++    };
++    ($dst:expr, $($arg:tt)*) => {
++        { let _ = writeln!($dst, $($arg)*); }
++    };
++}
++
++struct Printer<'a> {
++    body: &'a Body,
++    buf: String,
++    indent_level: usize,
++    needs_indent: bool,
++}
++
++impl<'a> Write for Printer<'a> {
++    fn write_str(&mut self, s: &str) -> fmt::Result {
++        for line in s.split_inclusive('\n') {
++            if self.needs_indent {
++                match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() {
++                    Some('\n') | None => {}
++                    _ => self.buf.push('\n'),
++                }
++                self.buf.push_str(&"    ".repeat(self.indent_level));
++                self.needs_indent = false;
++            }
++
++            self.buf.push_str(line);
++            self.needs_indent = line.ends_with('\n');
++        }
++
++        Ok(())
++    }
++}
++
++impl<'a> Printer<'a> {
++    fn indented(&mut self, f: impl FnOnce(&mut Self)) {
++        self.indent_level += 1;
++        wln!(self);
++        f(self);
++        self.indent_level -= 1;
++        self.buf = self.buf.trim_end_matches('\n').to_string();
++    }
++
++    fn whitespace(&mut self) {
++        match self.buf.chars().next_back() {
++            None | Some('\n' | ' ') => {}
++            _ => self.buf.push(' '),
++        }
++    }
++
++    fn newline(&mut self) {
++        match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() {
++            Some('\n') | None => {}
++            _ => writeln!(self).unwrap(),
++        }
++    }
++
++    fn print_expr(&mut self, expr: ExprId) {
++        let expr = &self.body[expr];
++
++        match expr {
++            Expr::Missing => w!(self, "�"),
++            Expr::Underscore => w!(self, "_"),
++            Expr::Path(path) => self.print_path(path),
++            Expr::If { condition, then_branch, else_branch } => {
++                w!(self, "if ");
++                self.print_expr(*condition);
++                w!(self, " ");
++                self.print_expr(*then_branch);
++                if let Some(els) = *else_branch {
++                    w!(self, " else ");
++                    self.print_expr(els);
++                }
++            }
++            Expr::Let { pat, expr } => {
++                w!(self, "let ");
++                self.print_pat(*pat);
++                w!(self, " = ");
++                self.print_expr(*expr);
++            }
++            Expr::Loop { body, label } => {
++                if let Some(lbl) = label {
++                    w!(self, "{}: ", self.body[*lbl].name);
++                }
++                w!(self, "loop ");
++                self.print_expr(*body);
++            }
++            Expr::While { condition, body, label } => {
++                if let Some(lbl) = label {
++                    w!(self, "{}: ", self.body[*lbl].name);
++                }
++                w!(self, "while ");
++                self.print_expr(*condition);
++                self.print_expr(*body);
++            }
++            Expr::For { iterable, pat, body, label } => {
++                if let Some(lbl) = label {
++                    w!(self, "{}: ", self.body[*lbl].name);
++                }
++                w!(self, "for ");
++                self.print_pat(*pat);
++                w!(self, " in ");
++                self.print_expr(*iterable);
++                self.print_expr(*body);
++            }
++            Expr::Call { callee, args, is_assignee_expr: _ } => {
++                self.print_expr(*callee);
++                w!(self, "(");
++                if !args.is_empty() {
++                    self.indented(|p| {
++                        for arg in &**args {
++                            p.print_expr(*arg);
++                            wln!(p, ",");
++                        }
++                    });
++                }
++                w!(self, ")");
++            }
++            Expr::MethodCall { receiver, method_name, args, generic_args } => {
++                self.print_expr(*receiver);
++                w!(self, ".{}", method_name);
++                if let Some(args) = generic_args {
++                    w!(self, "::<");
++                    print_generic_args(args, self).unwrap();
++                    w!(self, ">");
++                }
++                w!(self, "(");
++                if !args.is_empty() {
++                    self.indented(|p| {
++                        for arg in &**args {
++                            p.print_expr(*arg);
++                            wln!(p, ",");
++                        }
++                    });
++                }
++                w!(self, ")");
++            }
++            Expr::Match { expr, arms } => {
++                w!(self, "match ");
++                self.print_expr(*expr);
++                w!(self, " {{");
++                self.indented(|p| {
++                    for arm in &**arms {
++                        p.print_pat(arm.pat);
++                        if let Some(guard) = arm.guard {
++                            w!(p, " if ");
++                            p.print_expr(guard);
++                        }
++                        w!(p, " => ");
++                        p.print_expr(arm.expr);
++                        wln!(p, ",");
++                    }
++                });
++                wln!(self, "}}");
++            }
++            Expr::Continue { label } => {
++                w!(self, "continue");
++                if let Some(label) = label {
++                    w!(self, " {}", label);
++                }
++            }
++            Expr::Break { expr, label } => {
++                w!(self, "break");
++                if let Some(label) = label {
++                    w!(self, " {}", label);
++                }
++                if let Some(expr) = expr {
++                    self.whitespace();
++                    self.print_expr(*expr);
++                }
++            }
++            Expr::Return { expr } => {
++                w!(self, "return");
++                if let Some(expr) = expr {
++                    self.whitespace();
++                    self.print_expr(*expr);
++                }
++            }
++            Expr::Yield { expr } => {
++                w!(self, "yield");
++                if let Some(expr) = expr {
++                    self.whitespace();
++                    self.print_expr(*expr);
++                }
++            }
++            Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => {
++                match path {
++                    Some(path) => self.print_path(path),
++                    None => w!(self, "�"),
++                }
++
++                w!(self, "{{");
++                self.indented(|p| {
++                    for field in &**fields {
++                        w!(p, "{}: ", field.name);
++                        p.print_expr(field.expr);
++                        wln!(p, ",");
++                    }
++                    if let Some(spread) = spread {
++                        w!(p, "..");
++                        p.print_expr(*spread);
++                        wln!(p);
++                    }
++                    if *ellipsis {
++                        wln!(p, "..");
++                    }
++                });
++                w!(self, "}}");
++            }
++            Expr::Field { expr, name } => {
++                self.print_expr(*expr);
++                w!(self, ".{}", name);
++            }
++            Expr::Await { expr } => {
++                self.print_expr(*expr);
++                w!(self, ".await");
++            }
++            Expr::Try { expr } => {
++                self.print_expr(*expr);
++                w!(self, "?");
++            }
++            Expr::TryBlock { body } => {
++                w!(self, "try ");
++                self.print_expr(*body);
++            }
++            Expr::Async { body } => {
++                w!(self, "async ");
++                self.print_expr(*body);
++            }
++            Expr::Const { body } => {
++                w!(self, "const ");
++                self.print_expr(*body);
++            }
++            Expr::Cast { expr, type_ref } => {
++                self.print_expr(*expr);
++                w!(self, " as ");
++                self.print_type_ref(type_ref);
++            }
++            Expr::Ref { expr, rawness, mutability } => {
++                w!(self, "&");
++                if rawness.is_raw() {
++                    w!(self, "raw ");
++                }
++                if mutability.is_mut() {
++                    w!(self, "mut ");
++                }
++                self.print_expr(*expr);
++            }
++            Expr::Box { expr } => {
++                w!(self, "box ");
++                self.print_expr(*expr);
++            }
++            Expr::UnaryOp { expr, op } => {
++                let op = match op {
++                    ast::UnaryOp::Deref => "*",
++                    ast::UnaryOp::Not => "!",
++                    ast::UnaryOp::Neg => "-",
++                };
++                w!(self, "{}", op);
++                self.print_expr(*expr);
++            }
++            Expr::BinaryOp { lhs, rhs, op } => {
++                let (bra, ket) = match op {
++                    None | Some(ast::BinaryOp::Assignment { .. }) => ("", ""),
++                    _ => ("(", ")"),
++                };
++                w!(self, "{}", bra);
++                self.print_expr(*lhs);
++                w!(self, "{} ", ket);
++                match op {
++                    Some(op) => w!(self, "{}", op),
++                    None => w!(self, "�"), // :)
++                }
++                w!(self, " {}", bra);
++                self.print_expr(*rhs);
++                w!(self, "{}", ket);
++            }
++            Expr::Range { lhs, rhs, range_type } => {
++                if let Some(lhs) = lhs {
++                    w!(self, "(");
++                    self.print_expr(*lhs);
++                    w!(self, ") ");
++                }
++                let range = match range_type {
++                    ast::RangeOp::Exclusive => "..",
++                    ast::RangeOp::Inclusive => "..=",
++                };
++                w!(self, "{}", range);
++                if let Some(rhs) = rhs {
++                    w!(self, "(");
++                    self.print_expr(*rhs);
++                    w!(self, ") ");
++                }
++            }
++            Expr::Index { base, index } => {
++                self.print_expr(*base);
++                w!(self, "[");
++                self.print_expr(*index);
++                w!(self, "]");
++            }
++            Expr::Closure { args, arg_types, ret_type, body } => {
++                w!(self, "|");
++                for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
++                    if i != 0 {
++                        w!(self, ", ");
++                    }
++                    self.print_pat(*pat);
++                    if let Some(ty) = ty {
++                        w!(self, ": ");
++                        self.print_type_ref(ty);
++                    }
++                }
++                w!(self, "|");
++                if let Some(ret_ty) = ret_type {
++                    w!(self, " -> ");
++                    self.print_type_ref(ret_ty);
++                }
++                self.whitespace();
++                self.print_expr(*body);
++            }
++            Expr::Tuple { exprs, is_assignee_expr: _ } => {
++                w!(self, "(");
++                for expr in exprs.iter() {
++                    self.print_expr(*expr);
++                    w!(self, ", ");
++                }
++                w!(self, ")");
++            }
++            Expr::Unsafe { body } => {
++                w!(self, "unsafe ");
++                self.print_expr(*body);
++            }
++            Expr::Array(arr) => {
++                w!(self, "[");
++                if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) {
++                    self.indented(|p| match arr {
++                        Array::ElementList { elements, is_assignee_expr: _ } => {
++                            for elem in elements.iter() {
++                                p.print_expr(*elem);
++                                w!(p, ", ");
++                            }
++                        }
++                        Array::Repeat { initializer, repeat } => {
++                            p.print_expr(*initializer);
++                            w!(p, "; ");
++                            p.print_expr(*repeat);
++                        }
++                    });
++                    self.newline();
++                }
++                w!(self, "]");
++            }
++            Expr::Literal(lit) => self.print_literal(lit),
++            Expr::Block { id: _, statements, tail, label } => {
++                self.whitespace();
++                if let Some(lbl) = label {
++                    w!(self, "{}: ", self.body[*lbl].name);
++                }
++                w!(self, "{{");
++                if !statements.is_empty() || tail.is_some() {
++                    self.indented(|p| {
++                        for stmt in &**statements {
++                            p.print_stmt(stmt);
++                        }
++                        if let Some(tail) = tail {
++                            p.print_expr(*tail);
++                        }
++                        p.newline();
++                    });
++                }
++                w!(self, "}}");
++            }
++            Expr::MacroStmts { statements, tail } => {
++                w!(self, "{{ // macro statements");
++                self.indented(|p| {
++                    for stmt in statements.iter() {
++                        p.print_stmt(stmt);
++                    }
++                    if let Some(tail) = tail {
++                        p.print_expr(*tail);
++                    }
++                });
++                self.newline();
++                w!(self, "}}");
++            }
++        }
++    }
++
++    fn print_pat(&mut self, pat: PatId) {
++        let pat = &self.body[pat];
++
++        match pat {
++            Pat::Missing => w!(self, "�"),
++            Pat::Wild => w!(self, "_"),
++            Pat::Tuple { args, ellipsis } => {
++                w!(self, "(");
++                for (i, pat) in args.iter().enumerate() {
++                    if i != 0 {
++                        w!(self, ", ");
++                    }
++                    if *ellipsis == Some(i) {
++                        w!(self, ".., ");
++                    }
++                    self.print_pat(*pat);
++                }
++                w!(self, ")");
++            }
++            Pat::Or(pats) => {
++                for (i, pat) in pats.iter().enumerate() {
++                    if i != 0 {
++                        w!(self, " | ");
++                    }
++                    self.print_pat(*pat);
++                }
++            }
++            Pat::Record { path, args, ellipsis } => {
++                match path {
++                    Some(path) => self.print_path(path),
++                    None => w!(self, "�"),
++                }
++
++                w!(self, " {{");
++                self.indented(|p| {
++                    for arg in args.iter() {
++                        w!(p, "{}: ", arg.name);
++                        p.print_pat(arg.pat);
++                        wln!(p, ",");
++                    }
++                    if *ellipsis {
++                        wln!(p, "..");
++                    }
++                });
++                w!(self, "}}");
++            }
++            Pat::Range { start, end } => {
++                self.print_expr(*start);
++                w!(self, "...");
++                self.print_expr(*end);
++            }
++            Pat::Slice { prefix, slice, suffix } => {
++                w!(self, "[");
++                for pat in prefix.iter() {
++                    self.print_pat(*pat);
++                    w!(self, ", ");
++                }
++                if let Some(pat) = slice {
++                    self.print_pat(*pat);
++                    w!(self, ", ");
++                }
++                for pat in suffix.iter() {
++                    self.print_pat(*pat);
++                    w!(self, ", ");
++                }
++                w!(self, "]");
++            }
++            Pat::Path(path) => self.print_path(path),
++            Pat::Lit(expr) => self.print_expr(*expr),
++            Pat::Bind { mode, name, subpat } => {
++                let mode = match mode {
++                    BindingAnnotation::Unannotated => "",
++                    BindingAnnotation::Mutable => "mut ",
++                    BindingAnnotation::Ref => "ref ",
++                    BindingAnnotation::RefMut => "ref mut ",
++                };
++                w!(self, "{}{}", mode, name);
++                if let Some(pat) = subpat {
++                    self.whitespace();
++                    self.print_pat(*pat);
++                }
++            }
++            Pat::TupleStruct { path, args, ellipsis } => {
++                match path {
++                    Some(path) => self.print_path(path),
++                    None => w!(self, "�"),
++                }
++                w!(self, "(");
++                for (i, arg) in args.iter().enumerate() {
++                    if i != 0 {
++                        w!(self, ", ");
++                    }
++                    if *ellipsis == Some(i) {
++                        w!(self, ", ..");
++                    }
++                    self.print_pat(*arg);
++                }
++                w!(self, ")");
++            }
++            Pat::Ref { pat, mutability } => {
++                w!(self, "&");
++                if mutability.is_mut() {
++                    w!(self, "mut ");
++                }
++                self.print_pat(*pat);
++            }
++            Pat::Box { inner } => {
++                w!(self, "box ");
++                self.print_pat(*inner);
++            }
++            Pat::ConstBlock(c) => {
++                w!(self, "const ");
++                self.print_expr(*c);
++            }
++        }
++    }
++
++    fn print_stmt(&mut self, stmt: &Statement) {
++        match stmt {
++            Statement::Let { pat, type_ref, initializer, else_branch } => {
++                w!(self, "let ");
++                self.print_pat(*pat);
++                if let Some(ty) = type_ref {
++                    w!(self, ": ");
++                    self.print_type_ref(ty);
++                }
++                if let Some(init) = initializer {
++                    w!(self, " = ");
++                    self.print_expr(*init);
++                }
++                if let Some(els) = else_branch {
++                    w!(self, " else ");
++                    self.print_expr(*els);
++                }
++                wln!(self, ";");
++            }
++            Statement::Expr { expr, has_semi } => {
++                self.print_expr(*expr);
++                if *has_semi {
++                    w!(self, ";");
++                }
++                wln!(self);
++            }
++        }
++    }
++
++    fn print_literal(&mut self, literal: &Literal) {
++        match literal {
++            Literal::String(it) => w!(self, "{:?}", it),
++            Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()),
++            Literal::Char(it) => w!(self, "'{}'", it.escape_debug()),
++            Literal::Bool(it) => w!(self, "{}", it),
++            Literal::Int(i, suffix) => {
++                w!(self, "{}", i);
++                if let Some(suffix) = suffix {
++                    w!(self, "{}", suffix);
++                }
++            }
++            Literal::Uint(i, suffix) => {
++                w!(self, "{}", i);
++                if let Some(suffix) = suffix {
++                    w!(self, "{}", suffix);
++                }
++            }
++            Literal::Float(f, suffix) => {
++                w!(self, "{}", f);
++                if let Some(suffix) = suffix {
++                    w!(self, "{}", suffix);
++                }
++            }
++        }
++    }
++
++    fn print_type_ref(&mut self, ty: &TypeRef) {
++        print_type_ref(ty, self).unwrap();
++    }
++
++    fn print_path(&mut self, path: &Path) {
++        print_path(path, self).unwrap();
++    }
++}
index 25a408036ff7d70f0968e6e420d71bf1ac096cab,0000000000000000000000000000000000000000..dd69c3ab4731519ff08c60b2696f0773906edcd7
mode 100644,000000..100644
--- /dev/null
@@@ -1,158 -1,0 +1,193 @@@
 +//! This module defines built-in types.
 +//!
 +//! A peculiarity of built-in types is that they are always available and are
 +//! not associated with any particular crate.
 +
 +use std::fmt;
 +
 +use hir_expand::name::{name, AsName, Name};
 +/// Different signed int types.
 +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 +pub enum BuiltinInt {
 +    Isize,
 +    I8,
 +    I16,
 +    I32,
 +    I64,
 +    I128,
 +}
 +
 +/// Different unsigned int types.
 +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 +pub enum BuiltinUint {
 +    Usize,
 +    U8,
 +    U16,
 +    U32,
 +    U64,
 +    U128,
 +}
 +
 +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 +pub enum BuiltinFloat {
 +    F32,
 +    F64,
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum BuiltinType {
 +    Char,
 +    Bool,
 +    Str,
 +    Int(BuiltinInt),
 +    Uint(BuiltinUint),
 +    Float(BuiltinFloat),
 +}
 +
 +impl BuiltinType {
 +    #[rustfmt::skip]
 +    pub const ALL: &'static [(Name, BuiltinType)] = &[
 +        (name![char], BuiltinType::Char),
 +        (name![bool], BuiltinType::Bool),
 +        (name![str],  BuiltinType::Str),
 +
 +        (name![isize], BuiltinType::Int(BuiltinInt::Isize)),
 +        (name![i8],    BuiltinType::Int(BuiltinInt::I8)),
 +        (name![i16],   BuiltinType::Int(BuiltinInt::I16)),
 +        (name![i32],   BuiltinType::Int(BuiltinInt::I32)),
 +        (name![i64],   BuiltinType::Int(BuiltinInt::I64)),
 +        (name![i128],  BuiltinType::Int(BuiltinInt::I128)),
 +
 +        (name![usize], BuiltinType::Uint(BuiltinUint::Usize)),
 +        (name![u8],    BuiltinType::Uint(BuiltinUint::U8)),
 +        (name![u16],   BuiltinType::Uint(BuiltinUint::U16)),
 +        (name![u32],   BuiltinType::Uint(BuiltinUint::U32)),
 +        (name![u64],   BuiltinType::Uint(BuiltinUint::U64)),
 +        (name![u128],  BuiltinType::Uint(BuiltinUint::U128)),
 +
 +        (name![f32], BuiltinType::Float(BuiltinFloat::F32)),
 +        (name![f64], BuiltinType::Float(BuiltinFloat::F64)),
 +    ];
 +
 +    pub fn by_name(name: &Name) -> Option<Self> {
 +        Self::ALL.iter().find_map(|(n, ty)| if n == name { Some(*ty) } else { None })
 +    }
 +}
 +
 +impl AsName for BuiltinType {
 +    fn as_name(&self) -> Name {
 +        match self {
 +            BuiltinType::Char => name![char],
 +            BuiltinType::Bool => name![bool],
 +            BuiltinType::Str => name![str],
 +            BuiltinType::Int(it) => match it {
 +                BuiltinInt::Isize => name![isize],
 +                BuiltinInt::I8 => name![i8],
 +                BuiltinInt::I16 => name![i16],
 +                BuiltinInt::I32 => name![i32],
 +                BuiltinInt::I64 => name![i64],
 +                BuiltinInt::I128 => name![i128],
 +            },
 +            BuiltinType::Uint(it) => match it {
 +                BuiltinUint::Usize => name![usize],
 +                BuiltinUint::U8 => name![u8],
 +                BuiltinUint::U16 => name![u16],
 +                BuiltinUint::U32 => name![u32],
 +                BuiltinUint::U64 => name![u64],
 +                BuiltinUint::U128 => name![u128],
 +            },
 +            BuiltinType::Float(it) => match it {
 +                BuiltinFloat::F32 => name![f32],
 +                BuiltinFloat::F64 => name![f64],
 +            },
 +        }
 +    }
 +}
 +
 +impl fmt::Display for BuiltinType {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        let type_name = self.as_name();
 +        type_name.fmt(f)
 +    }
 +}
 +
 +#[rustfmt::skip]
 +impl BuiltinInt {
 +    pub fn from_suffix(suffix: &str) -> Option<BuiltinInt> {
 +        let res = match suffix {
 +            "isize" => Self::Isize,
 +            "i8"    => Self::I8,
 +            "i16"   => Self::I16,
 +            "i32"   => Self::I32,
 +            "i64"   => Self::I64,
 +            "i128"  => Self::I128,
 +
 +            _ => return None,
 +        };
 +        Some(res)
 +    }
 +}
 +
 +#[rustfmt::skip]
 +impl BuiltinUint {
 +    pub fn from_suffix(suffix: &str) -> Option<BuiltinUint> {
 +        let res = match suffix {
 +            "usize" => Self::Usize,
 +            "u8"    => Self::U8,
 +            "u16"   => Self::U16,
 +            "u32"   => Self::U32,
 +            "u64"   => Self::U64,
 +            "u128"  => Self::U128,
 +
 +            _ => return None,
 +        };
 +        Some(res)
 +    }
 +}
 +
 +#[rustfmt::skip]
 +impl BuiltinFloat {
 +    pub fn from_suffix(suffix: &str) -> Option<BuiltinFloat> {
 +        let res = match suffix {
 +            "f32" => BuiltinFloat::F32,
 +            "f64" => BuiltinFloat::F64,
 +            _ => return None,
 +        };
 +        Some(res)
 +    }
 +}
++
++impl fmt::Display for BuiltinInt {
++    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
++        f.write_str(match self {
++            BuiltinInt::Isize => "isize",
++            BuiltinInt::I8 => "i8",
++            BuiltinInt::I16 => "i16",
++            BuiltinInt::I32 => "i32",
++            BuiltinInt::I64 => "i64",
++            BuiltinInt::I128 => "i128",
++        })
++    }
++}
++
++impl fmt::Display for BuiltinUint {
++    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
++        f.write_str(match self {
++            BuiltinUint::Usize => "usize",
++            BuiltinUint::U8 => "u8",
++            BuiltinUint::U16 => "u16",
++            BuiltinUint::U32 => "u32",
++            BuiltinUint::U64 => "u64",
++            BuiltinUint::U128 => "u128",
++        })
++    }
++}
++
++impl fmt::Display for BuiltinFloat {
++    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
++        f.write_str(match self {
++            BuiltinFloat::F32 => "f32",
++            BuiltinFloat::F64 => "f64",
++        })
++    }
++}
index c1b3788acb7d36d97a53272df8228458b139270e,0000000000000000000000000000000000000000..4381b43c258bfe90a9387e10f7608981090105f8
mode 100644,000000..100644
--- /dev/null
@@@ -1,444 -1,0 +1,446 @@@
- impl std::fmt::Display for FloatTypeWrapper {
-     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +//! This module describes hir-level representation of expressions.
 +//!
 +//! This representation is:
 +//!
 +//! 1. Identity-based. Each expression has an `id`, so we can distinguish
 +//!    between different `1` in `1 + 1`.
 +//! 2. Independent of syntax. Though syntactic provenance information can be
 +//!    attached separately via id-based side map.
 +//! 3. Unresolved. Paths are stored as sequences of names, and not as defs the
 +//!    names refer to.
 +//! 4. Desugared. There's no `if let`.
 +//!
 +//! See also a neighboring `body` module.
 +
++use std::fmt;
++
 +use hir_expand::name::Name;
 +use la_arena::{Idx, RawIdx};
 +
 +use crate::{
 +    builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
 +    intern::Interned,
 +    path::{GenericArgs, Path},
 +    type_ref::{Mutability, Rawness, TypeRef},
 +    BlockId,
 +};
 +
 +pub use syntax::ast::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp};
 +
 +pub type ExprId = Idx<Expr>;
 +
 +/// FIXME: this is a hacky function which should be removed
 +pub(crate) fn dummy_expr_id() -> ExprId {
 +    ExprId::from_raw(RawIdx::from(u32::MAX))
 +}
 +
 +pub type PatId = Idx<Pat>;
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct Label {
 +    pub name: Name,
 +}
 +pub type LabelId = Idx<Label>;
 +
 +// We convert float values into bits and that's how we don't need to deal with f32 and f64.
 +// For PartialEq, bits comparison should work, as ordering is not important
 +// https://github.com/rust-lang/rust-analyzer/issues/12380#issuecomment-1137284360
 +#[derive(Default, Debug, Clone, Eq, PartialEq)]
 +pub struct FloatTypeWrapper(u64);
 +
 +impl FloatTypeWrapper {
 +    pub fn new(value: f64) -> Self {
 +        Self(value.to_bits())
 +    }
 +}
 +
++impl fmt::Display for FloatTypeWrapper {
++    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        write!(f, "{:?}", f64::from_bits(self.0))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum Literal {
 +    String(Box<str>),
 +    ByteString(Box<[u8]>),
 +    Char(char),
 +    Bool(bool),
 +    Int(i128, Option<BuiltinInt>),
 +    Uint(u128, Option<BuiltinUint>),
 +    // Here we are using a wrapper around float because f32 and f64 do not implement Eq, so they
 +    // could not be used directly here, to understand how the wrapper works go to definition of
 +    // FloatTypeWrapper
 +    Float(FloatTypeWrapper, Option<BuiltinFloat>),
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum Expr {
 +    /// This is produced if the syntax tree does not have a required expression piece.
 +    Missing,
 +    Path(Path),
 +    If {
 +        condition: ExprId,
 +        then_branch: ExprId,
 +        else_branch: Option<ExprId>,
 +    },
 +    Let {
 +        pat: PatId,
 +        expr: ExprId,
 +    },
 +    Block {
 +        id: BlockId,
 +        statements: Box<[Statement]>,
 +        tail: Option<ExprId>,
 +        label: Option<LabelId>,
 +    },
 +    Loop {
 +        body: ExprId,
 +        label: Option<LabelId>,
 +    },
 +    While {
 +        condition: ExprId,
 +        body: ExprId,
 +        label: Option<LabelId>,
 +    },
 +    For {
 +        iterable: ExprId,
 +        pat: PatId,
 +        body: ExprId,
 +        label: Option<LabelId>,
 +    },
 +    Call {
 +        callee: ExprId,
 +        args: Box<[ExprId]>,
 +        is_assignee_expr: bool,
 +    },
 +    MethodCall {
 +        receiver: ExprId,
 +        method_name: Name,
 +        args: Box<[ExprId]>,
 +        generic_args: Option<Box<GenericArgs>>,
 +    },
 +    Match {
 +        expr: ExprId,
 +        arms: Box<[MatchArm]>,
 +    },
 +    Continue {
 +        label: Option<Name>,
 +    },
 +    Break {
 +        expr: Option<ExprId>,
 +        label: Option<Name>,
 +    },
 +    Return {
 +        expr: Option<ExprId>,
 +    },
 +    Yield {
 +        expr: Option<ExprId>,
 +    },
 +    RecordLit {
 +        path: Option<Box<Path>>,
 +        fields: Box<[RecordLitField]>,
 +        spread: Option<ExprId>,
 +        ellipsis: bool,
 +        is_assignee_expr: bool,
 +    },
 +    Field {
 +        expr: ExprId,
 +        name: Name,
 +    },
 +    Await {
 +        expr: ExprId,
 +    },
 +    Try {
 +        expr: ExprId,
 +    },
 +    TryBlock {
 +        body: ExprId,
 +    },
 +    Async {
 +        body: ExprId,
 +    },
 +    Const {
 +        body: ExprId,
 +    },
 +    Cast {
 +        expr: ExprId,
 +        type_ref: Interned<TypeRef>,
 +    },
 +    Ref {
 +        expr: ExprId,
 +        rawness: Rawness,
 +        mutability: Mutability,
 +    },
 +    Box {
 +        expr: ExprId,
 +    },
 +    UnaryOp {
 +        expr: ExprId,
 +        op: UnaryOp,
 +    },
 +    BinaryOp {
 +        lhs: ExprId,
 +        rhs: ExprId,
 +        op: Option<BinaryOp>,
 +    },
 +    Range {
 +        lhs: Option<ExprId>,
 +        rhs: Option<ExprId>,
 +        range_type: RangeOp,
 +    },
 +    Index {
 +        base: ExprId,
 +        index: ExprId,
 +    },
 +    Closure {
 +        args: Box<[PatId]>,
 +        arg_types: Box<[Option<Interned<TypeRef>>]>,
 +        ret_type: Option<Interned<TypeRef>>,
 +        body: ExprId,
 +    },
 +    Tuple {
 +        exprs: Box<[ExprId]>,
 +        is_assignee_expr: bool,
 +    },
 +    Unsafe {
 +        body: ExprId,
 +    },
 +    MacroStmts {
 +        statements: Box<[Statement]>,
 +        tail: Option<ExprId>,
 +    },
 +    Array(Array),
 +    Literal(Literal),
 +    Underscore,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum Array {
 +    ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
 +    Repeat { initializer: ExprId, repeat: ExprId },
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct MatchArm {
 +    pub pat: PatId,
 +    pub guard: Option<ExprId>,
 +    pub expr: ExprId,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct RecordLitField {
 +    pub name: Name,
 +    pub expr: ExprId,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum Statement {
 +    Let {
 +        pat: PatId,
 +        type_ref: Option<Interned<TypeRef>>,
 +        initializer: Option<ExprId>,
 +        else_branch: Option<ExprId>,
 +    },
 +    Expr {
 +        expr: ExprId,
 +        has_semi: bool,
 +    },
 +}
 +
 +impl Expr {
 +    pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
 +        match self {
 +            Expr::Missing => {}
 +            Expr::Path(_) => {}
 +            Expr::If { condition, then_branch, else_branch } => {
 +                f(*condition);
 +                f(*then_branch);
 +                if let &Some(else_branch) = else_branch {
 +                    f(else_branch);
 +                }
 +            }
 +            Expr::Let { expr, .. } => {
 +                f(*expr);
 +            }
 +            Expr::MacroStmts { tail, statements } | Expr::Block { statements, tail, .. } => {
 +                for stmt in statements.iter() {
 +                    match stmt {
 +                        Statement::Let { initializer, .. } => {
 +                            if let &Some(expr) = initializer {
 +                                f(expr);
 +                            }
 +                        }
 +                        Statement::Expr { expr: expression, .. } => f(*expression),
 +                    }
 +                }
 +                if let &Some(expr) = tail {
 +                    f(expr);
 +                }
 +            }
 +            Expr::TryBlock { body }
 +            | Expr::Unsafe { body }
 +            | Expr::Async { body }
 +            | Expr::Const { body } => f(*body),
 +            Expr::Loop { body, .. } => f(*body),
 +            Expr::While { condition, body, .. } => {
 +                f(*condition);
 +                f(*body);
 +            }
 +            Expr::For { iterable, body, .. } => {
 +                f(*iterable);
 +                f(*body);
 +            }
 +            Expr::Call { callee, args, .. } => {
 +                f(*callee);
 +                args.iter().copied().for_each(f);
 +            }
 +            Expr::MethodCall { receiver, args, .. } => {
 +                f(*receiver);
 +                args.iter().copied().for_each(f);
 +            }
 +            Expr::Match { expr, arms } => {
 +                f(*expr);
 +                arms.iter().map(|arm| arm.expr).for_each(f);
 +            }
 +            Expr::Continue { .. } => {}
 +            Expr::Break { expr, .. } | Expr::Return { expr } | Expr::Yield { expr } => {
 +                if let &Some(expr) = expr {
 +                    f(expr);
 +                }
 +            }
 +            Expr::RecordLit { fields, spread, .. } => {
 +                for field in fields.iter() {
 +                    f(field.expr);
 +                }
 +                if let &Some(expr) = spread {
 +                    f(expr);
 +                }
 +            }
 +            Expr::Closure { body, .. } => {
 +                f(*body);
 +            }
 +            Expr::BinaryOp { lhs, rhs, .. } => {
 +                f(*lhs);
 +                f(*rhs);
 +            }
 +            Expr::Range { lhs, rhs, .. } => {
 +                if let &Some(lhs) = rhs {
 +                    f(lhs);
 +                }
 +                if let &Some(rhs) = lhs {
 +                    f(rhs);
 +                }
 +            }
 +            Expr::Index { base, index } => {
 +                f(*base);
 +                f(*index);
 +            }
 +            Expr::Field { expr, .. }
 +            | Expr::Await { expr }
 +            | Expr::Try { expr }
 +            | Expr::Cast { expr, .. }
 +            | Expr::Ref { expr, .. }
 +            | Expr::UnaryOp { expr, .. }
 +            | Expr::Box { expr } => {
 +                f(*expr);
 +            }
 +            Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
 +            Expr::Array(a) => match a {
 +                Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
 +                Array::Repeat { initializer, repeat } => {
 +                    f(*initializer);
 +                    f(*repeat)
 +                }
 +            },
 +            Expr::Literal(_) => {}
 +            Expr::Underscore => {}
 +        }
 +    }
 +}
 +
 +/// Explicit binding annotations given in the HIR for a binding. Note
 +/// that this is not the final binding *mode* that we infer after type
 +/// inference.
 +#[derive(Clone, PartialEq, Eq, Debug, Copy)]
 +pub enum BindingAnnotation {
 +    /// No binding annotation given: this means that the final binding mode
 +    /// will depend on whether we have skipped through a `&` reference
 +    /// when matching. For example, the `x` in `Some(x)` will have binding
 +    /// mode `None`; if you do `let Some(x) = &Some(22)`, it will
 +    /// ultimately be inferred to be by-reference.
 +    Unannotated,
 +
 +    /// Annotated with `mut x` -- could be either ref or not, similar to `None`.
 +    Mutable,
 +
 +    /// Annotated as `ref`, like `ref x`
 +    Ref,
 +
 +    /// Annotated as `ref mut x`.
 +    RefMut,
 +}
 +
 +impl BindingAnnotation {
 +    pub fn new(is_mutable: bool, is_ref: bool) -> Self {
 +        match (is_mutable, is_ref) {
 +            (true, true) => BindingAnnotation::RefMut,
 +            (false, true) => BindingAnnotation::Ref,
 +            (true, false) => BindingAnnotation::Mutable,
 +            (false, false) => BindingAnnotation::Unannotated,
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct RecordFieldPat {
 +    pub name: Name,
 +    pub pat: PatId,
 +}
 +
 +/// Close relative to rustc's hir::PatKind
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum Pat {
 +    Missing,
 +    Wild,
 +    Tuple { args: Box<[PatId]>, ellipsis: Option<usize> },
 +    Or(Box<[PatId]>),
 +    Record { path: Option<Box<Path>>, args: Box<[RecordFieldPat]>, ellipsis: bool },
 +    Range { start: ExprId, end: ExprId },
 +    Slice { prefix: Box<[PatId]>, slice: Option<PatId>, suffix: Box<[PatId]> },
 +    Path(Box<Path>),
 +    Lit(ExprId),
 +    Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> },
 +    TupleStruct { path: Option<Box<Path>>, args: Box<[PatId]>, ellipsis: Option<usize> },
 +    Ref { pat: PatId, mutability: Mutability },
 +    Box { inner: PatId },
 +    ConstBlock(ExprId),
 +}
 +
 +impl Pat {
 +    pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) {
 +        match self {
 +            Pat::Range { .. }
 +            | Pat::Lit(..)
 +            | Pat::Path(..)
 +            | Pat::ConstBlock(..)
 +            | Pat::Wild
 +            | Pat::Missing => {}
 +            Pat::Bind { subpat, .. } => {
 +                subpat.iter().copied().for_each(f);
 +            }
 +            Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => {
 +                args.iter().copied().for_each(f);
 +            }
 +            Pat::Ref { pat, .. } => f(*pat),
 +            Pat::Slice { prefix, slice, suffix } => {
 +                let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
 +                total_iter.copied().for_each(f);
 +            }
 +            Pat::Record { args, .. } => {
 +                args.iter().map(|f| f.pat).for_each(f);
 +            }
 +            Pat::Box { inner } => f(*inner),
 +        }
 +    }
 +}
index f12d9a1273cc16bba0c6e67c3e0cbcbbeafb4bd9,0000000000000000000000000000000000000000..34dd817fd130ce555c85bff6de7544949664ceb6
mode 100644,000000..100644
--- /dev/null
@@@ -1,754 -1,0 +1,583 @@@
- use itertools::Itertools;
 +//! `ItemTree` debug printer.
 +
 +use std::fmt::{self, Write};
 +
-     path::GenericArg,
-     type_ref::TraitBoundModifier,
 +use crate::{
 +    attr::RawAttrs,
 +    generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
-         // FIXME: deduplicate with `HirDisplay` impl
-         match type_ref {
-             TypeRef::Never => w!(self, "!"),
-             TypeRef::Placeholder => w!(self, "_"),
-             TypeRef::Tuple(fields) => {
-                 w!(self, "(");
-                 for (i, field) in fields.iter().enumerate() {
-                     if i != 0 {
-                         w!(self, ", ");
-                     }
-                     self.print_type_ref(field);
-                 }
-                 w!(self, ")");
-             }
-             TypeRef::Path(path) => self.print_path(path),
-             TypeRef::RawPtr(pointee, mtbl) => {
-                 let mtbl = match mtbl {
-                     Mutability::Shared => "*const",
-                     Mutability::Mut => "*mut",
-                 };
-                 w!(self, "{} ", mtbl);
-                 self.print_type_ref(pointee);
-             }
-             TypeRef::Reference(pointee, lt, mtbl) => {
-                 let mtbl = match mtbl {
-                     Mutability::Shared => "",
-                     Mutability::Mut => "mut ",
-                 };
-                 w!(self, "&");
-                 if let Some(lt) = lt {
-                     w!(self, "{} ", lt.name);
-                 }
-                 w!(self, "{}", mtbl);
-                 self.print_type_ref(pointee);
-             }
-             TypeRef::Array(elem, len) => {
-                 w!(self, "[");
-                 self.print_type_ref(elem);
-                 w!(self, "; {}]", len);
-             }
-             TypeRef::Slice(elem) => {
-                 w!(self, "[");
-                 self.print_type_ref(elem);
-                 w!(self, "]");
-             }
-             TypeRef::Fn(args_and_ret, varargs) => {
-                 let ((_, return_type), args) =
-                     args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
-                 w!(self, "fn(");
-                 for (i, (_, typeref)) in args.iter().enumerate() {
-                     if i != 0 {
-                         w!(self, ", ");
-                     }
-                     self.print_type_ref(typeref);
-                 }
-                 if *varargs {
-                     if !args.is_empty() {
-                         w!(self, ", ");
-                     }
-                     w!(self, "...");
-                 }
-                 w!(self, ") -> ");
-                 self.print_type_ref(return_type);
-             }
-             TypeRef::Macro(_ast_id) => {
-                 w!(self, "<macro>");
-             }
-             TypeRef::Error => w!(self, "{{unknown}}"),
-             TypeRef::ImplTrait(bounds) => {
-                 w!(self, "impl ");
-                 self.print_type_bounds(bounds);
-             }
-             TypeRef::DynTrait(bounds) => {
-                 w!(self, "dyn ");
-                 self.print_type_bounds(bounds);
-             }
-         }
++    pretty::{print_path, print_type_bounds, print_type_ref},
 +    visibility::RawVisibility,
 +};
 +
 +use super::*;
 +
 +pub(super) fn print_item_tree(tree: &ItemTree) -> String {
 +    let mut p = Printer { tree, buf: String::new(), indent_level: 0, needs_indent: true };
 +
 +    if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
 +        p.print_attrs(attrs, true);
 +    }
 +    p.blank();
 +
 +    for item in tree.top_level_items() {
 +        p.print_mod_item(*item);
 +    }
 +
 +    let mut s = p.buf.trim_end_matches('\n').to_string();
 +    s.push('\n');
 +    s
 +}
 +
 +macro_rules! w {
 +    ($dst:expr, $($arg:tt)*) => {
 +        { let _ = write!($dst, $($arg)*); }
 +    };
 +}
 +
 +macro_rules! wln {
 +    ($dst:expr) => {
 +        { let _ = writeln!($dst); }
 +    };
 +    ($dst:expr, $($arg:tt)*) => {
 +        { let _ = writeln!($dst, $($arg)*); }
 +    };
 +}
 +
 +struct Printer<'a> {
 +    tree: &'a ItemTree,
 +    buf: String,
 +    indent_level: usize,
 +    needs_indent: bool,
 +}
 +
 +impl<'a> Printer<'a> {
 +    fn indented(&mut self, f: impl FnOnce(&mut Self)) {
 +        self.indent_level += 1;
 +        wln!(self);
 +        f(self);
 +        self.indent_level -= 1;
 +        self.buf = self.buf.trim_end_matches('\n').to_string();
 +    }
 +
 +    /// Ensures that a blank line is output before the next text.
 +    fn blank(&mut self) {
 +        let mut iter = self.buf.chars().rev().fuse();
 +        match (iter.next(), iter.next()) {
 +            (Some('\n'), Some('\n') | None) | (None, None) => {}
 +            (Some('\n'), Some(_)) => {
 +                self.buf.push('\n');
 +            }
 +            (Some(_), _) => {
 +                self.buf.push('\n');
 +                self.buf.push('\n');
 +            }
 +            (None, Some(_)) => unreachable!(),
 +        }
 +    }
 +
 +    fn whitespace(&mut self) {
 +        match self.buf.chars().next_back() {
 +            None | Some('\n' | ' ') => {}
 +            _ => self.buf.push(' '),
 +        }
 +    }
 +
 +    fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool) {
 +        let inner = if inner { "!" } else { "" };
 +        for attr in &**attrs {
 +            wln!(
 +                self,
 +                "#{}[{}{}]",
 +                inner,
 +                attr.path,
 +                attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(),
 +            );
 +        }
 +    }
 +
 +    fn print_attrs_of(&mut self, of: impl Into<AttrOwner>) {
 +        if let Some(attrs) = self.tree.attrs.get(&of.into()) {
 +            self.print_attrs(attrs, false);
 +        }
 +    }
 +
 +    fn print_visibility(&mut self, vis: RawVisibilityId) {
 +        match &self.tree[vis] {
 +            RawVisibility::Module(path) => w!(self, "pub({}) ", path),
 +            RawVisibility::Public => w!(self, "pub "),
 +        };
 +    }
 +
 +    fn print_fields(&mut self, fields: &Fields) {
 +        match fields {
 +            Fields::Record(fields) => {
 +                self.whitespace();
 +                w!(self, "{{");
 +                self.indented(|this| {
 +                    for field in fields.clone() {
 +                        let Field { visibility, name, type_ref } = &this.tree[field];
 +                        this.print_attrs_of(field);
 +                        this.print_visibility(*visibility);
 +                        w!(this, "{}: ", name);
 +                        this.print_type_ref(type_ref);
 +                        wln!(this, ",");
 +                    }
 +                });
 +                w!(self, "}}");
 +            }
 +            Fields::Tuple(fields) => {
 +                w!(self, "(");
 +                self.indented(|this| {
 +                    for field in fields.clone() {
 +                        let Field { visibility, name, type_ref } = &this.tree[field];
 +                        this.print_attrs_of(field);
 +                        this.print_visibility(*visibility);
 +                        w!(this, "{}: ", name);
 +                        this.print_type_ref(type_ref);
 +                        wln!(this, ",");
 +                    }
 +                });
 +                w!(self, ")");
 +            }
 +            Fields::Unit => {}
 +        }
 +    }
 +
 +    fn print_fields_and_where_clause(&mut self, fields: &Fields, params: &GenericParams) {
 +        match fields {
 +            Fields::Record(_) => {
 +                if self.print_where_clause(params) {
 +                    wln!(self);
 +                }
 +                self.print_fields(fields);
 +            }
 +            Fields::Unit => {
 +                self.print_where_clause(params);
 +                self.print_fields(fields);
 +            }
 +            Fields::Tuple(_) => {
 +                self.print_fields(fields);
 +                self.print_where_clause(params);
 +            }
 +        }
 +    }
 +
 +    fn print_use_tree(&mut self, use_tree: &UseTree) {
 +        match &use_tree.kind {
 +            UseTreeKind::Single { path, alias } => {
 +                w!(self, "{}", path);
 +                if let Some(alias) = alias {
 +                    w!(self, " as {}", alias);
 +                }
 +            }
 +            UseTreeKind::Glob { path } => {
 +                if let Some(path) = path {
 +                    w!(self, "{}::", path);
 +                }
 +                w!(self, "*");
 +            }
 +            UseTreeKind::Prefixed { prefix, list } => {
 +                if let Some(prefix) = prefix {
 +                    w!(self, "{}::", prefix);
 +                }
 +                w!(self, "{{");
 +                for (i, tree) in list.iter().enumerate() {
 +                    if i != 0 {
 +                        w!(self, ", ");
 +                    }
 +                    self.print_use_tree(tree);
 +                }
 +                w!(self, "}}");
 +            }
 +        }
 +    }
 +
 +    fn print_mod_item(&mut self, item: ModItem) {
 +        self.print_attrs_of(item);
 +
 +        match item {
 +            ModItem::Import(it) => {
 +                let Import { visibility, use_tree, ast_id: _ } = &self.tree[it];
 +                self.print_visibility(*visibility);
 +                w!(self, "use ");
 +                self.print_use_tree(use_tree);
 +                wln!(self, ";");
 +            }
 +            ModItem::ExternCrate(it) => {
 +                let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it];
 +                self.print_visibility(*visibility);
 +                w!(self, "extern crate {}", name);
 +                if let Some(alias) = alias {
 +                    w!(self, " as {}", alias);
 +                }
 +                wln!(self, ";");
 +            }
 +            ModItem::ExternBlock(it) => {
 +                let ExternBlock { abi, ast_id: _, children } = &self.tree[it];
 +                w!(self, "extern ");
 +                if let Some(abi) = abi {
 +                    w!(self, "\"{}\" ", abi);
 +                }
 +                w!(self, "{{");
 +                self.indented(|this| {
 +                    for child in &**children {
 +                        this.print_mod_item(*child);
 +                    }
 +                });
 +                wln!(self, "}}");
 +            }
 +            ModItem::Function(it) => {
 +                let Function {
 +                    name,
 +                    visibility,
 +                    explicit_generic_params,
 +                    abi,
 +                    params,
 +                    ret_type,
 +                    async_ret_type: _,
 +                    ast_id: _,
 +                    flags,
 +                } = &self.tree[it];
 +                self.print_visibility(*visibility);
 +                if flags.contains(FnFlags::HAS_DEFAULT_KW) {
 +                    w!(self, "default ");
 +                }
 +                if flags.contains(FnFlags::HAS_CONST_KW) {
 +                    w!(self, "const ");
 +                }
 +                if flags.contains(FnFlags::HAS_ASYNC_KW) {
 +                    w!(self, "async ");
 +                }
 +                if flags.contains(FnFlags::HAS_UNSAFE_KW) {
 +                    w!(self, "unsafe ");
 +                }
 +                if let Some(abi) = abi {
 +                    w!(self, "extern \"{}\" ", abi);
 +                }
 +                w!(self, "fn {}", name);
 +                self.print_generic_params(explicit_generic_params);
 +                w!(self, "(");
 +                if !params.is_empty() {
 +                    self.indented(|this| {
 +                        for (i, param) in params.clone().enumerate() {
 +                            this.print_attrs_of(param);
 +                            match &this.tree[param] {
 +                                Param::Normal(name, ty) => {
 +                                    match name {
 +                                        Some(name) => w!(this, "{}: ", name),
 +                                        None => w!(this, "_: "),
 +                                    }
 +                                    this.print_type_ref(ty);
 +                                    w!(this, ",");
 +                                    if flags.contains(FnFlags::HAS_SELF_PARAM) && i == 0 {
 +                                        wln!(this, "  // self");
 +                                    } else {
 +                                        wln!(this);
 +                                    }
 +                                }
 +                                Param::Varargs => {
 +                                    wln!(this, "...");
 +                                }
 +                            };
 +                        }
 +                    });
 +                }
 +                w!(self, ") -> ");
 +                self.print_type_ref(ret_type);
 +                self.print_where_clause(explicit_generic_params);
 +                if flags.contains(FnFlags::HAS_BODY) {
 +                    wln!(self, " {{ ... }}");
 +                } else {
 +                    wln!(self, ";");
 +                }
 +            }
 +            ModItem::Struct(it) => {
 +                let Struct { visibility, name, fields, generic_params, ast_id: _ } = &self.tree[it];
 +                self.print_visibility(*visibility);
 +                w!(self, "struct {}", name);
 +                self.print_generic_params(generic_params);
 +                self.print_fields_and_where_clause(fields, generic_params);
 +                if matches!(fields, Fields::Record(_)) {
 +                    wln!(self);
 +                } else {
 +                    wln!(self, ";");
 +                }
 +            }
 +            ModItem::Union(it) => {
 +                let Union { name, visibility, fields, generic_params, ast_id: _ } = &self.tree[it];
 +                self.print_visibility(*visibility);
 +                w!(self, "union {}", name);
 +                self.print_generic_params(generic_params);
 +                self.print_fields_and_where_clause(fields, generic_params);
 +                if matches!(fields, Fields::Record(_)) {
 +                    wln!(self);
 +                } else {
 +                    wln!(self, ";");
 +                }
 +            }
 +            ModItem::Enum(it) => {
 +                let Enum { name, visibility, variants, generic_params, ast_id: _ } = &self.tree[it];
 +                self.print_visibility(*visibility);
 +                w!(self, "enum {}", name);
 +                self.print_generic_params(generic_params);
 +                self.print_where_clause_and_opening_brace(generic_params);
 +                self.indented(|this| {
 +                    for variant in variants.clone() {
 +                        let Variant { name, fields } = &this.tree[variant];
 +                        this.print_attrs_of(variant);
 +                        w!(this, "{}", name);
 +                        this.print_fields(fields);
 +                        wln!(this, ",");
 +                    }
 +                });
 +                wln!(self, "}}");
 +            }
 +            ModItem::Const(it) => {
 +                let Const { name, visibility, type_ref, ast_id: _ } = &self.tree[it];
 +                self.print_visibility(*visibility);
 +                w!(self, "const ");
 +                match name {
 +                    Some(name) => w!(self, "{}", name),
 +                    None => w!(self, "_"),
 +                }
 +                w!(self, ": ");
 +                self.print_type_ref(type_ref);
 +                wln!(self, " = _;");
 +            }
 +            ModItem::Static(it) => {
 +                let Static { name, visibility, mutable, type_ref, ast_id: _ } = &self.tree[it];
 +                self.print_visibility(*visibility);
 +                w!(self, "static ");
 +                if *mutable {
 +                    w!(self, "mut ");
 +                }
 +                w!(self, "{}: ", name);
 +                self.print_type_ref(type_ref);
 +                w!(self, " = _;");
 +                wln!(self);
 +            }
 +            ModItem::Trait(it) => {
 +                let Trait {
 +                    name,
 +                    visibility,
 +                    is_auto,
 +                    is_unsafe,
 +                    items,
 +                    generic_params,
 +                    ast_id: _,
 +                } = &self.tree[it];
 +                self.print_visibility(*visibility);
 +                if *is_unsafe {
 +                    w!(self, "unsafe ");
 +                }
 +                if *is_auto {
 +                    w!(self, "auto ");
 +                }
 +                w!(self, "trait {}", name);
 +                self.print_generic_params(generic_params);
 +                self.print_where_clause_and_opening_brace(generic_params);
 +                self.indented(|this| {
 +                    for item in &**items {
 +                        this.print_mod_item((*item).into());
 +                    }
 +                });
 +                wln!(self, "}}");
 +            }
 +            ModItem::Impl(it) => {
 +                let Impl { target_trait, self_ty, is_negative, items, generic_params, ast_id: _ } =
 +                    &self.tree[it];
 +                w!(self, "impl");
 +                self.print_generic_params(generic_params);
 +                w!(self, " ");
 +                if *is_negative {
 +                    w!(self, "!");
 +                }
 +                if let Some(tr) = target_trait {
 +                    self.print_path(&tr.path);
 +                    w!(self, " for ");
 +                }
 +                self.print_type_ref(self_ty);
 +                self.print_where_clause_and_opening_brace(generic_params);
 +                self.indented(|this| {
 +                    for item in &**items {
 +                        this.print_mod_item((*item).into());
 +                    }
 +                });
 +                wln!(self, "}}");
 +            }
 +            ModItem::TypeAlias(it) => {
 +                let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id: _ } =
 +                    &self.tree[it];
 +                self.print_visibility(*visibility);
 +                w!(self, "type {}", name);
 +                self.print_generic_params(generic_params);
 +                if !bounds.is_empty() {
 +                    w!(self, ": ");
 +                    self.print_type_bounds(bounds);
 +                }
 +                if let Some(ty) = type_ref {
 +                    w!(self, " = ");
 +                    self.print_type_ref(ty);
 +                }
 +                self.print_where_clause(generic_params);
 +                w!(self, ";");
 +                wln!(self);
 +            }
 +            ModItem::Mod(it) => {
 +                let Mod { name, visibility, kind, ast_id: _ } = &self.tree[it];
 +                self.print_visibility(*visibility);
 +                w!(self, "mod {}", name);
 +                match kind {
 +                    ModKind::Inline { items } => {
 +                        w!(self, " {{");
 +                        self.indented(|this| {
 +                            for item in &**items {
 +                                this.print_mod_item(*item);
 +                            }
 +                        });
 +                        wln!(self, "}}");
 +                    }
 +                    ModKind::Outline => {
 +                        wln!(self, ";");
 +                    }
 +                }
 +            }
 +            ModItem::MacroCall(it) => {
 +                let MacroCall { path, ast_id: _, expand_to: _ } = &self.tree[it];
 +                wln!(self, "{}!(...);", path);
 +            }
 +            ModItem::MacroRules(it) => {
 +                let MacroRules { name, ast_id: _ } = &self.tree[it];
 +                wln!(self, "macro_rules! {} {{ ... }}", name);
 +            }
 +            ModItem::MacroDef(it) => {
 +                let MacroDef { name, visibility, ast_id: _ } = &self.tree[it];
 +                self.print_visibility(*visibility);
 +                wln!(self, "macro {} {{ ... }}", name);
 +            }
 +        }
 +
 +        self.blank();
 +    }
 +
 +    fn print_type_ref(&mut self, type_ref: &TypeRef) {
-         for (i, bound) in bounds.iter().enumerate() {
-             if i != 0 {
-                 w!(self, " + ");
-             }
-             match bound.as_ref() {
-                 TypeBound::Path(path, modifier) => {
-                     match modifier {
-                         TraitBoundModifier::None => (),
-                         TraitBoundModifier::Maybe => w!(self, "?"),
-                     }
-                     self.print_path(path)
-                 }
-                 TypeBound::ForLifetime(lifetimes, path) => {
-                     w!(self, "for<{}> ", lifetimes.iter().format(", "));
-                     self.print_path(path);
-                 }
-                 TypeBound::Lifetime(lt) => w!(self, "{}", lt.name),
-                 TypeBound::Error => w!(self, "{{unknown}}"),
-             }
-         }
++        print_type_ref(type_ref, self).unwrap();
 +    }
 +
 +    fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
-         match path.type_anchor() {
-             Some(anchor) => {
-                 w!(self, "<");
-                 self.print_type_ref(anchor);
-                 w!(self, ">::");
-             }
-             None => match path.kind() {
-                 PathKind::Plain => {}
-                 PathKind::Super(0) => w!(self, "self::"),
-                 PathKind::Super(n) => {
-                     for _ in 0..*n {
-                         w!(self, "super::");
-                     }
-                 }
-                 PathKind::Crate => w!(self, "crate::"),
-                 PathKind::Abs => w!(self, "::"),
-                 PathKind::DollarCrate(_) => w!(self, "$crate::"),
-             },
-         }
-         for (i, segment) in path.segments().iter().enumerate() {
-             if i != 0 {
-                 w!(self, "::");
-             }
-             w!(self, "{}", segment.name);
-             if let Some(generics) = segment.args_and_bindings {
-                 // NB: these are all in type position, so `::<` turbofish syntax is not necessary
-                 w!(self, "<");
-                 let mut first = true;
-                 let args = if generics.has_self_type {
-                     let (self_ty, args) = generics.args.split_first().unwrap();
-                     w!(self, "Self=");
-                     self.print_generic_arg(self_ty);
-                     first = false;
-                     args
-                 } else {
-                     &generics.args
-                 };
-                 for arg in args {
-                     if !first {
-                         w!(self, ", ");
-                     }
-                     first = false;
-                     self.print_generic_arg(arg);
-                 }
-                 for binding in &generics.bindings {
-                     if !first {
-                         w!(self, ", ");
-                     }
-                     first = false;
-                     w!(self, "{}", binding.name);
-                     if !binding.bounds.is_empty() {
-                         w!(self, ": ");
-                         self.print_type_bounds(&binding.bounds);
-                     }
-                     if let Some(ty) = &binding.type_ref {
-                         w!(self, " = ");
-                         self.print_type_ref(ty);
-                     }
-                 }
-                 w!(self, ">");
-             }
-         }
-     }
-     fn print_generic_arg(&mut self, arg: &GenericArg) {
-         match arg {
-             GenericArg::Type(ty) => self.print_type_ref(ty),
-             GenericArg::Const(c) => w!(self, "{}", c),
-             GenericArg::Lifetime(lt) => w!(self, "{}", lt.name),
-         }
++        print_type_bounds(bounds, self).unwrap();
 +    }
 +
 +    fn print_path(&mut self, path: &Path) {
++        print_path(path, self).unwrap();
 +    }
 +
 +    fn print_generic_params(&mut self, params: &GenericParams) {
 +        if params.type_or_consts.is_empty() && params.lifetimes.is_empty() {
 +            return;
 +        }
 +
 +        w!(self, "<");
 +        let mut first = true;
 +        for (_, lt) in params.lifetimes.iter() {
 +            if !first {
 +                w!(self, ", ");
 +            }
 +            first = false;
 +            w!(self, "{}", lt.name);
 +        }
 +        for (idx, x) in params.type_or_consts.iter() {
 +            if !first {
 +                w!(self, ", ");
 +            }
 +            first = false;
 +            match x {
 +                TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
 +                    Some(name) => w!(self, "{}", name),
 +                    None => w!(self, "_anon_{}", idx.into_raw()),
 +                },
 +                TypeOrConstParamData::ConstParamData(konst) => {
 +                    w!(self, "const {}: ", konst.name);
 +                    self.print_type_ref(&konst.ty);
 +                }
 +            }
 +        }
 +        w!(self, ">");
 +    }
 +
 +    fn print_where_clause_and_opening_brace(&mut self, params: &GenericParams) {
 +        if self.print_where_clause(params) {
 +            w!(self, "\n{{");
 +        } else {
 +            self.whitespace();
 +            w!(self, "{{");
 +        }
 +    }
 +
 +    fn print_where_clause(&mut self, params: &GenericParams) -> bool {
 +        if params.where_predicates.is_empty() {
 +            return false;
 +        }
 +
 +        w!(self, "\nwhere");
 +        self.indented(|this| {
 +            for (i, pred) in params.where_predicates.iter().enumerate() {
 +                if i != 0 {
 +                    wln!(this, ",");
 +                }
 +
 +                let (target, bound) = match pred {
 +                    WherePredicate::TypeBound { target, bound } => (target, bound),
 +                    WherePredicate::Lifetime { target, bound } => {
 +                        wln!(this, "{}: {},", target.name, bound.name);
 +                        continue;
 +                    }
 +                    WherePredicate::ForLifetime { lifetimes, target, bound } => {
 +                        w!(this, "for<");
 +                        for (i, lt) in lifetimes.iter().enumerate() {
 +                            if i != 0 {
 +                                w!(this, ", ");
 +                            }
 +                            w!(this, "{}", lt);
 +                        }
 +                        w!(this, "> ");
 +                        (target, bound)
 +                    }
 +                };
 +
 +                match target {
 +                    WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
 +                    WherePredicateTypeTarget::TypeOrConstParam(id) => {
 +                        match &params.type_or_consts[*id].name() {
 +                            Some(name) => w!(this, "{}", name),
 +                            None => w!(this, "_anon_{}", id.into_raw()),
 +                        }
 +                    }
 +                }
 +                w!(this, ": ");
 +                this.print_type_bounds(std::slice::from_ref(bound));
 +            }
 +        });
 +        true
 +    }
 +}
 +
 +impl<'a> Write for Printer<'a> {
 +    fn write_str(&mut self, s: &str) -> fmt::Result {
 +        for line in s.split_inclusive('\n') {
 +            if self.needs_indent {
 +                match self.buf.chars().last() {
 +                    Some('\n') | None => {}
 +                    _ => self.buf.push('\n'),
 +                }
 +                self.buf.push_str(&"    ".repeat(self.indent_level));
 +                self.needs_indent = false;
 +            }
 +
 +            self.buf.push_str(line);
 +            self.needs_indent = line.ends_with('\n');
 +        }
 +
 +        Ok(())
 +    }
 +}
index 5cdf36cc61b83f2859b5149a8592b31fef9604da,0000000000000000000000000000000000000000..e30d9652bb5dde974f65e5955ba36f68d0c75305
mode 100644,000000..100644
--- /dev/null
@@@ -1,360 -1,0 +1,360 @@@
-                 pub(self) a: Mixed<'a, T, Item = (), OtherItem = u8>,
-                 pub(self) b: Qualified<Self=Fully>::Syntax,
-                 pub(self) c: <TypeAnchored>::Path<'a>,
-                 pub(self) d: dyn for<'a> Trait<'a>,
 +use base_db::fixture::WithFixture;
 +use expect_test::{expect, Expect};
 +
 +use crate::{db::DefDatabase, test_db::TestDB};
 +
 +fn check(ra_fixture: &str, expect: Expect) {
 +    let (db, file_id) = TestDB::with_single_file(ra_fixture);
 +    let item_tree = db.file_item_tree(file_id.into());
 +    let pretty = item_tree.pretty_print();
 +    expect.assert_eq(&pretty);
 +}
 +
 +#[test]
 +fn imports() {
 +    check(
 +        r#"
 +//! file comment
 +#![no_std]
 +//! another file comment
 +
 +extern crate self as renamed;
 +pub(super) extern crate bli;
 +
 +pub use crate::path::{nested, items as renamed, Trait as _};
 +use globs::*;
 +
 +/// docs on import
 +use crate::{A, B};
 +
 +use a::{c, d::{e}};
 +        "#,
 +        expect![[r##"
 +            #![doc = " file comment"]
 +            #![no_std]
 +            #![doc = " another file comment"]
 +
 +            pub(self) extern crate self as renamed;
 +
 +            pub(super) extern crate bli;
 +
 +            pub use crate::path::{nested, items as renamed, Trait as _};
 +
 +            pub(self) use globs::*;
 +
 +            #[doc = " docs on import"]
 +            pub(self) use crate::{A, B};
 +
 +            pub(self) use a::{c, d::{e}};
 +        "##]],
 +    );
 +}
 +
 +#[test]
 +fn extern_blocks() {
 +    check(
 +        r#"
 +#[on_extern_block]
 +extern "C" {
 +    #[on_extern_type]
 +    type ExType;
 +
 +    #[on_extern_static]
 +    static EX_STATIC: u8;
 +
 +    #[on_extern_fn]
 +    fn ex_fn();
 +}
 +        "#,
 +        expect![[r##"
 +            #[on_extern_block]
 +            extern "C" {
 +                #[on_extern_type]
 +                pub(self) type ExType;
 +
 +                #[on_extern_static]
 +                pub(self) static EX_STATIC: u8 = _;
 +
 +                #[on_extern_fn]
 +                pub(self) fn ex_fn() -> ();
 +            }
 +        "##]],
 +    );
 +}
 +
 +#[test]
 +fn adts() {
 +    check(
 +        r#"
 +struct Unit;
 +
 +#[derive(Debug)]
 +struct Struct {
 +    /// fld docs
 +    fld: (),
 +}
 +
 +struct Tuple(#[attr] u8);
 +
 +union Ize {
 +    a: (),
 +    b: (),
 +}
 +
 +enum E {
 +    /// comment on Unit
 +    Unit,
 +    /// comment on Tuple
 +    Tuple(u8),
 +    Struct {
 +        /// comment on a: u8
 +        a: u8,
 +    }
 +}
 +        "#,
 +        expect![[r##"
 +            pub(self) struct Unit;
 +
 +            #[derive(Debug)]
 +            pub(self) struct Struct {
 +                #[doc = " fld docs"]
 +                pub(self) fld: (),
 +            }
 +
 +            pub(self) struct Tuple(
 +                #[attr]
 +                pub(self) 0: u8,
 +            );
 +
 +            pub(self) union Ize {
 +                pub(self) a: (),
 +                pub(self) b: (),
 +            }
 +
 +            pub(self) enum E {
 +                #[doc = " comment on Unit"]
 +                Unit,
 +                #[doc = " comment on Tuple"]
 +                Tuple(
 +                    pub(self) 0: u8,
 +                ),
 +                Struct {
 +                    #[doc = " comment on a: u8"]
 +                    pub(self) a: u8,
 +                },
 +            }
 +        "##]],
 +    );
 +}
 +
 +#[test]
 +fn misc() {
 +    check(
 +        r#"
 +pub static mut ST: () = ();
 +
 +const _: Anon = ();
 +
 +#[attr]
 +fn f(#[attr] arg: u8, _: ()) {
 +    #![inner_attr_in_fn]
 +}
 +
 +trait Tr: SuperTrait + 'lifetime {
 +    type Assoc: AssocBound = Default;
 +    fn method(&self);
 +}
 +        "#,
 +        expect![[r##"
 +            pub static mut ST: () = _;
 +
 +            pub(self) const _: Anon = _;
 +
 +            #[attr]
 +            #[inner_attr_in_fn]
 +            pub(self) fn f(
 +                #[attr]
 +                arg: u8,
 +                _: (),
 +            ) -> () { ... }
 +
 +            pub(self) trait Tr<Self>
 +            where
 +                Self: SuperTrait,
 +                Self: 'lifetime
 +            {
 +                pub(self) type Assoc: AssocBound = Default;
 +
 +                pub(self) fn method(
 +                    _: &Self,  // self
 +                ) -> ();
 +            }
 +        "##]],
 +    );
 +}
 +
 +#[test]
 +fn modules() {
 +    check(
 +        r#"
 +/// outer
 +mod inline {
 +    //! inner
 +
 +    use super::*;
 +
 +    fn fn_in_module() {}
 +}
 +
 +mod outline;
 +        "#,
 +        expect![[r##"
 +            #[doc = " outer"]
 +            #[doc = " inner"]
 +            pub(self) mod inline {
 +                pub(self) use super::*;
 +
 +                pub(self) fn fn_in_module() -> () { ... }
 +            }
 +
 +            pub(self) mod outline;
 +        "##]],
 +    );
 +}
 +
 +#[test]
 +fn macros() {
 +    check(
 +        r#"
 +macro_rules! m {
 +    () => {};
 +}
 +
 +pub macro m2() {}
 +
 +m!();
 +        "#,
 +        expect![[r#"
 +            macro_rules! m { ... }
 +
 +            pub macro m2 { ... }
 +
 +            m!(...);
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn mod_paths() {
 +    check(
 +        r#"
 +struct S {
 +    a: self::Ty,
 +    b: super::SuperTy,
 +    c: super::super::SuperSuperTy,
 +    d: ::abs::Path,
 +    e: crate::Crate,
 +    f: plain::path::Ty,
 +}
 +        "#,
 +        expect![[r#"
 +            pub(self) struct S {
 +                pub(self) a: self::Ty,
 +                pub(self) b: super::SuperTy,
 +                pub(self) c: super::super::SuperSuperTy,
 +                pub(self) d: ::abs::Path,
 +                pub(self) e: crate::Crate,
 +                pub(self) f: plain::path::Ty,
 +            }
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn types() {
 +    check(
 +        r#"
 +struct S {
 +    a: Mixed<'a, T, Item=(), OtherItem=u8>,
 +    b: <Fully as Qualified>::Syntax,
 +    c: <TypeAnchored>::Path::<'a>,
 +    d: dyn for<'a> Trait<'a>,
 +}
 +        "#,
 +        expect![[r#"
 +            pub(self) struct S {
-             impl<'a, 'b, T, const K: u8> S<'a, 'b, T, K>
++                pub(self) a: Mixed::<'a, T, Item = (), OtherItem = u8>,
++                pub(self) b: Qualified::<Self=Fully>::Syntax,
++                pub(self) c: <TypeAnchored>::Path::<'a>,
++                pub(self) d: dyn for<'a> Trait::<'a>,
 +            }
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn generics() {
 +    check(
 +        r#"
 +struct S<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> {
 +    field: &'a &'b T,
 +}
 +
 +struct Tuple<T: Copy, U: ?Sized>(T, U);
 +
 +impl<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> S<'a, 'b, T, K> {
 +    fn f<G: 'a>(arg: impl Copy) -> impl Copy {}
 +}
 +
 +enum Enum<'a, T, const U: u8> {}
 +union Union<'a, T, const U: u8> {}
 +
 +trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
 +        "#,
 +        expect![[r#"
 +            pub(self) struct S<'a, 'b, T, const K: u8>
 +            where
 +                T: Copy,
 +                T: 'a,
 +                T: 'b
 +            {
 +                pub(self) field: &'a &'b T,
 +            }
 +
 +            pub(self) struct Tuple<T, U>(
 +                pub(self) 0: T,
 +                pub(self) 1: U,
 +            )
 +            where
 +                T: Copy,
 +                U: ?Sized;
 +
-                 Self: for<'a> Tr<'a, T>
++            impl<'a, 'b, T, const K: u8> S::<'a, 'b, T, K>
 +            where
 +                T: Copy,
 +                T: 'a,
 +                T: 'b
 +            {
 +                pub(self) fn f<G>(
 +                    arg: impl Copy,
 +                ) -> impl Copy
 +                where
 +                    G: 'a { ... }
 +            }
 +
 +            pub(self) enum Enum<'a, T, const U: u8> {
 +            }
 +
 +            pub(self) union Union<'a, T, const U: u8> {
 +            }
 +
 +            pub(self) trait Tr<'a, Self, T>
 +            where
 +                Self: Super,
 +                T: 'a,
++                Self: for<'a> Tr::<'a, T>
 +            {
 +            }
 +        "#]],
 +    )
 +}
index 56603f4b154569f471e80fe6cfa807f4b13afab3,0000000000000000000000000000000000000000..32ebfda4fd926d475ec1b595bd0c7b01c698372f
mode 100644,000000..100644
--- /dev/null
@@@ -1,980 -1,0 +1,981 @@@
 +//! `hir_def` crate contains everything between macro expansion and type
 +//! inference.
 +//!
 +//! It defines various items (structs, enums, traits) which comprises Rust code,
 +//! as well as an algorithm for resolving paths to such entities.
 +//!
 +//! Note that `hir_def` is a work in progress, so not all of the above is
 +//! actually true.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +#[allow(unused)]
 +macro_rules! eprintln {
 +    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
 +}
 +
 +pub mod db;
 +
 +pub mod attr;
 +pub mod path;
 +pub mod type_ref;
 +pub mod builtin_type;
 +pub mod builtin_attr;
 +pub mod per_ns;
 +pub mod item_scope;
 +
 +pub mod dyn_map;
 +pub mod keys;
 +
 +pub mod item_tree;
 +pub mod intern;
 +
 +pub mod adt;
 +pub mod data;
 +pub mod generics;
 +pub mod lang_item;
 +
 +pub mod expr;
 +pub mod body;
 +pub mod resolver;
 +
 +mod trace;
 +pub mod nameres;
 +
 +pub mod src;
 +pub mod child_by_source;
 +
 +pub mod visibility;
 +pub mod find_path;
 +pub mod import_map;
 +
 +#[cfg(test)]
 +mod test_db;
 +#[cfg(test)]
 +mod macro_expansion_tests;
++mod pretty;
 +
 +use std::{
 +    hash::{Hash, Hasher},
 +    sync::Arc,
 +};
 +
 +use attr::Attr;
 +use base_db::{impl_intern_key, salsa, CrateId, ProcMacroKind};
 +use hir_expand::{
 +    ast_id_map::FileAstId,
 +    builtin_attr_macro::BuiltinAttrExpander,
 +    builtin_derive_macro::BuiltinDeriveExpander,
 +    builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
 +    eager::{expand_eager_macro, ErrorEmitted, ErrorSink},
 +    hygiene::Hygiene,
 +    proc_macro::ProcMacroExpander,
 +    AstId, ExpandError, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId,
 +    MacroDefKind, UnresolvedMacro,
 +};
 +use item_tree::ExternBlock;
 +use la_arena::Idx;
 +use nameres::DefMap;
 +use stdx::impl_from;
 +use syntax::ast;
 +
 +use crate::{
 +    adt::VariantData,
 +    attr::AttrId,
 +    builtin_type::BuiltinType,
 +    item_tree::{
 +        Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, MacroDef, MacroRules, ModItem,
 +        Static, Struct, Trait, TypeAlias, Union,
 +    },
 +};
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct ModuleId {
 +    krate: CrateId,
 +    /// If this `ModuleId` was derived from a `DefMap` for a block expression, this stores the
 +    /// `BlockId` of that block expression. If `None`, this module is part of the crate-level
 +    /// `DefMap` of `krate`.
 +    block: Option<BlockId>,
 +    /// The module's ID in its originating `DefMap`.
 +    pub local_id: LocalModuleId,
 +}
 +
 +impl ModuleId {
 +    pub fn def_map(&self, db: &dyn db::DefDatabase) -> Arc<DefMap> {
 +        match self.block {
 +            Some(block) => {
 +                db.block_def_map(block).unwrap_or_else(|| {
 +                    // NOTE: This should be unreachable - all `ModuleId`s come from their `DefMap`s,
 +                    // so the `DefMap` here must exist.
 +                    unreachable!("no `block_def_map` for `ModuleId` {:?}", self);
 +                })
 +            }
 +            None => db.crate_def_map(self.krate),
 +        }
 +    }
 +
 +    pub fn krate(&self) -> CrateId {
 +        self.krate
 +    }
 +
 +    pub fn containing_module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> {
 +        self.def_map(db).containing_module(self.local_id)
 +    }
 +
 +    pub fn containing_block(&self) -> Option<BlockId> {
 +        self.block
 +    }
 +}
 +
 +/// An ID of a module, **local** to a specific crate
 +pub type LocalModuleId = Idx<nameres::ModuleData>;
 +
 +#[derive(Debug)]
 +pub struct ItemLoc<N: ItemTreeNode> {
 +    pub container: ModuleId,
 +    pub id: ItemTreeId<N>,
 +}
 +
 +impl<N: ItemTreeNode> Clone for ItemLoc<N> {
 +    fn clone(&self) -> Self {
 +        Self { container: self.container, id: self.id }
 +    }
 +}
 +
 +impl<N: ItemTreeNode> Copy for ItemLoc<N> {}
 +
 +impl<N: ItemTreeNode> PartialEq for ItemLoc<N> {
 +    fn eq(&self, other: &Self) -> bool {
 +        self.container == other.container && self.id == other.id
 +    }
 +}
 +
 +impl<N: ItemTreeNode> Eq for ItemLoc<N> {}
 +
 +impl<N: ItemTreeNode> Hash for ItemLoc<N> {
 +    fn hash<H: Hasher>(&self, state: &mut H) {
 +        self.container.hash(state);
 +        self.id.hash(state);
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub struct AssocItemLoc<N: ItemTreeNode> {
 +    pub container: ItemContainerId,
 +    pub id: ItemTreeId<N>,
 +}
 +
 +impl<N: ItemTreeNode> Clone for AssocItemLoc<N> {
 +    fn clone(&self) -> Self {
 +        Self { container: self.container, id: self.id }
 +    }
 +}
 +
 +impl<N: ItemTreeNode> Copy for AssocItemLoc<N> {}
 +
 +impl<N: ItemTreeNode> PartialEq for AssocItemLoc<N> {
 +    fn eq(&self, other: &Self) -> bool {
 +        self.container == other.container && self.id == other.id
 +    }
 +}
 +
 +impl<N: ItemTreeNode> Eq for AssocItemLoc<N> {}
 +
 +impl<N: ItemTreeNode> Hash for AssocItemLoc<N> {
 +    fn hash<H: Hasher>(&self, state: &mut H) {
 +        self.container.hash(state);
 +        self.id.hash(state);
 +    }
 +}
 +
 +macro_rules! impl_intern {
 +    ($id:ident, $loc:ident, $intern:ident, $lookup:ident) => {
 +        impl_intern_key!($id);
 +
 +        impl Intern for $loc {
 +            type ID = $id;
 +            fn intern(self, db: &dyn db::DefDatabase) -> $id {
 +                db.$intern(self)
 +            }
 +        }
 +
 +        impl Lookup for $id {
 +            type Data = $loc;
 +            fn lookup(&self, db: &dyn db::DefDatabase) -> $loc {
 +                db.$lookup(*self)
 +            }
 +        }
 +    };
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct FunctionId(salsa::InternId);
 +type FunctionLoc = AssocItemLoc<Function>;
 +impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub struct StructId(salsa::InternId);
 +type StructLoc = ItemLoc<Struct>;
 +impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub struct UnionId(salsa::InternId);
 +pub type UnionLoc = ItemLoc<Union>;
 +impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub struct EnumId(salsa::InternId);
 +pub type EnumLoc = ItemLoc<Enum>;
 +impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum);
 +
 +// FIXME: rename to `VariantId`, only enums can ave variants
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct EnumVariantId {
 +    pub parent: EnumId,
 +    pub local_id: LocalEnumVariantId,
 +}
 +
 +pub type LocalEnumVariantId = Idx<adt::EnumVariantData>;
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct FieldId {
 +    pub parent: VariantId,
 +    pub local_id: LocalFieldId,
 +}
 +
 +pub type LocalFieldId = Idx<adt::FieldData>;
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct ConstId(salsa::InternId);
 +type ConstLoc = AssocItemLoc<Const>;
 +impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct StaticId(salsa::InternId);
 +pub type StaticLoc = AssocItemLoc<Static>;
 +impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct TraitId(salsa::InternId);
 +pub type TraitLoc = ItemLoc<Trait>;
 +impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct TypeAliasId(salsa::InternId);
 +type TypeAliasLoc = AssocItemLoc<TypeAlias>;
 +impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 +pub struct ImplId(salsa::InternId);
 +type ImplLoc = ItemLoc<Impl>;
 +impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 +pub struct ExternBlockId(salsa::InternId);
 +type ExternBlockLoc = ItemLoc<ExternBlock>;
 +impl_intern!(ExternBlockId, ExternBlockLoc, intern_extern_block, lookup_intern_extern_block);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum MacroExpander {
 +    Declarative,
 +    BuiltIn(BuiltinFnLikeExpander),
 +    BuiltInAttr(BuiltinAttrExpander),
 +    BuiltInDerive(BuiltinDeriveExpander),
 +    BuiltInEager(EagerExpander),
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 +pub struct Macro2Id(salsa::InternId);
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Macro2Loc {
 +    pub container: ModuleId,
 +    pub id: ItemTreeId<MacroDef>,
 +    pub expander: MacroExpander,
 +}
 +impl_intern!(Macro2Id, Macro2Loc, intern_macro2, lookup_intern_macro2);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 +pub struct MacroRulesId(salsa::InternId);
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct MacroRulesLoc {
 +    pub container: ModuleId,
 +    pub id: ItemTreeId<MacroRules>,
 +    pub local_inner: bool,
 +    pub expander: MacroExpander,
 +}
 +impl_intern!(MacroRulesId, MacroRulesLoc, intern_macro_rules, lookup_intern_macro_rules);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 +pub struct ProcMacroId(salsa::InternId);
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct ProcMacroLoc {
 +    // FIXME: this should be a crate? or just a crate-root module
 +    pub container: ModuleId,
 +    pub id: ItemTreeId<Function>,
 +    pub expander: ProcMacroExpander,
 +    pub kind: ProcMacroKind,
 +}
 +impl_intern!(ProcMacroId, ProcMacroLoc, intern_proc_macro, lookup_intern_proc_macro);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 +pub struct BlockId(salsa::InternId);
 +#[derive(Debug, Hash, PartialEq, Eq, Clone)]
 +pub struct BlockLoc {
 +    ast_id: AstId<ast::BlockExpr>,
 +    /// The containing module.
 +    module: ModuleId,
 +}
 +impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct TypeOrConstParamId {
 +    pub parent: GenericDefId,
 +    pub local_id: LocalTypeOrConstParamId,
 +}
 +
 +/// A TypeOrConstParamId with an invariant that it actually belongs to a type
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct TypeParamId(TypeOrConstParamId);
 +
 +impl TypeParamId {
 +    pub fn parent(&self) -> GenericDefId {
 +        self.0.parent
 +    }
 +    pub fn local_id(&self) -> LocalTypeOrConstParamId {
 +        self.0.local_id
 +    }
 +}
 +
 +impl TypeParamId {
 +    /// Caller should check if this toc id really belongs to a type
 +    pub fn from_unchecked(x: TypeOrConstParamId) -> Self {
 +        Self(x)
 +    }
 +}
 +
 +impl From<TypeParamId> for TypeOrConstParamId {
 +    fn from(x: TypeParamId) -> Self {
 +        x.0
 +    }
 +}
 +
 +/// A TypeOrConstParamId with an invariant that it actually belongs to a const
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct ConstParamId(TypeOrConstParamId);
 +
 +impl ConstParamId {
 +    pub fn parent(&self) -> GenericDefId {
 +        self.0.parent
 +    }
 +    pub fn local_id(&self) -> LocalTypeOrConstParamId {
 +        self.0.local_id
 +    }
 +}
 +
 +impl ConstParamId {
 +    /// Caller should check if this toc id really belongs to a const
 +    pub fn from_unchecked(x: TypeOrConstParamId) -> Self {
 +        Self(x)
 +    }
 +}
 +
 +impl From<ConstParamId> for TypeOrConstParamId {
 +    fn from(x: ConstParamId) -> Self {
 +        x.0
 +    }
 +}
 +
 +pub type LocalTypeOrConstParamId = Idx<generics::TypeOrConstParamData>;
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct LifetimeParamId {
 +    pub parent: GenericDefId,
 +    pub local_id: LocalLifetimeParamId,
 +}
 +pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>;
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum ItemContainerId {
 +    ExternBlockId(ExternBlockId),
 +    ModuleId(ModuleId),
 +    ImplId(ImplId),
 +    TraitId(TraitId),
 +}
 +impl_from!(ModuleId for ItemContainerId);
 +
 +/// A Data Type
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub enum AdtId {
 +    StructId(StructId),
 +    UnionId(UnionId),
 +    EnumId(EnumId),
 +}
 +impl_from!(StructId, UnionId, EnumId for AdtId);
 +
 +/// A macro
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub enum MacroId {
 +    Macro2Id(Macro2Id),
 +    MacroRulesId(MacroRulesId),
 +    ProcMacroId(ProcMacroId),
 +}
 +impl_from!(Macro2Id, MacroRulesId, ProcMacroId for MacroId);
 +
 +impl MacroId {
 +    pub fn is_attribute(self, db: &dyn db::DefDatabase) -> bool {
 +        match self {
 +            MacroId::ProcMacroId(it) => it.lookup(db).kind == ProcMacroKind::Attr,
 +            _ => false,
 +        }
 +    }
 +}
 +
 +/// A generic param
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum GenericParamId {
 +    TypeParamId(TypeParamId),
 +    ConstParamId(ConstParamId),
 +    LifetimeParamId(LifetimeParamId),
 +}
 +impl_from!(TypeParamId, LifetimeParamId, ConstParamId for GenericParamId);
 +
 +/// The defs which can be visible in the module.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum ModuleDefId {
 +    ModuleId(ModuleId),
 +    FunctionId(FunctionId),
 +    AdtId(AdtId),
 +    // Can't be directly declared, but can be imported.
 +    EnumVariantId(EnumVariantId),
 +    ConstId(ConstId),
 +    StaticId(StaticId),
 +    TraitId(TraitId),
 +    TypeAliasId(TypeAliasId),
 +    BuiltinType(BuiltinType),
 +    MacroId(MacroId),
 +}
 +impl_from!(
 +    MacroId(Macro2Id, MacroRulesId, ProcMacroId),
 +    ModuleId,
 +    FunctionId,
 +    AdtId(StructId, EnumId, UnionId),
 +    EnumVariantId,
 +    ConstId,
 +    StaticId,
 +    TraitId,
 +    TypeAliasId,
 +    BuiltinType
 +    for ModuleDefId
 +);
 +
 +/// The defs which have a body.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum DefWithBodyId {
 +    FunctionId(FunctionId),
 +    StaticId(StaticId),
 +    ConstId(ConstId),
 +}
 +
 +impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId);
 +
 +impl DefWithBodyId {
 +    pub fn as_generic_def_id(self) -> Option<GenericDefId> {
 +        match self {
 +            DefWithBodyId::FunctionId(f) => Some(f.into()),
 +            DefWithBodyId::StaticId(_) => None,
 +            DefWithBodyId::ConstId(c) => Some(c.into()),
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 +pub enum AssocItemId {
 +    FunctionId(FunctionId),
 +    ConstId(ConstId),
 +    TypeAliasId(TypeAliasId),
 +}
 +// FIXME: not every function, ... is actually an assoc item. maybe we should make
 +// sure that you can only turn actual assoc items into AssocItemIds. This would
 +// require not implementing From, and instead having some checked way of
 +// casting them, and somehow making the constructors private, which would be annoying.
 +impl_from!(FunctionId, ConstId, TypeAliasId for AssocItemId);
 +
 +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 +pub enum GenericDefId {
 +    FunctionId(FunctionId),
 +    AdtId(AdtId),
 +    TraitId(TraitId),
 +    TypeAliasId(TypeAliasId),
 +    ImplId(ImplId),
 +    // enum variants cannot have generics themselves, but their parent enums
 +    // can, and this makes some code easier to write
 +    EnumVariantId(EnumVariantId),
 +    // consts can have type parameters from their parents (i.e. associated consts of traits)
 +    ConstId(ConstId),
 +}
 +impl_from!(
 +    FunctionId,
 +    AdtId(StructId, EnumId, UnionId),
 +    TraitId,
 +    TypeAliasId,
 +    ImplId,
 +    EnumVariantId,
 +    ConstId
 +    for GenericDefId
 +);
 +
 +impl From<AssocItemId> for GenericDefId {
 +    fn from(item: AssocItemId) -> Self {
 +        match item {
 +            AssocItemId::FunctionId(f) => f.into(),
 +            AssocItemId::ConstId(c) => c.into(),
 +            AssocItemId::TypeAliasId(t) => t.into(),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum AttrDefId {
 +    ModuleId(ModuleId),
 +    FieldId(FieldId),
 +    AdtId(AdtId),
 +    FunctionId(FunctionId),
 +    EnumVariantId(EnumVariantId),
 +    StaticId(StaticId),
 +    ConstId(ConstId),
 +    TraitId(TraitId),
 +    TypeAliasId(TypeAliasId),
 +    MacroId(MacroId),
 +    ImplId(ImplId),
 +    GenericParamId(GenericParamId),
 +    ExternBlockId(ExternBlockId),
 +}
 +
 +impl_from!(
 +    ModuleId,
 +    FieldId,
 +    AdtId(StructId, EnumId, UnionId),
 +    EnumVariantId,
 +    StaticId,
 +    ConstId,
 +    FunctionId,
 +    TraitId,
 +    TypeAliasId,
 +    MacroId(Macro2Id, MacroRulesId, ProcMacroId),
 +    ImplId,
 +    GenericParamId
 +    for AttrDefId
 +);
 +
 +impl From<ItemContainerId> for AttrDefId {
 +    fn from(acid: ItemContainerId) -> Self {
 +        match acid {
 +            ItemContainerId::ModuleId(mid) => AttrDefId::ModuleId(mid),
 +            ItemContainerId::ImplId(iid) => AttrDefId::ImplId(iid),
 +            ItemContainerId::TraitId(tid) => AttrDefId::TraitId(tid),
 +            ItemContainerId::ExternBlockId(id) => AttrDefId::ExternBlockId(id),
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum VariantId {
 +    EnumVariantId(EnumVariantId),
 +    StructId(StructId),
 +    UnionId(UnionId),
 +}
 +impl_from!(EnumVariantId, StructId, UnionId for VariantId);
 +
 +impl VariantId {
 +    pub fn variant_data(self, db: &dyn db::DefDatabase) -> Arc<VariantData> {
 +        match self {
 +            VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
 +            VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
 +            VariantId::EnumVariantId(it) => {
 +                db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
 +            }
 +        }
 +    }
 +
 +    pub fn file_id(self, db: &dyn db::DefDatabase) -> HirFileId {
 +        match self {
 +            VariantId::EnumVariantId(it) => it.parent.lookup(db).id.file_id(),
 +            VariantId::StructId(it) => it.lookup(db).id.file_id(),
 +            VariantId::UnionId(it) => it.lookup(db).id.file_id(),
 +        }
 +    }
 +
 +    pub fn adt_id(self) -> AdtId {
 +        match self {
 +            VariantId::EnumVariantId(it) => it.parent.into(),
 +            VariantId::StructId(it) => it.into(),
 +            VariantId::UnionId(it) => it.into(),
 +        }
 +    }
 +}
 +
 +trait Intern {
 +    type ID;
 +    fn intern(self, db: &dyn db::DefDatabase) -> Self::ID;
 +}
 +
 +pub trait Lookup {
 +    type Data;
 +    fn lookup(&self, db: &dyn db::DefDatabase) -> Self::Data;
 +}
 +
 +pub trait HasModule {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId;
 +}
 +
 +impl HasModule for ItemContainerId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        match *self {
 +            ItemContainerId::ModuleId(it) => it,
 +            ItemContainerId::ImplId(it) => it.lookup(db).container,
 +            ItemContainerId::TraitId(it) => it.lookup(db).container,
 +            ItemContainerId::ExternBlockId(it) => it.lookup(db).container,
 +        }
 +    }
 +}
 +
 +impl<N: ItemTreeNode> HasModule for AssocItemLoc<N> {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        self.container.module(db)
 +    }
 +}
 +
 +impl HasModule for AdtId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        match self {
 +            AdtId::StructId(it) => it.lookup(db).container,
 +            AdtId::UnionId(it) => it.lookup(db).container,
 +            AdtId::EnumId(it) => it.lookup(db).container,
 +        }
 +    }
 +}
 +
 +impl HasModule for VariantId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        match self {
 +            VariantId::EnumVariantId(it) => it.parent.lookup(db).container,
 +            VariantId::StructId(it) => it.lookup(db).container,
 +            VariantId::UnionId(it) => it.lookup(db).container,
 +        }
 +    }
 +}
 +
 +impl HasModule for MacroId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        match self {
 +            MacroId::MacroRulesId(it) => it.lookup(db).container,
 +            MacroId::Macro2Id(it) => it.lookup(db).container,
 +            MacroId::ProcMacroId(it) => it.lookup(db).container,
 +        }
 +    }
 +}
 +
 +impl HasModule for DefWithBodyId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        match self {
 +            DefWithBodyId::FunctionId(it) => it.lookup(db).module(db),
 +            DefWithBodyId::StaticId(it) => it.lookup(db).module(db),
 +            DefWithBodyId::ConstId(it) => it.lookup(db).module(db),
 +        }
 +    }
 +}
 +
 +impl DefWithBodyId {
 +    pub fn as_mod_item(self, db: &dyn db::DefDatabase) -> ModItem {
 +        match self {
 +            DefWithBodyId::FunctionId(it) => it.lookup(db).id.value.into(),
 +            DefWithBodyId::StaticId(it) => it.lookup(db).id.value.into(),
 +            DefWithBodyId::ConstId(it) => it.lookup(db).id.value.into(),
 +        }
 +    }
 +}
 +
 +impl HasModule for GenericDefId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        match self {
 +            GenericDefId::FunctionId(it) => it.lookup(db).module(db),
 +            GenericDefId::AdtId(it) => it.module(db),
 +            GenericDefId::TraitId(it) => it.lookup(db).container,
 +            GenericDefId::TypeAliasId(it) => it.lookup(db).module(db),
 +            GenericDefId::ImplId(it) => it.lookup(db).container,
 +            GenericDefId::EnumVariantId(it) => it.parent.lookup(db).container,
 +            GenericDefId::ConstId(it) => it.lookup(db).module(db),
 +        }
 +    }
 +}
 +
 +impl HasModule for TypeAliasId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        self.lookup(db).module(db)
 +    }
 +}
 +
 +impl HasModule for TraitId {
 +    fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
 +        self.lookup(db).container
 +    }
 +}
 +
 +impl ModuleDefId {
 +    /// Returns the module containing `self` (or `self`, if `self` is itself a module).
 +    ///
 +    /// Returns `None` if `self` refers to a primitive type.
 +    pub fn module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> {
 +        Some(match self {
 +            ModuleDefId::ModuleId(id) => *id,
 +            ModuleDefId::FunctionId(id) => id.lookup(db).module(db),
 +            ModuleDefId::AdtId(id) => id.module(db),
 +            ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container,
 +            ModuleDefId::ConstId(id) => id.lookup(db).container.module(db),
 +            ModuleDefId::StaticId(id) => id.lookup(db).module(db),
 +            ModuleDefId::TraitId(id) => id.lookup(db).container,
 +            ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db),
 +            ModuleDefId::MacroId(id) => id.module(db),
 +            ModuleDefId::BuiltinType(_) => return None,
 +        })
 +    }
 +}
 +
 +impl AttrDefId {
 +    pub fn krate(&self, db: &dyn db::DefDatabase) -> CrateId {
 +        match self {
 +            AttrDefId::ModuleId(it) => it.krate,
 +            AttrDefId::FieldId(it) => it.parent.module(db).krate,
 +            AttrDefId::AdtId(it) => it.module(db).krate,
 +            AttrDefId::FunctionId(it) => it.lookup(db).module(db).krate,
 +            AttrDefId::EnumVariantId(it) => it.parent.lookup(db).container.krate,
 +            AttrDefId::StaticId(it) => it.lookup(db).module(db).krate,
 +            AttrDefId::ConstId(it) => it.lookup(db).module(db).krate,
 +            AttrDefId::TraitId(it) => it.lookup(db).container.krate,
 +            AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate,
 +            AttrDefId::ImplId(it) => it.lookup(db).container.krate,
 +            AttrDefId::ExternBlockId(it) => it.lookup(db).container.krate,
 +            AttrDefId::GenericParamId(it) => {
 +                match it {
 +                    GenericParamId::TypeParamId(it) => it.parent(),
 +                    GenericParamId::ConstParamId(it) => it.parent(),
 +                    GenericParamId::LifetimeParamId(it) => it.parent,
 +                }
 +                .module(db)
 +                .krate
 +            }
 +            AttrDefId::MacroId(it) => it.module(db).krate,
 +        }
 +    }
 +}
 +
 +/// A helper trait for converting to MacroCallId
 +pub trait AsMacroCall {
 +    fn as_call_id(
 +        &self,
 +        db: &dyn db::DefDatabase,
 +        krate: CrateId,
 +        resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
 +    ) -> Option<MacroCallId> {
 +        self.as_call_id_with_errors(db, krate, resolver, &mut |_| ()).ok()?.ok()
 +    }
 +
 +    fn as_call_id_with_errors(
 +        &self,
 +        db: &dyn db::DefDatabase,
 +        krate: CrateId,
 +        resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
 +        error_sink: &mut dyn FnMut(ExpandError),
 +    ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro>;
 +}
 +
 +impl AsMacroCall for InFile<&ast::MacroCall> {
 +    fn as_call_id_with_errors(
 +        &self,
 +        db: &dyn db::DefDatabase,
 +        krate: CrateId,
 +        resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
 +        mut error_sink: &mut dyn FnMut(ExpandError),
 +    ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
 +        let expands_to = hir_expand::ExpandTo::from_call_site(self.value);
 +        let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
 +        let h = Hygiene::new(db.upcast(), self.file_id);
 +        let path =
 +            self.value.path().and_then(|path| path::ModPath::from_src(db.upcast(), path, &h));
 +
 +        let path = match error_sink
 +            .option(path, || ExpandError::Other("malformed macro invocation".into()))
 +        {
 +            Ok(path) => path,
 +            Err(error) => {
 +                return Ok(Err(error));
 +            }
 +        };
 +
 +        macro_call_as_call_id(
 +            db,
 +            &AstIdWithPath::new(ast_id.file_id, ast_id.value, path),
 +            expands_to,
 +            krate,
 +            resolver,
 +            error_sink,
 +        )
 +    }
 +}
 +
 +/// Helper wrapper for `AstId` with `ModPath`
 +#[derive(Clone, Debug, Eq, PartialEq)]
 +struct AstIdWithPath<T: ast::AstNode> {
 +    ast_id: AstId<T>,
 +    path: path::ModPath,
 +}
 +
 +impl<T: ast::AstNode> AstIdWithPath<T> {
 +    fn new(file_id: HirFileId, ast_id: FileAstId<T>, path: path::ModPath) -> AstIdWithPath<T> {
 +        AstIdWithPath { ast_id: AstId::new(file_id, ast_id), path }
 +    }
 +}
 +
 +fn macro_call_as_call_id(
 +    db: &dyn db::DefDatabase,
 +    call: &AstIdWithPath<ast::MacroCall>,
 +    expand_to: ExpandTo,
 +    krate: CrateId,
 +    resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
 +    error_sink: &mut dyn FnMut(ExpandError),
 +) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
 +    let def =
 +        resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
 +
 +    let res = if let MacroDefKind::BuiltInEager(..) = def.kind {
 +        let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast()));
 +
 +        expand_eager_macro(db.upcast(), krate, macro_call, def, &resolver, error_sink)?
 +    } else {
 +        Ok(def.as_lazy_macro(
 +            db.upcast(),
 +            krate,
 +            MacroCallKind::FnLike { ast_id: call.ast_id, expand_to },
 +        ))
 +    };
 +    Ok(res)
 +}
 +
 +pub fn macro_id_to_def_id(db: &dyn db::DefDatabase, id: MacroId) -> MacroDefId {
 +    match id {
 +        MacroId::Macro2Id(it) => {
 +            let loc = it.lookup(db);
 +
 +            let item_tree = loc.id.item_tree(db);
 +            let makro = &item_tree[loc.id.value];
 +            let in_file = |m: FileAstId<ast::MacroDef>| InFile::new(loc.id.file_id(), m.upcast());
 +            MacroDefId {
 +                krate: loc.container.krate,
 +                kind: match loc.expander {
 +                    MacroExpander::Declarative => MacroDefKind::Declarative(in_file(makro.ast_id)),
 +                    MacroExpander::BuiltIn(it) => MacroDefKind::BuiltIn(it, in_file(makro.ast_id)),
 +                    MacroExpander::BuiltInAttr(it) => {
 +                        MacroDefKind::BuiltInAttr(it, in_file(makro.ast_id))
 +                    }
 +                    MacroExpander::BuiltInDerive(it) => {
 +                        MacroDefKind::BuiltInDerive(it, in_file(makro.ast_id))
 +                    }
 +                    MacroExpander::BuiltInEager(it) => {
 +                        MacroDefKind::BuiltInEager(it, in_file(makro.ast_id))
 +                    }
 +                },
 +                local_inner: false,
 +            }
 +        }
 +        MacroId::MacroRulesId(it) => {
 +            let loc = it.lookup(db);
 +
 +            let item_tree = loc.id.item_tree(db);
 +            let makro = &item_tree[loc.id.value];
 +            let in_file = |m: FileAstId<ast::MacroRules>| InFile::new(loc.id.file_id(), m.upcast());
 +            MacroDefId {
 +                krate: loc.container.krate,
 +                kind: match loc.expander {
 +                    MacroExpander::Declarative => MacroDefKind::Declarative(in_file(makro.ast_id)),
 +                    MacroExpander::BuiltIn(it) => MacroDefKind::BuiltIn(it, in_file(makro.ast_id)),
 +                    MacroExpander::BuiltInAttr(it) => {
 +                        MacroDefKind::BuiltInAttr(it, in_file(makro.ast_id))
 +                    }
 +                    MacroExpander::BuiltInDerive(it) => {
 +                        MacroDefKind::BuiltInDerive(it, in_file(makro.ast_id))
 +                    }
 +                    MacroExpander::BuiltInEager(it) => {
 +                        MacroDefKind::BuiltInEager(it, in_file(makro.ast_id))
 +                    }
 +                },
 +                local_inner: loc.local_inner,
 +            }
 +        }
 +        MacroId::ProcMacroId(it) => {
 +            let loc = it.lookup(db);
 +
 +            let item_tree = loc.id.item_tree(db);
 +            let makro = &item_tree[loc.id.value];
 +            MacroDefId {
 +                krate: loc.container.krate,
 +                kind: MacroDefKind::ProcMacro(
 +                    loc.expander,
 +                    loc.kind,
 +                    InFile::new(loc.id.file_id(), makro.ast_id),
 +                ),
 +                local_inner: false,
 +            }
 +        }
 +    }
 +}
 +
 +fn derive_macro_as_call_id(
 +    db: &dyn db::DefDatabase,
 +    item_attr: &AstIdWithPath<ast::Adt>,
 +    derive_attr: AttrId,
 +    derive_pos: u32,
 +    krate: CrateId,
 +    resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>,
 +) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {
 +    let (macro_id, def_id) = resolver(item_attr.path.clone())
 +        .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
 +    let call_id = def_id.as_lazy_macro(
 +        db.upcast(),
 +        krate,
 +        MacroCallKind::Derive {
 +            ast_id: item_attr.ast_id,
 +            derive_index: derive_pos,
 +            derive_attr_index: derive_attr.ast_index,
 +        },
 +    );
 +    Ok((macro_id, def_id, call_id))
 +}
 +
 +fn attr_macro_as_call_id(
 +    db: &dyn db::DefDatabase,
 +    item_attr: &AstIdWithPath<ast::Item>,
 +    macro_attr: &Attr,
 +    krate: CrateId,
 +    def: MacroDefId,
 +    is_derive: bool,
 +) -> MacroCallId {
 +    let mut arg = match macro_attr.input.as_deref() {
 +        Some(attr::AttrInput::TokenTree(tt, map)) => (tt.clone(), map.clone()),
 +        _ => Default::default(),
 +    };
 +
 +    // The parentheses are always disposed here.
 +    arg.0.delimiter = None;
 +
 +    let res = def.as_lazy_macro(
 +        db.upcast(),
 +        krate,
 +        MacroCallKind::Attr {
 +            ast_id: item_attr.ast_id,
 +            attr_args: Arc::new(arg),
 +            invoc_attr_index: macro_attr.id.ast_index,
 +            is_derive,
 +        },
 +    );
 +    res
 +}
index c579bc9194c30bfbe88232fec290fa7d1e8790e8,0000000000000000000000000000000000000000..8dfda6df64e7c5579bfa48c908ac7c7a82a52124
mode 100644,000000..100644
--- /dev/null
@@@ -1,448 -1,0 +1,448 @@@
-         let from_extern_prelude = self
-             .extern_prelude
-             .get(name)
-             .map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public));
 +//! This modules implements a function to resolve a path `foo::bar::baz` to a
 +//! def, which is used within the name resolution.
 +//!
 +//! When name resolution is finished, the result of resolving a path is either
 +//! `Some(def)` or `None`. However, when we are in process of resolving imports
 +//! or macros, there's a third possibility:
 +//!
 +//!   I can't resolve this path right now, but I might be resolve this path
 +//!   later, when more macros are expanded.
 +//!
 +//! `ReachedFixedPoint` signals about this.
 +
 +use base_db::Edition;
 +use hir_expand::name::Name;
 +
 +use crate::{
 +    db::DefDatabase,
 +    item_scope::BUILTIN_SCOPE,
 +    nameres::{BuiltinShadowMode, DefMap},
 +    path::{ModPath, PathKind},
 +    per_ns::PerNs,
 +    visibility::{RawVisibility, Visibility},
 +    AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId,
 +};
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 +pub(super) enum ResolveMode {
 +    Import,
 +    Other,
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 +pub(super) enum ReachedFixedPoint {
 +    Yes,
 +    No,
 +}
 +
 +#[derive(Debug, Clone)]
 +pub(super) struct ResolvePathResult {
 +    pub(super) resolved_def: PerNs,
 +    pub(super) segment_index: Option<usize>,
 +    pub(super) reached_fixedpoint: ReachedFixedPoint,
 +    pub(super) krate: Option<CrateId>,
 +}
 +
 +impl ResolvePathResult {
 +    fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
 +        ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None, None)
 +    }
 +
 +    fn with(
 +        resolved_def: PerNs,
 +        reached_fixedpoint: ReachedFixedPoint,
 +        segment_index: Option<usize>,
 +        krate: Option<CrateId>,
 +    ) -> ResolvePathResult {
 +        ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, krate }
 +    }
 +}
 +
 +impl DefMap {
 +    pub(super) fn resolve_name_in_extern_prelude(
 +        &self,
 +        db: &dyn DefDatabase,
 +        name: &Name,
 +    ) -> Option<ModuleId> {
 +        match self.block {
 +            Some(_) => self.crate_root(db).def_map(db).extern_prelude.get(name).copied(),
 +            None => self.extern_prelude.get(name).copied(),
 +        }
 +    }
 +
 +    pub(crate) fn resolve_visibility(
 +        &self,
 +        db: &dyn DefDatabase,
 +        original_module: LocalModuleId,
 +        visibility: &RawVisibility,
 +    ) -> Option<Visibility> {
 +        let mut vis = match visibility {
 +            RawVisibility::Module(path) => {
 +                let (result, remaining) =
 +                    self.resolve_path(db, original_module, path, BuiltinShadowMode::Module);
 +                if remaining.is_some() {
 +                    return None;
 +                }
 +                let types = result.take_types()?;
 +                match types {
 +                    ModuleDefId::ModuleId(m) => Visibility::Module(m),
 +                    _ => {
 +                        // error: visibility needs to refer to module
 +                        return None;
 +                    }
 +                }
 +            }
 +            RawVisibility::Public => Visibility::Public,
 +        };
 +
 +        // In block expressions, `self` normally refers to the containing non-block module, and
 +        // `super` to its parent (etc.). However, visibilities must only refer to a module in the
 +        // DefMap they're written in, so we restrict them when that happens.
 +        if let Visibility::Module(m) = vis {
 +            if self.block_id() != m.block {
 +                cov_mark::hit!(adjust_vis_in_block_def_map);
 +                vis = Visibility::Module(self.module_id(self.root()));
 +                tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis);
 +            }
 +        }
 +
 +        Some(vis)
 +    }
 +
 +    // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
 +    // the result.
 +    pub(super) fn resolve_path_fp_with_macro(
 +        &self,
 +        db: &dyn DefDatabase,
 +        mode: ResolveMode,
 +        mut original_module: LocalModuleId,
 +        path: &ModPath,
 +        shadow: BuiltinShadowMode,
 +    ) -> ResolvePathResult {
 +        let mut result = ResolvePathResult::empty(ReachedFixedPoint::No);
 +
 +        let mut arc;
 +        let mut current_map = self;
 +        loop {
 +            let new = current_map.resolve_path_fp_with_macro_single(
 +                db,
 +                mode,
 +                original_module,
 +                path,
 +                shadow,
 +            );
 +
 +            // Merge `new` into `result`.
 +            result.resolved_def = result.resolved_def.or(new.resolved_def);
 +            if result.reached_fixedpoint == ReachedFixedPoint::No {
 +                result.reached_fixedpoint = new.reached_fixedpoint;
 +            }
 +            // FIXME: this doesn't seem right; what if the different namespace resolutions come from different crates?
 +            result.krate = result.krate.or(new.krate);
 +            result.segment_index = match (result.segment_index, new.segment_index) {
 +                (Some(idx), None) => Some(idx),
 +                (Some(old), Some(new)) => Some(old.max(new)),
 +                (None, new) => new,
 +            };
 +
 +            match &current_map.block {
 +                Some(block) => {
 +                    original_module = block.parent.local_id;
 +                    arc = block.parent.def_map(db);
 +                    current_map = &*arc;
 +                }
 +                None => return result,
 +            }
 +        }
 +    }
 +
 +    pub(super) fn resolve_path_fp_with_macro_single(
 +        &self,
 +        db: &dyn DefDatabase,
 +        mode: ResolveMode,
 +        original_module: LocalModuleId,
 +        path: &ModPath,
 +        shadow: BuiltinShadowMode,
 +    ) -> ResolvePathResult {
 +        let graph = db.crate_graph();
 +        let _cx = stdx::panic_context::enter(format!(
 +            "DefMap {:?} crate_name={:?} block={:?} path={}",
 +            self.krate, graph[self.krate].display_name, self.block, path
 +        ));
 +
 +        let mut segments = path.segments().iter().enumerate();
 +        let mut curr_per_ns: PerNs = match path.kind {
 +            PathKind::DollarCrate(krate) => {
 +                if krate == self.krate {
 +                    cov_mark::hit!(macro_dollar_crate_self);
 +                    PerNs::types(self.crate_root(db).into(), Visibility::Public)
 +                } else {
 +                    let def_map = db.crate_def_map(krate);
 +                    let module = def_map.module_id(def_map.root);
 +                    cov_mark::hit!(macro_dollar_crate_other);
 +                    PerNs::types(module.into(), Visibility::Public)
 +                }
 +            }
 +            PathKind::Crate => PerNs::types(self.crate_root(db).into(), Visibility::Public),
 +            // plain import or absolute path in 2015: crate-relative with
 +            // fallback to extern prelude (with the simplification in
 +            // rust-lang/rust#57745)
 +            // FIXME there must be a nicer way to write this condition
 +            PathKind::Plain | PathKind::Abs
 +                if self.edition == Edition::Edition2015
 +                    && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
 +            {
 +                let (_, segment) = match segments.next() {
 +                    Some((idx, segment)) => (idx, segment),
 +                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
 +                };
 +                tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
 +                self.resolve_name_in_crate_root_or_extern_prelude(db, segment)
 +            }
 +            PathKind::Plain => {
 +                let (_, segment) = match segments.next() {
 +                    Some((idx, segment)) => (idx, segment),
 +                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
 +                };
 +                // The first segment may be a builtin type. If the path has more
 +                // than one segment, we first try resolving it as a module
 +                // anyway.
 +                // FIXME: If the next segment doesn't resolve in the module and
 +                // BuiltinShadowMode wasn't Module, then we need to try
 +                // resolving it as a builtin.
 +                let prefer_module =
 +                    if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module };
 +
 +                tracing::debug!("resolving {:?} in module", segment);
 +                self.resolve_name_in_module(db, original_module, segment, prefer_module)
 +            }
 +            PathKind::Super(lvl) => {
 +                let mut module = original_module;
 +                for i in 0..lvl {
 +                    match self.modules[module].parent {
 +                        Some(it) => module = it,
 +                        None => match &self.block {
 +                            Some(block) => {
 +                                // Look up remaining path in parent `DefMap`
 +                                let new_path = ModPath::from_segments(
 +                                    PathKind::Super(lvl - i),
 +                                    path.segments().to_vec(),
 +                                );
 +                                tracing::debug!(
 +                                    "`super` path: {} -> {} in parent map",
 +                                    path,
 +                                    new_path
 +                                );
 +                                return block.parent.def_map(db).resolve_path_fp_with_macro(
 +                                    db,
 +                                    mode,
 +                                    block.parent.local_id,
 +                                    &new_path,
 +                                    shadow,
 +                                );
 +                            }
 +                            None => {
 +                                tracing::debug!("super path in root module");
 +                                return ResolvePathResult::empty(ReachedFixedPoint::Yes);
 +                            }
 +                        },
 +                    }
 +                }
 +
 +                // Resolve `self` to the containing crate-rooted module if we're a block
 +                self.with_ancestor_maps(db, module, &mut |def_map, module| {
 +                    if def_map.block.is_some() {
 +                        None // keep ascending
 +                    } else {
 +                        Some(PerNs::types(def_map.module_id(module).into(), Visibility::Public))
 +                    }
 +                })
 +                .expect("block DefMap not rooted in crate DefMap")
 +            }
 +            PathKind::Abs => {
 +                // 2018-style absolute path -- only extern prelude
 +                let segment = match segments.next() {
 +                    Some((_, segment)) => segment,
 +                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
 +                };
 +                if let Some(&def) = self.extern_prelude.get(segment) {
 +                    tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
 +                    PerNs::types(def.into(), Visibility::Public)
 +                } else {
 +                    return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
 +                }
 +            }
 +        };
 +
 +        for (i, segment) in segments {
 +            let (curr, vis) = match curr_per_ns.take_types_vis() {
 +                Some(r) => r,
 +                None => {
 +                    // we still have path segments left, but the path so far
 +                    // didn't resolve in the types namespace => no resolution
 +                    // (don't break here because `curr_per_ns` might contain
 +                    // something in the value namespace, and it would be wrong
 +                    // to return that)
 +                    return ResolvePathResult::empty(ReachedFixedPoint::No);
 +                }
 +            };
 +            // resolve segment in curr
 +
 +            curr_per_ns = match curr {
 +                ModuleDefId::ModuleId(module) => {
 +                    if module.krate != self.krate {
 +                        let path = ModPath::from_segments(
 +                            PathKind::Super(0),
 +                            path.segments()[i..].iter().cloned(),
 +                        );
 +                        tracing::debug!("resolving {:?} in other crate", path);
 +                        let defp_map = module.def_map(db);
 +                        let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
 +                        return ResolvePathResult::with(
 +                            def,
 +                            ReachedFixedPoint::Yes,
 +                            s.map(|s| s + i),
 +                            Some(module.krate),
 +                        );
 +                    }
 +
 +                    let def_map;
 +                    let module_data = if module.block == self.block_id() {
 +                        &self[module.local_id]
 +                    } else {
 +                        def_map = module.def_map(db);
 +                        &def_map[module.local_id]
 +                    };
 +
 +                    // Since it is a qualified path here, it should not contains legacy macros
 +                    module_data.scope.get(segment)
 +                }
 +                ModuleDefId::AdtId(AdtId::EnumId(e)) => {
 +                    // enum variant
 +                    cov_mark::hit!(can_import_enum_variant);
 +                    let enum_data = db.enum_data(e);
 +                    match enum_data.variant(segment) {
 +                        Some(local_id) => {
 +                            let variant = EnumVariantId { parent: e, local_id };
 +                            match &*enum_data.variants[local_id].variant_data {
 +                                crate::adt::VariantData::Record(_) => {
 +                                    PerNs::types(variant.into(), Visibility::Public)
 +                                }
 +                                crate::adt::VariantData::Tuple(_)
 +                                | crate::adt::VariantData::Unit => {
 +                                    PerNs::both(variant.into(), variant.into(), Visibility::Public)
 +                                }
 +                            }
 +                        }
 +                        None => {
 +                            return ResolvePathResult::with(
 +                                PerNs::types(e.into(), vis),
 +                                ReachedFixedPoint::Yes,
 +                                Some(i),
 +                                Some(self.krate),
 +                            );
 +                        }
 +                    }
 +                }
 +                s => {
 +                    // could be an inherent method call in UFCS form
 +                    // (`Struct::method`), or some other kind of associated item
 +                    tracing::debug!(
 +                        "path segment {:?} resolved to non-module {:?}, but is not last",
 +                        segment,
 +                        curr,
 +                    );
 +
 +                    return ResolvePathResult::with(
 +                        PerNs::types(s, vis),
 +                        ReachedFixedPoint::Yes,
 +                        Some(i),
 +                        Some(self.krate),
 +                    );
 +                }
 +            };
 +        }
 +
 +        ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate))
 +    }
 +
 +    fn resolve_name_in_module(
 +        &self,
 +        db: &dyn DefDatabase,
 +        module: LocalModuleId,
 +        name: &Name,
 +        shadow: BuiltinShadowMode,
 +    ) -> PerNs {
 +        // Resolve in:
 +        //  - legacy scope of macro
 +        //  - current module / scope
 +        //  - extern prelude
 +        //  - std prelude
 +        let from_legacy_macro = self[module]
 +            .scope
 +            .get_legacy_macro(name)
 +            // FIXME: shadowing
 +            .and_then(|it| it.last())
 +            .map_or_else(PerNs::none, |&m| PerNs::macros(m.into(), Visibility::Public));
 +        let from_scope = self[module].scope.get(name);
 +        let from_builtin = match self.block {
 +            Some(_) => {
 +                // Only resolve to builtins in the root `DefMap`.
 +                PerNs::none()
 +            }
 +            None => BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none),
 +        };
 +        let from_scope_or_builtin = match shadow {
 +            BuiltinShadowMode::Module => from_scope.or(from_builtin),
 +            BuiltinShadowMode::Other => match from_scope.take_types() {
 +                Some(ModuleDefId::ModuleId(_)) => from_builtin.or(from_scope),
 +                Some(_) | None => from_scope.or(from_builtin),
 +            },
 +        };
-         let from_prelude = self.resolve_in_prelude(db, name);
 +
-         from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude)
++        let extern_prelude = || {
++            self.extern_prelude
++                .get(name)
++                .map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public))
++        };
++        let prelude = || self.resolve_in_prelude(db, name);
 +
-         let arc;
-         let crate_def_map = match self.block {
++        from_legacy_macro.or(from_scope_or_builtin).or_else(extern_prelude).or_else(prelude)
 +    }
 +
 +    fn resolve_name_in_crate_root_or_extern_prelude(
 +        &self,
 +        db: &dyn DefDatabase,
 +        name: &Name,
 +    ) -> PerNs {
-                 arc = self.crate_root(db).def_map(db);
-                 &arc
++        let from_crate_root = match self.block {
 +            Some(_) => {
-             None => self,
++                let def_map = self.crate_root(db).def_map(db);
++                def_map[def_map.root].scope.get(name)
 +            }
-         let from_crate_root = crate_def_map[crate_def_map.root].scope.get(name);
-         let from_extern_prelude = self
-             .resolve_name_in_extern_prelude(db, name)
-             .map_or(PerNs::none(), |it| PerNs::types(it.into(), Visibility::Public));
++            None => self[self.root].scope.get(name),
++        };
++        let from_extern_prelude = || {
++            self.resolve_name_in_extern_prelude(db, name)
++                .map_or(PerNs::none(), |it| PerNs::types(it.into(), Visibility::Public))
 +        };
-         from_crate_root.or(from_extern_prelude)
 +
++        from_crate_root.or_else(from_extern_prelude)
 +    }
 +
 +    fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
 +        if let Some(prelude) = self.prelude {
 +            let keep;
 +            let def_map = if prelude.krate == self.krate {
 +                self
 +            } else {
 +                // Extend lifetime
 +                keep = prelude.def_map(db);
 +                &keep
 +            };
 +            def_map[prelude.local_id].scope.get(name)
 +        } else {
 +            PerNs::none()
 +        }
 +    }
 +}
index 5089ef2d8171769685a419f8b4e3b0eb15dd1d5a,0000000000000000000000000000000000000000..52b79cd0fdda2f5cf0d4a61c5f349717ea7f2744
mode 100644,000000..100644
--- /dev/null
@@@ -1,81 -1,0 +1,81 @@@
-                 // `#[proc_macro_derive(Trait, attibutes(helper1, helper2, ...))]`
 +//! Nameres-specific procedural macro data and helpers.
 +
 +use hir_expand::name::{AsName, Name};
 +use tt::{Leaf, TokenTree};
 +
 +use crate::attr::Attrs;
 +
 +#[derive(Debug, PartialEq, Eq)]
 +pub struct ProcMacroDef {
 +    pub name: Name,
 +    pub kind: ProcMacroKind,
 +}
 +
 +#[derive(Debug, PartialEq, Eq)]
 +pub enum ProcMacroKind {
 +    CustomDerive { helpers: Box<[Name]> },
 +    FnLike,
 +    Attr,
 +}
 +
 +impl ProcMacroKind {
 +    pub(super) fn to_basedb_kind(&self) -> base_db::ProcMacroKind {
 +        match self {
 +            ProcMacroKind::CustomDerive { .. } => base_db::ProcMacroKind::CustomDerive,
 +            ProcMacroKind::FnLike => base_db::ProcMacroKind::FuncLike,
 +            ProcMacroKind::Attr => base_db::ProcMacroKind::Attr,
 +        }
 +    }
 +}
 +
 +impl Attrs {
 +    #[rustfmt::skip]
 +    pub fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> {
 +        if self.is_proc_macro() {
 +            Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::FnLike })
 +        } else if self.is_proc_macro_attribute() {
 +            Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Attr })
 +        } else if self.by_key("proc_macro_derive").exists() {
 +            let derive = self.by_key("proc_macro_derive").tt_values().next()?;
 +
 +            match &*derive.token_trees {
 +                // `#[proc_macro_derive(Trait)]`
 +                [TokenTree::Leaf(Leaf::Ident(trait_name))] => Some(ProcMacroDef {
 +                    name: trait_name.as_name(),
 +                    kind: ProcMacroKind::CustomDerive { helpers: Box::new([]) },
 +                }),
 +
++                // `#[proc_macro_derive(Trait, attributes(helper1, helper2, ...))]`
 +                [
 +                    TokenTree::Leaf(Leaf::Ident(trait_name)),
 +                    TokenTree::Leaf(Leaf::Punct(comma)),
 +                    TokenTree::Leaf(Leaf::Ident(attributes)),
 +                    TokenTree::Subtree(helpers)
 +                ] if comma.char == ',' && attributes.text == "attributes" =>
 +                {
 +                    let helpers = helpers.token_trees.iter()
 +                        .filter(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Punct(comma)) if comma.char == ','))
 +                        .map(|tt| {
 +                            match tt {
 +                                TokenTree::Leaf(Leaf::Ident(helper)) => Some(helper.as_name()),
 +                                _ => None
 +                            }
 +                        })
 +                        .collect::<Option<Box<[_]>>>()?;
 +
 +                    Some(ProcMacroDef {
 +                        name: trait_name.as_name(),
 +                        kind: ProcMacroKind::CustomDerive { helpers },
 +                    })
 +                }
 +
 +                _ => {
 +                    tracing::trace!("malformed `#[proc_macro_derive]`: {}", derive);
 +                    None
 +                }
 +            }
 +        } else {
 +            None
 +        }
 +    }
 +}
index bf5bf10c4caaf7cf21a75a805878fb230ec352f0,0000000000000000000000000000000000000000..2bc1f8e926e97f04db9936a0862d36c36a7b255e
mode 100644,000000..100644
--- /dev/null
@@@ -1,95 -1,0 +1,107 @@@
 +//! In rust, it is possible to have a value, a type and a macro with the same
 +//! name without conflicts.
 +//!
 +//! `PerNs` (per namespace) captures this.
 +
 +use crate::{item_scope::ItemInNs, visibility::Visibility, MacroId, ModuleDefId};
 +
 +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 +pub struct PerNs {
 +    pub types: Option<(ModuleDefId, Visibility)>,
 +    pub values: Option<(ModuleDefId, Visibility)>,
 +    pub macros: Option<(MacroId, Visibility)>,
 +}
 +
 +impl Default for PerNs {
 +    fn default() -> Self {
 +        PerNs { types: None, values: None, macros: None }
 +    }
 +}
 +
 +impl PerNs {
 +    pub fn none() -> PerNs {
 +        PerNs { types: None, values: None, macros: None }
 +    }
 +
 +    pub fn values(t: ModuleDefId, v: Visibility) -> PerNs {
 +        PerNs { types: None, values: Some((t, v)), macros: None }
 +    }
 +
 +    pub fn types(t: ModuleDefId, v: Visibility) -> PerNs {
 +        PerNs { types: Some((t, v)), values: None, macros: None }
 +    }
 +
 +    pub fn both(types: ModuleDefId, values: ModuleDefId, v: Visibility) -> PerNs {
 +        PerNs { types: Some((types, v)), values: Some((values, v)), macros: None }
 +    }
 +
 +    pub fn macros(macro_: MacroId, v: Visibility) -> PerNs {
 +        PerNs { types: None, values: None, macros: Some((macro_, v)) }
 +    }
 +
 +    pub fn is_none(&self) -> bool {
 +        self.types.is_none() && self.values.is_none() && self.macros.is_none()
 +    }
 +
++    pub fn is_full(&self) -> bool {
++        self.types.is_some() && self.values.is_some() && self.macros.is_some()
++    }
++
 +    pub fn take_types(self) -> Option<ModuleDefId> {
 +        self.types.map(|it| it.0)
 +    }
 +
 +    pub fn take_types_vis(self) -> Option<(ModuleDefId, Visibility)> {
 +        self.types
 +    }
 +
 +    pub fn take_values(self) -> Option<ModuleDefId> {
 +        self.values.map(|it| it.0)
 +    }
 +
 +    pub fn take_macros(self) -> Option<MacroId> {
 +        self.macros.map(|it| it.0)
 +    }
 +
 +    pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs {
 +        let _p = profile::span("PerNs::filter_visibility");
 +        PerNs {
 +            types: self.types.filter(|(_, v)| f(*v)),
 +            values: self.values.filter(|(_, v)| f(*v)),
 +            macros: self.macros.filter(|(_, v)| f(*v)),
 +        }
 +    }
 +
 +    pub fn with_visibility(self, vis: Visibility) -> PerNs {
 +        PerNs {
 +            types: self.types.map(|(it, _)| (it, vis)),
 +            values: self.values.map(|(it, _)| (it, vis)),
 +            macros: self.macros.map(|(it, _)| (it, vis)),
 +        }
 +    }
 +
 +    pub fn or(self, other: PerNs) -> PerNs {
 +        PerNs {
 +            types: self.types.or(other.types),
 +            values: self.values.or(other.values),
 +            macros: self.macros.or(other.macros),
 +        }
 +    }
 +
++    pub fn or_else(self, f: impl FnOnce() -> PerNs) -> PerNs {
++        if self.is_full() {
++            self
++        } else {
++            self.or(f())
++        }
++    }
++
 +    pub fn iter_items(self) -> impl Iterator<Item = ItemInNs> {
 +        let _p = profile::span("PerNs::iter_items");
 +        self.types
 +            .map(|it| ItemInNs::Types(it.0))
 +            .into_iter()
 +            .chain(self.values.map(|it| ItemInNs::Values(it.0)).into_iter())
 +            .chain(self.macros.map(|it| ItemInNs::Macros(it.0)).into_iter())
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6636c8a23ca5fea4e31eef52f1d9d86ab0292359
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,209 @@@
++//! Display and pretty printing routines.
++
++use std::fmt::{self, Write};
++
++use hir_expand::mod_path::PathKind;
++use itertools::Itertools;
++
++use crate::{
++    intern::Interned,
++    path::{GenericArg, GenericArgs, Path},
++    type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
++};
++
++pub(crate) fn print_path(path: &Path, buf: &mut dyn Write) -> fmt::Result {
++    match path.type_anchor() {
++        Some(anchor) => {
++            write!(buf, "<")?;
++            print_type_ref(anchor, buf)?;
++            write!(buf, ">::")?;
++        }
++        None => match path.kind() {
++            PathKind::Plain => {}
++            PathKind::Super(0) => write!(buf, "self")?,
++            PathKind::Super(n) => {
++                for i in 0..*n {
++                    if i == 0 {
++                        buf.write_str("super")?;
++                    } else {
++                        buf.write_str("::super")?;
++                    }
++                }
++            }
++            PathKind::Crate => write!(buf, "crate")?,
++            PathKind::Abs => {}
++            PathKind::DollarCrate(_) => write!(buf, "$crate")?,
++        },
++    }
++
++    for (i, segment) in path.segments().iter().enumerate() {
++        if i != 0 || !matches!(path.kind(), PathKind::Plain) {
++            write!(buf, "::")?;
++        }
++
++        write!(buf, "{}", segment.name)?;
++        if let Some(generics) = segment.args_and_bindings {
++            write!(buf, "::<")?;
++            print_generic_args(generics, buf)?;
++
++            write!(buf, ">")?;
++        }
++    }
++
++    Ok(())
++}
++
++pub(crate) fn print_generic_args(generics: &GenericArgs, buf: &mut dyn Write) -> fmt::Result {
++    let mut first = true;
++    let args = if generics.has_self_type {
++        let (self_ty, args) = generics.args.split_first().unwrap();
++        write!(buf, "Self=")?;
++        print_generic_arg(self_ty, buf)?;
++        first = false;
++        args
++    } else {
++        &generics.args
++    };
++    for arg in args {
++        if !first {
++            write!(buf, ", ")?;
++        }
++        first = false;
++        print_generic_arg(arg, buf)?;
++    }
++    for binding in &generics.bindings {
++        if !first {
++            write!(buf, ", ")?;
++        }
++        first = false;
++        write!(buf, "{}", binding.name)?;
++        if !binding.bounds.is_empty() {
++            write!(buf, ": ")?;
++            print_type_bounds(&binding.bounds, buf)?;
++        }
++        if let Some(ty) = &binding.type_ref {
++            write!(buf, " = ")?;
++            print_type_ref(ty, buf)?;
++        }
++    }
++    Ok(())
++}
++
++pub(crate) fn print_generic_arg(arg: &GenericArg, buf: &mut dyn Write) -> fmt::Result {
++    match arg {
++        GenericArg::Type(ty) => print_type_ref(ty, buf),
++        GenericArg::Const(c) => write!(buf, "{}", c),
++        GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name),
++    }
++}
++
++pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Result {
++    // FIXME: deduplicate with `HirDisplay` impl
++    match type_ref {
++        TypeRef::Never => write!(buf, "!")?,
++        TypeRef::Placeholder => write!(buf, "_")?,
++        TypeRef::Tuple(fields) => {
++            write!(buf, "(")?;
++            for (i, field) in fields.iter().enumerate() {
++                if i != 0 {
++                    write!(buf, ", ")?;
++                }
++                print_type_ref(field, buf)?;
++            }
++            write!(buf, ")")?;
++        }
++        TypeRef::Path(path) => print_path(path, buf)?,
++        TypeRef::RawPtr(pointee, mtbl) => {
++            let mtbl = match mtbl {
++                Mutability::Shared => "*const",
++                Mutability::Mut => "*mut",
++            };
++            write!(buf, "{} ", mtbl)?;
++            print_type_ref(pointee, buf)?;
++        }
++        TypeRef::Reference(pointee, lt, mtbl) => {
++            let mtbl = match mtbl {
++                Mutability::Shared => "",
++                Mutability::Mut => "mut ",
++            };
++            write!(buf, "&")?;
++            if let Some(lt) = lt {
++                write!(buf, "{} ", lt.name)?;
++            }
++            write!(buf, "{}", mtbl)?;
++            print_type_ref(pointee, buf)?;
++        }
++        TypeRef::Array(elem, len) => {
++            write!(buf, "[")?;
++            print_type_ref(elem, buf)?;
++            write!(buf, "; {}]", len)?;
++        }
++        TypeRef::Slice(elem) => {
++            write!(buf, "[")?;
++            print_type_ref(elem, buf)?;
++            write!(buf, "]")?;
++        }
++        TypeRef::Fn(args_and_ret, varargs) => {
++            let ((_, return_type), args) =
++                args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
++            write!(buf, "fn(")?;
++            for (i, (_, typeref)) in args.iter().enumerate() {
++                if i != 0 {
++                    write!(buf, ", ")?;
++                }
++                print_type_ref(typeref, buf)?;
++            }
++            if *varargs {
++                if !args.is_empty() {
++                    write!(buf, ", ")?;
++                }
++                write!(buf, "...")?;
++            }
++            write!(buf, ") -> ")?;
++            print_type_ref(return_type, buf)?;
++        }
++        TypeRef::Macro(_ast_id) => {
++            write!(buf, "<macro>")?;
++        }
++        TypeRef::Error => write!(buf, "{{unknown}}")?,
++        TypeRef::ImplTrait(bounds) => {
++            write!(buf, "impl ")?;
++            print_type_bounds(bounds, buf)?;
++        }
++        TypeRef::DynTrait(bounds) => {
++            write!(buf, "dyn ")?;
++            print_type_bounds(bounds, buf)?;
++        }
++    }
++
++    Ok(())
++}
++
++pub(crate) fn print_type_bounds(
++    bounds: &[Interned<TypeBound>],
++    buf: &mut dyn Write,
++) -> fmt::Result {
++    for (i, bound) in bounds.iter().enumerate() {
++        if i != 0 {
++            write!(buf, " + ")?;
++        }
++
++        match bound.as_ref() {
++            TypeBound::Path(path, modifier) => {
++                match modifier {
++                    TraitBoundModifier::None => (),
++                    TraitBoundModifier::Maybe => write!(buf, "?")?,
++                }
++                print_path(path, buf)?;
++            }
++            TypeBound::ForLifetime(lifetimes, path) => {
++                write!(buf, "for<{}> ", lifetimes.iter().format(", "))?;
++                print_path(path, buf)?;
++            }
++            TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name)?,
++            TypeBound::Error => write!(buf, "{{unknown}}")?,
++        }
++    }
++
++    Ok(())
++}
index 9248059627d2af2b098d23b588911d1bf473817d,0000000000000000000000000000000000000000..5b4c71be7fb837eb688529d7d6ab976445655979
mode 100644,000000..100644
--- /dev/null
@@@ -1,486 -1,0 +1,490 @@@
 +//! HIR for references to types. Paths in these are not yet resolved. They can
 +//! be directly created from an ast::TypeRef, without further queries.
 +
 +use std::fmt::Write;
 +
 +use hir_expand::{
 +    name::{AsName, Name},
 +    AstId,
 +};
 +use syntax::ast::{self, HasName};
 +
 +use crate::{
 +    body::LowerCtx,
 +    builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
 +    expr::Literal,
 +    intern::Interned,
 +    path::Path,
 +};
 +
 +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 +pub enum Mutability {
 +    Shared,
 +    Mut,
 +}
 +
 +impl Mutability {
 +    pub fn from_mutable(mutable: bool) -> Mutability {
 +        if mutable {
 +            Mutability::Mut
 +        } else {
 +            Mutability::Shared
 +        }
 +    }
 +
 +    pub fn as_keyword_for_ref(self) -> &'static str {
 +        match self {
 +            Mutability::Shared => "",
 +            Mutability::Mut => "mut ",
 +        }
 +    }
 +
 +    pub fn as_keyword_for_ptr(self) -> &'static str {
 +        match self {
 +            Mutability::Shared => "const ",
 +            Mutability::Mut => "mut ",
 +        }
 +    }
 +
 +    /// Returns `true` if the mutability is [`Mut`].
 +    ///
 +    /// [`Mut`]: Mutability::Mut
 +    #[must_use]
 +    pub fn is_mut(&self) -> bool {
 +        matches!(self, Self::Mut)
 +    }
 +
 +    /// Returns `true` if the mutability is [`Shared`].
 +    ///
 +    /// [`Shared`]: Mutability::Shared
 +    #[must_use]
 +    pub fn is_shared(&self) -> bool {
 +        matches!(self, Self::Shared)
 +    }
 +}
 +
 +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 +pub enum Rawness {
 +    RawPtr,
 +    Ref,
 +}
 +
 +impl Rawness {
 +    pub fn from_raw(is_raw: bool) -> Rawness {
 +        if is_raw {
 +            Rawness::RawPtr
 +        } else {
 +            Rawness::Ref
 +        }
 +    }
++
++    pub fn is_raw(&self) -> bool {
++        matches!(self, Self::RawPtr)
++    }
 +}
 +
 +#[derive(Clone, PartialEq, Eq, Hash, Debug)]
 +pub struct TraitRef {
 +    pub path: Path,
 +}
 +
 +impl TraitRef {
 +    /// Converts an `ast::PathType` to a `hir::TraitRef`.
 +    pub(crate) fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Option<Self> {
 +        // FIXME: Use `Path::from_src`
 +        match node {
 +            ast::Type::PathType(path) => {
 +                path.path().and_then(|it| ctx.lower_path(it)).map(|path| TraitRef { path })
 +            }
 +            _ => None,
 +        }
 +    }
 +}
 +
 +/// Compare ty::Ty
 +///
 +/// Note: Most users of `TypeRef` that end up in the salsa database intern it using
 +/// `Interned<TypeRef>` to save space. But notably, nested `TypeRef`s are not interned, since that
 +/// does not seem to save any noticeable amount of memory.
 +#[derive(Clone, PartialEq, Eq, Hash, Debug)]
 +pub enum TypeRef {
 +    Never,
 +    Placeholder,
 +    Tuple(Vec<TypeRef>),
 +    Path(Path),
 +    RawPtr(Box<TypeRef>, Mutability),
 +    Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
 +    // FIXME: for full const generics, the latter element (length) here is going to have to be an
 +    // expression that is further lowered later in hir_ty.
 +    Array(Box<TypeRef>, ConstScalarOrPath),
 +    Slice(Box<TypeRef>),
 +    /// A fn pointer. Last element of the vector is the return type.
 +    Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/),
 +    ImplTrait(Vec<Interned<TypeBound>>),
 +    DynTrait(Vec<Interned<TypeBound>>),
 +    Macro(AstId<ast::MacroCall>),
 +    Error,
 +}
 +
 +#[derive(Clone, PartialEq, Eq, Hash, Debug)]
 +pub struct LifetimeRef {
 +    pub name: Name,
 +}
 +
 +impl LifetimeRef {
 +    pub(crate) fn new_name(name: Name) -> Self {
 +        LifetimeRef { name }
 +    }
 +
 +    pub(crate) fn new(lifetime: &ast::Lifetime) -> Self {
 +        LifetimeRef { name: Name::new_lifetime(lifetime) }
 +    }
 +
 +    pub fn missing() -> LifetimeRef {
 +        LifetimeRef { name: Name::missing() }
 +    }
 +}
 +
 +#[derive(Clone, PartialEq, Eq, Hash, Debug)]
 +pub enum TypeBound {
 +    Path(Path, TraitBoundModifier),
 +    ForLifetime(Box<[Name]>, Path),
 +    Lifetime(LifetimeRef),
 +    Error,
 +}
 +
 +/// A modifier on a bound, currently this is only used for `?Sized`, where the
 +/// modifier is `Maybe`.
 +#[derive(Clone, PartialEq, Eq, Hash, Debug)]
 +pub enum TraitBoundModifier {
 +    None,
 +    Maybe,
 +}
 +
 +impl TypeRef {
 +    /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
 +    pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Self {
 +        match node {
 +            ast::Type::ParenType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
 +            ast::Type::TupleType(inner) => {
 +                TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect())
 +            }
 +            ast::Type::NeverType(..) => TypeRef::Never,
 +            ast::Type::PathType(inner) => {
 +                // FIXME: Use `Path::from_src`
 +                inner
 +                    .path()
 +                    .and_then(|it| ctx.lower_path(it))
 +                    .map(TypeRef::Path)
 +                    .unwrap_or(TypeRef::Error)
 +            }
 +            ast::Type::PtrType(inner) => {
 +                let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
 +                let mutability = Mutability::from_mutable(inner.mut_token().is_some());
 +                TypeRef::RawPtr(Box::new(inner_ty), mutability)
 +            }
 +            ast::Type::ArrayType(inner) => {
 +                // FIXME: This is a hack. We should probably reuse the machinery of
 +                // `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the
 +                // `hir_ty` level, which would allow knowing the type of:
 +                // let v: [u8; 2 + 2] = [0u8; 4];
 +                let len = ConstScalarOrPath::from_expr_opt(inner.expr());
 +                TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len)
 +            }
 +            ast::Type::SliceType(inner) => {
 +                TypeRef::Slice(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())))
 +            }
 +            ast::Type::RefType(inner) => {
 +                let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
 +                let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(&lt));
 +                let mutability = Mutability::from_mutable(inner.mut_token().is_some());
 +                TypeRef::Reference(Box::new(inner_ty), lifetime, mutability)
 +            }
 +            ast::Type::InferType(_inner) => TypeRef::Placeholder,
 +            ast::Type::FnPtrType(inner) => {
 +                let ret_ty = inner
 +                    .ret_type()
 +                    .and_then(|rt| rt.ty())
 +                    .map(|it| TypeRef::from_ast(ctx, it))
 +                    .unwrap_or_else(|| TypeRef::Tuple(Vec::new()));
 +                let mut is_varargs = false;
 +                let mut params = if let Some(pl) = inner.param_list() {
 +                    if let Some(param) = pl.params().last() {
 +                        is_varargs = param.dotdotdot_token().is_some();
 +                    }
 +
 +                    pl.params()
 +                        .map(|it| {
 +                            let type_ref = TypeRef::from_ast_opt(ctx, it.ty());
 +                            let name = match it.pat() {
 +                                Some(ast::Pat::IdentPat(it)) => Some(
 +                                    it.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing),
 +                                ),
 +                                _ => None,
 +                            };
 +                            (name, type_ref)
 +                        })
 +                        .collect()
 +                } else {
 +                    Vec::new()
 +                };
 +                params.push((None, ret_ty));
 +                TypeRef::Fn(params, is_varargs)
 +            }
 +            // for types are close enough for our purposes to the inner type for now...
 +            ast::Type::ForType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
 +            ast::Type::ImplTraitType(inner) => {
 +                TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
 +            }
 +            ast::Type::DynTraitType(inner) => {
 +                TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
 +            }
 +            ast::Type::MacroType(mt) => match mt.macro_call() {
 +                Some(mc) => ctx.ast_id(ctx.db, &mc).map(TypeRef::Macro).unwrap_or(TypeRef::Error),
 +                None => TypeRef::Error,
 +            },
 +        }
 +    }
 +
 +    pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> Self {
 +        match node {
 +            Some(node) => TypeRef::from_ast(ctx, node),
 +            None => TypeRef::Error,
 +        }
 +    }
 +
 +    pub(crate) fn unit() -> TypeRef {
 +        TypeRef::Tuple(Vec::new())
 +    }
 +
 +    pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
 +        go(self, f);
 +
 +        fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
 +            f(type_ref);
 +            match type_ref {
 +                TypeRef::Fn(params, _) => {
 +                    params.iter().for_each(|(_, param_type)| go(param_type, f))
 +                }
 +                TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)),
 +                TypeRef::RawPtr(type_ref, _)
 +                | TypeRef::Reference(type_ref, ..)
 +                | TypeRef::Array(type_ref, _)
 +                | TypeRef::Slice(type_ref) => go(type_ref, f),
 +                TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
 +                    for bound in bounds {
 +                        match bound.as_ref() {
 +                            TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
 +                                go_path(path, f)
 +                            }
 +                            TypeBound::Lifetime(_) | TypeBound::Error => (),
 +                        }
 +                    }
 +                }
 +                TypeRef::Path(path) => go_path(path, f),
 +                TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
 +            };
 +        }
 +
 +        fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) {
 +            if let Some(type_ref) = path.type_anchor() {
 +                go(type_ref, f);
 +            }
 +            for segment in path.segments().iter() {
 +                if let Some(args_and_bindings) = segment.args_and_bindings {
 +                    for arg in &args_and_bindings.args {
 +                        match arg {
 +                            crate::path::GenericArg::Type(type_ref) => {
 +                                go(type_ref, f);
 +                            }
 +                            crate::path::GenericArg::Const(_)
 +                            | crate::path::GenericArg::Lifetime(_) => {}
 +                        }
 +                    }
 +                    for binding in &args_and_bindings.bindings {
 +                        if let Some(type_ref) = &binding.type_ref {
 +                            go(type_ref, f);
 +                        }
 +                        for bound in &binding.bounds {
 +                            match bound.as_ref() {
 +                                TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
 +                                    go_path(path, f)
 +                                }
 +                                TypeBound::Lifetime(_) | TypeBound::Error => (),
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +pub(crate) fn type_bounds_from_ast(
 +    lower_ctx: &LowerCtx<'_>,
 +    type_bounds_opt: Option<ast::TypeBoundList>,
 +) -> Vec<Interned<TypeBound>> {
 +    if let Some(type_bounds) = type_bounds_opt {
 +        type_bounds.bounds().map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))).collect()
 +    } else {
 +        vec![]
 +    }
 +}
 +
 +impl TypeBound {
 +    pub(crate) fn from_ast(ctx: &LowerCtx<'_>, node: ast::TypeBound) -> Self {
 +        let lower_path_type = |path_type: ast::PathType| ctx.lower_path(path_type.path()?);
 +
 +        match node.kind() {
 +            ast::TypeBoundKind::PathType(path_type) => {
 +                let m = match node.question_mark_token() {
 +                    Some(_) => TraitBoundModifier::Maybe,
 +                    None => TraitBoundModifier::None,
 +                };
 +                lower_path_type(path_type)
 +                    .map(|p| TypeBound::Path(p, m))
 +                    .unwrap_or(TypeBound::Error)
 +            }
 +            ast::TypeBoundKind::ForType(for_type) => {
 +                let lt_refs = match for_type.generic_param_list() {
 +                    Some(gpl) => gpl
 +                        .lifetime_params()
 +                        .flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(&lt)))
 +                        .collect(),
 +                    None => Box::default(),
 +                };
 +                let path = for_type.ty().and_then(|ty| match ty {
 +                    ast::Type::PathType(path_type) => lower_path_type(path_type),
 +                    _ => None,
 +                });
 +                match path {
 +                    Some(p) => TypeBound::ForLifetime(lt_refs, p),
 +                    None => TypeBound::Error,
 +                }
 +            }
 +            ast::TypeBoundKind::Lifetime(lifetime) => {
 +                TypeBound::Lifetime(LifetimeRef::new(&lifetime))
 +            }
 +        }
 +    }
 +
 +    pub fn as_path(&self) -> Option<(&Path, &TraitBoundModifier)> {
 +        match self {
 +            TypeBound::Path(p, m) => Some((p, m)),
 +            TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)),
 +            TypeBound::Lifetime(_) | TypeBound::Error => None,
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum ConstScalarOrPath {
 +    Scalar(ConstScalar),
 +    Path(Name),
 +}
 +
 +impl std::fmt::Display for ConstScalarOrPath {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        match self {
 +            ConstScalarOrPath::Scalar(s) => s.fmt(f),
 +            ConstScalarOrPath::Path(n) => n.fmt(f),
 +        }
 +    }
 +}
 +
 +impl ConstScalarOrPath {
 +    pub(crate) fn from_expr_opt(expr: Option<ast::Expr>) -> Self {
 +        match expr {
 +            Some(x) => Self::from_expr(x),
 +            None => Self::Scalar(ConstScalar::Unknown),
 +        }
 +    }
 +
 +    // FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this
 +    // parse stage.
 +    fn from_expr(expr: ast::Expr) -> Self {
 +        match expr {
 +            ast::Expr::PathExpr(p) => {
 +                match p.path().and_then(|x| x.segment()).and_then(|x| x.name_ref()) {
 +                    Some(x) => Self::Path(x.as_name()),
 +                    None => Self::Scalar(ConstScalar::Unknown),
 +                }
 +            }
 +            ast::Expr::PrefixExpr(prefix_expr) => match prefix_expr.op_kind() {
 +                Some(ast::UnaryOp::Neg) => {
 +                    let unsigned = Self::from_expr_opt(prefix_expr.expr());
 +                    // Add sign
 +                    match unsigned {
 +                        Self::Scalar(ConstScalar::UInt(num)) => {
 +                            Self::Scalar(ConstScalar::Int(-(num as i128)))
 +                        }
 +                        other => other,
 +                    }
 +                }
 +                _ => Self::from_expr_opt(prefix_expr.expr()),
 +            },
 +            ast::Expr::Literal(literal) => Self::Scalar(match literal.kind() {
 +                ast::LiteralKind::IntNumber(num) => {
 +                    num.value().map(ConstScalar::UInt).unwrap_or(ConstScalar::Unknown)
 +                }
 +                ast::LiteralKind::Char(c) => {
 +                    c.value().map(ConstScalar::Char).unwrap_or(ConstScalar::Unknown)
 +                }
 +                ast::LiteralKind::Bool(f) => ConstScalar::Bool(f),
 +                _ => ConstScalar::Unknown,
 +            }),
 +            _ => Self::Scalar(ConstScalar::Unknown),
 +        }
 +    }
 +}
 +
 +/// A concrete constant value
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum ConstScalar {
 +    Int(i128),
 +    UInt(u128),
 +    Bool(bool),
 +    Char(char),
 +
 +    /// Case of an unknown value that rustc might know but we don't
 +    // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
 +    // constants
 +    // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177
 +    // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348
 +    Unknown,
 +}
 +
 +impl ConstScalar {
 +    pub fn builtin_type(&self) -> BuiltinType {
 +        match self {
 +            ConstScalar::UInt(_) | ConstScalar::Unknown => BuiltinType::Uint(BuiltinUint::U128),
 +            ConstScalar::Int(_) => BuiltinType::Int(BuiltinInt::I128),
 +            ConstScalar::Char(_) => BuiltinType::Char,
 +            ConstScalar::Bool(_) => BuiltinType::Bool,
 +        }
 +    }
 +}
 +
 +impl From<Literal> for ConstScalar {
 +    fn from(literal: Literal) -> Self {
 +        match literal {
 +            Literal::Char(c) => Self::Char(c),
 +            Literal::Bool(flag) => Self::Bool(flag),
 +            Literal::Int(num, _) => Self::Int(num),
 +            Literal::Uint(num, _) => Self::UInt(num),
 +            _ => Self::Unknown,
 +        }
 +    }
 +}
 +
 +impl std::fmt::Display for ConstScalar {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
 +        match self {
 +            ConstScalar::Int(num) => num.fmt(f),
 +            ConstScalar::UInt(num) => num.fmt(f),
 +            ConstScalar::Bool(flag) => flag.fmt(f),
 +            ConstScalar::Char(c) => write!(f, "'{c}'"),
 +            ConstScalar::Unknown => f.write_char('_'),
 +        }
 +    }
 +}
index c1ddef03ba3b439f2795f38e9b74eafafa2c5ef2,0000000000000000000000000000000000000000..11c0a6764e9d89b745325a63537dd4dda1c10628
mode 100644,000000..100644
--- /dev/null
@@@ -1,181 -1,0 +1,176 @@@
- use syntax::{ast, match_ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr};
 +//! `AstIdMap` allows to create stable IDs for "large" syntax nodes like items
 +//! and macro calls.
 +//!
 +//! Specifically, it enumerates all items in a file and uses position of a an
 +//! item as an ID. That way, id's don't change unless the set of items itself
 +//! changes.
 +
 +use std::{
 +    any::type_name,
 +    fmt,
 +    hash::{BuildHasher, BuildHasherDefault, Hash, Hasher},
 +    marker::PhantomData,
 +};
 +
 +use la_arena::{Arena, Idx};
 +use profile::Count;
 +use rustc_hash::FxHasher;
-             match_ast! {
-                 match it {
-                     ast::Item(module_item) => {
-                         res.alloc(module_item.syntax());
-                         true
-                     },
-                     ast::BlockExpr(block) => {
-                         res.alloc(block.syntax());
-                         true
-                     },
-                     _ => false,
-                 }
++use syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr};
 +
 +/// `AstId` points to an AST node in a specific file.
 +pub struct FileAstId<N: AstNode> {
 +    raw: ErasedFileAstId,
 +    _ty: PhantomData<fn() -> N>,
 +}
 +
 +impl<N: AstNode> Clone for FileAstId<N> {
 +    fn clone(&self) -> FileAstId<N> {
 +        *self
 +    }
 +}
 +impl<N: AstNode> Copy for FileAstId<N> {}
 +
 +impl<N: AstNode> PartialEq for FileAstId<N> {
 +    fn eq(&self, other: &Self) -> bool {
 +        self.raw == other.raw
 +    }
 +}
 +impl<N: AstNode> Eq for FileAstId<N> {}
 +impl<N: AstNode> Hash for FileAstId<N> {
 +    fn hash<H: Hasher>(&self, hasher: &mut H) {
 +        self.raw.hash(hasher);
 +    }
 +}
 +
 +impl<N: AstNode> fmt::Debug for FileAstId<N> {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        write!(f, "FileAstId::<{}>({})", type_name::<N>(), self.raw.into_raw())
 +    }
 +}
 +
 +impl<N: AstNode> FileAstId<N> {
 +    // Can't make this a From implementation because of coherence
 +    pub fn upcast<M: AstNode>(self) -> FileAstId<M>
 +    where
 +        N: Into<M>,
 +    {
 +        FileAstId { raw: self.raw, _ty: PhantomData }
 +    }
 +}
 +
 +type ErasedFileAstId = Idx<SyntaxNodePtr>;
 +
 +/// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back.
 +#[derive(Default)]
 +pub struct AstIdMap {
 +    /// Maps stable id to unstable ptr.
 +    arena: Arena<SyntaxNodePtr>,
 +    /// Reverse: map ptr to id.
 +    map: hashbrown::HashMap<Idx<SyntaxNodePtr>, (), ()>,
 +    _c: Count<Self>,
 +}
 +
 +impl fmt::Debug for AstIdMap {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        f.debug_struct("AstIdMap").field("arena", &self.arena).finish()
 +    }
 +}
 +
 +impl PartialEq for AstIdMap {
 +    fn eq(&self, other: &Self) -> bool {
 +        self.arena == other.arena
 +    }
 +}
 +impl Eq for AstIdMap {}
 +
 +impl AstIdMap {
 +    pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap {
 +        assert!(node.parent().is_none());
 +        let mut res = AstIdMap::default();
 +        // By walking the tree in breadth-first order we make sure that parents
 +        // get lower ids then children. That is, adding a new child does not
 +        // change parent's id. This means that, say, adding a new function to a
 +        // trait does not change ids of top-level items, which helps caching.
 +        bdfs(node, |it| {
++            let kind = it.kind();
++            if ast::Item::can_cast(kind) || ast::BlockExpr::can_cast(kind) {
++                res.alloc(&it);
++                true
++            } else {
++                false
 +            }
 +        });
 +        res.map = hashbrown::HashMap::with_capacity_and_hasher(res.arena.len(), ());
 +        for (idx, ptr) in res.arena.iter() {
 +            let hash = hash_ptr(ptr);
 +            match res.map.raw_entry_mut().from_hash(hash, |idx2| *idx2 == idx) {
 +                hashbrown::hash_map::RawEntryMut::Occupied(_) => unreachable!(),
 +                hashbrown::hash_map::RawEntryMut::Vacant(entry) => {
 +                    entry.insert_with_hasher(hash, idx, (), |&idx| hash_ptr(&res.arena[idx]));
 +                }
 +            }
 +        }
 +        res
 +    }
 +
 +    pub fn ast_id<N: AstNode>(&self, item: &N) -> FileAstId<N> {
 +        let raw = self.erased_ast_id(item.syntax());
 +        FileAstId { raw, _ty: PhantomData }
 +    }
++
 +    fn erased_ast_id(&self, item: &SyntaxNode) -> ErasedFileAstId {
 +        let ptr = SyntaxNodePtr::new(item);
 +        let hash = hash_ptr(&ptr);
 +        match self.map.raw_entry().from_hash(hash, |&idx| self.arena[idx] == ptr) {
 +            Some((&idx, &())) => idx,
 +            None => panic!(
 +                "Can't find {:?} in AstIdMap:\n{:?}",
 +                item,
 +                self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
 +            ),
 +        }
 +    }
 +
 +    pub fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> {
 +        AstPtr::try_from_raw(self.arena[id.raw].clone()).unwrap()
 +    }
 +
 +    fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId {
 +        self.arena.alloc(SyntaxNodePtr::new(item))
 +    }
 +}
 +
 +fn hash_ptr(ptr: &SyntaxNodePtr) -> u64 {
 +    let mut hasher = BuildHasherDefault::<FxHasher>::default().build_hasher();
 +    ptr.hash(&mut hasher);
 +    hasher.finish()
 +}
 +
 +/// Walks the subtree in bdfs order, calling `f` for each node. What is bdfs
 +/// order? It is a mix of breadth-first and depth first orders. Nodes for which
 +/// `f` returns true are visited breadth-first, all the other nodes are explored
 +/// depth-first.
 +///
 +/// In other words, the size of the bfs queue is bound by the number of "true"
 +/// nodes.
 +fn bdfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode) -> bool) {
 +    let mut curr_layer = vec![node.clone()];
 +    let mut next_layer = vec![];
 +    while !curr_layer.is_empty() {
 +        curr_layer.drain(..).for_each(|node| {
 +            let mut preorder = node.preorder();
 +            while let Some(event) = preorder.next() {
 +                match event {
 +                    syntax::WalkEvent::Enter(node) => {
 +                        if f(node.clone()) {
 +                            next_layer.extend(node.children());
 +                            preorder.skip_subtree();
 +                        }
 +                    }
 +                    syntax::WalkEvent::Leave(_) => {}
 +                }
 +            }
 +        });
 +        std::mem::swap(&mut curr_layer, &mut next_layer);
 +    }
 +}
index bd60c3d26868cb347a8b8a4242f71f89664d3f05,0000000000000000000000000000000000000000..bc97ee15c7d3030be56a04047cbace837f8261a6
mode 100644,000000..100644
--- /dev/null
@@@ -1,509 -1,0 +1,513 @@@
-                     // FIXME
 +//! Defines database & queries for macro expansion.
 +
 +use std::sync::Arc;
 +
 +use base_db::{salsa, SourceDatabase};
 +use either::Either;
 +use limit::Limit;
 +use mbe::syntax_node_to_token_tree;
 +use rustc_hash::FxHashSet;
 +use syntax::{
 +    ast::{self, HasAttrs, HasDocComments},
 +    AstNode, GreenNode, Parse, SyntaxNode, SyntaxToken, T,
 +};
 +
 +use crate::{
 +    ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, fixup,
 +    hygiene::HygieneFrame, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander,
 +    ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind,
 +    MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander,
 +};
 +
 +/// Total limit on the number of tokens produced by any macro invocation.
 +///
 +/// If an invocation produces more tokens than this limit, it will not be stored in the database and
 +/// an error will be emitted.
 +///
 +/// Actual max for `analysis-stats .` at some point: 30672.
 +static TOKEN_LIMIT: Limit = Limit::new(524_288);
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum TokenExpander {
 +    /// Old-style `macro_rules` or the new macros 2.0
 +    DeclarativeMacro { mac: mbe::DeclarativeMacro, def_site_token_map: mbe::TokenMap },
 +    /// Stuff like `line!` and `file!`.
 +    Builtin(BuiltinFnLikeExpander),
 +    /// `global_allocator` and such.
 +    BuiltinAttr(BuiltinAttrExpander),
 +    /// `derive(Copy)` and such.
 +    BuiltinDerive(BuiltinDeriveExpander),
 +    /// The thing we love the most here in rust-analyzer -- procedural macros.
 +    ProcMacro(ProcMacroExpander),
 +}
 +
 +impl TokenExpander {
 +    fn expand(
 +        &self,
 +        db: &dyn AstDatabase,
 +        id: MacroCallId,
 +        tt: &tt::Subtree,
 +    ) -> ExpandResult<tt::Subtree> {
 +        match self {
 +            TokenExpander::DeclarativeMacro { mac, .. } => mac.expand(tt).map_err(Into::into),
 +            TokenExpander::Builtin(it) => it.expand(db, id, tt).map_err(Into::into),
 +            TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt),
 +            TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt),
 +            TokenExpander::ProcMacro(_) => {
 +                // We store the result in salsa db to prevent non-deterministic behavior in
 +                // some proc-macro implementation
 +                // See #4315 for details
 +                db.expand_proc_macro(id)
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
 +        match self {
 +            TokenExpander::DeclarativeMacro { mac, .. } => mac.map_id_down(id),
 +            TokenExpander::Builtin(..)
 +            | TokenExpander::BuiltinAttr(..)
 +            | TokenExpander::BuiltinDerive(..)
 +            | TokenExpander::ProcMacro(..) => id,
 +        }
 +    }
 +
 +    pub(crate) fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) {
 +        match self {
 +            TokenExpander::DeclarativeMacro { mac, .. } => mac.map_id_up(id),
 +            TokenExpander::Builtin(..)
 +            | TokenExpander::BuiltinAttr(..)
 +            | TokenExpander::BuiltinDerive(..)
 +            | TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call),
 +        }
 +    }
 +}
 +
 +// FIXME: rename to ExpandDatabase
 +#[salsa::query_group(AstDatabaseStorage)]
 +pub trait AstDatabase: SourceDatabase {
 +    fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
 +
 +    /// Main public API -- parses a hir file, not caring whether it's a real
 +    /// file or a macro expansion.
 +    #[salsa::transparent]
 +    fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode>;
 +    /// Implementation for the macro case.
 +    fn parse_macro_expansion(
 +        &self,
 +        macro_file: MacroFile,
 +    ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>>;
 +
 +    /// Macro ids. That's probably the tricksiest bit in rust-analyzer, and the
 +    /// reason why we use salsa at all.
 +    ///
 +    /// We encode macro definitions into ids of macro calls, this what allows us
 +    /// to be incremental.
 +    #[salsa::interned]
 +    fn intern_macro_call(&self, macro_call: MacroCallLoc) -> MacroCallId;
 +
 +    /// Lowers syntactic macro call to a token tree representation.
 +    #[salsa::transparent]
 +    fn macro_arg(
 +        &self,
 +        id: MacroCallId,
 +    ) -> Option<Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>>;
 +    /// Extracts syntax node, corresponding to a macro call. That's a firewall
 +    /// query, only typing in the macro call itself changes the returned
 +    /// subtree.
 +    fn macro_arg_text(&self, id: MacroCallId) -> Option<GreenNode>;
 +    /// Gets the expander for this macro. This compiles declarative macros, and
 +    /// just fetches procedural ones.
 +    fn macro_def(&self, id: MacroDefId) -> Result<Arc<TokenExpander>, mbe::ParseError>;
 +
 +    /// Expand macro call to a token tree. This query is LRUed (we keep 128 or so results in memory)
 +    fn macro_expand(&self, macro_call: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>>;
 +    /// Special case of the previous query for procedural macros. We can't LRU
 +    /// proc macros, since they are not deterministic in general, and
 +    /// non-determinism breaks salsa in a very, very, very bad way. @edwin0cheng
 +    /// heroically debugged this once!
 +    fn expand_proc_macro(&self, call: MacroCallId) -> ExpandResult<tt::Subtree>;
 +    /// Firewall query that returns the error from the `macro_expand` query.
 +    fn macro_expand_error(&self, macro_call: MacroCallId) -> Option<ExpandError>;
 +
 +    fn hygiene_frame(&self, file_id: HirFileId) -> Arc<HygieneFrame>;
 +}
 +
 +/// This expands the given macro call, but with different arguments. This is
 +/// used for completion, where we want to see what 'would happen' if we insert a
 +/// token. The `token_to_map` mapped down into the expansion, with the mapped
 +/// token returned.
 +pub fn expand_speculative(
 +    db: &dyn AstDatabase,
 +    actual_macro_call: MacroCallId,
 +    speculative_args: &SyntaxNode,
 +    token_to_map: SyntaxToken,
 +) -> Option<(SyntaxNode, SyntaxToken)> {
 +    let loc = db.lookup_intern_macro_call(actual_macro_call);
 +    let macro_def = db.macro_def(loc.def).ok()?;
 +    let token_range = token_to_map.text_range();
 +
 +    // Build the subtree and token mapping for the speculative args
 +    let censor = censor_for_macro_input(&loc, speculative_args);
 +    let mut fixups = fixup::fixup_syntax(speculative_args);
 +    fixups.replace.extend(censor.into_iter().map(|node| (node.into(), Vec::new())));
 +    let (mut tt, spec_args_tmap, _) = mbe::syntax_node_to_token_tree_with_modifications(
 +        speculative_args,
 +        fixups.token_map,
 +        fixups.next_id,
 +        fixups.replace,
 +        fixups.append,
 +    );
 +
 +    let (attr_arg, token_id) = match loc.kind {
 +        MacroCallKind::Attr { invoc_attr_index, is_derive, .. } => {
 +            let attr = if is_derive {
 +                // for pseudo-derive expansion we actually pass the attribute itself only
 +                ast::Attr::cast(speculative_args.clone())
 +            } else {
 +                // Attributes may have an input token tree, build the subtree and map for this as well
 +                // then try finding a token id for our token if it is inside this input subtree.
 +                let item = ast::Item::cast(speculative_args.clone())?;
 +                item.doc_comments_and_attrs().nth(invoc_attr_index as usize).and_then(Either::left)
 +            }?;
 +            match attr.token_tree() {
 +                Some(token_tree) => {
 +                    let (mut tree, map) = syntax_node_to_token_tree(attr.token_tree()?.syntax());
 +                    tree.delimiter = None;
 +
 +                    let shift = mbe::Shift::new(&tt);
 +                    shift.shift_all(&mut tree);
 +
 +                    let token_id = if token_tree.syntax().text_range().contains_range(token_range) {
 +                        let attr_input_start =
 +                            token_tree.left_delimiter_token()?.text_range().start();
 +                        let range = token_range.checked_sub(attr_input_start)?;
 +                        let token_id = shift.shift(map.token_by_range(range)?);
 +                        Some(token_id)
 +                    } else {
 +                        None
 +                    };
 +                    (Some(tree), token_id)
 +                }
 +                _ => (None, None),
 +            }
 +        }
 +        _ => (None, None),
 +    };
 +    let token_id = match token_id {
 +        Some(token_id) => token_id,
 +        // token wasn't inside an attribute input so it has to be in the general macro input
 +        None => {
 +            let range = token_range.checked_sub(speculative_args.text_range().start())?;
 +            let token_id = spec_args_tmap.token_by_range(range)?;
 +            macro_def.map_id_down(token_id)
 +        }
 +    };
 +
 +    // Do the actual expansion, we need to directly expand the proc macro due to the attribute args
 +    // Otherwise the expand query will fetch the non speculative attribute args and pass those instead.
 +    let mut speculative_expansion = match loc.def.kind {
 +        MacroDefKind::ProcMacro(expander, ..) => {
 +            tt.delimiter = None;
 +            expander.expand(db, loc.krate, &tt, attr_arg.as_ref())
 +        }
 +        MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => {
 +            pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?)
 +        }
 +        _ => macro_def.expand(db, actual_macro_call, &tt),
 +    };
 +
 +    let expand_to = macro_expand_to(db, actual_macro_call);
 +    fixup::reverse_fixups(&mut speculative_expansion.value, &spec_args_tmap, &fixups.undo_info);
 +    let (node, rev_tmap) = token_tree_to_syntax_node(&speculative_expansion.value, expand_to);
 +
 +    let range = rev_tmap.first_range_by_token(token_id, token_to_map.kind())?;
 +    let token = node.syntax_node().covering_element(range).into_token()?;
 +    Some((node.syntax_node(), token))
 +}
 +
 +fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
 +    let map = db.parse_or_expand(file_id).map(|it| AstIdMap::from_source(&it)).unwrap_or_default();
 +    Arc::new(map)
 +}
 +
 +fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> {
 +    match file_id.0 {
 +        HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
 +        HirFileIdRepr::MacroFile(macro_file) => {
 +            // FIXME: Note how we convert from `Parse` to `SyntaxNode` here,
 +            // forgetting about parse errors.
 +            db.parse_macro_expansion(macro_file).value.map(|(it, _)| it.syntax_node())
 +        }
 +    }
 +}
 +
 +fn parse_macro_expansion(
 +    db: &dyn AstDatabase,
 +    macro_file: MacroFile,
 +) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>> {
 +    let _p = profile::span("parse_macro_expansion");
 +    let result = db.macro_expand(macro_file.macro_call_id);
 +
 +    if let Some(err) = &result.err {
 +        // Note:
 +        // The final goal we would like to make all parse_macro success,
 +        // such that the following log will not call anyway.
 +        let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +        let node = loc.kind.to_node(db);
 +
 +        // collect parent information for warning log
 +        let parents =
 +            std::iter::successors(loc.kind.file_id().call_node(db), |it| it.file_id.call_node(db))
 +                .map(|n| format!("{:#}", n.value))
 +                .collect::<Vec<_>>()
 +                .join("\n");
 +
 +        tracing::debug!(
 +            "fail on macro_parse: (reason: {:?} macro_call: {:#}) parents: {}",
 +            err,
 +            node.value,
 +            parents
 +        );
 +    }
 +    let tt = match result.value {
 +        Some(tt) => tt,
 +        None => return ExpandResult { value: None, err: result.err },
 +    };
 +
 +    let expand_to = macro_expand_to(db, macro_file.macro_call_id);
 +
 +    tracing::debug!("expanded = {}", tt.as_debug_string());
 +    tracing::debug!("kind = {:?}", expand_to);
 +
 +    let (parse, rev_token_map) = token_tree_to_syntax_node(&tt, expand_to);
 +
 +    ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: result.err }
 +}
 +
 +fn macro_arg(
 +    db: &dyn AstDatabase,
 +    id: MacroCallId,
 +) -> Option<Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>> {
 +    let arg = db.macro_arg_text(id)?;
 +    let loc = db.lookup_intern_macro_call(id);
 +
 +    let node = SyntaxNode::new_root(arg);
 +    let censor = censor_for_macro_input(&loc, &node);
 +    let mut fixups = fixup::fixup_syntax(&node);
 +    fixups.replace.extend(censor.into_iter().map(|node| (node.into(), Vec::new())));
 +    let (mut tt, tmap, _) = mbe::syntax_node_to_token_tree_with_modifications(
 +        &node,
 +        fixups.token_map,
 +        fixups.next_id,
 +        fixups.replace,
 +        fixups.append,
 +    );
 +
 +    if loc.def.is_proc_macro() {
 +        // proc macros expect their inputs without parentheses, MBEs expect it with them included
 +        tt.delimiter = None;
 +    }
 +
 +    Some(Arc::new((tt, tmap, fixups.undo_info)))
 +}
 +
 +fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet<SyntaxNode> {
 +    (|| {
 +        let censor = match loc.kind {
 +            MacroCallKind::FnLike { .. } => return None,
 +            MacroCallKind::Derive { derive_attr_index, .. } => {
 +                cov_mark::hit!(derive_censoring);
 +                ast::Item::cast(node.clone())?
 +                    .attrs()
 +                    .take(derive_attr_index as usize + 1)
++                    // FIXME, this resolution should not be done syntactically
++                    // derive is a proper macro now, no longer builtin
++                    // But we do not have resolution at this stage, this means
++                    // we need to know about all macro calls for the given ast item here
++                    // so we require some kind of mapping...
 +                    .filter(|attr| attr.simple_name().as_deref() == Some("derive"))
 +                    .map(|it| it.syntax().clone())
 +                    .collect()
 +            }
 +            MacroCallKind::Attr { is_derive: true, .. } => return None,
 +            MacroCallKind::Attr { invoc_attr_index, .. } => {
 +                cov_mark::hit!(attribute_macro_attr_censoring);
 +                ast::Item::cast(node.clone())?
 +                    .doc_comments_and_attrs()
 +                    .nth(invoc_attr_index as usize)
 +                    .and_then(Either::left)
 +                    .map(|attr| attr.syntax().clone())
 +                    .into_iter()
 +                    .collect()
 +            }
 +        };
 +        Some(censor)
 +    })()
 +    .unwrap_or_default()
 +}
 +
 +fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> {
 +    let loc = db.lookup_intern_macro_call(id);
 +    let arg = loc.kind.arg(db)?;
 +    if matches!(loc.kind, MacroCallKind::FnLike { .. }) {
 +        let first = arg.first_child_or_token().map_or(T![.], |it| it.kind());
 +        let last = arg.last_child_or_token().map_or(T![.], |it| it.kind());
 +        let well_formed_tt =
 +            matches!((first, last), (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']));
 +        if !well_formed_tt {
 +            // Don't expand malformed (unbalanced) macro invocations. This is
 +            // less than ideal, but trying to expand unbalanced  macro calls
 +            // sometimes produces pathological, deeply nested code which breaks
 +            // all kinds of things.
 +            //
 +            // Some day, we'll have explicit recursion counters for all
 +            // recursive things, at which point this code might be removed.
 +            cov_mark::hit!(issue9358_bad_macro_stack_overflow);
 +            return None;
 +        }
 +    }
 +    Some(arg.green().into())
 +}
 +
 +fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Result<Arc<TokenExpander>, mbe::ParseError> {
 +    match id.kind {
 +        MacroDefKind::Declarative(ast_id) => {
 +            let (mac, def_site_token_map) = match ast_id.to_node(db) {
 +                ast::Macro::MacroRules(macro_rules) => {
 +                    let arg = macro_rules
 +                        .token_tree()
 +                        .ok_or_else(|| mbe::ParseError::Expected("expected a token tree".into()))?;
 +                    let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax());
 +                    let mac = mbe::DeclarativeMacro::parse_macro_rules(&tt)?;
 +                    (mac, def_site_token_map)
 +                }
 +                ast::Macro::MacroDef(macro_def) => {
 +                    let arg = macro_def
 +                        .body()
 +                        .ok_or_else(|| mbe::ParseError::Expected("expected a token tree".into()))?;
 +                    let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax());
 +                    let mac = mbe::DeclarativeMacro::parse_macro2(&tt)?;
 +                    (mac, def_site_token_map)
 +                }
 +            };
 +            Ok(Arc::new(TokenExpander::DeclarativeMacro { mac, def_site_token_map }))
 +        }
 +        MacroDefKind::BuiltIn(expander, _) => Ok(Arc::new(TokenExpander::Builtin(expander))),
 +        MacroDefKind::BuiltInAttr(expander, _) => {
 +            Ok(Arc::new(TokenExpander::BuiltinAttr(expander)))
 +        }
 +        MacroDefKind::BuiltInDerive(expander, _) => {
 +            Ok(Arc::new(TokenExpander::BuiltinDerive(expander)))
 +        }
 +        MacroDefKind::BuiltInEager(..) => {
 +            // FIXME: Return a random error here just to make the types align.
 +            // This obviously should do something real instead.
 +            Err(mbe::ParseError::UnexpectedToken("unexpected eager macro".into()))
 +        }
 +        MacroDefKind::ProcMacro(expander, ..) => Ok(Arc::new(TokenExpander::ProcMacro(expander))),
 +    }
 +}
 +
 +fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>> {
 +    let _p = profile::span("macro_expand");
 +    let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
 +    if let Some(eager) = &loc.eager {
 +        return ExpandResult {
 +            value: Some(eager.arg_or_expansion.clone()),
 +            // FIXME: There could be errors here!
 +            err: None,
 +        };
 +    }
 +
 +    let macro_arg = match db.macro_arg(id) {
 +        Some(it) => it,
 +        None => {
 +            return ExpandResult::only_err(ExpandError::Other(
 +                "Failed to lower macro args to token tree".into(),
 +            ))
 +        }
 +    };
 +
 +    let expander = match db.macro_def(loc.def) {
 +        Ok(it) => it,
 +        // FIXME: This is weird -- we effectively report macro *definition*
 +        // errors lazily, when we try to expand the macro. Instead, they should
 +        // be reported at the definition site (when we construct a def map).
 +        Err(err) => {
 +            return ExpandResult::only_err(ExpandError::Other(
 +                format!("invalid macro definition: {}", err).into(),
 +            ))
 +        }
 +    };
 +    let ExpandResult { value: mut tt, err } = expander.expand(db, id, &macro_arg.0);
 +    // Set a hard limit for the expanded tt
 +    let count = tt.count();
 +    if TOKEN_LIMIT.check(count).is_err() {
 +        return ExpandResult::only_err(ExpandError::Other(
 +            format!(
 +                "macro invocation exceeds token limit: produced {} tokens, limit is {}",
 +                count,
 +                TOKEN_LIMIT.inner(),
 +            )
 +            .into(),
 +        ));
 +    }
 +
 +    fixup::reverse_fixups(&mut tt, &macro_arg.1, &macro_arg.2);
 +
 +    ExpandResult { value: Some(Arc::new(tt)), err }
 +}
 +
 +fn macro_expand_error(db: &dyn AstDatabase, macro_call: MacroCallId) -> Option<ExpandError> {
 +    db.macro_expand(macro_call).err
 +}
 +
 +fn expand_proc_macro(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<tt::Subtree> {
 +    let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
 +    let macro_arg = match db.macro_arg(id) {
 +        Some(it) => it,
 +        None => {
 +            return ExpandResult::only_err(ExpandError::Other("No arguments for proc-macro".into()))
 +        }
 +    };
 +
 +    let expander = match loc.def.kind {
 +        MacroDefKind::ProcMacro(expander, ..) => expander,
 +        _ => unreachable!(),
 +    };
 +
 +    let attr_arg = match &loc.kind {
 +        MacroCallKind::Attr { attr_args, .. } => {
 +            let mut attr_args = attr_args.0.clone();
 +            mbe::Shift::new(&macro_arg.0).shift_all(&mut attr_args);
 +            Some(attr_args)
 +        }
 +        _ => None,
 +    };
 +
 +    expander.expand(db, loc.krate, &macro_arg.0, attr_arg.as_ref())
 +}
 +
 +fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> {
 +    Arc::new(HygieneFrame::new(db, file_id))
 +}
 +
 +fn macro_expand_to(db: &dyn AstDatabase, id: MacroCallId) -> ExpandTo {
 +    let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
 +    loc.kind.expand_to()
 +}
 +
 +fn token_tree_to_syntax_node(
 +    tt: &tt::Subtree,
 +    expand_to: ExpandTo,
 +) -> (Parse<SyntaxNode>, mbe::TokenMap) {
 +    let entry_point = match expand_to {
 +        ExpandTo::Statements => mbe::TopEntryPoint::MacroStmts,
 +        ExpandTo::Items => mbe::TopEntryPoint::MacroItems,
 +        ExpandTo::Pattern => mbe::TopEntryPoint::Pattern,
 +        ExpandTo::Type => mbe::TopEntryPoint::Type,
 +        ExpandTo::Expr => mbe::TopEntryPoint::Expr,
 +    };
 +    mbe::token_tree_to_syntax_node(tt, entry_point)
 +}
index 252293090bb0cdc3006c3f4ec58c7225ce97bf46,0000000000000000000000000000000000000000..d753d88470c442cb3c372494c2fc38720eb91573
mode 100644,000000..100644
--- /dev/null
@@@ -1,1000 -1,0 +1,999 @@@
-     // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander
 +//! `hir_expand` deals with macro expansion.
 +//!
 +//! Specifically, it implements a concept of `MacroFile` -- a file whose syntax
 +//! tree originates not from the text of some `FileId`, but from some macro
 +//! expansion.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +pub mod db;
 +pub mod ast_id_map;
 +pub mod name;
 +pub mod hygiene;
 +pub mod builtin_attr_macro;
 +pub mod builtin_derive_macro;
 +pub mod builtin_fn_macro;
 +pub mod proc_macro;
 +pub mod quote;
 +pub mod eager;
 +pub mod mod_path;
 +mod fixup;
 +
 +pub use mbe::{Origin, ValueResult};
 +
 +use std::{fmt, hash::Hash, iter, sync::Arc};
 +
 +use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange, ProcMacroKind};
 +use either::Either;
 +use syntax::{
 +    algo::{self, skip_trivia_token},
 +    ast::{self, AstNode, HasDocComments},
 +    Direction, SyntaxNode, SyntaxToken,
 +};
 +
 +use crate::{
 +    ast_id_map::FileAstId,
 +    builtin_attr_macro::BuiltinAttrExpander,
 +    builtin_derive_macro::BuiltinDeriveExpander,
 +    builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
 +    db::TokenExpander,
 +    mod_path::ModPath,
 +    proc_macro::ProcMacroExpander,
 +};
 +
 +pub type ExpandResult<T> = ValueResult<T, ExpandError>;
 +
 +#[derive(Debug, PartialEq, Eq, Clone)]
 +pub enum ExpandError {
 +    UnresolvedProcMacro(CrateId),
 +    Mbe(mbe::ExpandError),
 +    Other(Box<str>),
 +}
 +
 +impl From<mbe::ExpandError> for ExpandError {
 +    fn from(mbe: mbe::ExpandError) -> Self {
 +        Self::Mbe(mbe)
 +    }
 +}
 +
 +impl fmt::Display for ExpandError {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match self {
 +            ExpandError::UnresolvedProcMacro(_) => f.write_str("unresolved proc-macro"),
 +            ExpandError::Mbe(it) => it.fmt(f),
 +            ExpandError::Other(it) => f.write_str(it),
 +        }
 +    }
 +}
 +
 +/// Input to the analyzer is a set of files, where each file is identified by
 +/// `FileId` and contains source code. However, another source of source code in
 +/// Rust are macros: each macro can be thought of as producing a "temporary
 +/// file". To assign an id to such a file, we use the id of the macro call that
 +/// produced the file. So, a `HirFileId` is either a `FileId` (source code
 +/// written by user), or a `MacroCallId` (source code produced by macro).
 +///
 +/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
 +/// containing the call plus the offset of the macro call in the file. Note that
 +/// this is a recursive definition! However, the size_of of `HirFileId` is
 +/// finite (because everything bottoms out at the real `FileId`) and small
 +/// (`MacroCallId` uses the location interning. You can check details here:
 +/// <https://en.wikipedia.org/wiki/String_interning>).
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct HirFileId(HirFileIdRepr);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +enum HirFileIdRepr {
 +    FileId(FileId),
 +    MacroFile(MacroFile),
 +}
 +
 +impl From<FileId> for HirFileId {
 +    fn from(id: FileId) -> Self {
 +        HirFileId(HirFileIdRepr::FileId(id))
 +    }
 +}
 +
 +impl From<MacroFile> for HirFileId {
 +    fn from(id: MacroFile) -> Self {
 +        HirFileId(HirFileIdRepr::MacroFile(id))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct MacroFile {
 +    pub macro_call_id: MacroCallId,
 +}
 +
 +/// `MacroCallId` identifies a particular macro invocation, like
 +/// `println!("Hello, {}", world)`.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct MacroCallId(salsa::InternId);
 +impl_intern_key!(MacroCallId);
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct MacroCallLoc {
 +    pub def: MacroDefId,
 +    pub(crate) krate: CrateId,
 +    eager: Option<EagerCallInfo>,
 +    pub kind: MacroCallKind,
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct MacroDefId {
 +    pub krate: CrateId,
 +    pub kind: MacroDefKind,
 +    pub local_inner: bool,
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum MacroDefKind {
 +    Declarative(AstId<ast::Macro>),
 +    BuiltIn(BuiltinFnLikeExpander, AstId<ast::Macro>),
-             // the token is not inside an attribute's input so do the lookup in the macro_arg as ususal
 +    BuiltInAttr(BuiltinAttrExpander, AstId<ast::Macro>),
 +    BuiltInDerive(BuiltinDeriveExpander, AstId<ast::Macro>),
 +    BuiltInEager(EagerExpander, AstId<ast::Macro>),
 +    ProcMacro(ProcMacroExpander, ProcMacroKind, AstId<ast::Fn>),
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +struct EagerCallInfo {
 +    /// NOTE: This can be *either* the expansion result, *or* the argument to the eager macro!
 +    arg_or_expansion: Arc<tt::Subtree>,
 +    included_file: Option<FileId>,
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum MacroCallKind {
 +    FnLike {
 +        ast_id: AstId<ast::MacroCall>,
 +        expand_to: ExpandTo,
 +    },
 +    Derive {
 +        ast_id: AstId<ast::Adt>,
 +        /// Syntactical index of the invoking `#[derive]` attribute.
 +        ///
 +        /// Outer attributes are counted first, then inner attributes. This does not support
 +        /// out-of-line modules, which may have attributes spread across 2 files!
 +        derive_attr_index: u32,
 +        /// Index of the derive macro in the derive attribute
 +        derive_index: u32,
 +    },
 +    Attr {
 +        ast_id: AstId<ast::Item>,
 +        attr_args: Arc<(tt::Subtree, mbe::TokenMap)>,
 +        /// Syntactical index of the invoking `#[attribute]`.
 +        ///
 +        /// Outer attributes are counted first, then inner attributes. This does not support
 +        /// out-of-line modules, which may have attributes spread across 2 files!
 +        invoc_attr_index: u32,
 +        /// Whether this attribute is the `#[derive]` attribute.
 +        is_derive: bool,
 +    },
 +}
 +
 +impl HirFileId {
 +    /// For macro-expansion files, returns the file original source file the
 +    /// expansion originated from.
 +    pub fn original_file(self, db: &dyn db::AstDatabase) -> FileId {
 +        let mut file_id = self;
 +        loop {
 +            match file_id.0 {
 +                HirFileIdRepr::FileId(id) => break id,
 +                HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => {
 +                    let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_call_id);
 +                    file_id = match loc.eager {
 +                        Some(EagerCallInfo { included_file: Some(file), .. }) => file.into(),
 +                        _ => loc.kind.file_id(),
 +                    };
 +                }
 +            }
 +        }
 +    }
 +
 +    pub fn expansion_level(self, db: &dyn db::AstDatabase) -> u32 {
 +        let mut level = 0;
 +        let mut curr = self;
 +        while let HirFileIdRepr::MacroFile(macro_file) = curr.0 {
 +            let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +
 +            level += 1;
 +            curr = loc.kind.file_id();
 +        }
 +        level
 +    }
 +
 +    /// If this is a macro call, returns the syntax node of the call.
 +    pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
 +        match self.0 {
 +            HirFileIdRepr::FileId(_) => None,
 +            HirFileIdRepr::MacroFile(macro_file) => {
 +                let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +                Some(loc.kind.to_node(db))
 +            }
 +        }
 +    }
 +
 +    /// If this is a macro call, returns the syntax node of the very first macro call this file resides in.
 +    pub fn original_call_node(self, db: &dyn db::AstDatabase) -> Option<(FileId, SyntaxNode)> {
 +        let mut call = match self.0 {
 +            HirFileIdRepr::FileId(_) => return None,
 +            HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => {
 +                db.lookup_intern_macro_call(macro_call_id).kind.to_node(db)
 +            }
 +        };
 +        loop {
 +            match call.file_id.0 {
 +                HirFileIdRepr::FileId(file_id) => break Some((file_id, call.value)),
 +                HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => {
 +                    call = db.lookup_intern_macro_call(macro_call_id).kind.to_node(db);
 +                }
 +            }
 +        }
 +    }
 +
 +    /// Return expansion information if it is a macro-expansion file
 +    pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> {
 +        match self.0 {
 +            HirFileIdRepr::FileId(_) => None,
 +            HirFileIdRepr::MacroFile(macro_file) => {
 +                let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +
 +                let arg_tt = loc.kind.arg(db)?;
 +
 +                let macro_def = db.macro_def(loc.def).ok()?;
 +                let (parse, exp_map) = db.parse_macro_expansion(macro_file).value?;
 +                let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
 +
 +                let def = loc.def.ast_id().left().and_then(|id| {
 +                    let def_tt = match id.to_node(db) {
 +                        ast::Macro::MacroRules(mac) => mac.token_tree()?,
 +                        ast::Macro::MacroDef(_)
 +                            if matches!(*macro_def, TokenExpander::BuiltinAttr(_)) =>
 +                        {
 +                            return None
 +                        }
 +                        ast::Macro::MacroDef(mac) => mac.body()?,
 +                    };
 +                    Some(InFile::new(id.file_id, def_tt))
 +                });
 +                let attr_input_or_mac_def = def.or_else(|| match loc.kind {
 +                    MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
 +                        let tt = ast_id
 +                            .to_node(db)
 +                            .doc_comments_and_attrs()
 +                            .nth(invoc_attr_index as usize)
 +                            .and_then(Either::left)?
 +                            .token_tree()?;
 +                        Some(InFile::new(ast_id.file_id, tt))
 +                    }
 +                    _ => None,
 +                });
 +
 +                Some(ExpansionInfo {
 +                    expanded: InFile::new(self, parse.syntax_node()),
 +                    arg: InFile::new(loc.kind.file_id(), arg_tt),
 +                    attr_input_or_mac_def,
 +                    macro_arg_shift: mbe::Shift::new(&macro_arg.0),
 +                    macro_arg,
 +                    macro_def,
 +                    exp_map,
 +                })
 +            }
 +        }
 +    }
 +
 +    /// Indicate it is macro file generated for builtin derive
 +    pub fn is_builtin_derive(&self, db: &dyn db::AstDatabase) -> Option<InFile<ast::Attr>> {
 +        match self.0 {
 +            HirFileIdRepr::FileId(_) => None,
 +            HirFileIdRepr::MacroFile(macro_file) => {
 +                let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +                let attr = match loc.def.kind {
 +                    MacroDefKind::BuiltInDerive(..) => loc.kind.to_node(db),
 +                    _ => return None,
 +                };
 +                Some(attr.with_value(ast::Attr::cast(attr.value.clone())?))
 +            }
 +        }
 +    }
 +
 +    pub fn is_custom_derive(&self, db: &dyn db::AstDatabase) -> bool {
 +        match self.0 {
 +            HirFileIdRepr::FileId(_) => false,
 +            HirFileIdRepr::MacroFile(macro_file) => {
 +                let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +                matches!(loc.def.kind, MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _))
 +            }
 +        }
 +    }
 +
 +    /// Return whether this file is an include macro
 +    pub fn is_include_macro(&self, db: &dyn db::AstDatabase) -> bool {
 +        match self.0 {
 +            HirFileIdRepr::MacroFile(macro_file) => {
 +                let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +                matches!(loc.eager, Some(EagerCallInfo { included_file: Some(_), .. }))
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    /// Return whether this file is an attr macro
 +    pub fn is_attr_macro(&self, db: &dyn db::AstDatabase) -> bool {
 +        match self.0 {
 +            HirFileIdRepr::MacroFile(macro_file) => {
 +                let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +                matches!(loc.kind, MacroCallKind::Attr { .. })
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    /// Return whether this file is the pseudo expansion of the derive attribute.
 +    /// See [`crate::builtin_attr_macro::derive_attr_expand`].
 +    pub fn is_derive_attr_pseudo_expansion(&self, db: &dyn db::AstDatabase) -> bool {
 +        match self.0 {
 +            HirFileIdRepr::MacroFile(macro_file) => {
 +                let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +                matches!(loc.kind, MacroCallKind::Attr { is_derive: true, .. })
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    pub fn is_macro(self) -> bool {
 +        matches!(self.0, HirFileIdRepr::MacroFile(_))
 +    }
 +
 +    pub fn macro_file(self) -> Option<MacroFile> {
 +        match self.0 {
 +            HirFileIdRepr::FileId(_) => None,
 +            HirFileIdRepr::MacroFile(m) => Some(m),
 +        }
 +    }
 +}
 +
 +impl MacroDefId {
 +    pub fn as_lazy_macro(
 +        self,
 +        db: &dyn db::AstDatabase,
 +        krate: CrateId,
 +        kind: MacroCallKind,
 +    ) -> MacroCallId {
 +        db.intern_macro_call(MacroCallLoc { def: self, krate, eager: None, kind })
 +    }
 +
 +    pub fn ast_id(&self) -> Either<AstId<ast::Macro>, AstId<ast::Fn>> {
 +        let id = match self.kind {
 +            MacroDefKind::ProcMacro(.., id) => return Either::Right(id),
 +            MacroDefKind::Declarative(id)
 +            | MacroDefKind::BuiltIn(_, id)
 +            | MacroDefKind::BuiltInAttr(_, id)
 +            | MacroDefKind::BuiltInDerive(_, id)
 +            | MacroDefKind::BuiltInEager(_, id) => id,
 +        };
 +        Either::Left(id)
 +    }
 +
 +    pub fn is_proc_macro(&self) -> bool {
 +        matches!(self.kind, MacroDefKind::ProcMacro(..))
 +    }
 +
 +    pub fn is_attribute(&self) -> bool {
 +        matches!(
 +            self.kind,
 +            MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, ProcMacroKind::Attr, _)
 +        )
 +    }
 +}
 +
 +// FIXME: attribute indices do not account for `cfg_attr`, which means that we'll strip the whole
 +// `cfg_attr` instead of just one of the attributes it expands to
 +
 +impl MacroCallKind {
 +    /// Returns the file containing the macro invocation.
 +    fn file_id(&self) -> HirFileId {
 +        match *self {
 +            MacroCallKind::FnLike { ast_id: InFile { file_id, .. }, .. }
 +            | MacroCallKind::Derive { ast_id: InFile { file_id, .. }, .. }
 +            | MacroCallKind::Attr { ast_id: InFile { file_id, .. }, .. } => file_id,
 +        }
 +    }
 +
 +    pub fn to_node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> {
 +        match self {
 +            MacroCallKind::FnLike { ast_id, .. } => {
 +                ast_id.with_value(ast_id.to_node(db).syntax().clone())
 +            }
 +            MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
 +                // FIXME: handle `cfg_attr`
 +                ast_id.with_value(ast_id.to_node(db)).map(|it| {
 +                    it.doc_comments_and_attrs()
 +                        .nth(*derive_attr_index as usize)
 +                        .and_then(|it| match it {
 +                            Either::Left(attr) => Some(attr.syntax().clone()),
 +                            Either::Right(_) => None,
 +                        })
 +                        .unwrap_or_else(|| it.syntax().clone())
 +                })
 +            }
 +            MacroCallKind::Attr { ast_id, is_derive: true, invoc_attr_index, .. } => {
 +                // FIXME: handle `cfg_attr`
 +                ast_id.with_value(ast_id.to_node(db)).map(|it| {
 +                    it.doc_comments_and_attrs()
 +                        .nth(*invoc_attr_index as usize)
 +                        .and_then(|it| match it {
 +                            Either::Left(attr) => Some(attr.syntax().clone()),
 +                            Either::Right(_) => None,
 +                        })
 +                        .unwrap_or_else(|| it.syntax().clone())
 +                })
 +            }
 +            MacroCallKind::Attr { ast_id, .. } => {
 +                ast_id.with_value(ast_id.to_node(db).syntax().clone())
 +            }
 +        }
 +    }
 +
 +    /// Returns the original file range that best describes the location of this macro call.
 +    ///
 +    /// Unlike `MacroCallKind::original_call_range`, this also spans the item of attributes and derives.
 +    pub fn original_call_range_with_body(self, db: &dyn db::AstDatabase) -> FileRange {
 +        let mut kind = self;
 +        let file_id = loop {
 +            match kind.file_id().0 {
 +                HirFileIdRepr::MacroFile(file) => {
 +                    kind = db.lookup_intern_macro_call(file.macro_call_id).kind;
 +                }
 +                HirFileIdRepr::FileId(file_id) => break file_id,
 +            }
 +        };
 +
 +        let range = match kind {
 +            MacroCallKind::FnLike { ast_id, .. } => ast_id.to_node(db).syntax().text_range(),
 +            MacroCallKind::Derive { ast_id, .. } => ast_id.to_node(db).syntax().text_range(),
 +            MacroCallKind::Attr { ast_id, .. } => ast_id.to_node(db).syntax().text_range(),
 +        };
 +
 +        FileRange { range, file_id }
 +    }
 +
 +    /// Returns the original file range that best describes the location of this macro call.
 +    ///
 +    /// Here we try to roughly match what rustc does to improve diagnostics: fn-like macros
 +    /// get the whole `ast::MacroCall`, attribute macros get the attribute's range, and derives
 +    /// get only the specific derive that is being referred to.
 +    pub fn original_call_range(self, db: &dyn db::AstDatabase) -> FileRange {
 +        let mut kind = self;
 +        let file_id = loop {
 +            match kind.file_id().0 {
 +                HirFileIdRepr::MacroFile(file) => {
 +                    kind = db.lookup_intern_macro_call(file.macro_call_id).kind;
 +                }
 +                HirFileIdRepr::FileId(file_id) => break file_id,
 +            }
 +        };
 +
 +        let range = match kind {
 +            MacroCallKind::FnLike { ast_id, .. } => ast_id.to_node(db).syntax().text_range(),
 +            MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
 +                // FIXME: should be the range of the macro name, not the whole derive
 +                ast_id
 +                    .to_node(db)
 +                    .doc_comments_and_attrs()
 +                    .nth(derive_attr_index as usize)
 +                    .expect("missing derive")
 +                    .expect_left("derive is a doc comment?")
 +                    .syntax()
 +                    .text_range()
 +            }
 +            MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => ast_id
 +                .to_node(db)
 +                .doc_comments_and_attrs()
 +                .nth(invoc_attr_index as usize)
 +                .expect("missing attribute")
 +                .expect_left("attribute macro is a doc comment?")
 +                .syntax()
 +                .text_range(),
 +        };
 +
 +        FileRange { range, file_id }
 +    }
 +
 +    fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> {
 +        match self {
 +            MacroCallKind::FnLike { ast_id, .. } => {
 +                Some(ast_id.to_node(db).token_tree()?.syntax().clone())
 +            }
 +            MacroCallKind::Derive { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()),
 +            MacroCallKind::Attr { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()),
 +        }
 +    }
 +
 +    fn expand_to(&self) -> ExpandTo {
 +        match self {
 +            MacroCallKind::FnLike { expand_to, .. } => *expand_to,
 +            MacroCallKind::Derive { .. } => ExpandTo::Items,
 +            MacroCallKind::Attr { is_derive: true, .. } => ExpandTo::Statements,
 +            MacroCallKind::Attr { .. } => ExpandTo::Items, // is this always correct?
 +        }
 +    }
 +}
 +
 +impl MacroCallId {
 +    pub fn as_file(self) -> HirFileId {
 +        MacroFile { macro_call_id: self }.into()
 +    }
 +}
 +
 +/// ExpansionInfo mainly describes how to map text range between src and expanded macro
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub struct ExpansionInfo {
 +    expanded: InFile<SyntaxNode>,
 +    /// The argument TokenTree or item for attributes
 +    arg: InFile<SyntaxNode>,
 +    /// The `macro_rules!` or attribute input.
 +    attr_input_or_mac_def: Option<InFile<ast::TokenTree>>,
 +
 +    macro_def: Arc<TokenExpander>,
 +    macro_arg: Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>,
 +    /// A shift built from `macro_arg`'s subtree, relevant for attributes as the item is the macro arg
 +    /// and as such we need to shift tokens if they are part of an attributes input instead of their item.
 +    macro_arg_shift: mbe::Shift,
 +    exp_map: Arc<mbe::TokenMap>,
 +}
 +
 +impl ExpansionInfo {
 +    pub fn expanded(&self) -> InFile<SyntaxNode> {
 +        self.expanded.clone()
 +    }
 +
 +    pub fn call_node(&self) -> Option<InFile<SyntaxNode>> {
 +        Some(self.arg.with_value(self.arg.value.parent()?))
 +    }
 +
 +    /// Map a token down from macro input into the macro expansion.
 +    ///
 +    /// The inner workings of this function differ slightly depending on the type of macro we are dealing with:
 +    /// - declarative:
 +    ///     For declarative macros, we need to accommodate for the macro definition site(which acts as a second unchanging input)
 +    ///     , as tokens can mapped in and out of it.
 +    ///     To do this we shift all ids in the expansion by the maximum id of the definition site giving us an easy
 +    ///     way to map all the tokens.
 +    /// - attribute:
 +    ///     Attributes have two different inputs, the input tokentree in the attribute node and the item
 +    ///     the attribute is annotating. Similarly as for declarative macros we need to do a shift here
 +    ///     as well. Currently this is done by shifting the attribute input by the maximum id of the item.
 +    /// - function-like and derives:
 +    ///     Both of these only have one simple call site input so no special handling is required here.
 +    pub fn map_token_down(
 +        &self,
 +        db: &dyn db::AstDatabase,
 +        item: Option<ast::Item>,
 +        token: InFile<&SyntaxToken>,
 +    ) -> Option<impl Iterator<Item = InFile<SyntaxToken>> + '_> {
 +        assert_eq!(token.file_id, self.arg.file_id);
 +        let token_id_in_attr_input = if let Some(item) = item {
 +            // check if we are mapping down in an attribute input
 +            // this is a special case as attributes can have two inputs
 +            let call_id = self.expanded.file_id.macro_file()?.macro_call_id;
 +            let loc = db.lookup_intern_macro_call(call_id);
 +
 +            let token_range = token.value.text_range();
 +            match &loc.kind {
 +                MacroCallKind::Attr { attr_args, invoc_attr_index, is_derive, .. } => {
 +                    let attr = item
 +                        .doc_comments_and_attrs()
 +                        .nth(*invoc_attr_index as usize)
 +                        .and_then(Either::left)?;
 +                    match attr.token_tree() {
 +                        Some(token_tree)
 +                            if token_tree.syntax().text_range().contains_range(token_range) =>
 +                        {
 +                            let attr_input_start =
 +                                token_tree.left_delimiter_token()?.text_range().start();
 +                            let relative_range =
 +                                token.value.text_range().checked_sub(attr_input_start)?;
 +                            // shift by the item's tree's max id
 +                            let token_id = attr_args.1.token_by_range(relative_range)?;
 +                            let token_id = if *is_derive {
 +                                // we do not shift for `#[derive]`, as we only need to downmap the derive attribute tokens
 +                                token_id
 +                            } else {
 +                                self.macro_arg_shift.shift(token_id)
 +                            };
 +                            Some(token_id)
 +                        }
 +                        _ => None,
 +                    }
 +                }
 +                _ => None,
 +            }
 +        } else {
 +            None
 +        };
 +
 +        let token_id = match token_id_in_attr_input {
 +            Some(token_id) => token_id,
++            // the token is not inside an attribute's input so do the lookup in the macro_arg as usual
 +            None => {
 +                let relative_range =
 +                    token.value.text_range().checked_sub(self.arg.value.text_range().start())?;
 +                let token_id = self.macro_arg.1.token_by_range(relative_range)?;
 +                // conditionally shift the id by a declaratives macro definition
 +                self.macro_def.map_id_down(token_id)
 +            }
 +        };
 +
 +        let tokens = self
 +            .exp_map
 +            .ranges_by_token(token_id, token.value.kind())
 +            .flat_map(move |range| self.expanded.value.covering_element(range).into_token());
 +
 +        Some(tokens.map(move |token| self.expanded.with_value(token)))
 +    }
 +
 +    /// Map a token up out of the expansion it resides in into the arguments of the macro call of the expansion.
 +    pub fn map_token_up(
 +        &self,
 +        db: &dyn db::AstDatabase,
 +        token: InFile<&SyntaxToken>,
 +    ) -> Option<(InFile<SyntaxToken>, Origin)> {
 +        // Fetch the id through its text range,
 +        let token_id = self.exp_map.token_by_range(token.value.text_range())?;
 +        // conditionally unshifting the id to accommodate for macro-rules def site
 +        let (mut token_id, origin) = self.macro_def.map_id_up(token_id);
 +
 +        let call_id = self.expanded.file_id.macro_file()?.macro_call_id;
 +        let loc = db.lookup_intern_macro_call(call_id);
 +
 +        // Attributes are a bit special for us, they have two inputs, the input tokentree and the annotated item.
 +        let (token_map, tt) = match &loc.kind {
 +            MacroCallKind::Attr { attr_args, is_derive: true, .. } => {
 +                (&attr_args.1, self.attr_input_or_mac_def.clone()?.syntax().cloned())
 +            }
 +            MacroCallKind::Attr { attr_args, .. } => {
 +                // try unshifting the the token id, if unshifting fails, the token resides in the non-item attribute input
 +                // note that the `TokenExpander::map_id_up` earlier only unshifts for declarative macros, so we don't double unshift with this
 +                match self.macro_arg_shift.unshift(token_id) {
 +                    Some(unshifted) => {
 +                        token_id = unshifted;
 +                        (&attr_args.1, self.attr_input_or_mac_def.clone()?.syntax().cloned())
 +                    }
 +                    None => (&self.macro_arg.1, self.arg.clone()),
 +                }
 +            }
 +            _ => match origin {
 +                mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()),
 +                mbe::Origin::Def => match (&*self.macro_def, &self.attr_input_or_mac_def) {
 +                    (TokenExpander::DeclarativeMacro { def_site_token_map, .. }, Some(tt)) => {
 +                        (def_site_token_map, tt.syntax().cloned())
 +                    }
 +                    _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"),
 +                },
 +            },
 +        };
 +
 +        let range = token_map.first_range_by_token(token_id, token.value.kind())?;
 +        let token =
 +            tt.value.covering_element(range + tt.value.text_range().start()).into_token()?;
 +        Some((tt.with_value(token), origin))
 +    }
 +}
 +
 +/// `AstId` points to an AST node in any file.
 +///
 +/// It is stable across reparses, and can be used as salsa key/value.
 +pub type AstId<N> = InFile<FileAstId<N>>;
 +
 +impl<N: AstNode> AstId<N> {
 +    pub fn to_node(&self, db: &dyn db::AstDatabase) -> N {
 +        let root = db.parse_or_expand(self.file_id).unwrap();
 +        db.ast_id_map(self.file_id).get(self.value).to_node(&root)
 +    }
 +}
 +
 +/// `InFile<T>` stores a value of `T` inside a particular file/syntax tree.
 +///
 +/// Typical usages are:
 +///
 +/// * `InFile<SyntaxNode>` -- syntax node in a file
 +/// * `InFile<ast::FnDef>` -- ast node in a file
 +/// * `InFile<TextSize>` -- offset in a file
 +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
 +pub struct InFile<T> {
 +    pub file_id: HirFileId,
 +    pub value: T,
 +}
 +
 +impl<T> InFile<T> {
 +    pub fn new(file_id: HirFileId, value: T) -> InFile<T> {
 +        InFile { file_id, value }
 +    }
 +
 +    pub fn with_value<U>(&self, value: U) -> InFile<U> {
 +        InFile::new(self.file_id, value)
 +    }
 +
 +    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> InFile<U> {
 +        InFile::new(self.file_id, f(self.value))
 +    }
 +
 +    pub fn as_ref(&self) -> InFile<&T> {
 +        self.with_value(&self.value)
 +    }
 +
 +    pub fn file_syntax(&self, db: &dyn db::AstDatabase) -> SyntaxNode {
 +        db.parse_or_expand(self.file_id).expect("source created from invalid file")
 +    }
 +}
 +
 +impl<T: Clone> InFile<&T> {
 +    pub fn cloned(&self) -> InFile<T> {
 +        self.with_value(self.value.clone())
 +    }
 +}
 +
 +impl<T> InFile<Option<T>> {
 +    pub fn transpose(self) -> Option<InFile<T>> {
 +        let value = self.value?;
 +        Some(InFile::new(self.file_id, value))
 +    }
 +}
 +
 +impl<'a> InFile<&'a SyntaxNode> {
 +    pub fn ancestors_with_macros(
 +        self,
 +        db: &dyn db::AstDatabase,
 +    ) -> impl Iterator<Item = InFile<SyntaxNode>> + Clone + '_ {
 +        iter::successors(Some(self.cloned()), move |node| match node.value.parent() {
 +            Some(parent) => Some(node.with_value(parent)),
 +            None => node.file_id.call_node(db),
 +        })
 +    }
 +
 +    /// Skips the attributed item that caused the macro invocation we are climbing up
 +    pub fn ancestors_with_macros_skip_attr_item(
 +        self,
 +        db: &dyn db::AstDatabase,
 +    ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
 +        let succ = move |node: &InFile<SyntaxNode>| match node.value.parent() {
 +            Some(parent) => Some(node.with_value(parent)),
 +            None => {
 +                let parent_node = node.file_id.call_node(db)?;
 +                if node.file_id.is_attr_macro(db) {
 +                    // macro call was an attributed item, skip it
 +                    // FIXME: does this fail if this is a direct expansion of another macro?
 +                    parent_node.map(|node| node.parent()).transpose()
 +                } else {
 +                    Some(parent_node)
 +                }
 +            }
 +        };
 +        iter::successors(succ(&self.cloned()), succ)
 +    }
 +
 +    /// Falls back to the macro call range if the node cannot be mapped up fully.
 +    ///
 +    /// For attributes and derives, this will point back to the attribute only.
 +    /// For the entire item `InFile::use original_file_range_full`.
 +    pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange {
 +        match self.file_id.0 {
 +            HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
 +            HirFileIdRepr::MacroFile(mac_file) => {
 +                if let Some(res) = self.original_file_range_opt(db) {
 +                    return res;
 +                }
 +                // Fall back to whole macro call.
 +                let loc = db.lookup_intern_macro_call(mac_file.macro_call_id);
 +                loc.kind.original_call_range(db)
 +            }
 +        }
 +    }
 +
 +    /// Attempts to map the syntax node back up its macro calls.
 +    pub fn original_file_range_opt(self, db: &dyn db::AstDatabase) -> Option<FileRange> {
 +        match ascend_node_border_tokens(db, self) {
 +            Some(InFile { file_id, value: (first, last) }) => {
 +                let original_file = file_id.original_file(db);
 +                let range = first.text_range().cover(last.text_range());
 +                if file_id != original_file.into() {
 +                    tracing::error!("Failed mapping up more for {:?}", range);
 +                    return None;
 +                }
 +                Some(FileRange { file_id: original_file, range })
 +            }
 +            _ if !self.file_id.is_macro() => Some(FileRange {
 +                file_id: self.file_id.original_file(db),
 +                range: self.value.text_range(),
 +            }),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +impl InFile<SyntaxToken> {
 +    pub fn upmap(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxToken>> {
 +        let expansion = self.file_id.expansion_info(db)?;
 +        expansion.map_token_up(db, self.as_ref()).map(|(it, _)| it)
 +    }
 +
 +    /// Falls back to the macro call range if the node cannot be mapped up fully.
 +    pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange {
 +        match self.file_id.0 {
 +            HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
 +            HirFileIdRepr::MacroFile(mac_file) => {
 +                if let Some(res) = self.original_file_range_opt(db) {
 +                    return res;
 +                }
 +                // Fall back to whole macro call.
 +                let loc = db.lookup_intern_macro_call(mac_file.macro_call_id);
 +                loc.kind.original_call_range(db)
 +            }
 +        }
 +    }
 +
 +    /// Attempts to map the syntax node back up its macro calls.
 +    pub fn original_file_range_opt(self, db: &dyn db::AstDatabase) -> Option<FileRange> {
 +        match self.file_id.0 {
 +            HirFileIdRepr::FileId(file_id) => {
 +                Some(FileRange { file_id, range: self.value.text_range() })
 +            }
 +            HirFileIdRepr::MacroFile(_) => {
 +                let expansion = self.file_id.expansion_info(db)?;
 +                let InFile { file_id, value } = ascend_call_token(db, &expansion, self)?;
 +                let original_file = file_id.original_file(db);
 +                if file_id != original_file.into() {
 +                    return None;
 +                }
 +                Some(FileRange { file_id: original_file, range: value.text_range() })
 +            }
 +        }
 +    }
 +
 +    pub fn ancestors_with_macros(
 +        self,
 +        db: &dyn db::AstDatabase,
 +    ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
 +        self.value.parent().into_iter().flat_map({
 +            let file_id = self.file_id;
 +            move |parent| InFile::new(file_id, &parent).ancestors_with_macros(db)
 +        })
 +    }
 +}
 +
 +fn ascend_node_border_tokens(
 +    db: &dyn db::AstDatabase,
 +    InFile { file_id, value: node }: InFile<&SyntaxNode>,
 +) -> Option<InFile<(SyntaxToken, SyntaxToken)>> {
 +    let expansion = file_id.expansion_info(db)?;
 +
 +    let first_token = |node: &SyntaxNode| skip_trivia_token(node.first_token()?, Direction::Next);
 +    let last_token = |node: &SyntaxNode| skip_trivia_token(node.last_token()?, Direction::Prev);
 +
 +    let first = first_token(node)?;
 +    let last = last_token(node)?;
 +    let first = ascend_call_token(db, &expansion, InFile::new(file_id, first))?;
 +    let last = ascend_call_token(db, &expansion, InFile::new(file_id, last))?;
 +    (first.file_id == last.file_id).then(|| InFile::new(first.file_id, (first.value, last.value)))
 +}
 +
 +fn ascend_call_token(
 +    db: &dyn db::AstDatabase,
 +    expansion: &ExpansionInfo,
 +    token: InFile<SyntaxToken>,
 +) -> Option<InFile<SyntaxToken>> {
 +    let mut mapping = expansion.map_token_up(db, token.as_ref())?;
 +    while let (mapped, Origin::Call) = mapping {
 +        match mapped.file_id.expansion_info(db) {
 +            Some(info) => mapping = info.map_token_up(db, mapped.as_ref())?,
 +            None => return Some(mapped),
 +        }
 +    }
 +    None
 +}
 +
 +impl<N: AstNode> InFile<N> {
 +    pub fn descendants<T: AstNode>(self) -> impl Iterator<Item = InFile<T>> {
 +        self.value.syntax().descendants().filter_map(T::cast).map(move |n| self.with_value(n))
 +    }
 +
 +    pub fn original_ast_node(self, db: &dyn db::AstDatabase) -> Option<InFile<N>> {
 +        // This kind of upmapping can only be achieved in attribute expanded files,
 +        // as we don't have node inputs otherwise and  therefor can't find an `N` node in the input
 +        if !self.file_id.is_macro() {
 +            return Some(self);
 +        } else if !self.file_id.is_attr_macro(db) {
 +            return None;
 +        }
 +
 +        if let Some(InFile { file_id, value: (first, last) }) =
 +            ascend_node_border_tokens(db, self.syntax())
 +        {
 +            if file_id.is_macro() {
 +                let range = first.text_range().cover(last.text_range());
 +                tracing::error!("Failed mapping out of macro file for {:?}", range);
 +                return None;
 +            }
 +            // FIXME: This heuristic is brittle and with the right macro may select completely unrelated nodes
 +            let anc = algo::least_common_ancestor(&first.parent()?, &last.parent()?)?;
 +            let value = anc.ancestors().find_map(N::cast)?;
 +            return Some(InFile::new(file_id, value));
 +        }
 +        None
 +    }
 +
 +    pub fn syntax(&self) -> InFile<&SyntaxNode> {
 +        self.with_value(self.value.syntax())
 +    }
 +}
 +
 +/// In Rust, macros expand token trees to token trees. When we want to turn a
 +/// token tree into an AST node, we need to figure out what kind of AST node we
 +/// want: something like `foo` can be a type, an expression, or a pattern.
 +///
 +/// Naively, one would think that "what this expands to" is a property of a
 +/// particular macro: macro `m1` returns an item, while macro `m2` returns an
 +/// expression, etc. That's not the case -- macros are polymorphic in the
 +/// result, and can expand to any type of the AST node.
 +///
 +/// What defines the actual AST node is the syntactic context of the macro
 +/// invocation. As a contrived example, in `let T![*] = T![*];` the first `T`
 +/// expands to a pattern, while the second one expands to an expression.
 +///
 +/// `ExpandTo` captures this bit of information about a particular macro call
 +/// site.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum ExpandTo {
 +    Statements,
 +    Items,
 +    Pattern,
 +    Type,
 +    Expr,
 +}
 +
 +impl ExpandTo {
 +    pub fn from_call_site(call: &ast::MacroCall) -> ExpandTo {
 +        use syntax::SyntaxKind::*;
 +
 +        let syn = call.syntax();
 +
 +        let parent = match syn.parent() {
 +            Some(it) => it,
 +            None => return ExpandTo::Statements,
 +        };
 +
 +        // FIXME: macros in statement position are treated as expression statements, they should
 +        // probably be their own statement kind. The *grand*parent indicates what's valid.
 +        if parent.kind() == MACRO_EXPR
 +            && parent
 +                .parent()
 +                .map_or(true, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS))
 +        {
 +            return ExpandTo::Statements;
 +        }
 +
 +        match parent.kind() {
 +            MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => ExpandTo::Items,
 +            MACRO_STMTS | EXPR_STMT | STMT_LIST => ExpandTo::Statements,
 +            MACRO_PAT => ExpandTo::Pattern,
 +            MACRO_TYPE => ExpandTo::Type,
 +
 +            ARG_LIST | ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BREAK_EXPR | CALL_EXPR | CAST_EXPR
 +            | CLOSURE_EXPR | FIELD_EXPR | FOR_EXPR | IF_EXPR | INDEX_EXPR | LET_EXPR
 +            | MATCH_ARM | MATCH_EXPR | MATCH_GUARD | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR
 +            | PREFIX_EXPR | RANGE_EXPR | RECORD_EXPR_FIELD | REF_EXPR | RETURN_EXPR | TRY_EXPR
 +            | TUPLE_EXPR | WHILE_EXPR | MACRO_EXPR => ExpandTo::Expr,
 +            _ => {
 +                // Unknown , Just guess it is `Items`
 +                ExpandTo::Items
 +            }
 +        }
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub struct UnresolvedMacro {
 +    pub path: ModPath,
 +}
index d0f73ec8208c60e52b2a38de539257b3321d98c9,0000000000000000000000000000000000000000..d7586d129b768b1e639b915df81f51aa4a5c89b5
mode 100644,000000..100644
--- /dev/null
@@@ -1,276 -1,0 +1,277 @@@
 +//! 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 87c663eec8e81c2deea72c1c6e41c49c55f383cf,0000000000000000000000000000000000000000..2b859f775095beb0e005fb1657e59d001e933408
mode 100644,000000..100644
--- /dev/null
@@@ -1,437 -1,0 +1,445 @@@
-         // When `raw_text` starts with "r#" but the name does not coincide with any
-         // keyword, we never need the prefix so we strip it.
 +//! 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,
 +        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,
 +        // 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 5cd444c1ad3bd6b58dca6fc5a001ce12e91b8ed3,0000000000000000000000000000000000000000..7f143f396c765055c0a9b54702129d163866194d
mode 100644,000000..100644
--- /dev/null
@@@ -1,44 -1,0 +1,44 @@@
- chalk-solve = { version = "0.83.0", default-features = false }
- chalk-ir = "0.83.0"
- chalk-recursive = { version = "0.83.0", default-features = false }
 +[package]
 +name = "hir-ty"
 +version = "0.0.0"
 +description = "TBD"
 +license = "MIT OR Apache-2.0"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
 +cov-mark = "2.0.0-pre.1"
 +itertools = "0.10.3"
 +arrayvec = "0.7.2"
 +smallvec = "1.9.0"
 +ena = "0.14.0"
 +tracing = "0.1.35"
 +rustc-hash = "1.1.0"
 +scoped-tls = "1.0.0"
++chalk-solve = { version = "0.84.0", default-features = false }
++chalk-ir = "0.84.0"
++chalk-recursive = { version = "0.84.0", default-features = false }
 +la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
 +once_cell = "1.12.0"
 +typed-arena = "2.0.1"
 +
 +stdx = { path = "../stdx", version = "0.0.0" }
 +hir-def = { path = "../hir-def", version = "0.0.0" }
 +hir-expand = { path = "../hir-expand", version = "0.0.0" }
 +base-db = { path = "../base-db", version = "0.0.0" }
 +profile = { path = "../profile", version = "0.0.0" }
 +syntax = { path = "../syntax", version = "0.0.0" }
 +limit = { path = "../limit", version = "0.0.0" }
 +
 +[dev-dependencies]
 +test-utils = { path = "../test-utils" }
 +expect-test = "1.4.0"
 +tracing = "0.1.35"
 +tracing-subscriber = { version = "0.3.14", default-features = false, features = [
 +    "env-filter",
 +    "registry",
 +] }
 +tracing-tree = "0.2.1"
index 46eeea0e6fc4e8863e8128ae1291abeeff118d41,0000000000000000000000000000000000000000..5df48e5fdcbaf40502d0aa11f3b9bd666132b771
mode 100644,000000..100644
--- /dev/null
@@@ -1,1088 -1,0 +1,1092 @@@
-         let trait_ = self.resolve_lang_item(name![future_trait])?.as_trait()?;
 +//! 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 librustc_typeck/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,
 +    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, 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)),
 +    }
 +
 +    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 },
 +    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 Unknown 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,
 +    diverges: Diverges,
 +    breakables: Vec<BreakableContext>,
 +}
 +
 +#[derive(Clone, Debug)]
 +struct BreakableContext {
 +    may_break: bool,
 +    coerce: CoerceMany,
 +    label: Option<name::Name>,
 +}
 +
 +fn find_breakable<'c>(
 +    ctxs: &'c mut [BreakableContext],
 +    label: Option<&name::Name>,
 +) -> Option<&'c mut BreakableContext> {
 +    match label {
 +        Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label),
 +        None => ctxs.last_mut(),
 +    }
 +}
 +
 +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
 +            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 resolve_obligations_as_possible(&mut self) {
 +        self.table.resolve_obligations_as_possible();
 +    }
 +
 +    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.resolve_obligations_as_possible();
 +        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>,
 +        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 ty = TyBuilder::def_ty(self.db, it.into())
 +                    .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![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 239f66bcb7e798f813a0e2d9206f78897a1d0c95,0000000000000000000000000000000000000000..ae115c8c0da85ad7afa7a84dd4fbee7fbd01cc47
mode 100644,000000..100644
--- /dev/null
@@@ -1,1778 -1,0 +1,1769 @@@
-             TypeRef::DynTrait(bounds) => {
-                 let self_ty =
-                     TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
-                 let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
-                     QuantifiedWhereClauses::from_iter(
-                         Interner,
-                         bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
-                     )
-                 });
-                 let bounds = crate::make_single_type_binders(bounds);
-                 TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
-             }
 +//! Methods for lowering the HIR to types. There are two main cases here:
 +//!
 +//!  - Lowering a type reference like `&usize` or `Option<foo::bar::Baz>` to a
 +//!    type: The entry point for this is `Ty::from_hir`.
 +//!  - Building the type for an item: This happens through the `type_for_def` query.
 +//!
 +//! This usually involves resolving names, collecting generic arguments etc.
 +use std::{
 +    cell::{Cell, RefCell},
 +    iter,
 +    sync::Arc,
 +};
 +
 +use base_db::CrateId;
 +use chalk_ir::{
 +    cast::Cast, fold::Shift, fold::TypeFoldable, interner::HasInterner, Mutability, Safety,
 +};
 +
 +use hir_def::{
 +    adt::StructKind,
 +    body::{Expander, LowerCtx},
 +    builtin_type::BuiltinType,
 +    generics::{
 +        TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
 +    },
 +    intern::Interned,
 +    lang_item::lang_attr,
 +    path::{GenericArg, ModPath, Path, PathKind, PathSegment, PathSegments},
 +    resolver::{HasResolver, Resolver, TypeNs},
 +    type_ref::{
 +        ConstScalarOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
 +    },
 +    AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
 +    HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
 +    TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId,
 +};
 +use hir_expand::{name::Name, ExpandResult};
 +use itertools::Either;
 +use la_arena::ArenaMap;
 +use rustc_hash::FxHashSet;
 +use smallvec::SmallVec;
 +use stdx::{impl_from, never};
 +use syntax::{ast, SmolStr};
 +
 +use crate::{
 +    all_super_traits,
 +    consteval::{intern_const_scalar, path_to_const, unknown_const, unknown_const_as_generic},
 +    db::HirDatabase,
 +    make_binders,
 +    mapping::ToChalk,
 +    static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
 +    utils::Generics,
 +    utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics},
 +    AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DynTy, FnPointer,
 +    FnSig, FnSubst, GenericArgData, ImplTraitId, Interner, ParamKind, PolyFnSig, ProjectionTy,
 +    QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits,
 +    Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
 +};
 +
 +#[derive(Debug)]
 +pub struct TyLoweringContext<'a> {
 +    pub db: &'a dyn HirDatabase,
 +    pub resolver: &'a Resolver,
 +    in_binders: DebruijnIndex,
 +    /// Note: Conceptually, it's thinkable that we could be in a location where
 +    /// some type params should be represented as placeholders, and others
 +    /// should be converted to variables. I think in practice, this isn't
 +    /// possible currently, so this should be fine for now.
 +    pub type_param_mode: ParamLoweringMode,
 +    pub impl_trait_mode: ImplTraitLoweringMode,
 +    impl_trait_counter: Cell<u16>,
 +    /// When turning `impl Trait` into opaque types, we have to collect the
 +    /// bounds at the same time to get the IDs correct (without becoming too
 +    /// complicated). I don't like using interior mutability (as for the
 +    /// counter), but I've tried and failed to make the lifetimes work for
 +    /// passing around a `&mut TyLoweringContext`. The core problem is that
 +    /// we're grouping the mutable data (the counter and this field) together
 +    /// with the immutable context (the references to the DB and resolver).
 +    /// Splitting this up would be a possible fix.
 +    opaque_type_data: RefCell<Vec<ReturnTypeImplTrait>>,
 +    expander: RefCell<Option<Expander>>,
 +    /// Tracks types with explicit `?Sized` bounds.
 +    pub(crate) unsized_types: RefCell<FxHashSet<Ty>>,
 +}
 +
 +impl<'a> TyLoweringContext<'a> {
 +    pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self {
 +        let impl_trait_counter = Cell::new(0);
 +        let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
 +        let type_param_mode = ParamLoweringMode::Placeholder;
 +        let in_binders = DebruijnIndex::INNERMOST;
 +        let opaque_type_data = RefCell::new(Vec::new());
 +        Self {
 +            db,
 +            resolver,
 +            in_binders,
 +            impl_trait_mode,
 +            impl_trait_counter,
 +            type_param_mode,
 +            opaque_type_data,
 +            expander: RefCell::new(None),
 +            unsized_types: RefCell::default(),
 +        }
 +    }
 +
 +    pub fn with_debruijn<T>(
 +        &self,
 +        debruijn: DebruijnIndex,
 +        f: impl FnOnce(&TyLoweringContext<'_>) -> T,
 +    ) -> T {
 +        let opaque_ty_data_vec = self.opaque_type_data.take();
 +        let expander = self.expander.take();
 +        let unsized_types = self.unsized_types.take();
 +        let new_ctx = Self {
 +            in_binders: debruijn,
 +            impl_trait_counter: Cell::new(self.impl_trait_counter.get()),
 +            opaque_type_data: RefCell::new(opaque_ty_data_vec),
 +            expander: RefCell::new(expander),
 +            unsized_types: RefCell::new(unsized_types),
 +            ..*self
 +        };
 +        let result = f(&new_ctx);
 +        self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
 +        self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner());
 +        self.expander.replace(new_ctx.expander.into_inner());
 +        self.unsized_types.replace(new_ctx.unsized_types.into_inner());
 +        result
 +    }
 +
 +    pub fn with_shifted_in<T>(
 +        &self,
 +        debruijn: DebruijnIndex,
 +        f: impl FnOnce(&TyLoweringContext<'_>) -> T,
 +    ) -> T {
 +        self.with_debruijn(self.in_binders.shifted_in_from(debruijn), f)
 +    }
 +
 +    pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
 +        Self { impl_trait_mode, ..self }
 +    }
 +
 +    pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self {
 +        Self { type_param_mode, ..self }
 +    }
 +}
 +
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +pub enum ImplTraitLoweringMode {
 +    /// `impl Trait` gets lowered into an opaque type that doesn't unify with
 +    /// anything except itself. This is used in places where values flow 'out',
 +    /// i.e. for arguments of the function we're currently checking, and return
 +    /// types of functions we're calling.
 +    Opaque,
 +    /// `impl Trait` gets lowered into a type variable. Used for argument
 +    /// position impl Trait when inside the respective function, since it allows
 +    /// us to support that without Chalk.
 +    Param,
 +    /// `impl Trait` gets lowered into a variable that can unify with some
 +    /// type. This is used in places where values flow 'in', i.e. for arguments
 +    /// of functions we're calling, and the return type of the function we're
 +    /// currently checking.
 +    Variable,
 +    /// `impl Trait` is disallowed and will be an error.
 +    Disallowed,
 +}
 +
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +pub enum ParamLoweringMode {
 +    Placeholder,
 +    Variable,
 +}
 +
 +impl<'a> TyLoweringContext<'a> {
 +    pub fn lower_ty(&self, type_ref: &TypeRef) -> Ty {
 +        self.lower_ty_ext(type_ref).0
 +    }
 +
 +    fn generics(&self) -> Generics {
 +        generics(
 +            self.db.upcast(),
 +            self.resolver
 +                .generic_def()
 +                .expect("there should be generics if there's a generic param"),
 +        )
 +    }
 +
 +    pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
 +        let mut res = None;
 +        let ty = match type_ref {
 +            TypeRef::Never => TyKind::Never.intern(Interner),
 +            TypeRef::Tuple(inner) => {
 +                let inner_tys = inner.iter().map(|tr| self.lower_ty(tr));
 +                TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
 +                    .intern(Interner)
 +            }
 +            TypeRef::Path(path) => {
 +                let (ty, res_) = self.lower_path(path);
 +                res = res_;
 +                ty
 +            }
 +            TypeRef::RawPtr(inner, mutability) => {
 +                let inner_ty = self.lower_ty(inner);
 +                TyKind::Raw(lower_to_chalk_mutability(*mutability), inner_ty).intern(Interner)
 +            }
 +            TypeRef::Array(inner, len) => {
 +                let inner_ty = self.lower_ty(inner);
 +                let const_len = const_or_path_to_chalk(
 +                    self.db,
 +                    self.resolver,
 +                    TyBuilder::usize(),
 +                    len,
 +                    self.type_param_mode,
 +                    || self.generics(),
 +                    self.in_binders,
 +                );
 +
 +                TyKind::Array(inner_ty, const_len).intern(Interner)
 +            }
 +            TypeRef::Slice(inner) => {
 +                let inner_ty = self.lower_ty(inner);
 +                TyKind::Slice(inner_ty).intern(Interner)
 +            }
 +            TypeRef::Reference(inner, _, mutability) => {
 +                let inner_ty = self.lower_ty(inner);
 +                let lifetime = static_lifetime();
 +                TyKind::Ref(lower_to_chalk_mutability(*mutability), lifetime, inner_ty)
 +                    .intern(Interner)
 +            }
 +            TypeRef::Placeholder => TyKind::Error.intern(Interner),
 +            TypeRef::Fn(params, is_varargs) => {
 +                let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
 +                    Substitution::from_iter(Interner, params.iter().map(|(_, tr)| ctx.lower_ty(tr)))
 +                });
 +                TyKind::Function(FnPointer {
 +                    num_binders: 0, // FIXME lower `for<'a> fn()` correctly
 +                    sig: FnSig { abi: (), safety: Safety::Safe, variadic: *is_varargs },
 +                    substitution: FnSubst(substs),
 +                })
 +                .intern(Interner)
 +            }
-                         let self_ty = Some(
-                             TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
-                                 .intern(Interner),
-                         );
-                         let trait_ref = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
-                             ctx.lower_trait_ref_from_resolved_path(
-                                 trait_,
-                                 resolved_segment,
-                                 self_ty,
-                             )
-                         });
-                         let dyn_ty = DynTy {
-                             bounds: crate::make_single_type_binders(
-                                 QuantifiedWhereClauses::from_iter(
-                                     Interner,
-                                     Some(crate::wrap_empty_binders(WhereClause::Implemented(
-                                         trait_ref,
-                                     ))),
-                                 ),
-                             ),
-                             lifetime: static_lifetime(),
-                         };
-                         TyKind::Dyn(dyn_ty).intern(Interner)
++            TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds),
 +            TypeRef::ImplTrait(bounds) => {
 +                match self.impl_trait_mode {
 +                    ImplTraitLoweringMode::Opaque => {
 +                        let idx = self.impl_trait_counter.get();
 +                        self.impl_trait_counter.set(idx + 1);
 +                        let func = match self.resolver.generic_def() {
 +                            Some(GenericDefId::FunctionId(f)) => f,
 +                            _ => panic!("opaque impl trait lowering in non-function"),
 +                        };
 +
 +                        assert!(idx as usize == self.opaque_type_data.borrow().len());
 +                        // this dance is to make sure the data is in the right
 +                        // place even if we encounter more opaque types while
 +                        // lowering the bounds
 +                        self.opaque_type_data.borrow_mut().push(ReturnTypeImplTrait {
 +                            bounds: crate::make_single_type_binders(Vec::new()),
 +                        });
 +                        // We don't want to lower the bounds inside the binders
 +                        // we're currently in, because they don't end up inside
 +                        // those binders. E.g. when we have `impl Trait<impl
 +                        // OtherTrait<T>>`, the `impl OtherTrait<T>` can't refer
 +                        // to the self parameter from `impl Trait`, and the
 +                        // bounds aren't actually stored nested within each
 +                        // other, but separately. So if the `T` refers to a type
 +                        // parameter of the outer function, it's just one binder
 +                        // away instead of two.
 +                        let actual_opaque_type_data = self
 +                            .with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
 +                                ctx.lower_impl_trait(bounds, func)
 +                            });
 +                        self.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data;
 +
 +                        let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx);
 +                        let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
 +                        let generics = generics(self.db.upcast(), func.into());
 +                        let parameters = generics.bound_vars_subst(self.db, self.in_binders);
 +                        TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner)
 +                    }
 +                    ImplTraitLoweringMode::Param => {
 +                        let idx = self.impl_trait_counter.get();
 +                        // FIXME we're probably doing something wrong here
 +                        self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
 +                        if let Some(def) = self.resolver.generic_def() {
 +                            let generics = generics(self.db.upcast(), def);
 +                            let param = generics
 +                                .iter()
 +                                .filter(|(_, data)| {
 +                                    matches!(
 +                                        data,
 +                                        TypeOrConstParamData::TypeParamData(data)
 +                                        if data.provenance == TypeParamProvenance::ArgumentImplTrait
 +                                    )
 +                                })
 +                                .nth(idx as usize)
 +                                .map_or(TyKind::Error, |(id, _)| {
 +                                    TyKind::Placeholder(to_placeholder_idx(self.db, id))
 +                                });
 +                            param.intern(Interner)
 +                        } else {
 +                            TyKind::Error.intern(Interner)
 +                        }
 +                    }
 +                    ImplTraitLoweringMode::Variable => {
 +                        let idx = self.impl_trait_counter.get();
 +                        // FIXME we're probably doing something wrong here
 +                        self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
 +                        let (
 +                            parent_params,
 +                            self_params,
 +                            list_params,
 +                            const_params,
 +                            _impl_trait_params,
 +                        ) = if let Some(def) = self.resolver.generic_def() {
 +                            let generics = generics(self.db.upcast(), def);
 +                            generics.provenance_split()
 +                        } else {
 +                            (0, 0, 0, 0, 0)
 +                        };
 +                        TyKind::BoundVar(BoundVar::new(
 +                            self.in_binders,
 +                            idx as usize + parent_params + self_params + list_params + const_params,
 +                        ))
 +                        .intern(Interner)
 +                    }
 +                    ImplTraitLoweringMode::Disallowed => {
 +                        // FIXME: report error
 +                        TyKind::Error.intern(Interner)
 +                    }
 +                }
 +            }
 +            TypeRef::Macro(macro_call) => {
 +                let (expander, recursion_start) = {
 +                    let mut expander = self.expander.borrow_mut();
 +                    if expander.is_some() {
 +                        (Some(expander), false)
 +                    } else {
 +                        *expander = Some(Expander::new(
 +                            self.db.upcast(),
 +                            macro_call.file_id,
 +                            self.resolver.module(),
 +                        ));
 +                        (Some(expander), true)
 +                    }
 +                };
 +                let ty = if let Some(mut expander) = expander {
 +                    let expander_mut = expander.as_mut().unwrap();
 +                    let macro_call = macro_call.to_node(self.db.upcast());
 +                    match expander_mut.enter_expand::<ast::Type>(self.db.upcast(), macro_call) {
 +                        Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
 +                            let ctx =
 +                                LowerCtx::new(self.db.upcast(), expander_mut.current_file_id());
 +                            let type_ref = TypeRef::from_ast(&ctx, expanded);
 +
 +                            drop(expander);
 +                            let ty = self.lower_ty(&type_ref);
 +
 +                            self.expander
 +                                .borrow_mut()
 +                                .as_mut()
 +                                .unwrap()
 +                                .exit(self.db.upcast(), mark);
 +                            Some(ty)
 +                        }
 +                        _ => None,
 +                    }
 +                } else {
 +                    None
 +                };
 +                if recursion_start {
 +                    *self.expander.borrow_mut() = None;
 +                }
 +                ty.unwrap_or_else(|| TyKind::Error.intern(Interner))
 +            }
 +            TypeRef::Error => TyKind::Error.intern(Interner),
 +        };
 +        (ty, res)
 +    }
 +
 +    /// This is only for `generic_predicates_for_param`, where we can't just
 +    /// lower the self types of the predicates since that could lead to cycles.
 +    /// So we just check here if the `type_ref` resolves to a generic param, and which.
 +    fn lower_ty_only_param(&self, type_ref: &TypeRef) -> Option<TypeOrConstParamId> {
 +        let path = match type_ref {
 +            TypeRef::Path(path) => path,
 +            _ => return None,
 +        };
 +        if path.type_anchor().is_some() {
 +            return None;
 +        }
 +        if path.segments().len() > 1 {
 +            return None;
 +        }
 +        let resolution =
 +            match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
 +                Some((it, None)) => it,
 +                _ => return None,
 +            };
 +        match resolution {
 +            TypeNs::GenericParam(param_id) => Some(param_id.into()),
 +            _ => None,
 +        }
 +    }
 +
 +    pub(crate) fn lower_ty_relative_path(
 +        &self,
 +        ty: Ty,
 +        // We need the original resolution to lower `Self::AssocTy` correctly
 +        res: Option<TypeNs>,
 +        remaining_segments: PathSegments<'_>,
 +    ) -> (Ty, Option<TypeNs>) {
 +        match remaining_segments.len() {
 +            0 => (ty, res),
 +            1 => {
 +                // resolve unselected assoc types
 +                let segment = remaining_segments.first().unwrap();
 +                (self.select_associated_type(res, segment), None)
 +            }
 +            _ => {
 +                // FIXME report error (ambiguous associated type)
 +                (TyKind::Error.intern(Interner), None)
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn lower_partly_resolved_path(
 +        &self,
 +        resolution: TypeNs,
 +        resolved_segment: PathSegment<'_>,
 +        remaining_segments: PathSegments<'_>,
 +        infer_args: bool,
 +    ) -> (Ty, Option<TypeNs>) {
 +        let ty = match resolution {
 +            TypeNs::TraitId(trait_) => {
 +                let ty = match remaining_segments.len() {
 +                    1 => {
 +                        let trait_ref =
 +                            self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None);
 +                        let segment = remaining_segments.first().unwrap();
 +                        let found = self
 +                            .db
 +                            .trait_data(trait_ref.hir_trait_id())
 +                            .associated_type_by_name(segment.name);
 +                        match found {
 +                            Some(associated_ty) => {
 +                                // FIXME handle type parameters on the segment
 +                                TyKind::Alias(AliasTy::Projection(ProjectionTy {
 +                                    associated_ty_id: to_assoc_type_id(associated_ty),
 +                                    substitution: trait_ref.substitution,
 +                                }))
 +                                .intern(Interner)
 +                            }
 +                            None => {
 +                                // FIXME: report error (associated type not found)
 +                                TyKind::Error.intern(Interner)
 +                            }
 +                        }
 +                    }
 +                    0 => {
++                        // Trait object type without dyn; this should be handled in upstream. See
++                        // `lower_path()`.
++                        stdx::never!("unexpected fully resolved trait path");
++                        TyKind::Error.intern(Interner)
 +                    }
 +                    _ => {
 +                        // FIXME report error (ambiguous associated type)
 +                        TyKind::Error.intern(Interner)
 +                    }
 +                };
 +                return (ty, None);
 +            }
 +            TypeNs::GenericParam(param_id) => {
 +                let generics = generics(
 +                    self.db.upcast(),
 +                    self.resolver.generic_def().expect("generics in scope"),
 +                );
 +                match self.type_param_mode {
 +                    ParamLoweringMode::Placeholder => {
 +                        TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
 +                    }
 +                    ParamLoweringMode::Variable => {
 +                        let idx = generics.param_idx(param_id.into()).expect("matching generics");
 +                        TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
 +                    }
 +                }
 +                .intern(Interner)
 +            }
 +            TypeNs::SelfType(impl_id) => {
 +                let generics = generics(self.db.upcast(), impl_id.into());
 +                let substs = match self.type_param_mode {
 +                    ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
 +                    ParamLoweringMode::Variable => {
 +                        generics.bound_vars_subst(self.db, self.in_binders)
 +                    }
 +                };
 +                self.db.impl_self_ty(impl_id).substitute(Interner, &substs)
 +            }
 +            TypeNs::AdtSelfType(adt) => {
 +                let generics = generics(self.db.upcast(), adt.into());
 +                let substs = match self.type_param_mode {
 +                    ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
 +                    ParamLoweringMode::Variable => {
 +                        generics.bound_vars_subst(self.db, self.in_binders)
 +                    }
 +                };
 +                self.db.ty(adt.into()).substitute(Interner, &substs)
 +            }
 +
 +            TypeNs::AdtId(it) => self.lower_path_inner(resolved_segment, it.into(), infer_args),
 +            TypeNs::BuiltinType(it) => {
 +                self.lower_path_inner(resolved_segment, it.into(), infer_args)
 +            }
 +            TypeNs::TypeAliasId(it) => {
 +                self.lower_path_inner(resolved_segment, it.into(), infer_args)
 +            }
 +            // FIXME: report error
 +            TypeNs::EnumVariantId(_) => return (TyKind::Error.intern(Interner), None),
 +        };
 +        self.lower_ty_relative_path(ty, Some(resolution), remaining_segments)
 +    }
 +
 +    pub(crate) fn lower_path(&self, path: &Path) -> (Ty, Option<TypeNs>) {
 +        // Resolve the path (in type namespace)
 +        if let Some(type_ref) = path.type_anchor() {
 +            let (ty, res) = self.lower_ty_ext(type_ref);
 +            return self.lower_ty_relative_path(ty, res, path.segments());
 +        }
++
 +        let (resolution, remaining_index) =
 +            match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
 +                Some(it) => it,
 +                None => return (TyKind::Error.intern(Interner), None),
 +            };
++
++        if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
++            // trait object type without dyn
++            let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None);
++            let ty = self.lower_dyn_trait(&[Interned::new(bound)]);
++            return (ty, None);
++        }
++
 +        let (resolved_segment, remaining_segments) = match remaining_index {
 +            None => (
 +                path.segments().last().expect("resolved path has at least one element"),
 +                PathSegments::EMPTY,
 +            ),
 +            Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)),
 +        };
 +        self.lower_partly_resolved_path(resolution, resolved_segment, remaining_segments, false)
 +    }
 +
 +    fn select_associated_type(&self, res: Option<TypeNs>, segment: PathSegment<'_>) -> Ty {
 +        let (def, res) = match (self.resolver.generic_def(), res) {
 +            (Some(def), Some(res)) => (def, res),
 +            _ => return TyKind::Error.intern(Interner),
 +        };
 +        let ty = named_associated_type_shorthand_candidates(
 +            self.db,
 +            def,
 +            res,
 +            Some(segment.name.clone()),
 +            move |name, t, associated_ty| {
 +                if name == segment.name {
 +                    let substs = match self.type_param_mode {
 +                        ParamLoweringMode::Placeholder => {
 +                            // if we're lowering to placeholders, we have to put
 +                            // them in now
 +                            let generics = generics(
 +                                self.db.upcast(),
 +                                self.resolver
 +                                    .generic_def()
 +                                    .expect("there should be generics if there's a generic param"),
 +                            );
 +                            let s = generics.placeholder_subst(self.db);
 +                            s.apply(t.substitution.clone(), Interner)
 +                        }
 +                        ParamLoweringMode::Variable => t.substitution.clone(),
 +                    };
 +                    // We need to shift in the bound vars, since
 +                    // associated_type_shorthand_candidates does not do that
 +                    let substs = substs.shifted_in_from(Interner, self.in_binders);
 +                    // FIXME handle type parameters on the segment
 +                    Some(
 +                        TyKind::Alias(AliasTy::Projection(ProjectionTy {
 +                            associated_ty_id: to_assoc_type_id(associated_ty),
 +                            substitution: substs,
 +                        }))
 +                        .intern(Interner),
 +                    )
 +                } else {
 +                    None
 +                }
 +            },
 +        );
 +
 +        ty.unwrap_or_else(|| TyKind::Error.intern(Interner))
 +    }
 +
 +    fn lower_path_inner(
 +        &self,
 +        segment: PathSegment<'_>,
 +        typeable: TyDefId,
 +        infer_args: bool,
 +    ) -> Ty {
 +        let generic_def = match typeable {
 +            TyDefId::BuiltinType(_) => None,
 +            TyDefId::AdtId(it) => Some(it.into()),
 +            TyDefId::TypeAliasId(it) => Some(it.into()),
 +        };
 +        let substs = self.substs_from_path_segment(segment, generic_def, infer_args, None);
 +        self.db.ty(typeable).substitute(Interner, &substs)
 +    }
 +
 +    /// Collect generic arguments from a path into a `Substs`. See also
 +    /// `create_substs_for_ast_path` and `def_to_ty` in rustc.
 +    pub(super) fn substs_from_path(
 +        &self,
 +        path: &Path,
 +        // Note that we don't call `db.value_type(resolved)` here,
 +        // `ValueTyDefId` is just a convenient way to pass generics and
 +        // special-case enum variants
 +        resolved: ValueTyDefId,
 +        infer_args: bool,
 +    ) -> Substitution {
 +        let last = path.segments().last().expect("path should have at least one segment");
 +        let (segment, generic_def) = match resolved {
 +            ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
 +            ValueTyDefId::StructId(it) => (last, Some(it.into())),
 +            ValueTyDefId::UnionId(it) => (last, Some(it.into())),
 +            ValueTyDefId::ConstId(it) => (last, Some(it.into())),
 +            ValueTyDefId::StaticId(_) => (last, None),
 +            ValueTyDefId::EnumVariantId(var) => {
 +                // the generic args for an enum variant may be either specified
 +                // on the segment referring to the enum, or on the segment
 +                // referring to the variant. So `Option::<T>::None` and
 +                // `Option::None::<T>` are both allowed (though the former is
 +                // preferred). See also `def_ids_for_path_segments` in rustc.
 +                let len = path.segments().len();
 +                let penultimate = len.checked_sub(2).and_then(|idx| path.segments().get(idx));
 +                let segment = match penultimate {
 +                    Some(segment) if segment.args_and_bindings.is_some() => segment,
 +                    _ => last,
 +                };
 +                (segment, Some(var.parent.into()))
 +            }
 +        };
 +        self.substs_from_path_segment(segment, generic_def, infer_args, None)
 +    }
 +
 +    fn substs_from_path_segment(
 +        &self,
 +        segment: PathSegment<'_>,
 +        def_generic: Option<GenericDefId>,
 +        infer_args: bool,
 +        explicit_self_ty: Option<Ty>,
 +    ) -> Substitution {
 +        let mut substs = Vec::new();
 +        let def_generics = if let Some(def) = def_generic {
 +            generics(self.db.upcast(), def)
 +        } else {
 +            return Substitution::empty(Interner);
 +        };
 +        let (parent_params, self_params, type_params, const_params, impl_trait_params) =
 +            def_generics.provenance_split();
 +        let total_len =
 +            parent_params + self_params + type_params + const_params + impl_trait_params;
 +
 +        let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
 +
 +        let mut def_generic_iter = def_generics.iter_id();
 +
 +        for _ in 0..parent_params {
 +            if let Some(eid) = def_generic_iter.next() {
 +                match eid {
 +                    Either::Left(_) => substs.push(ty_error.clone()),
 +                    Either::Right(x) => {
 +                        substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
 +                    }
 +                }
 +            }
 +        }
 +
 +        let fill_self_params = || {
 +            for x in explicit_self_ty
 +                .into_iter()
 +                .map(|x| GenericArgData::Ty(x).intern(Interner))
 +                .chain(iter::repeat(ty_error.clone()))
 +                .take(self_params)
 +            {
 +                if let Some(id) = def_generic_iter.next() {
 +                    assert!(id.is_left());
 +                    substs.push(x);
 +                }
 +            }
 +        };
 +        let mut had_explicit_args = false;
 +
 +        if let Some(generic_args) = &segment.args_and_bindings {
 +            if !generic_args.has_self_type {
 +                fill_self_params();
 +            }
 +            let expected_num = if generic_args.has_self_type {
 +                self_params + type_params + const_params
 +            } else {
 +                type_params + const_params
 +            };
 +            let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 };
 +            // if args are provided, it should be all of them, but we can't rely on that
 +            for arg in generic_args
 +                .args
 +                .iter()
 +                .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
 +                .skip(skip)
 +                .take(expected_num)
 +            {
 +                if let Some(id) = def_generic_iter.next() {
 +                    if let Some(x) = generic_arg_to_chalk(
 +                        self.db,
 +                        id,
 +                        arg,
 +                        &mut (),
 +                        |_, type_ref| self.lower_ty(type_ref),
 +                        |_, c, ty| {
 +                            const_or_path_to_chalk(
 +                                self.db,
 +                                &self.resolver,
 +                                ty,
 +                                c,
 +                                self.type_param_mode,
 +                                || self.generics(),
 +                                self.in_binders,
 +                            )
 +                        },
 +                    ) {
 +                        had_explicit_args = true;
 +                        substs.push(x);
 +                    } else {
 +                        // we just filtered them out
 +                        never!("Unexpected lifetime argument");
 +                    }
 +                }
 +            }
 +        } else {
 +            fill_self_params();
 +        }
 +
 +        // handle defaults. In expression or pattern path segments without
 +        // explicitly specified type arguments, missing type arguments are inferred
 +        // (i.e. defaults aren't used).
 +        if !infer_args || had_explicit_args {
 +            if let Some(def_generic) = def_generic {
 +                let defaults = self.db.generic_defaults(def_generic);
 +                assert_eq!(total_len, defaults.len());
 +
 +                for default_ty in defaults.iter().skip(substs.len()) {
 +                    // each default can depend on the previous parameters
 +                    let substs_so_far = Substitution::from_iter(Interner, substs.clone());
 +                    if let Some(_id) = def_generic_iter.next() {
 +                        substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
 +                    }
 +                }
 +            }
 +        }
 +
 +        // add placeholders for args that were not provided
 +        // FIXME: emit diagnostics in contexts where this is not allowed
 +        for eid in def_generic_iter {
 +            match eid {
 +                Either::Left(_) => substs.push(ty_error.clone()),
 +                Either::Right(x) => {
 +                    substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
 +                }
 +            }
 +        }
 +        // If this assert fails, it means you pushed into subst but didn't call .next() of def_generic_iter
 +        assert_eq!(substs.len(), total_len);
 +
 +        Substitution::from_iter(Interner, substs)
 +    }
 +
 +    fn lower_trait_ref_from_path(
 +        &self,
 +        path: &Path,
 +        explicit_self_ty: Option<Ty>,
 +    ) -> Option<TraitRef> {
 +        let resolved =
 +            match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path.mod_path())? {
 +                TypeNs::TraitId(tr) => tr,
 +                _ => return None,
 +            };
 +        let segment = path.segments().last().expect("path should have at least one segment");
 +        Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty))
 +    }
 +
 +    pub(crate) fn lower_trait_ref_from_resolved_path(
 +        &self,
 +        resolved: TraitId,
 +        segment: PathSegment<'_>,
 +        explicit_self_ty: Option<Ty>,
 +    ) -> TraitRef {
 +        let substs = self.trait_ref_substs_from_path(segment, resolved, explicit_self_ty);
 +        TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
 +    }
 +
 +    fn lower_trait_ref(
 +        &self,
 +        trait_ref: &HirTraitRef,
 +        explicit_self_ty: Option<Ty>,
 +    ) -> Option<TraitRef> {
 +        self.lower_trait_ref_from_path(&trait_ref.path, explicit_self_ty)
 +    }
 +
 +    fn trait_ref_substs_from_path(
 +        &self,
 +        segment: PathSegment<'_>,
 +        resolved: TraitId,
 +        explicit_self_ty: Option<Ty>,
 +    ) -> Substitution {
 +        self.substs_from_path_segment(segment, Some(resolved.into()), false, explicit_self_ty)
 +    }
 +
 +    pub(crate) fn lower_where_predicate(
 +        &'a self,
 +        where_predicate: &'a WherePredicate,
 +        ignore_bindings: bool,
 +    ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
 +        match where_predicate {
 +            WherePredicate::ForLifetime { target, bound, .. }
 +            | WherePredicate::TypeBound { target, bound } => {
 +                let self_ty = match target {
 +                    WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref),
 +                    WherePredicateTypeTarget::TypeOrConstParam(param_id) => {
 +                        let generic_def = self.resolver.generic_def().expect("generics in scope");
 +                        let generics = generics(self.db.upcast(), generic_def);
 +                        let param_id = hir_def::TypeOrConstParamId {
 +                            parent: generic_def,
 +                            local_id: *param_id,
 +                        };
 +                        let placeholder = to_placeholder_idx(self.db, param_id);
 +                        match self.type_param_mode {
 +                            ParamLoweringMode::Placeholder => TyKind::Placeholder(placeholder),
 +                            ParamLoweringMode::Variable => {
 +                                let idx = generics.param_idx(param_id).expect("matching generics");
 +                                TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, idx))
 +                            }
 +                        }
 +                        .intern(Interner)
 +                    }
 +                };
 +                self.lower_type_bound(bound, self_ty, ignore_bindings)
 +                    .collect::<Vec<_>>()
 +                    .into_iter()
 +            }
 +            WherePredicate::Lifetime { .. } => vec![].into_iter(),
 +        }
 +    }
 +
 +    pub(crate) fn lower_type_bound(
 +        &'a self,
 +        bound: &'a TypeBound,
 +        self_ty: Ty,
 +        ignore_bindings: bool,
 +    ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
 +        let mut bindings = None;
 +        let trait_ref = match bound {
 +            TypeBound::Path(path, TraitBoundModifier::None) => {
 +                bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
 +                bindings
 +                    .clone()
 +                    .filter(|tr| {
 +                        // ignore `T: Drop` or `T: Destruct` bounds.
 +                        // - `T: ~const Drop` has a special meaning in Rust 1.61 that we don't implement.
 +                        //   (So ideally, we'd only ignore `~const Drop` here)
 +                        // - `Destruct` impls are built-in in 1.62 (current nightlies as of 08-04-2022), so until
 +                        //   the builtin impls are supported by Chalk, we ignore them here.
 +                        if let Some(lang) = lang_attr(self.db.upcast(), tr.hir_trait_id()) {
 +                            if lang == "drop" || lang == "destruct" {
 +                                return false;
 +                            }
 +                        }
 +                        true
 +                    })
 +                    .map(WhereClause::Implemented)
 +                    .map(crate::wrap_empty_binders)
 +            }
 +            TypeBound::Path(path, TraitBoundModifier::Maybe) => {
 +                let sized_trait = self
 +                    .db
 +                    .lang_item(self.resolver.krate(), SmolStr::new_inline("sized"))
 +                    .and_then(|lang_item| lang_item.as_trait());
 +                // Don't lower associated type bindings as the only possible relaxed trait bound
 +                // `?Sized` has no of them.
 +                // If we got another trait here ignore the bound completely.
 +                let trait_id = self
 +                    .lower_trait_ref_from_path(path, Some(self_ty.clone()))
 +                    .map(|trait_ref| trait_ref.hir_trait_id());
 +                if trait_id == sized_trait {
 +                    self.unsized_types.borrow_mut().insert(self_ty);
 +                }
 +                None
 +            }
 +            TypeBound::ForLifetime(_, path) => {
 +                // FIXME Don't silently drop the hrtb lifetimes here
 +                bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
 +                bindings.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
 +            }
 +            TypeBound::Lifetime(_) => None,
 +            TypeBound::Error => None,
 +        };
 +        trait_ref.into_iter().chain(
 +            bindings
 +                .into_iter()
 +                .filter(move |_| !ignore_bindings)
 +                .flat_map(move |tr| self.assoc_type_bindings_from_type_bound(bound, tr)),
 +        )
 +    }
 +
 +    fn assoc_type_bindings_from_type_bound(
 +        &'a self,
 +        bound: &'a TypeBound,
 +        trait_ref: TraitRef,
 +    ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
 +        let last_segment = match bound {
 +            TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => {
 +                path.segments().last()
 +            }
 +            TypeBound::Path(_, TraitBoundModifier::Maybe)
 +            | TypeBound::Error
 +            | TypeBound::Lifetime(_) => None,
 +        };
 +        last_segment
 +            .into_iter()
 +            .filter_map(|segment| segment.args_and_bindings)
 +            .flat_map(|args_and_bindings| &args_and_bindings.bindings)
 +            .flat_map(move |binding| {
 +                let found = associated_type_by_name_including_super_traits(
 +                    self.db,
 +                    trait_ref.clone(),
 +                    &binding.name,
 +                );
 +                let (super_trait_ref, associated_ty) = match found {
 +                    None => return SmallVec::new(),
 +                    Some(t) => t,
 +                };
 +                let projection_ty = ProjectionTy {
 +                    associated_ty_id: to_assoc_type_id(associated_ty),
 +                    substitution: super_trait_ref.substitution,
 +                };
 +                let mut preds: SmallVec<[_; 1]> = SmallVec::with_capacity(
 +                    binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
 +                );
 +                if let Some(type_ref) = &binding.type_ref {
 +                    let ty = self.lower_ty(type_ref);
 +                    let alias_eq =
 +                        AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
 +                    preds.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
 +                }
 +                for bound in &binding.bounds {
 +                    preds.extend(self.lower_type_bound(
 +                        bound,
 +                        TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(Interner),
 +                        false,
 +                    ));
 +                }
 +                preds
 +            })
 +    }
 +
++    fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
++        let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
++        let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
++            QuantifiedWhereClauses::from_iter(
++                Interner,
++                bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
++            )
++        });
++        let bounds = crate::make_single_type_binders(bounds);
++        TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
++    }
++
 +    fn lower_impl_trait(
 +        &self,
 +        bounds: &[Interned<TypeBound>],
 +        func: FunctionId,
 +    ) -> ReturnTypeImplTrait {
 +        cov_mark::hit!(lower_rpit);
 +        let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
 +        let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
 +            let mut predicates: Vec<_> = bounds
 +                .iter()
 +                .flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false))
 +                .collect();
 +
 +            if !ctx.unsized_types.borrow().contains(&self_ty) {
 +                let krate = func.lookup(ctx.db.upcast()).module(ctx.db.upcast()).krate();
 +                let sized_trait = ctx
 +                    .db
 +                    .lang_item(krate, SmolStr::new_inline("sized"))
 +                    .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
 +                let sized_clause = sized_trait.map(|trait_id| {
 +                    let clause = WhereClause::Implemented(TraitRef {
 +                        trait_id,
 +                        substitution: Substitution::from1(Interner, self_ty.clone()),
 +                    });
 +                    crate::wrap_empty_binders(clause)
 +                });
 +                predicates.extend(sized_clause.into_iter());
 +                predicates.shrink_to_fit();
 +            }
 +            predicates
 +        });
 +        ReturnTypeImplTrait { bounds: crate::make_single_type_binders(predicates) }
 +    }
 +}
 +
 +fn count_impl_traits(type_ref: &TypeRef) -> usize {
 +    let mut count = 0;
 +    type_ref.walk(&mut |type_ref| {
 +        if matches!(type_ref, TypeRef::ImplTrait(_)) {
 +            count += 1;
 +        }
 +    });
 +    count
 +}
 +
 +/// Build the signature of a callable item (function, struct or enum variant).
 +pub(crate) fn callable_item_sig(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig {
 +    match def {
 +        CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f),
 +        CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s),
 +        CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e),
 +    }
 +}
 +
 +pub fn associated_type_shorthand_candidates<R>(
 +    db: &dyn HirDatabase,
 +    def: GenericDefId,
 +    res: TypeNs,
 +    cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
 +) -> Option<R> {
 +    named_associated_type_shorthand_candidates(db, def, res, None, cb)
 +}
 +
 +fn named_associated_type_shorthand_candidates<R>(
 +    db: &dyn HirDatabase,
 +    // If the type parameter is defined in an impl and we're in a method, there
 +    // might be additional where clauses to consider
 +    def: GenericDefId,
 +    res: TypeNs,
 +    assoc_name: Option<Name>,
 +    mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
 +) -> Option<R> {
 +    let mut search = |t| {
 +        for t in all_super_trait_refs(db, t) {
 +            let data = db.trait_data(t.hir_trait_id());
 +
 +            for (name, assoc_id) in &data.items {
 +                if let AssocItemId::TypeAliasId(alias) = assoc_id {
 +                    if let Some(result) = cb(name, &t, *alias) {
 +                        return Some(result);
 +                    }
 +                }
 +            }
 +        }
 +        None
 +    };
 +
 +    match res {
 +        TypeNs::SelfType(impl_id) => search(
 +            // we're _in_ the impl -- the binders get added back later. Correct,
 +            // but it would be nice to make this more explicit
 +            db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
 +        ),
 +        TypeNs::GenericParam(param_id) => {
 +            let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
 +            let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
 +                // FIXME: how to correctly handle higher-ranked bounds here?
 +                WhereClause::Implemented(tr) => search(
 +                    tr.clone()
 +                        .shifted_out_to(Interner, DebruijnIndex::ONE)
 +                        .expect("FIXME unexpected higher-ranked trait bound"),
 +                ),
 +                _ => None,
 +            });
 +            if let Some(_) = res {
 +                return res;
 +            }
 +            // Handle `Self::Type` referring to own associated type in trait definitions
 +            if let GenericDefId::TraitId(trait_id) = param_id.parent() {
 +                let generics = generics(db.upcast(), trait_id.into());
 +                if generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
 +                    let trait_ref = TyBuilder::trait_ref(db, trait_id)
 +                        .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
 +                        .build();
 +                    return search(trait_ref);
 +                }
 +            }
 +            None
 +        }
 +        _ => None,
 +    }
 +}
 +
 +/// Build the type of all specific fields of a struct or enum variant.
 +pub(crate) fn field_types_query(
 +    db: &dyn HirDatabase,
 +    variant_id: VariantId,
 +) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> {
 +    let var_data = variant_id.variant_data(db.upcast());
 +    let (resolver, def): (_, GenericDefId) = match variant_id {
 +        VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()),
 +        VariantId::UnionId(it) => (it.resolver(db.upcast()), it.into()),
 +        VariantId::EnumVariantId(it) => (it.parent.resolver(db.upcast()), it.parent.into()),
 +    };
 +    let generics = generics(db.upcast(), def);
 +    let mut res = ArenaMap::default();
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    for (field_id, field_data) in var_data.fields().iter() {
 +        res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref)));
 +    }
 +    Arc::new(res)
 +}
 +
 +/// This query exists only to be used when resolving short-hand associated types
 +/// like `T::Item`.
 +///
 +/// See the analogous query in rustc and its comment:
 +/// <https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46>
 +/// This is a query mostly to handle cycles somewhat gracefully; e.g. the
 +/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but
 +/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
 +pub(crate) fn generic_predicates_for_param_query(
 +    db: &dyn HirDatabase,
 +    def: GenericDefId,
 +    param_id: TypeOrConstParamId,
 +    assoc_name: Option<Name>,
 +) -> Arc<[Binders<QuantifiedWhereClause>]> {
 +    let resolver = def.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    let generics = generics(db.upcast(), def);
 +    let mut predicates: Vec<_> = resolver
 +        .where_predicates_in_scope()
 +        // we have to filter out all other predicates *first*, before attempting to lower them
 +        .filter(|pred| match pred {
 +            WherePredicate::ForLifetime { target, bound, .. }
 +            | WherePredicate::TypeBound { target, bound, .. } => {
 +                match target {
 +                    WherePredicateTypeTarget::TypeRef(type_ref) => {
 +                        if ctx.lower_ty_only_param(type_ref) != Some(param_id) {
 +                            return false;
 +                        }
 +                    }
 +                    &WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
 +                        let target_id = TypeOrConstParamId { parent: def, local_id };
 +                        if target_id != param_id {
 +                            return false;
 +                        }
 +                    }
 +                };
 +
 +                match &**bound {
 +                    TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => {
 +                        // Only lower the bound if the trait could possibly define the associated
 +                        // type we're looking for.
 +
 +                        let assoc_name = match &assoc_name {
 +                            Some(it) => it,
 +                            None => return true,
 +                        };
 +                        let tr = match resolver
 +                            .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path())
 +                        {
 +                            Some(TypeNs::TraitId(tr)) => tr,
 +                            _ => return false,
 +                        };
 +
 +                        all_super_traits(db.upcast(), tr).iter().any(|tr| {
 +                            db.trait_data(*tr).items.iter().any(|(name, item)| {
 +                                matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
 +                            })
 +                        })
 +                    }
 +                    TypeBound::Lifetime(_) | TypeBound::Error => false,
 +                }
 +            }
 +            WherePredicate::Lifetime { .. } => false,
 +        })
 +        .flat_map(|pred| {
 +            ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p))
 +        })
 +        .collect();
 +
 +    let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
 +    let implicitly_sized_predicates =
 +        implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &subst, &resolver)
 +            .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p)));
 +    predicates.extend(implicitly_sized_predicates);
 +    predicates.into()
 +}
 +
 +pub(crate) fn generic_predicates_for_param_recover(
 +    _db: &dyn HirDatabase,
 +    _cycle: &[String],
 +    _def: &GenericDefId,
 +    _param_id: &TypeOrConstParamId,
 +    _assoc_name: &Option<Name>,
 +) -> Arc<[Binders<QuantifiedWhereClause>]> {
 +    Arc::new([])
 +}
 +
 +pub(crate) fn trait_environment_query(
 +    db: &dyn HirDatabase,
 +    def: GenericDefId,
 +) -> Arc<TraitEnvironment> {
 +    let resolver = def.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Placeholder);
 +    let mut traits_in_scope = Vec::new();
 +    let mut clauses = Vec::new();
 +    for pred in resolver.where_predicates_in_scope() {
 +        for pred in ctx.lower_where_predicate(pred, false) {
 +            if let WhereClause::Implemented(tr) = &pred.skip_binders() {
 +                traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
 +            }
 +            let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
 +            clauses.push(program_clause.into_from_env_clause(Interner));
 +        }
 +    }
 +
 +    let container: Option<ItemContainerId> = match def {
 +        // FIXME: is there a function for this?
 +        GenericDefId::FunctionId(f) => Some(f.lookup(db.upcast()).container),
 +        GenericDefId::AdtId(_) => None,
 +        GenericDefId::TraitId(_) => None,
 +        GenericDefId::TypeAliasId(t) => Some(t.lookup(db.upcast()).container),
 +        GenericDefId::ImplId(_) => None,
 +        GenericDefId::EnumVariantId(_) => None,
 +        GenericDefId::ConstId(c) => Some(c.lookup(db.upcast()).container),
 +    };
 +    if let Some(ItemContainerId::TraitId(trait_id)) = container {
 +        // add `Self: Trait<T1, T2, ...>` to the environment in trait
 +        // function default implementations (and speculative code
 +        // inside consts or type aliases)
 +        cov_mark::hit!(trait_self_implements_self);
 +        let substs = TyBuilder::placeholder_subst(db, trait_id);
 +        let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
 +        let pred = WhereClause::Implemented(trait_ref);
 +        let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
 +        clauses.push(program_clause.into_from_env_clause(Interner));
 +    }
 +
 +    let subst = generics(db.upcast(), def).placeholder_subst(db);
 +    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
 +    let implicitly_sized_clauses =
 +        implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver).map(|pred| {
 +            let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
 +            program_clause.into_from_env_clause(Interner)
 +        });
 +    clauses.extend(implicitly_sized_clauses);
 +
 +    let krate = def.module(db.upcast()).krate();
 +
 +    let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses);
 +
 +    Arc::new(TraitEnvironment { krate, traits_from_clauses: traits_in_scope, env })
 +}
 +
 +/// Resolve the where clause(s) of an item with generics.
 +pub(crate) fn generic_predicates_query(
 +    db: &dyn HirDatabase,
 +    def: GenericDefId,
 +) -> Arc<[Binders<QuantifiedWhereClause>]> {
 +    let resolver = def.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    let generics = generics(db.upcast(), def);
 +
 +    let mut predicates = resolver
 +        .where_predicates_in_scope()
 +        .flat_map(|pred| {
 +            ctx.lower_where_predicate(pred, false).map(|p| make_binders(db, &generics, p))
 +        })
 +        .collect::<Vec<_>>();
 +
 +    let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
 +    let implicitly_sized_predicates =
 +        implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
 +            .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p)));
 +    predicates.extend(implicitly_sized_predicates);
 +    predicates.into()
 +}
 +
 +/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
 +/// Exception is Self of a trait def.
 +fn implicitly_sized_clauses<'a>(
 +    db: &dyn HirDatabase,
 +    def: GenericDefId,
 +    explicitly_unsized_tys: &'a FxHashSet<Ty>,
 +    substitution: &'a Substitution,
 +    resolver: &Resolver,
 +) -> impl Iterator<Item = WhereClause> + 'a {
 +    let is_trait_def = matches!(def, GenericDefId::TraitId(..));
 +    let generic_args = &substitution.as_slice(Interner)[is_trait_def as usize..];
 +    let sized_trait = db
 +        .lang_item(resolver.krate(), SmolStr::new_inline("sized"))
 +        .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
 +
 +    sized_trait.into_iter().flat_map(move |sized_trait| {
 +        let implicitly_sized_tys = generic_args
 +            .iter()
 +            .filter_map(|generic_arg| generic_arg.ty(Interner))
 +            .filter(move |&self_ty| !explicitly_unsized_tys.contains(self_ty));
 +        implicitly_sized_tys.map(move |self_ty| {
 +            WhereClause::Implemented(TraitRef {
 +                trait_id: sized_trait,
 +                substitution: Substitution::from1(Interner, self_ty.clone()),
 +            })
 +        })
 +    })
 +}
 +
 +/// Resolve the default type params from generics
 +pub(crate) fn generic_defaults_query(
 +    db: &dyn HirDatabase,
 +    def: GenericDefId,
 +) -> Arc<[Binders<chalk_ir::GenericArg<Interner>>]> {
 +    let resolver = def.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    let generic_params = generics(db.upcast(), def);
 +
 +    let defaults = generic_params
 +        .iter()
 +        .enumerate()
 +        .map(|(idx, (id, p))| {
 +            let p = match p {
 +                TypeOrConstParamData::TypeParamData(p) => p,
 +                TypeOrConstParamData::ConstParamData(_) => {
 +                    // FIXME: implement const generic defaults
 +                    let val = unknown_const_as_generic(
 +                        db.const_param_ty(ConstParamId::from_unchecked(id)),
 +                    );
 +                    return crate::make_binders_with_count(db, idx, &generic_params, val);
 +                }
 +            };
 +            let mut ty =
 +                p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
 +
 +            // Each default can only refer to previous parameters.
 +            // type variable default referring to parameter coming
 +            // after it. This is forbidden (FIXME: report
 +            // diagnostic)
 +            ty = fallback_bound_vars(ty, idx);
 +            let val = GenericArgData::Ty(ty).intern(Interner);
 +            crate::make_binders_with_count(db, idx, &generic_params, val)
 +        })
 +        .collect();
 +
 +    defaults
 +}
 +
 +pub(crate) fn generic_defaults_recover(
 +    db: &dyn HirDatabase,
 +    _cycle: &[String],
 +    def: &GenericDefId,
 +) -> Arc<[Binders<crate::GenericArg>]> {
 +    let generic_params = generics(db.upcast(), *def);
 +    // FIXME: this code is not covered in tests.
 +    // we still need one default per parameter
 +    let defaults = generic_params
 +        .iter_id()
 +        .enumerate()
 +        .map(|(count, id)| {
 +            let val = match id {
 +                itertools::Either::Left(_) => {
 +                    GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
 +                }
 +                itertools::Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
 +            };
 +            crate::make_binders_with_count(db, count, &generic_params, val)
 +        })
 +        .collect();
 +
 +    defaults
 +}
 +
 +fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
 +    let data = db.function_data(def);
 +    let resolver = def.resolver(db.upcast());
 +    let ctx_params = TyLoweringContext::new(db, &resolver)
 +        .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
 +        .with_type_param_mode(ParamLoweringMode::Variable);
 +    let params = data.params.iter().map(|(_, tr)| ctx_params.lower_ty(tr)).collect::<Vec<_>>();
 +    let ctx_ret = TyLoweringContext::new(db, &resolver)
 +        .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
 +        .with_type_param_mode(ParamLoweringMode::Variable);
 +    let ret = ctx_ret.lower_ty(&data.ret_type);
 +    let generics = generics(db.upcast(), def.into());
 +    let sig = CallableSig::from_params_and_return(params, ret, data.is_varargs());
 +    make_binders(db, &generics, sig)
 +}
 +
 +/// Build the declared type of a function. This should not need to look at the
 +/// function body.
 +fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> {
 +    let generics = generics(db.upcast(), def.into());
 +    let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +    make_binders(
 +        db,
 +        &generics,
 +        TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(Interner),
 +    )
 +}
 +
 +/// Build the declared type of a const.
 +fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> {
 +    let data = db.const_data(def);
 +    let generics = generics(db.upcast(), def.into());
 +    let resolver = def.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +
 +    make_binders(db, &generics, ctx.lower_ty(&data.type_ref))
 +}
 +
 +/// Build the declared type of a static.
 +fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> {
 +    let data = db.static_data(def);
 +    let resolver = def.resolver(db.upcast());
 +    let ctx = TyLoweringContext::new(db, &resolver);
 +
 +    Binders::empty(Interner, ctx.lower_ty(&data.type_ref))
 +}
 +
 +fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig {
 +    let struct_data = db.struct_data(def);
 +    let fields = struct_data.variant_data.fields();
 +    let resolver = def.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
 +    let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
 +    Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
 +}
 +
 +/// Build the type of a tuple struct constructor.
 +fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders<Ty> {
 +    let struct_data = db.struct_data(def);
 +    if let StructKind::Unit = struct_data.variant_data.kind() {
 +        return type_for_adt(db, def.into());
 +    }
 +    let generics = generics(db.upcast(), def.into());
 +    let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +    make_binders(
 +        db,
 +        &generics,
 +        TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(Interner),
 +    )
 +}
 +
 +fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> PolyFnSig {
 +    let enum_data = db.enum_data(def.parent);
 +    let var_data = &enum_data.variants[def.local_id];
 +    let fields = var_data.variant_data.fields();
 +    let resolver = def.parent.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
 +    let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders();
 +    Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
 +}
 +
 +/// Build the type of a tuple enum variant constructor.
 +fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> Binders<Ty> {
 +    let enum_data = db.enum_data(def.parent);
 +    let var_data = &enum_data.variants[def.local_id].variant_data;
 +    if let StructKind::Unit = var_data.kind() {
 +        return type_for_adt(db, def.parent.into());
 +    }
 +    let generics = generics(db.upcast(), def.parent.into());
 +    let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +    make_binders(
 +        db,
 +        &generics,
 +        TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs).intern(Interner),
 +    )
 +}
 +
 +fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
 +    let generics = generics(db.upcast(), adt.into());
 +    let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +    let ty = TyKind::Adt(crate::AdtId(adt), subst).intern(Interner);
 +    make_binders(db, &generics, ty)
 +}
 +
 +fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
 +    let generics = generics(db.upcast(), t.into());
 +    let resolver = t.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    if db.type_alias_data(t).is_extern {
 +        Binders::empty(Interner, TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner))
 +    } else {
 +        let type_ref = &db.type_alias_data(t).type_ref;
 +        let inner = ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error));
 +        make_binders(db, &generics, inner)
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum CallableDefId {
 +    FunctionId(FunctionId),
 +    StructId(StructId),
 +    EnumVariantId(EnumVariantId),
 +}
 +impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId);
 +
 +impl CallableDefId {
 +    pub fn krate(self, db: &dyn HirDatabase) -> CrateId {
 +        let db = db.upcast();
 +        match self {
 +            CallableDefId::FunctionId(f) => f.lookup(db).module(db),
 +            CallableDefId::StructId(s) => s.lookup(db).container,
 +            CallableDefId::EnumVariantId(e) => e.parent.lookup(db).container,
 +        }
 +        .krate()
 +    }
 +}
 +
 +impl From<CallableDefId> for GenericDefId {
 +    fn from(def: CallableDefId) -> GenericDefId {
 +        match def {
 +            CallableDefId::FunctionId(f) => f.into(),
 +            CallableDefId::StructId(s) => s.into(),
 +            CallableDefId::EnumVariantId(e) => e.into(),
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum TyDefId {
 +    BuiltinType(BuiltinType),
 +    AdtId(AdtId),
 +    TypeAliasId(TypeAliasId),
 +}
 +impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefId);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum ValueTyDefId {
 +    FunctionId(FunctionId),
 +    StructId(StructId),
 +    UnionId(UnionId),
 +    EnumVariantId(EnumVariantId),
 +    ConstId(ConstId),
 +    StaticId(StaticId),
 +}
 +impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
 +
 +/// Build the declared type of an item. This depends on the namespace; e.g. for
 +/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
 +/// the constructor function `(usize) -> Foo` which lives in the values
 +/// namespace.
 +pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> {
 +    match def {
 +        TyDefId::BuiltinType(it) => Binders::empty(Interner, TyBuilder::builtin(it)),
 +        TyDefId::AdtId(it) => type_for_adt(db, it),
 +        TyDefId::TypeAliasId(it) => type_for_type_alias(db, it),
 +    }
 +}
 +
 +pub(crate) fn ty_recover(db: &dyn HirDatabase, _cycle: &[String], def: &TyDefId) -> Binders<Ty> {
 +    let generics = match *def {
 +        TyDefId::BuiltinType(_) => return Binders::empty(Interner, TyKind::Error.intern(Interner)),
 +        TyDefId::AdtId(it) => generics(db.upcast(), it.into()),
 +        TyDefId::TypeAliasId(it) => generics(db.upcast(), it.into()),
 +    };
 +    make_binders(db, &generics, TyKind::Error.intern(Interner))
 +}
 +
 +pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders<Ty> {
 +    match def {
 +        ValueTyDefId::FunctionId(it) => type_for_fn(db, it),
 +        ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it),
 +        ValueTyDefId::UnionId(it) => type_for_adt(db, it.into()),
 +        ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it),
 +        ValueTyDefId::ConstId(it) => type_for_const(db, it),
 +        ValueTyDefId::StaticId(it) => type_for_static(db, it),
 +    }
 +}
 +
 +pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders<Ty> {
 +    let impl_loc = impl_id.lookup(db.upcast());
 +    let impl_data = db.impl_data(impl_id);
 +    let resolver = impl_id.resolver(db.upcast());
 +    let _cx = stdx::panic_context::enter(format!(
 +        "impl_self_ty_query({:?} -> {:?} -> {:?})",
 +        impl_id, impl_loc, impl_data
 +    ));
 +    let generics = generics(db.upcast(), impl_id.into());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    make_binders(db, &generics, ctx.lower_ty(&impl_data.self_ty))
 +}
 +
 +// returns None if def is a type arg
 +pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
 +    let parent_data = db.generic_params(def.parent());
 +    let data = &parent_data.type_or_consts[def.local_id()];
 +    let resolver = def.parent().resolver(db.upcast());
 +    let ctx = TyLoweringContext::new(db, &resolver);
 +    match data {
 +        TypeOrConstParamData::TypeParamData(_) => {
 +            never!();
 +            Ty::new(Interner, TyKind::Error)
 +        }
 +        TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(&d.ty),
 +    }
 +}
 +
 +pub(crate) fn impl_self_ty_recover(
 +    db: &dyn HirDatabase,
 +    _cycle: &[String],
 +    impl_id: &ImplId,
 +) -> Binders<Ty> {
 +    let generics = generics(db.upcast(), (*impl_id).into());
 +    make_binders(db, &generics, TyKind::Error.intern(Interner))
 +}
 +
 +pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
 +    let impl_loc = impl_id.lookup(db.upcast());
 +    let impl_data = db.impl_data(impl_id);
 +    let resolver = impl_id.resolver(db.upcast());
 +    let _cx = stdx::panic_context::enter(format!(
 +        "impl_trait_query({:?} -> {:?} -> {:?})",
 +        impl_id, impl_loc, impl_data
 +    ));
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
 +    let target_trait = impl_data.target_trait.as_ref()?;
 +    Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, Some(self_ty))?))
 +}
 +
 +pub(crate) fn return_type_impl_traits(
 +    db: &dyn HirDatabase,
 +    def: hir_def::FunctionId,
 +) -> Option<Arc<Binders<ReturnTypeImplTraits>>> {
 +    // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
 +    let data = db.function_data(def);
 +    let resolver = def.resolver(db.upcast());
 +    let ctx_ret = TyLoweringContext::new(db, &resolver)
 +        .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
 +        .with_type_param_mode(ParamLoweringMode::Variable);
 +    let _ret = (&ctx_ret).lower_ty(&data.ret_type);
 +    let generics = generics(db.upcast(), def.into());
 +    let return_type_impl_traits =
 +        ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() };
 +    if return_type_impl_traits.impl_traits.is_empty() {
 +        None
 +    } else {
 +        Some(Arc::new(make_binders(db, &generics, return_type_impl_traits)))
 +    }
 +}
 +
 +pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mutability {
 +    match m {
 +        hir_def::type_ref::Mutability::Shared => Mutability::Not,
 +        hir_def::type_ref::Mutability::Mut => Mutability::Mut,
 +    }
 +}
 +
 +/// Checks if the provided generic arg matches its expected kind, then lower them via
 +/// provided closures. Use unknown if there was kind mismatch.
 +///
 +/// Returns `Some` of the lowered generic arg. `None` if the provided arg is a lifetime.
 +pub(crate) fn generic_arg_to_chalk<'a, T>(
 +    db: &dyn HirDatabase,
 +    kind_id: Either<TypeParamId, ConstParamId>,
 +    arg: &'a GenericArg,
 +    this: &mut T,
 +    for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
 +    for_const: impl FnOnce(&mut T, &ConstScalarOrPath, Ty) -> Const + 'a,
 +) -> Option<crate::GenericArg> {
 +    let kind = match kind_id {
 +        Either::Left(_) => ParamKind::Type,
 +        Either::Right(id) => {
 +            let ty = db.const_param_ty(id);
 +            ParamKind::Const(ty)
 +        }
 +    };
 +    Some(match (arg, kind) {
 +        (GenericArg::Type(type_ref), ParamKind::Type) => {
 +            let ty = for_type(this, type_ref);
 +            GenericArgData::Ty(ty).intern(Interner)
 +        }
 +        (GenericArg::Const(c), ParamKind::Const(c_ty)) => {
 +            GenericArgData::Const(for_const(this, c, c_ty)).intern(Interner)
 +        }
 +        (GenericArg::Const(_), ParamKind::Type) => {
 +            GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
 +        }
 +        (GenericArg::Type(t), ParamKind::Const(c_ty)) => {
 +            // We want to recover simple idents, which parser detects them
 +            // as types. Maybe here is not the best place to do it, but
 +            // it works.
 +            if let TypeRef::Path(p) = t {
 +                let p = p.mod_path();
 +                if p.kind == PathKind::Plain {
 +                    if let [n] = p.segments() {
 +                        let c = ConstScalarOrPath::Path(n.clone());
 +                        return Some(
 +                            GenericArgData::Const(for_const(this, &c, c_ty)).intern(Interner),
 +                        );
 +                    }
 +                }
 +            }
 +            unknown_const_as_generic(c_ty)
 +        }
 +        (GenericArg::Lifetime(_), _) => return None,
 +    })
 +}
 +
 +pub(crate) fn const_or_path_to_chalk(
 +    db: &dyn HirDatabase,
 +    resolver: &Resolver,
 +    expected_ty: Ty,
 +    value: &ConstScalarOrPath,
 +    mode: ParamLoweringMode,
 +    args: impl FnOnce() -> Generics,
 +    debruijn: DebruijnIndex,
 +) -> Const {
 +    match value {
 +        ConstScalarOrPath::Scalar(s) => intern_const_scalar(s.clone(), expected_ty),
 +        ConstScalarOrPath::Path(n) => {
 +            let path = ModPath::from_segments(PathKind::Plain, Some(n.clone()));
 +            path_to_const(db, resolver, &path, mode, args, debruijn)
 +                .unwrap_or_else(|| unknown_const(expected_ty))
 +        }
 +    }
 +}
 +
 +/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
 +/// num_vars_to_keep) by `TyKind::Unknown`.
 +fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
 +    s: T,
 +    num_vars_to_keep: usize,
 +) -> T {
 +    crate::fold_free_vars(
 +        s,
 +        |bound, binders| {
 +            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
 +                TyKind::Error.intern(Interner)
 +            } else {
 +                bound.shifted_in_from(binders).to_ty(Interner)
 +            }
 +        },
 +        |ty, bound, binders| {
 +            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
 +                unknown_const(ty.clone())
 +            } else {
 +                bound.shifted_in_from(binders).to_const(Interner, ty)
 +            }
 +        },
 +    )
 +}
index 64622545f8408b190cec4f87e906a0627d515a6a,0000000000000000000000000000000000000000..9a63d5013b4671274e8c93747049a5aa11fd33c7
mode 100644,000000..100644
--- /dev/null
@@@ -1,1235 -1,0 +1,1287 @@@
-     macro_rules! check_that {
-         ($cond:expr) => {
-             if !$cond {
-                 return false;
-             }
-         };
-     }
 +//! 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 librustc_typeck/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_).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(..));
 +    // if ty is `dyn Trait`, the trait doesn't need to be in scope
 +    let inherent_trait =
 +        self_ty.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
 +    let env_traits = matches!(self_ty.kind(Interner), TyKind::Placeholder(_))
 +        // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
 +        .then(|| {
 +            env.traits_in_scope_from_clauses(self_ty.clone())
 +                .flat_map(|t| all_super_traits(db.upcast(), t))
 +        })
 +        .into_iter()
 +        .flatten();
 +    let traits = inherent_trait.chain(env_traits).chain(traits_in_scope.iter().copied());
 +
 +    let canonical_self_ty = table.canonicalize(self_ty.clone()).value;
 +
 +    'traits: for t in traits {
 +        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();
 +    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 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 data = db.function_data(m);
-             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(m).is_visible_from(db.upcast(), from_module);
-                 if !v {
-                     cov_mark::hit!(autoderef_candidate_not_visible);
-                 }
-                 v
-             }));
-             table.run_in_snapshot(|table| {
-                 let subst = TyBuilder::subst_for_def(db, m).fill_with_inference_vars(table).build();
-                 let expect_self_ty = match m.lookup(db.upcast()).container {
-                     ItemContainerId::TraitId(_) => {
-                         subst.at(Interner, 0).assert_ty_ref(Interner).clone()
-                     }
-                     ItemContainerId::ImplId(impl_id) => {
-                         subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner)
-                     }
-                     // We should only get called for associated items (impl/trait)
-                     ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
-                         unreachable!()
-                     }
-                 };
-                 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(m.into());
-                     let expected_receiver =
-                         sig.map(|s| s.params()[0].clone()).substitute(Interner, &subst);
-                     check_that!(table.unify(&receiver_ty, &expected_receiver));
-                 }
-                 true
-             })
 +    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 subst =
 +                        TyBuilder::subst_for_def(db, c).fill_with_inference_vars(table).build();
 +                    let expected_self_ty =
 +                        subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner);
 +                    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 = match container {
++            ItemContainerId::ImplId(it) => {
++                TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
++            }
++            ItemContainerId::TraitId(it) => {
++                TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
++            }
++            _ => unreachable!(),
++        };
++
++        let fn_subst = TyBuilder::subst_for_def(db, fn_id)
++            .use_parent_substs(&impl_subst)
++            .fill_with_inference_vars(table)
++            .build();
++
++        let expect_self_ty = match container {
++            ItemContainerId::TraitId(_) => fn_subst.at(Interner, 0).assert_ty_ref(Interner).clone(),
++            ItemContainerId::ImplId(impl_id) => {
++                fn_subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner)
++            }
++            // We should only get called for associated items (impl/trait)
++            ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
++                unreachable!()
++            }
++        };
++        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 68463dc068bcf3d870ab787e380b27f337daa543,0000000000000000000000000000000000000000..81588a7c4ffd668bb6ccfb92f65e3628b09cb5a7
mode 100644,000000..100644
--- /dev/null
@@@ -1,1792 -1,0 +1,1835 @@@
 +use expect_test::expect;
 +
 +use crate::tests::check;
 +
 +use super::{check_infer, check_no_mismatches, check_types};
 +
 +#[test]
 +fn infer_slice_method() {
 +    check_types(
 +        r#"
 +impl<T> [T] {
 +    fn foo(&self) -> T {
 +        loop {}
 +    }
 +}
 +
 +fn test(x: &[u8]) {
 +    <[_]>::foo(x);
 +  //^^^^^^^^^^^^^ u8
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn cross_crate_primitive_method() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:other_crate
 +fn test() {
 +    let x = 1f32;
 +    x.foo();
 +} //^^^^^^^ f32
 +
 +//- /lib.rs crate:other_crate
 +mod foo {
 +    impl f32 {
 +        pub fn foo(self) -> f32 { 0. }
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_array_inherent_impl() {
 +    check_types(
 +        r#"
 +impl<T, const N: usize> [T; N] {
 +    fn foo(&self) -> T {
 +        loop {}
 +    }
 +}
 +fn test(x: &[u8; 0]) {
 +    <[_; 0]>::foo(x);
 +  //^^^^^^^^^^^^^^^^ u8
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_method_struct() {
 +    check_infer(
 +        r#"
 +        struct A { x: u32 }
 +
 +        impl A {
 +            fn new() -> A {
 +                A { x: 0 }
 +            }
 +        }
 +        fn test() {
 +            let a = A::new();
 +            a.x;
 +        }
 +        "#,
 +        expect![[r#"
 +            48..74 '{     ...     }': A
 +            58..68 'A { x: 0 }': A
 +            65..66 '0': u32
 +            87..121 '{     ...a.x; }': ()
 +            97..98 'a': A
 +            101..107 'A::new': fn new() -> A
 +            101..109 'A::new()': A
 +            115..116 'a': A
 +            115..118 'a.x': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_method_struct_in_local_scope() {
 +    check_infer(
 +        r#"
 +        fn mismatch() {
 +            struct A;
 +
 +            impl A {
 +                fn from(_: i32, _: i32) -> Self {
 +                    A
 +                }
 +            }
 +
 +            let _a = A::from(1, 2);
 +        }
 +        "#,
 +        expect![[r#"
 +            14..146 '{     ... 2); }': ()
 +            125..127 '_a': A
 +            130..137 'A::from': fn from(i32, i32) -> A
 +            130..143 'A::from(1, 2)': A
 +            138..139 '1': i32
 +            141..142 '2': i32
 +            60..61 '_': i32
 +            68..69 '_': i32
 +            84..109 '{     ...     }': A
 +            98..99 'A': A
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_method_enum() {
 +    check_infer(
 +        r#"
 +        enum A { B, C }
 +
 +        impl A {
 +            pub fn b() -> A {
 +                A::B
 +            }
 +            pub fn c() -> A {
 +                A::C
 +            }
 +        }
 +        fn test() {
 +            let a = A::b();
 +            a;
 +            let c = A::c();
 +            c;
 +        }
 +        "#,
 +        expect![[r#"
 +            46..66 '{     ...     }': A
 +            56..60 'A::B': A
 +            87..107 '{     ...     }': A
 +            97..101 'A::C': A
 +            120..177 '{     ...  c; }': ()
 +            130..131 'a': A
 +            134..138 'A::b': fn b() -> A
 +            134..140 'A::b()': A
 +            146..147 'a': A
 +            157..158 'c': A
 +            161..165 'A::c': fn c() -> A
 +            161..167 'A::c()': A
 +            173..174 'c': A
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_method_with_modules() {
 +    check_infer(
 +        r#"
 +        mod a {
 +            struct A;
 +            impl A { pub fn thing() -> A { A {} }}
 +        }
 +
 +        mod b {
 +            struct B;
 +            impl B { pub fn thing() -> u32 { 99 }}
 +
 +            mod c {
 +                struct C;
 +                impl C { pub fn thing() -> C { C {} }}
 +            }
 +        }
 +        use b::c;
 +
 +        fn test() {
 +            let x = a::A::thing();
 +            let y = b::B::thing();
 +            let z = c::C::thing();
 +        }
 +        "#,
 +        expect![[r#"
 +            55..63 '{ A {} }': A
 +            57..61 'A {}': A
 +            125..131 '{ 99 }': u32
 +            127..129 '99': u32
 +            201..209 '{ C {} }': C
 +            203..207 'C {}': C
 +            240..324 '{     ...g(); }': ()
 +            250..251 'x': A
 +            254..265 'a::A::thing': fn thing() -> A
 +            254..267 'a::A::thing()': A
 +            277..278 'y': u32
 +            281..292 'b::B::thing': fn thing() -> u32
 +            281..294 'b::B::thing()': u32
 +            304..305 'z': C
 +            308..319 'c::C::thing': fn thing() -> C
 +            308..321 'c::C::thing()': C
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_method_generics() {
 +    check_infer(
 +        r#"
 +        struct Gen<T> {
 +            val: T
 +        }
 +
 +        impl<T> Gen<T> {
 +            pub fn make(val: T) -> Gen<T> {
 +                Gen { val }
 +            }
 +        }
 +
 +        fn test() {
 +            let a = Gen::make(0u32);
 +        }
 +        "#,
 +        expect![[r#"
 +            63..66 'val': T
 +            81..108 '{     ...     }': Gen<T>
 +            91..102 'Gen { val }': Gen<T>
 +            97..100 'val': T
 +            122..154 '{     ...32); }': ()
 +            132..133 'a': Gen<u32>
 +            136..145 'Gen::make': fn make<u32>(u32) -> Gen<u32>
 +            136..151 'Gen::make(0u32)': Gen<u32>
 +            146..150 '0u32': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_method_generics_without_args() {
 +    check_infer(
 +        r#"
 +        struct Gen<T> {
 +            val: T
 +        }
 +
 +        impl<T> Gen<T> {
 +            pub fn make() -> Gen<T> {
 +                loop { }
 +            }
 +        }
 +
 +        fn test() {
 +            let a = Gen::<u32>::make();
 +        }
 +        "#,
 +        expect![[r#"
 +            75..99 '{     ...     }': Gen<T>
 +            85..93 'loop { }': !
 +            90..93 '{ }': ()
 +            113..148 '{     ...e(); }': ()
 +            123..124 'a': Gen<u32>
 +            127..143 'Gen::<...::make': fn make<u32>() -> Gen<u32>
 +            127..145 'Gen::<...make()': Gen<u32>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_method_generics_2_type_params_without_args() {
 +    check_infer(
 +        r#"
 +        struct Gen<T, U> {
 +            val: T,
 +            val2: U,
 +        }
 +
 +        impl<T> Gen<u32, T> {
 +            pub fn make() -> Gen<u32,T> {
 +                loop { }
 +            }
 +        }
 +
 +        fn test() {
 +            let a = Gen::<u32, u64>::make();
 +        }
 +        "#,
 +        expect![[r#"
 +            101..125 '{     ...     }': Gen<u32, T>
 +            111..119 'loop { }': !
 +            116..119 '{ }': ()
 +            139..179 '{     ...e(); }': ()
 +            149..150 'a': Gen<u32, u64>
 +            153..174 'Gen::<...::make': fn make<u64>() -> Gen<u32, u64>
 +            153..176 'Gen::<...make()': Gen<u32, u64>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn cross_crate_associated_method_call() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:other_crate
 +fn test() {
 +    let x = other_crate::foo::S::thing();
 +    x;
 +} //^ i128
 +
 +//- /lib.rs crate:other_crate
 +pub mod foo {
 +    pub struct S;
 +    impl S {
 +        pub fn thing() -> i128 { 0 }
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_method_simple() {
 +    // the trait implementation is intentionally incomplete -- it shouldn't matter
 +    check_types(
 +        r#"
 +trait Trait1 {
 +    fn method(&self) -> u32;
 +}
 +struct S1;
 +impl Trait1 for S1 {}
 +trait Trait2 {
 +    fn method(&self) -> i128;
 +}
 +struct S2;
 +impl Trait2 for S2 {}
 +fn test() {
 +    S1.method();
 +  //^^^^^^^^^^^ u32
 +    S2.method(); // -> i128
 +  //^^^^^^^^^^^ i128
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_method_scoped() {
 +    // the trait implementation is intentionally incomplete -- it shouldn't matter
 +    check_types(
 +        r#"
 +struct S;
 +mod foo {
 +    pub trait Trait1 {
 +        fn method(&self) -> u32;
 +    }
 +    impl Trait1 for super::S {}
 +}
 +mod bar {
 +    pub trait Trait2 {
 +        fn method(&self) -> i128;
 +    }
 +    impl Trait2 for super::S {}
 +}
 +
 +mod foo_test {
 +    use super::S;
 +    use super::foo::Trait1;
 +    fn test() {
 +        S.method();
 +      //^^^^^^^^^^ u32
 +    }
 +}
 +
 +mod bar_test {
 +    use super::S;
 +    use super::bar::Trait2;
 +    fn test() {
 +        S.method();
 +      //^^^^^^^^^^ i128
 +    }
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_method_generic_1() {
 +    // the trait implementation is intentionally incomplete -- it shouldn't matter
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +    fn method(&self) -> T;
 +}
 +struct S;
 +impl Trait<u32> for S {}
 +fn test() {
 +    S.method();
 +  //^^^^^^^^^^ u32
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_method_generic_more_params() {
 +    // the trait implementation is intentionally incomplete -- it shouldn't matter
 +    check_types(
 +        r#"
 +trait Trait<T1, T2, T3> {
 +    fn method1(&self) -> (T1, T2, T3);
 +    fn method2(&self) -> (T3, T2, T1);
 +}
 +struct S1;
 +impl Trait<u8, u16, u32> for S1 {}
 +struct S2;
 +impl<T> Trait<i8, i16, T> for S2 {}
 +fn test() {
 +    S1.method1();
 +  //^^^^^^^^^^^^ (u8, u16, u32)
 +    S1.method2();
 +  //^^^^^^^^^^^^ (u32, u16, u8)
 +    S2.method1();
 +  //^^^^^^^^^^^^ (i8, i16, {unknown})
 +    S2.method2();
 +  //^^^^^^^^^^^^ ({unknown}, i16, i8)
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_method_generic_2() {
 +    // the trait implementation is intentionally incomplete -- it shouldn't matter
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +    fn method(&self) -> T;
 +}
 +struct S<T>(T);
 +impl<U> Trait<U> for S<U> {}
 +fn test() {
 +    S(1u32).method();
 +  //^^^^^^^^^^^^^^^^ u32
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_assoc_method() {
 +    check_infer(
 +        r#"
 +        trait Default {
 +            fn default() -> Self;
 +        }
 +        struct S;
 +        impl Default for S {}
 +        fn test() {
 +            let s1: S = Default::default();
 +            let s2 = S::default();
 +            let s3 = <S as Default>::default();
 +        }
 +        "#,
 +        expect![[r#"
 +            86..192 '{     ...t(); }': ()
 +            96..98 's1': S
 +            104..120 'Defaul...efault': fn default<S>() -> S
 +            104..122 'Defaul...ault()': S
 +            132..134 's2': S
 +            137..147 'S::default': fn default<S>() -> S
 +            137..149 'S::default()': S
 +            159..161 's3': S
 +            164..187 '<S as ...efault': fn default<S>() -> S
 +            164..189 '<S as ...ault()': S
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_assoc_method_generics_1() {
 +    check_infer(
 +        r#"
 +        trait Trait<T> {
 +            fn make() -> T;
 +        }
 +        struct S;
 +        impl Trait<u32> for S {}
 +        struct G<T>;
 +        impl<T> Trait<T> for G<T> {}
 +        fn test() {
 +            let a = S::make();
 +            let b = G::<u64>::make();
 +            let c: f64 = G::make();
 +        }
 +        "#,
 +        expect![[r#"
 +            126..210 '{     ...e(); }': ()
 +            136..137 'a': u32
 +            140..147 'S::make': fn make<S, u32>() -> u32
 +            140..149 'S::make()': u32
 +            159..160 'b': u64
 +            163..177 'G::<u64>::make': fn make<G<u64>, u64>() -> u64
 +            163..179 'G::<u6...make()': u64
 +            189..190 'c': f64
 +            198..205 'G::make': fn make<G<f64>, f64>() -> f64
 +            198..207 'G::make()': f64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_assoc_method_generics_2() {
 +    check_infer(
 +        r#"
 +        trait Trait<T> {
 +            fn make<U>() -> (T, U);
 +        }
 +        struct S;
 +        impl Trait<u32> for S {}
 +        struct G<T>;
 +        impl<T> Trait<T> for G<T> {}
 +        fn test() {
 +            let a = S::make::<i64>();
 +            let b: (_, i64) = S::make();
 +            let c = G::<u32>::make::<i64>();
 +            let d: (u32, _) = G::make::<i64>();
 +            let e: (u32, i64) = G::make();
 +        }
 +        "#,
 +        expect![[r#"
 +            134..312 '{     ...e(); }': ()
 +            144..145 'a': (u32, i64)
 +            148..162 'S::make::<i64>': fn make<S, u32, i64>() -> (u32, i64)
 +            148..164 'S::mak...i64>()': (u32, i64)
 +            174..175 'b': (u32, i64)
 +            188..195 'S::make': fn make<S, u32, i64>() -> (u32, i64)
 +            188..197 'S::make()': (u32, i64)
 +            207..208 'c': (u32, i64)
 +            211..232 'G::<u3...:<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64)
 +            211..234 'G::<u3...i64>()': (u32, i64)
 +            244..245 'd': (u32, i64)
 +            258..272 'G::make::<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64)
 +            258..274 'G::mak...i64>()': (u32, i64)
 +            284..285 'e': (u32, i64)
 +            300..307 'G::make': fn make<G<u32>, u32, i64>() -> (u32, i64)
 +            300..309 'G::make()': (u32, i64)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_assoc_method_generics_3() {
 +    check_infer(
 +        r#"
 +        trait Trait<T> {
 +            fn make() -> (Self, T);
 +        }
 +        struct S<T>;
 +        impl Trait<i64> for S<i32> {}
 +        fn test() {
 +            let a = S::make();
 +        }
 +        "#,
 +        expect![[r#"
 +            100..126 '{     ...e(); }': ()
 +            110..111 'a': (S<i32>, i64)
 +            114..121 'S::make': fn make<S<i32>, i64>() -> (S<i32>, i64)
 +            114..123 'S::make()': (S<i32>, i64)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_assoc_method_generics_4() {
 +    check_infer(
 +        r#"
 +        trait Trait<T> {
 +            fn make() -> (Self, T);
 +        }
 +        struct S<T>;
 +        impl Trait<i64> for S<u64> {}
 +        impl Trait<i32> for S<u32> {}
 +        fn test() {
 +            let a: (S<u64>, _) = S::make();
 +            let b: (_, i32) = S::make();
 +        }
 +        "#,
 +        expect![[r#"
 +            130..202 '{     ...e(); }': ()
 +            140..141 'a': (S<u64>, i64)
 +            157..164 'S::make': fn make<S<u64>, i64>() -> (S<u64>, i64)
 +            157..166 'S::make()': (S<u64>, i64)
 +            176..177 'b': (S<u32>, i32)
 +            190..197 'S::make': fn make<S<u32>, i32>() -> (S<u32>, i32)
 +            190..199 'S::make()': (S<u32>, i32)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_trait_assoc_method_generics_5() {
 +    check_infer(
 +        r#"
 +        trait Trait<T> {
 +            fn make<U>() -> (Self, T, U);
 +        }
 +        struct S<T>;
 +        impl Trait<i64> for S<u64> {}
 +        fn test() {
 +            let a = <S as Trait<i64>>::make::<u8>();
 +            let b: (S<u64>, _, _) = Trait::<i64>::make::<u8>();
 +        }
 +        "#,
 +        expect![[r#"
 +            106..210 '{     ...>(); }': ()
 +            116..117 'a': (S<u64>, i64, u8)
 +            120..149 '<S as ...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8)
 +            120..151 '<S as ...<u8>()': (S<u64>, i64, u8)
 +            161..162 'b': (S<u64>, i64, u8)
 +            181..205 'Trait:...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8)
 +            181..207 'Trait:...<u8>()': (S<u64>, i64, u8)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_call_trait_method_on_generic_param_1() {
 +    check_infer(
 +        r#"
 +        trait Trait {
 +            fn method(&self) -> u32;
 +        }
 +        fn test<T: Trait>(t: T) {
 +            t.method();
 +        }
 +        "#,
 +        expect![[r#"
 +            29..33 'self': &Self
 +            63..64 't': T
 +            69..88 '{     ...d(); }': ()
 +            75..76 't': T
 +            75..85 't.method()': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_call_trait_method_on_generic_param_2() {
 +    check_infer(
 +        r#"
 +        trait Trait<T> {
 +            fn method(&self) -> T;
 +        }
 +        fn test<U, T: Trait<U>>(t: T) {
 +            t.method();
 +        }
 +        "#,
 +        expect![[r#"
 +            32..36 'self': &Self
 +            70..71 't': T
 +            76..95 '{     ...d(); }': ()
 +            82..83 't': T
 +            82..92 't.method()': U
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_with_multiple_trait_impls() {
 +    check_infer(
 +        r#"
 +        trait Into<T> {
 +            fn into(self) -> T;
 +        }
 +        struct S;
 +        impl Into<u32> for S {}
 +        impl Into<u64> for S {}
 +        fn test() {
 +            let x: u32 = S.into();
 +            let y: u64 = S.into();
 +            let z = Into::<u64>::into(S);
 +        }
 +        "#,
 +        expect![[r#"
 +            28..32 'self': Self
 +            110..201 '{     ...(S); }': ()
 +            120..121 'x': u32
 +            129..130 'S': S
 +            129..137 'S.into()': u32
 +            147..148 'y': u64
 +            156..157 'S': S
 +            156..164 'S.into()': u64
 +            174..175 'z': u64
 +            178..195 'Into::...::into': fn into<S, u64>(S) -> u64
 +            178..198 'Into::...nto(S)': u64
 +            196..197 'S': S
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_unify_impl_self_type() {
 +    check_types(
 +        r#"
 +struct S<T>;
 +impl S<u32> { fn foo(&self) -> u8 { 0 } }
 +impl S<i32> { fn foo(&self) -> i8 { 0 } }
 +fn test() { (S::<u32>.foo(), S::<i32>.foo()); }
 +          //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (u8, i8)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_trait_before_autoref() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl S { fn foo(&self) -> i8 { 0 } }
 +impl Trait for S { fn foo(self) -> u128 { 0 } }
 +fn test() { S.foo(); }
 +          //^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_by_value_before_autoref() {
 +    check_types(
 +        r#"
 +trait Clone { fn clone(&self) -> Self; }
 +struct S;
 +impl Clone for S {}
 +impl Clone for &S {}
 +fn test() { (S.clone(), (&S).clone(), (&&S).clone()); }
 +          //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &S)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_trait_before_autoderef() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl S { fn foo(self) -> i8 { 0 } }
 +impl Trait for &S { fn foo(self) -> u128 { 0 } }
 +fn test() { (&S).foo(); }
 +          //^^^^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_impl_before_trait() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl S { fn foo(self) -> i8 { 0 } }
 +impl Trait for S { fn foo(self) -> u128 { 0 } }
 +fn test() { S.foo(); }
 +          //^^^^^^^ i8
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_impl_ref_before_trait() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl S { fn foo(&self) -> i8 { 0 } }
 +impl Trait for &S { fn foo(self) -> u128 { 0 } }
 +fn test() { S.foo(); }
 +          //^^^^^^^ i8
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_trait_autoderef() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl Trait for S { fn foo(self) -> u128 { 0 } }
 +fn test() { (&S).foo(); }
 +          //^^^^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_unsize_array() {
 +    check_types(
 +        r#"
 +//- minicore: slice
 +fn test() {
 +    let a = [1, 2, 3];
 +    a.len();
 +} //^^^^^^^ usize
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_trait_from_prelude() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:core
 +struct S;
 +impl Clone for S {}
 +
 +fn test() {
 +    S.clone();
 +  //^^^^^^^^^ S
 +}
 +
 +//- /lib.rs crate:core
 +pub mod prelude {
 +    pub mod rust_2018 {
 +        pub trait Clone {
 +            fn clone(&self) -> Self;
 +        }
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_where_clause_for_unknown_trait() {
 +    // The blanket impl currently applies because we ignore the unresolved where clause
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl<T> Trait for T where T: UnknownTrait {}
 +fn test() { (&S).foo(); }
 +          //^^^^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_where_clause_not_met() {
 +    // The blanket impl shouldn't apply because we can't prove S: Clone
 +    // This is also to make sure that we don't resolve to the foo method just
 +    // because that's the only method named foo we can find, which would make
 +    // the below tests not work
 +    check_types(
 +        r#"
 +trait Clone {}
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl<T> Trait for T where T: Clone {}
 +fn test() { (&S).foo(); }
 +          //^^^^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_where_clause_inline_not_met() {
 +    // The blanket impl shouldn't apply because we can't prove S: Clone
 +    check_types(
 +        r#"
 +trait Clone {}
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl<T: Clone> Trait for T {}
 +fn test() { (&S).foo(); }
 +          //^^^^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_where_clause_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() { S.foo(); }
 +          //^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_where_clause_2() {
 +    check_types(
 +        r#"
 +trait Into<T> { fn into(self) -> T; }
 +trait From<T> { fn from(other: T) -> Self; }
 +struct S1;
 +struct S2;
 +impl From<S2> for S1 {}
 +impl<T, U> Into<U> for T where U: From<T> {}
 +fn test() { S2.into(); }
 +          //^^^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_where_clause_inline() {
 +    check_types(
 +        r#"
 +trait Into<T> { fn into(self) -> T; }
 +trait From<T> { fn from(other: T) -> Self; }
 +struct S1;
 +struct S2;
 +impl From<S2> for S1 {}
 +impl<T, U: From<T>> Into<U> for T {}
 +fn test() { S2.into(); }
 +          //^^^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_overloaded_method() {
 +    check_types(
 +        r#"
 +struct Wrapper<T>(T);
 +struct Foo<T>(T);
 +struct Bar<T>(T);
 +
 +impl<T> Wrapper<Foo<T>> {
 +    pub fn new(foo_: T) -> Self {
 +        Wrapper(Foo(foo_))
 +    }
 +}
 +
 +impl<T> Wrapper<Bar<T>> {
 +    pub fn new(bar_: T) -> Self {
 +        Wrapper(Bar(bar_))
 +    }
 +}
 +
 +fn main() {
 +    let a = Wrapper::<Foo<f32>>::new(1.0);
 +    let b = Wrapper::<Bar<f32>>::new(1.0);
 +    (a, b);
 +  //^^^^^^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>)
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_overloaded_const() {
 +    cov_mark::check!(const_candidate_self_type_mismatch);
 +    check_types(
 +        r#"
 +struct Wrapper<T>(T);
 +struct Foo<T>(T);
 +struct Bar<T>(T);
 +
 +impl<T> Wrapper<Foo<T>> {
 +    pub const VALUE: Foo<T>;
 +}
 +
 +impl<T> Wrapper<Bar<T>> {
 +    pub const VALUE: Bar<T>;
 +}
 +
 +fn main() {
 +    let a = Wrapper::<Foo<f32>>::VALUE;
 +    let b = Wrapper::<Bar<f32>>::VALUE;
 +    (a, b);
 +  //^^^^^^ (Foo<f32>, Bar<f32>)
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_encountering_fn_type() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +fn foo() {}
 +trait FnOnce { fn call(self); }
 +fn test() { foo.call(); }
 +          //^^^^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn super_trait_impl_return_trait_method_resolution() {
 +    check_infer(
 +        r#"
 +        //- minicore: sized
 +        trait Base {
 +            fn foo(self) -> usize;
 +        }
 +
 +        trait Super : Base {}
 +
 +        fn base1() -> impl Base { loop {} }
 +        fn super1() -> impl Super { loop {} }
 +
 +        fn test(base2: impl Base, super2: impl Super) {
 +            base1().foo();
 +            super1().foo();
 +            base2.foo();
 +            super2.foo();
 +        }
 +        "#,
 +        expect![[r#"
 +            24..28 'self': Self
 +            90..101 '{ loop {} }': !
 +            92..99 'loop {}': !
 +            97..99 '{}': ()
 +            128..139 '{ loop {} }': !
 +            130..137 'loop {}': !
 +            135..137 '{}': ()
 +            149..154 'base2': impl Base
 +            167..173 'super2': impl Super
 +            187..264 '{     ...o(); }': ()
 +            193..198 'base1': fn base1() -> impl Base
 +            193..200 'base1()': impl Base
 +            193..206 'base1().foo()': usize
 +            212..218 'super1': fn super1() -> impl Super
 +            212..220 'super1()': impl Super
 +            212..226 'super1().foo()': usize
 +            232..237 'base2': impl Base
 +            232..243 'base2.foo()': usize
 +            249..255 'super2': impl Super
 +            249..261 'super2.foo()': usize
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_non_parameter_type() {
 +    check_types(
 +        r#"
 +mod a {
 +    pub trait Foo {
 +        fn foo(&self);
 +    }
 +}
 +
 +struct Wrapper<T>(T);
 +fn foo<T>(t: Wrapper<T>)
 +where
 +    Wrapper<T>: a::Foo,
 +{
 +    t.foo();
 +} //^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_3373() {
 +    check_types(
 +        r#"
 +struct A<T>(T);
 +
 +impl A<i32> {
 +    fn from(v: i32) -> A<i32> { A(v) }
 +}
 +
 +fn main() {
 +    A::from(3);
 +} //^^^^^^^^^^ A<i32>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_slow() {
 +    // this can get quite slow if we set the solver size limit too high
 +    check_types(
 +        r#"
 +trait SendX {}
 +
 +struct S1; impl SendX for S1 {}
 +struct S2; impl SendX for S2 {}
 +struct U1;
 +
 +trait Trait { fn method(self); }
 +
 +struct X1<A, B> {}
 +impl<A, B> SendX for X1<A, B> where A: SendX, B: SendX {}
 +
 +struct S<B, C> {}
 +
 +trait FnX {}
 +
 +impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
 +
 +fn test() { (S {}).method(); }
 +          //^^^^^^^^^^^^^^^ ()
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn dyn_trait_super_trait_not_in_scope() {
 +    check_infer(
 +        r#"
 +        mod m {
 +            pub trait SuperTrait {
 +                fn foo(&self) -> u32 { 0 }
 +            }
 +        }
 +        trait Trait: m::SuperTrait {}
 +
 +        struct S;
 +        impl m::SuperTrait for S {}
 +        impl Trait for S {}
 +
 +        fn test(d: &dyn Trait) {
 +            d.foo();
 +        }
 +        "#,
 +        expect![[r#"
 +            51..55 'self': &Self
 +            64..69 '{ 0 }': u32
 +            66..67 '0': u32
 +            176..177 'd': &dyn Trait
 +            191..207 '{     ...o(); }': ()
 +            197..198 'd': &dyn Trait
 +            197..204 'd.foo()': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn method_resolution_foreign_opaque_type() {
 +    check_infer(
 +        r#"
 +extern "C" {
 +    type S;
 +    fn f() -> &'static S;
 +}
 +
 +impl S {
 +    fn foo(&self) -> bool {
 +        true
 +    }
 +}
 +
 +fn test() {
 +    let s = unsafe { f() };
 +    s.foo();
 +}
 +"#,
 +        expect![[r#"
 +            75..79 'self': &S
 +            89..109 '{     ...     }': bool
 +            99..103 'true': bool
 +            123..167 '{     ...o(); }': ()
 +            133..134 's': &S
 +            137..151 'unsafe { f() }': &S
 +            137..151 'unsafe { f() }': &S
 +            146..147 'f': fn f() -> &S
 +            146..149 'f()': &S
 +            157..158 's': &S
 +            157..164 's.foo()': bool
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn method_with_allocator_box_self_type() {
 +    check_types(
 +        r#"
 +struct Slice<T> {}
 +struct Box<T, A> {}
 +
 +impl<T> Slice<T> {
 +    pub fn into_vec<A>(self: Box<Self, A>) { }
 +}
 +
 +fn main() {
 +    let foo: Slice<u32>;
 +    foo.into_vec(); // we shouldn't crash on this at least
 +} //^^^^^^^^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn method_on_dyn_impl() {
 +    check_types(
 +        r#"
 +trait Foo {}
 +
 +impl Foo for u32 {}
 +impl dyn Foo + '_ {
 +    pub fn dyn_foo(&self) -> u32 {
 +        0
 +    }
 +}
 +
 +fn main() {
 +    let f = &42u32 as &dyn Foo;
 +    f.dyn_foo();
 + // ^^^^^^^^^^^ u32
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn autoderef_visibility_field() {
 +    check(
 +        r#"
 +//- minicore: deref
 +mod a {
 +    pub struct Foo(pub char);
 +    pub struct Bar(i32);
 +    impl Bar {
 +        pub fn new() -> Self {
 +            Self(0)
 +        }
 +    }
 +    impl core::ops::Deref for Bar {
 +        type Target = Foo;
 +        fn deref(&self) -> &Foo {
 +            &Foo('z')
 +        }
 +    }
 +}
 +mod b {
 +    fn foo() {
 +        let x = super::a::Bar::new().0;
 +             // ^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(Some(OverloadedDeref(Not)))
 +             // ^^^^^^^^^^^^^^^^^^^^^^ type: char
 +    }
 +}
 +"#,
 +    )
 +}
 +
 +#[test]
 +fn autoderef_visibility_method() {
 +    cov_mark::check!(autoderef_candidate_not_visible);
 +    check(
 +        r#"
 +//- minicore: deref
 +mod a {
 +    pub struct Foo(pub char);
 +    impl Foo {
 +        pub fn mango(&self) -> char {
 +            self.0
 +        }
 +    }
 +    pub struct Bar(i32);
 +    impl Bar {
 +        pub fn new() -> Self {
 +            Self(0)
 +        }
 +        fn mango(&self) -> i32 {
 +            self.0
 +        }
 +    }
 +    impl core::ops::Deref for Bar {
 +        type Target = Foo;
 +        fn deref(&self) -> &Foo {
 +            &Foo('z')
 +        }
 +    }
 +}
 +mod b {
 +    fn foo() {
 +        let x = super::a::Bar::new().mango();
 +             // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: char
 +    }
 +}
 +"#,
 +    )
 +}
 +
 +#[test]
 +fn trait_vs_private_inherent_const() {
 +    cov_mark::check!(const_candidate_not_visible);
 +    check(
 +        r#"
 +mod a {
 +    pub struct Foo;
 +    impl Foo {
 +        const VALUE: u32 = 2;
 +    }
 +    pub trait Trait {
 +        const VALUE: usize;
 +    }
 +    impl Trait for Foo {
 +        const VALUE: usize = 3;
 +    }
 +
 +    fn foo() {
 +        let x = Foo::VALUE;
 +            //  ^^^^^^^^^^ type: u32
 +    }
 +}
 +use a::Trait;
 +fn foo() {
 +    let x = a::Foo::VALUE;
 +         // ^^^^^^^^^^^^^ type: usize
 +}
 +"#,
 +    )
 +}
 +
 +#[test]
 +fn trait_impl_in_unnamed_const() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +trait Tr {
 +    fn method(&self) -> u16;
 +}
 +
 +const _: () = {
 +    impl Tr for S {}
 +};
 +
 +fn f() {
 +    S.method();
 +  //^^^^^^^^^^ u16
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn trait_impl_in_synstructure_const() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +trait Tr {
 +    fn method(&self) -> u16;
 +}
 +
 +const _DERIVE_Tr_: () = {
 +    impl Tr for S {}
 +};
 +
 +fn f() {
 +    S.method();
 +  //^^^^^^^^^^ u16
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn inherent_impl_in_unnamed_const() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +const _: () = {
 +    impl S {
 +        fn method(&self) -> u16 { 0 }
 +
 +        pub(super) fn super_method(&self) -> u16 { 0 }
 +
 +        pub(crate) fn crate_method(&self) -> u16 { 0 }
 +
 +        pub fn pub_method(&self) -> u16 { 0 }
 +    }
 +};
 +
 +fn f() {
 +    S.method();
 +  //^^^^^^^^^^ u16
 +
 +    S.super_method();
 +  //^^^^^^^^^^^^^^^^ u16
 +
 +    S.crate_method();
 +  //^^^^^^^^^^^^^^^^ u16
 +
 +    S.pub_method();
 +  //^^^^^^^^^^^^^^ u16
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn resolve_const_generic_array_methods() {
 +    check_types(
 +        r#"
 +#[lang = "array"]
 +impl<T, const N: usize> [T; N] {
 +    pub fn map<F, U>(self, f: F) -> [U; N]
 +    where
 +        F: FnMut(T) -> U,
 +    { loop {} }
 +}
 +
 +#[lang = "slice"]
 +impl<T> [T] {
 +    pub fn map<F, U>(self, f: F) -> &[U]
 +    where
 +        F: FnMut(T) -> U,
 +    { loop {} }
 +}
 +
 +fn f() {
 +    let v = [1, 2].map::<_, usize>(|x| -> x * 2);
 +    v;
 +  //^ [usize; 2]
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn resolve_const_generic_method() {
 +    check_types(
 +        r#"
 +struct Const<const N: usize>;
 +
 +#[lang = "array"]
 +impl<T, const N: usize> [T; N] {
 +    pub fn my_map<F, U, const X: usize>(self, f: F, c: Const<X>) -> [U; X]
 +    where
 +        F: FnMut(T) -> U,
 +    { loop {} }
 +}
 +
 +#[lang = "slice"]
 +impl<T> [T] {
 +    pub fn my_map<F, const X: usize, U>(self, f: F, c: Const<X>) -> &[U]
 +    where
 +        F: FnMut(T) -> U,
 +    { loop {} }
 +}
 +
 +fn f<const C: usize, P>() {
 +    let v = [1, 2].my_map::<_, (), 12>(|x| -> x * 2, Const::<12>);
 +    v;
 +  //^ [(); 12]
 +    let v = [1, 2].my_map::<_, P, C>(|x| -> x * 2, Const::<C>);
 +    v;
 +  //^ [P; C]
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn const_generic_type_alias() {
 +    check_types(
 +        r#"
 +struct Const<const N: usize>;
 +type U2 = Const<2>;
 +type U5 = Const<5>;
 +
 +impl U2 {
 +    fn f(self) -> Const<12> {
 +        loop {}
 +    }
 +}
 +
 +impl U5 {
 +    fn f(self) -> Const<15> {
 +        loop {}
 +    }
 +}
 +
 +fn f(x: U2) {
 +    let y = x.f();
 +      //^ Const<12>
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn skip_array_during_method_dispatch() {
 +    check_types(
 +        r#"
 +//- /main2018.rs crate:main2018 deps:core
 +use core::IntoIterator;
 +
 +fn f() {
 +    let v = [4].into_iter();
 +    v;
 +  //^ &i32
 +
 +    let a = [0, 1].into_iter();
 +    a;
 +  //^ &i32
 +}
 +
 +//- /main2021.rs crate:main2021 deps:core edition:2021
 +use core::IntoIterator;
 +
 +fn f() {
 +    let v = [4].into_iter();
 +    v;
 +  //^ i32
 +
 +    let a = [0, 1].into_iter();
 +    a;
 +  //^ &i32
 +}
 +
 +//- /core.rs crate:core
 +#[rustc_skip_array_during_method_dispatch]
 +pub trait IntoIterator {
 +    type Out;
 +    fn into_iter(self) -> Self::Out;
 +}
 +
 +impl<T> IntoIterator for [T; 1] {
 +    type Out = T;
 +    fn into_iter(self) -> Self::Out { loop {} }
 +}
 +impl<'a, T> IntoIterator for &'a [T] {
 +    type Out = &'a T;
 +    fn into_iter(self) -> Self::Out { loop {} }
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn sized_blanket_impl() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Foo { fn foo() -> u8; }
 +impl<T: Sized> Foo for T {}
 +fn f<S: Sized, T, U: ?Sized>() {
 +    u32::foo;
 +    S::foo;
 +    T::foo;
 +    U::foo;
 +    <[u32]>::foo;
 +}
 +"#,
 +        expect![[r#"
 +            89..160 '{     ...foo; }': ()
 +            95..103 'u32::foo': fn foo<u32>() -> u8
 +            109..115 'S::foo': fn foo<S>() -> u8
 +            121..127 'T::foo': fn foo<T>() -> u8
 +            133..139 'U::foo': {unknown}
 +            145..157 '<[u32]>::foo': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn local_impl() {
 +    check_types(
 +        r#"
 +fn main() {
 +    struct SomeStruct(i32);
 +
 +    impl SomeStruct {
 +        fn is_even(&self) -> bool {
 +            self.0 % 2 == 0
 +        }
 +    }
 +
 +    let o = SomeStruct(3);
 +    let is_even = o.is_even();
 +     // ^^^^^^^ bool
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn deref_fun_1() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +
 +struct A<T, U>(T, U);
 +struct B<T>(T);
 +struct C<T>(T);
 +
 +impl<T> core::ops::Deref for A<B<T>, u32> {
 +    type Target = B<T>;
 +    fn deref(&self) -> &B<T> { &self.0 }
 +}
 +impl core::ops::Deref for B<isize> {
 +    type Target = C<isize>;
 +    fn deref(&self) -> &C<isize> { loop {} }
 +}
 +
 +impl<T: Copy> C<T> {
 +    fn thing(&self) -> T { self.0 }
 +}
 +
 +fn make<T>() -> T { loop {} }
 +
 +fn test() {
 +    let a1 = A(make(), make());
 +    let _: usize = (*a1).0;
 +    a1;
 +  //^^ A<B<usize>, u32>
 +
 +    let a2 = A(make(), make());
 +    a2.thing();
 +  //^^^^^^^^^^ isize
 +    a2;
 +  //^^ A<B<isize>, u32>
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_fun_2() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +
 +struct A<T, U>(T, U);
 +struct B<T>(T);
 +struct C<T>(T);
 +
 +impl<T> core::ops::Deref for A<B<T>, u32> {
 +    type Target = B<T>;
 +    fn deref(&self) -> &B<T> { &self.0 }
 +}
 +impl core::ops::Deref for B<isize> {
 +    type Target = C<isize>;
 +    fn deref(&self) -> &C<isize> { loop {} }
 +}
 +
 +impl<T> core::ops::Deref for A<C<T>, i32> {
 +    type Target = C<T>;
 +    fn deref(&self) -> &C<T> { &self.0 }
 +}
 +
 +impl<T: Copy> C<T> {
 +    fn thing(&self) -> T { self.0 }
 +}
 +
 +fn make<T>() -> T { loop {} }
 +
 +fn test() {
 +    let a1 = A(make(), 1u32);
 +    a1.thing();
 +    a1;
 +  //^^ A<B<isize>, u32>
 +
 +    let a2 = A(make(), 1i32);
 +    let _: &str = a2.thing();
 +    a2;
 +  //^^ A<C<&str>, i32>
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn receiver_adjustment_autoref() {
 +    check(
 +        r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {}
 +}
 +fn test() {
 +    Foo.foo();
 +  //^^^ adjustments: Borrow(Ref(Not))
 +    (&Foo).foo();
 +  // ^^^^ adjustments: ,
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn receiver_adjustment_unsize_array() {
 +    // FIXME not quite correct
 +    check(
 +        r#"
 +//- minicore: slice
 +fn test() {
 +    let a = [1, 2, 3];
 +    a.len();
 +} //^ adjustments: Pointer(Unsize), Borrow(Ref(Not))
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn bad_inferred_reference_1() {
 +    check_no_mismatches(
 +        r#"
 +//- minicore: sized
 +pub trait Into<T>: Sized {
 +    fn into(self) -> T;
 +}
 +impl<T> Into<T> for T {
 +    fn into(self) -> T { self }
 +}
 +
 +trait ExactSizeIterator {
 +    fn len(&self) -> usize;
 +}
 +
 +pub struct Foo;
 +impl Foo {
 +    fn len(&self) -> usize { 0 }
 +}
 +
 +pub fn test(generic_args: impl Into<Foo>) {
 +    let generic_args = generic_args.into();
 +    generic_args.len();
 +    let _: Foo = generic_args;
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn bad_inferred_reference_2() {
 +    check_no_mismatches(
 +        r#"
 +//- minicore: deref
 +trait ExactSizeIterator {
 +    fn len(&self) -> usize;
 +}
 +
 +pub struct Foo;
 +impl Foo {
 +    fn len(&self) -> usize { 0 }
 +}
 +
 +pub fn test() {
 +    let generic_args;
 +    generic_args.len();
 +    let _: Foo = generic_args;
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn resolve_minicore_iterator() {
 +    check_types(
 +        r#"
 +//- minicore: iterators, sized
 +fn foo() {
 +    let m = core::iter::repeat(()).filter_map(|()| Some(92)).next();
 +}         //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Option<i32>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn primitive_assoc_fn_shadowed_by_use() {
 +    check_types(
 +        r#"
 +//- /lib.rs crate:lib deps:core
 +use core::u16;
 +
 +fn f() -> u16 {
 +    let x = u16::from_le_bytes();
 +      x
 +    //^ u16
 +}
 +
 +//- /core.rs crate:core
 +pub mod u16 {}
 +
 +impl u16 {
 +    pub fn from_le_bytes() -> Self { 0 }
 +}
 +        "#,
 +    )
 +}
++
++#[test]
++fn with_impl_bounds() {
++    check_types(
++        r#"
++trait Trait {}
++struct Foo<T>(T);
++impl Trait for isize {}
++
++impl<T: Trait> Foo<T> {
++  fn foo() -> isize { 0 }
++  fn bar(&self) -> isize { 0 }
++}
++
++impl Foo<()> {
++  fn foo() {}
++  fn bar(&self) {}
++}
++
++fn f() {
++  let _ = Foo::<isize>::foo();
++    //^isize
++  let _ = Foo(0isize).bar();
++    //^isize
++  let _ = Foo::<()>::foo();
++    //^()
++  let _ = Foo(()).bar();
++    //^()
++  let _ = Foo::<usize>::foo();
++    //^{unknown}
++  let _ = Foo(0usize).bar();
++    //^{unknown}
++}
++
++fn g<T: Trait>(a: T) {
++    let _ = Foo::<T>::foo();
++      //^isize
++    let _ = Foo(a).bar();
++      //^isize
++}
++        "#,
++    );
++}
index 94efe7bc11a8be577ee80081540ed8123683c558,0000000000000000000000000000000000000000..eb04bf87783b40dc8a0c9ef78b7b42044b407a7e
mode 100644,000000..100644
--- /dev/null
@@@ -1,1036 -1,0 +1,1072 @@@
 +use expect_test::expect;
 +
 +use super::{check, check_infer, check_infer_with_mismatches, check_types};
 +
 +#[test]
 +fn infer_pattern() {
 +    check_infer(
 +        r#"
 +        fn test(x: &i32) {
 +            let y = x;
 +            let &z = x;
 +            let a = z;
 +            let (c, d) = (1, "hello");
 +
 +            for (e, f) in some_iter {
 +                let g = e;
 +            }
 +
 +            if let [val] = opt {
 +                let h = val;
 +            }
 +
 +            if let x @ true = &true {}
 +
 +            let lambda = |a: u64, b, c: i32| { a + b; c };
 +
 +            let ref ref_to_x = x;
 +            let mut mut_x = x;
 +            let ref mut mut_ref_to_x = x;
 +            let k = mut_ref_to_x;
 +        }
 +        "#,
 +        expect![[r#"
 +            8..9 'x': &i32
 +            17..400 '{     ...o_x; }': ()
 +            27..28 'y': &i32
 +            31..32 'x': &i32
 +            42..44 '&z': &i32
 +            43..44 'z': i32
 +            47..48 'x': &i32
 +            58..59 'a': i32
 +            62..63 'z': i32
 +            73..79 '(c, d)': (i32, &str)
 +            74..75 'c': i32
 +            77..78 'd': &str
 +            82..94 '(1, "hello")': (i32, &str)
 +            83..84 '1': i32
 +            86..93 '"hello"': &str
 +            101..151 'for (e...     }': ()
 +            105..111 '(e, f)': ({unknown}, {unknown})
 +            106..107 'e': {unknown}
 +            109..110 'f': {unknown}
 +            115..124 'some_iter': {unknown}
 +            125..151 '{     ...     }': ()
 +            139..140 'g': {unknown}
 +            143..144 'e': {unknown}
 +            157..204 'if let...     }': ()
 +            160..175 'let [val] = opt': bool
 +            164..169 '[val]': [{unknown}]
 +            165..168 'val': {unknown}
 +            172..175 'opt': [{unknown}]
 +            176..204 '{     ...     }': ()
 +            190..191 'h': {unknown}
 +            194..197 'val': {unknown}
 +            210..236 'if let...rue {}': ()
 +            213..233 'let x ... &true': bool
 +            217..225 'x @ true': &bool
 +            221..225 'true': bool
 +            221..225 'true': bool
 +            228..233 '&true': &bool
 +            229..233 'true': bool
 +            234..236 '{}': ()
 +            246..252 'lambda': |u64, u64, i32| -> i32
 +            255..287 '|a: u6...b; c }': |u64, u64, i32| -> i32
 +            256..257 'a': u64
 +            264..265 'b': u64
 +            267..268 'c': i32
 +            275..287 '{ a + b; c }': i32
 +            277..278 'a': u64
 +            277..282 'a + b': u64
 +            281..282 'b': u64
 +            284..285 'c': i32
 +            298..310 'ref ref_to_x': &&i32
 +            313..314 'x': &i32
 +            324..333 'mut mut_x': &i32
 +            336..337 'x': &i32
 +            347..367 'ref mu...f_to_x': &mut &i32
 +            370..371 'x': &i32
 +            381..382 'k': &mut &i32
 +            385..397 'mut_ref_to_x': &mut &i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_literal_pattern() {
 +    check_infer_with_mismatches(
 +        r#"
 +        fn any<T>() -> T { loop {} }
 +        fn test(x: &i32) {
 +            if let "foo" = any() {}
 +            if let 1 = any() {}
 +            if let 1u32 = any() {}
 +            if let 1f32 = any() {}
 +            if let 1.0 = any() {}
 +            if let true = any() {}
 +        }
 +        "#,
 +        expect![[r#"
 +            17..28 '{ loop {} }': T
 +            19..26 'loop {}': !
 +            24..26 '{}': ()
 +            37..38 'x': &i32
 +            46..208 '{     ...) {} }': ()
 +            52..75 'if let...y() {}': ()
 +            55..72 'let "f... any()': bool
 +            59..64 '"foo"': &str
 +            59..64 '"foo"': &str
 +            67..70 'any': fn any<&str>() -> &str
 +            67..72 'any()': &str
 +            73..75 '{}': ()
 +            80..99 'if let...y() {}': ()
 +            83..96 'let 1 = any()': bool
 +            87..88 '1': i32
 +            87..88 '1': i32
 +            91..94 'any': fn any<i32>() -> i32
 +            91..96 'any()': i32
 +            97..99 '{}': ()
 +            104..126 'if let...y() {}': ()
 +            107..123 'let 1u... any()': bool
 +            111..115 '1u32': u32
 +            111..115 '1u32': u32
 +            118..121 'any': fn any<u32>() -> u32
 +            118..123 'any()': u32
 +            124..126 '{}': ()
 +            131..153 'if let...y() {}': ()
 +            134..150 'let 1f... any()': bool
 +            138..142 '1f32': f32
 +            138..142 '1f32': f32
 +            145..148 'any': fn any<f32>() -> f32
 +            145..150 'any()': f32
 +            151..153 '{}': ()
 +            158..179 'if let...y() {}': ()
 +            161..176 'let 1.0 = any()': bool
 +            165..168 '1.0': f64
 +            165..168 '1.0': f64
 +            171..174 'any': fn any<f64>() -> f64
 +            171..176 'any()': f64
 +            177..179 '{}': ()
 +            184..206 'if let...y() {}': ()
 +            187..203 'let tr... any()': bool
 +            191..195 'true': bool
 +            191..195 'true': bool
 +            198..201 'any': fn any<bool>() -> bool
 +            198..203 'any()': bool
 +            204..206 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_range_pattern() {
 +    check_infer_with_mismatches(
 +        r#"
 +        fn test(x: &i32) {
 +            if let 1..76 = 2u32 {}
 +            if let 1..=76 = 2u32 {}
 +        }
 +        "#,
 +        expect![[r#"
 +            8..9 'x': &i32
 +            17..75 '{     ...2 {} }': ()
 +            23..45 'if let...u32 {}': ()
 +            26..42 'let 1....= 2u32': bool
 +            30..35 '1..76': u32
 +            38..42 '2u32': u32
 +            43..45 '{}': ()
 +            50..73 'if let...u32 {}': ()
 +            53..70 'let 1....= 2u32': bool
 +            57..63 '1..=76': u32
 +            66..70 '2u32': u32
 +            71..73 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_pattern_match_ergonomics() {
 +    check_infer(
 +        r#"
 +        struct A<T>(T);
 +
 +        fn test() {
 +            let A(n) = &A(1);
 +            let A(n) = &mut A(1);
 +        }
 +        "#,
 +        expect![[r#"
 +            27..78 '{     ...(1); }': ()
 +            37..41 'A(n)': A<i32>
 +            39..40 'n': &i32
 +            44..49 '&A(1)': &A<i32>
 +            45..46 'A': A<i32>(i32) -> A<i32>
 +            45..49 'A(1)': A<i32>
 +            47..48 '1': i32
 +            59..63 'A(n)': A<i32>
 +            61..62 'n': &mut i32
 +            66..75 '&mut A(1)': &mut A<i32>
 +            71..72 'A': A<i32>(i32) -> A<i32>
 +            71..75 'A(1)': A<i32>
 +            73..74 '1': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_pattern_match_ergonomics_ref() {
 +    cov_mark::check!(match_ergonomics_ref);
 +    check_infer(
 +        r#"
 +        fn test() {
 +            let v = &(1, &2);
 +            let (_, &w) = v;
 +        }
 +        "#,
 +        expect![[r#"
 +            10..56 '{     ...= v; }': ()
 +            20..21 'v': &(i32, &i32)
 +            24..32 '&(1, &2)': &(i32, &i32)
 +            25..32 '(1, &2)': (i32, &i32)
 +            26..27 '1': i32
 +            29..31 '&2': &i32
 +            30..31 '2': i32
 +            42..49 '(_, &w)': (i32, &i32)
 +            43..44 '_': i32
 +            46..48 '&w': &i32
 +            47..48 'w': i32
 +            52..53 'v': &(i32, &i32)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_pattern_match_slice() {
 +    check_infer(
 +        r#"
 +        fn test() {
 +            let slice: &[f64] = &[0.0];
 +            match slice {
 +                &[] => {},
 +                &[a] => {
 +                    a;
 +                },
 +                &[b, c] => {
 +                    b;
 +                    c;
 +                }
 +                _ => {}
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            10..209 '{     ...   } }': ()
 +            20..25 'slice': &[f64]
 +            36..42 '&[0.0]': &[f64; 1]
 +            37..42 '[0.0]': [f64; 1]
 +            38..41 '0.0': f64
 +            48..207 'match ...     }': ()
 +            54..59 'slice': &[f64]
 +            70..73 '&[]': &[f64]
 +            71..73 '[]': [f64]
 +            77..79 '{}': ()
 +            89..93 '&[a]': &[f64]
 +            90..93 '[a]': [f64]
 +            91..92 'a': f64
 +            97..123 '{     ...     }': ()
 +            111..112 'a': f64
 +            133..140 '&[b, c]': &[f64]
 +            134..140 '[b, c]': [f64]
 +            135..136 'b': f64
 +            138..139 'c': f64
 +            144..185 '{     ...     }': ()
 +            158..159 'b': f64
 +            173..174 'c': f64
 +            194..195 '_': &[f64]
 +            199..201 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_pattern_match_string_literal() {
 +    check_infer_with_mismatches(
 +        r#"
 +        fn test() {
 +            let s: &str = "hello";
 +            match s {
 +                "hello" => {}
 +                _ => {}
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            10..98 '{     ...   } }': ()
 +            20..21 's': &str
 +            30..37 '"hello"': &str
 +            43..96 'match ...     }': ()
 +            49..50 's': &str
 +            61..68 '"hello"': &str
 +            61..68 '"hello"': &str
 +            72..74 '{}': ()
 +            83..84 '_': &str
 +            88..90 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_pattern_match_byte_string_literal() {
 +    check_infer_with_mismatches(
 +        r#"
 +        //- minicore: index
 +        struct S;
 +        impl<T, const N: usize> core::ops::Index<S> for [T; N] {
 +            type Output = [u8];
 +            fn index(&self, index: core::ops::RangeFull) -> &Self::Output {
 +                loop {}
 +            }
 +        }
 +        fn test(v: [u8; 3]) {
 +            if let b"foo" = &v[S] {}
 +            if let b"foo" = &v {}
 +        }
 +        "#,
 +        expect![[r#"
 +            105..109 'self': &[T; N]
 +            111..116 'index': {unknown}
 +            157..180 '{     ...     }': &[u8]
 +            167..174 'loop {}': !
 +            172..174 '{}': ()
 +            191..192 'v': [u8; 3]
 +            203..261 '{     ...v {} }': ()
 +            209..233 'if let...[S] {}': ()
 +            212..230 'let b"... &v[S]': bool
 +            216..222 'b"foo"': &[u8]
 +            216..222 'b"foo"': &[u8]
 +            225..230 '&v[S]': &[u8]
 +            226..227 'v': [u8; 3]
 +            226..230 'v[S]': [u8]
 +            228..229 'S': S
 +            231..233 '{}': ()
 +            238..259 'if let... &v {}': ()
 +            241..256 'let b"foo" = &v': bool
 +            245..251 'b"foo"': &[u8; 3]
 +            245..251 'b"foo"': &[u8; 3]
 +            254..256 '&v': &[u8; 3]
 +            255..256 'v': [u8; 3]
 +            257..259 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_pattern_match_or() {
 +    check_infer_with_mismatches(
 +        r#"
 +        fn test() {
 +            let s: &str = "hello";
 +            match s {
 +                "hello" | "world" => {}
 +                _ => {}
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            10..108 '{     ...   } }': ()
 +            20..21 's': &str
 +            30..37 '"hello"': &str
 +            43..106 'match ...     }': ()
 +            49..50 's': &str
 +            61..68 '"hello"': &str
 +            61..68 '"hello"': &str
 +            61..78 '"hello...world"': &str
 +            71..78 '"world"': &str
 +            71..78 '"world"': &str
 +            82..84 '{}': ()
 +            93..94 '_': &str
 +            98..100 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_pattern_match_arr() {
 +    check_infer(
 +        r#"
 +        fn test() {
 +            let arr: [f64; 2] = [0.0, 1.0];
 +            match arr {
 +                [1.0, a] => {
 +                    a;
 +                },
 +                [b, c] => {
 +                    b;
 +                    c;
 +                }
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            10..179 '{     ...   } }': ()
 +            20..23 'arr': [f64; 2]
 +            36..46 '[0.0, 1.0]': [f64; 2]
 +            37..40 '0.0': f64
 +            42..45 '1.0': f64
 +            52..177 'match ...     }': ()
 +            58..61 'arr': [f64; 2]
 +            72..80 '[1.0, a]': [f64; 2]
 +            73..76 '1.0': f64
 +            73..76 '1.0': f64
 +            78..79 'a': f64
 +            84..110 '{     ...     }': ()
 +            98..99 'a': f64
 +            120..126 '[b, c]': [f64; 2]
 +            121..122 'b': f64
 +            124..125 'c': f64
 +            130..171 '{     ...     }': ()
 +            144..145 'b': f64
 +            159..160 'c': f64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_adt_pattern() {
 +    check_infer(
 +        r#"
 +        enum E {
 +            A { x: usize },
 +            B
 +        }
 +
 +        struct S(u32, E);
 +
 +        fn test() {
 +            let e = E::A { x: 3 };
 +
 +            let S(y, z) = foo;
 +            let E::A { x: new_var } = e;
 +
 +            match e {
 +                E::A { x } => x,
 +                E::B if foo => 1,
 +                E::B => 10,
 +            };
 +
 +            let ref d @ E::A { .. } = e;
 +            d;
 +        }
 +        "#,
 +        expect![[r#"
 +            67..288 '{     ...  d; }': ()
 +            77..78 'e': E
 +            81..94 'E::A { x: 3 }': E
 +            91..92 '3': usize
 +            105..112 'S(y, z)': S
 +            107..108 'y': u32
 +            110..111 'z': E
 +            115..118 'foo': S
 +            128..147 'E::A {..._var }': E
 +            138..145 'new_var': usize
 +            150..151 'e': E
 +            158..244 'match ...     }': usize
 +            164..165 'e': E
 +            176..186 'E::A { x }': E
 +            183..184 'x': usize
 +            190..191 'x': usize
 +            201..205 'E::B': E
 +            209..212 'foo': bool
 +            216..217 '1': usize
 +            227..231 'E::B': E
 +            235..237 '10': usize
 +            255..274 'ref d ...{ .. }': &E
 +            263..274 'E::A { .. }': E
 +            277..278 'e': E
 +            284..285 'd': &E
 +        "#]],
 +    );
 +}
 +
++#[test]
++fn tuple_struct_destructured_with_self() {
++    check_infer(
++        r#"
++struct Foo(usize,);
++impl Foo {
++    fn f() {
++        let Self(s,) = &Foo(0,);
++        let Self(s,) = &mut Foo(0,);
++        let Self(s,) = Foo(0,);
++    }
++}
++        "#,
++        expect![[r#"
++            42..151 '{     ...     }': ()
++            56..64 'Self(s,)': Foo
++            61..62 's': &usize
++            67..75 '&Foo(0,)': &Foo
++            68..71 'Foo': Foo(usize) -> Foo
++            68..75 'Foo(0,)': Foo
++            72..73 '0': usize
++            89..97 'Self(s,)': Foo
++            94..95 's': &mut usize
++            100..112 '&mut Foo(0,)': &mut Foo
++            105..108 'Foo': Foo(usize) -> Foo
++            105..112 'Foo(0,)': Foo
++            109..110 '0': usize
++            126..134 'Self(s,)': Foo
++            131..132 's': usize
++            137..140 'Foo': Foo(usize) -> Foo
++            137..144 'Foo(0,)': Foo
++            141..142 '0': usize
++        "#]],
++    );
++}
++
 +#[test]
 +fn enum_variant_through_self_in_pattern() {
 +    check_infer(
 +        r#"
 +        enum E {
 +            A { x: usize },
 +            B(usize),
 +            C
 +        }
 +
 +        impl E {
 +            fn test() {
 +                match (loop {}) {
 +                    Self::A { x } => { x; },
 +                    Self::B(x) => { x; },
 +                    Self::C => {},
 +                };
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            75..217 '{     ...     }': ()
 +            85..210 'match ...     }': ()
 +            92..99 'loop {}': !
 +            97..99 '{}': ()
 +            115..128 'Self::A { x }': E
 +            125..126 'x': usize
 +            132..138 '{ x; }': ()
 +            134..135 'x': usize
 +            152..162 'Self::B(x)': E
 +            160..161 'x': usize
 +            166..172 '{ x; }': ()
 +            168..169 'x': usize
 +            186..193 'Self::C': E
 +            197..199 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_generics_in_patterns() {
 +    check_infer(
 +        r#"
 +        struct A<T> {
 +            x: T,
 +        }
 +
 +        enum Option<T> {
 +            Some(T),
 +            None,
 +        }
 +
 +        fn test(a1: A<u32>, o: Option<u64>) {
 +            let A { x: x2 } = a1;
 +            let A::<i64> { x: x3 } = A { x: 1 };
 +            match o {
 +                Option::Some(t) => t,
 +                _ => 1,
 +            };
 +        }
 +        "#,
 +        expect![[r#"
 +            78..80 'a1': A<u32>
 +            90..91 'o': Option<u64>
 +            106..243 '{     ...  }; }': ()
 +            116..127 'A { x: x2 }': A<u32>
 +            123..125 'x2': u32
 +            130..132 'a1': A<u32>
 +            142..160 'A::<i6...: x3 }': A<i64>
 +            156..158 'x3': i64
 +            163..173 'A { x: 1 }': A<i64>
 +            170..171 '1': i64
 +            179..240 'match ...     }': u64
 +            185..186 'o': Option<u64>
 +            197..212 'Option::Some(t)': Option<u64>
 +            210..211 't': u64
 +            216..217 't': u64
 +            227..228 '_': Option<u64>
 +            232..233 '1': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_const_pattern() {
 +    check(
 +        r#"
 +enum Option<T> { None }
 +use Option::None;
 +struct Foo;
 +const Bar: usize = 1;
 +
 +fn test() {
 +    let a: Option<u32> = None;
 +    let b: Option<i64> = match a {
 +        None => None,
 +    };
 +    let _: () = match () { Foo => () };
 +                        // ^^^ expected (), got Foo
 +    let _: () = match () { Bar => () };
 +                        // ^^^ expected (), got usize
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_guard() {
 +    check_infer(
 +        r#"
 +struct S;
 +impl S { fn foo(&self) -> bool { false } }
 +
 +fn main() {
 +    match S {
 +        s if s.foo() => (),
 +    }
 +}
 +        "#,
 +        expect![[r#"
 +            27..31 'self': &S
 +            41..50 '{ false }': bool
 +            43..48 'false': bool
 +            64..115 '{     ...   } }': ()
 +            70..113 'match ...     }': ()
 +            76..77 'S': S
 +            88..89 's': S
 +            93..94 's': S
 +            93..100 's.foo()': bool
 +            104..106 '()': ()
 +    "#]],
 +    )
 +}
 +
 +#[test]
 +fn match_ergonomics_in_closure_params() {
 +    check_infer(
 +        r#"
 +//- minicore: fn
 +fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} }
 +
 +fn test() {
 +    foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics
 +    foo(&(1, "a"), |(x, y)| x);
 +}
 +"#,
 +        expect![[r#"
 +            32..33 't': T
 +            38..39 'f': F
 +            49..60 '{ loop {} }': U
 +            51..58 'loop {}': !
 +            56..58 '{}': ()
 +            72..171 '{     ... x); }': ()
 +            78..81 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32
 +            78..105 'foo(&(...y)| x)': i32
 +            82..91 '&(1, "a")': &(i32, &str)
 +            83..91 '(1, "a")': (i32, &str)
 +            84..85 '1': i32
 +            87..90 '"a"': &str
 +            93..104 '|&(x, y)| x': |&(i32, &str)| -> i32
 +            94..101 '&(x, y)': &(i32, &str)
 +            95..101 '(x, y)': (i32, &str)
 +            96..97 'x': i32
 +            99..100 'y': &str
 +            103..104 'x': i32
 +            142..145 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32
 +            142..168 'foo(&(...y)| x)': &i32
 +            146..155 '&(1, "a")': &(i32, &str)
 +            147..155 '(1, "a")': (i32, &str)
 +            148..149 '1': i32
 +            151..154 '"a"': &str
 +            157..167 '|(x, y)| x': |&(i32, &str)| -> &i32
 +            158..164 '(x, y)': (i32, &str)
 +            159..160 'x': &i32
 +            162..163 'y': &&str
 +            166..167 'x': &i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn slice_tail_pattern() {
 +    check_infer(
 +        r#"
 +        fn foo(params: &[i32]) {
 +            match params {
 +                [head, tail @ ..] => {
 +                }
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            7..13 'params': &[i32]
 +            23..92 '{     ...   } }': ()
 +            29..90 'match ...     }': ()
 +            35..41 'params': &[i32]
 +            52..69 '[head,... @ ..]': [i32]
 +            53..57 'head': &i32
 +            59..68 'tail @ ..': &[i32]
 +            66..68 '..': [i32]
 +            73..84 '{         }': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn box_pattern() {
 +    check_infer(
 +        r#"
 +        pub struct Global;
 +        #[lang = "owned_box"]
 +        pub struct Box<T, A = Global>(T);
 +
 +        fn foo(params: Box<i32>) {
 +            match params {
 +                box integer => {}
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            83..89 'params': Box<i32, Global>
 +            101..155 '{     ...   } }': ()
 +            107..153 'match ...     }': ()
 +            113..119 'params': Box<i32, Global>
 +            130..141 'box integer': Box<i32, Global>
 +            134..141 'integer': i32
 +            145..147 '{}': ()
 +        "#]],
 +    );
 +    check_infer(
 +        r#"
 +        #[lang = "owned_box"]
 +        pub struct Box<T>(T);
 +
 +        fn foo(params: Box<i32>) {
 +            match params {
 +                box integer => {}
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            52..58 'params': Box<i32>
 +            70..124 '{     ...   } }': ()
 +            76..122 'match ...     }': ()
 +            82..88 'params': Box<i32>
 +            99..110 'box integer': Box<i32>
 +            103..110 'integer': i32
 +            114..116 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn tuple_ellipsis_pattern() {
 +    check_infer_with_mismatches(
 +        r#"
 +fn foo(tuple: (u8, i16, f32)) {
 +    match tuple {
 +        (.., b, c) => {},
 +        (a, .., c) => {},
 +        (a, b, ..) => {},
 +        (a, b) => {/*too short*/}
 +        (a, b, c, d) => {/*too long*/}
 +        _ => {}
 +    }
 +}"#,
 +        expect![[r#"
 +            7..12 'tuple': (u8, i16, f32)
 +            30..224 '{     ...   } }': ()
 +            36..222 'match ...     }': ()
 +            42..47 'tuple': (u8, i16, f32)
 +            58..68 '(.., b, c)': (u8, i16, f32)
 +            63..64 'b': i16
 +            66..67 'c': f32
 +            72..74 '{}': ()
 +            84..94 '(a, .., c)': (u8, i16, f32)
 +            85..86 'a': u8
 +            92..93 'c': f32
 +            98..100 '{}': ()
 +            110..120 '(a, b, ..)': (u8, i16, f32)
 +            111..112 'a': u8
 +            114..115 'b': i16
 +            124..126 '{}': ()
 +            136..142 '(a, b)': (u8, i16)
 +            137..138 'a': u8
 +            140..141 'b': i16
 +            146..161 '{/*too short*/}': ()
 +            170..182 '(a, b, c, d)': (u8, i16, f32, {unknown})
 +            171..172 'a': u8
 +            174..175 'b': i16
 +            177..178 'c': f32
 +            180..181 'd': {unknown}
 +            186..200 '{/*too long*/}': ()
 +            209..210 '_': (u8, i16, f32)
 +            214..216 '{}': ()
 +            136..142: expected (u8, i16, f32), got (u8, i16)
 +            170..182: expected (u8, i16, f32), got (u8, i16, f32, {unknown})
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn tuple_struct_ellipsis_pattern() {
 +    check_infer(
 +        r#"
 +struct Tuple(u8, i16, f32);
 +fn foo(tuple: Tuple) {
 +    match tuple {
 +        Tuple(.., b, c) => {},
 +        Tuple(a, .., c) => {},
 +        Tuple(a, b, ..) => {},
 +        Tuple(a, b) => {/*too short*/}
 +        Tuple(a, b, c, d) => {/*too long*/}
 +        _ => {}
 +    }
 +}"#,
 +        expect![[r#"
 +            35..40 'tuple': Tuple
 +            49..268 '{     ...   } }': ()
 +            55..266 'match ...     }': ()
 +            61..66 'tuple': Tuple
 +            77..92 'Tuple(.., b, c)': Tuple
 +            87..88 'b': i16
 +            90..91 'c': f32
 +            96..98 '{}': ()
 +            108..123 'Tuple(a, .., c)': Tuple
 +            114..115 'a': u8
 +            121..122 'c': f32
 +            127..129 '{}': ()
 +            139..154 'Tuple(a, b, ..)': Tuple
 +            145..146 'a': u8
 +            148..149 'b': i16
 +            158..160 '{}': ()
 +            170..181 'Tuple(a, b)': Tuple
 +            176..177 'a': u8
 +            179..180 'b': i16
 +            185..200 '{/*too short*/}': ()
 +            209..226 'Tuple(... c, d)': Tuple
 +            215..216 'a': u8
 +            218..219 'b': i16
 +            221..222 'c': f32
 +            224..225 'd': {unknown}
 +            230..244 '{/*too long*/}': ()
 +            253..254 '_': Tuple
 +            258..260 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn const_block_pattern() {
 +    check_infer(
 +        r#"
 +struct Foo(usize);
 +fn foo(foo: Foo) {
 +    match foo {
 +        const { Foo(15 + 32) } => {},
 +        _ => {}
 +    }
 +}"#,
 +        expect![[r#"
 +            26..29 'foo': Foo
 +            36..115 '{     ...   } }': ()
 +            42..113 'match ...     }': ()
 +            48..51 'foo': Foo
 +            62..84 'const ... 32) }': Foo
 +            68..84 '{ Foo(... 32) }': Foo
 +            70..73 'Foo': Foo(usize) -> Foo
 +            70..82 'Foo(15 + 32)': Foo
 +            74..76 '15': usize
 +            74..81 '15 + 32': usize
 +            79..81 '32': usize
 +            88..90 '{}': ()
 +            100..101 '_': Foo
 +            105..107 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn macro_pat() {
 +    check_types(
 +        r#"
 +macro_rules! pat {
 +    ($name:ident) => { Enum::Variant1($name) }
 +}
 +
 +enum Enum {
 +    Variant1(u8),
 +    Variant2,
 +}
 +
 +fn f(e: Enum) {
 +    match e {
 +        pat!(bind) => {
 +            bind;
 +          //^^^^ u8
 +        }
 +        Enum::Variant2 => {}
 +    }
 +}
 +    "#,
 +    )
 +}
 +
 +#[test]
 +fn type_mismatch_in_or_pattern() {
 +    check_infer_with_mismatches(
 +        r#"
 +fn main() {
 +    match (false,) {
 +        (true | (),) => {}
 +        (() | true,) => {}
 +        (_ | (),) => {}
 +        (() | _,) => {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            10..142 '{     ...   } }': ()
 +            16..140 'match ...     }': ()
 +            22..30 '(false,)': (bool,)
 +            23..28 'false': bool
 +            41..53 '(true | (),)': (bool,)
 +            42..46 'true': bool
 +            42..46 'true': bool
 +            42..51 'true | ()': bool
 +            49..51 '()': ()
 +            57..59 '{}': ()
 +            68..80 '(() | true,)': ((),)
 +            69..71 '()': ()
 +            69..78 '() | true': ()
 +            74..78 'true': bool
 +            74..78 'true': bool
 +            84..86 '{}': ()
 +            95..104 '(_ | (),)': (bool,)
 +            96..97 '_': bool
 +            96..102 '_ | ()': bool
 +            100..102 '()': ()
 +            108..110 '{}': ()
 +            119..128 '(() | _,)': ((),)
 +            120..122 '()': ()
 +            120..126 '() | _': ()
 +            125..126 '_': bool
 +            132..134 '{}': ()
 +            49..51: expected bool, got ()
 +            68..80: expected (bool,), got ((),)
 +            69..71: expected bool, got ()
 +            69..78: expected bool, got ()
 +            100..102: expected bool, got ()
 +            119..128: expected (bool,), got ((),)
 +            120..122: expected bool, got ()
 +            120..126: expected bool, got ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn slice_pattern_correctly_handles_array_length() {
 +    check_infer(
 +        r#"
 +fn main() {
 +    let [head, middle @ .., tail, tail2] = [1, 2, 3, 4, 5];
 +}
 +    "#,
 +        expect![[r#"
 +            10..73 '{     ... 5]; }': ()
 +            20..52 '[head,...tail2]': [i32; 5]
 +            21..25 'head': i32
 +            27..38 'middle @ ..': [i32; 2]
 +            36..38 '..': [i32; 2]
 +            40..44 'tail': i32
 +            46..51 'tail2': i32
 +            55..70 '[1, 2, 3, 4, 5]': [i32; 5]
 +            56..57 '1': i32
 +            59..60 '2': i32
 +            62..63 '3': i32
 +            65..66 '4': i32
 +            68..69 '5': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn pattern_lookup_in_value_ns() {
 +    check_types(
 +        r#"
 +use self::Constructor::*;
 +struct IntRange {
 +    range: (),
 +}
 +enum Constructor {
 +    IntRange(IntRange),
 +}
 +fn main() {
 +    match Constructor::IntRange(IntRange { range: () }) {
 +        IntRange(x) => {
 +            x;
 +          //^ IntRange
 +        }
 +        Constructor::IntRange(x) => {
 +            x;
 +          //^ IntRange
 +        }
 +    }
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn if_let_guards() {
 +    check_types(
 +        r#"
 +fn main() {
 +    match (0,) {
 +        opt if let (x,) = opt => {
 +            x;
 +          //^ i32
 +        }
 +        _ => {}
 +    }
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn tuple_wildcard() {
 +    check_types(
 +        r#"
 +fn main() {
 +    enum Option<T> {Some(T), None}
 +    use Option::*;
 +
 +    let mut x = None;
 +    x;
 +  //^ Option<(i32, i32)>
 +
 +    if let Some((_, _a)) = x {}
 +
 +    x = Some((1, 2));
 +}
 +        "#,
 +    );
 +}
index 93a88ab58ef82dee1d6b7fe9a8e03238136a6987,0000000000000000000000000000000000000000..1b5ed0603bfd137696aeb4fd7c79cf86bf8cb46f
mode 100644,000000..100644
--- /dev/null
@@@ -1,1650 -1,0 +1,1667 @@@
 +use expect_test::expect;
 +
 +use super::{check_infer, check_no_mismatches, check_types};
 +
 +#[test]
 +fn bug_484() {
 +    check_infer(
 +        r#"
 +        fn test() {
 +            let x = if true {};
 +        }
 +        "#,
 +        expect![[r#"
 +            10..37 '{     ... {}; }': ()
 +            20..21 'x': ()
 +            24..34 'if true {}': ()
 +            27..31 'true': bool
 +            32..34 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn no_panic_on_field_of_enum() {
 +    check_infer(
 +        r#"
 +        enum X {}
 +
 +        fn test(x: X) {
 +            x.some_field;
 +        }
 +        "#,
 +        expect![[r#"
 +            19..20 'x': X
 +            25..46 '{     ...eld; }': ()
 +            31..32 'x': X
 +            31..43 'x.some_field': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn bug_585() {
 +    check_infer(
 +        r#"
 +        fn test() {
 +            X {};
 +            match x {
 +                A::B {} => (),
 +                A::Y() => (),
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            10..88 '{     ...   } }': ()
 +            16..20 'X {}': {unknown}
 +            26..86 'match ...     }': ()
 +            32..33 'x': {unknown}
 +            44..51 'A::B {}': {unknown}
 +            55..57 '()': ()
 +            67..73 'A::Y()': {unknown}
 +            77..79 '()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn bug_651() {
 +    check_infer(
 +        r#"
 +        fn quux() {
 +            let y = 92;
 +            1 + y;
 +        }
 +        "#,
 +        expect![[r#"
 +            10..40 '{     ...+ y; }': ()
 +            20..21 'y': i32
 +            24..26 '92': i32
 +            32..33 '1': i32
 +            32..37 '1 + y': i32
 +            36..37 'y': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn recursive_vars() {
 +    check_infer(
 +        r#"
 +        fn test() {
 +            let y = unknown;
 +            [y, &y];
 +        }
 +        "#,
 +        expect![[r#"
 +            10..47 '{     ...&y]; }': ()
 +            20..21 'y': {unknown}
 +            24..31 'unknown': {unknown}
 +            37..44 '[y, &y]': [{unknown}; 2]
 +            38..39 'y': {unknown}
 +            41..43 '&y': &{unknown}
 +            42..43 'y': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn recursive_vars_2() {
 +    check_infer(
 +        r#"
 +        fn test() {
 +            let x = unknown;
 +            let y = unknown;
 +            [(x, y), (&y, &x)];
 +        }
 +        "#,
 +        expect![[r#"
 +            10..79 '{     ...x)]; }': ()
 +            20..21 'x': &{unknown}
 +            24..31 'unknown': &{unknown}
 +            41..42 'y': {unknown}
 +            45..52 'unknown': {unknown}
 +            58..76 '[(x, y..., &x)]': [(&{unknown}, {unknown}); 2]
 +            59..65 '(x, y)': (&{unknown}, {unknown})
 +            60..61 'x': &{unknown}
 +            63..64 'y': {unknown}
 +            67..75 '(&y, &x)': (&{unknown}, {unknown})
 +            68..70 '&y': &{unknown}
 +            69..70 'y': {unknown}
 +            72..74 '&x': &&{unknown}
 +            73..74 'x': &{unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn array_elements_expected_type() {
 +    check_no_mismatches(
 +        r#"
 +        fn test() {
 +            let x: [[u32; 2]; 2] = [[1, 2], [3, 4]];
 +        }
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_std_crash_1() {
 +    // caused stack overflow, taken from std
 +    check_infer(
 +        r#"
 +        enum Maybe<T> {
 +            Real(T),
 +            Fake,
 +        }
 +
 +        fn write() {
 +            match something_unknown {
 +                Maybe::Real(ref mut something) => (),
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            53..138 '{     ...   } }': ()
 +            59..136 'match ...     }': ()
 +            65..82 'someth...nknown': Maybe<{unknown}>
 +            93..123 'Maybe:...thing)': Maybe<{unknown}>
 +            105..122 'ref mu...ething': &mut {unknown}
 +            127..129 '()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_std_crash_2() {
 +    // caused "equating two type variables, ...", taken from std
 +    check_infer(
 +        r#"
 +        fn test_line_buffer() {
 +            &[0, b'\n', 1, b'\n'];
 +        }
 +        "#,
 +        expect![[r#"
 +            22..52 '{     ...n']; }': ()
 +            28..49 '&[0, b...b'\n']': &[u8; 4]
 +            29..49 '[0, b'...b'\n']': [u8; 4]
 +            30..31 '0': u8
 +            33..38 'b'\n'': u8
 +            40..41 '1': u8
 +            43..48 'b'\n'': u8
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_std_crash_3() {
 +    // taken from rustc
 +    check_infer(
 +        r#"
 +        pub fn compute() {
 +            match nope!() {
 +                SizeSkeleton::Pointer { non_zero: true, tail } => {}
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            17..107 '{     ...   } }': ()
 +            23..105 'match ...     }': ()
 +            29..36 'nope!()': {unknown}
 +            47..93 'SizeSk...tail }': {unknown}
 +            81..85 'true': bool
 +            81..85 'true': bool
 +            87..91 'tail': {unknown}
 +            97..99 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_std_crash_4() {
 +    // taken from rustc
 +    check_infer(
 +        r#"
 +        pub fn primitive_type() {
 +            match *self {
 +                BorrowedRef { type_: Primitive(p), ..} => {},
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            24..105 '{     ...   } }': ()
 +            30..103 'match ...     }': ()
 +            36..41 '*self': {unknown}
 +            37..41 'self': {unknown}
 +            52..90 'Borrow...), ..}': {unknown}
 +            73..85 'Primitive(p)': {unknown}
 +            83..84 'p': {unknown}
 +            94..96 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_std_crash_5() {
 +    // taken from rustc
 +    check_infer(
 +        r#"
 +        fn extra_compiler_flags() {
 +            for content in doesnt_matter {
 +                let name = if doesnt_matter {
 +                    first
 +                } else {
 +                    &content
 +                };
 +
 +                let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) {
 +                    name
 +                } else {
 +                    content
 +                };
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            26..322 '{     ...   } }': ()
 +            32..320 'for co...     }': ()
 +            36..43 'content': {unknown}
 +            47..60 'doesnt_matter': {unknown}
 +            61..320 '{     ...     }': ()
 +            75..79 'name': &{unknown}
 +            82..166 'if doe...     }': &{unknown}
 +            85..98 'doesnt_matter': bool
 +            99..128 '{     ...     }': &{unknown}
 +            113..118 'first': &{unknown}
 +            134..166 '{     ...     }': &{unknown}
 +            148..156 '&content': &{unknown}
 +            149..156 'content': {unknown}
 +            181..188 'content': &{unknown}
 +            191..313 'if ICE...     }': &{unknown}
 +            194..231 'ICE_RE..._VALUE': {unknown}
 +            194..247 'ICE_RE...&name)': bool
 +            241..246 '&name': &&{unknown}
 +            242..246 'name': &{unknown}
 +            248..276 '{     ...     }': &{unknown}
 +            262..266 'name': &{unknown}
 +            282..313 '{     ...     }': {unknown}
 +            296..303 'content': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_nested_generics_crash() {
 +    // another crash found typechecking rustc
 +    check_infer(
 +        r#"
 +        struct Canonical<V> {
 +            value: V,
 +        }
 +        struct QueryResponse<V> {
 +            value: V,
 +        }
 +        fn test<R>(query_response: Canonical<QueryResponse<R>>) {
 +            &query_response.value;
 +        }
 +        "#,
 +        expect![[r#"
 +            91..105 'query_response': Canonical<QueryResponse<R>>
 +            136..166 '{     ...lue; }': ()
 +            142..163 '&query....value': &QueryResponse<R>
 +            143..157 'query_response': Canonical<QueryResponse<R>>
 +            143..163 'query_....value': QueryResponse<R>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_paren_macro_call() {
 +    check_infer(
 +        r#"
 +        macro_rules! bar { () => {0u32} }
 +        fn test() {
 +            let a = (bar!());
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..4 '0u32': u32
 +            44..69 '{     ...()); }': ()
 +            54..55 'a': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_array_macro_call() {
 +    check_infer(
 +        r#"
 +        macro_rules! bar { () => {0u32} }
 +        fn test() {
 +            let a = [bar!()];
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..4 '0u32': u32
 +            44..69 '{     ...()]; }': ()
 +            54..55 'a': [u32; 1]
 +            58..66 '[bar!()]': [u32; 1]
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn bug_1030() {
 +    check_infer(
 +        r#"
 +        struct HashSet<T, H>;
 +        struct FxHasher;
 +        type FxHashSet<T> = HashSet<T, FxHasher>;
 +
 +        impl<T, H> HashSet<T, H> {
 +            fn default() -> HashSet<T, H> {}
 +        }
 +
 +        pub fn main_loop() {
 +            FxHashSet::default();
 +        }
 +        "#,
 +        expect![[r#"
 +            143..145 '{}': HashSet<T, H>
 +            168..197 '{     ...t(); }': ()
 +            174..192 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<{unknown}, FxHasher>
 +            174..194 'FxHash...ault()': HashSet<{unknown}, FxHasher>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_2669() {
 +    check_infer(
 +        r#"
 +        trait A {}
 +        trait Write {}
 +        struct Response<T> {}
 +
 +        trait D {
 +            fn foo();
 +        }
 +
 +        impl<T:A> D for Response<T> {
 +            fn foo() {
 +                end();
 +                fn end<W: Write>() {
 +                    let _x: T =  loop {};
 +                }
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            119..214 '{     ...     }': ()
 +            129..132 'end': fn end<{unknown}>()
 +            129..134 'end()': ()
 +            163..208 '{     ...     }': ()
 +            181..183 '_x': !
 +            190..197 'loop {}': !
 +            195..197 '{}': ()
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn issue_2705() {
 +    check_infer(
 +        r#"
 +        trait Trait {}
 +        fn test() {
 +            <Trait<u32>>::foo()
 +        }
 +        "#,
 +        expect![[r#"
 +            25..52 '{     ...oo() }': ()
 +            31..48 '<Trait...>::foo': {unknown}
 +            31..50 '<Trait...:foo()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_2683_chars_impl() {
 +    check_types(
 +        r#"
 +//- minicore: iterator
 +pub struct Chars<'a> {}
 +impl<'a> Iterator for Chars<'a> {
 +    type Item = char;
 +    fn next(&mut self) -> Option<char> { loop {} }
 +}
 +
 +fn test() {
 +    let chars: Chars<'_>;
 +    (chars.next(), chars.nth(1));
 +} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (Option<char>, Option<char>)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn issue_3999_slice() {
 +    check_infer(
 +        r#"
 +        fn foo(params: &[usize]) {
 +            match params {
 +                [ps @ .., _] => {}
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            7..13 'params': &[usize]
 +            25..80 '{     ...   } }': ()
 +            31..78 'match ...     }': ()
 +            37..43 'params': &[usize]
 +            54..66 '[ps @ .., _]': [usize]
 +            55..62 'ps @ ..': &[usize]
 +            60..62 '..': [usize]
 +            64..65 '_': usize
 +            70..72 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_3999_struct() {
 +    // rust-analyzer should not panic on seeing this malformed
 +    // record pattern.
 +    check_infer(
 +        r#"
 +        struct Bar {
 +            a: bool,
 +        }
 +        fn foo(b: Bar) {
 +            match b {
 +                Bar { a: .. } => {},
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            35..36 'b': Bar
 +            43..95 '{     ...   } }': ()
 +            49..93 'match ...     }': ()
 +            55..56 'b': Bar
 +            67..80 'Bar { a: .. }': Bar
 +            76..78 '..': bool
 +            84..86 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4235_name_conflicts() {
 +    check_infer(
 +        r#"
 +        struct FOO {}
 +        static FOO:FOO = FOO {};
 +
 +        impl FOO {
 +            fn foo(&self) {}
 +        }
 +
 +        fn main() {
 +            let a = &FOO;
 +            a.foo();
 +        }
 +        "#,
 +        expect![[r#"
 +            31..37 'FOO {}': FOO
 +            63..67 'self': &FOO
 +            69..71 '{}': ()
 +            85..119 '{     ...o(); }': ()
 +            95..96 'a': &FOO
 +            99..103 '&FOO': &FOO
 +            100..103 'FOO': FOO
 +            109..110 'a': &FOO
 +            109..116 'a.foo()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4465_dollar_crate_at_type() {
 +    check_infer(
 +        r#"
 +        pub struct Foo {}
 +        pub fn anything<T>() -> T {
 +            loop {}
 +        }
 +        macro_rules! foo {
 +            () => {{
 +                let r: $crate::Foo = anything();
 +                r
 +            }};
 +        }
 +        fn main() {
 +            let _a = foo!();
 +        }
 +        "#,
 +        expect![[r#"
 +            44..59 '{     loop {} }': T
 +            50..57 'loop {}': !
 +            55..57 '{}': ()
 +            !0..31 '{letr:...g();r}': Foo
 +            !4..5 'r': Foo
 +            !18..26 'anything': fn anything<Foo>() -> Foo
 +            !18..28 'anything()': Foo
 +            !29..30 'r': Foo
 +            163..187 '{     ...!(); }': ()
 +            173..175 '_a': Foo
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_6811() {
 +    check_infer(
 +        r#"
 +        macro_rules! profile_function {
 +            () => {
 +                let _a = 1;
 +                let _b = 1;
 +            };
 +        }
 +        fn main() {
 +            profile_function!();
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..16 'let_a=...t_b=1;': ()
 +            !3..5 '_a': i32
 +            !6..7 '1': i32
 +            !11..13 '_b': i32
 +            !14..15 '1': i32
 +            103..131 '{     ...!(); }': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4053_diesel_where_clauses() {
 +    check_infer(
 +        r#"
 +        trait BoxedDsl<DB> {
 +            type Output;
 +            fn internal_into_boxed(self) -> Self::Output;
 +        }
 +
 +        struct SelectStatement<From, Select, Distinct, Where, Order, LimitOffset, GroupBy, Locking> {
 +            order: Order,
 +        }
 +
 +        trait QueryFragment<DB: Backend> {}
 +
 +        trait Into<T> { fn into(self) -> T; }
 +
 +        impl<F, S, D, W, O, LOf, DB> BoxedDsl<DB>
 +            for SelectStatement<F, S, D, W, O, LOf, G>
 +        where
 +            O: Into<dyn QueryFragment<DB>>,
 +        {
 +            type Output = XXX;
 +
 +            fn internal_into_boxed(self) -> Self::Output {
 +                self.order.into();
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            65..69 'self': Self
 +            267..271 'self': Self
 +            466..470 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
 +            488..522 '{     ...     }': ()
 +            498..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
 +            498..508 'self.order': O
 +            498..515 'self.o...into()': dyn QueryFragment<DB>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4953() {
 +    check_infer(
 +        r#"
 +        pub struct Foo(pub i64);
 +        impl Foo {
 +            fn test() -> Self { Self(0i64) }
 +        }
 +        "#,
 +        expect![[r#"
 +            58..72 '{ Self(0i64) }': Foo
 +            60..64 'Self': Foo(i64) -> Foo
 +            60..70 'Self(0i64)': Foo
 +            65..69 '0i64': i64
 +        "#]],
 +    );
 +    check_infer(
 +        r#"
 +        pub struct Foo<T>(pub T);
 +        impl Foo<i64> {
 +            fn test() -> Self { Self(0i64) }
 +        }
 +        "#,
 +        expect![[r#"
 +            64..78 '{ Self(0i64) }': Foo<i64>
 +            66..70 'Self': Foo<i64>(i64) -> Foo<i64>
 +            66..76 'Self(0i64)': Foo<i64>
 +            71..75 '0i64': i64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4931() {
 +    check_infer(
 +        r#"
 +        trait Div<T> {
 +            type Output;
 +        }
 +
 +        trait CheckedDiv: Div<()> {}
 +
 +        trait PrimInt: CheckedDiv<Output = ()> {
 +            fn pow(self);
 +        }
 +
 +        fn check<T: PrimInt>(i: T) {
 +            i.pow();
 +        }
 +        "#,
 +        expect![[r#"
 +            117..121 'self': Self
 +            148..149 'i': T
 +            154..170 '{     ...w(); }': ()
 +            160..161 'i': T
 +            160..167 'i.pow()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4885() {
 +    check_infer(
 +        r#"
 +        //- minicore: coerce_unsized, future
 +        use core::future::Future;
 +        trait Foo<R> {
 +            type Bar;
 +        }
 +        fn foo<R, K>(key: &K) -> impl Future<Output = K::Bar>
 +        where
 +            K: Foo<R>,
 +        {
 +            bar(key)
 +        }
 +        fn bar<R, K>(key: &K) -> impl Future<Output = K::Bar>
 +        where
 +            K: Foo<R>,
 +        {
 +        }
 +        "#,
 +        expect![[r#"
 +            70..73 'key': &K
 +            132..148 '{     ...key) }': impl Future<Output = <K as Foo<R>>::Bar>
 +            138..141 'bar': fn bar<R, K>(&K) -> impl Future<Output = <K as Foo<R>>::Bar>
 +            138..146 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar>
 +            142..145 'key': &K
 +            162..165 'key': &K
 +            224..227 '{ }': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4800() {
 +    check_infer(
 +        r#"
 +        trait Debug {}
 +
 +        struct Foo<T>;
 +
 +        type E1<T> = (T, T, T);
 +        type E2<T> = E1<E1<E1<(T, T, T)>>>;
 +
 +        impl Debug for Foo<E2<()>> {}
 +
 +        struct Request;
 +
 +        pub trait Future {
 +            type Output;
 +        }
 +
 +        pub struct PeerSet<D>;
 +
 +        impl<D> Service<Request> for PeerSet<D>
 +        where
 +            D: Discover,
 +            D::Key: Debug,
 +        {
 +            type Error = ();
 +            type Future = dyn Future<Output = Self::Error>;
 +
 +            fn call(&mut self) -> Self::Future {
 +                loop {}
 +            }
 +        }
 +
 +        pub trait Discover {
 +            type Key;
 +        }
 +
 +        pub trait Service<Request> {
 +            type Error;
 +            type Future: Future<Output = Self::Error>;
 +            fn call(&mut self) -> Self::Future;
 +        }
 +        "#,
 +        expect![[r#"
 +            379..383 'self': &mut PeerSet<D>
 +            401..424 '{     ...     }': dyn Future<Output = ()>
 +            411..418 'loop {}': !
 +            416..418 '{}': ()
 +            575..579 'self': &mut Self
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4966() {
 +    check_infer(
 +        r#"
 +        //- minicore: deref
 +        pub trait IntoIterator {
 +            type Item;
 +        }
 +
 +        struct Repeat<A> { element: A }
 +
 +        struct Map<F> { f: F }
 +
 +        struct Vec<T> {}
 +
 +        impl<T> core::ops::Deref for Vec<T> {
 +            type Target = [T];
 +        }
 +
 +        fn from_iter<A, T: IntoIterator<Item = A>>(iter: T) -> Vec<A> {}
 +
 +        fn main() {
 +            let inner = Map { f: |_: &f64| 0.0 };
 +
 +            let repeat = Repeat { element: inner };
 +
 +            let vec = from_iter(repeat);
 +
 +            vec.foo_bar();
 +        }
 +        "#,
 +        expect![[r#"
 +            225..229 'iter': T
 +            244..246 '{}': Vec<A>
 +            258..402 '{     ...r(); }': ()
 +            268..273 'inner': Map<|&f64| -> f64>
 +            276..300 'Map { ... 0.0 }': Map<|&f64| -> f64>
 +            285..298 '|_: &f64| 0.0': |&f64| -> f64
 +            286..287 '_': &f64
 +            295..298 '0.0': f64
 +            311..317 'repeat': Repeat<Map<|&f64| -> f64>>
 +            320..345 'Repeat...nner }': Repeat<Map<|&f64| -> f64>>
 +            338..343 'inner': Map<|&f64| -> f64>
 +            356..359 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
 +            362..371 'from_iter': fn from_iter<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>, Repeat<Map<|&f64| -> f64>>>(Repeat<Map<|&f64| -> f64>>) -> Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
 +            362..379 'from_i...epeat)': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
 +            372..378 'repeat': Repeat<Map<|&f64| -> f64>>
 +            386..389 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
 +            386..399 'vec.foo_bar()': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_6628() {
 +    check_infer(
 +        r#"
 +//- minicore: fn
 +struct S<T>();
 +impl<T> S<T> {
 +    fn f(&self, _t: T) {}
 +    fn g<F: FnOnce(&T)>(&self, _f: F) {}
 +}
 +fn main() {
 +    let s = S();
 +    s.g(|_x| {});
 +    s.f(10);
 +}
 +"#,
 +        expect![[r#"
 +            40..44 'self': &S<T>
 +            46..48 '_t': T
 +            53..55 '{}': ()
 +            81..85 'self': &S<T>
 +            87..89 '_f': F
 +            94..96 '{}': ()
 +            109..160 '{     ...10); }': ()
 +            119..120 's': S<i32>
 +            123..124 'S': S<i32>() -> S<i32>
 +            123..126 'S()': S<i32>
 +            132..133 's': S<i32>
 +            132..144 's.g(|_x| {})': ()
 +            136..143 '|_x| {}': |&i32| -> ()
 +            137..139 '_x': &i32
 +            141..143 '{}': ()
 +            150..151 's': S<i32>
 +            150..157 's.f(10)': ()
 +            154..156 '10': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_6852() {
 +    check_infer(
 +        r#"
 +//- minicore: deref
 +use core::ops::Deref;
 +
 +struct BufWriter {}
 +
 +struct Mutex<T> {}
 +struct MutexGuard<'a, T> {}
 +impl<T> Mutex<T> {
 +    fn lock(&self) -> MutexGuard<'_, T> {}
 +}
 +impl<'a, T: 'a> Deref for MutexGuard<'a, T> {
 +    type Target = T;
 +}
 +fn flush(&self) {
 +    let w: &Mutex<BufWriter>;
 +    *(w.lock());
 +}
 +"#,
 +        expect![[r#"
 +            123..127 'self': &Mutex<T>
 +            150..152 '{}': MutexGuard<T>
 +            234..238 'self': &{unknown}
 +            240..290 '{     ...()); }': ()
 +            250..251 'w': &Mutex<BufWriter>
 +            276..287 '*(w.lock())': BufWriter
 +            278..279 'w': &Mutex<BufWriter>
 +            278..286 'w.lock()': MutexGuard<BufWriter>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn param_overrides_fn() {
 +    check_types(
 +        r#"
 +        fn example(example: i32) {
 +            fn f() {}
 +            example;
 +          //^^^^^^^ i32
 +        }
 +        "#,
 +    )
 +}
 +
 +#[test]
 +fn lifetime_from_chalk_during_deref() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Box<T: ?Sized> {}
 +impl<T: ?Sized> core::ops::Deref for Box<T> {
 +    type Target = T;
 +
 +    fn deref(&self) -> &Self::Target {
 +        loop {}
 +    }
 +}
 +
 +trait Iterator {
 +    type Item;
 +}
 +
 +pub struct Iter<'a, T: 'a> {
 +    inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>,
 +}
 +
 +trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> {
 +    fn clone_box(&self);
 +}
 +
 +fn clone_iter<T>(s: Iter<T>) {
 +    s.inner.clone_box();
 +  //^^^^^^^^^^^^^^^^^^^ ()
 +}
 +"#,
 +    )
 +}
 +
 +#[test]
 +fn issue_8686() {
 +    check_infer(
 +        r#"
 +pub trait Try: FromResidual {
 +    type Output;
 +    type Residual;
 +}
 +pub trait FromResidual<R = <Self as Try>::Residual> {
 +     fn from_residual(residual: R) -> Self;
 +}
 +
 +struct ControlFlow<B, C>;
 +impl<B, C> Try for ControlFlow<B, C> {
 +    type Output = C;
 +    type Residual = ControlFlow<B, !>;
 +}
 +impl<B, C> FromResidual for ControlFlow<B, C> {
 +    fn from_residual(r: ControlFlow<B, !>) -> Self { ControlFlow }
 +}
 +
 +fn test() {
 +    ControlFlow::from_residual(ControlFlow::<u32, !>);
 +}
 +        "#,
 +        expect![[r#"
 +            144..152 'residual': R
 +            365..366 'r': ControlFlow<B, !>
 +            395..410 '{ ControlFlow }': ControlFlow<B, C>
 +            397..408 'ControlFlow': ControlFlow<B, C>
 +            424..482 '{     ...!>); }': ()
 +            430..456 'Contro...sidual': fn from_residual<ControlFlow<u32, {unknown}>, ControlFlow<u32, !>>(ControlFlow<u32, !>) -> ControlFlow<u32, {unknown}>
 +            430..479 'Contro...2, !>)': ControlFlow<u32, {unknown}>
 +            457..478 'Contro...32, !>': ControlFlow<u32, !>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn cfg_tail() {
 +    // https://github.com/rust-lang/rust-analyzer/issues/8378
 +    check_infer(
 +        r#"
 +        fn fake_tail(){
 +            { "first" }
 +            #[cfg(never)] 9
 +        }
 +        fn multiple_fake(){
 +            { "fake" }
 +            { "fake" }
 +            { "second" }
 +            #[cfg(never)] { 11 }
 +            #[cfg(never)] 12;
 +            #[cfg(never)] 13
 +        }
 +        fn no_normal_tail(){
 +            { "third" }
 +            #[cfg(never)] 14;
 +            #[cfg(never)] 15;
 +        }
 +        fn no_actual_tail(){
 +            { "fourth" };
 +            #[cfg(never)] 14;
 +            #[cfg(never)] 15
 +        }
 +        "#,
 +        expect![[r#"
 +            14..53 '{     ...)] 9 }': ()
 +            20..31 '{ "first" }': ()
 +            22..29 '"first"': &str
 +            72..190 '{     ...] 13 }': ()
 +            78..88 '{ "fake" }': &str
 +            80..86 '"fake"': &str
 +            93..103 '{ "fake" }': &str
 +            95..101 '"fake"': &str
 +            108..120 '{ "second" }': ()
 +            110..118 '"second"': &str
 +            210..273 '{     ... 15; }': ()
 +            216..227 '{ "third" }': ()
 +            218..225 '"third"': &str
 +            293..357 '{     ...] 15 }': ()
 +            299..311 '{ "fourth" }': &str
 +            301..309 '"fourth"': &str
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn impl_trait_in_option_9530() {
 +    check_types(
 +        r#"
 +//- minicore: sized
 +struct Option<T>;
 +impl<T> Option<T> {
 +    fn unwrap(self) -> T { loop {} }
 +}
 +fn make() -> Option<impl Copy> { Option }
 +trait Copy {}
 +fn test() {
 +    let o = make();
 +    o.unwrap();
 +  //^^^^^^^^^^ impl Copy
 +}
 +        "#,
 +    )
 +}
 +
 +#[test]
 +fn bare_dyn_trait_binders_9639() {
 +    check_no_mismatches(
 +        r#"
 +//- minicore: fn, coerce_unsized
 +fn infix_parse<T, S>(_state: S, _level_code: &Fn(S)) -> T {
 +    loop {}
 +}
 +
 +fn parse_arule() {
 +    infix_parse((), &(|_recurse| ()))
 +}
 +        "#,
 +    )
 +}
 +
 +#[test]
 +fn call_expected_type_closure() {
 +    check_types(
 +        r#"
 +//- minicore: fn, option
 +
 +fn map<T, U>(o: Option<T>, f: impl FnOnce(T) -> U) -> Option<U> { loop {} }
 +struct S {
 +    field: u32
 +}
 +
 +fn test() {
 +    let o = Some(S { field: 2 });
 +    let _: Option<()> = map(o, |s| { s.field; });
 +                                  // ^^^^^^^ u32
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn coerce_diesel_panic() {
 +    check_no_mismatches(
 +        r#"
 +//- minicore: option
 +
 +trait TypeMetadata {
 +    type MetadataLookup;
 +}
 +
 +pub struct Output<'a, T, DB>
 +where
 +    DB: TypeMetadata,
 +    DB::MetadataLookup: 'a,
 +{
 +    out: T,
 +    metadata_lookup: Option<&'a DB::MetadataLookup>,
 +}
 +
 +impl<'a, T, DB: TypeMetadata> Output<'a, T, DB> {
 +    pub fn new(out: T, metadata_lookup: &'a DB::MetadataLookup) -> Self {
 +        Output {
 +            out,
 +            metadata_lookup: Some(metadata_lookup),
 +        }
 +    }
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn bitslice_panic() {
 +    check_no_mismatches(
 +        r#"
 +//- minicore: option, deref
 +
 +pub trait BitView {
 +    type Store;
 +}
 +
 +pub struct Lsb0;
 +
 +pub struct BitArray<V: BitView> { }
 +
 +pub struct BitSlice<T> { }
 +
 +impl<V: BitView> core::ops::Deref for BitArray<V> {
 +    type Target = BitSlice<V::Store>;
 +}
 +
 +impl<T> BitSlice<T> {
 +    pub fn split_first(&self) -> Option<(T, &Self)> { loop {} }
 +}
 +
 +fn multiexp_inner() {
 +    let exp: &BitArray<Foo>;
 +    exp.split_first();
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn macro_expands_to_impl_trait() {
 +    check_no_mismatches(
 +        r#"
 +trait Foo {}
 +
 +macro_rules! ty {
 +    () => {
 +        impl Foo
 +    }
 +}
 +
 +fn foo(_: ty!()) {}
 +
 +fn bar() {
 +    foo(());
 +}
 +    "#,
 +    )
 +}
 +
 +#[test]
 +fn nested_macro_in_fn_params() {
 +    check_no_mismatches(
 +        r#"
 +macro_rules! U32Inner {
 +    () => {
 +        u32
 +    };
 +}
 +
 +macro_rules! U32 {
 +    () => {
 +        U32Inner!()
 +    };
 +}
 +
 +fn mamba(a: U32!(), p: u32) -> u32 {
 +    a
 +}
 +    "#,
 +    )
 +}
 +
 +#[test]
 +fn for_loop_block_expr_iterable() {
 +    check_infer(
 +        r#"
 +fn test() {
 +    for _ in { let x = 0; } {
 +        let y = 0;
 +    }
 +}
 +        "#,
 +        expect![[r#"
 +            10..68 '{     ...   } }': ()
 +            16..66 'for _ ...     }': ()
 +            20..21 '_': {unknown}
 +            25..39 '{ let x = 0; }': ()
 +            31..32 'x': i32
 +            35..36 '0': i32
 +            40..66 '{     ...     }': ()
 +            54..55 'y': i32
 +            58..59 '0': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn while_loop_block_expr_iterable() {
 +    check_infer(
 +        r#"
 +fn test() {
 +    while { true } {
 +        let y = 0;
 +    }
 +}
 +        "#,
 +        expect![[r#"
 +            10..59 '{     ...   } }': ()
 +            16..57 'while ...     }': ()
 +            22..30 '{ true }': bool
 +            24..28 'true': bool
 +            31..57 '{     ...     }': ()
 +            45..46 'y': i32
 +            49..50 '0': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn bug_11242() {
 +    // FIXME: wrong, should be u32
 +    check_types(
 +        r#"
 +fn foo<A, B>()
 +where
 +    A: IntoIterator<Item = u32>,
 +    B: IntoIterator<Item = usize>,
 +{
 +    let _x: <A as IntoIterator>::Item;
 +     // ^^ {unknown}
 +}
 +
 +pub trait Iterator {
 +    type Item;
 +}
 +
 +pub trait IntoIterator {
 +    type Item;
 +    type IntoIter: Iterator<Item = Self::Item>;
 +}
 +
 +impl<I: Iterator> IntoIterator for I {
 +    type Item = I::Item;
 +    type IntoIter = I;
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn bug_11659() {
 +    check_no_mismatches(
 +        r#"
 +struct LinkArray<const N: usize, LD>(LD);
 +fn f<const N: usize, LD>(x: LD) -> LinkArray<N, LD> {
 +    let r = LinkArray::<N, LD>(x);
 +    r
 +}
 +
 +fn test() {
 +    let x = f::<2, i32>(5);
 +    let y = LinkArray::<52, LinkArray<2, i32>>(x);
 +}
 +        "#,
 +    );
 +    check_no_mismatches(
 +        r#"
 +struct LinkArray<LD, const N: usize>(LD);
 +fn f<const N: usize, LD>(x: LD) -> LinkArray<LD, N> {
 +    let r = LinkArray::<LD, N>(x);
 +    r
 +}
 +
 +fn test() {
 +    let x = f::<i32, 2>(5);
 +    let y = LinkArray::<LinkArray<i32, 2>, 52>(x);
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn const_generic_error_tolerance() {
 +    check_no_mismatches(
 +        r#"
 +#[lang = "sized"]
 +pub trait Sized {}
 +
 +struct CT<const N: usize, T>(T);
 +struct TC<T, const N: usize>(T);
 +fn f<const N: usize, T>(x: T) -> (CT<N, T>, TC<T, N>) {
 +    let l = CT::<N, T>(x);
 +    let r = TC::<N, T>(x);
 +    (l, r)
 +}
 +
 +trait TR1<const N: usize>;
 +trait TR2<const N: usize>;
 +
 +impl<const N: usize, T> TR1<N> for CT<N, T>;
 +impl<const N: usize, T> TR1<5> for TC<T, N>;
 +impl<const N: usize, T> TR2<N> for CT<T, N>;
 +
 +trait TR3<const N: usize> {
 +    fn tr3(&self) -> &Self;
 +}
 +
 +impl<const N: usize, T> TR3<5> for TC<T, N> {
 +    fn tr3(&self) -> &Self {
 +        self
 +    }
 +}
 +
 +impl<const N: usize, T> TR3<Item = 5> for TC<T, N> {}
 +impl<const N: usize, T> TR3<T> for TC<T, N> {}
 +
 +fn impl_trait<const N: usize>(inp: impl TR1<N>) {}
 +fn dyn_trait<const N: usize>(inp: &dyn TR2<N>) {}
 +fn impl_trait_bad<'a, const N: usize>(inp: impl TR1<i32>) -> impl TR1<'a, i32> {}
 +fn impl_trait_very_bad<const N: usize>(inp: impl TR1<Item = i32>) -> impl TR1<'a, Item = i32, 5, Foo = N> {}
 +
 +fn test() {
 +    f::<2, i32>(5);
 +    f::<2, 2>(5);
 +    f(5);
 +    f::<i32>(5);
 +    CT::<52, CT<2, i32>>(x);
 +    CT::<CT<2, i32>>(x);
 +    impl_trait_bad(5);
 +    impl_trait_bad(12);
 +    TR3<5>::tr3();
 +    TR3<{ 2+3 }>::tr3();
 +    TC::<i32, 10>(5).tr3();
 +    TC::<i32, 20>(5).tr3();
 +    TC::<i32, i32>(5).tr3();
 +    TC::<i32, { 7 + 3 }>(5).tr3();
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn const_generic_impl_trait() {
 +    check_no_mismatches(
 +        r#"
 +        //- minicore: from
 +
 +        struct Foo<T, const M: usize>;
 +
 +        trait Tr<T> {
 +            fn f(T) -> Self;
 +        }
 +
 +        impl<T, const M: usize> Tr<[T; M]> for Foo<T, M> {
 +            fn f(_: [T; M]) -> Self {
 +                Self
 +            }
 +        }
 +
 +        fn test() {
 +            Foo::f([1, 2, 7, 10]);
 +        }
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn nalgebra_factorial() {
 +    check_no_mismatches(
 +        r#"
 +        const FACTORIAL: [u128; 4] = [1, 1, 2, 6];
 +
 +        fn factorial(n: usize) -> u128 {
 +            match FACTORIAL.get(n) {
 +                Some(f) => *f,
 +                None => panic!("{}! is greater than u128::MAX", n),
 +            }
 +        }
 +        "#,
 +    )
 +}
 +
 +#[test]
 +fn regression_11688_1() {
 +    check_no_mismatches(
 +        r#"
 +        pub struct Buffer<T>(T);
 +        type Writer = Buffer<u8>;
 +        impl<T> Buffer<T> {
 +            fn extend_from_array<const N: usize>(&mut self, xs: &[T; N]) {
 +                loop {}
 +            }
 +        }
 +        trait Encode<S> {
 +            fn encode(self, w: &mut Writer, s: &mut S);
 +        }
 +        impl<S> Encode<S> for u8 {
 +            fn encode(self, w: &mut Writer, _: &mut S) {
 +                w.extend_from_array(&self.to_le_bytes());
 +            }
 +        }
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn regression_11688_2() {
 +    check_types(
 +        r#"
 +        union MaybeUninit<T> {
 +            uninit: (),
 +            value: T,
 +        }
 +
 +        impl<T> MaybeUninit<T> {
 +            fn uninit_array<const LEN: usize>() -> [Self; LEN] {
 +                loop {}
 +            }
 +        }
 +
 +        fn main() {
 +            let x = MaybeUninit::<i32>::uninit_array::<1>();
 +              //^ [MaybeUninit<i32>; 1]
 +        }
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn regression_11688_3() {
 +    check_types(
 +        r#"
 +        //- minicore: iterator
 +        struct Ar<T, const N: u8>(T);
 +        fn f<const LEN: usize, T, const BASE: u8>(
 +            num_zeros: usize,
 +        ) -> dyn Iterator<Item = [Ar<T, BASE>; LEN]> {
 +            loop {}
 +        }
 +        fn dynamic_programming() {
 +            for board in f::<9, u8, 7>(1) {
 +              //^^^^^ [Ar<u8, 7>; 9]
 +            }
 +        }
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn regression_11688_4() {
 +    check_types(
 +        r#"
 +        trait Bar<const C: usize> {
 +            fn baz(&self) -> [i32; C];
 +        }
 +
 +        fn foo(x: &dyn Bar<2>) {
 +            x.baz();
 +          //^^^^^^^ [i32; 2]
 +        }
 +        "#,
 +    )
 +}
 +
 +#[test]
 +fn gat_crash_1() {
 +    cov_mark::check!(ignore_gats);
 +    check_no_mismatches(
 +        r#"
 +trait ATrait {}
 +
 +trait Crash {
 +    type Member<const N: usize>: ATrait;
 +    fn new<const N: usize>() -> Self::Member<N>;
 +}
 +
 +fn test<T: Crash>() {
 +    T::new();
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn gat_crash_2() {
 +    check_no_mismatches(
 +        r#"
 +pub struct InlineStorage {}
 +
 +pub struct InlineStorageHandle<T: ?Sized> {}
 +
 +pub unsafe trait Storage {
 +    type Handle<T: ?Sized>;
 +    fn create<T: ?Sized>() -> Self::Handle<T>;
 +}
 +
 +unsafe impl Storage for InlineStorage {
 +    type Handle<T: ?Sized> = InlineStorageHandle<T>;
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn cfgd_out_self_param() {
 +    cov_mark::check!(cfgd_out_self_param);
 +    check_no_mismatches(
 +        r#"
 +struct S;
 +impl S {
 +    fn f(#[cfg(never)] &self) {}
 +}
 +
 +fn f(s: S) {
 +    s.f();
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn rust_161_option_clone() {
 +    check_types(
 +        r#"
 +//- minicore: option, drop
 +
 +fn test(o: &Option<i32>) {
 +    o.my_clone();
 +  //^^^^^^^^^^^^ Option<i32>
 +}
 +
 +pub trait MyClone: Sized {
 +    fn my_clone(&self) -> Self;
 +}
 +
 +impl<T> const MyClone for Option<T>
 +where
 +    T: ~const MyClone + ~const Drop + ~const Destruct,
 +{
 +    fn my_clone(&self) -> Self {
 +        match self {
 +            Some(x) => Some(x.my_clone()),
 +            None => None,
 +        }
 +    }
 +}
 +
 +impl const MyClone for i32 {
 +    fn my_clone(&self) -> Self {
 +        *self
 +    }
 +}
 +
 +pub trait Destruct {}
 +
 +impl<T: ?Sized> const Destruct for T {}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn rust_162_option_clone() {
 +    check_types(
 +        r#"
 +//- minicore: option, drop
 +
 +fn test(o: &Option<i32>) {
 +    o.my_clone();
 +  //^^^^^^^^^^^^ Option<i32>
 +}
 +
 +pub trait MyClone: Sized {
 +    fn my_clone(&self) -> Self;
 +}
 +
 +impl<T> const MyClone for Option<T>
 +where
 +    T: ~const MyClone + ~const Destruct,
 +{
 +    fn my_clone(&self) -> Self {
 +        match self {
 +            Some(x) => Some(x.my_clone()),
 +            None => None,
 +        }
 +    }
 +}
 +
 +impl const MyClone for i32 {
 +    fn my_clone(&self) -> Self {
 +        *self
 +    }
 +}
 +
 +#[lang = "destruct"]
 +pub trait Destruct {}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn tuple_struct_pattern_with_unmatched_args_crash() {
 +    check_infer(
 +        r#"
 +struct S(usize);
 +fn main() {
 +    let S(.., a, b) = S(1);
 +    let (.., a, b) = (1,);
 +}
 +        "#,
 +        expect![[r#"
 +        27..85 '{     ...1,); }': ()
 +        37..48 'S(.., a, b)': S
 +        43..44 'a': usize
 +        46..47 'b': {unknown}
 +        51..52 'S': S(usize) -> S
 +        51..55 'S(1)': S
 +        53..54 '1': usize
 +        65..75 '(.., a, b)': (i32, {unknown})
 +        70..71 'a': i32
 +        73..74 'b': {unknown}
 +        78..82 '(1,)': (i32,)
 +        79..80 '1': i32
 +        "#]],
 +    );
 +}
++
++#[test]
++fn trailing_empty_macro() {
++    cov_mark::check!(empty_macro_in_trailing_position_is_removed);
++    check_no_mismatches(
++        r#"
++macro_rules! m2 {
++    ($($t:tt)*) => {$($t)*};
++}
++
++fn macrostmts() -> u8 {
++    m2! { 0 }
++    m2! {}
++}
++    "#,
++    );
++}
index 75802a5eb4db83810cf88cc18cf6f5cb3f1e5d6f,0000000000000000000000000000000000000000..0f37970e2b38d7fe678e101b19873789b2fbdd7e
mode 100644,000000..100644
--- /dev/null
@@@ -1,3782 -1,0 +1,3835 @@@
 +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#"
 +//- /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;
 +    }
 +}
 +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;
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[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
 +}
 +"#,
 +    )
 +}
index 8f984210e1176702c1ce23c865ed8aca631a4c82,0000000000000000000000000000000000000000..aa019ca48381adc9230359094bdf6e69f23701f9
mode 100644,000000..100644
--- /dev/null
@@@ -1,3639 -1,0 +1,3652 @@@
- use stdx::{format_to, impl_from, never};
 +//! 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::{ReprKind, 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,
 +    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,
 +    subst_prefix,
 +    traits::FnTrait,
 +    AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
 +    ClosureId, DebruijnIndex, GenericArgData, InEnvironment, Interner, ParamKind,
 +    QuantifiedWhereClause, Scalar, Solution, Substitution, TraitEnvironment, TraitRefExt, Ty,
 +    TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind, WhereClause,
 +};
 +use itertools::Itertools;
 +use nameres::diagnostics::DefDiagnosticKind;
 +use once_cell::unsync::Lazy;
 +use rustc_hash::FxHashSet;
-     /// A textual representation of the HIR of this function for debugging purposes.
-     pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
-         let body = db.body(self.id.into());
-         let mut result = String::new();
-         format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db));
-         for (id, expr) in body.exprs.iter() {
-             format_to!(result, "{:?}: {:?}\n", id, expr);
-         }
-         result
-     }
++use stdx::{impl_from, never};
 +use syntax::{
 +    ast::{self, HasAttrs as _, HasDocComments, HasName},
 +    AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T,
 +};
 +
 +use crate::db::{DefDatabase, HirDatabase};
 +
 +pub use crate::{
 +    attrs::{HasAttrs, Namespace},
 +    diagnostics::{
 +        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(),
 +            _ => 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::Module(_)
 +            | ModuleDef::Adt(_)
 +            | ModuleDef::Variant(_)
 +            | 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()
 +    }
 +
 +    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)
 +                    }
 +                }
 +                _ => acc.extend(decl.diagnostics(db)),
 +            }
 +        }
 +
 +        for impl_def in self.impl_defs(db) {
 +            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>) -> Option<ModPath> {
 +        hir_def::find_path::find_path(db, item.into().into(), self.into())
 +    }
 +
 +    /// 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,
 +    ) -> Option<ModPath> {
 +        hir_def::find_path::find_path_prefixed(db, item.into().into(), self.into(), prefix_kind)
 +    }
 +}
 +
 +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<ReprKind> {
 +        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)
 +    }
 +}
 +
 +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()))
 +    }
 +}
 +
 +#[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()
 +    }
 +}
 +
 +/// 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())
 +            .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),
 +}
 +impl_from!(Function, Const, Static 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),
 +        }
 +    }
 +
 +    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),
 +        }
 +    }
 +
 +    /// 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),
 +        }
 +    }
 +
++    fn id(&self) -> DefWithBodyId {
++        match self {
++            DefWithBody::Function(it) => it.id.into(),
++            DefWithBody::Static(it) => it.id.into(),
++            DefWithBody::Const(it) => it.id.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 {
 +            match d {
 +                hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
 +                    let field = source_map.field_syntax(*expr);
 +                    acc.push(NoSuchField { field }.into())
 +                }
 +                hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
 +                    let expr = source_map
 +                        .expr_syntax(*expr)
 +                        .expect("break outside of loop in synthetic syntax");
 +                    acc.push(BreakOutsideOfLoop { expr }.into())
 +                }
 +                hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
 +                    match source_map.expr_syntax(*call_expr) {
 +                        Ok(source_ptr) => acc.push(
 +                            MismatchedArgCount {
 +                                call_expr: source_ptr,
 +                                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(),
 +        };
 +        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() })
 +    }
-     /// Checks that particular type `ty` implements `std::future::Future`.
 +}
 +
 +// 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_prefix(&subst, local_idx));
 +        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 = TyBuilder::def_ty(db, def.into()).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()
 +    }
 +
-     pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
-         let std_future_trait = db
-             .lang_item(self.env.krate, SmolStr::new_inline("future_trait"))
-             .and_then(|it| it.as_trait());
-         let std_future_trait = match std_future_trait {
++    /// Checks that particular type `ty` implements `std::future::IntoFuture` or
++    /// `std::future::Future`.
 +    /// This function is used in `.await` syntax completion.
-         method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), std_future_trait)
++    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 projection = TyBuilder::assoc_type_projection(db, alias.id)
 +            .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();
 +        let goal = hir_ty::make_canonical(
 +            InEnvironment::new(
 +                &self.env.env,
 +                AliasEq {
 +                    alias: AliasTy::Projection(projection),
 +                    ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
 +                        .intern(Interner),
 +                }
 +                .cast(Interner),
 +            ),
 +            [TyVariableKind::General].into_iter(),
 +        );
 +
 +        match db.trait_solve(self.env.krate, goal)? {
 +            Solution::Unique(s) => s
 +                .value
 +                .subst
 +                .as_slice(Interner)
 +                .first()
 +                .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone())),
 +            Solution::Ambig(_) => None,
 +        }
 +    }
 +
 +    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(ReprKind::Packed)),
 +            _ => 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 ae2896e19329913cb3e57567fa2f8ccee4dc69cc,0000000000000000000000000000000000000000..bd35af06e23eb0ccbbd29146b61ca99394db1bfa
mode 100644,000000..100644
--- /dev/null
@@@ -1,1026 -1,0 +1,1048 @@@
-         let ty = self.ty_of_expr(db, &await_expr.expr()?.into())?;
 +//! Lookup hir elements using positions in the source code. This is a lossy
 +//! transformation: in general, a single source might correspond to several
 +//! modules, functions, etc, due to macros, cfgs and `#[path=]` attributes on
 +//! modules.
 +//!
 +//! So, this modules should not be used during hir construction, it exists
 +//! purely for "IDE needs".
 +use std::{
 +    iter::{self, once},
 +    sync::Arc,
 +};
 +
 +use hir_def::{
 +    body::{
 +        self,
 +        scope::{ExprScopes, ScopeId},
 +        Body, BodySourceMap,
 +    },
 +    expr::{ExprId, Pat, PatId},
 +    macro_id_to_def_id,
 +    path::{ModPath, Path, PathKind},
 +    resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
 +    type_ref::Mutability,
 +    AsMacroCall, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, LocalFieldId,
 +    Lookup, ModuleDefId, VariantId,
 +};
 +use hir_expand::{
 +    builtin_fn_macro::BuiltinFnLikeExpander,
 +    hygiene::Hygiene,
++    mod_path::path,
 +    name,
 +    name::{AsName, Name},
 +    HirFileId, InFile,
 +};
 +use hir_ty::{
 +    diagnostics::{
 +        record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
 +        UnsafeExpr,
 +    },
 +    method_resolution::{self, lang_names_for_bin_op},
 +    Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind,
 +    TyLoweringContext,
 +};
 +use itertools::Itertools;
 +use smallvec::SmallVec;
 +use syntax::{
 +    ast::{self, AstNode},
 +    SyntaxKind, SyntaxNode, TextRange, TextSize,
 +};
 +
 +use crate::{
 +    db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
 +    BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static,
 +    Struct, ToolModule, Trait, Type, TypeAlias, Variant,
 +};
 +
 +/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
 +/// original source files. It should not be used inside the HIR itself.
 +#[derive(Debug)]
 +pub(crate) struct SourceAnalyzer {
 +    pub(crate) file_id: HirFileId,
 +    pub(crate) resolver: Resolver,
 +    def: Option<(DefWithBodyId, Arc<Body>, Arc<BodySourceMap>)>,
 +    infer: Option<Arc<InferenceResult>>,
 +}
 +
 +impl SourceAnalyzer {
 +    pub(crate) fn new_for_body(
 +        db: &dyn HirDatabase,
 +        def: DefWithBodyId,
 +        node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
 +        offset: Option<TextSize>,
 +    ) -> SourceAnalyzer {
 +        let (body, source_map) = db.body_with_source_map(def);
 +        let scopes = db.expr_scopes(def);
 +        let scope = match offset {
 +            None => scope_for(&scopes, &source_map, node),
 +            Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
 +        };
 +        let resolver = resolver_for_scope(db.upcast(), def, scope);
 +        SourceAnalyzer {
 +            resolver,
 +            def: Some((def, body, source_map)),
 +            infer: Some(db.infer(def)),
 +            file_id,
 +        }
 +    }
 +
 +    pub(crate) fn new_for_body_no_infer(
 +        db: &dyn HirDatabase,
 +        def: DefWithBodyId,
 +        node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
 +        offset: Option<TextSize>,
 +    ) -> SourceAnalyzer {
 +        let (body, source_map) = db.body_with_source_map(def);
 +        let scopes = db.expr_scopes(def);
 +        let scope = match offset {
 +            None => scope_for(&scopes, &source_map, node),
 +            Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
 +        };
 +        let resolver = resolver_for_scope(db.upcast(), def, scope);
 +        SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer: None, file_id }
 +    }
 +
 +    pub(crate) fn new_for_resolver(
 +        resolver: Resolver,
 +        node: InFile<&SyntaxNode>,
 +    ) -> SourceAnalyzer {
 +        SourceAnalyzer { resolver, def: None, infer: None, file_id: node.file_id }
 +    }
 +
 +    fn body_source_map(&self) -> Option<&BodySourceMap> {
 +        self.def.as_ref().map(|(.., source_map)| &**source_map)
 +    }
 +    fn body(&self) -> Option<&Body> {
 +        self.def.as_ref().map(|(_, body, _)| &**body)
 +    }
 +
 +    fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
 +        let src = match expr {
 +            ast::Expr::MacroExpr(expr) => {
 +                self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?.clone()))?
 +            }
 +            _ => InFile::new(self.file_id, expr.clone()),
 +        };
 +        let sm = self.body_source_map()?;
 +        sm.node_expr(src.as_ref())
 +    }
 +
 +    fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
 +        // FIXME: macros, see `expr_id`
 +        let src = InFile { file_id: self.file_id, value: pat };
 +        self.body_source_map()?.node_pat(src)
 +    }
 +
 +    fn expand_expr(
 +        &self,
 +        db: &dyn HirDatabase,
 +        expr: InFile<ast::MacroCall>,
 +    ) -> Option<InFile<ast::Expr>> {
 +        let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?;
 +        let expanded = db.parse_or_expand(macro_file)?;
 +
 +        let res = match ast::MacroCall::cast(expanded.clone()) {
 +            Some(call) => self.expand_expr(db, InFile::new(macro_file, call))?,
 +            _ => InFile::new(macro_file, ast::Expr::cast(expanded)?),
 +        };
 +        Some(res)
 +    }
 +
 +    pub(crate) fn is_implicit_reborrow(
 +        &self,
 +        db: &dyn HirDatabase,
 +        expr: &ast::Expr,
 +    ) -> Option<Mutability> {
 +        let expr_id = self.expr_id(db, expr)?;
 +        let infer = self.infer.as_ref()?;
 +        let adjustments = infer.expr_adjustments.get(&expr_id)?;
 +        adjustments.windows(2).find_map(|slice| match slice {
 +            &[Adjustment {kind: Adjust::Deref(None), ..}, Adjustment {kind: Adjust::Borrow(AutoBorrow::Ref(m)), ..}] => Some(match m {
 +                hir_ty::Mutability::Mut => Mutability::Mut,
 +                hir_ty::Mutability::Not => Mutability::Shared,
 +            }),
 +            _ => None,
 +        })
 +    }
 +
 +    pub(crate) fn type_of_expr(
 +        &self,
 +        db: &dyn HirDatabase,
 +        expr: &ast::Expr,
 +    ) -> Option<(Type, Option<Type>)> {
 +        let expr_id = self.expr_id(db, expr)?;
 +        let infer = self.infer.as_ref()?;
 +        let coerced = infer
 +            .expr_adjustments
 +            .get(&expr_id)
 +            .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
 +        let ty = infer[expr_id].clone();
 +        let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
 +        Some((mk_ty(ty), coerced.map(mk_ty)))
 +    }
 +
 +    pub(crate) fn type_of_pat(
 +        &self,
 +        db: &dyn HirDatabase,
 +        pat: &ast::Pat,
 +    ) -> Option<(Type, Option<Type>)> {
 +        let pat_id = self.pat_id(pat)?;
 +        let infer = self.infer.as_ref()?;
 +        let coerced = infer
 +            .pat_adjustments
 +            .get(&pat_id)
 +            .and_then(|adjusts| adjusts.last().map(|adjust| adjust.clone()));
 +        let ty = infer[pat_id].clone();
 +        let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
 +        Some((mk_ty(ty), coerced.map(mk_ty)))
 +    }
 +
 +    pub(crate) fn type_of_self(
 +        &self,
 +        db: &dyn HirDatabase,
 +        param: &ast::SelfParam,
 +    ) -> Option<Type> {
 +        let src = InFile { file_id: self.file_id, value: param };
 +        let pat_id = self.body_source_map()?.node_self_param(src)?;
 +        let ty = self.infer.as_ref()?[pat_id].clone();
 +        Some(Type::new_with_resolver(db, &self.resolver, ty))
 +    }
 +
 +    pub(crate) fn binding_mode_of_pat(
 +        &self,
 +        _db: &dyn HirDatabase,
 +        pat: &ast::IdentPat,
 +    ) -> Option<BindingMode> {
 +        let pat_id = self.pat_id(&pat.clone().into())?;
 +        let infer = self.infer.as_ref()?;
 +        infer.pat_binding_modes.get(&pat_id).map(|bm| match bm {
 +            hir_ty::BindingMode::Move => BindingMode::Move,
 +            hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut),
 +            hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => {
 +                BindingMode::Ref(Mutability::Shared)
 +            }
 +        })
 +    }
 +    pub(crate) fn pattern_adjustments(
 +        &self,
 +        db: &dyn HirDatabase,
 +        pat: &ast::Pat,
 +    ) -> Option<SmallVec<[Type; 1]>> {
 +        let pat_id = self.pat_id(&pat)?;
 +        let infer = self.infer.as_ref()?;
 +        Some(
 +            infer
 +                .pat_adjustments
 +                .get(&pat_id)?
 +                .iter()
 +                .map(|ty| Type::new_with_resolver(db, &self.resolver, ty.clone()))
 +                .collect(),
 +        )
 +    }
 +
 +    pub(crate) fn resolve_method_call_as_callable(
 +        &self,
 +        db: &dyn HirDatabase,
 +        call: &ast::MethodCallExpr,
 +    ) -> Option<Callable> {
 +        let expr_id = self.expr_id(db, &call.clone().into())?;
 +        let (func, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
 +        let ty = db.value_ty(func.into()).substitute(Interner, &substs);
 +        let ty = Type::new_with_resolver(db, &self.resolver, ty);
 +        let mut res = ty.as_callable(db)?;
 +        res.is_bound_method = true;
 +        Some(res)
 +    }
 +
 +    pub(crate) fn resolve_method_call(
 +        &self,
 +        db: &dyn HirDatabase,
 +        call: &ast::MethodCallExpr,
 +    ) -> Option<FunctionId> {
 +        let expr_id = self.expr_id(db, &call.clone().into())?;
 +        let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
 +
 +        Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, &substs))
 +    }
 +
 +    pub(crate) fn resolve_await_to_poll(
 +        &self,
 +        db: &dyn HirDatabase,
 +        await_expr: &ast::AwaitExpr,
 +    ) -> Option<FunctionId> {
-         let op_fn = db
++        let mut ty = self.ty_of_expr(db, &await_expr.expr()?.into())?.clone();
 +
-         let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
-         Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
++        let into_future_trait = self
++            .resolver
++            .resolve_known_trait(db.upcast(), &path![core::future::IntoFuture])
++            .map(Trait::from);
++
++        if let Some(into_future_trait) = into_future_trait {
++            let type_ = Type::new_with_resolver(db, &self.resolver, ty.clone());
++            if type_.impls_trait(db, into_future_trait, &[]) {
++                let items = into_future_trait.items(db);
++                let into_future_type = items.into_iter().find_map(|item| match item {
++                    AssocItem::TypeAlias(alias)
++                        if alias.name(db) == hir_expand::name![IntoFuture] =>
++                    {
++                        Some(alias)
++                    }
++                    _ => None,
++                })?;
++                let future_trait = type_.normalize_trait_assoc_type(db, &[], into_future_type)?;
++                ty = future_trait.ty;
++            }
++        }
++
++        let poll_fn = db
 +            .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
 +            .as_function()?;
++        let substs = hir_ty::TyBuilder::subst_for_def(db, poll_fn).push(ty.clone()).build();
++        Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs))
 +    }
 +
 +    pub(crate) fn resolve_prefix_expr(
 +        &self,
 +        db: &dyn HirDatabase,
 +        prefix_expr: &ast::PrefixExpr,
 +    ) -> Option<FunctionId> {
 +        let lang_item_name = match prefix_expr.op_kind()? {
 +            ast::UnaryOp::Deref => name![deref],
 +            ast::UnaryOp::Not => name![not],
 +            ast::UnaryOp::Neg => name![neg],
 +        };
 +        let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?;
 +
 +        let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
 +        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
 +
 +        Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
 +    }
 +
 +    pub(crate) fn resolve_index_expr(
 +        &self,
 +        db: &dyn HirDatabase,
 +        index_expr: &ast::IndexExpr,
 +    ) -> Option<FunctionId> {
 +        let base_ty = self.ty_of_expr(db, &index_expr.base()?.into())?;
 +        let index_ty = self.ty_of_expr(db, &index_expr.index()?.into())?;
 +
 +        let lang_item_name = name![index];
 +
 +        let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
 +        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn)
 +            .push(base_ty.clone())
 +            .push(index_ty.clone())
 +            .build();
 +        Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
 +    }
 +
 +    pub(crate) fn resolve_bin_expr(
 +        &self,
 +        db: &dyn HirDatabase,
 +        binop_expr: &ast::BinExpr,
 +    ) -> Option<FunctionId> {
 +        let op = binop_expr.op_kind()?;
 +        let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?;
 +        let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?;
 +
 +        let op_fn = lang_names_for_bin_op(op)
 +            .and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?;
 +        let substs =
 +            hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build();
 +
 +        Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
 +    }
 +
 +    pub(crate) fn resolve_try_expr(
 +        &self,
 +        db: &dyn HirDatabase,
 +        try_expr: &ast::TryExpr,
 +    ) -> Option<FunctionId> {
 +        let ty = self.ty_of_expr(db, &try_expr.expr()?.into())?;
 +
 +        let op_fn =
 +            db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?;
 +        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
 +
 +        Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
 +    }
 +
 +    pub(crate) fn resolve_field(
 +        &self,
 +        db: &dyn HirDatabase,
 +        field: &ast::FieldExpr,
 +    ) -> Option<Field> {
 +        let expr_id = self.expr_id(db, &field.clone().into())?;
 +        self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into())
 +    }
 +
 +    pub(crate) fn resolve_record_field(
 +        &self,
 +        db: &dyn HirDatabase,
 +        field: &ast::RecordExprField,
 +    ) -> Option<(Field, Option<Local>, Type)> {
 +        let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
 +        let expr = ast::Expr::from(record_expr);
 +        let expr_id = self.body_source_map()?.node_expr(InFile::new(self.file_id, &expr))?;
 +
 +        let local_name = field.field_name()?.as_name();
 +        let local = if field.name_ref().is_some() {
 +            None
 +        } else {
 +            // Shorthand syntax, resolve to the local
 +            let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone()));
 +            match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
 +                Some(ValueNs::LocalBinding(pat_id)) => {
 +                    Some(Local { pat_id, parent: self.resolver.body_owner()? })
 +                }
 +                _ => None,
 +            }
 +        };
 +        let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?;
 +        let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?;
 +        let variant_data = variant.variant_data(db.upcast());
 +        let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
 +        let field_ty =
 +            db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst);
 +        Some((field.into(), local, Type::new_with_resolver(db, &self.resolver, field_ty)))
 +    }
 +
 +    pub(crate) fn resolve_record_pat_field(
 +        &self,
 +        db: &dyn HirDatabase,
 +        field: &ast::RecordPatField,
 +    ) -> Option<Field> {
 +        let field_name = field.field_name()?.as_name();
 +        let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
 +        let pat_id = self.pat_id(&record_pat.into())?;
 +        let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id)?;
 +        let variant_data = variant.variant_data(db.upcast());
 +        let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
 +        Some(field.into())
 +    }
 +
 +    pub(crate) fn resolve_macro_call(
 +        &self,
 +        db: &dyn HirDatabase,
 +        macro_call: InFile<&ast::MacroCall>,
 +    ) -> Option<Macro> {
 +        let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id);
 +        let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?;
 +        self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into())
 +    }
 +
 +    pub(crate) fn resolve_bind_pat_to_const(
 +        &self,
 +        db: &dyn HirDatabase,
 +        pat: &ast::IdentPat,
 +    ) -> Option<ModuleDef> {
 +        let pat_id = self.pat_id(&pat.clone().into())?;
 +        let body = self.body()?;
 +        let path = match &body[pat_id] {
 +            Pat::Path(path) => path,
 +            _ => return None,
 +        };
 +        let res = resolve_hir_path(db, &self.resolver, path)?;
 +        match res {
 +            PathResolution::Def(def) => Some(def),
 +            _ => None,
 +        }
 +    }
 +
 +    pub(crate) fn resolve_path(
 +        &self,
 +        db: &dyn HirDatabase,
 +        path: &ast::Path,
 +    ) -> Option<PathResolution> {
 +        let parent = path.syntax().parent();
 +        let parent = || parent.clone();
 +
 +        let mut prefer_value_ns = false;
 +        let resolved = (|| {
 +            if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {
 +                let expr_id = self.expr_id(db, &path_expr.into())?;
 +                let infer = self.infer.as_ref()?;
 +                if let Some(assoc) = infer.assoc_resolutions_for_expr(expr_id) {
 +                    let assoc = match assoc {
 +                        AssocItemId::FunctionId(f_in_trait) => {
 +                            match infer.type_of_expr.get(expr_id) {
 +                                None => assoc,
 +                                Some(func_ty) => {
 +                                    if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) {
 +                                        self.resolve_impl_method(db, f_in_trait, subs)
 +                                            .map(AssocItemId::FunctionId)
 +                                            .unwrap_or(assoc)
 +                                    } else {
 +                                        assoc
 +                                    }
 +                                }
 +                            }
 +                        }
 +
 +                        _ => assoc,
 +                    };
 +
 +                    return Some(PathResolution::Def(AssocItem::from(assoc).into()));
 +                }
 +                if let Some(VariantId::EnumVariantId(variant)) =
 +                    infer.variant_resolution_for_expr(expr_id)
 +                {
 +                    return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
 +                }
 +                prefer_value_ns = true;
 +            } else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) {
 +                let pat_id = self.pat_id(&path_pat.into())?;
 +                if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) {
 +                    return Some(PathResolution::Def(AssocItem::from(assoc).into()));
 +                }
 +                if let Some(VariantId::EnumVariantId(variant)) =
 +                    self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
 +                {
 +                    return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
 +                }
 +            } else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) {
 +                let expr_id = self.expr_id(db, &rec_lit.into())?;
 +                if let Some(VariantId::EnumVariantId(variant)) =
 +                    self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
 +                {
 +                    return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
 +                }
 +            } else {
 +                let record_pat = parent().and_then(ast::RecordPat::cast).map(ast::Pat::from);
 +                let tuple_struct_pat =
 +                    || parent().and_then(ast::TupleStructPat::cast).map(ast::Pat::from);
 +                if let Some(pat) = record_pat.or_else(tuple_struct_pat) {
 +                    let pat_id = self.pat_id(&pat)?;
 +                    let variant_res_for_pat =
 +                        self.infer.as_ref()?.variant_resolution_for_pat(pat_id);
 +                    if let Some(VariantId::EnumVariantId(variant)) = variant_res_for_pat {
 +                        return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
 +                    }
 +                }
 +            }
 +            None
 +        })();
 +        if let Some(_) = resolved {
 +            return resolved;
 +        }
 +
 +        // This must be a normal source file rather than macro file.
 +        let hygiene = Hygiene::new(db.upcast(), self.file_id);
 +        let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene);
 +        let hir_path = Path::from_src(path.clone(), &ctx)?;
 +
 +        // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
 +        // trying to resolve foo::bar.
 +        if let Some(use_tree) = parent().and_then(ast::UseTree::cast) {
 +            if use_tree.coloncolon_token().is_some() {
 +                return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
 +            }
 +        }
 +
 +        let meta_path = path
 +            .syntax()
 +            .ancestors()
 +            .take_while(|it| {
 +                let kind = it.kind();
 +                ast::Path::can_cast(kind) || ast::Meta::can_cast(kind)
 +            })
 +            .last()
 +            .and_then(ast::Meta::cast);
 +
 +        // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
 +        // trying to resolve foo::bar.
 +        if path.parent_path().is_some() {
 +            return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path) {
 +                None if meta_path.is_some() => {
 +                    path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
 +                        ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
 +                            .map(PathResolution::ToolModule)
 +                    })
 +                }
 +                res => res,
 +            };
 +        } else if let Some(meta_path) = meta_path {
 +            // Case where we are resolving the final path segment of a path in an attribute
 +            // in this case we have to check for inert/builtin attributes and tools and prioritize
 +            // resolution of attributes over other namespaces
 +            if let Some(name_ref) = path.as_single_name_ref() {
 +                let builtin =
 +                    BuiltinAttr::by_name(db, self.resolver.krate().into(), &name_ref.text());
 +                if let Some(_) = builtin {
 +                    return builtin.map(PathResolution::BuiltinAttr);
 +                }
 +
 +                if let Some(attr) = meta_path.parent_attr() {
 +                    let adt = if let Some(field) =
 +                        attr.syntax().parent().and_then(ast::RecordField::cast)
 +                    {
 +                        field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
 +                    } else if let Some(field) =
 +                        attr.syntax().parent().and_then(ast::TupleField::cast)
 +                    {
 +                        field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
 +                    } else if let Some(variant) =
 +                        attr.syntax().parent().and_then(ast::Variant::cast)
 +                    {
 +                        variant.syntax().ancestors().nth(2).and_then(ast::Adt::cast)
 +                    } else {
 +                        None
 +                    };
 +                    if let Some(adt) = adt {
 +                        let ast_id = db.ast_id_map(self.file_id).ast_id(&adt);
 +                        if let Some(helpers) = self
 +                            .resolver
 +                            .def_map()
 +                            .derive_helpers_in_scope(InFile::new(self.file_id, ast_id))
 +                        {
 +                            // FIXME: Multiple derives can have the same helper
 +                            let name_ref = name_ref.as_name();
 +                            for (macro_id, mut helpers) in
 +                                helpers.iter().group_by(|(_, macro_id, ..)| macro_id).into_iter()
 +                            {
 +                                if let Some(idx) = helpers.position(|(name, ..)| *name == name_ref)
 +                                {
 +                                    return Some(PathResolution::DeriveHelper(DeriveHelper {
 +                                        derive: *macro_id,
 +                                        idx,
 +                                    }));
 +                                }
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +            return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) {
 +                Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))),
 +                // this labels any path that starts with a tool module as the tool itself, this is technically wrong
 +                // but there is no benefit in differentiating these two cases for the time being
 +                None => path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
 +                    ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
 +                        .map(PathResolution::ToolModule)
 +                }),
 +            };
 +        }
 +        if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) {
 +            resolve_hir_path_qualifier(db, &self.resolver, &hir_path)
 +        } else {
 +            resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns)
 +        }
 +    }
 +
 +    pub(crate) fn record_literal_missing_fields(
 +        &self,
 +        db: &dyn HirDatabase,
 +        literal: &ast::RecordExpr,
 +    ) -> Option<Vec<(Field, Type)>> {
 +        let body = self.body()?;
 +        let infer = self.infer.as_ref()?;
 +
 +        let expr_id = self.expr_id(db, &literal.clone().into())?;
 +        let substs = infer.type_of_expr[expr_id].as_adt()?.1;
 +
 +        let (variant, missing_fields, _exhaustive) =
 +            record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;
 +        let res = self.missing_fields(db, substs, variant, missing_fields);
 +        Some(res)
 +    }
 +
 +    pub(crate) fn record_pattern_missing_fields(
 +        &self,
 +        db: &dyn HirDatabase,
 +        pattern: &ast::RecordPat,
 +    ) -> Option<Vec<(Field, Type)>> {
 +        let body = self.body()?;
 +        let infer = self.infer.as_ref()?;
 +
 +        let pat_id = self.pat_id(&pattern.clone().into())?;
 +        let substs = infer.type_of_pat[pat_id].as_adt()?.1;
 +
 +        let (variant, missing_fields, _exhaustive) =
 +            record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?;
 +        let res = self.missing_fields(db, substs, variant, missing_fields);
 +        Some(res)
 +    }
 +
 +    fn missing_fields(
 +        &self,
 +        db: &dyn HirDatabase,
 +        substs: &Substitution,
 +        variant: VariantId,
 +        missing_fields: Vec<LocalFieldId>,
 +    ) -> Vec<(Field, Type)> {
 +        let field_types = db.field_types(variant);
 +
 +        missing_fields
 +            .into_iter()
 +            .map(|local_id| {
 +                let field = FieldId { parent: variant, local_id };
 +                let ty = field_types[local_id].clone().substitute(Interner, substs);
 +                (field.into(), Type::new_with_resolver_inner(db, &self.resolver, ty))
 +            })
 +            .collect()
 +    }
 +
 +    pub(crate) fn expand(
 +        &self,
 +        db: &dyn HirDatabase,
 +        macro_call: InFile<&ast::MacroCall>,
 +    ) -> Option<HirFileId> {
 +        let krate = self.resolver.krate();
 +        let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
 +            self.resolver
 +                .resolve_path_as_macro(db.upcast(), &path)
 +                .map(|it| macro_id_to_def_id(db.upcast(), it))
 +        })?;
 +        Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64)
 +    }
 +
 +    pub(crate) fn resolve_variant(
 +        &self,
 +        db: &dyn HirDatabase,
 +        record_lit: ast::RecordExpr,
 +    ) -> Option<VariantId> {
 +        let infer = self.infer.as_ref()?;
 +        let expr_id = self.expr_id(db, &record_lit.into())?;
 +        infer.variant_resolution_for_expr(expr_id)
 +    }
 +
 +    pub(crate) fn is_unsafe_macro_call(
 +        &self,
 +        db: &dyn HirDatabase,
 +        macro_call: InFile<&ast::MacroCall>,
 +    ) -> bool {
 +        // check for asm/global_asm
 +        if let Some(mac) = self.resolve_macro_call(db, macro_call) {
 +            let ex = match mac.id {
 +                hir_def::MacroId::Macro2Id(it) => it.lookup(db.upcast()).expander,
 +                hir_def::MacroId::MacroRulesId(it) => it.lookup(db.upcast()).expander,
 +                _ => hir_def::MacroExpander::Declarative,
 +            };
 +            match ex {
 +                hir_def::MacroExpander::BuiltIn(e)
 +                    if e == BuiltinFnLikeExpander::Asm || e == BuiltinFnLikeExpander::GlobalAsm =>
 +                {
 +                    return true
 +                }
 +                _ => (),
 +            }
 +        }
 +        let macro_expr = match macro_call
 +            .map(|it| it.syntax().parent().and_then(ast::MacroExpr::cast))
 +            .transpose()
 +        {
 +            Some(it) => it,
 +            None => return false,
 +        };
 +
 +        if let (Some((def, body, sm)), Some(infer)) = (&self.def, &self.infer) {
 +            if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr.as_ref()) {
 +                let mut is_unsafe = false;
 +                unsafe_expressions(
 +                    db,
 +                    infer,
 +                    *def,
 +                    body,
 +                    expanded_expr,
 +                    &mut |UnsafeExpr { inside_unsafe_block, .. }| is_unsafe |= !inside_unsafe_block,
 +                );
 +                return is_unsafe;
 +            }
 +        }
 +        false
 +    }
 +
 +    fn resolve_impl_method(
 +        &self,
 +        db: &dyn HirDatabase,
 +        func: FunctionId,
 +        substs: &Substitution,
 +    ) -> Option<FunctionId> {
 +        let impled_trait = match func.lookup(db.upcast()).container {
 +            ItemContainerId::TraitId(trait_id) => trait_id,
 +            _ => return None,
 +        };
 +        if substs.is_empty(Interner) {
 +            return None;
 +        }
 +        let self_ty = substs.at(Interner, 0).ty(Interner)?;
 +        let krate = self.resolver.krate();
 +        let trait_env = self.resolver.body_owner()?.as_generic_def_id().map_or_else(
 +            || Arc::new(hir_ty::TraitEnvironment::empty(krate)),
 +            |d| db.trait_environment(d),
 +        );
 +
 +        let fun_data = db.function_data(func);
 +        method_resolution::lookup_impl_method(self_ty, db, trait_env, impled_trait, &fun_data.name)
 +    }
 +
 +    fn resolve_impl_method_or_trait_def(
 +        &self,
 +        db: &dyn HirDatabase,
 +        func: FunctionId,
 +        substs: &Substitution,
 +    ) -> FunctionId {
 +        self.resolve_impl_method(db, func, substs).unwrap_or(func)
 +    }
 +
 +    fn lang_trait_fn(
 +        &self,
 +        db: &dyn HirDatabase,
 +        lang_trait: &Name,
 +        method_name: &Name,
 +    ) -> Option<FunctionId> {
 +        db.trait_data(db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?)
 +            .method_by_name(method_name)
 +    }
 +
 +    fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
 +        self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, &expr)?)
 +    }
 +}
 +
 +fn scope_for(
 +    scopes: &ExprScopes,
 +    source_map: &BodySourceMap,
 +    node: InFile<&SyntaxNode>,
 +) -> Option<ScopeId> {
 +    node.value
 +        .ancestors()
 +        .filter_map(ast::Expr::cast)
 +        .filter_map(|it| source_map.node_expr(InFile::new(node.file_id, &it)))
 +        .find_map(|it| scopes.scope_for(it))
 +}
 +
 +fn scope_for_offset(
 +    db: &dyn HirDatabase,
 +    scopes: &ExprScopes,
 +    source_map: &BodySourceMap,
 +    from_file: HirFileId,
 +    offset: TextSize,
 +) -> Option<ScopeId> {
 +    scopes
 +        .scope_by_expr()
 +        .iter()
 +        .filter_map(|(id, scope)| {
 +            let InFile { file_id, value } = source_map.expr_syntax(*id).ok()?;
 +            if from_file == file_id {
 +                return Some((value.text_range(), scope));
 +            }
 +
 +            // FIXME handle attribute expansion
 +            let source = iter::successors(file_id.call_node(db.upcast()), |it| {
 +                it.file_id.call_node(db.upcast())
 +            })
 +            .find(|it| it.file_id == from_file)
 +            .filter(|it| it.value.kind() == SyntaxKind::MACRO_CALL)?;
 +            Some((source.value.text_range(), scope))
 +        })
 +        .filter(|(expr_range, _scope)| expr_range.start() <= offset && offset <= expr_range.end())
 +        // find containing scope
 +        .min_by_key(|(expr_range, _scope)| expr_range.len())
 +        .map(|(expr_range, scope)| {
 +            adjust(db, scopes, source_map, expr_range, from_file, offset).unwrap_or(*scope)
 +        })
 +}
 +
 +// XXX: during completion, cursor might be outside of any particular
 +// expression. Try to figure out the correct scope...
 +fn adjust(
 +    db: &dyn HirDatabase,
 +    scopes: &ExprScopes,
 +    source_map: &BodySourceMap,
 +    expr_range: TextRange,
 +    from_file: HirFileId,
 +    offset: TextSize,
 +) -> Option<ScopeId> {
 +    let child_scopes = scopes
 +        .scope_by_expr()
 +        .iter()
 +        .filter_map(|(id, scope)| {
 +            let source = source_map.expr_syntax(*id).ok()?;
 +            // FIXME: correctly handle macro expansion
 +            if source.file_id != from_file {
 +                return None;
 +            }
 +            let root = source.file_syntax(db.upcast());
 +            let node = source.value.to_node(&root);
 +            Some((node.syntax().text_range(), scope))
 +        })
 +        .filter(|&(range, _)| {
 +            range.start() <= offset && expr_range.contains_range(range) && range != expr_range
 +        });
 +
 +    child_scopes
 +        .max_by(|&(r1, _), &(r2, _)| {
 +            if r1.contains_range(r2) {
 +                std::cmp::Ordering::Greater
 +            } else if r2.contains_range(r1) {
 +                std::cmp::Ordering::Less
 +            } else {
 +                r1.start().cmp(&r2.start())
 +            }
 +        })
 +        .map(|(_ptr, scope)| *scope)
 +}
 +
 +#[inline]
 +pub(crate) fn resolve_hir_path(
 +    db: &dyn HirDatabase,
 +    resolver: &Resolver,
 +    path: &Path,
 +) -> Option<PathResolution> {
 +    resolve_hir_path_(db, resolver, path, false)
 +}
 +
 +#[inline]
 +pub(crate) fn resolve_hir_path_as_macro(
 +    db: &dyn HirDatabase,
 +    resolver: &Resolver,
 +    path: &Path,
 +) -> Option<Macro> {
 +    resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(Into::into)
 +}
 +
 +fn resolve_hir_path_(
 +    db: &dyn HirDatabase,
 +    resolver: &Resolver,
 +    path: &Path,
 +    prefer_value_ns: bool,
 +) -> Option<PathResolution> {
 +    let types = || {
 +        let (ty, unresolved) = match path.type_anchor() {
 +            Some(type_ref) => {
 +                let (_, res) = TyLoweringContext::new(db, resolver).lower_ty_ext(type_ref);
 +                res.map(|ty_ns| (ty_ns, path.segments().first()))
 +            }
 +            None => {
 +                let (ty, remaining) =
 +                    resolver.resolve_path_in_type_ns(db.upcast(), path.mod_path())?;
 +                match remaining {
 +                    Some(remaining) if remaining > 1 => {
 +                        if remaining + 1 == path.segments().len() {
 +                            Some((ty, path.segments().last()))
 +                        } else {
 +                            None
 +                        }
 +                    }
 +                    _ => Some((ty, path.segments().get(1))),
 +                }
 +            }
 +        }?;
 +
 +        // If we are in a TypeNs for a Trait, and we have an unresolved name, try to resolve it as a type
 +        // within the trait's associated types.
 +        if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) {
 +            if let Some(type_alias_id) =
 +                db.trait_data(trait_id).associated_type_by_name(unresolved.name)
 +            {
 +                return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));
 +            }
 +        }
 +
 +        let res = match ty {
 +            TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
 +            TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
 +            TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
 +                PathResolution::Def(Adt::from(it).into())
 +            }
 +            TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
 +            TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
 +            TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
 +            TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
 +        };
 +        match unresolved {
 +            Some(unresolved) => resolver
 +                .generic_def()
 +                .and_then(|def| {
 +                    hir_ty::associated_type_shorthand_candidates(
 +                        db,
 +                        def,
 +                        res.in_type_ns()?,
 +                        |name, _, id| (name == unresolved.name).then(|| id),
 +                    )
 +                })
 +                .map(TypeAlias::from)
 +                .map(Into::into)
 +                .map(PathResolution::Def),
 +            None => Some(res),
 +        }
 +    };
 +
 +    let body_owner = resolver.body_owner();
 +    let values = || {
 +        resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| {
 +            let res = match val {
 +                ValueNs::LocalBinding(pat_id) => {
 +                    let var = Local { parent: body_owner?, pat_id };
 +                    PathResolution::Local(var)
 +                }
 +                ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()),
 +                ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()),
 +                ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()),
 +                ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
 +                ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
 +                ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()),
 +                ValueNs::GenericParam(id) => PathResolution::ConstParam(id.into()),
 +            };
 +            Some(res)
 +        })
 +    };
 +
 +    let items = || {
 +        resolver
 +            .resolve_module_path_in_items(db.upcast(), path.mod_path())
 +            .take_types()
 +            .map(|it| PathResolution::Def(it.into()))
 +    };
 +
 +    let macros = || {
 +        resolver
 +            .resolve_path_as_macro(db.upcast(), path.mod_path())
 +            .map(|def| PathResolution::Def(ModuleDef::Macro(def.into())))
 +    };
 +
 +    if prefer_value_ns { values().or_else(types) } else { types().or_else(values) }
 +        .or_else(items)
 +        .or_else(macros)
 +}
 +
 +/// Resolves a path where we know it is a qualifier of another path.
 +///
 +/// For example, if we have:
 +/// ```
 +/// mod my {
 +///     pub mod foo {
 +///         struct Bar;
 +///     }
 +///
 +///     pub fn foo() {}
 +/// }
 +/// ```
 +/// then we know that `foo` in `my::foo::Bar` refers to the module, not the function.
 +fn resolve_hir_path_qualifier(
 +    db: &dyn HirDatabase,
 +    resolver: &Resolver,
 +    path: &Path,
 +) -> Option<PathResolution> {
 +    resolver
 +        .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path())
 +        .map(|ty| match ty {
 +            TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
 +            TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
 +            TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
 +                PathResolution::Def(Adt::from(it).into())
 +            }
 +            TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
 +            TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
 +            TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
 +            TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
 +        })
 +        .or_else(|| {
 +            resolver
 +                .resolve_module_path_in_items(db.upcast(), path.mod_path())
 +                .take_types()
 +                .map(|it| PathResolution::Def(it.into()))
 +        })
 +}
index b3c4d306ac1c58d64fc3b1e4281dfc826ff4d467,0000000000000000000000000000000000000000..897980c6650497132360baa4833ee68bcb5858a1
mode 100644,000000..100644
--- /dev/null
@@@ -1,1770 -1,0 +1,1770 @@@
- // Extracts a selected region as seperate module. All the references, visibility and imports are
 +use std::{
 +    collections::{HashMap, HashSet},
 +    iter,
 +};
 +
 +use hir::{HasSource, ModuleSource};
 +use ide_db::{
 +    assists::{AssistId, AssistKind},
 +    base_db::FileId,
 +    defs::{Definition, NameClass, NameRefClass},
 +    search::{FileReference, SearchScope},
 +};
 +use stdx::format_to;
 +use syntax::{
 +    algo::find_node_at_range,
 +    ast::{
 +        self,
 +        edit::{AstNodeEdit, IndentLevel},
 +        make, HasName, HasVisibility,
 +    },
 +    match_ast, ted, AstNode, SourceFile,
 +    SyntaxKind::{self, WHITESPACE},
 +    SyntaxNode, TextRange,
 +};
 +
 +use crate::{AssistContext, Assists};
 +
 +use super::remove_unused_param::range_to_remove;
 +
 +// Assist: extract_module
 +//
-             //  new import statemnts
++// Extracts a selected region as separate module. All the references, visibility and imports are
 +// resolved.
 +//
 +// ```
 +// $0fn foo(name: i32) -> i32 {
 +//     name + 1
 +// }$0
 +//
 +// fn bar(name: i32) -> i32 {
 +//     name + 2
 +// }
 +// ```
 +// ->
 +// ```
 +// mod modname {
 +//     pub(crate) fn foo(name: i32) -> i32 {
 +//         name + 1
 +//     }
 +// }
 +//
 +// fn bar(name: i32) -> i32 {
 +//     name + 2
 +// }
 +// ```
 +pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    if ctx.has_empty_selection() {
 +        return None;
 +    }
 +
 +    let node = ctx.covering_element();
 +    let node = match node {
 +        syntax::NodeOrToken::Node(n) => n,
 +        syntax::NodeOrToken::Token(t) => t.parent()?,
 +    };
 +
 +    //If the selection is inside impl block, we need to place new module outside impl block,
 +    //as impl blocks cannot contain modules
 +
 +    let mut impl_parent: Option<ast::Impl> = None;
 +    let mut impl_child_count: usize = 0;
 +    if let Some(parent_assoc_list) = node.parent() {
 +        if let Some(parent_impl) = parent_assoc_list.parent() {
 +            if let Some(impl_) = ast::Impl::cast(parent_impl) {
 +                impl_child_count = parent_assoc_list.children().count();
 +                impl_parent = Some(impl_);
 +            }
 +        }
 +    }
 +
 +    let mut curr_parent_module: Option<ast::Module> = None;
 +    if let Some(mod_syn_opt) = node.ancestors().find(|it| ast::Module::can_cast(it.kind())) {
 +        curr_parent_module = ast::Module::cast(mod_syn_opt);
 +    }
 +
 +    let mut module = extract_target(&node, ctx.selection_trimmed())?;
 +    if module.body_items.is_empty() {
 +        return None;
 +    }
 +
 +    let old_item_indent = module.body_items[0].indent_level();
 +
 +    acc.add(
 +        AssistId("extract_module", AssistKind::RefactorExtract),
 +        "Extract Module",
 +        module.text_range,
 +        |builder| {
 +            //This takes place in three steps:
 +            //
 +            //- Firstly, we will update the references(usages) e.g. converting a
 +            //  function call bar() to modname::bar(), and similarly for other items
 +            //
 +            //- Secondly, changing the visibility of each item inside the newly selected module
 +            //  i.e. making a fn a() {} to pub(crate) fn a() {}
 +            //
 +            //- Thirdly, resolving all the imports this includes removing paths from imports
 +            //  outside the module, shifting/cloning them inside new module, or shifting the imports, or making
-         // Text ranges recieved here for imports are extended to the
++            //  new import statements
 +
 +            //We are getting item usages and record_fields together, record_fields
 +            //for change_visibility and usages for first point mentioned above in the process
 +            let (usages_to_be_processed, record_fields) = module.get_usages_and_record_fields(ctx);
 +
 +            let import_paths_to_be_removed = module.resolve_imports(curr_parent_module, ctx);
 +            module.change_visibility(record_fields);
 +
 +            let mut body_items: Vec<String> = Vec::new();
 +            let mut items_to_be_processed: Vec<ast::Item> = module.body_items.clone();
 +            let mut new_item_indent = old_item_indent + 1;
 +
 +            if impl_parent.is_some() {
 +                new_item_indent = old_item_indent + 2;
 +            } else {
 +                items_to_be_processed = [module.use_items.clone(), items_to_be_processed].concat();
 +            }
 +
 +            for item in items_to_be_processed {
 +                let item = item.indent(IndentLevel(1));
 +                let mut indented_item = String::new();
 +                format_to!(indented_item, "{}{}", new_item_indent, item.to_string());
 +                body_items.push(indented_item);
 +            }
 +
 +            let mut body = body_items.join("\n\n");
 +
 +            if let Some(impl_) = &impl_parent {
 +                let mut impl_body_def = String::new();
 +
 +                if let Some(self_ty) = impl_.self_ty() {
 +                    format_to!(
 +                        impl_body_def,
 +                        "{}impl {} {{\n{}\n{}}}",
 +                        old_item_indent + 1,
 +                        self_ty.to_string(),
 +                        body,
 +                        old_item_indent + 1
 +                    );
 +
 +                    body = impl_body_def;
 +
 +                    // Add the import for enum/struct corresponding to given impl block
 +                    module.make_use_stmt_of_node_with_super(self_ty.syntax());
 +                    for item in module.use_items {
 +                        let mut indented_item = String::new();
 +                        format_to!(indented_item, "{}{}", old_item_indent + 1, item.to_string());
 +                        body = format!("{}\n\n{}", indented_item, body);
 +                    }
 +                }
 +            }
 +
 +            let mut module_def = String::new();
 +
 +            format_to!(module_def, "mod {} {{\n{}\n{}}}", module.name, body, old_item_indent);
 +
 +            let mut usages_to_be_updated_for_curr_file = vec![];
 +            for usages_to_be_updated_for_file in usages_to_be_processed {
 +                if usages_to_be_updated_for_file.0 == ctx.file_id() {
 +                    usages_to_be_updated_for_curr_file = usages_to_be_updated_for_file.1;
 +                    continue;
 +                }
 +                builder.edit_file(usages_to_be_updated_for_file.0);
 +                for usage_to_be_processed in usages_to_be_updated_for_file.1 {
 +                    builder.replace(usage_to_be_processed.0, usage_to_be_processed.1)
 +                }
 +            }
 +
 +            builder.edit_file(ctx.file_id());
 +            for usage_to_be_processed in usages_to_be_updated_for_curr_file {
 +                builder.replace(usage_to_be_processed.0, usage_to_be_processed.1)
 +            }
 +
 +            for import_path_text_range in import_paths_to_be_removed {
 +                builder.delete(import_path_text_range);
 +            }
 +
 +            if let Some(impl_) = impl_parent {
 +                // Remove complete impl block if it has only one child (as such it will be empty
 +                // after deleting that child)
 +                let node_to_be_removed = if impl_child_count == 1 {
 +                    impl_.syntax()
 +                } else {
 +                    //Remove selected node
 +                    &node
 +                };
 +
 +                builder.delete(node_to_be_removed.text_range());
 +                // Remove preceding indentation from node
 +                if let Some(range) = indent_range_before_given_node(node_to_be_removed) {
 +                    builder.delete(range);
 +                }
 +
 +                builder.insert(impl_.syntax().text_range().end(), format!("\n\n{}", module_def));
 +            } else {
 +                builder.replace(module.text_range, module_def)
 +            }
 +        },
 +    )
 +}
 +
 +#[derive(Debug)]
 +struct Module {
 +    text_range: TextRange,
 +    name: &'static str,
 +    /// All items except use items.
 +    body_items: Vec<ast::Item>,
 +    /// Use items are kept separately as they help when the selection is inside an impl block,
 +    /// we can directly take these items and keep them outside generated impl block inside
 +    /// generated module.
 +    use_items: Vec<ast::Item>,
 +}
 +
 +fn extract_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Module> {
 +    let selected_nodes = node
 +        .children()
 +        .filter(|node| selection_range.contains_range(node.text_range()))
 +        .chain(iter::once(node.clone()));
 +    let (use_items, body_items) = selected_nodes
 +        .filter_map(ast::Item::cast)
 +        .partition(|item| matches!(item, ast::Item::Use(..)));
 +
 +    Some(Module { text_range: selection_range, name: "modname", body_items, use_items })
 +}
 +
 +impl Module {
 +    fn get_usages_and_record_fields(
 +        &self,
 +        ctx: &AssistContext<'_>,
 +    ) -> (HashMap<FileId, Vec<(TextRange, String)>>, Vec<SyntaxNode>) {
 +        let mut adt_fields = Vec::new();
 +        let mut refs: HashMap<FileId, Vec<(TextRange, String)>> = HashMap::new();
 +
 +        //Here impl is not included as each item inside impl will be tied to the parent of
 +        //implementing block(a struct, enum, etc), if the parent is in selected module, it will
 +        //get updated by ADT section given below or if it is not, then we dont need to do any operation
 +        for item in &self.body_items {
 +            match_ast! {
 +                match (item.syntax()) {
 +                    ast::Adt(it) => {
 +                        if let Some( nod ) = ctx.sema.to_def(&it) {
 +                            let node_def = Definition::Adt(nod);
 +                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
 +
 +                            //Enum Fields are not allowed to explicitly specify pub, it is implied
 +                            match it {
 +                                ast::Adt::Struct(x) => {
 +                                    if let Some(field_list) = x.field_list() {
 +                                        match field_list {
 +                                            ast::FieldList::RecordFieldList(record_field_list) => {
 +                                                record_field_list.fields().for_each(|record_field| {
 +                                                    adt_fields.push(record_field.syntax().clone());
 +                                                });
 +                                            },
 +                                            ast::FieldList::TupleFieldList(tuple_field_list) => {
 +                                                tuple_field_list.fields().for_each(|tuple_field| {
 +                                                    adt_fields.push(tuple_field.syntax().clone());
 +                                                });
 +                                            },
 +                                        }
 +                                    }
 +                                },
 +                                ast::Adt::Union(x) => {
 +                                        if let Some(record_field_list) = x.record_field_list() {
 +                                            record_field_list.fields().for_each(|record_field| {
 +                                                    adt_fields.push(record_field.syntax().clone());
 +                                            });
 +                                        }
 +                                },
 +                                ast::Adt::Enum(_) => {},
 +                            }
 +                        }
 +                    },
 +                    ast::TypeAlias(it) => {
 +                        if let Some( nod ) = ctx.sema.to_def(&it) {
 +                            let node_def = Definition::TypeAlias(nod);
 +                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
 +                        }
 +                    },
 +                    ast::Const(it) => {
 +                        if let Some( nod ) = ctx.sema.to_def(&it) {
 +                            let node_def = Definition::Const(nod);
 +                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
 +                        }
 +                    },
 +                    ast::Static(it) => {
 +                        if let Some( nod ) = ctx.sema.to_def(&it) {
 +                            let node_def = Definition::Static(nod);
 +                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
 +                        }
 +                    },
 +                    ast::Fn(it) => {
 +                        if let Some( nod ) = ctx.sema.to_def(&it) {
 +                            let node_def = Definition::Function(nod);
 +                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
 +                        }
 +                    },
 +                    ast::Macro(it) => {
 +                        if let Some(nod) = ctx.sema.to_def(&it) {
 +                            self.expand_and_group_usages_file_wise(ctx, Definition::Macro(nod), &mut refs);
 +                        }
 +                    },
 +                    _ => (),
 +                }
 +            }
 +        }
 +
 +        (refs, adt_fields)
 +    }
 +
 +    fn expand_and_group_usages_file_wise(
 +        &self,
 +        ctx: &AssistContext<'_>,
 +        node_def: Definition,
 +        refs_in_files: &mut HashMap<FileId, Vec<(TextRange, String)>>,
 +    ) {
 +        for (file_id, references) in node_def.usages(&ctx.sema).all() {
 +            let source_file = ctx.sema.parse(file_id);
 +            let usages_in_file = references
 +                .into_iter()
 +                .filter_map(|usage| self.get_usage_to_be_processed(&source_file, usage));
 +            refs_in_files.entry(file_id).or_default().extend(usages_in_file);
 +        }
 +    }
 +
 +    fn get_usage_to_be_processed(
 +        &self,
 +        source_file: &SourceFile,
 +        FileReference { range, name, .. }: FileReference,
 +    ) -> Option<(TextRange, String)> {
 +        let path: ast::Path = find_node_at_range(source_file.syntax(), range)?;
 +
 +        for desc in path.syntax().descendants() {
 +            if desc.to_string() == name.syntax().to_string()
 +                && !self.text_range.contains_range(desc.text_range())
 +            {
 +                if let Some(name_ref) = ast::NameRef::cast(desc) {
 +                    return Some((
 +                        name_ref.syntax().text_range(),
 +                        format!("{}::{}", self.name, name_ref),
 +                    ));
 +                }
 +            }
 +        }
 +
 +        None
 +    }
 +
 +    fn change_visibility(&mut self, record_fields: Vec<SyntaxNode>) {
 +        let (mut replacements, record_field_parents, impls) =
 +            get_replacements_for_visibilty_change(&mut self.body_items, false);
 +
 +        let mut impl_items: Vec<ast::Item> = impls
 +            .into_iter()
 +            .flat_map(|impl_| impl_.syntax().descendants())
 +            .filter_map(ast::Item::cast)
 +            .collect();
 +
 +        let (mut impl_item_replacements, _, _) =
 +            get_replacements_for_visibilty_change(&mut impl_items, true);
 +
 +        replacements.append(&mut impl_item_replacements);
 +
 +        for (_, field_owner) in record_field_parents {
 +            for desc in field_owner.descendants().filter_map(ast::RecordField::cast) {
 +                let is_record_field_present =
 +                    record_fields.clone().into_iter().any(|x| x.to_string() == desc.to_string());
 +                if is_record_field_present {
 +                    replacements.push((desc.visibility(), desc.syntax().clone()));
 +                }
 +            }
 +        }
 +
 +        for (vis, syntax) in replacements {
 +            let item = syntax.children_with_tokens().find(|node_or_token| {
 +                match node_or_token.kind() {
 +                    // We're skipping comments, doc comments, and attribute macros that may precede the keyword
 +                    // that the visibility should be placed before.
 +                    SyntaxKind::COMMENT | SyntaxKind::ATTR | SyntaxKind::WHITESPACE => false,
 +                    _ => true,
 +                }
 +            });
 +
 +            add_change_vis(vis, item);
 +        }
 +    }
 +
 +    fn resolve_imports(
 +        &mut self,
 +        curr_parent_module: Option<ast::Module>,
 +        ctx: &AssistContext<'_>,
 +    ) -> Vec<TextRange> {
 +        let mut import_paths_to_be_removed: Vec<TextRange> = vec![];
 +        let mut node_set: HashSet<String> = HashSet::new();
 +
 +        for item in self.body_items.clone() {
 +            for x in item.syntax().descendants() {
 +                if let Some(name) = ast::Name::cast(x.clone()) {
 +                    if let Some(name_classify) = NameClass::classify(&ctx.sema, &name) {
 +                        //Necessary to avoid two same names going through
 +                        if !node_set.contains(&name.syntax().to_string()) {
 +                            node_set.insert(name.syntax().to_string());
 +                            let def_opt: Option<Definition> = match name_classify {
 +                                NameClass::Definition(def) => Some(def),
 +                                _ => None,
 +                            };
 +
 +                            if let Some(def) = def_opt {
 +                                if let Some(import_path) = self
 +                                    .process_names_and_namerefs_for_import_resolve(
 +                                        def,
 +                                        name.syntax(),
 +                                        &curr_parent_module,
 +                                        ctx,
 +                                    )
 +                                {
 +                                    check_intersection_and_push(
 +                                        &mut import_paths_to_be_removed,
 +                                        import_path,
 +                                    );
 +                                }
 +                            }
 +                        }
 +                    }
 +                }
 +
 +                if let Some(name_ref) = ast::NameRef::cast(x) {
 +                    if let Some(name_classify) = NameRefClass::classify(&ctx.sema, &name_ref) {
 +                        //Necessary to avoid two same names going through
 +                        if !node_set.contains(&name_ref.syntax().to_string()) {
 +                            node_set.insert(name_ref.syntax().to_string());
 +                            let def_opt: Option<Definition> = match name_classify {
 +                                NameRefClass::Definition(def) => Some(def),
 +                                _ => None,
 +                            };
 +
 +                            if let Some(def) = def_opt {
 +                                if let Some(import_path) = self
 +                                    .process_names_and_namerefs_for_import_resolve(
 +                                        def,
 +                                        name_ref.syntax(),
 +                                        &curr_parent_module,
 +                                        ctx,
 +                                    )
 +                                {
 +                                    check_intersection_and_push(
 +                                        &mut import_paths_to_be_removed,
 +                                        import_path,
 +                                    );
 +                                }
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +
 +        import_paths_to_be_removed
 +    }
 +
 +    fn process_names_and_namerefs_for_import_resolve(
 +        &mut self,
 +        def: Definition,
 +        node_syntax: &SyntaxNode,
 +        curr_parent_module: &Option<ast::Module>,
 +        ctx: &AssistContext<'_>,
 +    ) -> Option<TextRange> {
 +        //We only need to find in the current file
 +        let selection_range = ctx.selection_trimmed();
 +        let curr_file_id = ctx.file_id();
 +        let search_scope = SearchScope::single_file(curr_file_id);
 +        let usage_res = def.usages(&ctx.sema).in_scope(search_scope).all();
 +        let file = ctx.sema.parse(curr_file_id);
 +
 +        let mut exists_inside_sel = false;
 +        let mut exists_outside_sel = false;
 +        for (_, refs) in usage_res.iter() {
 +            let mut non_use_nodes_itr = refs.iter().filter_map(|x| {
 +                if find_node_at_range::<ast::Use>(file.syntax(), x.range).is_none() {
 +                    let path_opt = find_node_at_range::<ast::Path>(file.syntax(), x.range);
 +                    return path_opt;
 +                }
 +
 +                None
 +            });
 +
 +            if non_use_nodes_itr
 +                .clone()
 +                .any(|x| !selection_range.contains_range(x.syntax().text_range()))
 +            {
 +                exists_outside_sel = true;
 +            }
 +            if non_use_nodes_itr.any(|x| selection_range.contains_range(x.syntax().text_range())) {
 +                exists_inside_sel = true;
 +            }
 +        }
 +
 +        let source_exists_outside_sel_in_same_mod = does_source_exists_outside_sel_in_same_mod(
 +            def,
 +            ctx,
 +            curr_parent_module,
 +            selection_range,
 +            curr_file_id,
 +        );
 +
 +        let use_stmt_opt: Option<ast::Use> = usage_res.into_iter().find_map(|(file_id, refs)| {
 +            if file_id == curr_file_id {
 +                refs.into_iter()
 +                    .rev()
 +                    .find_map(|fref| find_node_at_range(file.syntax(), fref.range))
 +            } else {
 +                None
 +            }
 +        });
 +
 +        let mut use_tree_str_opt: Option<Vec<ast::Path>> = None;
 +        //Exists inside and outside selection
 +        // - Use stmt for item is present -> get the use_tree_str and reconstruct the path in new
 +        // module
 +        // - Use stmt for item is not present ->
 +        //If it is not found, the definition is either ported inside new module or it stays
 +        //outside:
 +        //- Def is inside: Nothing to import
 +        //- Def is outside: Import it inside with super
 +
 +        //Exists inside selection but not outside -> Check for the import of it in original module,
 +        //get the use_tree_str, reconstruct the use stmt in new module
 +
 +        let mut import_path_to_be_removed: Option<TextRange> = None;
 +        if exists_inside_sel && exists_outside_sel {
 +            //Changes to be made only inside new module
 +
 +            //If use_stmt exists, find the use_tree_str, reconstruct it inside new module
 +            //If not, insert a use stmt with super and the given nameref
 +            if let Some((use_tree_str, _)) =
 +                self.process_use_stmt_for_import_resolve(use_stmt_opt, node_syntax)
 +            {
 +                use_tree_str_opt = Some(use_tree_str);
 +            } else if source_exists_outside_sel_in_same_mod {
 +                //Considered only after use_stmt is not present
 +                //source_exists_outside_sel_in_same_mod | exists_outside_sel(exists_inside_sel =
 +                //true for all cases)
 +                // false | false -> Do nothing
 +                // false | true -> If source is in selection -> nothing to do, If source is outside
 +                // mod -> ust_stmt transversal
 +                // true  | false -> super import insertion
 +                // true  | true -> super import insertion
 +                self.make_use_stmt_of_node_with_super(node_syntax);
 +            }
 +        } else if exists_inside_sel && !exists_outside_sel {
 +            //Changes to be made inside new module, and remove import from outside
 +
 +            if let Some((mut use_tree_str, text_range_opt)) =
 +                self.process_use_stmt_for_import_resolve(use_stmt_opt, node_syntax)
 +            {
 +                if let Some(text_range) = text_range_opt {
 +                    import_path_to_be_removed = Some(text_range);
 +                }
 +
 +                if source_exists_outside_sel_in_same_mod {
 +                    if let Some(first_path_in_use_tree) = use_tree_str.last() {
 +                        let first_path_in_use_tree_str = first_path_in_use_tree.to_string();
 +                        if !first_path_in_use_tree_str.contains("super")
 +                            && !first_path_in_use_tree_str.contains("crate")
 +                        {
 +                            let super_path = make::ext::ident_path("super");
 +                            use_tree_str.push(super_path);
 +                        }
 +                    }
 +                }
 +
 +                use_tree_str_opt = Some(use_tree_str);
 +            } else if source_exists_outside_sel_in_same_mod {
 +                self.make_use_stmt_of_node_with_super(node_syntax);
 +            }
 +        }
 +
 +        if let Some(use_tree_str) = use_tree_str_opt {
 +            let mut use_tree_str = use_tree_str;
 +            use_tree_str.reverse();
 +
 +            if !(!exists_outside_sel && exists_inside_sel && source_exists_outside_sel_in_same_mod)
 +            {
 +                if let Some(first_path_in_use_tree) = use_tree_str.first() {
 +                    let first_path_in_use_tree_str = first_path_in_use_tree.to_string();
 +                    if first_path_in_use_tree_str.contains("super") {
 +                        let super_path = make::ext::ident_path("super");
 +                        use_tree_str.insert(0, super_path)
 +                    }
 +                }
 +            }
 +
 +            let use_ =
 +                make::use_(None, make::use_tree(make::join_paths(use_tree_str), None, None, false));
 +            let item = ast::Item::from(use_);
 +            self.use_items.insert(0, item);
 +        }
 +
 +        import_path_to_be_removed
 +    }
 +
 +    fn make_use_stmt_of_node_with_super(&mut self, node_syntax: &SyntaxNode) -> ast::Item {
 +        let super_path = make::ext::ident_path("super");
 +        let node_path = make::ext::ident_path(&node_syntax.to_string());
 +        let use_ = make::use_(
 +            None,
 +            make::use_tree(make::join_paths(vec![super_path, node_path]), None, None, false),
 +        );
 +
 +        let item = ast::Item::from(use_);
 +        self.use_items.insert(0, item.clone());
 +        item
 +    }
 +
 +    fn process_use_stmt_for_import_resolve(
 +        &self,
 +        use_stmt_opt: Option<ast::Use>,
 +        node_syntax: &SyntaxNode,
 +    ) -> Option<(Vec<ast::Path>, Option<TextRange>)> {
 +        if let Some(use_stmt) = use_stmt_opt {
 +            for desc in use_stmt.syntax().descendants() {
 +                if let Some(path_seg) = ast::PathSegment::cast(desc) {
 +                    if path_seg.syntax().to_string() == node_syntax.to_string() {
 +                        let mut use_tree_str = vec![path_seg.parent_path()];
 +                        get_use_tree_paths_from_path(path_seg.parent_path(), &mut use_tree_str);
 +                        for ancs in path_seg.syntax().ancestors() {
 +                            //Here we are looking for use_tree with same string value as node
 +                            //passed above as the range_to_remove function looks for a comma and
 +                            //then includes it in the text range to remove it. But the comma only
 +                            //appears at the use_tree level
 +                            if let Some(use_tree) = ast::UseTree::cast(ancs) {
 +                                if use_tree.syntax().to_string() == node_syntax.to_string() {
 +                                    return Some((
 +                                        use_tree_str,
 +                                        Some(range_to_remove(use_tree.syntax())),
 +                                    ));
 +                                }
 +                            }
 +                        }
 +
 +                        return Some((use_tree_str, None));
 +                    }
 +                }
 +            }
 +        }
 +
 +        None
 +    }
 +}
 +
 +fn check_intersection_and_push(
 +    import_paths_to_be_removed: &mut Vec<TextRange>,
 +    import_path: TextRange,
 +) {
 +    if import_paths_to_be_removed.len() > 0 {
++        // Text ranges received here for imports are extended to the
 +        // next/previous comma which can cause intersections among them
 +        // and later deletion of these can cause panics similar
 +        // to reported in #11766. So to mitigate it, we
 +        // check for intersection between all current members
 +        // and if it exists we combine both text ranges into
 +        // one
 +        let r = import_paths_to_be_removed
 +            .into_iter()
 +            .position(|it| it.intersect(import_path).is_some());
 +        match r {
 +            Some(it) => {
 +                import_paths_to_be_removed[it] = import_paths_to_be_removed[it].cover(import_path)
 +            }
 +            None => import_paths_to_be_removed.push(import_path),
 +        }
 +    } else {
 +        import_paths_to_be_removed.push(import_path);
 +    }
 +}
 +
 +fn does_source_exists_outside_sel_in_same_mod(
 +    def: Definition,
 +    ctx: &AssistContext<'_>,
 +    curr_parent_module: &Option<ast::Module>,
 +    selection_range: TextRange,
 +    curr_file_id: FileId,
 +) -> bool {
 +    let mut source_exists_outside_sel_in_same_mod = false;
 +    match def {
 +        Definition::Module(x) => {
 +            let source = x.definition_source(ctx.db());
 +            let have_same_parent;
 +            if let Some(ast_module) = &curr_parent_module {
 +                if let Some(hir_module) = x.parent(ctx.db()) {
 +                    have_same_parent =
 +                        compare_hir_and_ast_module(ast_module, hir_module, ctx).is_some();
 +                } else {
 +                    let source_file_id = source.file_id.original_file(ctx.db());
 +                    have_same_parent = source_file_id == curr_file_id;
 +                }
 +            } else {
 +                let source_file_id = source.file_id.original_file(ctx.db());
 +                have_same_parent = source_file_id == curr_file_id;
 +            }
 +
 +            if have_same_parent {
 +                match source.value {
 +                    ModuleSource::Module(module_) => {
 +                        source_exists_outside_sel_in_same_mod =
 +                            !selection_range.contains_range(module_.syntax().text_range());
 +                    }
 +                    _ => {}
 +                }
 +            }
 +        }
 +        Definition::Function(x) => {
 +            if let Some(source) = x.source(ctx.db()) {
 +                let have_same_parent = if let Some(ast_module) = &curr_parent_module {
 +                    compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
 +                } else {
 +                    let source_file_id = source.file_id.original_file(ctx.db());
 +                    source_file_id == curr_file_id
 +                };
 +
 +                if have_same_parent {
 +                    source_exists_outside_sel_in_same_mod =
 +                        !selection_range.contains_range(source.value.syntax().text_range());
 +                }
 +            }
 +        }
 +        Definition::Adt(x) => {
 +            if let Some(source) = x.source(ctx.db()) {
 +                let have_same_parent = if let Some(ast_module) = &curr_parent_module {
 +                    compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
 +                } else {
 +                    let source_file_id = source.file_id.original_file(ctx.db());
 +                    source_file_id == curr_file_id
 +                };
 +
 +                if have_same_parent {
 +                    source_exists_outside_sel_in_same_mod =
 +                        !selection_range.contains_range(source.value.syntax().text_range());
 +                }
 +            }
 +        }
 +        Definition::Variant(x) => {
 +            if let Some(source) = x.source(ctx.db()) {
 +                let have_same_parent = if let Some(ast_module) = &curr_parent_module {
 +                    compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
 +                } else {
 +                    let source_file_id = source.file_id.original_file(ctx.db());
 +                    source_file_id == curr_file_id
 +                };
 +
 +                if have_same_parent {
 +                    source_exists_outside_sel_in_same_mod =
 +                        !selection_range.contains_range(source.value.syntax().text_range());
 +                }
 +            }
 +        }
 +        Definition::Const(x) => {
 +            if let Some(source) = x.source(ctx.db()) {
 +                let have_same_parent = if let Some(ast_module) = &curr_parent_module {
 +                    compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
 +                } else {
 +                    let source_file_id = source.file_id.original_file(ctx.db());
 +                    source_file_id == curr_file_id
 +                };
 +
 +                if have_same_parent {
 +                    source_exists_outside_sel_in_same_mod =
 +                        !selection_range.contains_range(source.value.syntax().text_range());
 +                }
 +            }
 +        }
 +        Definition::Static(x) => {
 +            if let Some(source) = x.source(ctx.db()) {
 +                let have_same_parent = if let Some(ast_module) = &curr_parent_module {
 +                    compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
 +                } else {
 +                    let source_file_id = source.file_id.original_file(ctx.db());
 +                    source_file_id == curr_file_id
 +                };
 +
 +                if have_same_parent {
 +                    source_exists_outside_sel_in_same_mod =
 +                        !selection_range.contains_range(source.value.syntax().text_range());
 +                }
 +            }
 +        }
 +        Definition::Trait(x) => {
 +            if let Some(source) = x.source(ctx.db()) {
 +                let have_same_parent = if let Some(ast_module) = &curr_parent_module {
 +                    compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
 +                } else {
 +                    let source_file_id = source.file_id.original_file(ctx.db());
 +                    source_file_id == curr_file_id
 +                };
 +
 +                if have_same_parent {
 +                    source_exists_outside_sel_in_same_mod =
 +                        !selection_range.contains_range(source.value.syntax().text_range());
 +                }
 +            }
 +        }
 +        Definition::TypeAlias(x) => {
 +            if let Some(source) = x.source(ctx.db()) {
 +                let have_same_parent = if let Some(ast_module) = &curr_parent_module {
 +                    compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
 +                } else {
 +                    let source_file_id = source.file_id.original_file(ctx.db());
 +                    source_file_id == curr_file_id
 +                };
 +
 +                if have_same_parent {
 +                    source_exists_outside_sel_in_same_mod =
 +                        !selection_range.contains_range(source.value.syntax().text_range());
 +                }
 +            }
 +        }
 +        _ => {}
 +    }
 +
 +    source_exists_outside_sel_in_same_mod
 +}
 +
 +fn get_replacements_for_visibilty_change(
 +    items: &mut [ast::Item],
 +    is_clone_for_updated: bool,
 +) -> (
 +    Vec<(Option<ast::Visibility>, SyntaxNode)>,
 +    Vec<(Option<ast::Visibility>, SyntaxNode)>,
 +    Vec<ast::Impl>,
 +) {
 +    let mut replacements = Vec::new();
 +    let mut record_field_parents = Vec::new();
 +    let mut impls = Vec::new();
 +
 +    for item in items {
 +        if !is_clone_for_updated {
 +            *item = item.clone_for_update();
 +        }
 +        //Use stmts are ignored
 +        match item {
 +            ast::Item::Const(it) => replacements.push((it.visibility(), it.syntax().clone())),
 +            ast::Item::Enum(it) => replacements.push((it.visibility(), it.syntax().clone())),
 +            ast::Item::ExternCrate(it) => replacements.push((it.visibility(), it.syntax().clone())),
 +            ast::Item::Fn(it) => replacements.push((it.visibility(), it.syntax().clone())),
 +            //Associated item's visibility should not be changed
 +            ast::Item::Impl(it) if it.for_token().is_none() => impls.push(it.clone()),
 +            ast::Item::MacroDef(it) => replacements.push((it.visibility(), it.syntax().clone())),
 +            ast::Item::Module(it) => replacements.push((it.visibility(), it.syntax().clone())),
 +            ast::Item::Static(it) => replacements.push((it.visibility(), it.syntax().clone())),
 +            ast::Item::Struct(it) => {
 +                replacements.push((it.visibility(), it.syntax().clone()));
 +                record_field_parents.push((it.visibility(), it.syntax().clone()));
 +            }
 +            ast::Item::Trait(it) => replacements.push((it.visibility(), it.syntax().clone())),
 +            ast::Item::TypeAlias(it) => replacements.push((it.visibility(), it.syntax().clone())),
 +            ast::Item::Union(it) => {
 +                replacements.push((it.visibility(), it.syntax().clone()));
 +                record_field_parents.push((it.visibility(), it.syntax().clone()));
 +            }
 +            _ => (),
 +        }
 +    }
 +
 +    (replacements, record_field_parents, impls)
 +}
 +
 +fn get_use_tree_paths_from_path(
 +    path: ast::Path,
 +    use_tree_str: &mut Vec<ast::Path>,
 +) -> Option<&mut Vec<ast::Path>> {
 +    path.syntax().ancestors().filter(|x| x.to_string() != path.to_string()).find_map(|x| {
 +        if let Some(use_tree) = ast::UseTree::cast(x) {
 +            if let Some(upper_tree_path) = use_tree.path() {
 +                if upper_tree_path.to_string() != path.to_string() {
 +                    use_tree_str.push(upper_tree_path.clone());
 +                    get_use_tree_paths_from_path(upper_tree_path, use_tree_str);
 +                    return Some(use_tree);
 +                }
 +            }
 +        }
 +        None
 +    })?;
 +
 +    Some(use_tree_str)
 +}
 +
 +fn add_change_vis(vis: Option<ast::Visibility>, node_or_token_opt: Option<syntax::SyntaxElement>) {
 +    if vis.is_none() {
 +        if let Some(node_or_token) = node_or_token_opt {
 +            let pub_crate_vis = make::visibility_pub_crate().clone_for_update();
 +            ted::insert(ted::Position::before(node_or_token), pub_crate_vis.syntax());
 +        }
 +    }
 +}
 +
 +fn compare_hir_and_ast_module(
 +    ast_module: &ast::Module,
 +    hir_module: hir::Module,
 +    ctx: &AssistContext<'_>,
 +) -> Option<()> {
 +    let hir_mod_name = hir_module.name(ctx.db())?;
 +    let ast_mod_name = ast_module.name()?;
 +    if hir_mod_name.to_string() != ast_mod_name.to_string() {
 +        return None;
 +    }
 +
 +    Some(())
 +}
 +
 +fn indent_range_before_given_node(node: &SyntaxNode) -> Option<TextRange> {
 +    node.siblings_with_tokens(syntax::Direction::Prev)
 +        .find(|x| x.kind() == WHITESPACE)
 +        .map(|x| x.text_range())
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_not_applicable_without_selection() {
 +        check_assist_not_applicable(
 +            extract_module,
 +            r"
 +$0pub struct PublicStruct {
 +    field: i32,
 +}
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_extract_module() {
 +        check_assist(
 +            extract_module,
 +            r"
 +            mod thirdpartycrate {
 +                pub mod nest {
 +                    pub struct SomeType;
 +                    pub struct SomeType2;
 +                }
 +                pub struct SomeType1;
 +            }
 +
 +            mod bar {
 +                use crate::thirdpartycrate::{nest::{SomeType, SomeType2}, SomeType1};
 +
 +                pub struct PublicStruct {
 +                    field: PrivateStruct,
 +                    field1: SomeType1,
 +                }
 +
 +                impl PublicStruct {
 +                    pub fn new() -> Self {
 +                        Self { field: PrivateStruct::new(), field1: SomeType1 }
 +                    }
 +                }
 +
 +                fn foo() {
 +                    let _s = PrivateStruct::new();
 +                    let _a = bar();
 +                }
 +
 +$0struct PrivateStruct {
 +    inner: SomeType,
 +}
 +
 +pub struct PrivateStruct1 {
 +    pub inner: i32,
 +}
 +
 +impl PrivateStruct {
 +    fn new() -> Self {
 +         PrivateStruct { inner: SomeType }
 +    }
 +}
 +
 +fn bar() -> i32 {
 +    2
 +}$0
 +            }
 +            ",
 +            r"
 +            mod thirdpartycrate {
 +                pub mod nest {
 +                    pub struct SomeType;
 +                    pub struct SomeType2;
 +                }
 +                pub struct SomeType1;
 +            }
 +
 +            mod bar {
 +                use crate::thirdpartycrate::{nest::{SomeType2}, SomeType1};
 +
 +                pub struct PublicStruct {
 +                    field: modname::PrivateStruct,
 +                    field1: SomeType1,
 +                }
 +
 +                impl PublicStruct {
 +                    pub fn new() -> Self {
 +                        Self { field: modname::PrivateStruct::new(), field1: SomeType1 }
 +                    }
 +                }
 +
 +                fn foo() {
 +                    let _s = modname::PrivateStruct::new();
 +                    let _a = modname::bar();
 +                }
 +
 +mod modname {
 +    use crate::thirdpartycrate::nest::SomeType;
 +
 +    pub(crate) struct PrivateStruct {
 +        pub(crate) inner: SomeType,
 +    }
 +
 +    pub struct PrivateStruct1 {
 +        pub inner: i32,
 +    }
 +
 +    impl PrivateStruct {
 +        pub(crate) fn new() -> Self {
 +             PrivateStruct { inner: SomeType }
 +        }
 +    }
 +
 +    pub(crate) fn bar() -> i32 {
 +        2
 +    }
 +}
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_module_for_function_only() {
 +        check_assist(
 +            extract_module,
 +            r"
 +$0fn foo(name: i32) -> i32 {
 +    name + 1
 +}$0
 +
 +                fn bar(name: i32) -> i32 {
 +                    name + 2
 +                }
 +            ",
 +            r"
 +mod modname {
 +    pub(crate) fn foo(name: i32) -> i32 {
 +        name + 1
 +    }
 +}
 +
 +                fn bar(name: i32) -> i32 {
 +                    name + 2
 +                }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_extract_module_for_impl_having_corresponding_adt_in_selection() {
 +        check_assist(
 +            extract_module,
 +            r"
 +            mod impl_play {
 +$0struct A {}
 +
 +impl A {
 +    pub fn new_a() -> i32 {
 +        2
 +    }
 +}$0
 +
 +                fn a() {
 +                    let _a = A::new_a();
 +                }
 +            }
 +            ",
 +            r"
 +            mod impl_play {
 +mod modname {
 +    pub(crate) struct A {}
 +
 +    impl A {
 +        pub fn new_a() -> i32 {
 +            2
 +        }
 +    }
 +}
 +
 +                fn a() {
 +                    let _a = modname::A::new_a();
 +                }
 +            }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_import_resolve_when_its_only_inside_selection() {
 +        check_assist(
 +            extract_module,
 +            r"
 +            mod foo {
 +                pub struct PrivateStruct;
 +                pub struct PrivateStruct1;
 +            }
 +
 +            mod bar {
 +                use super::foo::{PrivateStruct, PrivateStruct1};
 +
 +$0struct Strukt {
 +    field: PrivateStruct,
 +}$0
 +
 +                struct Strukt1 {
 +                    field: PrivateStruct1,
 +                }
 +            }
 +            ",
 +            r"
 +            mod foo {
 +                pub struct PrivateStruct;
 +                pub struct PrivateStruct1;
 +            }
 +
 +            mod bar {
 +                use super::foo::{PrivateStruct1};
 +
 +mod modname {
 +    use super::super::foo::PrivateStruct;
 +
 +    pub(crate) struct Strukt {
 +        pub(crate) field: PrivateStruct,
 +    }
 +}
 +
 +                struct Strukt1 {
 +                    field: PrivateStruct1,
 +                }
 +            }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_import_resolve_when_its_inside_and_outside_selection_and_source_not_in_same_mod() {
 +        check_assist(
 +            extract_module,
 +            r"
 +            mod foo {
 +                pub struct PrivateStruct;
 +            }
 +
 +            mod bar {
 +                use super::foo::PrivateStruct;
 +
 +$0struct Strukt {
 +    field: PrivateStruct,
 +}$0
 +
 +                struct Strukt1 {
 +                    field: PrivateStruct,
 +                }
 +            }
 +            ",
 +            r"
 +            mod foo {
 +                pub struct PrivateStruct;
 +            }
 +
 +            mod bar {
 +                use super::foo::PrivateStruct;
 +
 +mod modname {
 +    use super::super::foo::PrivateStruct;
 +
 +    pub(crate) struct Strukt {
 +        pub(crate) field: PrivateStruct,
 +    }
 +}
 +
 +                struct Strukt1 {
 +                    field: PrivateStruct,
 +                }
 +            }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_import_resolve_when_its_inside_and_outside_selection_and_source_is_in_same_mod() {
 +        check_assist(
 +            extract_module,
 +            r"
 +            mod bar {
 +                pub struct PrivateStruct;
 +
 +$0struct Strukt {
 +   field: PrivateStruct,
 +}$0
 +
 +                struct Strukt1 {
 +                    field: PrivateStruct,
 +                }
 +            }
 +            ",
 +            r"
 +            mod bar {
 +                pub struct PrivateStruct;
 +
 +mod modname {
 +    use super::PrivateStruct;
 +
 +    pub(crate) struct Strukt {
 +       pub(crate) field: PrivateStruct,
 +    }
 +}
 +
 +                struct Strukt1 {
 +                    field: PrivateStruct,
 +                }
 +            }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_extract_module_for_correspoding_adt_of_impl_present_in_same_mod_but_not_in_selection() {
 +        check_assist(
 +            extract_module,
 +            r"
 +            mod impl_play {
 +                struct A {}
 +
 +$0impl A {
 +    pub fn new_a() -> i32 {
 +        2
 +    }
 +}$0
 +
 +                fn a() {
 +                    let _a = A::new_a();
 +                }
 +            }
 +            ",
 +            r"
 +            mod impl_play {
 +                struct A {}
 +
 +mod modname {
 +    use super::A;
 +
 +    impl A {
 +        pub fn new_a() -> i32 {
 +            2
 +        }
 +    }
 +}
 +
 +                fn a() {
 +                    let _a = A::new_a();
 +                }
 +            }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_extract_module_for_impl_not_having_corresponding_adt_in_selection_and_not_in_same_mod_but_with_super(
 +    ) {
 +        check_assist(
 +            extract_module,
 +            r"
 +            mod foo {
 +                pub struct A {}
 +            }
 +            mod impl_play {
 +                use super::foo::A;
 +
 +$0impl A {
 +    pub fn new_a() -> i32 {
 +        2
 +    }
 +}$0
 +
 +                fn a() {
 +                    let _a = A::new_a();
 +                }
 +            }
 +            ",
 +            r"
 +            mod foo {
 +                pub struct A {}
 +            }
 +            mod impl_play {
 +                use super::foo::A;
 +
 +mod modname {
 +    use super::super::foo::A;
 +
 +    impl A {
 +        pub fn new_a() -> i32 {
 +            2
 +        }
 +    }
 +}
 +
 +                fn a() {
 +                    let _a = A::new_a();
 +                }
 +            }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_import_resolve_for_trait_bounds_on_function() {
 +        check_assist(
 +            extract_module,
 +            r"
 +            mod impl_play2 {
 +                trait JustATrait {}
 +
 +$0struct A {}
 +
 +fn foo<T: JustATrait>(arg: T) -> T {
 +    arg
 +}
 +
 +impl JustATrait for A {}
 +
 +fn bar() {
 +    let a = A {};
 +    foo(a);
 +}$0
 +            }
 +            ",
 +            r"
 +            mod impl_play2 {
 +                trait JustATrait {}
 +
 +mod modname {
 +    use super::JustATrait;
 +
 +    pub(crate) struct A {}
 +
 +    pub(crate) fn foo<T: JustATrait>(arg: T) -> T {
 +        arg
 +    }
 +
 +    impl JustATrait for A {}
 +
 +    pub(crate) fn bar() {
 +        let a = A {};
 +        foo(a);
 +    }
 +}
 +            }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_extract_module_for_module() {
 +        check_assist(
 +            extract_module,
 +            r"
 +            mod impl_play2 {
 +$0mod impl_play {
 +    pub struct A {}
 +}$0
 +            }
 +            ",
 +            r"
 +            mod impl_play2 {
 +mod modname {
 +    pub(crate) mod impl_play {
 +        pub struct A {}
 +    }
 +}
 +            }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_extract_module_with_multiple_files() {
 +        check_assist(
 +            extract_module,
 +            r"
 +            //- /main.rs
 +            mod foo;
 +
 +            use foo::PrivateStruct;
 +
 +            pub struct Strukt {
 +                field: PrivateStruct,
 +            }
 +
 +            fn main() {
 +                $0struct Strukt1 {
 +                    field: Strukt,
 +                }$0
 +            }
 +            //- /foo.rs
 +            pub struct PrivateStruct;
 +            ",
 +            r"
 +            mod foo;
 +
 +            use foo::PrivateStruct;
 +
 +            pub struct Strukt {
 +                field: PrivateStruct,
 +            }
 +
 +            fn main() {
 +                mod modname {
 +                    use super::Strukt;
 +
 +                    pub(crate) struct Strukt1 {
 +                        pub(crate) field: Strukt,
 +                    }
 +                }
 +            }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_extract_module_macro_rules() {
 +        check_assist(
 +            extract_module,
 +            r"
 +$0macro_rules! m {
 +    () => {};
 +}$0
 +m! {}
 +            ",
 +            r"
 +mod modname {
 +    macro_rules! m {
 +        () => {};
 +    }
 +}
 +modname::m! {}
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn test_do_not_apply_visibility_modifier_to_trait_impl_items() {
 +        check_assist(
 +            extract_module,
 +            r"
 +            trait ATrait {
 +                fn function();
 +            }
 +
 +            struct A {}
 +
 +$0impl ATrait for A {
 +    fn function() {}
 +}$0
 +            ",
 +            r"
 +            trait ATrait {
 +                fn function();
 +            }
 +
 +            struct A {}
 +
 +mod modname {
 +    use super::A;
 +
 +    use super::ATrait;
 +
 +    impl ATrait for A {
 +        fn function() {}
 +    }
 +}
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_if_inside_impl_block_generate_module_outside() {
 +        check_assist(
 +            extract_module,
 +            r"
 +            struct A {}
 +
 +            impl A {
 +$0fn foo() {}$0
 +                fn bar() {}
 +            }
 +        ",
 +            r"
 +            struct A {}
 +
 +            impl A {
 +                fn bar() {}
 +            }
 +
 +mod modname {
 +    use super::A;
 +
 +    impl A {
 +        pub(crate) fn foo() {}
 +    }
 +}
 +        ",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_if_inside_impl_block_generate_module_outside_but_impl_block_having_one_child() {
 +        check_assist(
 +            extract_module,
 +            r"
 +            struct A {}
 +            struct B {}
 +
 +            impl A {
 +$0fn foo(x: B) {}$0
 +            }
 +        ",
 +            r"
 +            struct A {}
 +            struct B {}
 +
 +mod modname {
 +    use super::B;
 +
 +    use super::A;
 +
 +    impl A {
 +        pub(crate) fn foo(x: B) {}
 +    }
 +}
 +        ",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_issue_11766() {
 +        //https://github.com/rust-lang/rust-analyzer/issues/11766
 +        check_assist(
 +            extract_module,
 +            r"
 +            mod x {
 +                pub struct Foo;
 +                pub struct Bar;
 +            }
 +
 +            use x::{Bar, Foo};
 +
 +            $0type A = (Foo, Bar);$0
 +        ",
 +            r"
 +            mod x {
 +                pub struct Foo;
 +                pub struct Bar;
 +            }
 +
 +            use x::{};
 +
 +            mod modname {
 +                use super::x::Bar;
 +
 +                use super::x::Foo;
 +
 +                pub(crate) type A = (Foo, Bar);
 +            }
 +        ",
 +        )
 +    }
 +
 +    #[test]
 +    fn test_issue_12790() {
 +        check_assist(
 +            extract_module,
 +            r"
 +            $0/// A documented function
 +            fn documented_fn() {}
 +
 +            // A commented function with a #[] attribute macro
 +            #[cfg(test)]
 +            fn attribute_fn() {}
 +
 +            // A normally commented function
 +            fn normal_fn() {}
 +
 +            /// A documented Struct
 +            struct DocumentedStruct {
 +                // Normal field
 +                x: i32,
 +
 +                /// Documented field
 +                y: i32,
 +
 +                // Macroed field
 +                #[cfg(test)]
 +                z: i32,
 +            }
 +
 +            // A macroed Struct
 +            #[cfg(test)]
 +            struct MacroedStruct {
 +                // Normal field
 +                x: i32,
 +
 +                /// Documented field
 +                y: i32,
 +
 +                // Macroed field
 +                #[cfg(test)]
 +                z: i32,
 +            }
 +
 +            // A normal Struct
 +            struct NormalStruct {
 +                // Normal field
 +                x: i32,
 +
 +                /// Documented field
 +                y: i32,
 +
 +                // Macroed field
 +                #[cfg(test)]
 +                z: i32,
 +            }
 +
 +            /// A documented type
 +            type DocumentedType = i32;
 +
 +            // A macroed type
 +            #[cfg(test)]
 +            type MacroedType = i32;
 +
 +            /// A module to move
 +            mod module {}
 +
 +            /// An impl to move
 +            impl NormalStruct {
 +                /// A method
 +                fn new() {}
 +            }
 +
 +            /// A documented trait
 +            trait DocTrait {
 +                /// Inner function
 +                fn doc() {}
 +            }
 +
 +            /// An enum
 +            enum DocumentedEnum {
 +                /// A variant
 +                A,
 +                /// Another variant
 +                B { x: i32, y: i32 }
 +            }
 +
 +            /// Documented const
 +            const MY_CONST: i32 = 0;$0
 +        ",
 +            r"
 +            mod modname {
 +                /// A documented function
 +                pub(crate) fn documented_fn() {}
 +
 +                // A commented function with a #[] attribute macro
 +                #[cfg(test)]
 +                pub(crate) fn attribute_fn() {}
 +
 +                // A normally commented function
 +                pub(crate) fn normal_fn() {}
 +
 +                /// A documented Struct
 +                pub(crate) struct DocumentedStruct {
 +                    // Normal field
 +                    pub(crate) x: i32,
 +
 +                    /// Documented field
 +                    pub(crate) y: i32,
 +
 +                    // Macroed field
 +                    #[cfg(test)]
 +                    pub(crate) z: i32,
 +                }
 +
 +                // A macroed Struct
 +                #[cfg(test)]
 +                pub(crate) struct MacroedStruct {
 +                    // Normal field
 +                    pub(crate) x: i32,
 +
 +                    /// Documented field
 +                    pub(crate) y: i32,
 +
 +                    // Macroed field
 +                    #[cfg(test)]
 +                    pub(crate) z: i32,
 +                }
 +
 +                // A normal Struct
 +                pub(crate) struct NormalStruct {
 +                    // Normal field
 +                    pub(crate) x: i32,
 +
 +                    /// Documented field
 +                    pub(crate) y: i32,
 +
 +                    // Macroed field
 +                    #[cfg(test)]
 +                    pub(crate) z: i32,
 +                }
 +
 +                /// A documented type
 +                pub(crate) type DocumentedType = i32;
 +
 +                // A macroed type
 +                #[cfg(test)]
 +                pub(crate) type MacroedType = i32;
 +
 +                /// A module to move
 +                pub(crate) mod module {}
 +
 +                /// An impl to move
 +                impl NormalStruct {
 +                    /// A method
 +                    pub(crate) fn new() {}
 +                }
 +
 +                /// A documented trait
 +                pub(crate) trait DocTrait {
 +                    /// Inner function
 +                    fn doc() {}
 +                }
 +
 +                /// An enum
 +                pub(crate) enum DocumentedEnum {
 +                    /// A variant
 +                    A,
 +                    /// Another variant
 +                    B { x: i32, y: i32 }
 +                }
 +
 +                /// Documented const
 +                pub(crate) const MY_CONST: i32 = 0;
 +            }
 +        ",
 +        )
 +    }
 +}
index d564a0540898e77ac694f3dd0bc9d4ff61c003e3,0000000000000000000000000000000000000000..e26c76da1891649c0a035706e5eb278aa325b99e
mode 100644,000000..100644
--- /dev/null
@@@ -1,1787 -1,0 +1,1857 @@@
-     let target_module;
-     let mut adt_name = None;
 +use hir::{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 (target, file, insert_offset) = match path.qualifier() {
++    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,
++}
 +
-                 target_module = Some(module);
-                 get_fn_target(ctx, &target_module, call.clone())?
++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))) => {
-                     if name_ref.text().starts_with(char::is_uppercase) {
++                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
-                 let current_module = ctx.sema.scope(call.syntax())?.module();
-                 let module = adt.module(ctx.sema.db);
-                 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, &module, &impl_)?;
-                 adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
-                 (target, file, insert_offset)
++                    if fn_name.starts_with(char::is_uppercase) {
 +                        return None;
 +                    }
 +                }
 +
-             _ => {
-                 return None;
++                assoc_fn_target_info(ctx, call, adt, fn_name)
 +            }
-         _ => {
-             target_module = None;
-             get_fn_target(ctx, &target_module, call.clone())?
-         }
-     };
-     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,
-     )
++            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, &target_module, &impl_)?;
 +    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 function_template = function_builder.render();
 +        let mut func = function_template.to_string(ctx.config.snippet_cap);
 +        if let Some(name) = adt_name {
 +            func = format!("\nimpl {} {{\n{}\n}}", name, func);
 +        }
 +        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())?;
 +    find_struct_impl(ctx, &adt_source, fn_name).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 f = match cap {
 +            Some(cap) => {
 +                let cursor = if self.should_focus_return_type {
 +                    // Focus the return type if there is one
 +                    match self.ret_type {
 +                        Some(ref ret_type) => ret_type.syntax(),
 +                        None => self.tail_expr.syntax(),
 +                    }
 +                } else {
 +                    self.tail_expr.syntax()
 +                };
 +                render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(cursor))
 +            }
 +            None => self.fn_def.to_string(),
 +        };
 +
 +        format!("{}{}{}", self.leading_ws, f, self.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) -> 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 indent = IndentLevel::from_node(&it);
 +                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);
 +                leading_ws = format!("\n{}", indent + 1);
 +                fn_def = fn_def.indent(indent + 1);
 +                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<'_>,
 +    target_module: &Module,
 +    impl_: &Option<ast::Impl>,
 +) -> Option<(GeneratedFunctionTarget, TextSize)> {
 +    let target = match impl_ {
 +        Some(impl_) => next_space_for_fn_in_impl(impl_)?,
 +        None => {
 +            next_space_for_fn_in_module(ctx.sema.db, &target_module.definition_source(ctx.sema.db))?
 +                .1
 +        }
 +    };
 +    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, &module, &impl_)?;
++    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;
 +fn foo() {S.bar();}
 +impl S {
 +
 +
 +fn bar(&self) ${0:-> _} {
 +    todo!()
 +}
 +}
 +",
 +        )
 +    }
 +
 +    #[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;
 +mod s {
 +    fn foo() {
 +        super::S.bar();
 +    }
 +}
 +impl S {
 +
 +
 +fn bar(&self) ${0:-> _} {
 +    todo!()
 +}
 +}
 +
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_method_with_cursor_anywhere_on_call_expresion() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +fn foo() {$0S.bar();}
 +",
 +            r"
 +struct S;
 +fn foo() {S.bar();}
 +impl S {
 +
 +
 +fn bar(&self) ${0:-> _} {
 +    todo!()
 +}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_static_method() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +fn foo() {S::bar$0();}
 +",
 +            r"
 +struct S;
 +fn foo() {S::bar();}
 +impl S {
 +
 +
 +fn bar() ${0:-> _} {
 +    todo!()
 +}
 +}
 +",
 +        )
 +    }
 +
 +    #[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;
 +fn foo() {S::bar();}
 +impl S {
 +
 +
 +fn bar() ${0:-> _} {
 +    todo!()
 +}
 +}
 +",
 +        )
 +    }
 +
++    #[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 {}
 +fn main() {
 +    Foo::new();
 +}
 +impl Foo {
 +
 +
 +fn new() ${0:-> _} {
 +    todo!()
 +}
 +}
 +",
 +        )
 +    }
 +}
index 80d3b925593674266776a705fadd0c4ea59f9b65,0000000000000000000000000000000000000000..b5d092e39b02972b24da8cdfaedf9432e8e42691
mode 100644,000000..100644
--- /dev/null
@@@ -1,1194 -1,0 +1,1227 @@@
-     ted, AstNode,
 +use ast::make;
 +use either::Either;
 +use hir::{db::HirDatabase, PathResolution, Semantics, TypeInfo};
 +use ide_db::{
 +    base_db::{FileId, FileRange},
 +    defs::Definition,
 +    imports::insert_use::remove_path_if_in_use_stmt,
 +    path_transform::PathTransform,
 +    search::{FileReference, SearchScope},
 +    syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref},
 +    RootDatabase,
 +};
 +use itertools::{izip, Itertools};
 +use syntax::{
 +    ast::{self, edit_in_place::Indent, HasArgList, PathExpr},
++    ted, AstNode, NodeOrToken, SyntaxKind,
 +};
 +
 +use crate::{
 +    assist_context::{AssistContext, Assists},
 +    AssistId, AssistKind,
 +};
 +
 +// Assist: inline_into_callers
 +//
 +// Inline a function or method body into all of its callers where possible, creating a `let` statement per parameter
 +// unless the parameter can be inlined. The parameter will be inlined either if it the supplied argument is a simple local
 +// or if the parameter is only accessed inside the function body once.
 +// If all calls can be inlined the function will be removed.
 +//
 +// ```
 +// fn print(_: &str) {}
 +// fn foo$0(word: &str) {
 +//     if !word.is_empty() {
 +//         print(word);
 +//     }
 +// }
 +// fn bar() {
 +//     foo("안녕하세요");
 +//     foo("여러분");
 +// }
 +// ```
 +// ->
 +// ```
 +// fn print(_: &str) {}
 +//
 +// fn bar() {
 +//     {
 +//         let word = "안녕하세요";
 +//         if !word.is_empty() {
 +//             print(word);
 +//         }
 +//     };
 +//     {
 +//         let word = "여러분";
 +//         if !word.is_empty() {
 +//             print(word);
 +//         }
 +//     };
 +// }
 +// ```
 +pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let def_file = ctx.file_id();
 +    let name = ctx.find_node_at_offset::<ast::Name>()?;
 +    let ast_func = name.syntax().parent().and_then(ast::Fn::cast)?;
 +    let func_body = ast_func.body()?;
 +    let param_list = ast_func.param_list()?;
 +
 +    let function = ctx.sema.to_def(&ast_func)?;
 +
 +    let params = get_fn_params(ctx.sema.db, function, &param_list)?;
 +
 +    let usages = Definition::Function(function).usages(&ctx.sema);
 +    if !usages.at_least_one() {
 +        return None;
 +    }
 +
 +    let is_recursive_fn = usages
 +        .clone()
 +        .in_scope(SearchScope::file_range(FileRange {
 +            file_id: def_file,
 +            range: func_body.syntax().text_range(),
 +        }))
 +        .at_least_one();
 +    if is_recursive_fn {
 +        cov_mark::hit!(inline_into_callers_recursive);
 +        return None;
 +    }
 +
 +    acc.add(
 +        AssistId("inline_into_callers", AssistKind::RefactorInline),
 +        "Inline into all callers",
 +        name.syntax().text_range(),
 +        |builder| {
 +            let mut usages = usages.all();
 +            let current_file_usage = usages.references.remove(&def_file);
 +
 +            let mut remove_def = true;
 +            let mut inline_refs_for_file = |file_id, refs: Vec<FileReference>| {
 +                builder.edit_file(file_id);
 +                let count = refs.len();
 +                // The collects are required as we are otherwise iterating while mutating 🙅‍♀️🙅‍♂️
 +                let (name_refs, name_refs_use): (Vec<_>, Vec<_>) = refs
 +                    .into_iter()
 +                    .filter_map(|file_ref| match file_ref.name {
 +                        ast::NameLike::NameRef(name_ref) => Some(name_ref),
 +                        _ => None,
 +                    })
 +                    .partition_map(|name_ref| {
 +                        match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) {
 +                            Some(use_tree) => Either::Right(builder.make_mut(use_tree)),
 +                            None => Either::Left(name_ref),
 +                        }
 +                    });
 +                let call_infos: Vec<_> = name_refs
 +                    .into_iter()
 +                    .filter_map(CallInfo::from_name_ref)
 +                    .map(|call_info| {
 +                        let mut_node = builder.make_syntax_mut(call_info.node.syntax().clone());
 +                        (call_info, mut_node)
 +                    })
 +                    .collect();
 +                let replaced = call_infos
 +                    .into_iter()
 +                    .map(|(call_info, mut_node)| {
 +                        let replacement =
 +                            inline(&ctx.sema, def_file, function, &func_body, &params, &call_info);
 +                        ted::replace(mut_node, replacement.syntax());
 +                    })
 +                    .count();
 +                if replaced + name_refs_use.len() == count {
 +                    // we replaced all usages in this file, so we can remove the imports
 +                    name_refs_use.into_iter().for_each(|use_tree| {
 +                        if let Some(path) = use_tree.path() {
 +                            remove_path_if_in_use_stmt(&path);
 +                        }
 +                    })
 +                } else {
 +                    remove_def = false;
 +                }
 +            };
 +            for (file_id, refs) in usages.into_iter() {
 +                inline_refs_for_file(file_id, refs);
 +            }
 +            match current_file_usage {
 +                Some(refs) => inline_refs_for_file(def_file, refs),
 +                None => builder.edit_file(def_file),
 +            }
 +            if remove_def {
 +                builder.delete(ast_func.syntax().text_range());
 +            }
 +        },
 +    )
 +}
 +
 +// Assist: inline_call
 +//
 +// Inlines a function or method body creating a `let` statement per parameter unless the parameter
 +// can be inlined. The parameter will be inlined either if it the supplied argument is a simple local
 +// or if the parameter is only accessed inside the function body once.
 +//
 +// ```
 +// # //- minicore: option
 +// fn foo(name: Option<&str>) {
 +//     let name = name.unwrap$0();
 +// }
 +// ```
 +// ->
 +// ```
 +// fn foo(name: Option<&str>) {
 +//     let name = match name {
 +//             Some(val) => val,
 +//             None => panic!("called `Option::unwrap()` on a `None` value"),
 +//         };
 +// }
 +// ```
 +pub(crate) fn inline_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let name_ref: ast::NameRef = ctx.find_node_at_offset()?;
 +    let call_info = CallInfo::from_name_ref(name_ref.clone())?;
 +    let (function, label) = match &call_info.node {
 +        ast::CallableExpr::Call(call) => {
 +            let path = match call.expr()? {
 +                ast::Expr::PathExpr(path) => path.path(),
 +                _ => None,
 +            }?;
 +            let function = match ctx.sema.resolve_path(&path)? {
 +                PathResolution::Def(hir::ModuleDef::Function(f)) => f,
 +                _ => return None,
 +            };
 +            (function, format!("Inline `{}`", path))
 +        }
 +        ast::CallableExpr::MethodCall(call) => {
 +            (ctx.sema.resolve_method_call(call)?, format!("Inline `{}`", name_ref))
 +        }
 +    };
 +
 +    let fn_source = ctx.sema.source(function)?;
 +    let fn_body = fn_source.value.body()?;
 +    let param_list = fn_source.value.param_list()?;
 +
 +    let FileRange { file_id, range } = fn_source.syntax().original_file_range(ctx.sema.db);
 +    if file_id == ctx.file_id() && range.contains(ctx.offset()) {
 +        cov_mark::hit!(inline_call_recursive);
 +        return None;
 +    }
 +    let params = get_fn_params(ctx.sema.db, function, &param_list)?;
 +
 +    if call_info.arguments.len() != params.len() {
 +        // Can't inline the function because they've passed the wrong number of
 +        // arguments to this function
 +        cov_mark::hit!(inline_call_incorrect_number_of_arguments);
 +        return None;
 +    }
 +
 +    let syntax = call_info.node.syntax().clone();
 +    acc.add(
 +        AssistId("inline_call", AssistKind::RefactorInline),
 +        label,
 +        syntax.text_range(),
 +        |builder| {
 +            let replacement = inline(&ctx.sema, file_id, function, &fn_body, &params, &call_info);
 +
 +            builder.replace_ast(
 +                match call_info.node {
 +                    ast::CallableExpr::Call(it) => ast::Expr::CallExpr(it),
 +                    ast::CallableExpr::MethodCall(it) => ast::Expr::MethodCallExpr(it),
 +                },
 +                replacement,
 +            );
 +        },
 +    )
 +}
 +
 +struct CallInfo {
 +    node: ast::CallableExpr,
 +    arguments: Vec<ast::Expr>,
 +    generic_arg_list: Option<ast::GenericArgList>,
 +}
 +
 +impl CallInfo {
 +    fn from_name_ref(name_ref: ast::NameRef) -> Option<CallInfo> {
 +        let parent = name_ref.syntax().parent()?;
 +        if let Some(call) = ast::MethodCallExpr::cast(parent.clone()) {
 +            let receiver = call.receiver()?;
 +            let mut arguments = vec![receiver];
 +            arguments.extend(call.arg_list()?.args());
 +            Some(CallInfo {
 +                generic_arg_list: call.generic_arg_list(),
 +                node: ast::CallableExpr::MethodCall(call),
 +                arguments,
 +            })
 +        } else if let Some(segment) = ast::PathSegment::cast(parent) {
 +            let path = segment.syntax().parent().and_then(ast::Path::cast)?;
 +            let path = path.syntax().parent().and_then(ast::PathExpr::cast)?;
 +            let call = path.syntax().parent().and_then(ast::CallExpr::cast)?;
 +
 +            Some(CallInfo {
 +                arguments: call.arg_list()?.args().collect(),
 +                node: ast::CallableExpr::Call(call),
 +                generic_arg_list: segment.generic_arg_list(),
 +            })
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +fn get_fn_params(
 +    db: &dyn HirDatabase,
 +    function: hir::Function,
 +    param_list: &ast::ParamList,
 +) -> Option<Vec<(ast::Pat, Option<ast::Type>, hir::Param)>> {
 +    let mut assoc_fn_params = function.assoc_fn_params(db).into_iter();
 +
 +    let mut params = Vec::new();
 +    if let Some(self_param) = param_list.self_param() {
 +        // FIXME this should depend on the receiver as well as the self_param
 +        params.push((
 +            make::ident_pat(
 +                self_param.amp_token().is_some(),
 +                self_param.mut_token().is_some(),
 +                make::name("this"),
 +            )
 +            .into(),
 +            None,
 +            assoc_fn_params.next()?,
 +        ));
 +    }
 +    for param in param_list.params() {
 +        params.push((param.pat()?, param.ty(), assoc_fn_params.next()?));
 +    }
 +
 +    Some(params)
 +}
 +
 +fn inline(
 +    sema: &Semantics<'_, RootDatabase>,
 +    function_def_file_id: FileId,
 +    function: hir::Function,
 +    fn_body: &ast::BlockExpr,
 +    params: &[(ast::Pat, Option<ast::Type>, hir::Param)],
 +    CallInfo { node, arguments, generic_arg_list }: &CallInfo,
 +) -> ast::Expr {
 +    let body = if sema.hir_file_for(fn_body.syntax()).is_macro() {
 +        cov_mark::hit!(inline_call_defined_in_macro);
 +        if let Some(body) = ast::BlockExpr::cast(insert_ws_into(fn_body.syntax().clone())) {
 +            body
 +        } else {
 +            fn_body.clone_for_update()
 +        }
 +    } else {
 +        fn_body.clone_for_update()
 +    };
++    if let Some(t) = body.syntax().ancestors().find_map(ast::Impl::cast).and_then(|i| i.self_ty()) {
++        body.syntax()
++            .descendants_with_tokens()
++            .filter_map(NodeOrToken::into_token)
++            .filter(|tok| tok.kind() == SyntaxKind::SELF_TYPE_KW)
++            .for_each(|tok| ted::replace(tok, t.syntax()));
++    }
 +    let usages_for_locals = |local| {
 +        Definition::Local(local)
 +            .usages(sema)
 +            .all()
 +            .references
 +            .remove(&function_def_file_id)
 +            .unwrap_or_default()
 +            .into_iter()
 +    };
 +    let param_use_nodes: Vec<Vec<_>> = params
 +        .iter()
 +        .map(|(pat, _, param)| {
 +            if !matches!(pat, ast::Pat::IdentPat(pat) if pat.is_simple_ident()) {
 +                return Vec::new();
 +            }
 +            // FIXME: we need to fetch all locals declared in the parameter here
 +            // not only the local if it is a simple binding
 +            match param.as_local(sema.db) {
 +                Some(l) => usages_for_locals(l)
 +                    .map(|FileReference { name, range, .. }| match name {
 +                        ast::NameLike::NameRef(_) => body
 +                            .syntax()
 +                            .covering_element(range)
 +                            .ancestors()
 +                            .nth(3)
 +                            .and_then(ast::PathExpr::cast),
 +                        _ => None,
 +                    })
 +                    .collect::<Option<Vec<_>>>()
 +                    .unwrap_or_default(),
 +                None => Vec::new(),
 +            }
 +        })
 +        .collect();
++
 +    if function.self_param(sema.db).is_some() {
 +        let this = || make::name_ref("this").syntax().clone_for_update();
 +        if let Some(self_local) = params[0].2.as_local(sema.db) {
 +            usages_for_locals(self_local)
 +                .flat_map(|FileReference { name, range, .. }| match name {
 +                    ast::NameLike::NameRef(_) => Some(body.syntax().covering_element(range)),
 +                    _ => None,
 +                })
 +                .for_each(|it| {
 +                    ted::replace(it, &this());
 +                })
 +        }
 +    }
 +    // Inline parameter expressions or generate `let` statements depending on whether inlining works or not.
 +    for ((pat, param_ty, _), usages, expr) in izip!(params, param_use_nodes, arguments).rev() {
 +        let inline_direct = |usage, replacement: &ast::Expr| {
 +            if let Some(field) = path_expr_as_record_field(usage) {
 +                cov_mark::hit!(inline_call_inline_direct_field);
 +                field.replace_expr(replacement.clone_for_update());
 +            } else {
 +                ted::replace(usage.syntax(), &replacement.syntax().clone_for_update());
 +            }
 +        };
 +        // izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors
 +        let usages: &[ast::PathExpr] = &*usages;
 +        let expr: &ast::Expr = expr;
 +        match usages {
 +            // inline single use closure arguments
 +            [usage]
 +                if matches!(expr, ast::Expr::ClosureExpr(_))
 +                    && usage.syntax().parent().and_then(ast::Expr::cast).is_some() =>
 +            {
 +                cov_mark::hit!(inline_call_inline_closure);
 +                let expr = make::expr_paren(expr.clone());
 +                inline_direct(usage, &expr);
 +            }
 +            // inline single use literals
 +            [usage] if matches!(expr, ast::Expr::Literal(_)) => {
 +                cov_mark::hit!(inline_call_inline_literal);
 +                inline_direct(usage, expr);
 +            }
 +            // inline direct local arguments
 +            [_, ..] if expr_as_name_ref(expr).is_some() => {
 +                cov_mark::hit!(inline_call_inline_locals);
 +                usages.iter().for_each(|usage| inline_direct(usage, expr));
 +            }
 +            // can't inline, emit a let statement
 +            _ => {
 +                let ty =
 +                    sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone());
 +                if let Some(stmt_list) = body.stmt_list() {
 +                    stmt_list.push_front(
 +                        make::let_stmt(pat.clone(), ty, Some(expr.clone()))
 +                            .clone_for_update()
 +                            .into(),
 +                    )
 +                }
 +            }
 +        }
 +    }
 +    if let Some(generic_arg_list) = generic_arg_list.clone() {
 +        if let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax()))
 +        {
 +            PathTransform::function_call(target, source, function, generic_arg_list)
 +                .apply(body.syntax());
 +        }
 +    }
 +
 +    let original_indentation = match node {
 +        ast::CallableExpr::Call(it) => it.indent_level(),
 +        ast::CallableExpr::MethodCall(it) => it.indent_level(),
 +    };
 +    body.reindent_to(original_indentation);
 +
 +    match body.tail_expr() {
 +        Some(expr) if body.statements().next().is_none() => expr,
 +        _ => match node
 +            .syntax()
 +            .parent()
 +            .and_then(ast::BinExpr::cast)
 +            .and_then(|bin_expr| bin_expr.lhs())
 +        {
 +            Some(lhs) if lhs.syntax() == node.syntax() => {
 +                make::expr_paren(ast::Expr::BlockExpr(body)).clone_for_update()
 +            }
 +            _ => ast::Expr::BlockExpr(body),
 +        },
 +    }
 +}
 +
 +fn path_expr_as_record_field(usage: &PathExpr) -> Option<ast::RecordExprField> {
 +    let path = usage.path()?;
 +    let name_ref = path.as_single_name_ref()?;
 +    ast::RecordExprField::for_name_ref(&name_ref)
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn no_args_or_return_value_gets_inlined_without_block() {
 +        check_assist(
 +            inline_call,
 +            r#"
 +fn foo() { println!("Hello, World!"); }
 +fn main() {
 +    fo$0o();
 +}
 +"#,
 +            r#"
 +fn foo() { println!("Hello, World!"); }
 +fn main() {
 +    { println!("Hello, World!"); };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_when_incorrect_number_of_parameters_are_provided() {
 +        cov_mark::check!(inline_call_incorrect_number_of_arguments);
 +        check_assist_not_applicable(
 +            inline_call,
 +            r#"
 +fn add(a: u32, b: u32) -> u32 { a + b }
 +fn main() { let x = add$0(42); }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn args_with_side_effects() {
 +        check_assist(
 +            inline_call,
 +            r#"
 +fn foo(name: String) {
 +    println!("Hello, {}!", name);
 +}
 +fn main() {
 +    foo$0(String::from("Michael"));
 +}
 +"#,
 +            r#"
 +fn foo(name: String) {
 +    println!("Hello, {}!", name);
 +}
 +fn main() {
 +    {
 +        let name = String::from("Michael");
 +        println!("Hello, {}!", name);
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn function_with_multiple_statements() {
 +        check_assist(
 +            inline_call,
 +            r#"
 +fn foo(a: u32, b: u32) -> u32 {
 +    let x = a + b;
 +    let y = x - b;
 +    x * y
 +}
 +
 +fn main() {
 +    let x = foo$0(1, 2);
 +}
 +"#,
 +            r#"
 +fn foo(a: u32, b: u32) -> u32 {
 +    let x = a + b;
 +    let y = x - b;
 +    x * y
 +}
 +
 +fn main() {
 +    let x = {
 +        let b = 2;
 +        let x = 1 + b;
 +        let y = x - b;
 +        x * y
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn function_with_self_param() {
 +        check_assist(
 +            inline_call,
 +            r#"
 +struct Foo(u32);
 +
 +impl Foo {
 +    fn add(self, a: u32) -> Self {
 +        Foo(self.0 + a)
 +    }
 +}
 +
 +fn main() {
 +    let x = Foo::add$0(Foo(3), 2);
 +}
 +"#,
 +            r#"
 +struct Foo(u32);
 +
 +impl Foo {
 +    fn add(self, a: u32) -> Self {
 +        Foo(self.0 + a)
 +    }
 +}
 +
 +fn main() {
 +    let x = {
 +        let this = Foo(3);
 +        Foo(this.0 + 2)
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn method_by_val() {
 +        check_assist(
 +            inline_call,
 +            r#"
 +struct Foo(u32);
 +
 +impl Foo {
 +    fn add(self, a: u32) -> Self {
 +        Foo(self.0 + a)
 +    }
 +}
 +
 +fn main() {
 +    let x = Foo(3).add$0(2);
 +}
 +"#,
 +            r#"
 +struct Foo(u32);
 +
 +impl Foo {
 +    fn add(self, a: u32) -> Self {
 +        Foo(self.0 + a)
 +    }
 +}
 +
 +fn main() {
 +    let x = {
 +        let this = Foo(3);
 +        Foo(this.0 + 2)
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn method_by_ref() {
 +        check_assist(
 +            inline_call,
 +            r#"
 +struct Foo(u32);
 +
 +impl Foo {
 +    fn add(&self, a: u32) -> Self {
 +        Foo(self.0 + a)
 +    }
 +}
 +
 +fn main() {
 +    let x = Foo(3).add$0(2);
 +}
 +"#,
 +            r#"
 +struct Foo(u32);
 +
 +impl Foo {
 +    fn add(&self, a: u32) -> Self {
 +        Foo(self.0 + a)
 +    }
 +}
 +
 +fn main() {
 +    let x = {
 +        let ref this = Foo(3);
 +        Foo(this.0 + 2)
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn method_by_ref_mut() {
 +        check_assist(
 +            inline_call,
 +            r#"
 +struct Foo(u32);
 +
 +impl Foo {
 +    fn clear(&mut self) {
 +        self.0 = 0;
 +    }
 +}
 +
 +fn main() {
 +    let mut foo = Foo(3);
 +    foo.clear$0();
 +}
 +"#,
 +            r#"
 +struct Foo(u32);
 +
 +impl Foo {
 +    fn clear(&mut self) {
 +        self.0 = 0;
 +    }
 +}
 +
 +fn main() {
 +    let mut foo = Foo(3);
 +    {
 +        let ref mut this = foo;
 +        this.0 = 0;
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn function_multi_use_expr_in_param() {
 +        check_assist(
 +            inline_call,
 +            r#"
 +fn square(x: u32) -> u32 {
 +    x * x
 +}
 +fn main() {
 +    let x = 51;
 +    let y = square$0(10 + x);
 +}
 +"#,
 +            r#"
 +fn square(x: u32) -> u32 {
 +    x * x
 +}
 +fn main() {
 +    let x = 51;
 +    let y = {
 +        let x = 10 + x;
 +        x * x
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn function_use_local_in_param() {
 +        cov_mark::check!(inline_call_inline_locals);
 +        check_assist(
 +            inline_call,
 +            r#"
 +fn square(x: u32) -> u32 {
 +    x * x
 +}
 +fn main() {
 +    let local = 51;
 +    let y = square$0(local);
 +}
 +"#,
 +            r#"
 +fn square(x: u32) -> u32 {
 +    x * x
 +}
 +fn main() {
 +    let local = 51;
 +    let y = local * local;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn method_in_impl() {
 +        check_assist(
 +            inline_call,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {
 +        self;
 +        self;
 +    }
 +    fn bar(&self) {
 +        self.foo$0();
 +    }
 +}
 +"#,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {
 +        self;
 +        self;
 +    }
 +    fn bar(&self) {
 +        {
 +            let ref this = self;
 +            this;
 +            this;
 +        };
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn wraps_closure_in_paren() {
 +        cov_mark::check!(inline_call_inline_closure);
 +        check_assist(
 +            inline_call,
 +            r#"
 +fn foo(x: fn()) {
 +    x();
 +}
 +
 +fn main() {
 +    foo$0(|| {})
 +}
 +"#,
 +            r#"
 +fn foo(x: fn()) {
 +    x();
 +}
 +
 +fn main() {
 +    {
 +        (|| {})();
 +    }
 +}
 +"#,
 +        );
 +        check_assist(
 +            inline_call,
 +            r#"
 +fn foo(x: fn()) {
 +    x();
 +}
 +
 +fn main() {
 +    foo$0(main)
 +}
 +"#,
 +            r#"
 +fn foo(x: fn()) {
 +    x();
 +}
 +
 +fn main() {
 +    {
 +        main();
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn inline_single_literal_expr() {
 +        cov_mark::check!(inline_call_inline_literal);
 +        check_assist(
 +            inline_call,
 +            r#"
 +fn foo(x: u32) -> u32{
 +    x
 +}
 +
 +fn main() {
 +    foo$0(222);
 +}
 +"#,
 +            r#"
 +fn foo(x: u32) -> u32{
 +    x
 +}
 +
 +fn main() {
 +    222;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn inline_emits_type_for_coercion() {
 +        check_assist(
 +            inline_call,
 +            r#"
 +fn foo(x: *const u32) -> u32 {
 +    x as u32
 +}
 +
 +fn main() {
 +    foo$0(&222);
 +}
 +"#,
 +            r#"
 +fn foo(x: *const u32) -> u32 {
 +    x as u32
 +}
 +
 +fn main() {
 +    {
 +        let x: *const u32 = &222;
 +        x as u32
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    // FIXME: const generics aren't being substituted, this is blocked on better support for them
 +    #[test]
 +    fn inline_substitutes_generics() {
 +        check_assist(
 +            inline_call,
 +            r#"
 +fn foo<T, const N: usize>() {
 +    bar::<T, N>()
 +}
 +
 +fn bar<U, const M: usize>() {}
 +
 +fn main() {
 +    foo$0::<usize, {0}>();
 +}
 +"#,
 +            r#"
 +fn foo<T, const N: usize>() {
 +    bar::<T, N>()
 +}
 +
 +fn bar<U, const M: usize>() {}
 +
 +fn main() {
 +    bar::<usize, N>();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn inline_callers() {
 +        check_assist(
 +            inline_into_callers,
 +            r#"
 +fn do_the_math$0(b: u32) -> u32 {
 +    let foo = 10;
 +    foo * b + foo
 +}
 +fn foo() {
 +    do_the_math(0);
 +    let bar = 10;
 +    do_the_math(bar);
 +}
 +"#,
 +            r#"
 +
 +fn foo() {
 +    {
 +        let foo = 10;
 +        foo * 0 + foo
 +    };
 +    let bar = 10;
 +    {
 +        let foo = 10;
 +        foo * bar + foo
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn inline_callers_across_files() {
 +        check_assist(
 +            inline_into_callers,
 +            r#"
 +//- /lib.rs
 +mod foo;
 +fn do_the_math$0(b: u32) -> u32 {
 +    let foo = 10;
 +    foo * b + foo
 +}
 +//- /foo.rs
 +use super::do_the_math;
 +fn foo() {
 +    do_the_math(0);
 +    let bar = 10;
 +    do_the_math(bar);
 +}
 +"#,
 +            r#"
 +//- /lib.rs
 +mod foo;
 +
 +//- /foo.rs
 +fn foo() {
 +    {
 +        let foo = 10;
 +        foo * 0 + foo
 +    };
 +    let bar = 10;
 +    {
 +        let foo = 10;
 +        foo * bar + foo
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn inline_callers_across_files_with_def_file() {
 +        check_assist(
 +            inline_into_callers,
 +            r#"
 +//- /lib.rs
 +mod foo;
 +fn do_the_math$0(b: u32) -> u32 {
 +    let foo = 10;
 +    foo * b + foo
 +}
 +fn bar(a: u32, b: u32) -> u32 {
 +    do_the_math(0);
 +}
 +//- /foo.rs
 +use super::do_the_math;
 +fn foo() {
 +    do_the_math(0);
 +}
 +"#,
 +            r#"
 +//- /lib.rs
 +mod foo;
 +
 +fn bar(a: u32, b: u32) -> u32 {
 +    {
 +        let foo = 10;
 +        foo * 0 + foo
 +    };
 +}
 +//- /foo.rs
 +fn foo() {
 +    {
 +        let foo = 10;
 +        foo * 0 + foo
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn inline_callers_recursive() {
 +        cov_mark::check!(inline_into_callers_recursive);
 +        check_assist_not_applicable(
 +            inline_into_callers,
 +            r#"
 +fn foo$0() {
 +    foo();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn inline_call_recursive() {
 +        cov_mark::check!(inline_call_recursive);
 +        check_assist_not_applicable(
 +            inline_call,
 +            r#"
 +fn foo() {
 +    foo$0();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn inline_call_field_shorthand() {
 +        cov_mark::check!(inline_call_inline_direct_field);
 +        check_assist(
 +            inline_call,
 +            r#"
 +struct Foo {
 +    field: u32,
 +    field1: u32,
 +    field2: u32,
 +    field3: u32,
 +}
 +fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {
 +    Foo {
 +        field,
 +        field1,
 +        field2: val2,
 +        field3: val3,
 +    }
 +}
 +fn main() {
 +    let bar = 0;
 +    let baz = 0;
 +    foo$0(bar, 0, baz, 0);
 +}
 +"#,
 +            r#"
 +struct Foo {
 +    field: u32,
 +    field1: u32,
 +    field2: u32,
 +    field3: u32,
 +}
 +fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {
 +    Foo {
 +        field,
 +        field1,
 +        field2: val2,
 +        field3: val3,
 +    }
 +}
 +fn main() {
 +    let bar = 0;
 +    let baz = 0;
 +    Foo {
 +            field: bar,
 +            field1: 0,
 +            field2: baz,
 +            field3: 0,
 +        };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn inline_callers_wrapped_in_parentheses() {
 +        check_assist(
 +            inline_into_callers,
 +            r#"
 +fn foo$0() -> u32 {
 +    let x = 0;
 +    x
 +}
 +fn bar() -> u32 {
 +    foo() + foo()
 +}
 +"#,
 +            r#"
 +
 +fn bar() -> u32 {
 +    ({
 +        let x = 0;
 +        x
 +    }) + {
 +        let x = 0;
 +        x
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn inline_call_wrapped_in_parentheses() {
 +        check_assist(
 +            inline_call,
 +            r#"
 +fn foo() -> u32 {
 +    let x = 0;
 +    x
 +}
 +fn bar() -> u32 {
 +    foo$0() + foo()
 +}
 +"#,
 +            r#"
 +fn foo() -> u32 {
 +    let x = 0;
 +    x
 +}
 +fn bar() -> u32 {
 +    ({
 +        let x = 0;
 +        x
 +    }) + foo()
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn inline_call_defined_in_macro() {
 +        cov_mark::check!(inline_call_defined_in_macro);
 +        check_assist(
 +            inline_call,
 +            r#"
 +macro_rules! define_foo {
 +    () => { fn foo() -> u32 {
 +        let x = 0;
 +        x
 +    } };
 +}
 +define_foo!();
 +fn bar() -> u32 {
 +    foo$0()
 +}
 +"#,
 +            r#"
 +macro_rules! define_foo {
 +    () => { fn foo() -> u32 {
 +        let x = 0;
 +        x
 +    } };
 +}
 +define_foo!();
 +fn bar() -> u32 {
 +    {
 +      let x = 0;
 +      x
 +    }
 +}
++"#,
++        )
++    }
++
++    #[test]
++    fn inline_call_with_self_type() {
++        check_assist(
++            inline_call,
++            r#"
++struct A(u32);
++impl A {
++    fn f() -> Self { Self(114514) }
++}
++fn main() {
++    A::f$0();
++}
++"#,
++            r#"
++struct A(u32);
++impl A {
++    fn f() -> Self { Self(114514) }
++}
++fn main() {
++    A(114514);
++}
 +"#,
 +        )
 +    }
 +}
index 054663a06a1154b2868c00590dcc1a325b67e1e2,0000000000000000000000000000000000000000..9adf6381c1cbcf752b41b1852706043d71150050
mode 100644,000000..100644
--- /dev/null
@@@ -1,838 -1,0 +1,1001 @@@
- // - "inline_alias_to_users" assist #10881.
 +// Some ideas for future improvements:
 +// - Support replacing aliases which are used in expressions, e.g. `A::new()`.
-     enum Replacement {
-         Generic { lifetime_map: LifetimeMap, const_and_type_map: ConstAndTypeMap },
-         Plain,
-     }
 +// - Remove unused aliases if there are no longer any users, see inline_call.rs.
 +
 +use hir::{HasSource, PathResolution};
++use ide_db::{defs::Definition, search::FileReference};
 +use itertools::Itertools;
 +use std::collections::HashMap;
 +use syntax::{
 +    ast::{self, make, HasGenericParams, HasName},
 +    ted, AstNode, NodeOrToken, SyntaxNode,
 +};
 +
 +use crate::{
 +    assist_context::{AssistContext, Assists},
 +    AssistId, AssistKind,
 +};
 +
++// Assist: inline_type_alias_uses
++//
++// Inline a type alias into all of its uses where possible.
++//
++// ```
++// type $0A = i32;
++// fn id(x: A) -> A {
++//     x
++// };
++// fn foo() {
++//     let _: A = 3;
++// }
++// ```
++// ->
++// ```
++// type A = i32;
++// fn id(x: i32) -> i32 {
++//     x
++// };
++// fn foo() {
++//     let _: i32 = 3;
++// }
++pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
++    let name = ctx.find_node_at_offset::<ast::Name>()?;
++    let ast_alias = name.syntax().parent().and_then(ast::TypeAlias::cast)?;
++
++    let hir_alias = ctx.sema.to_def(&ast_alias)?;
++    let concrete_type = ast_alias.ty()?;
++
++    let usages = Definition::TypeAlias(hir_alias).usages(&ctx.sema);
++    if !usages.at_least_one() {
++        return None;
++    }
++
++    // until this is ok
++
++    acc.add(
++        AssistId("inline_type_alias_uses", AssistKind::RefactorInline),
++        "Inline type alias into all uses",
++        name.syntax().text_range(),
++        |builder| {
++            let usages = usages.all();
++
++            let mut inline_refs_for_file = |file_id, refs: Vec<FileReference>| {
++                builder.edit_file(file_id);
++
++                let path_types: Vec<ast::PathType> = refs
++                    .into_iter()
++                    .filter_map(|file_ref| match file_ref.name {
++                        ast::NameLike::NameRef(path_type) => {
++                            path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast)
++                        }
++                        _ => None,
++                    })
++                    .collect();
++
++                for (target, replacement) in path_types.into_iter().filter_map(|path_type| {
++                    let replacement = inline(&ast_alias, &path_type)?.to_text(&concrete_type);
++                    let target = path_type.syntax().text_range();
++                    Some((target, replacement))
++                }) {
++                    builder.replace(target, replacement);
++                }
++            };
++
++            for (file_id, refs) in usages.into_iter() {
++                inline_refs_for_file(file_id, refs);
++            }
++        },
++    )
++}
++
 +// Assist: inline_type_alias
 +//
 +// Replace a type alias with its concrete type.
 +//
 +// ```
 +// type A<T = u32> = Vec<T>;
 +//
 +// fn main() {
 +//     let a: $0A;
 +// }
 +// ```
 +// ->
 +// ```
 +// type A<T = u32> = Vec<T>;
 +//
 +// fn main() {
 +//     let a: Vec<u32>;
 +// }
 +// ```
 +pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-             replacement = if let Some(alias_generics) = alias.generic_param_list() {
-                 if alias_generics.generic_params().next().is_none() {
-                     cov_mark::hit!(no_generics_params);
-                     return None;
-                 }
-                 let instance_args =
-                     alias_instance.syntax().descendants().find_map(ast::GenericArgList::cast);
-                 Replacement::Generic {
-                     lifetime_map: LifetimeMap::new(&instance_args, &alias_generics)?,
-                     const_and_type_map: ConstAndTypeMap::new(&instance_args, &alias_generics)?,
-                 }
-             } else {
-                 Replacement::Plain
-             };
 +    let alias_instance = ctx.find_node_at_offset::<ast::PathType>()?;
 +    let concrete_type;
 +    let replacement;
 +    match alias_instance.path()?.as_single_name_ref() {
 +        Some(nameref) if nameref.Self_token().is_some() => {
 +            match ctx.sema.resolve_path(&alias_instance.path()?)? {
 +                PathResolution::SelfType(imp) => {
 +                    concrete_type = imp.source(ctx.db())?.value.self_ty()?;
 +                }
 +                // FIXME: should also work in ADT definitions
 +                _ => return None,
 +            }
 +
 +            replacement = Replacement::Plain;
 +        }
 +        _ => {
 +            let alias = get_type_alias(&ctx, &alias_instance)?;
 +            concrete_type = alias.ty()?;
-         |builder| {
-             let replacement_text = match replacement {
-                 Replacement::Generic { lifetime_map, const_and_type_map } => {
-                     create_replacement(&lifetime_map, &const_and_type_map, &concrete_type)
-                 }
-                 Replacement::Plain => concrete_type.to_string(),
-             };
-             builder.replace(target, replacement_text);
-         },
++            replacement = inline(&alias, &alias_instance)?;
 +        }
 +    }
 +
 +    let target = alias_instance.syntax().text_range();
 +
 +    acc.add(
 +        AssistId("inline_type_alias", AssistKind::RefactorInline),
 +        "Inline type alias",
 +        target,
++        |builder| builder.replace(target, replacement.to_text(&concrete_type)),
 +    )
 +}
 +
++impl Replacement {
++    fn to_text(&self, concrete_type: &ast::Type) -> String {
++        match self {
++            Replacement::Generic { lifetime_map, const_and_type_map } => {
++                create_replacement(&lifetime_map, &const_and_type_map, &concrete_type)
++            }
++            Replacement::Plain => concrete_type.to_string(),
++        }
++    }
++}
++
++enum Replacement {
++    Generic { lifetime_map: LifetimeMap, const_and_type_map: ConstAndTypeMap },
++    Plain,
++}
++
++fn inline(alias_def: &ast::TypeAlias, alias_instance: &ast::PathType) -> Option<Replacement> {
++    let repl = if let Some(alias_generics) = alias_def.generic_param_list() {
++        if alias_generics.generic_params().next().is_none() {
++            cov_mark::hit!(no_generics_params);
++            return None;
++        }
++        let instance_args =
++            alias_instance.syntax().descendants().find_map(ast::GenericArgList::cast);
++
++        Replacement::Generic {
++            lifetime_map: LifetimeMap::new(&instance_args, &alias_generics)?,
++            const_and_type_map: ConstAndTypeMap::new(&instance_args, &alias_generics)?,
++        }
++    } else {
++        Replacement::Plain
++    };
++    Some(repl)
++}
++
 +struct LifetimeMap(HashMap<String, ast::Lifetime>);
 +
 +impl LifetimeMap {
 +    fn new(
 +        instance_args: &Option<ast::GenericArgList>,
 +        alias_generics: &ast::GenericParamList,
 +    ) -> Option<Self> {
 +        let mut inner = HashMap::new();
 +
 +        let wildcard_lifetime = make::lifetime("'_");
 +        let lifetimes = alias_generics
 +            .lifetime_params()
 +            .filter_map(|lp| lp.lifetime())
 +            .map(|l| l.to_string())
 +            .collect_vec();
 +
 +        for lifetime in &lifetimes {
 +            inner.insert(lifetime.to_string(), wildcard_lifetime.clone());
 +        }
 +
 +        if let Some(instance_generic_args_list) = &instance_args {
 +            for (index, lifetime) in instance_generic_args_list
 +                .lifetime_args()
 +                .filter_map(|arg| arg.lifetime())
 +                .enumerate()
 +            {
 +                let key = match lifetimes.get(index) {
 +                    Some(key) => key,
 +                    None => {
 +                        cov_mark::hit!(too_many_lifetimes);
 +                        return None;
 +                    }
 +                };
 +
 +                inner.insert(key.clone(), lifetime);
 +            }
 +        }
 +
 +        Some(Self(inner))
 +    }
 +}
 +
 +struct ConstAndTypeMap(HashMap<String, SyntaxNode>);
 +
 +impl ConstAndTypeMap {
 +    fn new(
 +        instance_args: &Option<ast::GenericArgList>,
 +        alias_generics: &ast::GenericParamList,
 +    ) -> Option<Self> {
 +        let mut inner = HashMap::new();
 +        let instance_generics = generic_args_to_const_and_type_generics(instance_args);
 +        let alias_generics = generic_param_list_to_const_and_type_generics(&alias_generics);
 +
 +        if instance_generics.len() > alias_generics.len() {
 +            cov_mark::hit!(too_many_generic_args);
 +            return None;
 +        }
 +
 +        // Any declaration generics that don't have a default value must have one
 +        // provided by the instance.
 +        for (i, declaration_generic) in alias_generics.iter().enumerate() {
 +            let key = declaration_generic.replacement_key()?;
 +
 +            if let Some(instance_generic) = instance_generics.get(i) {
 +                inner.insert(key, instance_generic.replacement_value()?);
 +            } else if let Some(value) = declaration_generic.replacement_value() {
 +                inner.insert(key, value);
 +            } else {
 +                cov_mark::hit!(missing_replacement_param);
 +                return None;
 +            }
 +        }
 +
 +        Some(Self(inner))
 +    }
 +}
 +
 +/// This doesn't attempt to ensure specified generics are compatible with those
 +/// required by the type alias, other than lifetimes which must either all be
 +/// specified or all omitted. It will replace TypeArgs with ConstArgs and vice
 +/// versa if they're in the wrong position. It supports partially specified
 +/// generics.
 +///
 +/// 1. Map the provided instance's generic args to the type alias's generic
 +///    params:
 +///
 +///    ```
 +///    type A<'a, const N: usize, T = u64> = &'a [T; N];
 +///          ^ alias generic params
 +///    let a: A<100>;
 +///            ^ instance generic args
 +///    ```
 +///
 +///    generic['a] = '_ due to omission
 +///    generic[N] = 100 due to the instance arg
 +///    generic[T] = u64 due to the default param
 +///
 +/// 2. Copy the concrete type and substitute in each found mapping:
 +///
 +///    &'_ [u64; 100]
 +///
 +/// 3. Remove wildcard lifetimes entirely:
 +///
 +///    &[u64; 100]
 +fn create_replacement(
 +    lifetime_map: &LifetimeMap,
 +    const_and_type_map: &ConstAndTypeMap,
 +    concrete_type: &ast::Type,
 +) -> String {
 +    let updated_concrete_type = concrete_type.clone_for_update();
 +    let mut replacements = Vec::new();
 +    let mut removals = Vec::new();
 +
 +    for syntax in updated_concrete_type.syntax().descendants() {
 +        let syntax_string = syntax.to_string();
 +        let syntax_str = syntax_string.as_str();
 +
 +        if let Some(old_lifetime) = ast::Lifetime::cast(syntax.clone()) {
 +            if let Some(new_lifetime) = lifetime_map.0.get(&old_lifetime.to_string()) {
 +                if new_lifetime.text() == "'_" {
 +                    removals.push(NodeOrToken::Node(syntax.clone()));
 +
 +                    if let Some(ws) = syntax.next_sibling_or_token() {
 +                        removals.push(ws.clone());
 +                    }
 +
 +                    continue;
 +                }
 +
 +                replacements.push((syntax.clone(), new_lifetime.syntax().clone_for_update()));
 +            }
 +        } else if let Some(replacement_syntax) = const_and_type_map.0.get(syntax_str) {
 +            let new_string = replacement_syntax.to_string();
 +            let new = if new_string == "_" {
 +                make::wildcard_pat().syntax().clone_for_update()
 +            } else {
 +                replacement_syntax.clone_for_update()
 +            };
 +
 +            replacements.push((syntax.clone(), new));
 +        }
 +    }
 +
 +    for (old, new) in replacements {
 +        ted::replace(old, new);
 +    }
 +
 +    for syntax in removals {
 +        ted::remove(syntax);
 +    }
 +
 +    updated_concrete_type.to_string()
 +}
 +
 +fn get_type_alias(ctx: &AssistContext<'_>, path: &ast::PathType) -> Option<ast::TypeAlias> {
 +    let resolved_path = ctx.sema.resolve_path(&path.path()?)?;
 +
 +    // We need the generics in the correct order to be able to map any provided
 +    // instance generics to declaration generics. The `hir::TypeAlias` doesn't
 +    // keep the order, so we must get the `ast::TypeAlias` from the hir
 +    // definition.
 +    if let PathResolution::Def(hir::ModuleDef::TypeAlias(ta)) = resolved_path {
 +        Some(ctx.sema.source(ta)?.value)
 +    } else {
 +        None
 +    }
 +}
 +
 +enum ConstOrTypeGeneric {
 +    ConstArg(ast::ConstArg),
 +    TypeArg(ast::TypeArg),
 +    ConstParam(ast::ConstParam),
 +    TypeParam(ast::TypeParam),
 +}
 +
 +impl ConstOrTypeGeneric {
 +    fn replacement_key(&self) -> Option<String> {
 +        // Only params are used as replacement keys.
 +        match self {
 +            ConstOrTypeGeneric::ConstParam(cp) => Some(cp.name()?.to_string()),
 +            ConstOrTypeGeneric::TypeParam(tp) => Some(tp.name()?.to_string()),
 +            _ => None,
 +        }
 +    }
 +
 +    fn replacement_value(&self) -> Option<SyntaxNode> {
 +        Some(match self {
 +            ConstOrTypeGeneric::ConstArg(ca) => ca.expr()?.syntax().clone(),
 +            ConstOrTypeGeneric::TypeArg(ta) => ta.syntax().clone(),
 +            ConstOrTypeGeneric::ConstParam(cp) => cp.default_val()?.syntax().clone(),
 +            ConstOrTypeGeneric::TypeParam(tp) => tp.default_type()?.syntax().clone(),
 +        })
 +    }
 +}
 +
 +fn generic_param_list_to_const_and_type_generics(
 +    generics: &ast::GenericParamList,
 +) -> Vec<ConstOrTypeGeneric> {
 +    let mut others = Vec::new();
 +
 +    for param in generics.generic_params() {
 +        match param {
 +            ast::GenericParam::LifetimeParam(_) => {}
 +            ast::GenericParam::ConstParam(cp) => {
 +                others.push(ConstOrTypeGeneric::ConstParam(cp));
 +            }
 +            ast::GenericParam::TypeParam(tp) => others.push(ConstOrTypeGeneric::TypeParam(tp)),
 +        }
 +    }
 +
 +    others
 +}
 +
 +fn generic_args_to_const_and_type_generics(
 +    generics: &Option<ast::GenericArgList>,
 +) -> Vec<ConstOrTypeGeneric> {
 +    let mut others = Vec::new();
 +
 +    // It's fine for there to be no instance generics because the declaration
 +    // might have default values or they might be inferred.
 +    if let Some(generics) = generics {
 +        for arg in generics.generic_args() {
 +            match arg {
 +                ast::GenericArg::TypeArg(ta) => {
 +                    others.push(ConstOrTypeGeneric::TypeArg(ta));
 +                }
 +                ast::GenericArg::ConstArg(ca) => {
 +                    others.push(ConstOrTypeGeneric::ConstArg(ca));
 +                }
 +                _ => {}
 +            }
 +        }
 +    }
 +
 +    others
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::*;
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    #[test]
 +    fn empty_generic_params() {
 +        cov_mark::check!(no_generics_params);
 +        check_assist_not_applicable(
 +            inline_type_alias,
 +            r#"
 +type A<> = T;
 +fn main() {
 +    let a: $0A<u32>;
 +}
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn too_many_generic_args() {
 +        cov_mark::check!(too_many_generic_args);
 +        check_assist_not_applicable(
 +            inline_type_alias,
 +            r#"
 +type A<T> = T;
 +fn main() {
 +    let a: $0A<u32, u64>;
 +}
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn too_many_lifetimes() {
 +        cov_mark::check!(too_many_lifetimes);
 +        check_assist_not_applicable(
 +            inline_type_alias,
 +            r#"
 +type A<'a> = &'a &'b u32;
 +fn f<'a>() {
 +    let a: $0A<'a, 'b> = 0;
 +}
 +"#,
 +        );
 +    }
 +
 +    // This must be supported in order to support "inline_alias_to_users" or
 +    // whatever it will be called.
 +    #[test]
 +    fn alias_as_expression_ignored() {
 +        check_assist_not_applicable(
 +            inline_type_alias,
 +            r#"
 +type A = Vec<u32>;
 +fn main() {
 +    let a: A = $0A::new();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn primitive_arg() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +type A<T> = T;
 +fn main() {
 +    let a: $0A<u32> = 0;
 +}
 +"#,
 +            r#"
 +type A<T> = T;
 +fn main() {
 +    let a: u32 = 0;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_generic_replacements() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +type A = Vec<u32>;
 +fn main() {
 +    let a: $0A;
 +}
 +"#,
 +            r#"
 +type A = Vec<u32>;
 +fn main() {
 +    let a: Vec<u32>;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn param_expression() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +type A<const N: usize = { 1 }> = [u32; N];
 +fn main() {
 +    let a: $0A;
 +}
 +"#,
 +            r#"
 +type A<const N: usize = { 1 }> = [u32; N];
 +fn main() {
 +    let a: [u32; { 1 }];
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn param_default_value() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +type A<const N: usize = 1> = [u32; N];
 +fn main() {
 +    let a: $0A;
 +}
 +"#,
 +            r#"
 +type A<const N: usize = 1> = [u32; N];
 +fn main() {
 +    let a: [u32; 1];
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn all_param_types() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +struct Struct<const C: usize>;
 +type A<'inner1, 'outer1, Outer1, const INNER1: usize, Inner1: Clone, const OUTER1: usize> = (Struct<INNER1>, Struct<OUTER1>, Outer1, &'inner1 (), Inner1, &'outer1 ());
 +fn foo<'inner2, 'outer2, Outer2, const INNER2: usize, Inner2, const OUTER2: usize>() {
 +    let a: $0A<'inner2, 'outer2, Outer2, INNER2, Inner2, OUTER2>;
 +}
 +"#,
 +            r#"
 +struct Struct<const C: usize>;
 +type A<'inner1, 'outer1, Outer1, const INNER1: usize, Inner1: Clone, const OUTER1: usize> = (Struct<INNER1>, Struct<OUTER1>, Outer1, &'inner1 (), Inner1, &'outer1 ());
 +fn foo<'inner2, 'outer2, Outer2, const INNER2: usize, Inner2, const OUTER2: usize>() {
 +    let a: (Struct<INNER2>, Struct<OUTER2>, Outer2, &'inner2 (), Inner2, &'outer2 ());
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn omitted_lifetimes() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +type A<'l, 'r> = &'l &'r u32;
 +fn main() {
 +    let a: $0A;
 +}
 +"#,
 +            r#"
 +type A<'l, 'r> = &'l &'r u32;
 +fn main() {
 +    let a: &&u32;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn omitted_type() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +type A<'r, 'l, T = u32> = &'l std::collections::HashMap<&'r str, T>;
 +fn main() {
 +    let a: $0A<'_, '_>;
 +}
 +"#,
 +            r#"
 +type A<'r, 'l, T = u32> = &'l std::collections::HashMap<&'r str, T>;
 +fn main() {
 +    let a: &std::collections::HashMap<&str, u32>;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn omitted_everything() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +type A<'r, 'l, T = u32> = &'l std::collections::HashMap<&'r str, T>;
 +fn main() {
 +    let v = std::collections::HashMap<&str, u32>;
 +    let a: $0A = &v;
 +}
 +"#,
 +            r#"
 +type A<'r, 'l, T = u32> = &'l std::collections::HashMap<&'r str, T>;
 +fn main() {
 +    let v = std::collections::HashMap<&str, u32>;
 +    let a: &std::collections::HashMap<&str, u32> = &v;
 +}
 +"#,
 +        );
 +    }
 +
 +    // This doesn't actually cause the GenericArgsList to contain a AssocTypeArg.
 +    #[test]
 +    fn arg_associated_type() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +trait Tra { type Assoc; fn a(); }
 +struct Str {}
 +impl Tra for Str {
 +    type Assoc = u32;
 +    fn a() {
 +        type A<T> = Vec<T>;
 +        let a: $0A<Self::Assoc>;
 +    }
 +}
 +"#,
 +            r#"
 +trait Tra { type Assoc; fn a(); }
 +struct Str {}
 +impl Tra for Str {
 +    type Assoc = u32;
 +    fn a() {
 +        type A<T> = Vec<T>;
 +        let a: Vec<Self::Assoc>;
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn param_default_associated_type() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +trait Tra { type Assoc; fn a() }
 +struct Str {}
 +impl Tra for Str {
 +    type Assoc = u32;
 +    fn a() {
 +        type A<T = Self::Assoc> = Vec<T>;
 +        let a: $0A;
 +    }
 +}
 +"#,
 +            r#"
 +trait Tra { type Assoc; fn a() }
 +struct Str {}
 +impl Tra for Str {
 +    type Assoc = u32;
 +    fn a() {
 +        type A<T = Self::Assoc> = Vec<T>;
 +        let a: Vec<Self::Assoc>;
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn function_pointer() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +type A = fn(u32);
 +fn foo(a: u32) {}
 +fn main() {
 +    let a: $0A = foo;
 +}
 +"#,
 +            r#"
 +type A = fn(u32);
 +fn foo(a: u32) {}
 +fn main() {
 +    let a: fn(u32) = foo;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn closure() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +type A = Box<dyn FnOnce(u32) -> u32>;
 +fn main() {
 +    let a: $0A = Box::new(|_| 0);
 +}
 +"#,
 +            r#"
 +type A = Box<dyn FnOnce(u32) -> u32>;
 +fn main() {
 +    let a: Box<dyn FnOnce(u32) -> u32> = Box::new(|_| 0);
 +}
 +"#,
 +        );
 +    }
 +
 +    // Type aliases can't be used in traits, but someone might use the assist to
 +    // fix the error.
 +    #[test]
 +    fn bounds() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"type A = std::io::Write; fn f<T>() where T: $0A {}"#,
 +            r#"type A = std::io::Write; fn f<T>() where T: std::io::Write {}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn function_parameter() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +type A = std::io::Write;
 +fn f(a: impl $0A) {}
 +"#,
 +            r#"
 +type A = std::io::Write;
 +fn f(a: impl std::io::Write) {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn arg_expression() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +type A<const N: usize> = [u32; N];
 +fn main() {
 +    let a: $0A<{ 1 + 1 }>;
 +}
 +"#,
 +            r#"
 +type A<const N: usize> = [u32; N];
 +fn main() {
 +    let a: [u32; { 1 + 1 }];
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn alias_instance_generic_path() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +type A<const N: usize> = [u32; N];
 +fn main() {
 +    let a: $0A<u32::MAX>;
 +}
 +"#,
 +            r#"
 +type A<const N: usize> = [u32; N];
 +fn main() {
 +    let a: [u32; u32::MAX];
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn generic_type() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +type A = String;
 +fn f(a: Vec<$0A>) {}
 +"#,
 +            r#"
 +type A = String;
 +fn f(a: Vec<String>) {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn missing_replacement_param() {
 +        cov_mark::check!(missing_replacement_param);
 +        check_assist_not_applicable(
 +            inline_type_alias,
 +            r#"
 +type A<U> = Vec<T>;
 +fn main() {
 +    let a: $0A;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn full_path_type_is_replaced() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +mod foo {
 +    pub type A = String;
 +}
 +fn main() {
 +    let a: foo::$0A;
 +}
 +"#,
 +            r#"
 +mod foo {
 +    pub type A = String;
 +}
 +fn main() {
 +    let a: String;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn inline_self_type() {
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +struct Strukt;
 +
 +impl Strukt {
 +    fn new() -> Self$0 {}
 +}
 +"#,
 +            r#"
 +struct Strukt;
 +
 +impl Strukt {
 +    fn new() -> Strukt {}
 +}
 +"#,
 +        );
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +struct Strukt<'a, T, const C: usize>(&'a [T; C]);
 +
 +impl<T, const C: usize> Strukt<'_, T, C> {
 +    fn new() -> Self$0 {}
 +}
 +"#,
 +            r#"
 +struct Strukt<'a, T, const C: usize>(&'a [T; C]);
 +
 +impl<T, const C: usize> Strukt<'_, T, C> {
 +    fn new() -> Strukt<'_, T, C> {}
 +}
 +"#,
 +        );
 +        check_assist(
 +            inline_type_alias,
 +            r#"
 +struct Strukt<'a, T, const C: usize>(&'a [T; C]);
 +
 +trait Tr<'b, T> {}
 +
 +impl<T, const C: usize> Tr<'static, u8> for Strukt<'_, T, C> {
 +    fn new() -> Self$0 {}
 +}
 +"#,
 +            r#"
 +struct Strukt<'a, T, const C: usize>(&'a [T; C]);
 +
 +trait Tr<'b, T> {}
 +
 +impl<T, const C: usize> Tr<'static, u8> for Strukt<'_, T, C> {
 +    fn new() -> Strukt<'_, T, C> {}
 +}
 +"#,
 +        );
 +
 +        check_assist_not_applicable(
 +            inline_type_alias,
 +            r#"
 +trait Tr {
 +    fn new() -> Self$0;
 +}
 +"#,
 +        );
 +    }
++
++    mod inline_type_alias_uses {
++        use crate::{handlers::inline_type_alias::inline_type_alias_uses, tests::check_assist};
++
++        #[test]
++        fn inline_uses() {
++            check_assist(
++                inline_type_alias_uses,
++                r#"
++type $0A = u32;
++
++fn foo() {
++    let _: A = 3;
++    let _: A = 4;
++}
++"#,
++                r#"
++type A = u32;
++
++fn foo() {
++    let _: u32 = 3;
++    let _: u32 = 4;
++}
++"#,
++            );
++        }
++
++        #[test]
++        fn inline_uses_across_files() {
++            check_assist(
++                inline_type_alias_uses,
++                r#"
++//- /lib.rs
++mod foo;
++type $0T<E> = Vec<E>;
++fn f() -> T<&str> {
++    vec!["hello"]
++}
++
++//- /foo.rs
++use super::T;
++fn foo() {
++    let _: T<i8> = Vec::new();
++}
++"#,
++                r#"
++//- /lib.rs
++mod foo;
++type T<E> = Vec<E>;
++fn f() -> Vec<&str> {
++    vec!["hello"]
++}
++
++//- /foo.rs
++use super::T;
++fn foo() {
++    let _: Vec<i8> = Vec::new();
++}
++"#,
++            );
++        }
++
++        #[test]
++        fn inline_uses_across_files_2() {
++            check_assist(
++                inline_type_alias_uses,
++                r#"
++//- /lib.rs
++mod foo;
++type $0I = i32;
++
++//- /foo.rs
++use super::I;
++fn foo() {
++    let _: I = 0;
++}
++"#,
++                r#"
++use super::I;
++fn foo() {
++    let _: i32 = 0;
++}
++"#,
++            );
++        }
++    }
 +}
index 6112e09455a47c19c108ea4388346aef778534f7,0000000000000000000000000000000000000000..5242f3b5100cfa9357d322ac8f2cc647def5385f
mode 100644,000000..100644
--- /dev/null
@@@ -1,243 -1,0 +1,243 @@@
-         // If there's a type inferrence underscore, we can offer to replace it with the type in
 +use syntax::{
 +    ast::{Expr, GenericArg},
 +    ast::{LetStmt, Type::InferType},
 +    AstNode, TextRange,
 +};
 +
 +use crate::{
 +    assist_context::{AssistContext, Assists},
 +    AssistId, AssistKind,
 +};
 +
 +// Assist: replace_turbofish_with_explicit_type
 +//
 +// Converts `::<_>` to an explicit type assignment.
 +//
 +// ```
 +// fn make<T>() -> T { ) }
 +// fn main() {
 +//     let a = make$0::<i32>();
 +// }
 +// ```
 +// ->
 +// ```
 +// fn make<T>() -> T { ) }
 +// fn main() {
 +//     let a: i32 = make();
 +// }
 +// ```
 +pub(crate) fn replace_turbofish_with_explicit_type(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +) -> Option<()> {
 +    let let_stmt = ctx.find_node_at_offset::<LetStmt>()?;
 +
 +    let initializer = let_stmt.initializer()?;
 +
 +    let generic_args = match &initializer {
 +        Expr::MethodCallExpr(ce) => ce.generic_arg_list()?,
 +        Expr::CallExpr(ce) => {
 +            if let Expr::PathExpr(pe) = ce.expr()? {
 +                pe.path()?.segment()?.generic_arg_list()?
 +            } else {
 +                cov_mark::hit!(not_applicable_if_non_path_function_call);
 +                return None;
 +            }
 +        }
 +        _ => {
 +            cov_mark::hit!(not_applicable_if_non_function_call_initializer);
 +            return None;
 +        }
 +    };
 +
 +    // Find range of ::<_>
 +    let colon2 = generic_args.coloncolon_token()?;
 +    let r_angle = generic_args.r_angle_token()?;
 +    let turbofish_range = TextRange::new(colon2.text_range().start(), r_angle.text_range().end());
 +
 +    let turbofish_args: Vec<GenericArg> = generic_args.generic_args().into_iter().collect();
 +
 +    // Find type of ::<_>
 +    if turbofish_args.len() != 1 {
 +        cov_mark::hit!(not_applicable_if_not_single_arg);
 +        return None;
 +    }
 +
 +    // An improvement would be to check that this is correctly part of the return value of the
 +    // function call, or sub in the actual return type.
 +    let turbofish_type = &turbofish_args[0];
 +
 +    let initializer_start = initializer.syntax().text_range().start();
 +    if ctx.offset() > turbofish_range.end() || ctx.offset() < initializer_start {
 +        cov_mark::hit!(not_applicable_outside_turbofish);
 +        return None;
 +    }
 +
 +    if let None = let_stmt.colon_token() {
 +        // If there's no colon in a let statement, then there is no explicit type.
 +        // let x = fn::<...>();
 +        let ident_range = let_stmt.pat()?.syntax().text_range();
 +
 +        return acc.add(
 +            AssistId("replace_turbofish_with_explicit_type", AssistKind::RefactorRewrite),
 +            "Replace turbofish with explicit type",
 +            TextRange::new(initializer_start, turbofish_range.end()),
 +            |builder| {
 +                builder.insert(ident_range.end(), format!(": {}", turbofish_type));
 +                builder.delete(turbofish_range);
 +            },
 +        );
 +    } else if let Some(InferType(t)) = let_stmt.ty() {
++        // If there's a type inference underscore, we can offer to replace it with the type in
 +        // the turbofish.
 +        // let x: _ = fn::<...>();
 +        let underscore_range = t.syntax().text_range();
 +
 +        return acc.add(
 +            AssistId("replace_turbofish_with_explicit_type", AssistKind::RefactorRewrite),
 +            "Replace `_` with turbofish type",
 +            turbofish_range,
 +            |builder| {
 +                builder.replace(underscore_range, turbofish_type.to_string());
 +                builder.delete(turbofish_range);
 +            },
 +        );
 +    }
 +
 +    None
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use super::*;
 +
 +    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
 +
 +    #[test]
 +    fn replaces_turbofish_for_vec_string() {
 +        check_assist(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a = make$0::<Vec<String>>();
 +}
 +"#,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a: Vec<String> = make();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn replaces_method_calls() {
 +        // foo.make() is a method call which uses a different expr in the let initializer
 +        check_assist(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a = foo.make$0::<Vec<String>>();
 +}
 +"#,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a: Vec<String> = foo.make();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn replace_turbofish_target() {
 +        check_assist_target(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a = $0make::<Vec<String>>();
 +}
 +"#,
 +            r#"make::<Vec<String>>"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_outside_turbofish() {
 +        cov_mark::check!(not_applicable_outside_turbofish);
 +        check_assist_not_applicable(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let $0a = make::<Vec<String>>();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn replace_inferred_type_placeholder() {
 +        check_assist(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a: _ = make$0::<Vec<String>>();
 +}
 +"#,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a: Vec<String> = make();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_constant_initializer() {
 +        cov_mark::check!(not_applicable_if_non_function_call_initializer);
 +        check_assist_not_applicable(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a = "foo"$0;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_non_path_function_call() {
 +        cov_mark::check!(not_applicable_if_non_path_function_call);
 +        check_assist_not_applicable(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    $0let a = (|| {})();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn non_applicable_multiple_generic_args() {
 +        cov_mark::check!(not_applicable_if_not_single_arg);
 +        check_assist_not_applicable(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a = make$0::<Vec<String>, i32>();
 +}
 +"#,
 +        );
 +    }
 +}
index fe87aa15fcf23ffa542f5ac3071ba67585f0668e,0000000000000000000000000000000000000000..7fb35143fa2ff1303459cedde3579f16221d7fa7
mode 100644,000000..100644
--- /dev/null
@@@ -1,309 -1,0 +1,310 @@@
 +//! `assists` crate provides a bunch of code assists, also known as code actions
 +//! (in LSP) or intentions (in IntelliJ).
 +//!
 +//! An assist is a micro-refactoring, which is automatically activated in
 +//! certain context. For example, if the cursor is over `,`, a "swap `,`" assist
 +//! becomes available.
 +//!
 +//! ## Assists Guidelines
 +//!
 +//! Assists are the main mechanism to deliver advanced IDE features to the user,
 +//! so we should pay extra attention to the UX.
 +//!
 +//! The power of assists comes from their context-awareness. The main problem
 +//! with IDE features is that there are a lot of them, and it's hard to teach
 +//! the user what's available. Assists solve this problem nicely: 💡 signifies
 +//! that *something* is possible, and clicking on it reveals a *short* list of
 +//! actions. Contrast it with Emacs `M-x`, which just spits an infinite list of
 +//! all the features.
 +//!
 +//! Here are some considerations when creating a new assist:
 +//!
 +//! * It's good to preserve semantics, and it's good to keep the code compiling,
 +//!   but it isn't necessary. Example: "flip binary operation" might change
 +//!   semantics.
 +//! * Assist shouldn't necessary make the code "better". A lot of assist come in
 +//!   pairs: "if let <-> match".
 +//! * Assists should have as narrow scope as possible. Each new assists greatly
 +//!   improves UX for cases where the user actually invokes it, but it makes UX
 +//!   worse for every case where the user clicks 💡 to invoke some *other*
 +//!   assist. So, a rarely useful assist which is always applicable can be a net
 +//!   negative.
 +//! * Rarely useful actions are tricky. Sometimes there are features which are
 +//!   clearly useful to some users, but are just noise most of the time. We
 +//!   don't have a good solution here, our current approach is to make this
 +//!   functionality available only if assist is applicable to the whole
 +//!   selection. Example: `sort_items` sorts items alphabetically. Naively, it
 +//!   should be available more or less everywhere, which isn't useful. So
 +//!   instead we only show it if the user *selects* the items they want to sort.
 +//! * Consider grouping related assists together (see [`Assists::add_group`]).
 +//! * Make assists robust. If the assist depends on results of type-inference too
 +//!   much, it might only fire in fully-correct code. This makes assist less
 +//!   useful and (worse) less predictable. The user should have a clear
 +//!   intuition when each particular assist is available.
 +//! * Make small assists, which compose. Example: rather than auto-importing
 +//!   enums in `add_missing_match_arms`, we use fully-qualified names. There's a
 +//!   separate assist to shorten a fully-qualified name.
 +//! * Distinguish between assists and fixits for diagnostics. Internally, fixits
 +//!   and assists are equivalent. They have the same "show a list + invoke a
 +//!   single element" workflow, and both use [`Assist`] data structure. The main
 +//!   difference is in the UX: while 💡 looks only at the cursor position,
 +//!   diagnostics squigglies and fixits are calculated for the whole file and
 +//!   are presented to the user eagerly. So, diagnostics should be fixable
 +//!   errors, while assists can be just suggestions for an alternative way to do
 +//!   something. If something *could* be a diagnostic, it should be a
 +//!   diagnostic. Conversely, it might be valuable to turn a diagnostic with a
 +//!   lot of false errors into an assist.
 +//!
 +//! See also this post:
 +//! <https://rust-analyzer.github.io/blog/2020/09/28/how-to-make-a-light-bulb.html>
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +#[allow(unused)]
 +macro_rules! eprintln {
 +    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
 +}
 +
 +mod assist_config;
 +mod assist_context;
 +#[cfg(test)]
 +mod tests;
 +pub mod utils;
 +
 +use hir::Semantics;
 +use ide_db::{base_db::FileRange, RootDatabase};
 +use syntax::TextRange;
 +
 +pub(crate) use crate::assist_context::{AssistContext, Assists};
 +
 +pub use assist_config::AssistConfig;
 +pub use ide_db::assists::{
 +    Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel, SingleResolve,
 +};
 +
 +/// Return all the assists applicable at the given position.
 +///
 +// NOTE: We don't have a `Feature: ` section for assists, they are special-cased
 +// in the manual.
 +pub fn assists(
 +    db: &RootDatabase,
 +    config: &AssistConfig,
 +    resolve: AssistResolveStrategy,
 +    range: FileRange,
 +) -> Vec<Assist> {
 +    let sema = Semantics::new(db);
 +    let ctx = AssistContext::new(sema, config, range);
 +    let mut acc = Assists::new(&ctx, resolve);
 +    handlers::all().iter().for_each(|handler| {
 +        handler(&mut acc, &ctx);
 +    });
 +    acc.finish()
 +}
 +
 +mod handlers {
 +    use crate::{AssistContext, Assists};
 +
 +    pub(crate) type Handler = fn(&mut Assists, &AssistContext<'_>) -> Option<()>;
 +
 +    mod add_explicit_type;
 +    mod add_label_to_loop;
 +    mod add_lifetime_to_type;
 +    mod add_missing_impl_members;
 +    mod add_turbo_fish;
 +    mod apply_demorgan;
 +    mod auto_import;
 +    mod change_visibility;
 +    mod convert_bool_then;
 +    mod convert_comment_block;
 +    mod convert_integer_literal;
 +    mod convert_into_to_from;
 +    mod convert_iter_for_each_to_for;
 +    mod convert_let_else_to_match;
 +    mod convert_tuple_struct_to_named_struct;
 +    mod convert_to_guarded_return;
 +    mod convert_while_to_loop;
 +    mod destructure_tuple_binding;
 +    mod expand_glob_import;
 +    mod extract_function;
 +    mod extract_module;
 +    mod extract_struct_from_enum_variant;
 +    mod extract_type_alias;
 +    mod extract_variable;
 +    mod add_missing_match_arms;
 +    mod fix_visibility;
 +    mod flip_binexpr;
 +    mod flip_comma;
 +    mod flip_trait_bound;
 +    mod generate_constant;
 +    mod generate_default_from_enum_variant;
 +    mod generate_default_from_new;
 +    mod generate_deref;
 +    mod generate_derive;
 +    mod generate_documentation_template;
 +    mod generate_enum_is_method;
 +    mod generate_enum_projection_method;
 +    mod generate_enum_variant;
 +    mod generate_from_impl_for_enum;
 +    mod generate_function;
 +    mod generate_getter;
 +    mod generate_impl;
 +    mod generate_is_empty_from_len;
 +    mod generate_new;
 +    mod generate_setter;
 +    mod generate_delegate_methods;
 +    mod add_return_type;
 +    mod inline_call;
 +    mod inline_local_variable;
 +    mod inline_type_alias;
 +    mod introduce_named_lifetime;
 +    mod invert_if;
 +    mod merge_imports;
 +    mod merge_match_arms;
 +    mod move_bounds;
 +    mod move_guard;
 +    mod move_module_to_file;
 +    mod move_to_mod_rs;
 +    mod move_from_mod_rs;
 +    mod number_representation;
 +    mod promote_local_to_const;
 +    mod pull_assignment_up;
 +    mod qualify_path;
 +    mod qualify_method_call;
 +    mod raw_string;
 +    mod remove_dbg;
 +    mod remove_mut;
 +    mod remove_unused_param;
 +    mod reorder_fields;
 +    mod reorder_impl_items;
 +    mod replace_try_expr_with_match;
 +    mod replace_derive_with_manual_impl;
 +    mod replace_if_let_with_match;
 +    mod introduce_named_generic;
 +    mod replace_let_with_if_let;
 +    mod replace_qualified_name_with_use;
 +    mod replace_string_with_char;
 +    mod replace_turbofish_with_explicit_type;
 +    mod split_import;
 +    mod sort_items;
 +    mod toggle_ignore;
 +    mod unmerge_use;
 +    mod unnecessary_async;
 +    mod unwrap_block;
 +    mod unwrap_result_return_type;
 +    mod wrap_return_type_in_result;
 +
 +    pub(crate) fn all() -> &'static [Handler] {
 +        &[
 +            // These are alphabetic for the foolish consistency
 +            add_explicit_type::add_explicit_type,
 +            add_label_to_loop::add_label_to_loop,
 +            add_missing_match_arms::add_missing_match_arms,
 +            add_lifetime_to_type::add_lifetime_to_type,
 +            add_return_type::add_return_type,
 +            add_turbo_fish::add_turbo_fish,
 +            apply_demorgan::apply_demorgan,
 +            auto_import::auto_import,
 +            change_visibility::change_visibility,
 +            convert_bool_then::convert_bool_then_to_if,
 +            convert_bool_then::convert_if_to_bool_then,
 +            convert_comment_block::convert_comment_block,
 +            convert_integer_literal::convert_integer_literal,
 +            convert_into_to_from::convert_into_to_from,
 +            convert_iter_for_each_to_for::convert_iter_for_each_to_for,
 +            convert_iter_for_each_to_for::convert_for_loop_with_for_each,
 +            convert_let_else_to_match::convert_let_else_to_match,
 +            convert_to_guarded_return::convert_to_guarded_return,
 +            convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
 +            convert_while_to_loop::convert_while_to_loop,
 +            destructure_tuple_binding::destructure_tuple_binding,
 +            expand_glob_import::expand_glob_import,
 +            extract_struct_from_enum_variant::extract_struct_from_enum_variant,
 +            extract_type_alias::extract_type_alias,
 +            fix_visibility::fix_visibility,
 +            flip_binexpr::flip_binexpr,
 +            flip_comma::flip_comma,
 +            flip_trait_bound::flip_trait_bound,
 +            generate_constant::generate_constant,
 +            generate_default_from_enum_variant::generate_default_from_enum_variant,
 +            generate_default_from_new::generate_default_from_new,
 +            generate_derive::generate_derive,
 +            generate_documentation_template::generate_documentation_template,
 +            generate_documentation_template::generate_doc_example,
 +            generate_enum_is_method::generate_enum_is_method,
 +            generate_enum_projection_method::generate_enum_as_method,
 +            generate_enum_projection_method::generate_enum_try_into_method,
 +            generate_enum_variant::generate_enum_variant,
 +            generate_from_impl_for_enum::generate_from_impl_for_enum,
 +            generate_function::generate_function,
 +            generate_impl::generate_impl,
 +            generate_is_empty_from_len::generate_is_empty_from_len,
 +            generate_new::generate_new,
 +            inline_call::inline_call,
 +            inline_call::inline_into_callers,
 +            inline_local_variable::inline_local_variable,
 +            inline_type_alias::inline_type_alias,
++            inline_type_alias::inline_type_alias_uses,
 +            introduce_named_generic::introduce_named_generic,
 +            introduce_named_lifetime::introduce_named_lifetime,
 +            invert_if::invert_if,
 +            merge_imports::merge_imports,
 +            merge_match_arms::merge_match_arms,
 +            move_bounds::move_bounds_to_where_clause,
 +            move_guard::move_arm_cond_to_match_guard,
 +            move_guard::move_guard_to_arm_body,
 +            move_module_to_file::move_module_to_file,
 +            move_to_mod_rs::move_to_mod_rs,
 +            move_from_mod_rs::move_from_mod_rs,
 +            number_representation::reformat_number_literal,
 +            pull_assignment_up::pull_assignment_up,
 +            promote_local_to_const::promote_local_to_const,
 +            qualify_path::qualify_path,
 +            qualify_method_call::qualify_method_call,
 +            raw_string::add_hash,
 +            raw_string::make_usual_string,
 +            raw_string::remove_hash,
 +            remove_dbg::remove_dbg,
 +            remove_mut::remove_mut,
 +            remove_unused_param::remove_unused_param,
 +            reorder_fields::reorder_fields,
 +            reorder_impl_items::reorder_impl_items,
 +            replace_try_expr_with_match::replace_try_expr_with_match,
 +            replace_derive_with_manual_impl::replace_derive_with_manual_impl,
 +            replace_if_let_with_match::replace_if_let_with_match,
 +            replace_if_let_with_match::replace_match_with_if_let,
 +            replace_let_with_if_let::replace_let_with_if_let,
 +            replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type,
 +            replace_qualified_name_with_use::replace_qualified_name_with_use,
 +            sort_items::sort_items,
 +            split_import::split_import,
 +            toggle_ignore::toggle_ignore,
 +            unmerge_use::unmerge_use,
 +            unnecessary_async::unnecessary_async,
 +            unwrap_block::unwrap_block,
 +            unwrap_result_return_type::unwrap_result_return_type,
 +            wrap_return_type_in_result::wrap_return_type_in_result,
 +            // These are manually sorted for better priorities. By default,
 +            // priority is determined by the size of the target range (smaller
 +            // target wins). If the ranges are equal, position in this list is
 +            // used as a tie-breaker.
 +            add_missing_impl_members::add_missing_impl_members,
 +            add_missing_impl_members::add_missing_default_members,
 +            //
 +            replace_string_with_char::replace_string_with_char,
 +            replace_string_with_char::replace_char_with_string,
 +            raw_string::make_raw_string,
 +            //
 +            extract_variable::extract_variable,
 +            extract_function::extract_function,
 +            extract_module::extract_module,
 +            //
 +            generate_getter::generate_getter,
 +            generate_getter::generate_getter_mut,
 +            generate_setter::generate_setter,
 +            generate_delegate_methods::generate_delegate_methods,
 +            generate_deref::generate_deref,
 +            // Are you sure you want to add new assist here, and not to the
 +            // sorted list above?
 +        ]
 +    }
 +}
index 6eaab48a32ba54e567f0e958f9a52d8cebbe9bbe,0000000000000000000000000000000000000000..22319f36134fb6b6d0ee259ae1f2245754d36917
mode 100644,000000..100644
--- /dev/null
@@@ -1,2259 -1,0 +1,2284 @@@
 +//! Generated by `sourcegen_assists_docs`, do not edit by hand.
 +
 +use super::check_doc_test;
 +
 +#[test]
 +fn doctest_add_explicit_type() {
 +    check_doc_test(
 +        "add_explicit_type",
 +        r#####"
 +fn main() {
 +    let x$0 = 92;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let x: i32 = 92;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_hash() {
 +    check_doc_test(
 +        "add_hash",
 +        r#####"
 +fn main() {
 +    r#"Hello,$0 World!"#;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    r##"Hello, World!"##;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_impl_default_members() {
 +    check_doc_test(
 +        "add_impl_default_members",
 +        r#####"
 +trait Trait {
 +    type X;
 +    fn foo(&self);
 +    fn bar(&self) {}
 +}
 +
 +impl Trait for () {
 +    type X = ();
 +    fn foo(&self) {}$0
 +}
 +"#####,
 +        r#####"
 +trait Trait {
 +    type X;
 +    fn foo(&self);
 +    fn bar(&self) {}
 +}
 +
 +impl Trait for () {
 +    type X = ();
 +    fn foo(&self) {}
 +
 +    $0fn bar(&self) {}
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_impl_missing_members() {
 +    check_doc_test(
 +        "add_impl_missing_members",
 +        r#####"
 +trait Trait<T> {
 +    type X;
 +    fn foo(&self) -> T;
 +    fn bar(&self) {}
 +}
 +
 +impl Trait<u32> for () {$0
 +
 +}
 +"#####,
 +        r#####"
 +trait Trait<T> {
 +    type X;
 +    fn foo(&self) -> T;
 +    fn bar(&self) {}
 +}
 +
 +impl Trait<u32> for () {
 +    $0type X;
 +
 +    fn foo(&self) -> u32 {
 +        todo!()
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_label_to_loop() {
 +    check_doc_test(
 +        "add_label_to_loop",
 +        r#####"
 +fn main() {
 +    loop$0 {
 +        break;
 +        continue;
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    'l: loop {
 +        break 'l;
 +        continue 'l;
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_lifetime_to_type() {
 +    check_doc_test(
 +        "add_lifetime_to_type",
 +        r#####"
 +struct Point {
 +    x: &$0u32,
 +    y: u32,
 +}
 +"#####,
 +        r#####"
 +struct Point<'a> {
 +    x: &'a u32,
 +    y: u32,
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_missing_match_arms() {
 +    check_doc_test(
 +        "add_missing_match_arms",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        $0
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        $0Action::Move { distance } => todo!(),
 +        Action::Stop => todo!(),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_return_type() {
 +    check_doc_test(
 +        "add_return_type",
 +        r#####"
 +fn foo() { 4$02i32 }
 +"#####,
 +        r#####"
 +fn foo() -> i32 { 42i32 }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_turbo_fish() {
 +    check_doc_test(
 +        "add_turbo_fish",
 +        r#####"
 +fn make<T>() -> T { todo!() }
 +fn main() {
 +    let x = make$0();
 +}
 +"#####,
 +        r#####"
 +fn make<T>() -> T { todo!() }
 +fn main() {
 +    let x = make::<${0:_}>();
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_apply_demorgan() {
 +    check_doc_test(
 +        "apply_demorgan",
 +        r#####"
 +fn main() {
 +    if x != 4 ||$0 y < 3.14 {}
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    if !(x == 4 && y >= 3.14) {}
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_auto_import() {
 +    check_doc_test(
 +        "auto_import",
 +        r#####"
 +fn main() {
 +    let map = HashMap$0::new();
 +}
 +pub mod std { pub mod collections { pub struct HashMap { } } }
 +"#####,
 +        r#####"
 +use std::collections::HashMap;
 +
 +fn main() {
 +    let map = HashMap::new();
 +}
 +pub mod std { pub mod collections { pub struct HashMap { } } }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_change_visibility() {
 +    check_doc_test(
 +        "change_visibility",
 +        r#####"
 +$0fn frobnicate() {}
 +"#####,
 +        r#####"
 +pub(crate) fn frobnicate() {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_bool_then_to_if() {
 +    check_doc_test(
 +        "convert_bool_then_to_if",
 +        r#####"
 +//- minicore: bool_impl
 +fn main() {
 +    (0 == 0).then$0(|| val)
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    if 0 == 0 {
 +        Some(val)
 +    } else {
 +        None
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_for_loop_with_for_each() {
 +    check_doc_test(
 +        "convert_for_loop_with_for_each",
 +        r#####"
 +fn main() {
 +    let x = vec![1, 2, 3];
 +    for$0 v in x {
 +        let y = v * 2;
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let x = vec![1, 2, 3];
 +    x.into_iter().for_each(|v| {
 +        let y = v * 2;
 +    });
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_if_to_bool_then() {
 +    check_doc_test(
 +        "convert_if_to_bool_then",
 +        r#####"
 +//- minicore: option
 +fn main() {
 +    if$0 cond {
 +        Some(val)
 +    } else {
 +        None
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    cond.then(|| val)
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_integer_literal() {
 +    check_doc_test(
 +        "convert_integer_literal",
 +        r#####"
 +const _: i32 = 10$0;
 +"#####,
 +        r#####"
 +const _: i32 = 0b1010;
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_into_to_from() {
 +    check_doc_test(
 +        "convert_into_to_from",
 +        r#####"
 +//- minicore: from
 +impl $0Into<Thing> for usize {
 +    fn into(self) -> Thing {
 +        Thing {
 +            b: self.to_string(),
 +            a: self
 +        }
 +    }
 +}
 +"#####,
 +        r#####"
 +impl From<usize> for Thing {
 +    fn from(val: usize) -> Self {
 +        Thing {
 +            b: val.to_string(),
 +            a: val
 +        }
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_iter_for_each_to_for() {
 +    check_doc_test(
 +        "convert_iter_for_each_to_for",
 +        r#####"
 +//- minicore: iterators
 +use core::iter;
 +fn main() {
 +    let iter = iter::repeat((9, 2));
 +    iter.for_each$0(|(x, y)| {
 +        println!("x: {}, y: {}", x, y);
 +    });
 +}
 +"#####,
 +        r#####"
 +use core::iter;
 +fn main() {
 +    let iter = iter::repeat((9, 2));
 +    for (x, y) in iter {
 +        println!("x: {}, y: {}", x, y);
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_let_else_to_match() {
 +    check_doc_test(
 +        "convert_let_else_to_match",
 +        r#####"
 +fn main() {
 +    let Ok(mut x) = f() else$0 { return };
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let mut x = match f() {
 +        Ok(x) => x,
 +        _ => return,
 +    };
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_to_guarded_return() {
 +    check_doc_test(
 +        "convert_to_guarded_return",
 +        r#####"
 +fn main() {
 +    $0if cond {
 +        foo();
 +        bar();
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    if !cond {
 +        return;
 +    }
 +    foo();
 +    bar();
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_tuple_struct_to_named_struct() {
 +    check_doc_test(
 +        "convert_tuple_struct_to_named_struct",
 +        r#####"
 +struct Point$0(f32, f32);
 +
 +impl Point {
 +    pub fn new(x: f32, y: f32) -> Self {
 +        Point(x, y)
 +    }
 +
 +    pub fn x(&self) -> f32 {
 +        self.0
 +    }
 +
 +    pub fn y(&self) -> f32 {
 +        self.1
 +    }
 +}
 +"#####,
 +        r#####"
 +struct Point { field1: f32, field2: f32 }
 +
 +impl Point {
 +    pub fn new(x: f32, y: f32) -> Self {
 +        Point { field1: x, field2: y }
 +    }
 +
 +    pub fn x(&self) -> f32 {
 +        self.field1
 +    }
 +
 +    pub fn y(&self) -> f32 {
 +        self.field2
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_while_to_loop() {
 +    check_doc_test(
 +        "convert_while_to_loop",
 +        r#####"
 +fn main() {
 +    $0while cond {
 +        foo();
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    loop {
 +        if !cond {
 +            break;
 +        }
 +        foo();
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_destructure_tuple_binding() {
 +    check_doc_test(
 +        "destructure_tuple_binding",
 +        r#####"
 +fn main() {
 +    let $0t = (1,2);
 +    let v = t.0;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let ($0_0, _1) = (1,2);
 +    let v = _0;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_expand_glob_import() {
 +    check_doc_test(
 +        "expand_glob_import",
 +        r#####"
 +mod foo {
 +    pub struct Bar;
 +    pub struct Baz;
 +}
 +
 +use foo::*$0;
 +
 +fn qux(bar: Bar, baz: Baz) {}
 +"#####,
 +        r#####"
 +mod foo {
 +    pub struct Bar;
 +    pub struct Baz;
 +}
 +
 +use foo::{Bar, Baz};
 +
 +fn qux(bar: Bar, baz: Baz) {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_extract_function() {
 +    check_doc_test(
 +        "extract_function",
 +        r#####"
 +fn main() {
 +    let n = 1;
 +    $0let m = n + 2;
 +    // calculate
 +    let k = m + n;$0
 +    let g = 3;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let n = 1;
 +    fun_name(n);
 +    let g = 3;
 +}
 +
 +fn $0fun_name(n: i32) {
 +    let m = n + 2;
 +    // calculate
 +    let k = m + n;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_extract_module() {
 +    check_doc_test(
 +        "extract_module",
 +        r#####"
 +$0fn foo(name: i32) -> i32 {
 +    name + 1
 +}$0
 +
 +fn bar(name: i32) -> i32 {
 +    name + 2
 +}
 +"#####,
 +        r#####"
 +mod modname {
 +    pub(crate) fn foo(name: i32) -> i32 {
 +        name + 1
 +    }
 +}
 +
 +fn bar(name: i32) -> i32 {
 +    name + 2
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_extract_struct_from_enum_variant() {
 +    check_doc_test(
 +        "extract_struct_from_enum_variant",
 +        r#####"
 +enum A { $0One(u32, u32) }
 +"#####,
 +        r#####"
 +struct One(u32, u32);
 +
 +enum A { One(One) }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_extract_type_alias() {
 +    check_doc_test(
 +        "extract_type_alias",
 +        r#####"
 +struct S {
 +    field: $0(u8, u8, u8)$0,
 +}
 +"#####,
 +        r#####"
 +type $0Type = (u8, u8, u8);
 +
 +struct S {
 +    field: Type,
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_extract_variable() {
 +    check_doc_test(
 +        "extract_variable",
 +        r#####"
 +fn main() {
 +    $0(1 + 2)$0 * 4;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let $0var_name = (1 + 2);
 +    var_name * 4;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_fix_visibility() {
 +    check_doc_test(
 +        "fix_visibility",
 +        r#####"
 +mod m {
 +    fn frobnicate() {}
 +}
 +fn main() {
 +    m::frobnicate$0() {}
 +}
 +"#####,
 +        r#####"
 +mod m {
 +    $0pub(crate) fn frobnicate() {}
 +}
 +fn main() {
 +    m::frobnicate() {}
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_flip_binexpr() {
 +    check_doc_test(
 +        "flip_binexpr",
 +        r#####"
 +fn main() {
 +    let _ = 90 +$0 2;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let _ = 2 + 90;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_flip_comma() {
 +    check_doc_test(
 +        "flip_comma",
 +        r#####"
 +fn main() {
 +    ((1, 2),$0 (3, 4));
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    ((3, 4), (1, 2));
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_flip_trait_bound() {
 +    check_doc_test(
 +        "flip_trait_bound",
 +        r#####"
 +fn foo<T: Clone +$0 Copy>() { }
 +"#####,
 +        r#####"
 +fn foo<T: Copy + Clone>() { }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_constant() {
 +    check_doc_test(
 +        "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 doctest_generate_default_from_enum_variant() {
 +    check_doc_test(
 +        "generate_default_from_enum_variant",
 +        r#####"
 +enum Version {
 + Undefined,
 + Minor$0,
 + Major,
 +}
 +"#####,
 +        r#####"
 +enum Version {
 + Undefined,
 + Minor,
 + Major,
 +}
 +
 +impl Default for Version {
 +    fn default() -> Self {
 +        Self::Minor
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_default_from_new() {
 +    check_doc_test(
 +        "generate_default_from_new",
 +        r#####"
 +struct Example { _inner: () }
 +
 +impl Example {
 +    pub fn n$0ew() -> Self {
 +        Self { _inner: () }
 +    }
 +}
 +"#####,
 +        r#####"
 +struct Example { _inner: () }
 +
 +impl Example {
 +    pub fn new() -> Self {
 +        Self { _inner: () }
 +    }
 +}
 +
 +impl Default for Example {
 +    fn default() -> Self {
 +        Self::new()
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_delegate_methods() {
 +    check_doc_test(
 +        "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 doctest_generate_deref() {
 +    check_doc_test(
 +        "generate_deref",
 +        r#####"
 +//- minicore: deref, deref_mut
 +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 doctest_generate_derive() {
 +    check_doc_test(
 +        "generate_derive",
 +        r#####"
 +struct Point {
 +    x: u32,
 +    y: u32,$0
 +}
 +"#####,
 +        r#####"
 +#[derive($0)]
 +struct Point {
 +    x: u32,
 +    y: u32,
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_doc_example() {
 +    check_doc_test(
 +        "generate_doc_example",
 +        r#####"
 +/// Adds two numbers.$0
 +pub fn add(a: i32, b: i32) -> i32 { a + b }
 +"#####,
 +        r#####"
 +/// Adds two numbers.
 +///
 +/// # Examples
 +///
 +/// ```
 +/// use test::add;
 +///
 +/// assert_eq!(add(a, b), );
 +/// ```
 +pub fn add(a: i32, b: i32) -> i32 { a + b }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_documentation_template() {
 +    check_doc_test(
 +        "generate_documentation_template",
 +        r#####"
 +pub struct S;
 +impl S {
 +    pub unsafe fn set_len$0(&mut self, len: usize) -> Result<(), std::io::Error> {
 +        /* ... */
 +    }
 +}
 +"#####,
 +        r#####"
 +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> {
 +        /* ... */
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_enum_as_method() {
 +    check_doc_test(
 +        "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 doctest_generate_enum_is_method() {
 +    check_doc_test(
 +        "generate_enum_is_method",
 +        r#####"
 +enum Version {
 + Undefined,
 + Minor$0,
 + Major,
 +}
 +"#####,
 +        r#####"
 +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)
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_enum_try_into_method() {
 +    check_doc_test(
 +        "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 doctest_generate_enum_variant() {
 +    check_doc_test(
 +        "generate_enum_variant",
 +        r#####"
 +enum Countries {
 +    Ghana,
 +}
 +
 +fn main() {
 +    let country = Countries::Lesotho$0;
 +}
 +"#####,
 +        r#####"
 +enum Countries {
 +    Ghana,
 +    Lesotho,
 +}
 +
 +fn main() {
 +    let country = Countries::Lesotho;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_from_impl_for_enum() {
 +    check_doc_test(
 +        "generate_from_impl_for_enum",
 +        r#####"
 +enum A { $0One(u32) }
 +"#####,
 +        r#####"
 +enum A { One(u32) }
 +
 +impl From<u32> for A {
 +    fn from(v: u32) -> Self {
 +        Self::One(v)
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_function() {
 +    check_doc_test(
 +        "generate_function",
 +        r#####"
 +struct Baz;
 +fn baz() -> Baz { Baz }
 +fn foo() {
 +    bar$0("", baz());
 +}
 +
 +"#####,
 +        r#####"
 +struct Baz;
 +fn baz() -> Baz { Baz }
 +fn foo() {
 +    bar("", baz());
 +}
 +
 +fn bar(arg: &str, baz: Baz) ${0:-> _} {
 +    todo!()
 +}
 +
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_getter() {
 +    check_doc_test(
 +        "generate_getter",
 +        r#####"
 +//- minicore: as_ref
 +pub struct String;
 +impl AsRef<str> for String {
 +    fn as_ref(&self) -> &str {
 +        ""
 +    }
 +}
 +
 +struct Person {
 +    nam$0e: String,
 +}
 +"#####,
 +        r#####"
 +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()
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_getter_mut() {
 +    check_doc_test(
 +        "generate_getter_mut",
 +        r#####"
 +struct Person {
 +    nam$0e: String,
 +}
 +"#####,
 +        r#####"
 +struct Person {
 +    name: String,
 +}
 +
 +impl Person {
 +    fn $0name_mut(&mut self) -> &mut String {
 +        &mut self.name
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_impl() {
 +    check_doc_test(
 +        "generate_impl",
 +        r#####"
 +struct Ctx<T: Clone> {
 +    data: T,$0
 +}
 +"#####,
 +        r#####"
 +struct Ctx<T: Clone> {
 +    data: T,
 +}
 +
 +impl<T: Clone> Ctx<T> {
 +    $0
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_is_empty_from_len() {
 +    check_doc_test(
 +        "generate_is_empty_from_len",
 +        r#####"
 +struct MyStruct { data: Vec<String> }
 +
 +impl MyStruct {
 +    #[must_use]
 +    p$0ub fn len(&self) -> usize {
 +        self.data.len()
 +    }
 +}
 +"#####,
 +        r#####"
 +struct MyStruct { data: Vec<String> }
 +
 +impl MyStruct {
 +    #[must_use]
 +    pub fn len(&self) -> usize {
 +        self.data.len()
 +    }
 +
 +    #[must_use]
 +    pub fn is_empty(&self) -> bool {
 +        self.len() == 0
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_new() {
 +    check_doc_test(
 +        "generate_new",
 +        r#####"
 +struct Ctx<T: Clone> {
 +     data: T,$0
 +}
 +"#####,
 +        r#####"
 +struct Ctx<T: Clone> {
 +     data: T,
 +}
 +
 +impl<T: Clone> Ctx<T> {
 +    fn $0new(data: T) -> Self { Self { data } }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_generate_setter() {
 +    check_doc_test(
 +        "generate_setter",
 +        r#####"
 +struct Person {
 +    nam$0e: String,
 +}
 +"#####,
 +        r#####"
 +struct Person {
 +    name: String,
 +}
 +
 +impl Person {
 +    fn set_name(&mut self, name: String) {
 +        self.name = name;
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_inline_call() {
 +    check_doc_test(
 +        "inline_call",
 +        r#####"
 +//- minicore: option
 +fn foo(name: Option<&str>) {
 +    let name = name.unwrap$0();
 +}
 +"#####,
 +        r#####"
 +fn foo(name: Option<&str>) {
 +    let name = match name {
 +            Some(val) => val,
 +            None => panic!("called `Option::unwrap()` on a `None` value"),
 +        };
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_inline_into_callers() {
 +    check_doc_test(
 +        "inline_into_callers",
 +        r#####"
 +fn print(_: &str) {}
 +fn foo$0(word: &str) {
 +    if !word.is_empty() {
 +        print(word);
 +    }
 +}
 +fn bar() {
 +    foo("안녕하세요");
 +    foo("여러분");
 +}
 +"#####,
 +        r#####"
 +fn print(_: &str) {}
 +
 +fn bar() {
 +    {
 +        let word = "안녕하세요";
 +        if !word.is_empty() {
 +            print(word);
 +        }
 +    };
 +    {
 +        let word = "여러분";
 +        if !word.is_empty() {
 +            print(word);
 +        }
 +    };
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_inline_local_variable() {
 +    check_doc_test(
 +        "inline_local_variable",
 +        r#####"
 +fn main() {
 +    let x$0 = 1 + 2;
 +    x * 4;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    (1 + 2) * 4;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_inline_type_alias() {
 +    check_doc_test(
 +        "inline_type_alias",
 +        r#####"
 +type A<T = u32> = Vec<T>;
 +
 +fn main() {
 +    let a: $0A;
 +}
 +"#####,
 +        r#####"
 +type A<T = u32> = Vec<T>;
 +
 +fn main() {
 +    let a: Vec<u32>;
 +}
 +"#####,
 +    )
 +}
 +
++#[test]
++fn doctest_inline_type_alias_uses() {
++    check_doc_test(
++        "inline_type_alias_uses",
++        r#####"
++type $0A = i32;
++fn id(x: A) -> A {
++    x
++};
++fn foo() {
++    let _: A = 3;
++}
++"#####,
++        r#####"
++type A = i32;
++fn id(x: i32) -> i32 {
++    x
++};
++fn foo() {
++    let _: i32 = 3;
++}
++"#####,
++    )
++}
++
 +#[test]
 +fn doctest_introduce_named_generic() {
 +    check_doc_test(
 +        "introduce_named_generic",
 +        r#####"
 +fn foo(bar: $0impl Bar) {}
 +"#####,
 +        r#####"
 +fn foo<B: Bar>(bar: B) {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_introduce_named_lifetime() {
 +    check_doc_test(
 +        "introduce_named_lifetime",
 +        r#####"
 +impl Cursor<'_$0> {
 +    fn node(self) -> &SyntaxNode {
 +        match self {
 +            Cursor::Replace(node) | Cursor::Before(node) => node,
 +        }
 +    }
 +}
 +"#####,
 +        r#####"
 +impl<'a> Cursor<'a> {
 +    fn node(self) -> &SyntaxNode {
 +        match self {
 +            Cursor::Replace(node) | Cursor::Before(node) => node,
 +        }
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_invert_if() {
 +    check_doc_test(
 +        "invert_if",
 +        r#####"
 +fn main() {
 +    if$0 !y { A } else { B }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    if y { B } else { A }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_line_to_block() {
 +    check_doc_test(
 +        "line_to_block",
 +        r#####"
 +   // Multi-line$0
 +   // comment
 +"#####,
 +        r#####"
 +  /*
 +  Multi-line
 +  comment
 +  */
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_make_raw_string() {
 +    check_doc_test(
 +        "make_raw_string",
 +        r#####"
 +fn main() {
 +    "Hello,$0 World!";
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    r#"Hello, World!"#;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_make_usual_string() {
 +    check_doc_test(
 +        "make_usual_string",
 +        r#####"
 +fn main() {
 +    r#"Hello,$0 "World!""#;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    "Hello, \"World!\"";
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_merge_imports() {
 +    check_doc_test(
 +        "merge_imports",
 +        r#####"
 +use std::$0fmt::Formatter;
 +use std::io;
 +"#####,
 +        r#####"
 +use std::{fmt::Formatter, io};
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_merge_match_arms() {
 +    check_doc_test(
 +        "merge_match_arms",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        $0Action::Move(..) => foo(),
 +        Action::Stop => foo(),
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move(..) | Action::Stop => foo(),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_arm_cond_to_match_guard() {
 +    check_doc_test(
 +        "move_arm_cond_to_match_guard",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move { distance } => $0if distance > 10 { foo() },
 +        _ => (),
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move { distance } if distance > 10 => foo(),
 +        _ => (),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_bounds_to_where_clause() {
 +    check_doc_test(
 +        "move_bounds_to_where_clause",
 +        r#####"
 +fn apply<T, U, $0F: FnOnce(T) -> U>(f: F, x: T) -> U {
 +    f(x)
 +}
 +"#####,
 +        r#####"
 +fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U {
 +    f(x)
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_from_mod_rs() {
 +    check_doc_test(
 +        "move_from_mod_rs",
 +        r#####"
 +//- /main.rs
 +mod a;
 +//- /a/mod.rs
 +$0fn t() {}$0
 +"#####,
 +        r#####"
 +fn t() {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_guard_to_arm_body() {
 +    check_doc_test(
 +        "move_guard_to_arm_body",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move { distance } $0if distance > 10 => foo(),
 +        _ => (),
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move { distance } => if distance > 10 {
 +            foo()
 +        },
 +        _ => (),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_module_to_file() {
 +    check_doc_test(
 +        "move_module_to_file",
 +        r#####"
 +mod $0foo {
 +    fn t() {}
 +}
 +"#####,
 +        r#####"
 +mod foo;
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_to_mod_rs() {
 +    check_doc_test(
 +        "move_to_mod_rs",
 +        r#####"
 +//- /main.rs
 +mod a;
 +//- /a.rs
 +$0fn t() {}$0
 +"#####,
 +        r#####"
 +fn t() {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_promote_local_to_const() {
 +    check_doc_test(
 +        "promote_local_to_const",
 +        r#####"
 +fn main() {
 +    let foo$0 = true;
 +
 +    if foo {
 +        println!("It's true");
 +    } else {
 +        println!("It's false");
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    const $0FOO: bool = true;
 +
 +    if FOO {
 +        println!("It's true");
 +    } else {
 +        println!("It's false");
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_pull_assignment_up() {
 +    check_doc_test(
 +        "pull_assignment_up",
 +        r#####"
 +fn main() {
 +    let mut foo = 6;
 +
 +    if true {
 +        $0foo = 5;
 +    } else {
 +        foo = 4;
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let mut foo = 6;
 +
 +    foo = if true {
 +        5
 +    } else {
 +        4
 +    };
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_qualify_method_call() {
 +    check_doc_test(
 +        "qualify_method_call",
 +        r#####"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {}
 +}
 +fn main() {
 +    let foo = Foo;
 +    foo.fo$0o();
 +}
 +"#####,
 +        r#####"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {}
 +}
 +fn main() {
 +    let foo = Foo;
 +    Foo::foo(&foo);
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_qualify_path() {
 +    check_doc_test(
 +        "qualify_path",
 +        r#####"
 +fn main() {
 +    let map = HashMap$0::new();
 +}
 +pub mod std { pub mod collections { pub struct HashMap { } } }
 +"#####,
 +        r#####"
 +fn main() {
 +    let map = std::collections::HashMap::new();
 +}
 +pub mod std { pub mod collections { pub struct HashMap { } } }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_reformat_number_literal() {
 +    check_doc_test(
 +        "reformat_number_literal",
 +        r#####"
 +const _: i32 = 1012345$0;
 +"#####,
 +        r#####"
 +const _: i32 = 1_012_345;
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_remove_dbg() {
 +    check_doc_test(
 +        "remove_dbg",
 +        r#####"
 +fn main() {
 +    $0dbg!(92);
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    92;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_remove_hash() {
 +    check_doc_test(
 +        "remove_hash",
 +        r#####"
 +fn main() {
 +    r#"Hello,$0 World!"#;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    r"Hello, World!";
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_remove_mut() {
 +    check_doc_test(
 +        "remove_mut",
 +        r#####"
 +impl Walrus {
 +    fn feed(&mut$0 self, amount: u32) {}
 +}
 +"#####,
 +        r#####"
 +impl Walrus {
 +    fn feed(&self, amount: u32) {}
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_remove_unused_param() {
 +    check_doc_test(
 +        "remove_unused_param",
 +        r#####"
 +fn frobnicate(x: i32$0) {}
 +
 +fn main() {
 +    frobnicate(92);
 +}
 +"#####,
 +        r#####"
 +fn frobnicate() {}
 +
 +fn main() {
 +    frobnicate();
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_reorder_fields() {
 +    check_doc_test(
 +        "reorder_fields",
 +        r#####"
 +struct Foo {foo: i32, bar: i32};
 +const test: Foo = $0Foo {bar: 0, foo: 1}
 +"#####,
 +        r#####"
 +struct Foo {foo: i32, bar: i32};
 +const test: Foo = Foo {foo: 1, bar: 0}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_reorder_impl_items() {
 +    check_doc_test(
 +        "reorder_impl_items",
 +        r#####"
 +trait Foo {
 +    type A;
 +    const B: u8;
 +    fn c();
 +}
 +
 +struct Bar;
 +$0impl Foo for Bar {
 +    const B: u8 = 17;
 +    fn c() {}
 +    type A = String;
 +}
 +"#####,
 +        r#####"
 +trait Foo {
 +    type A;
 +    const B: u8;
 +    fn c();
 +}
 +
 +struct Bar;
 +impl Foo for Bar {
 +    type A = String;
 +    const B: u8 = 17;
 +    fn c() {}
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_char_with_string() {
 +    check_doc_test(
 +        "replace_char_with_string",
 +        r#####"
 +fn main() {
 +    find('{$0');
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    find("{");
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_derive_with_manual_impl() {
 +    check_doc_test(
 +        "replace_derive_with_manual_impl",
 +        r#####"
 +//- minicore: derive
 +trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
 +#[derive(Deb$0ug, Display)]
 +struct S;
 +"#####,
 +        r#####"
 +trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
 +#[derive(Display)]
 +struct S;
 +
 +impl Debug for S {
 +    $0fn fmt(&self, f: &mut Formatter) -> Result<()> {
 +        f.debug_struct("S").finish()
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_if_let_with_match() {
 +    check_doc_test(
 +        "replace_if_let_with_match",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    $0if let Action::Move { distance } = action {
 +        foo(distance)
 +    } else {
 +        bar()
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move { distance } => foo(distance),
 +        _ => bar(),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_let_with_if_let() {
 +    check_doc_test(
 +        "replace_let_with_if_let",
 +        r#####"
 +enum Option<T> { Some(T), None }
 +
 +fn main(action: Action) {
 +    $0let x = compute();
 +}
 +
 +fn compute() -> Option<i32> { None }
 +"#####,
 +        r#####"
 +enum Option<T> { Some(T), None }
 +
 +fn main(action: Action) {
 +    if let Some(x) = compute() {
 +    }
 +}
 +
 +fn compute() -> Option<i32> { None }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_match_with_if_let() {
 +    check_doc_test(
 +        "replace_match_with_if_let",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    $0match action {
 +        Action::Move { distance } => foo(distance),
 +        _ => bar(),
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    if let Action::Move { distance } = action {
 +        foo(distance)
 +    } else {
 +        bar()
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_qualified_name_with_use() {
 +    check_doc_test(
 +        "replace_qualified_name_with_use",
 +        r#####"
 +mod std { pub mod collections { pub struct HashMap<T, U>(T, U); } }
 +fn process(map: std::collections::$0HashMap<String, String>) {}
 +"#####,
 +        r#####"
 +use std::collections::HashMap;
 +
 +mod std { pub mod collections { pub struct HashMap<T, U>(T, U); } }
 +fn process(map: HashMap<String, String>) {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_string_with_char() {
 +    check_doc_test(
 +        "replace_string_with_char",
 +        r#####"
 +fn main() {
 +    find("{$0");
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    find('{');
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_try_expr_with_match() {
 +    check_doc_test(
 +        "replace_try_expr_with_match",
 +        r#####"
 +//- minicore:option
 +fn handle() {
 +    let pat = Some(true)$0?;
 +}
 +"#####,
 +        r#####"
 +fn handle() {
 +    let pat = match Some(true) {
 +        Some(it) => it,
 +        None => return None,
 +    };
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_turbofish_with_explicit_type() {
 +    check_doc_test(
 +        "replace_turbofish_with_explicit_type",
 +        r#####"
 +fn make<T>() -> T { ) }
 +fn main() {
 +    let a = make$0::<i32>();
 +}
 +"#####,
 +        r#####"
 +fn make<T>() -> T { ) }
 +fn main() {
 +    let a: i32 = make();
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_sort_items() {
 +    check_doc_test(
 +        "sort_items",
 +        r#####"
 +struct $0Foo$0 { second: u32, first: String }
 +"#####,
 +        r#####"
 +struct Foo { first: String, second: u32 }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_sort_items_1() {
 +    check_doc_test(
 +        "sort_items",
 +        r#####"
 +trait $0Bar$0 {
 +    fn second(&self) -> u32;
 +    fn first(&self) -> String;
 +}
 +"#####,
 +        r#####"
 +trait Bar {
 +    fn first(&self) -> String;
 +    fn second(&self) -> u32;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_sort_items_2() {
 +    check_doc_test(
 +        "sort_items",
 +        r#####"
 +struct Baz;
 +impl $0Baz$0 {
 +    fn second(&self) -> u32;
 +    fn first(&self) -> String;
 +}
 +"#####,
 +        r#####"
 +struct Baz;
 +impl Baz {
 +    fn first(&self) -> String;
 +    fn second(&self) -> u32;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_sort_items_3() {
 +    check_doc_test(
 +        "sort_items",
 +        r#####"
 +enum $0Animal$0 {
 +  Dog(String, f64),
 +  Cat { weight: f64, name: String },
 +}
 +"#####,
 +        r#####"
 +enum Animal {
 +  Cat { weight: f64, name: String },
 +  Dog(String, f64),
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_sort_items_4() {
 +    check_doc_test(
 +        "sort_items",
 +        r#####"
 +enum Animal {
 +  Dog(String, f64),
 +  Cat $0{ weight: f64, name: String }$0,
 +}
 +"#####,
 +        r#####"
 +enum Animal {
 +  Dog(String, f64),
 +  Cat { name: String, weight: f64 },
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_split_import() {
 +    check_doc_test(
 +        "split_import",
 +        r#####"
 +use std::$0collections::HashMap;
 +"#####,
 +        r#####"
 +use std::{collections::HashMap};
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_toggle_ignore() {
 +    check_doc_test(
 +        "toggle_ignore",
 +        r#####"
 +$0#[test]
 +fn arithmetics {
 +    assert_eq!(2 + 2, 5);
 +}
 +"#####,
 +        r#####"
 +#[test]
 +#[ignore]
 +fn arithmetics {
 +    assert_eq!(2 + 2, 5);
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_unmerge_use() {
 +    check_doc_test(
 +        "unmerge_use",
 +        r#####"
 +use std::fmt::{Debug, Display$0};
 +"#####,
 +        r#####"
 +use std::fmt::{Debug};
 +use std::fmt::Display;
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_unnecessary_async() {
 +    check_doc_test(
 +        "unnecessary_async",
 +        r#####"
 +pub async f$0n foo() {}
 +pub async fn bar() { foo().await }
 +"#####,
 +        r#####"
 +pub fn foo() {}
 +pub async fn bar() { foo() }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_unwrap_block() {
 +    check_doc_test(
 +        "unwrap_block",
 +        r#####"
 +fn foo() {
 +    if true {$0
 +        println!("foo");
 +    }
 +}
 +"#####,
 +        r#####"
 +fn foo() {
 +    println!("foo");
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_unwrap_result_return_type() {
 +    check_doc_test(
 +        "unwrap_result_return_type",
 +        r#####"
 +//- minicore: result
 +fn foo() -> Result<i32>$0 { Ok(42i32) }
 +"#####,
 +        r#####"
 +fn foo() -> i32 { 42i32 }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_wrap_return_type_in_result() {
 +    check_doc_test(
 +        "wrap_return_type_in_result",
 +        r#####"
 +//- minicore: result
 +fn foo() -> i32$0 { 42i32 }
 +"#####,
 +        r#####"
 +fn foo() -> Result<i32, ${0:_}> { Ok(42i32) }
 +"#####,
 +    )
 +}
index 779cdbc93c54a59d01914edbc84d2056ae61a608,0000000000000000000000000000000000000000..c521a10fccfc314942ce4baf642be6eecf6c36f8
mode 100644,000000..100644
--- /dev/null
@@@ -1,775 -1,0 +1,776 @@@
- /// * if expr is an argument to function/method, use paramter name
 +//! This module contains functions to suggest names for expressions, functions and other items
 +
 +use hir::Semantics;
 +use ide_db::RootDatabase;
 +use itertools::Itertools;
 +use stdx::to_lower_snake_case;
 +use syntax::{
 +    ast::{self, HasName},
 +    match_ast, AstNode, SmolStr,
 +};
 +
 +/// Trait names, that will be ignored when in `impl Trait` and `dyn Trait`
 +const USELESS_TRAITS: &[&str] = &["Send", "Sync", "Copy", "Clone", "Eq", "PartialEq"];
 +
 +/// Identifier names that won't be suggested, ever
 +///
 +/// **NOTE**: they all must be snake lower case
 +const USELESS_NAMES: &[&str] =
 +    &["new", "default", "option", "some", "none", "ok", "err", "str", "string"];
 +
 +/// Generic types replaced by their first argument
 +///
 +/// # Examples
 +/// `Option<Name>` -> `Name`
 +/// `Result<User, Error>` -> `User`
 +const WRAPPER_TYPES: &[&str] = &["Box", "Option", "Result"];
 +
 +/// Prefixes to strip from methods names
 +///
 +/// # Examples
 +/// `vec.as_slice()` -> `slice`
 +/// `args.into_config()` -> `config`
 +/// `bytes.to_vec()` -> `vec`
 +const USELESS_METHOD_PREFIXES: &[&str] = &["into_", "as_", "to_"];
 +
 +/// Useless methods that are stripped from expression
 +///
 +/// # Examples
 +/// `var.name().to_string()` -> `var.name()`
 +const USELESS_METHODS: &[&str] = &[
 +    "to_string",
 +    "as_str",
 +    "to_owned",
 +    "as_ref",
 +    "clone",
 +    "cloned",
 +    "expect",
 +    "expect_none",
 +    "unwrap",
 +    "unwrap_none",
 +    "unwrap_or",
 +    "unwrap_or_default",
 +    "unwrap_or_else",
 +    "unwrap_unchecked",
 +    "iter",
 +    "into_iter",
 +    "iter_mut",
++    "into_future",
 +];
 +
 +pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr {
 +    let c = ty
 +        .type_bound_list()
 +        .and_then(|bounds| bounds.syntax().text().char_at(0.into()))
 +        .unwrap_or('T');
 +    c.encode_utf8(&mut [0; 4]).into()
 +}
 +
 +/// Suggest name of variable for given expression
 +///
 +/// **NOTE**: it is caller's responsibility to guarantee uniqueness of the name.
 +/// I.e. it doesn't look for names in scope.
 +///
 +/// # Current implementation
 +///
 +/// In current implementation, the function tries to get the name from
 +/// the following sources:
 +///
-     // `from_param` does not benifit from stripping
++/// * if expr is an argument to function/method, use parameter name
 +/// * if expr is a function/method call, use function name
 +/// * expression type name if it exists (E.g. `()`, `fn() -> ()` or `!` do not have names)
 +/// * fallback: `var_name`
 +///
 +/// It also applies heuristics to filter out less informative names
 +///
 +/// Currently it sticks to the first name found.
 +// FIXME: Microoptimize and return a `SmolStr` here.
 +pub(crate) fn for_variable(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> String {
++    // `from_param` does not benefit from stripping
 +    // it need the largest context possible
 +    // so we check firstmost
 +    if let Some(name) = from_param(expr, sema) {
 +        return name;
 +    }
 +
 +    let mut next_expr = Some(expr.clone());
 +    while let Some(expr) = next_expr {
 +        let name =
 +            from_call(&expr).or_else(|| from_type(&expr, sema)).or_else(|| from_field_name(&expr));
 +        if let Some(name) = name {
 +            return name;
 +        }
 +
 +        match expr {
 +            ast::Expr::RefExpr(inner) => next_expr = inner.expr(),
 +            ast::Expr::BoxExpr(inner) => next_expr = inner.expr(),
 +            ast::Expr::AwaitExpr(inner) => next_expr = inner.expr(),
 +            // ast::Expr::BlockExpr(block) => expr = block.tail_expr(),
 +            ast::Expr::CastExpr(inner) => next_expr = inner.expr(),
 +            ast::Expr::MethodCallExpr(method) if is_useless_method(&method) => {
 +                next_expr = method.receiver();
 +            }
 +            ast::Expr::ParenExpr(inner) => next_expr = inner.expr(),
 +            ast::Expr::TryExpr(inner) => next_expr = inner.expr(),
 +            ast::Expr::PrefixExpr(prefix) if prefix.op_kind() == Some(ast::UnaryOp::Deref) => {
 +                next_expr = prefix.expr()
 +            }
 +            _ => break,
 +        }
 +    }
 +
 +    "var_name".to_string()
 +}
 +
 +fn normalize(name: &str) -> Option<String> {
 +    let name = to_lower_snake_case(name);
 +
 +    if USELESS_NAMES.contains(&name.as_str()) {
 +        return None;
 +    }
 +
 +    if !is_valid_name(&name) {
 +        return None;
 +    }
 +
 +    Some(name)
 +}
 +
 +fn is_valid_name(name: &str) -> bool {
 +    match ide_db::syntax_helpers::LexedStr::single_token(name) {
 +        Some((syntax::SyntaxKind::IDENT, _error)) => true,
 +        _ => false,
 +    }
 +}
 +
 +fn is_useless_method(method: &ast::MethodCallExpr) -> bool {
 +    let ident = method.name_ref().and_then(|it| it.ident_token());
 +
 +    match ident {
 +        Some(ident) => USELESS_METHODS.contains(&ident.text()),
 +        None => false,
 +    }
 +}
 +
 +fn from_call(expr: &ast::Expr) -> Option<String> {
 +    from_func_call(expr).or_else(|| from_method_call(expr))
 +}
 +
 +fn from_func_call(expr: &ast::Expr) -> Option<String> {
 +    let call = match expr {
 +        ast::Expr::CallExpr(call) => call,
 +        _ => return None,
 +    };
 +    let func = match call.expr()? {
 +        ast::Expr::PathExpr(path) => path,
 +        _ => return None,
 +    };
 +    let ident = func.path()?.segment()?.name_ref()?.ident_token()?;
 +    normalize(ident.text())
 +}
 +
 +fn from_method_call(expr: &ast::Expr) -> Option<String> {
 +    let method = match expr {
 +        ast::Expr::MethodCallExpr(call) => call,
 +        _ => return None,
 +    };
 +    let ident = method.name_ref()?.ident_token()?;
 +    let mut name = ident.text();
 +
 +    if USELESS_METHODS.contains(&name) {
 +        return None;
 +    }
 +
 +    for prefix in USELESS_METHOD_PREFIXES {
 +        if let Some(suffix) = name.strip_prefix(prefix) {
 +            name = suffix;
 +            break;
 +        }
 +    }
 +
 +    normalize(name)
 +}
 +
 +fn from_param(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<String> {
 +    let arg_list = expr.syntax().parent().and_then(ast::ArgList::cast)?;
 +    let args_parent = arg_list.syntax().parent()?;
 +    let func = match_ast! {
 +        match args_parent {
 +            ast::CallExpr(call) => {
 +                let func = call.expr()?;
 +                let func_ty = sema.type_of_expr(&func)?.adjusted();
 +                func_ty.as_callable(sema.db)?
 +            },
 +            ast::MethodCallExpr(method) => sema.resolve_method_call_as_callable(&method)?,
 +            _ => return None,
 +        }
 +    };
 +
 +    let (idx, _) = arg_list.args().find_position(|it| it == expr).unwrap();
 +    let (pat, _) = func.params(sema.db).into_iter().nth(idx)?;
 +    let pat = match pat? {
 +        either::Either::Right(pat) => pat,
 +        _ => return None,
 +    };
 +    let name = var_name_from_pat(&pat)?;
 +    normalize(&name.to_string())
 +}
 +
 +fn var_name_from_pat(pat: &ast::Pat) -> Option<ast::Name> {
 +    match pat {
 +        ast::Pat::IdentPat(var) => var.name(),
 +        ast::Pat::RefPat(ref_pat) => var_name_from_pat(&ref_pat.pat()?),
 +        ast::Pat::BoxPat(box_pat) => var_name_from_pat(&box_pat.pat()?),
 +        _ => None,
 +    }
 +}
 +
 +fn from_type(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<String> {
 +    let ty = sema.type_of_expr(expr)?.adjusted();
 +    let ty = ty.remove_ref().unwrap_or(ty);
 +
 +    name_of_type(&ty, sema.db)
 +}
 +
 +fn name_of_type(ty: &hir::Type, db: &RootDatabase) -> Option<String> {
 +    let name = if let Some(adt) = ty.as_adt() {
 +        let name = adt.name(db).to_string();
 +
 +        if WRAPPER_TYPES.contains(&name.as_str()) {
 +            let inner_ty = ty.type_arguments().next()?;
 +            return name_of_type(&inner_ty, db);
 +        }
 +
 +        name
 +    } else if let Some(trait_) = ty.as_dyn_trait() {
 +        trait_name(&trait_, db)?
 +    } else if let Some(traits) = ty.as_impl_traits(db) {
 +        let mut iter = traits.filter_map(|t| trait_name(&t, db));
 +        let name = iter.next()?;
 +        if iter.next().is_some() {
 +            return None;
 +        }
 +        name
 +    } else {
 +        return None;
 +    };
 +    normalize(&name)
 +}
 +
 +fn trait_name(trait_: &hir::Trait, db: &RootDatabase) -> Option<String> {
 +    let name = trait_.name(db).to_string();
 +    if USELESS_TRAITS.contains(&name.as_str()) {
 +        return None;
 +    }
 +    Some(name)
 +}
 +
 +fn from_field_name(expr: &ast::Expr) -> Option<String> {
 +    let field = match expr {
 +        ast::Expr::FieldExpr(field) => field,
 +        _ => return None,
 +    };
 +    let ident = field.name_ref()?.ident_token()?;
 +    normalize(ident.text())
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use ide_db::base_db::{fixture::WithFixture, FileRange};
 +
 +    use super::*;
 +
 +    #[track_caller]
 +    fn check(ra_fixture: &str, expected: &str) {
 +        let (db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture);
 +        let frange = FileRange { file_id, range: range_or_offset.into() };
 +
 +        let sema = Semantics::new(&db);
 +        let source_file = sema.parse(frange.file_id);
 +        let element = source_file.syntax().covering_element(frange.range);
 +        let expr =
 +            element.ancestors().find_map(ast::Expr::cast).expect("selection is not an expression");
 +        assert_eq!(
 +            expr.syntax().text_range(),
 +            frange.range,
 +            "selection is not an expression(yet contained in one)"
 +        );
 +        let name = for_variable(&expr, &sema);
 +        assert_eq!(&name, expected);
 +    }
 +
 +    #[test]
 +    fn no_args() {
 +        check(r#"fn foo() { $0bar()$0 }"#, "bar");
 +        check(r#"fn foo() { $0bar.frobnicate()$0 }"#, "frobnicate");
 +    }
 +
 +    #[test]
 +    fn single_arg() {
 +        check(r#"fn foo() { $0bar(1)$0 }"#, "bar");
 +    }
 +
 +    #[test]
 +    fn many_args() {
 +        check(r#"fn foo() { $0bar(1, 2, 3)$0 }"#, "bar");
 +    }
 +
 +    #[test]
 +    fn path() {
 +        check(r#"fn foo() { $0i32::bar(1, 2, 3)$0 }"#, "bar");
 +    }
 +
 +    #[test]
 +    fn generic_params() {
 +        check(r#"fn foo() { $0bar::<i32>(1, 2, 3)$0 }"#, "bar");
 +        check(r#"fn foo() { $0bar.frobnicate::<i32, u32>()$0 }"#, "frobnicate");
 +    }
 +
 +    #[test]
 +    fn to_name() {
 +        check(
 +            r#"
 +struct Args;
 +struct Config;
 +impl Args {
 +    fn to_config(&self) -> Config {}
 +}
 +fn foo() {
 +    $0Args.to_config()$0;
 +}
 +"#,
 +            "config",
 +        );
 +    }
 +
 +    #[test]
 +    fn plain_func() {
 +        check(
 +            r#"
 +fn bar(n: i32, m: u32);
 +fn foo() { bar($01$0, 2) }
 +"#,
 +            "n",
 +        );
 +    }
 +
 +    #[test]
 +    fn mut_param() {
 +        check(
 +            r#"
 +fn bar(mut n: i32, m: u32);
 +fn foo() { bar($01$0, 2) }
 +"#,
 +            "n",
 +        );
 +    }
 +
 +    #[test]
 +    fn func_does_not_exist() {
 +        check(r#"fn foo() { bar($01$0, 2) }"#, "var_name");
 +    }
 +
 +    #[test]
 +    fn unnamed_param() {
 +        check(
 +            r#"
 +fn bar(_: i32, m: u32);
 +fn foo() { bar($01$0, 2) }
 +"#,
 +            "var_name",
 +        );
 +    }
 +
 +    #[test]
 +    fn tuple_pat() {
 +        check(
 +            r#"
 +fn bar((n, k): (i32, i32), m: u32);
 +fn foo() {
 +    bar($0(1, 2)$0, 3)
 +}
 +"#,
 +            "var_name",
 +        );
 +    }
 +
 +    #[test]
 +    fn ref_pat() {
 +        check(
 +            r#"
 +fn bar(&n: &i32, m: u32);
 +fn foo() { bar($0&1$0, 3) }
 +"#,
 +            "n",
 +        );
 +    }
 +
 +    #[test]
 +    fn box_pat() {
 +        check(
 +            r#"
 +fn bar(box n: &i32, m: u32);
 +fn foo() { bar($01$0, 3) }
 +"#,
 +            "n",
 +        );
 +    }
 +
 +    #[test]
 +    fn param_out_of_index() {
 +        check(
 +            r#"
 +fn bar(n: i32, m: u32);
 +fn foo() { bar(1, 2, $03$0) }
 +"#,
 +            "var_name",
 +        );
 +    }
 +
 +    #[test]
 +    fn generic_param_resolved() {
 +        check(
 +            r#"
 +fn bar<T>(n: T, m: u32);
 +fn foo() { bar($01$0, 2) }
 +"#,
 +            "n",
 +        );
 +    }
 +
 +    #[test]
 +    fn generic_param_unresolved() {
 +        check(
 +            r#"
 +fn bar<T>(n: T, m: u32);
 +fn foo<T>(x: T) { bar($0x$0, 2) }
 +"#,
 +            "n",
 +        );
 +    }
 +
 +    #[test]
 +    fn method() {
 +        check(
 +            r#"
 +struct S;
 +impl S { fn bar(&self, n: i32, m: u32); }
 +fn foo() { S.bar($01$0, 2) }
 +"#,
 +            "n",
 +        );
 +    }
 +
 +    #[test]
 +    fn method_on_impl_trait() {
 +        check(
 +            r#"
 +struct S;
 +trait T {
 +    fn bar(&self, n: i32, m: u32);
 +}
 +impl T for S { fn bar(&self, n: i32, m: u32); }
 +fn foo() { S.bar($01$0, 2) }
 +"#,
 +            "n",
 +        );
 +    }
 +
 +    #[test]
 +    fn method_ufcs() {
 +        check(
 +            r#"
 +struct S;
 +impl S { fn bar(&self, n: i32, m: u32); }
 +fn foo() { S::bar(&S, $01$0, 2) }
 +"#,
 +            "n",
 +        );
 +    }
 +
 +    #[test]
 +    fn method_self() {
 +        check(
 +            r#"
 +struct S;
 +impl S { fn bar(&self, n: i32, m: u32); }
 +fn foo() { S::bar($0&S$0, 1, 2) }
 +"#,
 +            "s",
 +        );
 +    }
 +
 +    #[test]
 +    fn method_self_named() {
 +        check(
 +            r#"
 +struct S;
 +impl S { fn bar(strukt: &Self, n: i32, m: u32); }
 +fn foo() { S::bar($0&S$0, 1, 2) }
 +"#,
 +            "strukt",
 +        );
 +    }
 +
 +    #[test]
 +    fn i32() {
 +        check(r#"fn foo() { let _: i32 = $01$0; }"#, "var_name");
 +    }
 +
 +    #[test]
 +    fn u64() {
 +        check(r#"fn foo() { let _: u64 = $01$0; }"#, "var_name");
 +    }
 +
 +    #[test]
 +    fn bool() {
 +        check(r#"fn foo() { let _: bool = $0true$0; }"#, "var_name");
 +    }
 +
 +    #[test]
 +    fn struct_unit() {
 +        check(
 +            r#"
 +struct Seed;
 +fn foo() { let _ = $0Seed$0; }
 +"#,
 +            "seed",
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_unit_to_snake() {
 +        check(
 +            r#"
 +struct SeedState;
 +fn foo() { let _ = $0SeedState$0; }
 +"#,
 +            "seed_state",
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_single_arg() {
 +        check(
 +            r#"
 +struct Seed(u32);
 +fn foo() { let _ = $0Seed(0)$0; }
 +"#,
 +            "seed",
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_with_fields() {
 +        check(
 +            r#"
 +struct Seed { value: u32 }
 +fn foo() { let _ = $0Seed { value: 0 }$0; }
 +"#,
 +            "seed",
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_() {
 +        check(
 +            r#"
 +enum Kind { A, B }
 +fn foo() { let _ = $0Kind::A$0; }
 +"#,
 +            "kind",
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_generic_resolved() {
 +        check(
 +            r#"
 +enum Kind<T> { A { x: T }, B }
 +fn foo() { let _ = $0Kind::A { x:1 }$0; }
 +"#,
 +            "kind",
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_generic_unresolved() {
 +        check(
 +            r#"
 +enum Kind<T> { A { x: T }, B }
 +fn foo<T>(x: T) { let _ = $0Kind::A { x }$0; }
 +"#,
 +            "kind",
 +        );
 +    }
 +
 +    #[test]
 +    fn dyn_trait() {
 +        check(
 +            r#"
 +trait DynHandler {}
 +fn bar() -> dyn DynHandler {}
 +fn foo() { $0(bar())$0; }
 +"#,
 +            "dyn_handler",
 +        );
 +    }
 +
 +    #[test]
 +    fn impl_trait() {
 +        check(
 +            r#"
 +trait StaticHandler {}
 +fn bar() -> impl StaticHandler {}
 +fn foo() { $0(bar())$0; }
 +"#,
 +            "static_handler",
 +        );
 +    }
 +
 +    #[test]
 +    fn impl_trait_plus_clone() {
 +        check(
 +            r#"
 +trait StaticHandler {}
 +trait Clone {}
 +fn bar() -> impl StaticHandler + Clone {}
 +fn foo() { $0(bar())$0; }
 +"#,
 +            "static_handler",
 +        );
 +    }
 +
 +    #[test]
 +    fn impl_trait_plus_lifetime() {
 +        check(
 +            r#"
 +trait StaticHandler {}
 +trait Clone {}
 +fn bar<'a>(&'a i32) -> impl StaticHandler + 'a {}
 +fn foo() { $0(bar(&1))$0; }
 +"#,
 +            "static_handler",
 +        );
 +    }
 +
 +    #[test]
 +    fn impl_trait_plus_trait() {
 +        check(
 +            r#"
 +trait Handler {}
 +trait StaticHandler {}
 +fn bar() -> impl StaticHandler + Handler {}
 +fn foo() { $0(bar())$0; }
 +"#,
 +            "bar",
 +        );
 +    }
 +
 +    #[test]
 +    fn ref_value() {
 +        check(
 +            r#"
 +struct Seed;
 +fn bar() -> &Seed {}
 +fn foo() { $0(bar())$0; }
 +"#,
 +            "seed",
 +        );
 +    }
 +
 +    #[test]
 +    fn box_value() {
 +        check(
 +            r#"
 +struct Box<T>(*const T);
 +struct Seed;
 +fn bar() -> Box<Seed> {}
 +fn foo() { $0(bar())$0; }
 +"#,
 +            "seed",
 +        );
 +    }
 +
 +    #[test]
 +    fn box_generic() {
 +        check(
 +            r#"
 +struct Box<T>(*const T);
 +fn bar<T>() -> Box<T> {}
 +fn foo<T>() { $0(bar::<T>())$0; }
 +"#,
 +            "bar",
 +        );
 +    }
 +
 +    #[test]
 +    fn option_value() {
 +        check(
 +            r#"
 +enum Option<T> { Some(T) }
 +struct Seed;
 +fn bar() -> Option<Seed> {}
 +fn foo() { $0(bar())$0; }
 +"#,
 +            "seed",
 +        );
 +    }
 +
 +    #[test]
 +    fn result_value() {
 +        check(
 +            r#"
 +enum Result<T, E> { Ok(T), Err(E) }
 +struct Seed;
 +struct Error;
 +fn bar() -> Result<Seed, Error> {}
 +fn foo() { $0(bar())$0; }
 +"#,
 +            "seed",
 +        );
 +    }
 +
 +    #[test]
 +    fn ref_call() {
 +        check(
 +            r#"
 +fn foo() { $0&bar(1, 3)$0 }
 +"#,
 +            "bar",
 +        );
 +    }
 +
 +    #[test]
 +    fn name_to_string() {
 +        check(
 +            r#"
 +fn foo() { $0function.name().to_string()$0 }
 +"#,
 +            "name",
 +        );
 +    }
 +
 +    #[test]
 +    fn nested_useless_method() {
 +        check(
 +            r#"
 +fn foo() { $0function.name().as_ref().unwrap().to_string()$0 }
 +"#,
 +            "name",
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_field_name() {
 +        check(
 +            r#"
 +struct S<T> {
 +    some_field: T;
 +}
 +fn foo<T>(some_struct: S<T>) { $0some_struct.some_field$0 }
 +"#,
 +            "some_field",
 +        );
 +    }
 +}
index cf40ca489c009733174cb30083f1c3645aabbb72,0000000000000000000000000000000000000000..02004ff7b686876e2a699cb51f0c61ca90a3b06a
mode 100644,000000..100644
--- /dev/null
@@@ -1,947 -1,0 +1,947 @@@
-     if receiver_ty.impls_future(ctx.db) {
 +//! Completes references after dot (fields and method calls).
 +
 +use ide_db::FxHashSet;
 +
 +use crate::{
 +    context::{CompletionContext, DotAccess, DotAccessKind, ExprCtx, PathCompletionCtx, Qualified},
 +    CompletionItem, CompletionItemKind, Completions,
 +};
 +
 +/// Complete dot accesses, i.e. fields or methods.
 +pub(crate) fn complete_dot(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    dot_access: &DotAccess,
 +) {
 +    let receiver_ty = match dot_access {
 +        DotAccess { receiver_ty: Some(receiver_ty), .. } => &receiver_ty.original,
 +        _ => return,
 +    };
 +
 +    // Suggest .await syntax for types that implement Future trait
++    if receiver_ty.impls_into_future(ctx.db) {
 +        let mut item =
 +            CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), "await");
 +        item.detail("expr.await");
 +        item.add_to(acc);
 +    }
 +
 +    if let DotAccessKind::Method { .. } = dot_access.kind {
 +        cov_mark::hit!(test_no_struct_field_completion_for_method_call);
 +    } else {
 +        complete_fields(
 +            acc,
 +            ctx,
 +            &receiver_ty,
 +            |acc, field, ty| acc.add_field(ctx, dot_access, None, field, &ty),
 +            |acc, field, ty| acc.add_tuple_field(ctx, None, field, &ty),
 +        );
 +    }
 +    complete_methods(ctx, &receiver_ty, |func| acc.add_method(ctx, dot_access, func, None, None));
 +}
 +
 +pub(crate) fn complete_undotted_self(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    path_ctx: &PathCompletionCtx,
 +    expr_ctx: &ExprCtx,
 +) {
 +    if !ctx.config.enable_self_on_the_fly {
 +        return;
 +    }
 +    if !path_ctx.is_trivial_path() {
 +        return;
 +    }
 +    if !ctx.qualifier_ctx.none() {
 +        return;
 +    }
 +    if !matches!(path_ctx.qualified, Qualified::No) {
 +        return;
 +    }
 +    let self_param = match expr_ctx {
 +        ExprCtx { self_param: Some(self_param), .. } => self_param,
 +        _ => return,
 +    };
 +
 +    let ty = self_param.ty(ctx.db);
 +    complete_fields(
 +        acc,
 +        ctx,
 +        &ty,
 +        |acc, field, ty| {
 +            acc.add_field(
 +                ctx,
 +                &DotAccess {
 +                    receiver: None,
 +                    receiver_ty: None,
 +                    kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false },
 +                },
 +                Some(hir::known::SELF_PARAM),
 +                field,
 +                &ty,
 +            )
 +        },
 +        |acc, field, ty| acc.add_tuple_field(ctx, Some(hir::known::SELF_PARAM), field, &ty),
 +    );
 +    complete_methods(ctx, &ty, |func| {
 +        acc.add_method(
 +            ctx,
 +            &DotAccess {
 +                receiver: None,
 +                receiver_ty: None,
 +                kind: DotAccessKind::Method { has_parens: false },
 +            },
 +            func,
 +            Some(hir::known::SELF_PARAM),
 +            None,
 +        )
 +    });
 +}
 +
 +fn complete_fields(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    receiver: &hir::Type,
 +    mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type),
 +    mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type),
 +) {
 +    for receiver in receiver.autoderef(ctx.db) {
 +        for (field, ty) in receiver.fields(ctx.db) {
 +            named_field(acc, field, ty);
 +        }
 +        for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
 +            // Tuple fields are always public (tuple struct fields are handled above).
 +            tuple_index(acc, i, ty);
 +        }
 +    }
 +}
 +
 +fn complete_methods(
 +    ctx: &CompletionContext<'_>,
 +    receiver: &hir::Type,
 +    mut f: impl FnMut(hir::Function),
 +) {
 +    let mut seen_methods = FxHashSet::default();
 +    receiver.iterate_method_candidates(
 +        ctx.db,
 +        &ctx.scope,
 +        &ctx.traits_in_scope(),
 +        Some(ctx.module),
 +        None,
 +        |func| {
 +            if func.self_param(ctx.db).is_some() && seen_methods.insert(func.name(ctx.db)) {
 +                f(func);
 +            }
 +            None::<()>
 +        },
 +    );
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use expect_test::{expect, Expect};
 +
 +    use crate::tests::{
 +        check_edit, completion_list_no_kw, completion_list_no_kw_with_private_editable,
 +    };
 +
 +    fn check(ra_fixture: &str, expect: Expect) {
 +        let actual = completion_list_no_kw(ra_fixture);
 +        expect.assert_eq(&actual);
 +    }
 +
 +    fn check_with_private_editable(ra_fixture: &str, expect: Expect) {
 +        let actual = completion_list_no_kw_with_private_editable(ra_fixture);
 +        expect.assert_eq(&actual);
 +    }
 +
 +    #[test]
 +    fn test_struct_field_and_method_completion() {
 +        check(
 +            r#"
 +struct S { foo: u32 }
 +impl S {
 +    fn bar(&self) {}
 +}
 +fn foo(s: S) { s.$0 }
 +"#,
 +            expect![[r#"
 +                fd foo   u32
 +                me bar() fn(&self)
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_struct_field_completion_self() {
 +        check(
 +            r#"
 +struct S { the_field: (u32,) }
 +impl S {
 +    fn foo(self) { self.$0 }
 +}
 +"#,
 +            expect![[r#"
 +                fd the_field (u32,)
 +                me foo()     fn(self)
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn test_struct_field_completion_autoderef() {
 +        check(
 +            r#"
 +struct A { the_field: (u32, i32) }
 +impl A {
 +    fn foo(&self) { self.$0 }
 +}
 +"#,
 +            expect![[r#"
 +                fd the_field (u32, i32)
 +                me foo()     fn(&self)
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn test_no_struct_field_completion_for_method_call() {
 +        cov_mark::check!(test_no_struct_field_completion_for_method_call);
 +        check(
 +            r#"
 +struct A { the_field: u32 }
 +fn foo(a: A) { a.$0() }
 +"#,
 +            expect![[r#""#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_visibility_filtering() {
 +        check(
 +            r#"
 +//- /lib.rs crate:lib new_source_root:local
 +pub mod m {
 +    pub struct A {
 +        private_field: u32,
 +        pub pub_field: u32,
 +        pub(crate) crate_field: u32,
 +        pub(super) super_field: u32,
 +    }
 +}
 +//- /main.rs crate:main deps:lib new_source_root:local
 +fn foo(a: lib::m::A) { a.$0 }
 +"#,
 +            expect![[r#"
 +                fd pub_field u32
 +            "#]],
 +        );
 +
 +        check(
 +            r#"
 +//- /lib.rs crate:lib new_source_root:library
 +pub mod m {
 +    pub struct A {
 +        private_field: u32,
 +        pub pub_field: u32,
 +        pub(crate) crate_field: u32,
 +        pub(super) super_field: u32,
 +    }
 +}
 +//- /main.rs crate:main deps:lib new_source_root:local
 +fn foo(a: lib::m::A) { a.$0 }
 +"#,
 +            expect![[r#"
 +                fd pub_field u32
 +            "#]],
 +        );
 +
 +        check(
 +            r#"
 +//- /lib.rs crate:lib new_source_root:library
 +pub mod m {
 +    pub struct A(
 +        i32,
 +        pub f64,
 +    );
 +}
 +//- /main.rs crate:main deps:lib new_source_root:local
 +fn foo(a: lib::m::A) { a.$0 }
 +"#,
 +            expect![[r#"
 +                fd 1 f64
 +            "#]],
 +        );
 +
 +        check(
 +            r#"
 +//- /lib.rs crate:lib new_source_root:local
 +pub struct A {}
 +mod m {
 +    impl super::A {
 +        fn private_method(&self) {}
 +        pub(crate) fn crate_method(&self) {}
 +        pub fn pub_method(&self) {}
 +    }
 +}
 +//- /main.rs crate:main deps:lib new_source_root:local
 +fn foo(a: lib::A) { a.$0 }
 +"#,
 +            expect![[r#"
 +                me pub_method() fn(&self)
 +            "#]],
 +        );
 +        check(
 +            r#"
 +//- /lib.rs crate:lib new_source_root:library
 +pub struct A {}
 +mod m {
 +    impl super::A {
 +        fn private_method(&self) {}
 +        pub(crate) fn crate_method(&self) {}
 +        pub fn pub_method(&self) {}
 +    }
 +}
 +//- /main.rs crate:main deps:lib new_source_root:local
 +fn foo(a: lib::A) { a.$0 }
 +"#,
 +            expect![[r#"
 +                me pub_method() fn(&self)
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_visibility_filtering_with_private_editable_enabled() {
 +        check_with_private_editable(
 +            r#"
 +//- /lib.rs crate:lib new_source_root:local
 +pub mod m {
 +    pub struct A {
 +        private_field: u32,
 +        pub pub_field: u32,
 +        pub(crate) crate_field: u32,
 +        pub(super) super_field: u32,
 +    }
 +}
 +//- /main.rs crate:main deps:lib new_source_root:local
 +fn foo(a: lib::m::A) { a.$0 }
 +"#,
 +            expect![[r#"
 +                fd crate_field   u32
 +                fd private_field u32
 +                fd pub_field     u32
 +                fd super_field   u32
 +            "#]],
 +        );
 +
 +        check_with_private_editable(
 +            r#"
 +//- /lib.rs crate:lib new_source_root:library
 +pub mod m {
 +    pub struct A {
 +        private_field: u32,
 +        pub pub_field: u32,
 +        pub(crate) crate_field: u32,
 +        pub(super) super_field: u32,
 +    }
 +}
 +//- /main.rs crate:main deps:lib new_source_root:local
 +fn foo(a: lib::m::A) { a.$0 }
 +"#,
 +            expect![[r#"
 +                fd pub_field u32
 +            "#]],
 +        );
 +
 +        check_with_private_editable(
 +            r#"
 +//- /lib.rs crate:lib new_source_root:library
 +pub mod m {
 +    pub struct A(
 +        i32,
 +        pub f64,
 +    );
 +}
 +//- /main.rs crate:main deps:lib new_source_root:local
 +fn foo(a: lib::m::A) { a.$0 }
 +"#,
 +            expect![[r#"
 +                fd 1 f64
 +            "#]],
 +        );
 +
 +        check_with_private_editable(
 +            r#"
 +//- /lib.rs crate:lib new_source_root:local
 +pub struct A {}
 +mod m {
 +    impl super::A {
 +        fn private_method(&self) {}
 +        pub(crate) fn crate_method(&self) {}
 +        pub fn pub_method(&self) {}
 +    }
 +}
 +//- /main.rs crate:main deps:lib new_source_root:local
 +fn foo(a: lib::A) { a.$0 }
 +"#,
 +            expect![[r#"
 +                me crate_method()   fn(&self)
 +                me private_method() fn(&self)
 +                me pub_method()     fn(&self)
 +            "#]],
 +        );
 +        check_with_private_editable(
 +            r#"
 +//- /lib.rs crate:lib new_source_root:library
 +pub struct A {}
 +mod m {
 +    impl super::A {
 +        fn private_method(&self) {}
 +        pub(crate) fn crate_method(&self) {}
 +        pub fn pub_method(&self) {}
 +    }
 +}
 +//- /main.rs crate:main deps:lib new_source_root:local
 +fn foo(a: lib::A) { a.$0 }
 +"#,
 +            expect![[r#"
 +                me pub_method() fn(&self)
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_local_impls() {
 +        check(
 +            r#"
 +//- /lib.rs crate:lib
 +pub struct A {}
 +mod m {
 +    impl super::A {
 +        pub fn pub_module_method(&self) {}
 +    }
 +    fn f() {
 +        impl super::A {
 +            pub fn pub_foreign_local_method(&self) {}
 +        }
 +    }
 +}
 +//- /main.rs crate:main deps:lib
 +fn foo(a: lib::A) {
 +    impl lib::A {
 +        fn local_method(&self) {}
 +    }
 +    a.$0
 +}
 +"#,
 +            expect![[r#"
 +                me local_method()      fn(&self)
 +                me pub_module_method() fn(&self)
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_doc_hidden_filtering() {
 +        check(
 +            r#"
 +//- /lib.rs crate:lib deps:dep
 +fn foo(a: dep::A) { a.$0 }
 +//- /dep.rs crate:dep
 +pub struct A {
 +    #[doc(hidden)]
 +    pub hidden_field: u32,
 +    pub pub_field: u32,
 +}
 +
 +impl A {
 +    pub fn pub_method(&self) {}
 +
 +    #[doc(hidden)]
 +    pub fn hidden_method(&self) {}
 +}
 +            "#,
 +            expect![[r#"
 +                fd pub_field    u32
 +                me pub_method() fn(&self)
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn test_union_field_completion() {
 +        check(
 +            r#"
 +union U { field: u8, other: u16 }
 +fn foo(u: U) { u.$0 }
 +"#,
 +            expect![[r#"
 +                fd field u8
 +                fd other u16
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_method_completion_only_fitting_impls() {
 +        check(
 +            r#"
 +struct A<T> {}
 +impl A<u32> {
 +    fn the_method(&self) {}
 +}
 +impl A<i32> {
 +    fn the_other_method(&self) {}
 +}
 +fn foo(a: A<u32>) { a.$0 }
 +"#,
 +            expect![[r#"
 +                me the_method() fn(&self)
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn test_trait_method_completion() {
 +        check(
 +            r#"
 +struct A {}
 +trait Trait { fn the_method(&self); }
 +impl Trait for A {}
 +fn foo(a: A) { a.$0 }
 +"#,
 +            expect![[r#"
 +                me the_method() (as Trait) fn(&self)
 +            "#]],
 +        );
 +        check_edit(
 +            "the_method",
 +            r#"
 +struct A {}
 +trait Trait { fn the_method(&self); }
 +impl Trait for A {}
 +fn foo(a: A) { a.$0 }
 +"#,
 +            r#"
 +struct A {}
 +trait Trait { fn the_method(&self); }
 +impl Trait for A {}
 +fn foo(a: A) { a.the_method()$0 }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_trait_method_completion_deduplicated() {
 +        check(
 +            r"
 +struct A {}
 +trait Trait { fn the_method(&self); }
 +impl<T> Trait for T {}
 +fn foo(a: &A) { a.$0 }
 +",
 +            expect![[r#"
 +                me the_method() (as Trait) fn(&self)
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn completes_trait_method_from_other_module() {
 +        check(
 +            r"
 +struct A {}
 +mod m {
 +    pub trait Trait { fn the_method(&self); }
 +}
 +use m::Trait;
 +impl Trait for A {}
 +fn foo(a: A) { a.$0 }
 +",
 +            expect![[r#"
 +                me the_method() (as Trait) fn(&self)
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_no_non_self_method() {
 +        check(
 +            r#"
 +struct A {}
 +impl A {
 +    fn the_method() {}
 +}
 +fn foo(a: A) {
 +   a.$0
 +}
 +"#,
 +            expect![[r#""#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_tuple_field_completion() {
 +        check(
 +            r#"
 +fn foo() {
 +   let b = (0, 3.14);
 +   b.$0
 +}
 +"#,
 +            expect![[r#"
 +                fd 0 i32
 +                fd 1 f64
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_tuple_struct_field_completion() {
 +        check(
 +            r#"
 +struct S(i32, f64);
 +fn foo() {
 +   let b = S(0, 3.14);
 +   b.$0
 +}
 +"#,
 +            expect![[r#"
 +                fd 0 i32
 +                fd 1 f64
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_tuple_field_inference() {
 +        check(
 +            r#"
 +pub struct S;
 +impl S { pub fn blah(&self) {} }
 +
 +struct T(S);
 +
 +impl T {
 +    fn foo(&self) {
 +        // FIXME: This doesn't work without the trailing `a` as `0.` is a float
 +        self.0.a$0
 +    }
 +}
 +"#,
 +            expect![[r#"
 +                me blah() fn(&self)
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_completion_works_in_consts() {
 +        check(
 +            r#"
 +struct A { the_field: u32 }
 +const X: u32 = {
 +    A { the_field: 92 }.$0
 +};
 +"#,
 +            expect![[r#"
 +                fd the_field u32
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn works_in_simple_macro_1() {
 +        check(
 +            r#"
 +macro_rules! m { ($e:expr) => { $e } }
 +struct A { the_field: u32 }
 +fn foo(a: A) {
 +    m!(a.x$0)
 +}
 +"#,
 +            expect![[r#"
 +                fd the_field u32
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn works_in_simple_macro_2() {
 +        // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery
 +        check(
 +            r#"
 +macro_rules! m { ($e:expr) => { $e } }
 +struct A { the_field: u32 }
 +fn foo(a: A) {
 +    m!(a.$0)
 +}
 +"#,
 +            expect![[r#"
 +                fd the_field u32
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn works_in_simple_macro_recursive_1() {
 +        check(
 +            r#"
 +macro_rules! m { ($e:expr) => { $e } }
 +struct A { the_field: u32 }
 +fn foo(a: A) {
 +    m!(m!(m!(a.x$0)))
 +}
 +"#,
 +            expect![[r#"
 +                fd the_field u32
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn macro_expansion_resilient() {
 +        check(
 +            r#"
 +macro_rules! d {
 +    () => {};
 +    ($val:expr) => {
 +        match $val { tmp => { tmp } }
 +    };
 +    // Trailing comma with single argument is ignored
 +    ($val:expr,) => { $crate::d!($val) };
 +    ($($val:expr),+ $(,)?) => {
 +        ($($crate::d!($val)),+,)
 +    };
 +}
 +struct A { the_field: u32 }
 +fn foo(a: A) {
 +    d!(a.$0)
 +}
 +"#,
 +            expect![[r#"
 +                fd the_field u32
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_method_completion_issue_3547() {
 +        check(
 +            r#"
 +struct HashSet<T> {}
 +impl<T> HashSet<T> {
 +    pub fn the_method(&self) {}
 +}
 +fn foo() {
 +    let s: HashSet<_>;
 +    s.$0
 +}
 +"#,
 +            expect![[r#"
 +                me the_method() fn(&self)
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn completes_method_call_when_receiver_is_a_macro_call() {
 +        check(
 +            r#"
 +struct S;
 +impl S { fn foo(&self) {} }
 +macro_rules! make_s { () => { S }; }
 +fn main() { make_s!().f$0; }
 +"#,
 +            expect![[r#"
 +                me foo() fn(&self)
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn completes_after_macro_call_in_submodule() {
 +        check(
 +            r#"
 +macro_rules! empty {
 +    () => {};
 +}
 +
 +mod foo {
 +    #[derive(Debug, Default)]
 +    struct Template2 {}
 +
 +    impl Template2 {
 +        fn private(&self) {}
 +    }
 +    fn baz() {
 +        let goo: Template2 = Template2 {};
 +        empty!();
 +        goo.$0
 +    }
 +}
 +        "#,
 +            expect![[r#"
 +                me private() fn(&self)
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn issue_8931() {
 +        check(
 +            r#"
 +//- minicore: fn
 +struct S;
 +
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) -> &[u8] { loop {} }
 +}
 +
 +impl S {
 +    fn indented(&mut self, f: impl FnOnce(&mut Self)) {
 +    }
 +
 +    fn f(&mut self, v: Foo) {
 +        self.indented(|this| v.$0)
 +    }
 +}
 +        "#,
 +            expect![[r#"
 +                me foo() fn(&self) -> &[u8]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn completes_bare_fields_and_methods_in_methods() {
 +        check(
 +            r#"
 +struct Foo { field: i32 }
 +
 +impl Foo { fn foo(&self) { $0 } }"#,
 +            expect![[r#"
 +                fd self.field i32
 +                lc self       &Foo
 +                sp Self
 +                st Foo
 +                bt u32
 +                me self.foo() fn(&self)
 +            "#]],
 +        );
 +        check(
 +            r#"
 +struct Foo(i32);
 +
 +impl Foo { fn foo(&mut self) { $0 } }"#,
 +            expect![[r#"
 +                fd self.0     i32
 +                lc self       &mut Foo
 +                sp Self
 +                st Foo
 +                bt u32
 +                me self.foo() fn(&mut self)
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn macro_completion_after_dot() {
 +        check(
 +            r#"
 +macro_rules! m {
 +    ($e:expr) => { $e };
 +}
 +
 +struct Completable;
 +
 +impl Completable {
 +    fn method(&self) {}
 +}
 +
 +fn f() {
 +    let c = Completable;
 +    m!(c.$0);
 +}
 +    "#,
 +            expect![[r#"
 +                me method() fn(&self)
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn completes_method_call_when_receiver_type_has_errors_issue_10297() {
 +        check(
 +            r#"
 +//- minicore: iterator, sized
 +struct Vec<T>;
 +impl<T> IntoIterator for Vec<T> {
 +    type Item = ();
 +    type IntoIter = ();
 +    fn into_iter(self);
 +}
 +fn main() {
 +    let x: Vec<_>;
 +    x.$0;
 +}
 +"#,
 +            expect![[r#"
 +                me into_iter() (as IntoIterator) fn(self) -> <Self as IntoIterator>::IntoIter
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn postfix_drop_completion() {
 +        cov_mark::check!(postfix_drop_completion);
 +        check_edit(
 +            "drop",
 +            r#"
 +//- minicore: drop
 +struct Vec<T>(T);
 +impl<T> Drop for Vec<T> {
 +    fn drop(&mut self) {}
 +}
 +fn main() {
 +    let x = Vec(0u32)
 +    x.$0;
 +}
 +"#,
 +            r"
 +struct Vec<T>(T);
 +impl<T> Drop for Vec<T> {
 +    fn drop(&mut self) {}
 +}
 +fn main() {
 +    let x = Vec(0u32)
 +    drop($0x);
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn issue_12484() {
 +        check(
 +            r#"
 +//- minicore: sized
 +trait SizeUser {
 +    type Size;
 +}
 +trait Closure: SizeUser {}
 +trait Encrypt: SizeUser {
 +    fn encrypt(self, _: impl Closure<Size = Self::Size>);
 +}
 +fn test(thing: impl Encrypt) {
 +    thing.$0;
 +}
 +        "#,
 +            expect![[r#"
 +                me encrypt(…) (as Encrypt) fn(self, impl Closure<Size = <Self as SizeUser>::Size>)
 +            "#]],
 +        )
 +    }
 +}
index 3989a451bde42a150f8cdb9910df50fe9de245cc,0000000000000000000000000000000000000000..1d03c8cc5ca6d4f9b630b08ee2dc99d622dc9aec
mode 100644,000000..100644
--- /dev/null
@@@ -1,237 -1,0 +1,265 @@@
-                 kw await expr.await
-                 sn box   Box::new(expr)
-                 sn call  function(expr)
-                 sn dbg   dbg!(expr)
-                 sn dbgr  dbg!(&expr)
-                 sn let   let
-                 sn letm  let mut
-                 sn match match expr {}
-                 sn ref   &expr
-                 sn refm  &mut expr
 +//! Completes `where` and `for` keywords.
 +
 +use syntax::ast::{self, Item};
 +
 +use crate::{CompletionContext, Completions};
 +
 +pub(crate) fn complete_for_and_where(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    keyword_item: &ast::Item,
 +) {
 +    let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
 +
 +    match keyword_item {
 +        Item::Impl(it) => {
 +            if it.for_token().is_none() && it.trait_().is_none() && it.self_ty().is_some() {
 +                add_keyword("for", "for");
 +            }
 +            add_keyword("where", "where");
 +        }
 +        Item::Enum(_)
 +        | Item::Fn(_)
 +        | Item::Struct(_)
 +        | Item::Trait(_)
 +        | Item::TypeAlias(_)
 +        | Item::Union(_) => {
 +            add_keyword("where", "where");
 +        }
 +        _ => (),
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use expect_test::{expect, Expect};
 +
 +    use crate::tests::{check_edit, completion_list};
 +
 +    fn check(ra_fixture: &str, expect: Expect) {
 +        let actual = completion_list(ra_fixture);
 +        expect.assert_eq(&actual)
 +    }
 +
 +    #[test]
 +    fn test_else_edit_after_if() {
 +        check_edit(
 +            "else",
 +            r#"fn quux() { if true { () } $0 }"#,
 +            r#"fn quux() { if true { () } else {
 +    $0
 +} }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_keywords_after_unsafe_in_block_expr() {
 +        check(
 +            r"fn my_fn() { unsafe $0 }",
 +            expect![[r#"
 +                kw fn
 +                kw impl
 +                kw trait
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_completion_await_impls_future() {
 +        check(
 +            r#"
 +//- minicore: future
 +use core::future::*;
 +struct A {}
 +impl Future for A {}
 +fn foo(a: A) { a.$0 }
 +"#,
 +            expect![[r#"
-                 kw await expr.await
-                 sn box   Box::new(expr)
-                 sn call  function(expr)
-                 sn dbg   dbg!(expr)
-                 sn dbgr  dbg!(&expr)
-                 sn let   let
-                 sn letm  let mut
-                 sn match match expr {}
-                 sn ref   &expr
-                 sn refm  &mut expr
++                kw await                  expr.await
++                me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
++                sn box                    Box::new(expr)
++                sn call                   function(expr)
++                sn dbg                    dbg!(expr)
++                sn dbgr                   dbg!(&expr)
++                sn let                    let
++                sn letm                   let mut
++                sn match                  match expr {}
++                sn ref                    &expr
++                sn refm                   &mut expr
 +            "#]],
 +        );
 +
 +        check(
 +            r#"
 +//- minicore: future
 +use std::future::*;
 +fn foo() {
 +    let a = async {};
 +    a.$0
 +}
 +"#,
 +            expect![[r#"
-         )
++                kw await                  expr.await
++                me into_future() (use core::future::IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
++                sn box                    Box::new(expr)
++                sn call                   function(expr)
++                sn dbg                    dbg!(expr)
++                sn dbgr                   dbg!(&expr)
++                sn let                    let
++                sn letm                   let mut
++                sn match                  match expr {}
++                sn ref                    &expr
++                sn refm                   &mut expr
 +            "#]],
++        );
++    }
++
++    #[test]
++    fn test_completion_await_impls_into_future() {
++        check(
++            r#"
++//- minicore: future
++use core::future::*;
++struct A {}
++impl IntoFuture for A {}
++fn foo(a: A) { a.$0 }
++"#,
++            expect![[r#"
++                kw await                  expr.await
++                me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
++                sn box                    Box::new(expr)
++                sn call                   function(expr)
++                sn dbg                    dbg!(expr)
++                sn dbgr                   dbg!(&expr)
++                sn let                    let
++                sn letm                   let mut
++                sn match                  match expr {}
++                sn ref                    &expr
++                sn refm                   &mut expr
++            "#]],
++        );
 +    }
 +
 +    #[test]
 +    fn let_semi() {
 +        cov_mark::check!(let_semi);
 +        check_edit(
 +            "match",
 +            r#"
 +fn main() { let x = $0 }
 +"#,
 +            r#"
 +fn main() { let x = match $1 {
 +    $0
 +}; }
 +"#,
 +        );
 +
 +        check_edit(
 +            "if",
 +            r#"
 +fn main() {
 +    let x = $0
 +    let y = 92;
 +}
 +"#,
 +            r#"
 +fn main() {
 +    let x = if $1 {
 +    $0
 +};
 +    let y = 92;
 +}
 +"#,
 +        );
 +
 +        check_edit(
 +            "loop",
 +            r#"
 +fn main() {
 +    let x = $0
 +    bar();
 +}
 +"#,
 +            r#"
 +fn main() {
 +    let x = loop {
 +    $0
 +};
 +    bar();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn if_completion_in_match_guard() {
 +        check_edit(
 +            "if",
 +            r"
 +fn main() {
 +    match () {
 +        () $0
 +    }
 +}
 +",
 +            r"
 +fn main() {
 +    match () {
 +        () if $0
 +    }
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn if_completion_in_match_arm_expr() {
 +        check_edit(
 +            "if",
 +            r"
 +fn main() {
 +    match () {
 +        () => $0
 +    }
 +}
 +",
 +            r"
 +fn main() {
 +    match () {
 +        () => if $1 {
 +    $0
 +}
 +    }
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn if_completion_in_match_arm_expr_block() {
 +        check_edit(
 +            "if",
 +            r"
 +fn main() {
 +    match () {
 +        () => {
 +            $0
 +        }
 +    }
 +}
 +",
 +            r"
 +fn main() {
 +    match () {
 +        () => {
 +            if $1 {
 +    $0
 +}
 +        }
 +    }
 +}
 +",
 +        )
 +    }
 +}
index 6b94347e0ad05cb7e3b7d451184cfcdc1d04dfdc,0000000000000000000000000000000000000000..b273a4cb53ba1da2631b42798f5ecd86c11c1805
mode 100644,000000..100644
--- /dev/null
@@@ -1,311 -1,0 +1,311 @@@
-                     // path seperator
 +// Feature: Format String Completion
 +//
 +// `"Result {result} is {2 + 2}"` is expanded to the `"Result {} is {}", result, 2 + 2`.
 +//
 +// The following postfix snippets are available:
 +//
 +// * `format` -> `format!(...)`
 +// * `panic` -> `panic!(...)`
 +// * `println` -> `println!(...)`
 +// * `log`:
 +// ** `logd` -> `log::debug!(...)`
 +// ** `logt` -> `log::trace!(...)`
 +// ** `logi` -> `log::info!(...)`
 +// ** `logw` -> `log::warn!(...)`
 +// ** `loge` -> `log::error!(...)`
 +//
 +// image::https://user-images.githubusercontent.com/48062697/113020656-b560f500-917a-11eb-87de-02991f61beb8.gif[]
 +
 +use ide_db::SnippetCap;
 +use syntax::ast::{self, AstToken};
 +
 +use crate::{
 +    completions::postfix::build_postfix_snippet_builder, context::CompletionContext, Completions,
 +};
 +
 +/// Mapping ("postfix completion item" => "macro to use")
 +static KINDS: &[(&str, &str)] = &[
 +    ("format", "format!"),
 +    ("panic", "panic!"),
 +    ("println", "println!"),
 +    ("eprintln", "eprintln!"),
 +    ("logd", "log::debug!"),
 +    ("logt", "log::trace!"),
 +    ("logi", "log::info!"),
 +    ("logw", "log::warn!"),
 +    ("loge", "log::error!"),
 +];
 +
 +pub(crate) fn add_format_like_completions(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    dot_receiver: &ast::Expr,
 +    cap: SnippetCap,
 +    receiver_text: &ast::String,
 +) {
 +    let input = match string_literal_contents(receiver_text) {
 +        // It's not a string literal, do not parse input.
 +        Some(input) => input,
 +        None => return,
 +    };
 +
 +    let postfix_snippet = match build_postfix_snippet_builder(ctx, cap, dot_receiver) {
 +        Some(it) => it,
 +        None => return,
 +    };
 +    let mut parser = FormatStrParser::new(input);
 +
 +    if parser.parse().is_ok() {
 +        for (label, macro_name) in KINDS {
 +            let snippet = parser.to_suggestion(macro_name);
 +
 +            postfix_snippet(label, macro_name, &snippet).add_to(acc);
 +        }
 +    }
 +}
 +
 +/// Checks whether provided item is a string literal.
 +fn string_literal_contents(item: &ast::String) -> Option<String> {
 +    let item = item.text();
 +    if item.len() >= 2 && item.starts_with('\"') && item.ends_with('\"') {
 +        return Some(item[1..item.len() - 1].to_owned());
 +    }
 +
 +    None
 +}
 +
 +/// Parser for a format-like string. It is more allowing in terms of string contents,
 +/// as we expect variable placeholders to be filled with expressions.
 +#[derive(Debug)]
 +pub(crate) struct FormatStrParser {
 +    input: String,
 +    output: String,
 +    extracted_expressions: Vec<String>,
 +    state: State,
 +    parsed: bool,
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq)]
 +enum State {
 +    NotExpr,
 +    MaybeExpr,
 +    Expr,
 +    MaybeIncorrect,
 +    FormatOpts,
 +}
 +
 +impl FormatStrParser {
 +    pub(crate) fn new(input: String) -> Self {
 +        Self {
 +            input,
 +            output: String::new(),
 +            extracted_expressions: Vec::new(),
 +            state: State::NotExpr,
 +            parsed: false,
 +        }
 +    }
 +
 +    pub(crate) fn parse(&mut self) -> Result<(), ()> {
 +        let mut current_expr = String::new();
 +
 +        let mut placeholder_id = 1;
 +
 +        // Count of open braces inside of an expression.
 +        // We assume that user knows what they're doing, thus we treat it like a correct pattern, e.g.
 +        // "{MyStruct { val_a: 0, val_b: 1 }}".
 +        let mut inexpr_open_count = 0;
 +
 +        // We need to escape '\' and '$'. See the comments on `get_receiver_text()` for detail.
 +        let mut chars = self.input.chars().peekable();
 +        while let Some(chr) = chars.next() {
 +            match (self.state, chr) {
 +                (State::NotExpr, '{') => {
 +                    self.output.push(chr);
 +                    self.state = State::MaybeExpr;
 +                }
 +                (State::NotExpr, '}') => {
 +                    self.output.push(chr);
 +                    self.state = State::MaybeIncorrect;
 +                }
 +                (State::NotExpr, _) => {
 +                    if matches!(chr, '\\' | '$') {
 +                        self.output.push('\\');
 +                    }
 +                    self.output.push(chr);
 +                }
 +                (State::MaybeIncorrect, '}') => {
 +                    // It's okay, we met "}}".
 +                    self.output.push(chr);
 +                    self.state = State::NotExpr;
 +                }
 +                (State::MaybeIncorrect, _) => {
 +                    // Error in the string.
 +                    return Err(());
 +                }
 +                (State::MaybeExpr, '{') => {
 +                    self.output.push(chr);
 +                    self.state = State::NotExpr;
 +                }
 +                (State::MaybeExpr, '}') => {
 +                    // This is an empty sequence '{}'. Replace it with placeholder.
 +                    self.output.push(chr);
 +                    self.extracted_expressions.push(format!("${}", placeholder_id));
 +                    placeholder_id += 1;
 +                    self.state = State::NotExpr;
 +                }
 +                (State::MaybeExpr, _) => {
 +                    if matches!(chr, '\\' | '$') {
 +                        current_expr.push('\\');
 +                    }
 +                    current_expr.push(chr);
 +                    self.state = State::Expr;
 +                }
 +                (State::Expr, '}') => {
 +                    if inexpr_open_count == 0 {
 +                        self.output.push(chr);
 +                        self.extracted_expressions.push(current_expr.trim().into());
 +                        current_expr = String::new();
 +                        self.state = State::NotExpr;
 +                    } else {
 +                        // We're closing one brace met before inside of the expression.
 +                        current_expr.push(chr);
 +                        inexpr_open_count -= 1;
 +                    }
 +                }
 +                (State::Expr, ':') if chars.peek().copied() == Some(':') => {
-                         // We're inside of braced expression, assume that it's a struct field name/value delimeter.
++                    // path separator
 +                    current_expr.push_str("::");
 +                    chars.next();
 +                }
 +                (State::Expr, ':') => {
 +                    if inexpr_open_count == 0 {
 +                        // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}"
 +                        self.output.push(chr);
 +                        self.extracted_expressions.push(current_expr.trim().into());
 +                        current_expr = String::new();
 +                        self.state = State::FormatOpts;
 +                    } else {
++                        // We're inside of braced expression, assume that it's a struct field name/value delimiter.
 +                        current_expr.push(chr);
 +                    }
 +                }
 +                (State::Expr, '{') => {
 +                    current_expr.push(chr);
 +                    inexpr_open_count += 1;
 +                }
 +                (State::Expr, _) => {
 +                    if matches!(chr, '\\' | '$') {
 +                        current_expr.push('\\');
 +                    }
 +                    current_expr.push(chr);
 +                }
 +                (State::FormatOpts, '}') => {
 +                    self.output.push(chr);
 +                    self.state = State::NotExpr;
 +                }
 +                (State::FormatOpts, _) => {
 +                    if matches!(chr, '\\' | '$') {
 +                        self.output.push('\\');
 +                    }
 +                    self.output.push(chr);
 +                }
 +            }
 +        }
 +
 +        if self.state != State::NotExpr {
 +            return Err(());
 +        }
 +
 +        self.parsed = true;
 +        Ok(())
 +    }
 +
 +    pub(crate) fn to_suggestion(&self, macro_name: &str) -> String {
 +        assert!(self.parsed, "Attempt to get a suggestion from not parsed expression");
 +
 +        let expressions_as_string = self.extracted_expressions.join(", ");
 +        format!(r#"{}("{}", {})"#, macro_name, self.output, expressions_as_string)
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use super::*;
 +    use expect_test::{expect, Expect};
 +
 +    fn check(input: &str, expect: &Expect) {
 +        let mut parser = FormatStrParser::new((*input).to_owned());
 +        let outcome_repr = if parser.parse().is_ok() {
 +            // Parsing should be OK, expected repr is "string; expr_1, expr_2".
 +            if parser.extracted_expressions.is_empty() {
 +                parser.output
 +            } else {
 +                format!("{}; {}", parser.output, parser.extracted_expressions.join(", "))
 +            }
 +        } else {
 +            // Parsing should fail, expected repr is "-".
 +            "-".to_owned()
 +        };
 +
 +        expect.assert_eq(&outcome_repr);
 +    }
 +
 +    #[test]
 +    fn format_str_parser() {
 +        let test_vector = &[
 +            ("no expressions", expect![["no expressions"]]),
 +            (r"no expressions with \$0$1", expect![r"no expressions with \\\$0\$1"]),
 +            ("{expr} is {2 + 2}", expect![["{} is {}; expr, 2 + 2"]]),
 +            ("{expr:?}", expect![["{:?}; expr"]]),
 +            ("{expr:1$}", expect![[r"{:1\$}; expr"]]),
 +            ("{$0}", expect![[r"{}; \$0"]]),
 +            ("{malformed", expect![["-"]]),
 +            ("malformed}", expect![["-"]]),
 +            ("{{correct", expect![["{{correct"]]),
 +            ("correct}}", expect![["correct}}"]]),
 +            ("{correct}}}", expect![["{}}}; correct"]]),
 +            ("{correct}}}}}", expect![["{}}}}}; correct"]]),
 +            ("{incorrect}}", expect![["-"]]),
 +            ("placeholders {} {}", expect![["placeholders {} {}; $1, $2"]]),
 +            ("mixed {} {2 + 2} {}", expect![["mixed {} {} {}; $1, 2 + 2, $2"]]),
 +            (
 +                "{SomeStruct { val_a: 0, val_b: 1 }}",
 +                expect![["{}; SomeStruct { val_a: 0, val_b: 1 }"]],
 +            ),
 +            ("{expr:?} is {2.32f64:.5}", expect![["{:?} is {:.5}; expr, 2.32f64"]]),
 +            (
 +                "{SomeStruct { val_a: 0, val_b: 1 }:?}",
 +                expect![["{:?}; SomeStruct { val_a: 0, val_b: 1 }"]],
 +            ),
 +            ("{     2 + 2        }", expect![["{}; 2 + 2"]]),
 +            ("{strsim::jaro_winkle(a)}", expect![["{}; strsim::jaro_winkle(a)"]]),
 +            ("{foo::bar::baz()}", expect![["{}; foo::bar::baz()"]]),
 +            ("{foo::bar():?}", expect![["{:?}; foo::bar()"]]),
 +        ];
 +
 +        for (input, output) in test_vector {
 +            check(input, output)
 +        }
 +    }
 +
 +    #[test]
 +    fn test_into_suggestion() {
 +        let test_vector = &[
 +            ("println!", "{}", r#"println!("{}", $1)"#),
 +            ("eprintln!", "{}", r#"eprintln!("{}", $1)"#),
 +            (
 +                "log::info!",
 +                "{} {expr} {} {2 + 2}",
 +                r#"log::info!("{} {} {} {}", $1, expr, $2, 2 + 2)"#,
 +            ),
 +            ("format!", "{expr:?}", r#"format!("{:?}", expr)"#),
 +        ];
 +
 +        for (kind, input, output) in test_vector {
 +            let mut parser = FormatStrParser::new((*input).to_owned());
 +            parser.parse().expect("Parsing must succeed");
 +
 +            assert_eq!(&parser.to_suggestion(*kind), output);
 +        }
 +    }
 +}
index bfb98b9f2777fbfecaba4208c7be17a3ff7a4008,0000000000000000000000000000000000000000..5d96fbd30a81d1c4dd02f8a38e68b00602096c61
mode 100644,000000..100644
--- /dev/null
@@@ -1,368 -1,0 +1,368 @@@
-             "FooDesc {…}",
 +//! Complete fields in record literals and patterns.
 +use ide_db::SymbolKind;
 +use syntax::ast::{self, Expr};
 +
 +use crate::{
 +    context::{DotAccess, DotAccessKind, PatternContext},
 +    CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
 +    CompletionRelevancePostfixMatch, Completions,
 +};
 +
 +pub(crate) fn complete_record_pattern_fields(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    pattern_ctx: &PatternContext,
 +) {
 +    if let PatternContext { record_pat: Some(record_pat), .. } = pattern_ctx {
 +        let ty = ctx.sema.type_of_pat(&ast::Pat::RecordPat(record_pat.clone()));
 +        let missing_fields = match ty.as_ref().and_then(|t| t.original.as_adt()) {
 +            Some(hir::Adt::Union(un)) => {
 +                // ctx.sema.record_pat_missing_fields will always return
 +                // an empty Vec on a union literal. This is normally
 +                // reasonable, but here we'd like to present the full list
 +                // of fields if the literal is empty.
 +                let were_fields_specified =
 +                    record_pat.record_pat_field_list().and_then(|fl| fl.fields().next()).is_some();
 +
 +                match were_fields_specified {
 +                    false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(),
 +                    true => return,
 +                }
 +            }
 +            _ => ctx.sema.record_pattern_missing_fields(record_pat),
 +        };
 +        complete_fields(acc, ctx, missing_fields);
 +    }
 +}
 +
 +pub(crate) fn complete_record_expr_fields(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    record_expr: &ast::RecordExpr,
 +    &dot_prefix: &bool,
 +) {
 +    let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
 +
 +    let missing_fields = match ty.as_ref().and_then(|t| t.original.as_adt()) {
 +        Some(hir::Adt::Union(un)) => {
 +            // ctx.sema.record_literal_missing_fields will always return
 +            // an empty Vec on a union literal. This is normally
 +            // reasonable, but here we'd like to present the full list
 +            // of fields if the literal is empty.
 +            let were_fields_specified =
 +                record_expr.record_expr_field_list().and_then(|fl| fl.fields().next()).is_some();
 +
 +            match were_fields_specified {
 +                false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(),
 +                true => return,
 +            }
 +        }
 +        _ => {
 +            let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
 +
 +            if !missing_fields.is_empty() {
 +                cov_mark::hit!(functional_update_field);
 +                add_default_update(acc, ctx, ty);
 +            }
 +            if dot_prefix {
 +                cov_mark::hit!(functional_update_one_dot);
 +                let mut item =
 +                    CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), "..");
 +                item.insert_text(".");
 +                item.add_to(acc);
 +                return;
 +            }
 +            missing_fields
 +        }
 +    };
 +    complete_fields(acc, ctx, missing_fields);
 +}
 +
 +pub(crate) fn add_default_update(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    ty: Option<hir::TypeInfo>,
 +) {
 +    let default_trait = ctx.famous_defs().core_default_Default();
 +    let impls_default_trait = default_trait
 +        .zip(ty.as_ref())
 +        .map_or(false, |(default_trait, ty)| ty.original.impls_trait(ctx.db, default_trait, &[]));
 +    if impls_default_trait {
 +        // FIXME: This should make use of scope_def like completions so we get all the other goodies
 +        // that is we should handle this like actually completing the default function
 +        let completion_text = "..Default::default()";
 +        let mut item = CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text);
 +        let completion_text =
 +            completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
 +        item.insert_text(completion_text).set_relevance(CompletionRelevance {
 +            postfix_match: Some(CompletionRelevancePostfixMatch::Exact),
 +            ..Default::default()
 +        });
 +        item.add_to(acc);
 +    }
 +}
 +
 +fn complete_fields(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    missing_fields: Vec<(hir::Field, hir::Type)>,
 +) {
 +    for (field, ty) in missing_fields {
 +        acc.add_field(
 +            ctx,
 +            &DotAccess {
 +                receiver: None,
 +                receiver_ty: None,
 +                kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false },
 +            },
 +            None,
 +            field,
 +            &ty,
 +        );
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::check_edit;
 +
 +    #[test]
 +    fn literal_struct_completion_edit() {
 +        check_edit(
-             "Self {…}",
++            "FooDesc{}",
 +            r#"
 +struct FooDesc { pub bar: bool }
 +
 +fn create_foo(foo_desc: &FooDesc) -> () { () }
 +
 +fn baz() {
 +    let foo = create_foo(&$0);
 +}
 +            "#,
 +            r#"
 +struct FooDesc { pub bar: bool }
 +
 +fn create_foo(foo_desc: &FooDesc) -> () { () }
 +
 +fn baz() {
 +    let foo = create_foo(&FooDesc { bar: ${1:()} }$0);
 +}
 +            "#,
 +        )
 +    }
 +
 +    #[test]
 +    fn literal_struct_impl_self_completion() {
 +        check_edit(
-             "Self(…)",
++            "Self{}",
 +            r#"
 +struct Foo {
 +    bar: u64,
 +}
 +
 +impl Foo {
 +    fn new() -> Foo {
 +        Self$0
 +    }
 +}
 +            "#,
 +            r#"
 +struct Foo {
 +    bar: u64,
 +}
 +
 +impl Foo {
 +    fn new() -> Foo {
 +        Self { bar: ${1:()} }$0
 +    }
 +}
 +            "#,
 +        );
 +
 +        check_edit(
-             "submod::Struct {…}",
++            "Self()",
 +            r#"
 +mod submod {
 +    pub struct Foo(pub u64);
 +}
 +
 +impl submod::Foo {
 +    fn new() -> submod::Foo {
 +        Self$0
 +    }
 +}
 +            "#,
 +            r#"
 +mod submod {
 +    pub struct Foo(pub u64);
 +}
 +
 +impl submod::Foo {
 +    fn new() -> submod::Foo {
 +        Self(${1:()})$0
 +    }
 +}
 +            "#,
 +        )
 +    }
 +
 +    #[test]
 +    fn literal_struct_completion_from_sub_modules() {
 +        check_edit(
-             "FooDesc {…}",
++            "submod::Struct{}",
 +            r#"
 +mod submod {
 +    pub struct Struct {
 +        pub a: u64,
 +    }
 +}
 +
 +fn f() -> submod::Struct {
 +    Stru$0
 +}
 +            "#,
 +            r#"
 +mod submod {
 +    pub struct Struct {
 +        pub a: u64,
 +    }
 +}
 +
 +fn f() -> submod::Struct {
 +    submod::Struct { a: ${1:()} }$0
 +}
 +            "#,
 +        )
 +    }
 +
 +    #[test]
 +    fn literal_struct_complexion_module() {
 +        check_edit(
++            "FooDesc{}",
 +            r#"
 +mod _69latrick {
 +    pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
 +    pub fn create_foo(foo_desc: &FooDesc) -> () { () }
 +}
 +
 +fn baz() {
 +    use _69latrick::*;
 +
 +    let foo = create_foo(&$0);
 +}
 +            "#,
 +            r#"
 +mod _69latrick {
 +    pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, pub bar: bool }
 +    pub fn create_foo(foo_desc: &FooDesc) -> () { () }
 +}
 +
 +fn baz() {
 +    use _69latrick::*;
 +
 +    let foo = create_foo(&FooDesc { six: ${1:()}, neuf: ${2:()}, bar: ${3:()} }$0);
 +}
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn default_completion_edit() {
 +        check_edit(
 +            "..Default::default()",
 +            r#"
 +//- minicore: default
 +struct Struct { foo: u32, bar: usize }
 +
 +impl Default for Struct {
 +    fn default() -> Self {}
 +}
 +
 +fn foo() {
 +    let other = Struct {
 +        foo: 5,
 +        .$0
 +    };
 +}
 +"#,
 +            r#"
 +struct Struct { foo: u32, bar: usize }
 +
 +impl Default for Struct {
 +    fn default() -> Self {}
 +}
 +
 +fn foo() {
 +    let other = Struct {
 +        foo: 5,
 +        ..Default::default()
 +    };
 +}
 +"#,
 +        );
 +        check_edit(
 +            "..Default::default()",
 +            r#"
 +//- minicore: default
 +struct Struct { foo: u32, bar: usize }
 +
 +impl Default for Struct {
 +    fn default() -> Self {}
 +}
 +
 +fn foo() {
 +    let other = Struct {
 +        foo: 5,
 +        $0
 +    };
 +}
 +"#,
 +            r#"
 +struct Struct { foo: u32, bar: usize }
 +
 +impl Default for Struct {
 +    fn default() -> Self {}
 +}
 +
 +fn foo() {
 +    let other = Struct {
 +        foo: 5,
 +        ..Default::default()
 +    };
 +}
 +"#,
 +        );
 +        check_edit(
 +            "..Default::default()",
 +            r#"
 +//- minicore: default
 +struct Struct { foo: u32, bar: usize }
 +
 +impl Default for Struct {
 +    fn default() -> Self {}
 +}
 +
 +fn foo() {
 +    let other = Struct {
 +        foo: 5,
 +        ..$0
 +    };
 +}
 +"#,
 +            r#"
 +struct Struct { foo: u32, bar: usize }
 +
 +impl Default for Struct {
 +    fn default() -> Self {}
 +}
 +
 +fn foo() {
 +    let other = Struct {
 +        foo: 5,
 +        ..Default::default()
 +    };
 +}
 +"#,
 +        );
 +    }
 +}
index 693007ca3071a7cc2a5ee5fd205f66a62b291fd0,0000000000000000000000000000000000000000..a2cf6d68e5b3a08529ece70ce8b455a232cf5010
mode 100644,000000..100644
--- /dev/null
@@@ -1,1911 -1,0 +1,1913 @@@
-                         lookup: "Spam::Bar(…)",
 +//! `render` module provides utilities for rendering completion suggestions
 +//! into code pieces that will be presented to user.
 +
 +pub(crate) mod macro_;
 +pub(crate) mod function;
 +pub(crate) mod const_;
 +pub(crate) mod pattern;
 +pub(crate) mod type_alias;
 +pub(crate) mod variant;
 +pub(crate) mod union_literal;
 +pub(crate) mod literal;
 +
 +use hir::{AsAssocItem, HasAttrs, HirDisplay, ScopeDef};
 +use ide_db::{
 +    helpers::item_name, imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind,
 +};
 +use syntax::{AstNode, SmolStr, SyntaxKind, TextRange};
 +
 +use crate::{
 +    context::{DotAccess, PathCompletionCtx, PathKind, PatternContext},
 +    item::{Builder, CompletionRelevanceTypeMatch},
 +    render::{
 +        function::render_fn,
 +        literal::render_variant_lit,
 +        macro_::{render_macro, render_macro_pat},
 +    },
 +    CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
 +};
 +/// Interface for data and methods required for items rendering.
 +#[derive(Debug, Clone)]
 +pub(crate) struct RenderContext<'a> {
 +    completion: &'a CompletionContext<'a>,
 +    is_private_editable: bool,
 +    import_to_add: Option<LocatedImport>,
 +}
 +
 +impl<'a> RenderContext<'a> {
 +    pub(crate) fn new(completion: &'a CompletionContext<'a>) -> RenderContext<'a> {
 +        RenderContext { completion, is_private_editable: false, import_to_add: None }
 +    }
 +
 +    pub(crate) fn private_editable(mut self, private_editable: bool) -> Self {
 +        self.is_private_editable = private_editable;
 +        self
 +    }
 +
 +    pub(crate) fn import_to_add(mut self, import_to_add: Option<LocatedImport>) -> Self {
 +        self.import_to_add = import_to_add;
 +        self
 +    }
 +
 +    fn snippet_cap(&self) -> Option<SnippetCap> {
 +        self.completion.config.snippet_cap
 +    }
 +
 +    fn db(&self) -> &'a RootDatabase {
 +        self.completion.db
 +    }
 +
 +    fn source_range(&self) -> TextRange {
 +        self.completion.source_range()
 +    }
 +
 +    fn completion_relevance(&self) -> CompletionRelevance {
 +        CompletionRelevance {
 +            is_private_editable: self.is_private_editable,
 +            requires_import: self.import_to_add.is_some(),
 +            ..Default::default()
 +        }
 +    }
 +
 +    fn is_immediately_after_macro_bang(&self) -> bool {
 +        self.completion.token.kind() == SyntaxKind::BANG
 +            && self
 +                .completion
 +                .token
 +                .parent()
 +                .map_or(false, |it| it.kind() == SyntaxKind::MACRO_CALL)
 +    }
 +
 +    fn is_deprecated(&self, def: impl HasAttrs) -> bool {
 +        let attrs = def.attrs(self.db());
 +        attrs.by_key("deprecated").exists()
 +    }
 +
 +    fn is_deprecated_assoc_item(&self, as_assoc_item: impl AsAssocItem) -> bool {
 +        let db = self.db();
 +        let assoc = match as_assoc_item.as_assoc_item(db) {
 +            Some(assoc) => assoc,
 +            None => return false,
 +        };
 +
 +        let is_assoc_deprecated = match assoc {
 +            hir::AssocItem::Function(it) => self.is_deprecated(it),
 +            hir::AssocItem::Const(it) => self.is_deprecated(it),
 +            hir::AssocItem::TypeAlias(it) => self.is_deprecated(it),
 +        };
 +        is_assoc_deprecated
 +            || assoc
 +                .containing_trait_or_trait_impl(db)
 +                .map(|trait_| self.is_deprecated(trait_))
 +                .unwrap_or(false)
 +    }
 +
 +    // FIXME: remove this
 +    fn docs(&self, def: impl HasAttrs) -> Option<hir::Documentation> {
 +        def.docs(self.db())
 +    }
 +}
 +
 +pub(crate) fn render_field(
 +    ctx: RenderContext<'_>,
 +    dot_access: &DotAccess,
 +    receiver: Option<hir::Name>,
 +    field: hir::Field,
 +    ty: &hir::Type,
 +) -> CompletionItem {
 +    let is_deprecated = ctx.is_deprecated(field);
 +    let name = field.name(ctx.db());
 +    let (name, escaped_name) = (name.unescaped().to_smol_str(), name.to_smol_str());
 +    let mut item = CompletionItem::new(
 +        SymbolKind::Field,
 +        ctx.source_range(),
 +        field_with_receiver(receiver.as_ref(), &name),
 +    );
 +    item.set_relevance(CompletionRelevance {
 +        type_match: compute_type_match(ctx.completion, ty),
 +        exact_name_match: compute_exact_name_match(ctx.completion, name.as_str()),
 +        ..CompletionRelevance::default()
 +    });
 +    item.detail(ty.display(ctx.db()).to_string())
 +        .set_documentation(field.docs(ctx.db()))
 +        .set_deprecated(is_deprecated)
 +        .lookup_by(name.clone());
 +    item.insert_text(field_with_receiver(receiver.as_ref(), &escaped_name));
 +    if let Some(receiver) = &dot_access.receiver {
 +        if let Some(original) = ctx.completion.sema.original_ast_node(receiver.clone()) {
 +            if let Some(ref_match) = compute_ref_match(ctx.completion, ty) {
 +                item.ref_match(ref_match, original.syntax().text_range().start());
 +            }
 +        }
 +    }
 +    item.build()
 +}
 +
 +fn field_with_receiver(receiver: Option<&hir::Name>, field_name: &str) -> SmolStr {
 +    receiver
 +        .map_or_else(|| field_name.into(), |receiver| format!("{}.{}", receiver, field_name).into())
 +}
 +
 +pub(crate) fn render_tuple_field(
 +    ctx: RenderContext<'_>,
 +    receiver: Option<hir::Name>,
 +    field: usize,
 +    ty: &hir::Type,
 +) -> CompletionItem {
 +    let mut item = CompletionItem::new(
 +        SymbolKind::Field,
 +        ctx.source_range(),
 +        field_with_receiver(receiver.as_ref(), &field.to_string()),
 +    );
 +    item.detail(ty.display(ctx.db()).to_string()).lookup_by(field.to_string());
 +    item.build()
 +}
 +
 +pub(crate) fn render_type_inference(
 +    ty_string: String,
 +    ctx: &CompletionContext<'_>,
 +) -> CompletionItem {
 +    let mut builder =
 +        CompletionItem::new(CompletionItemKind::InferredType, ctx.source_range(), ty_string);
 +    builder.set_relevance(CompletionRelevance { is_definite: true, ..Default::default() });
 +    builder.build()
 +}
 +
 +pub(crate) fn render_path_resolution(
 +    ctx: RenderContext<'_>,
 +    path_ctx: &PathCompletionCtx,
 +    local_name: hir::Name,
 +    resolution: ScopeDef,
 +) -> Builder {
 +    render_resolution_path(ctx, path_ctx, local_name, None, resolution)
 +}
 +
 +pub(crate) fn render_pattern_resolution(
 +    ctx: RenderContext<'_>,
 +    pattern_ctx: &PatternContext,
 +    local_name: hir::Name,
 +    resolution: ScopeDef,
 +) -> Builder {
 +    render_resolution_pat(ctx, pattern_ctx, local_name, None, resolution)
 +}
 +
 +pub(crate) fn render_resolution_with_import(
 +    ctx: RenderContext<'_>,
 +    path_ctx: &PathCompletionCtx,
 +    import_edit: LocatedImport,
 +) -> Option<Builder> {
 +    let resolution = ScopeDef::from(import_edit.original_item);
 +    let local_name = scope_def_to_name(resolution, &ctx, &import_edit)?;
 +
 +    Some(render_resolution_path(ctx, path_ctx, local_name, Some(import_edit), resolution))
 +}
 +
 +pub(crate) fn render_resolution_with_import_pat(
 +    ctx: RenderContext<'_>,
 +    pattern_ctx: &PatternContext,
 +    import_edit: LocatedImport,
 +) -> Option<Builder> {
 +    let resolution = ScopeDef::from(import_edit.original_item);
 +    let local_name = scope_def_to_name(resolution, &ctx, &import_edit)?;
 +    Some(render_resolution_pat(ctx, pattern_ctx, local_name, Some(import_edit), resolution))
 +}
 +
 +fn scope_def_to_name(
 +    resolution: ScopeDef,
 +    ctx: &RenderContext<'_>,
 +    import_edit: &LocatedImport,
 +) -> Option<hir::Name> {
 +    Some(match resolution {
 +        ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
 +        ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
 +        ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
 +        _ => item_name(ctx.db(), import_edit.original_item)?,
 +    })
 +}
 +
 +fn render_resolution_pat(
 +    ctx: RenderContext<'_>,
 +    pattern_ctx: &PatternContext,
 +    local_name: hir::Name,
 +    import_to_add: Option<LocatedImport>,
 +    resolution: ScopeDef,
 +) -> Builder {
 +    let _p = profile::span("render_resolution");
 +    use hir::ModuleDef::*;
 +
 +    match resolution {
 +        ScopeDef::ModuleDef(Macro(mac)) => {
 +            let ctx = ctx.import_to_add(import_to_add);
 +            return render_macro_pat(ctx, pattern_ctx, local_name, mac);
 +        }
 +        _ => (),
 +    }
 +
 +    render_resolution_simple_(ctx, &local_name, import_to_add, resolution)
 +}
 +
 +fn render_resolution_path(
 +    ctx: RenderContext<'_>,
 +    path_ctx: &PathCompletionCtx,
 +    local_name: hir::Name,
 +    import_to_add: Option<LocatedImport>,
 +    resolution: ScopeDef,
 +) -> Builder {
 +    let _p = profile::span("render_resolution");
 +    use hir::ModuleDef::*;
 +
 +    match resolution {
 +        ScopeDef::ModuleDef(Macro(mac)) => {
 +            let ctx = ctx.import_to_add(import_to_add);
 +            return render_macro(ctx, path_ctx, local_name, mac);
 +        }
 +        ScopeDef::ModuleDef(Function(func)) => {
 +            let ctx = ctx.import_to_add(import_to_add);
 +            return render_fn(ctx, path_ctx, Some(local_name), func);
 +        }
 +        ScopeDef::ModuleDef(Variant(var)) => {
 +            let ctx = ctx.clone().import_to_add(import_to_add.clone());
 +            if let Some(item) =
 +                render_variant_lit(ctx, path_ctx, Some(local_name.clone()), var, None)
 +            {
 +                return item;
 +            }
 +        }
 +        _ => (),
 +    }
 +
 +    let completion = ctx.completion;
 +    let cap = ctx.snippet_cap();
 +    let db = completion.db;
 +    let config = completion.config;
 +
 +    let name = local_name.to_smol_str();
 +    let mut item = render_resolution_simple_(ctx, &local_name, import_to_add, resolution);
 +    if local_name.is_escaped() {
 +        item.insert_text(local_name.to_smol_str());
 +    }
 +    // Add `<>` for generic types
 +    let type_path_no_ty_args = matches!(
 +        path_ctx,
 +        PathCompletionCtx { kind: PathKind::Type { .. }, has_type_args: false, .. }
 +    ) && config.callable.is_some();
 +    if type_path_no_ty_args {
 +        if let Some(cap) = cap {
 +            let has_non_default_type_params = match resolution {
 +                ScopeDef::ModuleDef(hir::ModuleDef::Adt(it)) => it.has_non_default_type_params(db),
 +                ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(it)) => {
 +                    it.has_non_default_type_params(db)
 +                }
 +                _ => false,
 +            };
 +
 +            if has_non_default_type_params {
 +                cov_mark::hit!(inserts_angle_brackets_for_generics);
 +                item.lookup_by(name.clone())
 +                    .label(SmolStr::from_iter([&name, "<…>"]))
 +                    .trigger_call_info()
 +                    .insert_snippet(cap, format!("{}<$0>", local_name));
 +            }
 +        }
 +    }
 +    if let ScopeDef::Local(local) = resolution {
 +        let ty = local.ty(db);
 +        if !ty.is_unknown() {
 +            item.detail(ty.display(db).to_string());
 +        }
 +
 +        item.set_relevance(CompletionRelevance {
 +            type_match: compute_type_match(completion, &ty),
 +            exact_name_match: compute_exact_name_match(completion, &name),
 +            is_local: true,
 +            ..CompletionRelevance::default()
 +        });
 +
 +        if let Some(ref_match) = compute_ref_match(completion, &ty) {
 +            item.ref_match(ref_match, path_ctx.path.syntax().text_range().start());
 +        }
 +    };
 +    item
 +}
 +
 +fn render_resolution_simple_(
 +    ctx: RenderContext<'_>,
 +    local_name: &hir::Name,
 +    import_to_add: Option<LocatedImport>,
 +    resolution: ScopeDef,
 +) -> Builder {
 +    let _p = profile::span("render_resolution");
 +
 +    let db = ctx.db();
 +    let ctx = ctx.import_to_add(import_to_add);
 +    let kind = res_to_kind(resolution);
 +
 +    let mut item =
 +        CompletionItem::new(kind, ctx.source_range(), local_name.unescaped().to_smol_str());
 +    item.set_relevance(ctx.completion_relevance())
 +        .set_documentation(scope_def_docs(db, resolution))
 +        .set_deprecated(scope_def_is_deprecated(&ctx, resolution));
 +
 +    if let Some(import_to_add) = ctx.import_to_add {
 +        item.add_import(import_to_add);
 +    }
 +    item
 +}
 +
 +fn res_to_kind(resolution: ScopeDef) -> CompletionItemKind {
 +    use hir::ModuleDef::*;
 +    match resolution {
 +        ScopeDef::Unknown => CompletionItemKind::UnresolvedReference,
 +        ScopeDef::ModuleDef(Function(_)) => CompletionItemKind::SymbolKind(SymbolKind::Function),
 +        ScopeDef::ModuleDef(Variant(_)) => CompletionItemKind::SymbolKind(SymbolKind::Variant),
 +        ScopeDef::ModuleDef(Macro(_)) => CompletionItemKind::SymbolKind(SymbolKind::Macro),
 +        ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
 +        ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
 +            hir::Adt::Struct(_) => SymbolKind::Struct,
 +            hir::Adt::Union(_) => SymbolKind::Union,
 +            hir::Adt::Enum(_) => SymbolKind::Enum,
 +        }),
 +        ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
 +        ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),
 +        ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),
 +        ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::SymbolKind(SymbolKind::TypeAlias),
 +        ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
 +        ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
 +            hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
 +            hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
 +            hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
 +        }),
 +        ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
 +        ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),
 +        ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => {
 +            CompletionItemKind::SymbolKind(SymbolKind::SelfParam)
 +        }
 +    }
 +}
 +
 +fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option<hir::Documentation> {
 +    use hir::ModuleDef::*;
 +    match resolution {
 +        ScopeDef::ModuleDef(Module(it)) => it.docs(db),
 +        ScopeDef::ModuleDef(Adt(it)) => it.docs(db),
 +        ScopeDef::ModuleDef(Variant(it)) => it.docs(db),
 +        ScopeDef::ModuleDef(Const(it)) => it.docs(db),
 +        ScopeDef::ModuleDef(Static(it)) => it.docs(db),
 +        ScopeDef::ModuleDef(Trait(it)) => it.docs(db),
 +        ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(db),
 +        _ => None,
 +    }
 +}
 +
 +fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: ScopeDef) -> bool {
 +    match resolution {
 +        ScopeDef::ModuleDef(it) => ctx.is_deprecated_assoc_item(it),
 +        ScopeDef::GenericParam(it) => ctx.is_deprecated(it),
 +        ScopeDef::AdtSelfType(it) => ctx.is_deprecated(it),
 +        _ => false,
 +    }
 +}
 +
 +fn compute_type_match(
 +    ctx: &CompletionContext<'_>,
 +    completion_ty: &hir::Type,
 +) -> Option<CompletionRelevanceTypeMatch> {
 +    let expected_type = ctx.expected_type.as_ref()?;
 +
 +    // We don't ever consider unit type to be an exact type match, since
 +    // nearly always this is not meaningful to the user.
 +    if expected_type.is_unit() {
 +        return None;
 +    }
 +
 +    if completion_ty == expected_type {
 +        Some(CompletionRelevanceTypeMatch::Exact)
 +    } else if expected_type.could_unify_with(ctx.db, completion_ty) {
 +        Some(CompletionRelevanceTypeMatch::CouldUnify)
 +    } else {
 +        None
 +    }
 +}
 +
 +fn compute_exact_name_match(ctx: &CompletionContext<'_>, completion_name: &str) -> bool {
 +    ctx.expected_name.as_ref().map_or(false, |name| name.text() == completion_name)
 +}
 +
 +fn compute_ref_match(
 +    ctx: &CompletionContext<'_>,
 +    completion_ty: &hir::Type,
 +) -> Option<hir::Mutability> {
 +    let expected_type = ctx.expected_type.as_ref()?;
 +    if completion_ty != expected_type {
 +        let expected_type_without_ref = expected_type.remove_ref()?;
 +        if completion_ty.autoderef(ctx.db).any(|deref_ty| deref_ty == expected_type_without_ref) {
 +            cov_mark::hit!(suggest_ref);
 +            let mutability = if expected_type.is_mutable_reference() {
 +                hir::Mutability::Mut
 +            } else {
 +                hir::Mutability::Shared
 +            };
 +            return Some(mutability);
 +        };
 +    }
 +    None
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use std::cmp;
 +
 +    use expect_test::{expect, Expect};
 +    use ide_db::SymbolKind;
 +    use itertools::Itertools;
 +
 +    use crate::{
 +        item::CompletionRelevanceTypeMatch,
 +        tests::{check_edit, do_completion, get_all_items, TEST_CONFIG},
 +        CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch,
 +    };
 +
 +    #[track_caller]
 +    fn check(ra_fixture: &str, kind: impl Into<CompletionItemKind>, expect: Expect) {
 +        let actual = do_completion(ra_fixture, kind.into());
 +        expect.assert_debug_eq(&actual);
 +    }
 +
 +    #[track_caller]
 +    fn check_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
 +        let actual: Vec<_> =
 +            kinds.iter().flat_map(|&kind| do_completion(ra_fixture, kind)).collect();
 +        expect.assert_debug_eq(&actual);
 +    }
 +
 +    #[track_caller]
 +    fn check_relevance_for_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
 +        let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None);
 +        actual.retain(|it| kinds.contains(&it.kind()));
 +        actual.sort_by_key(|it| cmp::Reverse(it.relevance().score()));
 +        check_relevance_(actual, expect);
 +    }
 +
 +    #[track_caller]
 +    fn check_relevance(ra_fixture: &str, expect: Expect) {
 +        let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None);
 +        actual.retain(|it| it.kind() != CompletionItemKind::Snippet);
 +        actual.retain(|it| it.kind() != CompletionItemKind::Keyword);
 +        actual.retain(|it| it.kind() != CompletionItemKind::BuiltinType);
 +        actual.sort_by_key(|it| cmp::Reverse(it.relevance().score()));
 +        check_relevance_(actual, expect);
 +    }
 +
 +    #[track_caller]
 +    fn check_relevance_(actual: Vec<CompletionItem>, expect: Expect) {
 +        let actual = actual
 +            .into_iter()
 +            .flat_map(|it| {
 +                let mut items = vec![];
 +
 +                let tag = it.kind().tag();
 +                let relevance = display_relevance(it.relevance());
 +                items.push(format!("{} {} {}\n", tag, it.label(), relevance));
 +
 +                if let Some((mutability, _offset, relevance)) = it.ref_match() {
 +                    let label = format!("&{}{}", mutability.as_keyword_for_ref(), it.label());
 +                    let relevance = display_relevance(relevance);
 +
 +                    items.push(format!("{} {} {}\n", tag, label, relevance));
 +                }
 +
 +                items
 +            })
 +            .collect::<String>();
 +
 +        expect.assert_eq(&actual);
 +
 +        fn display_relevance(relevance: CompletionRelevance) -> String {
 +            let relevance_factors = vec![
 +                (relevance.type_match == Some(CompletionRelevanceTypeMatch::Exact), "type"),
 +                (
 +                    relevance.type_match == Some(CompletionRelevanceTypeMatch::CouldUnify),
 +                    "type_could_unify",
 +                ),
 +                (relevance.exact_name_match, "name"),
 +                (relevance.is_local, "local"),
 +                (
 +                    relevance.postfix_match == Some(CompletionRelevancePostfixMatch::Exact),
 +                    "snippet",
 +                ),
 +                (relevance.is_op_method, "op_method"),
 +                (relevance.requires_import, "requires_import"),
 +            ]
 +            .into_iter()
 +            .filter_map(|(cond, desc)| if cond { Some(desc) } else { None })
 +            .join("+");
 +
 +            format!("[{}]", relevance_factors)
 +        }
 +    }
 +
 +    #[test]
 +    fn enum_detail_includes_record_fields() {
 +        check(
 +            r#"
 +enum Foo { Foo { x: i32, y: i32 } }
 +
 +fn main() { Foo::Fo$0 }
 +"#,
 +            SymbolKind::Variant,
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "Foo {…}",
 +                        source_range: 54..56,
 +                        delete: 54..56,
 +                        insert: "Foo { x: ${1:()}, y: ${2:()} }$0",
 +                        kind: SymbolKind(
 +                            Variant,
 +                        ),
++                        lookup: "Foo{}",
 +                        detail: "Foo { x: i32, y: i32 }",
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_detail_includes_tuple_fields() {
 +        check(
 +            r#"
 +enum Foo { Foo (i32, i32) }
 +
 +fn main() { Foo::Fo$0 }
 +"#,
 +            SymbolKind::Variant,
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "Foo(…)",
 +                        source_range: 46..48,
 +                        delete: 46..48,
 +                        insert: "Foo(${1:()}, ${2:()})$0",
 +                        kind: SymbolKind(
 +                            Variant,
 +                        ),
++                        lookup: "Foo()",
 +                        detail: "Foo(i32, i32)",
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn fn_detail_includes_args_and_return_type() {
 +        check(
 +            r#"
 +fn foo<T>(a: u32, b: u32, t: T) -> (u32, T) { (a, t) }
 +
 +fn main() { fo$0 }
 +"#,
 +            SymbolKind::Function,
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "foo(…)",
 +                        source_range: 68..70,
 +                        delete: 68..70,
 +                        insert: "foo(${1:a}, ${2:b}, ${3:t})$0",
 +                        kind: SymbolKind(
 +                            Function,
 +                        ),
 +                        lookup: "foo",
 +                        detail: "fn(u32, u32, T) -> (u32, T)",
 +                        trigger_call_info: true,
 +                    },
 +                    CompletionItem {
 +                        label: "main()",
 +                        source_range: 68..70,
 +                        delete: 68..70,
 +                        insert: "main()$0",
 +                        kind: SymbolKind(
 +                            Function,
 +                        ),
 +                        lookup: "main",
 +                        detail: "fn()",
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_detail_just_name_for_unit() {
 +        check(
 +            r#"
 +enum Foo { Foo }
 +
 +fn main() { Foo::Fo$0 }
 +"#,
 +            SymbolKind::Variant,
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "Foo",
 +                        source_range: 35..37,
 +                        delete: 35..37,
 +                        insert: "Foo$0",
 +                        kind: SymbolKind(
 +                            Variant,
 +                        ),
 +                        detail: "Foo",
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn lookup_enums_by_two_qualifiers() {
 +        check_kinds(
 +            r#"
 +mod m {
 +    pub enum Spam { Foo, Bar(i32) }
 +}
 +fn main() { let _: m::Spam = S$0 }
 +"#,
 +            &[
 +                CompletionItemKind::SymbolKind(SymbolKind::Function),
 +                CompletionItemKind::SymbolKind(SymbolKind::Module),
 +                CompletionItemKind::SymbolKind(SymbolKind::Variant),
 +            ],
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "main()",
 +                        source_range: 75..76,
 +                        delete: 75..76,
 +                        insert: "main()$0",
 +                        kind: SymbolKind(
 +                            Function,
 +                        ),
 +                        lookup: "main",
 +                        detail: "fn()",
 +                    },
 +                    CompletionItem {
 +                        label: "m",
 +                        source_range: 75..76,
 +                        delete: 75..76,
 +                        insert: "m",
 +                        kind: SymbolKind(
 +                            Module,
 +                        ),
 +                    },
 +                    CompletionItem {
 +                        label: "m::Spam::Bar(…)",
 +                        source_range: 75..76,
 +                        delete: 75..76,
 +                        insert: "m::Spam::Bar(${1:()})$0",
 +                        kind: SymbolKind(
 +                            Variant,
 +                        ),
++                        lookup: "Spam::Bar()",
 +                        detail: "m::Spam::Bar(i32)",
 +                        relevance: CompletionRelevance {
 +                            exact_name_match: false,
 +                            type_match: Some(
 +                                Exact,
 +                            ),
 +                            is_local: false,
 +                            is_item_from_trait: false,
 +                            is_name_already_imported: false,
 +                            requires_import: false,
 +                            is_op_method: false,
 +                            is_private_editable: false,
 +                            postfix_match: None,
 +                            is_definite: false,
 +                        },
 +                    },
 +                    CompletionItem {
 +                        label: "m::Spam::Foo",
 +                        source_range: 75..76,
 +                        delete: 75..76,
 +                        insert: "m::Spam::Foo$0",
 +                        kind: SymbolKind(
 +                            Variant,
 +                        ),
 +                        lookup: "Spam::Foo",
 +                        detail: "m::Spam::Foo",
 +                        relevance: CompletionRelevance {
 +                            exact_name_match: false,
 +                            type_match: Some(
 +                                Exact,
 +                            ),
 +                            is_local: false,
 +                            is_item_from_trait: false,
 +                            is_name_already_imported: false,
 +                            requires_import: false,
 +                            is_op_method: false,
 +                            is_private_editable: false,
 +                            postfix_match: None,
 +                            is_definite: false,
 +                        },
 +                    },
 +                ]
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn sets_deprecated_flag_in_items() {
 +        check(
 +            r#"
 +#[deprecated]
 +fn something_deprecated() {}
 +
 +fn main() { som$0 }
 +"#,
 +            SymbolKind::Function,
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "main()",
 +                        source_range: 56..59,
 +                        delete: 56..59,
 +                        insert: "main()$0",
 +                        kind: SymbolKind(
 +                            Function,
 +                        ),
 +                        lookup: "main",
 +                        detail: "fn()",
 +                    },
 +                    CompletionItem {
 +                        label: "something_deprecated()",
 +                        source_range: 56..59,
 +                        delete: 56..59,
 +                        insert: "something_deprecated()$0",
 +                        kind: SymbolKind(
 +                            Function,
 +                        ),
 +                        lookup: "something_deprecated",
 +                        detail: "fn()",
 +                        deprecated: true,
 +                    },
 +                ]
 +            "#]],
 +        );
 +
 +        check(
 +            r#"
 +struct A { #[deprecated] the_field: u32 }
 +fn foo() { A { the$0 } }
 +"#,
 +            SymbolKind::Field,
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "the_field",
 +                        source_range: 57..60,
 +                        delete: 57..60,
 +                        insert: "the_field",
 +                        kind: SymbolKind(
 +                            Field,
 +                        ),
 +                        detail: "u32",
 +                        deprecated: true,
 +                        relevance: CompletionRelevance {
 +                            exact_name_match: false,
 +                            type_match: Some(
 +                                CouldUnify,
 +                            ),
 +                            is_local: false,
 +                            is_item_from_trait: false,
 +                            is_name_already_imported: false,
 +                            requires_import: false,
 +                            is_op_method: false,
 +                            is_private_editable: false,
 +                            postfix_match: None,
 +                            is_definite: false,
 +                        },
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn renders_docs() {
 +        check_kinds(
 +            r#"
 +struct S {
 +    /// Field docs
 +    foo:
 +}
 +impl S {
 +    /// Method docs
 +    fn bar(self) { self.$0 }
 +}"#,
 +            &[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)],
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "bar()",
 +                        source_range: 94..94,
 +                        delete: 94..94,
 +                        insert: "bar()$0",
 +                        kind: Method,
 +                        lookup: "bar",
 +                        detail: "fn(self)",
 +                        documentation: Documentation(
 +                            "Method docs",
 +                        ),
 +                    },
 +                    CompletionItem {
 +                        label: "foo",
 +                        source_range: 94..94,
 +                        delete: 94..94,
 +                        insert: "foo",
 +                        kind: SymbolKind(
 +                            Field,
 +                        ),
 +                        detail: "{unknown}",
 +                        documentation: Documentation(
 +                            "Field docs",
 +                        ),
 +                    },
 +                ]
 +            "#]],
 +        );
 +
 +        check_kinds(
 +            r#"
 +use self::my$0;
 +
 +/// mod docs
 +mod my { }
 +
 +/// enum docs
 +enum E {
 +    /// variant docs
 +    V
 +}
 +use self::E::*;
 +"#,
 +            &[
 +                CompletionItemKind::SymbolKind(SymbolKind::Module),
 +                CompletionItemKind::SymbolKind(SymbolKind::Variant),
 +                CompletionItemKind::SymbolKind(SymbolKind::Enum),
 +            ],
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "my",
 +                        source_range: 10..12,
 +                        delete: 10..12,
 +                        insert: "my",
 +                        kind: SymbolKind(
 +                            Module,
 +                        ),
 +                        documentation: Documentation(
 +                            "mod docs",
 +                        ),
 +                    },
 +                    CompletionItem {
 +                        label: "V",
 +                        source_range: 10..12,
 +                        delete: 10..12,
 +                        insert: "V$0",
 +                        kind: SymbolKind(
 +                            Variant,
 +                        ),
 +                        detail: "V",
 +                        documentation: Documentation(
 +                            "variant docs",
 +                        ),
 +                    },
 +                    CompletionItem {
 +                        label: "E",
 +                        source_range: 10..12,
 +                        delete: 10..12,
 +                        insert: "E",
 +                        kind: SymbolKind(
 +                            Enum,
 +                        ),
 +                        documentation: Documentation(
 +                            "enum docs",
 +                        ),
 +                    },
 +                ]
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn dont_render_attrs() {
 +        check(
 +            r#"
 +struct S;
 +impl S {
 +    #[inline]
 +    fn the_method(&self) { }
 +}
 +fn foo(s: S) { s.$0 }
 +"#,
 +            CompletionItemKind::Method,
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "the_method()",
 +                        source_range: 81..81,
 +                        delete: 81..81,
 +                        insert: "the_method()$0",
 +                        kind: Method,
 +                        lookup: "the_method",
 +                        detail: "fn(&self)",
 +                    },
 +                ]
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn no_call_parens_if_fn_ptr_needed() {
 +        cov_mark::check!(no_call_parens_if_fn_ptr_needed);
 +        check_edit(
 +            "foo",
 +            r#"
 +fn foo(foo: u8, bar: u8) {}
 +struct ManualVtable { f: fn(u8, u8) }
 +
 +fn main() -> ManualVtable {
 +    ManualVtable { f: f$0 }
 +}
 +"#,
 +            r#"
 +fn foo(foo: u8, bar: u8) {}
 +struct ManualVtable { f: fn(u8, u8) }
 +
 +fn main() -> ManualVtable {
 +    ManualVtable { f: foo }
 +}
 +"#,
 +        );
 +        check_edit(
 +            "type",
 +            r#"
 +struct RawIdentTable { r#type: u32 }
 +
 +fn main() -> RawIdentTable {
 +    RawIdentTable { t$0: 42 }
 +}
 +"#,
 +            r#"
 +struct RawIdentTable { r#type: u32 }
 +
 +fn main() -> RawIdentTable {
 +    RawIdentTable { r#type: 42 }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_parens_in_use_item() {
 +        check_edit(
 +            "foo",
 +            r#"
 +mod m { pub fn foo() {} }
 +use crate::m::f$0;
 +"#,
 +            r#"
 +mod m { pub fn foo() {} }
 +use crate::m::foo;
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_parens_in_call() {
 +        check_edit(
 +            "foo",
 +            r#"
 +fn foo(x: i32) {}
 +fn main() { f$0(); }
 +"#,
 +            r#"
 +fn foo(x: i32) {}
 +fn main() { foo(); }
 +"#,
 +        );
 +        check_edit(
 +            "foo",
 +            r#"
 +struct Foo;
 +impl Foo { fn foo(&self){} }
 +fn f(foo: &Foo) { foo.f$0(); }
 +"#,
 +            r#"
 +struct Foo;
 +impl Foo { fn foo(&self){} }
 +fn f(foo: &Foo) { foo.foo(); }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn inserts_angle_brackets_for_generics() {
 +        cov_mark::check!(inserts_angle_brackets_for_generics);
 +        check_edit(
 +            "Vec",
 +            r#"
 +struct Vec<T> {}
 +fn foo(xs: Ve$0)
 +"#,
 +            r#"
 +struct Vec<T> {}
 +fn foo(xs: Vec<$0>)
 +"#,
 +        );
 +        check_edit(
 +            "Vec",
 +            r#"
 +type Vec<T> = (T,);
 +fn foo(xs: Ve$0)
 +"#,
 +            r#"
 +type Vec<T> = (T,);
 +fn foo(xs: Vec<$0>)
 +"#,
 +        );
 +        check_edit(
 +            "Vec",
 +            r#"
 +struct Vec<T = i128> {}
 +fn foo(xs: Ve$0)
 +"#,
 +            r#"
 +struct Vec<T = i128> {}
 +fn foo(xs: Vec)
 +"#,
 +        );
 +        check_edit(
 +            "Vec",
 +            r#"
 +struct Vec<T> {}
 +fn foo(xs: Ve$0<i128>)
 +"#,
 +            r#"
 +struct Vec<T> {}
 +fn foo(xs: Vec<i128>)
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn active_param_relevance() {
 +        check_relevance(
 +            r#"
 +struct S { foo: i64, bar: u32, baz: u32 }
 +fn test(bar: u32) { }
 +fn foo(s: S) { test(s.$0) }
 +"#,
 +            expect![[r#"
 +                fd bar [type+name]
 +                fd baz [type]
 +                fd foo []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn record_field_relevances() {
 +        check_relevance(
 +            r#"
 +struct A { foo: i64, bar: u32, baz: u32 }
 +struct B { x: (), y: f32, bar: u32 }
 +fn foo(a: A) { B { bar: a.$0 }; }
 +"#,
 +            expect![[r#"
 +                fd bar [type+name]
 +                fd baz [type]
 +                fd foo []
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn record_field_and_call_relevances() {
 +        check_relevance(
 +            r#"
 +struct A { foo: i64, bar: u32, baz: u32 }
 +struct B { x: (), y: f32, bar: u32 }
 +fn f(foo: i64) {  }
 +fn foo(a: A) { B { bar: f(a.$0) }; }
 +"#,
 +            expect![[r#"
 +                fd foo [type+name]
 +                fd bar []
 +                fd baz []
 +            "#]],
 +        );
 +        check_relevance(
 +            r#"
 +struct A { foo: i64, bar: u32, baz: u32 }
 +struct B { x: (), y: f32, bar: u32 }
 +fn f(foo: i64) {  }
 +fn foo(a: A) { f(B { bar: a.$0 }); }
 +"#,
 +            expect![[r#"
 +                fd bar [type+name]
 +                fd baz [type]
 +                fd foo []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn prioritize_exact_ref_match() {
 +        check_relevance(
 +            r#"
 +struct WorldSnapshot { _f: () };
 +fn go(world: &WorldSnapshot) { go(w$0) }
 +"#,
 +            expect![[r#"
 +                lc world [type+name+local]
 +                st WorldSnapshot {…} []
 +                st &WorldSnapshot {…} [type]
 +                st WorldSnapshot []
 +                fn go(…) []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn too_many_arguments() {
 +        cov_mark::check!(too_many_arguments);
 +        check_relevance(
 +            r#"
 +struct Foo;
 +fn f(foo: &Foo) { f(foo, w$0) }
 +"#,
 +            expect![[r#"
 +                lc foo [local]
 +                st Foo []
 +                fn f(…) []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn score_fn_type_and_name_match() {
 +        check_relevance(
 +            r#"
 +struct A { bar: u8 }
 +fn baz() -> u8 { 0 }
 +fn bar() -> u8 { 0 }
 +fn f() { A { bar: b$0 }; }
 +"#,
 +            expect![[r#"
 +                fn bar() [type+name]
 +                fn baz() [type]
 +                st A []
 +                fn f() []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn score_method_type_and_name_match() {
 +        check_relevance(
 +            r#"
 +fn baz(aaa: u32){}
 +struct Foo;
 +impl Foo {
 +fn aaa(&self) -> u32 { 0 }
 +fn bbb(&self) -> u32 { 0 }
 +fn ccc(&self) -> u64 { 0 }
 +}
 +fn f() {
 +    baz(Foo.$0
 +}
 +"#,
 +            expect![[r#"
 +                me aaa() [type+name]
 +                me bbb() [type]
 +                me ccc() []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn score_method_name_match_only() {
 +        check_relevance(
 +            r#"
 +fn baz(aaa: u32){}
 +struct Foo;
 +impl Foo {
 +fn aaa(&self) -> u64 { 0 }
 +}
 +fn f() {
 +    baz(Foo.$0
 +}
 +"#,
 +            expect![[r#"
 +                me aaa() [name]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn suggest_ref_mut() {
 +        cov_mark::check!(suggest_ref);
 +        check_relevance(
 +            r#"
 +struct S;
 +fn foo(s: &mut S) {}
 +fn main() {
 +    let mut s = S;
 +    foo($0);
 +}
 +            "#,
 +            expect![[r#"
 +                lc s [name+local]
 +                lc &mut s [type+name+local]
 +                st S []
 +                st &mut S [type]
 +                st S []
 +                fn foo(…) []
 +                fn main() []
 +            "#]],
 +        );
 +        check_relevance(
 +            r#"
 +struct S;
 +fn foo(s: &mut S) {}
 +fn main() {
 +    let mut s = S;
 +    foo(&mut $0);
 +}
 +            "#,
 +            expect![[r#"
 +                lc s [type+name+local]
 +                st S [type]
 +                st S []
 +                fn foo(…) []
 +                fn main() []
 +            "#]],
 +        );
 +        check_relevance(
 +            r#"
 +struct S;
 +fn foo(s: &mut S) {}
 +fn main() {
 +    let mut ssss = S;
 +    foo(&mut s$0);
 +}
 +            "#,
 +            expect![[r#"
 +                lc ssss [type+local]
 +                st S [type]
 +                st S []
 +                fn foo(…) []
 +                fn main() []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn suggest_deref() {
 +        check_relevance(
 +            r#"
 +//- minicore: deref
 +struct S;
 +struct T(S);
 +
 +impl core::ops::Deref for T {
 +    type Target = S;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.0
 +    }
 +}
 +
 +fn foo(s: &S) {}
 +
 +fn main() {
 +    let t = T(S);
 +    let m = 123;
 +
 +    foo($0);
 +}
 +            "#,
 +            expect![[r#"
 +                lc m [local]
 +                lc t [local]
 +                lc &t [type+local]
 +                st S []
 +                st &S [type]
 +                st S []
 +                st T []
 +                fn foo(…) []
 +                fn main() []
 +                md core []
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn suggest_deref_mut() {
 +        check_relevance(
 +            r#"
 +//- minicore: deref_mut
 +struct S;
 +struct T(S);
 +
 +impl core::ops::Deref for T {
 +    type Target = S;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.0
 +    }
 +}
 +
 +impl core::ops::DerefMut for T {
 +    fn deref_mut(&mut self) -> &mut Self::Target {
 +        &mut self.0
 +    }
 +}
 +
 +fn foo(s: &mut S) {}
 +
 +fn main() {
 +    let t = T(S);
 +    let m = 123;
 +
 +    foo($0);
 +}
 +            "#,
 +            expect![[r#"
 +                lc m [local]
 +                lc t [local]
 +                lc &mut t [type+local]
 +                st S []
 +                st &mut S [type]
 +                st S []
 +                st T []
 +                fn foo(…) []
 +                fn main() []
 +                md core []
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn locals() {
 +        check_relevance(
 +            r#"
 +fn foo(bar: u32) {
 +    let baz = 0;
 +
 +    f$0
 +}
 +"#,
 +            expect![[r#"
 +                lc baz [local]
 +                lc bar [local]
 +                fn foo(…) []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_owned() {
 +        check_relevance(
 +            r#"
 +enum Foo { A, B }
 +fn foo() {
 +    bar($0);
 +}
 +fn bar(t: Foo) {}
 +"#,
 +            expect![[r#"
 +                ev Foo::A [type]
 +                ev Foo::B [type]
 +                en Foo []
 +                fn bar(…) []
 +                fn foo() []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_ref() {
 +        check_relevance(
 +            r#"
 +enum Foo { A, B }
 +fn foo() {
 +    bar($0);
 +}
 +fn bar(t: &Foo) {}
 +"#,
 +            expect![[r#"
 +                ev Foo::A []
 +                ev &Foo::A [type]
 +                ev Foo::B []
 +                ev &Foo::B [type]
 +                en Foo []
 +                fn bar(…) []
 +                fn foo() []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn suggest_deref_fn_ret() {
 +        check_relevance(
 +            r#"
 +//- minicore: deref
 +struct S;
 +struct T(S);
 +
 +impl core::ops::Deref for T {
 +    type Target = S;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.0
 +    }
 +}
 +
 +fn foo(s: &S) {}
 +fn bar() -> T {}
 +
 +fn main() {
 +    foo($0);
 +}
 +"#,
 +            expect![[r#"
 +                st S []
 +                st &S [type]
 +                st S []
 +                st T []
 +                fn bar() []
 +                fn &bar() [type]
 +                fn foo(…) []
 +                fn main() []
 +                md core []
 +            "#]],
 +        )
 +    }
 +
 +    #[test]
 +    fn op_function_relevances() {
 +        check_relevance(
 +            r#"
 +#[lang = "sub"]
 +trait Sub {
 +    fn sub(self, other: Self) -> Self { self }
 +}
 +impl Sub for u32 {}
 +fn foo(a: u32) { a.$0 }
 +"#,
 +            expect![[r#"
 +                me sub(…) (as Sub) [op_method]
 +            "#]],
 +        );
 +        check_relevance(
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn new() -> Self {}
 +}
 +#[lang = "eq"]
 +pub trait PartialEq<Rhs: ?Sized = Self> {
 +    fn eq(&self, other: &Rhs) -> bool;
 +    fn ne(&self, other: &Rhs) -> bool;
 +}
 +
 +impl PartialEq for Foo {}
 +fn main() {
 +    Foo::$0
 +}
 +"#,
 +            expect![[r#"
 +                fn new() []
 +                me eq(…) (as PartialEq) [op_method]
 +                me ne(…) (as PartialEq) [op_method]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_field_method_ref() {
 +        check_kinds(
 +            r#"
 +struct Foo { bar: u32 }
 +impl Foo { fn baz(&self) -> u32 { 0 } }
 +
 +fn foo(f: Foo) { let _: &u32 = f.b$0 }
 +"#,
 +            &[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)],
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "baz()",
 +                        source_range: 98..99,
 +                        delete: 98..99,
 +                        insert: "baz()$0",
 +                        kind: Method,
 +                        lookup: "baz",
 +                        detail: "fn(&self) -> u32",
 +                        ref_match: "&@96",
 +                    },
 +                    CompletionItem {
 +                        label: "bar",
 +                        source_range: 98..99,
 +                        delete: 98..99,
 +                        insert: "bar",
 +                        kind: SymbolKind(
 +                            Field,
 +                        ),
 +                        detail: "u32",
 +                        ref_match: "&@96",
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn qualified_path_ref() {
 +        check_kinds(
 +            r#"
 +struct S;
 +
 +struct T;
 +impl T {
 +    fn foo() -> S {}
 +}
 +
 +fn bar(s: &S) {}
 +
 +fn main() {
 +    bar(T::$0);
 +}
 +"#,
 +            &[CompletionItemKind::SymbolKind(SymbolKind::Function)],
 +            expect![[r#"
 +                [
 +                    CompletionItem {
 +                        label: "foo()",
 +                        source_range: 95..95,
 +                        delete: 95..95,
 +                        insert: "foo()$0",
 +                        kind: SymbolKind(
 +                            Function,
 +                        ),
 +                        lookup: "foo",
 +                        detail: "fn() -> S",
 +                        ref_match: "&@92",
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn generic_enum() {
 +        check_relevance(
 +            r#"
 +enum Foo<T> { A(T), B }
 +// bar() should not be an exact type match
 +// because the generic parameters are different
 +fn bar() -> Foo<u8> { Foo::B }
 +// FIXME baz() should be an exact type match
 +// because the types could unify, but it currently
 +// is not. This is due to the T here being
 +// TyKind::Placeholder rather than TyKind::Missing.
 +fn baz<T>() -> Foo<T> { Foo::B }
 +fn foo() {
 +    let foo: Foo<u32> = Foo::B;
 +    let _: Foo<u32> = f$0;
 +}
 +"#,
 +            expect![[r#"
 +                lc foo [type+local]
 +                ev Foo::A(…) [type_could_unify]
 +                ev Foo::B [type_could_unify]
 +                fn foo() []
 +                en Foo []
 +                fn bar() []
 +                fn baz() []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn postfix_exact_match_is_high_priority() {
 +        cov_mark::check!(postfix_exact_match_is_high_priority);
 +        check_relevance_for_kinds(
 +            r#"
 +mod ops {
 +    pub trait Not {
 +        type Output;
 +        fn not(self) -> Self::Output;
 +    }
 +
 +    impl Not for bool {
 +        type Output = bool;
 +        fn not(self) -> bool { if self { false } else { true }}
 +    }
 +}
 +
 +fn main() {
 +    let _: bool = (9 > 2).not$0;
 +}
 +    "#,
 +            &[CompletionItemKind::Snippet, CompletionItemKind::Method],
 +            expect![[r#"
 +                sn not [snippet]
 +                me not() (use ops::Not) [type_could_unify+requires_import]
 +                sn if []
 +                sn while []
 +                sn ref []
 +                sn refm []
 +                sn match []
 +                sn box []
 +                sn dbg []
 +                sn dbgr []
 +                sn call []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn postfix_inexact_match_is_low_priority() {
 +        cov_mark::check!(postfix_inexact_match_is_low_priority);
 +        check_relevance_for_kinds(
 +            r#"
 +struct S;
 +impl S {
 +    fn f(&self) {}
 +}
 +fn main() {
 +    S.$0
 +}
 +    "#,
 +            &[CompletionItemKind::Snippet, CompletionItemKind::Method],
 +            expect![[r#"
 +                me f() []
 +                sn ref []
 +                sn refm []
 +                sn match []
 +                sn box []
 +                sn dbg []
 +                sn dbgr []
 +                sn call []
 +                sn let []
 +                sn letm []
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn flyimport_reduced_relevance() {
 +        check_relevance(
 +            r#"
 +mod std {
 +    pub mod io {
 +        pub trait BufRead {}
 +        pub struct BufReader;
 +        pub struct BufWriter;
 +    }
 +}
 +struct Buffer;
 +
 +fn f() {
 +    Buf$0
 +}
 +"#,
 +            expect![[r#"
 +                st Buffer []
 +                fn f() []
 +                md std []
 +                tt BufRead (use std::io::BufRead) [requires_import]
 +                st BufReader (use std::io::BufReader) [requires_import]
 +                st BufWriter (use std::io::BufWriter) [requires_import]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn completes_struct_with_raw_identifier() {
 +        check_edit(
 +            "type",
 +            r#"
 +mod m { pub struct r#type {} }
 +fn main() {
 +    let r#type = m::t$0;
 +}
 +"#,
 +            r#"
 +mod m { pub struct r#type {} }
 +fn main() {
 +    let r#type = m::r#type;
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn completes_fn_with_raw_identifier() {
 +        check_edit(
 +            "type",
 +            r#"
 +mod m { pub fn r#type {} }
 +fn main() {
 +    m::t$0
 +}
 +"#,
 +            r#"
 +mod m { pub fn r#type {} }
 +fn main() {
 +    m::r#type()$0
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn completes_macro_with_raw_identifier() {
 +        check_edit(
 +            "let!",
 +            r#"
 +macro_rules! r#let { () => {} }
 +fn main() {
 +    $0
 +}
 +"#,
 +            r#"
 +macro_rules! r#let { () => {} }
 +fn main() {
 +    r#let!($0)
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn completes_variant_with_raw_identifier() {
 +        check_edit(
 +            "type",
 +            r#"
 +enum A { r#type }
 +fn main() {
 +    let a = A::t$0
 +}
 +"#,
 +            r#"
 +enum A { r#type }
 +fn main() {
 +    let a = A::r#type$0
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn completes_field_with_raw_identifier() {
 +        check_edit(
 +            "fn",
 +            r#"
 +mod r#type {
 +    pub struct r#struct {
 +        pub r#fn: u32
 +    }
 +}
 +
 +fn main() {
 +    let a = r#type::r#struct {};
 +    a.$0
 +}
 +"#,
 +            r#"
 +mod r#type {
 +    pub struct r#struct {
 +        pub r#fn: u32
 +    }
 +}
 +
 +fn main() {
 +    let a = r#type::r#struct {};
 +    a.r#fn
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn completes_const_with_raw_identifier() {
 +        check_edit(
 +            "type",
 +            r#"
 +struct r#struct {}
 +impl r#struct { pub const r#type: u8 = 1; }
 +fn main() {
 +    r#struct::t$0
 +}
 +"#,
 +            r#"
 +struct r#struct {}
 +impl r#struct { pub const r#type: u8 = 1; }
 +fn main() {
 +    r#struct::r#type
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn completes_type_alias_with_raw_identifier() {
 +        check_edit(
 +            "type type",
 +            r#"
 +struct r#struct {}
 +trait r#trait { type r#type; }
 +impl r#trait for r#struct { type t$0 }
 +"#,
 +            r#"
 +struct r#struct {}
 +trait r#trait { type r#type; }
 +impl r#trait for r#struct { type r#type = $0; }
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn field_access_includes_self() {
 +        check_edit(
 +            "length",
 +            r#"
 +struct S {
 +    length: i32
 +}
 +
 +impl S {
 +    fn some_fn(&self) {
 +        let l = len$0
 +    }
 +}
 +"#,
 +            r#"
 +struct S {
 +    length: i32
 +}
 +
 +impl S {
 +    fn some_fn(&self) {
 +        let l = self.length
 +    }
 +}
 +"#,
 +        )
 +    }
 +}
index 707dea206be577efcc7cbb455692dbe4614418bb,0000000000000000000000000000000000000000..af9c88a7e0a6cc87cbcb1f11ea22e9f4c207238b
mode 100644,000000..100644
--- /dev/null
@@@ -1,191 -1,0 +1,195 @@@
-             format_literal_label, render_record_lit, render_tuple_lit, visible_fields,
-             RenderedLiteral,
 +//! Renderer for `enum` variants.
 +
 +use hir::{db::HirDatabase, Documentation, HasAttrs, StructKind};
 +use ide_db::SymbolKind;
 +use syntax::AstNode;
 +
 +use crate::{
 +    context::{CompletionContext, PathCompletionCtx, PathKind},
 +    item::{Builder, CompletionItem},
 +    render::{
 +        compute_ref_match, compute_type_match,
 +        variant::{
-         format_literal_label(&qualified_name, kind),
++            format_literal_label, format_literal_lookup, render_record_lit, render_tuple_lit,
++            visible_fields, RenderedLiteral,
 +        },
 +        RenderContext,
 +    },
 +    CompletionItemKind, CompletionRelevance,
 +};
 +
 +pub(crate) fn render_variant_lit(
 +    ctx: RenderContext<'_>,
 +    path_ctx: &PathCompletionCtx,
 +    local_name: Option<hir::Name>,
 +    variant: hir::Variant,
 +    path: Option<hir::ModPath>,
 +) -> Option<Builder> {
 +    let _p = profile::span("render_enum_variant");
 +    let db = ctx.db();
 +
 +    let name = local_name.unwrap_or_else(|| variant.name(db));
 +    render(ctx, path_ctx, Variant::EnumVariant(variant), name, path)
 +}
 +
 +pub(crate) fn render_struct_literal(
 +    ctx: RenderContext<'_>,
 +    path_ctx: &PathCompletionCtx,
 +    strukt: hir::Struct,
 +    path: Option<hir::ModPath>,
 +    local_name: Option<hir::Name>,
 +) -> Option<Builder> {
 +    let _p = profile::span("render_struct_literal");
 +    let db = ctx.db();
 +
 +    let name = local_name.unwrap_or_else(|| strukt.name(db));
 +    render(ctx, path_ctx, Variant::Struct(strukt), name, path)
 +}
 +
 +fn render(
 +    ctx @ RenderContext { completion, .. }: RenderContext<'_>,
 +    path_ctx: &PathCompletionCtx,
 +    thing: Variant,
 +    name: hir::Name,
 +    path: Option<hir::ModPath>,
 +) -> Option<Builder> {
 +    let db = completion.db;
 +    let mut kind = thing.kind(db);
 +    let should_add_parens = match &path_ctx {
 +        PathCompletionCtx { has_call_parens: true, .. } => false,
 +        PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. } => false,
 +        _ => true,
 +    };
 +
 +    let fields = thing.fields(completion)?;
 +    let (qualified_name, short_qualified_name, qualified) = match path {
 +        Some(path) => {
 +            let short = hir::ModPath::from_segments(
 +                hir::PathKind::Plain,
 +                path.segments().iter().skip(path.segments().len().saturating_sub(2)).cloned(),
 +            );
 +            (path, short, true)
 +        }
 +        None => (name.clone().into(), name.into(), false),
 +    };
 +    let (qualified_name, escaped_qualified_name) =
 +        (qualified_name.unescaped().to_string(), qualified_name.to_string());
 +    let snippet_cap = ctx.snippet_cap();
 +
 +    let mut rendered = match kind {
 +        StructKind::Tuple if should_add_parens => {
 +            render_tuple_lit(db, snippet_cap, &fields, &escaped_qualified_name)
 +        }
 +        StructKind::Record if should_add_parens => {
 +            render_record_lit(db, snippet_cap, &fields, &escaped_qualified_name)
 +        }
 +        _ => RenderedLiteral {
 +            literal: escaped_qualified_name.clone(),
 +            detail: escaped_qualified_name.clone(),
 +        },
 +    };
 +
 +    if snippet_cap.is_some() {
 +        rendered.literal.push_str("$0");
 +    }
 +
 +    // only show name in label if not adding parens
 +    if !should_add_parens {
 +        kind = StructKind::Unit;
 +    }
++    let label = format_literal_label(&qualified_name, kind);
++    let lookup = if qualified {
++        format_literal_lookup(&short_qualified_name.to_string(), kind)
++    } else {
++        format_literal_lookup(&qualified_name, kind)
++    };
 +
 +    let mut item = CompletionItem::new(
 +        CompletionItemKind::SymbolKind(thing.symbol_kind()),
 +        ctx.source_range(),
-     if qualified {
-         item.lookup_by(format_literal_label(&short_qualified_name.to_string(), kind));
-     }
++        label,
 +    );
 +
++    item.lookup_by(lookup);
 +    item.detail(rendered.detail);
 +
 +    match snippet_cap {
 +        Some(snippet_cap) => item.insert_snippet(snippet_cap, rendered.literal),
 +        None => item.insert_text(rendered.literal),
 +    };
 +
 +    item.set_documentation(thing.docs(db)).set_deprecated(thing.is_deprecated(&ctx));
 +
 +    let ty = thing.ty(db);
 +    item.set_relevance(CompletionRelevance {
 +        type_match: compute_type_match(ctx.completion, &ty),
 +        ..ctx.completion_relevance()
 +    });
 +    if let Some(ref_match) = compute_ref_match(completion, &ty) {
 +        item.ref_match(ref_match, path_ctx.path.syntax().text_range().start());
 +    }
 +
 +    if let Some(import_to_add) = ctx.import_to_add {
 +        item.add_import(import_to_add);
 +    }
 +    Some(item)
 +}
 +
 +#[derive(Clone, Copy)]
 +enum Variant {
 +    Struct(hir::Struct),
 +    EnumVariant(hir::Variant),
 +}
 +
 +impl Variant {
 +    fn fields(self, ctx: &CompletionContext<'_>) -> Option<Vec<hir::Field>> {
 +        let fields = match self {
 +            Variant::Struct(it) => it.fields(ctx.db),
 +            Variant::EnumVariant(it) => it.fields(ctx.db),
 +        };
 +        let (visible_fields, fields_omitted) = match self {
 +            Variant::Struct(it) => visible_fields(ctx, &fields, it)?,
 +            Variant::EnumVariant(it) => visible_fields(ctx, &fields, it)?,
 +        };
 +        if !fields_omitted {
 +            Some(visible_fields)
 +        } else {
 +            None
 +        }
 +    }
 +
 +    fn kind(self, db: &dyn HirDatabase) -> StructKind {
 +        match self {
 +            Variant::Struct(it) => it.kind(db),
 +            Variant::EnumVariant(it) => it.kind(db),
 +        }
 +    }
 +
 +    fn symbol_kind(self) -> SymbolKind {
 +        match self {
 +            Variant::Struct(_) => SymbolKind::Struct,
 +            Variant::EnumVariant(_) => SymbolKind::Variant,
 +        }
 +    }
 +
 +    fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
 +        match self {
 +            Variant::Struct(it) => it.docs(db),
 +            Variant::EnumVariant(it) => it.docs(db),
 +        }
 +    }
 +
 +    fn is_deprecated(self, ctx: &RenderContext<'_>) -> bool {
 +        match self {
 +            Variant::Struct(it) => ctx.is_deprecated(it),
 +            Variant::EnumVariant(it) => ctx.is_deprecated(it),
 +        }
 +    }
 +
 +    fn ty(self, db: &dyn HirDatabase) -> hir::Type {
 +        match self {
 +            Variant::Struct(it) => it.ty(db),
 +            Variant::EnumVariant(it) => it.parent_enum(db).ty(db),
 +        }
 +    }
 +}
index 1c1299e33b6701951dd1646ea5de10998f88970b,0000000000000000000000000000000000000000..c845ff21aaba401045cbef14c30c12ea74a3857f
mode 100644,000000..100644
--- /dev/null
@@@ -1,193 -1,0 +1,199 @@@
-         variant::{format_literal_label, visible_fields},
 +//! Renderer for patterns.
 +
 +use hir::{db::HirDatabase, HasAttrs, Name, StructKind};
 +use ide_db::SnippetCap;
 +use itertools::Itertools;
 +use syntax::SmolStr;
 +
 +use crate::{
 +    context::{ParamContext, ParamKind, PathCompletionCtx, PatternContext},
 +    render::{
-     Some(build_completion(ctx, label, pat, strukt))
++        variant::{format_literal_label, format_literal_lookup, visible_fields},
 +        RenderContext,
 +    },
 +    CompletionItem, CompletionItemKind,
 +};
 +
 +pub(crate) fn render_struct_pat(
 +    ctx: RenderContext<'_>,
 +    pattern_ctx: &PatternContext,
 +    strukt: hir::Struct,
 +    local_name: Option<Name>,
 +) -> Option<CompletionItem> {
 +    let _p = profile::span("render_struct_pat");
 +
 +    let fields = strukt.fields(ctx.db());
 +    let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, strukt)?;
 +
 +    if visible_fields.is_empty() {
 +        // Matching a struct without matching its fields is pointless, unlike matching a Variant without its fields
 +        return None;
 +    }
 +
 +    let name = local_name.unwrap_or_else(|| strukt.name(ctx.db()));
 +    let (name, escaped_name) = (name.unescaped().to_smol_str(), name.to_smol_str());
 +    let kind = strukt.kind(ctx.db());
 +    let label = format_literal_label(name.as_str(), kind);
++    let lookup = format_literal_lookup(name.as_str(), kind);
 +    let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?;
 +
-     let (label, pat) = match path_ctx {
-         Some(PathCompletionCtx { has_call_parens: true, .. }) => (name, escaped_name.to_string()),
++    Some(build_completion(ctx, label, lookup, pat, strukt))
 +}
 +
 +pub(crate) fn render_variant_pat(
 +    ctx: RenderContext<'_>,
 +    pattern_ctx: &PatternContext,
 +    path_ctx: Option<&PathCompletionCtx>,
 +    variant: hir::Variant,
 +    local_name: Option<Name>,
 +    path: Option<&hir::ModPath>,
 +) -> Option<CompletionItem> {
 +    let _p = profile::span("render_variant_pat");
 +
 +    let fields = variant.fields(ctx.db());
 +    let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, variant)?;
 +
 +    let (name, escaped_name) = match path {
 +        Some(path) => (path.unescaped().to_string().into(), path.to_string().into()),
 +        None => {
 +            let name = local_name.unwrap_or_else(|| variant.name(ctx.db()));
 +            (name.unescaped().to_smol_str(), name.to_smol_str())
 +        }
 +    };
 +
-             (label, pat)
++    let (label, lookup, pat) = match path_ctx {
++        Some(PathCompletionCtx { has_call_parens: true, .. }) => {
++            (name.clone(), name, escaped_name.to_string())
++        }
 +        _ => {
 +            let kind = variant.kind(ctx.db());
 +            let label = format_literal_label(name.as_str(), kind);
++            let lookup = format_literal_lookup(name.as_str(), kind);
 +            let pat = render_pat(
 +                &ctx,
 +                pattern_ctx,
 +                &escaped_name,
 +                kind,
 +                &visible_fields,
 +                fields_omitted,
 +            )?;
-     Some(build_completion(ctx, label, pat, variant))
++            (label, lookup, pat)
 +        }
 +    };
 +
++    Some(build_completion(ctx, label, lookup, pat, variant))
 +}
 +
 +fn build_completion(
 +    ctx: RenderContext<'_>,
 +    label: SmolStr,
++    lookup: SmolStr,
 +    pat: String,
 +    def: impl HasAttrs + Copy,
 +) -> CompletionItem {
 +    let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), label);
 +    item.set_documentation(ctx.docs(def))
 +        .set_deprecated(ctx.is_deprecated(def))
 +        .detail(&pat)
++        .lookup_by(lookup)
 +        .set_relevance(ctx.completion_relevance());
 +    match ctx.snippet_cap() {
 +        Some(snippet_cap) => item.insert_snippet(snippet_cap, pat),
 +        None => item.insert_text(pat),
 +    };
 +    item.build()
 +}
 +
 +fn render_pat(
 +    ctx: &RenderContext<'_>,
 +    pattern_ctx: &PatternContext,
 +    name: &str,
 +    kind: StructKind,
 +    fields: &[hir::Field],
 +    fields_omitted: bool,
 +) -> Option<String> {
 +    let mut pat = match kind {
 +        StructKind::Tuple => render_tuple_as_pat(ctx.snippet_cap(), fields, name, fields_omitted),
 +        StructKind::Record => {
 +            render_record_as_pat(ctx.db(), ctx.snippet_cap(), fields, name, fields_omitted)
 +        }
 +        StructKind::Unit => name.to_string(),
 +    };
 +
 +    let needs_ascription = matches!(
 +        pattern_ctx,
 +        PatternContext {
 +            param_ctx: Some(ParamContext { kind: ParamKind::Function(_), .. }),
 +            has_type_ascription: false,
 +            ..
 +        }
 +    );
 +    if needs_ascription {
 +        pat.push(':');
 +        pat.push(' ');
 +        pat.push_str(name);
 +    }
 +    if ctx.snippet_cap().is_some() {
 +        pat.push_str("$0");
 +    }
 +    Some(pat)
 +}
 +
 +fn render_record_as_pat(
 +    db: &dyn HirDatabase,
 +    snippet_cap: Option<SnippetCap>,
 +    fields: &[hir::Field],
 +    name: &str,
 +    fields_omitted: bool,
 +) -> String {
 +    let fields = fields.iter();
 +    match snippet_cap {
 +        Some(_) => {
 +            format!(
 +                "{name} {{ {}{} }}",
 +                fields.enumerate().format_with(", ", |(idx, field), f| {
 +                    f(&format_args!("{}${}", field.name(db), idx + 1))
 +                }),
 +                if fields_omitted { ", .." } else { "" },
 +                name = name
 +            )
 +        }
 +        None => {
 +            format!(
 +                "{name} {{ {}{} }}",
 +                fields.map(|field| field.name(db).to_smol_str()).format(", "),
 +                if fields_omitted { ", .." } else { "" },
 +                name = name
 +            )
 +        }
 +    }
 +}
 +
 +fn render_tuple_as_pat(
 +    snippet_cap: Option<SnippetCap>,
 +    fields: &[hir::Field],
 +    name: &str,
 +    fields_omitted: bool,
 +) -> String {
 +    let fields = fields.iter();
 +    match snippet_cap {
 +        Some(_) => {
 +            format!(
 +                "{name}({}{})",
 +                fields
 +                    .enumerate()
 +                    .format_with(", ", |(idx, _), f| { f(&format_args!("${}", idx + 1)) }),
 +                if fields_omitted { ", .." } else { "" },
 +                name = name
 +            )
 +        }
 +        None => {
 +            format!(
 +                "{name}({}{})",
 +                fields.enumerate().map(|(idx, _)| idx).format(", "),
 +                if fields_omitted { ", .." } else { "" },
 +                name = name
 +            )
 +        }
 +    }
 +}
index bb32330f276de7853c3290be23277007c1f9c2cd,0000000000000000000000000000000000000000..54e97dd57ba82280074c27635f675d57fef6fa7c
mode 100644,000000..100644
--- /dev/null
@@@ -1,77 -1,0 +1,80 @@@
-         variant::{format_literal_label, visible_fields},
 +//! Renderer for `union` literals.
 +
 +use hir::{HirDisplay, Name, StructKind};
 +use ide_db::SymbolKind;
 +use itertools::Itertools;
 +
 +use crate::{
 +    render::{
++        variant::{format_literal_label, format_literal_lookup, visible_fields},
 +        RenderContext,
 +    },
 +    CompletionItem, CompletionItemKind,
 +};
 +
 +pub(crate) fn render_union_literal(
 +    ctx: RenderContext<'_>,
 +    un: hir::Union,
 +    path: Option<hir::ModPath>,
 +    local_name: Option<Name>,
 +) -> Option<CompletionItem> {
 +    let name = local_name.unwrap_or_else(|| un.name(ctx.db()));
 +
 +    let (qualified_name, escaped_qualified_name) = match path {
 +        Some(p) => (p.unescaped().to_string(), p.to_string()),
 +        None => (name.unescaped().to_string(), name.to_string()),
 +    };
-         format_literal_label(&name.to_smol_str(), StructKind::Record),
++    let label = format_literal_label(&name.to_smol_str(), StructKind::Record);
++    let lookup = format_literal_lookup(&name.to_smol_str(), StructKind::Record);
 +    let mut item = CompletionItem::new(
 +        CompletionItemKind::SymbolKind(SymbolKind::Union),
 +        ctx.source_range(),
++        label,
 +    );
 +
++    item.lookup_by(lookup);
++
 +    let fields = un.fields(ctx.db());
 +    let (fields, fields_omitted) = visible_fields(ctx.completion, &fields, un)?;
 +
 +    if fields.is_empty() {
 +        return None;
 +    }
 +
 +    let literal = if ctx.snippet_cap().is_some() {
 +        format!(
 +            "{} {{ ${{1|{}|}}: ${{2:()}} }}$0",
 +            escaped_qualified_name,
 +            fields.iter().map(|field| field.name(ctx.db()).to_smol_str()).format(",")
 +        )
 +    } else {
 +        format!(
 +            "{} {{ {} }}",
 +            escaped_qualified_name,
 +            fields
 +                .iter()
 +                .format_with(", ", |field, f| { f(&format_args!("{}: ()", field.name(ctx.db()))) })
 +        )
 +    };
 +
 +    let detail = format!(
 +        "{} {{ {}{} }}",
 +        qualified_name,
 +        fields.iter().format_with(", ", |field, f| {
 +            f(&format_args!("{}: {}", field.name(ctx.db()), field.ty(ctx.db()).display(ctx.db())))
 +        }),
 +        if fields_omitted { ", .." } else { "" }
 +    );
 +
 +    item.set_documentation(ctx.docs(un))
 +        .set_deprecated(ctx.is_deprecated(un))
 +        .detail(&detail)
 +        .set_relevance(ctx.completion_relevance());
 +
 +    match ctx.snippet_cap() {
 +        Some(snippet_cap) => item.insert_snippet(snippet_cap, literal),
 +        None => item.insert_text(literal),
 +    };
 +
 +    Some(item.build())
 +}
index 664845330eb8f4ab16fe74c2ba8aa1c6065525db,0000000000000000000000000000000000000000..24e6abdc9ad60918472e7508cad3b8c4f3cc5eef
mode 100644,000000..100644
--- /dev/null
@@@ -1,96 -1,0 +1,105 @@@
 +//! Code common to structs, unions, and enum variants.
 +
 +use crate::context::CompletionContext;
 +use hir::{db::HirDatabase, HasAttrs, HasCrate, HasVisibility, HirDisplay, StructKind};
 +use ide_db::SnippetCap;
 +use itertools::Itertools;
 +use syntax::SmolStr;
 +
 +/// A rendered struct, union, or enum variant, split into fields for actual
 +/// auto-completion (`literal`, using `field: ()`) and display in the
 +/// completions menu (`detail`, using `field: type`).
 +pub(crate) struct RenderedLiteral {
 +    pub(crate) literal: String,
 +    pub(crate) detail: String,
 +}
 +
 +/// Render a record type (or sub-type) to a `RenderedCompound`. Use `None` for
 +/// the `name` argument for an anonymous type.
 +pub(crate) fn render_record_lit(
 +    db: &dyn HirDatabase,
 +    snippet_cap: Option<SnippetCap>,
 +    fields: &[hir::Field],
 +    path: &str,
 +) -> RenderedLiteral {
 +    let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| {
 +        if snippet_cap.is_some() {
 +            f(&format_args!("{}: ${{{}:()}}", field.name(db), idx + 1))
 +        } else {
 +            f(&format_args!("{}: ()", field.name(db)))
 +        }
 +    });
 +
 +    let types = fields.iter().format_with(", ", |field, f| {
 +        f(&format_args!("{}: {}", field.name(db), field.ty(db).display(db)))
 +    });
 +
 +    RenderedLiteral {
 +        literal: format!("{} {{ {} }}", path, completions),
 +        detail: format!("{} {{ {} }}", path, types),
 +    }
 +}
 +
 +/// Render a tuple type (or sub-type) to a `RenderedCompound`. Use `None` for
 +/// the `name` argument for an anonymous type.
 +pub(crate) fn render_tuple_lit(
 +    db: &dyn HirDatabase,
 +    snippet_cap: Option<SnippetCap>,
 +    fields: &[hir::Field],
 +    path: &str,
 +) -> RenderedLiteral {
 +    let completions = fields.iter().enumerate().format_with(", ", |(idx, _), f| {
 +        if snippet_cap.is_some() {
 +            f(&format_args!("${{{}:()}}", idx + 1))
 +        } else {
 +            f(&format_args!("()"))
 +        }
 +    });
 +
 +    let types = fields.iter().format_with(", ", |field, f| f(&field.ty(db).display(db)));
 +
 +    RenderedLiteral {
 +        literal: format!("{}({})", path, completions),
 +        detail: format!("{}({})", path, types),
 +    }
 +}
 +
 +/// Find all the visible fields in a given list. Returns the list of visible
 +/// fields, plus a boolean for whether the list is comprehensive (contains no
 +/// private fields and its item is not marked `#[non_exhaustive]`).
 +pub(crate) fn visible_fields(
 +    ctx: &CompletionContext<'_>,
 +    fields: &[hir::Field],
 +    item: impl HasAttrs + HasCrate + Copy,
 +) -> Option<(Vec<hir::Field>, bool)> {
 +    let module = ctx.module;
 +    let n_fields = fields.len();
 +    let fields = fields
 +        .iter()
 +        .filter(|field| field.is_visible_from(ctx.db, module))
 +        .copied()
 +        .collect::<Vec<_>>();
 +    let has_invisible_field = n_fields - fields.len() > 0;
 +    let is_foreign_non_exhaustive = item.attrs(ctx.db).by_key("non_exhaustive").exists()
 +        && item.krate(ctx.db) != module.krate();
 +    let fields_omitted = has_invisible_field || is_foreign_non_exhaustive;
 +    Some((fields, fields_omitted))
 +}
 +
 +/// Format a struct, etc. literal option for display in the completions menu.
 +pub(crate) fn format_literal_label(name: &str, kind: StructKind) -> SmolStr {
 +    match kind {
 +        StructKind::Tuple => SmolStr::from_iter([name, "(…)"]),
 +        StructKind::Record => SmolStr::from_iter([name, " {…}"]),
 +        StructKind::Unit => name.into(),
 +    }
 +}
++
++/// Format a struct, etc. literal option for lookup used in completions filtering.
++pub(crate) fn format_literal_lookup(name: &str, kind: StructKind) -> SmolStr {
++    match kind {
++        StructKind::Tuple => SmolStr::from_iter([name, "()"]),
++        StructKind::Record => SmolStr::from_iter([name, "{}"]),
++        StructKind::Unit => name.into(),
++    }
++}
index 0bba7f2459cafae4a0e246586c0af6c278e09e9b,0000000000000000000000000000000000000000..a63ef006875bc9962ac460e3885e5acf42478d74
mode 100644,000000..100644
--- /dev/null
@@@ -1,1232 -1,0 +1,1232 @@@
-     // contains all letters from the query in the begginning, displayed first
 +use expect_test::{expect, Expect};
 +
 +use crate::{
 +    context::{CompletionAnalysis, NameContext, NameKind, NameRefKind},
 +    tests::{check_edit, check_edit_with_config, TEST_CONFIG},
 +};
 +
 +fn check(ra_fixture: &str, expect: Expect) {
 +    let config = TEST_CONFIG;
 +    let (db, position) = crate::tests::position(ra_fixture);
 +    let (ctx, analysis) = crate::context::CompletionContext::new(&db, position, &config).unwrap();
 +
 +    let mut acc = crate::completions::Completions::default();
 +    if let CompletionAnalysis::Name(NameContext { kind: NameKind::IdentPat(pat_ctx), .. }) =
 +        &analysis
 +    {
 +        crate::completions::flyimport::import_on_the_fly_pat(&mut acc, &ctx, pat_ctx);
 +    }
 +    if let CompletionAnalysis::NameRef(name_ref_ctx) = &analysis {
 +        match &name_ref_ctx.kind {
 +            NameRefKind::Path(path) => {
 +                crate::completions::flyimport::import_on_the_fly_path(&mut acc, &ctx, path);
 +            }
 +            NameRefKind::DotAccess(dot_access) => {
 +                crate::completions::flyimport::import_on_the_fly_dot(&mut acc, &ctx, dot_access);
 +            }
 +            NameRefKind::Pattern(pattern) => {
 +                crate::completions::flyimport::import_on_the_fly_pat(&mut acc, &ctx, pattern);
 +            }
 +            _ => (),
 +        }
 +    }
 +
 +    expect.assert_eq(&super::render_completion_list(Vec::from(acc)));
 +}
 +
 +#[test]
 +fn function_fuzzy_completion() {
 +    check_edit(
 +        "stdin",
 +        r#"
 +//- /lib.rs crate:dep
 +pub mod io {
 +    pub fn stdin() {}
 +};
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    stdi$0
 +}
 +"#,
 +        r#"
 +use dep::io::stdin;
 +
 +fn main() {
 +    stdin()$0
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn macro_fuzzy_completion() {
 +    check_edit(
 +        "macro_with_curlies!",
 +        r#"
 +//- /lib.rs crate:dep
 +/// Please call me as macro_with_curlies! {}
 +#[macro_export]
 +macro_rules! macro_with_curlies {
 +    () => {}
 +}
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    curli$0
 +}
 +"#,
 +        r#"
 +use dep::macro_with_curlies;
 +
 +fn main() {
 +    macro_with_curlies! {$0}
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn struct_fuzzy_completion() {
 +    check_edit(
 +        "ThirdStruct",
 +        r#"
 +//- /lib.rs crate:dep
 +pub struct FirstStruct;
 +pub mod some_module {
 +    pub struct SecondStruct;
 +    pub struct ThirdStruct;
 +}
 +
 +//- /main.rs crate:main deps:dep
 +use dep::{FirstStruct, some_module::SecondStruct};
 +
 +fn main() {
 +    this$0
 +}
 +"#,
 +        r#"
 +use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
 +
 +fn main() {
 +    ThirdStruct
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn short_paths_are_ignored() {
 +    cov_mark::check!(flyimport_exact_on_short_path);
 +
 +    check(
 +        r#"
 +//- /lib.rs crate:dep
 +pub struct Bar;
 +pub struct Rcar;
 +pub struct Rc;
 +pub mod some_module {
 +    pub struct Bar;
 +    pub struct Rcar;
 +    pub struct Rc;
 +}
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    rc$0
 +}
 +"#,
 +        expect![[r#"
 +            st Rc (use dep::Rc)
 +            st Rc (use dep::some_module::Rc)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn fuzzy_completions_come_in_specific_order() {
 +    cov_mark::check!(certain_fuzzy_order_test);
 +    check(
 +        r#"
 +//- /lib.rs crate:dep
 +pub struct FirstStruct;
 +pub mod some_module {
 +    // already imported, omitted
 +    pub struct SecondStruct;
 +    // does not contain all letters from the query, omitted
 +    pub struct UnrelatedOne;
 +    // contains all letters from the query, but not in sequence, displayed last
 +    pub struct ThiiiiiirdStruct;
 +    // contains all letters from the query, but not in the beginning, displayed second
 +    pub struct AfterThirdStruct;
++    // contains all letters from the query in the beginning, displayed first
 +    pub struct ThirdStruct;
 +}
 +
 +//- /main.rs crate:main deps:dep
 +use dep::{FirstStruct, some_module::SecondStruct};
 +
 +fn main() {
 +    hir$0
 +}
 +"#,
 +        expect![[r#"
 +                st ThirdStruct (use dep::some_module::ThirdStruct)
 +                st AfterThirdStruct (use dep::some_module::AfterThirdStruct)
 +                st ThiiiiiirdStruct (use dep::some_module::ThiiiiiirdStruct)
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn trait_function_fuzzy_completion() {
 +    let fixture = r#"
 +        //- /lib.rs crate:dep
 +        pub mod test_mod {
 +            pub trait TestTrait {
 +                const SPECIAL_CONST: u8;
 +                type HumbleType;
 +                fn weird_function();
 +                fn random_method(&self);
 +            }
 +            pub struct TestStruct {}
 +            impl TestTrait for TestStruct {
 +                const SPECIAL_CONST: u8 = 42;
 +                type HumbleType = ();
 +                fn weird_function() {}
 +                fn random_method(&self) {}
 +            }
 +        }
 +
 +        //- /main.rs crate:main deps:dep
 +        fn main() {
 +            dep::test_mod::TestStruct::wei$0
 +        }
 +        "#;
 +
 +    check(
 +        fixture,
 +        expect![[r#"
 +                fn weird_function() (use dep::test_mod::TestTrait) fn()
 +            "#]],
 +    );
 +
 +    check_edit(
 +        "weird_function",
 +        fixture,
 +        r#"
 +use dep::test_mod::TestTrait;
 +
 +fn main() {
 +    dep::test_mod::TestStruct::weird_function()$0
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_const_fuzzy_completion() {
 +    let fixture = r#"
 +        //- /lib.rs crate:dep
 +        pub mod test_mod {
 +            pub trait TestTrait {
 +                const SPECIAL_CONST: u8;
 +                type HumbleType;
 +                fn weird_function();
 +                fn random_method(&self);
 +            }
 +            pub struct TestStruct {}
 +            impl TestTrait for TestStruct {
 +                const SPECIAL_CONST: u8 = 42;
 +                type HumbleType = ();
 +                fn weird_function() {}
 +                fn random_method(&self) {}
 +            }
 +        }
 +
 +        //- /main.rs crate:main deps:dep
 +        fn main() {
 +            dep::test_mod::TestStruct::spe$0
 +        }
 +        "#;
 +
 +    check(
 +        fixture,
 +        expect![[r#"
 +            ct SPECIAL_CONST (use dep::test_mod::TestTrait)
 +        "#]],
 +    );
 +
 +    check_edit(
 +        "SPECIAL_CONST",
 +        fixture,
 +        r#"
 +use dep::test_mod::TestTrait;
 +
 +fn main() {
 +    dep::test_mod::TestStruct::SPECIAL_CONST
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_method_fuzzy_completion() {
 +    let fixture = r#"
 +        //- /lib.rs crate:dep
 +        pub mod test_mod {
 +            pub trait TestTrait {
 +                const SPECIAL_CONST: u8;
 +                type HumbleType;
 +                fn weird_function();
 +                fn random_method(&self);
 +            }
 +            pub struct TestStruct {}
 +            impl TestTrait for TestStruct {
 +                const SPECIAL_CONST: u8 = 42;
 +                type HumbleType = ();
 +                fn weird_function() {}
 +                fn random_method(&self) {}
 +            }
 +        }
 +
 +        //- /main.rs crate:main deps:dep
 +        fn main() {
 +            let test_struct = dep::test_mod::TestStruct {};
 +            test_struct.ran$0
 +        }
 +        "#;
 +
 +    check(
 +        fixture,
 +        expect![[r#"
 +                me random_method() (use dep::test_mod::TestTrait) fn(&self)
 +            "#]],
 +    );
 +
 +    check_edit(
 +        "random_method",
 +        fixture,
 +        r#"
 +use dep::test_mod::TestTrait;
 +
 +fn main() {
 +    let test_struct = dep::test_mod::TestStruct {};
 +    test_struct.random_method()$0
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_method_from_alias() {
 +    let fixture = r#"
 +//- /lib.rs crate:dep
 +pub mod test_mod {
 +    pub trait TestTrait {
 +        fn random_method();
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        fn random_method() {}
 +    }
 +    pub type TestAlias = TestStruct;
 +}
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    dep::test_mod::TestAlias::ran$0
 +}
 +"#;
 +
 +    check(
 +        fixture,
 +        expect![[r#"
 +                fn random_method() (use dep::test_mod::TestTrait) fn()
 +            "#]],
 +    );
 +
 +    check_edit(
 +        "random_method",
 +        fixture,
 +        r#"
 +use dep::test_mod::TestTrait;
 +
 +fn main() {
 +    dep::test_mod::TestAlias::random_method()$0
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn no_trait_type_fuzzy_completion() {
 +    check(
 +        r#"
 +//- /lib.rs crate:dep
 +pub mod test_mod {
 +    pub trait TestTrait {
 +        const SPECIAL_CONST: u8;
 +        type HumbleType;
 +        fn weird_function();
 +        fn random_method(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        const SPECIAL_CONST: u8 = 42;
 +        type HumbleType = ();
 +        fn weird_function() {}
 +        fn random_method(&self) {}
 +    }
 +}
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    dep::test_mod::TestStruct::hum$0
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +}
 +
 +#[test]
 +fn does_not_propose_names_in_scope() {
 +    check(
 +        r#"
 +//- /lib.rs crate:dep
 +pub mod test_mod {
 +    pub trait TestTrait {
 +        const SPECIAL_CONST: u8;
 +        type HumbleType;
 +        fn weird_function();
 +        fn random_method(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        const SPECIAL_CONST: u8 = 42;
 +        type HumbleType = ();
 +        fn weird_function() {}
 +        fn random_method(&self) {}
 +    }
 +}
 +
 +//- /main.rs crate:main deps:dep
 +use dep::test_mod::TestStruct;
 +fn main() {
 +    TestSt$0
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +}
 +
 +#[test]
 +fn does_not_propose_traits_in_scope() {
 +    check(
 +        r#"
 +//- /lib.rs crate:dep
 +pub mod test_mod {
 +    pub trait TestTrait {
 +        const SPECIAL_CONST: u8;
 +        type HumbleType;
 +        fn weird_function();
 +        fn random_method(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        const SPECIAL_CONST: u8 = 42;
 +        type HumbleType = ();
 +        fn weird_function() {}
 +        fn random_method(&self) {}
 +    }
 +}
 +
 +//- /main.rs crate:main deps:dep
 +use dep::test_mod::{TestStruct, TestTrait};
 +fn main() {
 +    dep::test_mod::TestStruct::hum$0
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +}
 +
 +#[test]
 +fn blanket_trait_impl_import() {
 +    check_edit(
 +        "another_function",
 +        r#"
 +//- /lib.rs crate:dep
 +pub mod test_mod {
 +    pub struct TestStruct {}
 +    pub trait TestTrait {
 +        fn another_function();
 +    }
 +    impl<T> TestTrait for T {
 +        fn another_function() {}
 +    }
 +}
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    dep::test_mod::TestStruct::ano$0
 +}
 +"#,
 +        r#"
 +use dep::test_mod::TestTrait;
 +
 +fn main() {
 +    dep::test_mod::TestStruct::another_function()$0
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn zero_input_deprecated_assoc_item_completion() {
 +    check(
 +        r#"
 +//- /lib.rs crate:dep
 +pub mod test_mod {
 +    #[deprecated]
 +    pub trait TestTrait {
 +        const SPECIAL_CONST: u8;
 +        type HumbleType;
 +        fn weird_function();
 +        fn random_method(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        const SPECIAL_CONST: u8 = 42;
 +        type HumbleType = ();
 +        fn weird_function() {}
 +        fn random_method(&self) {}
 +    }
 +}
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    let test_struct = dep::test_mod::TestStruct {};
 +    test_struct.$0
 +}
 +        "#,
 +        expect![[r#"
 +                me random_method() (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
 +            "#]],
 +    );
 +
 +    check(
 +        r#"
 +//- /lib.rs crate:dep
 +pub mod test_mod {
 +    #[deprecated]
 +    pub trait TestTrait {
 +        const SPECIAL_CONST: u8;
 +        type HumbleType;
 +        fn weird_function();
 +        fn random_method(&self);
 +    }
 +    pub struct TestStruct {}
 +    impl TestTrait for TestStruct {
 +        const SPECIAL_CONST: u8 = 42;
 +        type HumbleType = ();
 +        fn weird_function() {}
 +        fn random_method(&self) {}
 +    }
 +}
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    dep::test_mod::TestStruct::$0
 +}
 +"#,
 +        expect![[r#"
 +                fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
 +                ct SPECIAL_CONST (use dep::test_mod::TestTrait) DEPRECATED
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn no_completions_in_use_statements() {
 +    check(
 +        r#"
 +//- /lib.rs crate:dep
 +pub mod io {
 +    pub fn stdin() {}
 +};
 +
 +//- /main.rs crate:main deps:dep
 +use stdi$0
 +
 +fn main() {}
 +"#,
 +        expect![[]],
 +    );
 +}
 +
 +#[test]
 +fn prefix_config_usage() {
 +    let fixture = r#"
 +mod foo {
 +    pub mod bar {
 +        pub struct Item;
 +    }
 +}
 +
 +use crate::foo::bar;
 +
 +fn main() {
 +    Ite$0
 +}"#;
 +    let mut config = TEST_CONFIG;
 +
 +    config.insert_use.prefix_kind = hir::PrefixKind::ByCrate;
 +    check_edit_with_config(
 +        config.clone(),
 +        "Item",
 +        fixture,
 +        r#"
 +mod foo {
 +    pub mod bar {
 +        pub struct Item;
 +    }
 +}
 +
 +use crate::foo::bar::{self, Item};
 +
 +fn main() {
 +    Item
 +}"#,
 +    );
 +
 +    config.insert_use.prefix_kind = hir::PrefixKind::BySelf;
 +    check_edit_with_config(
 +        config.clone(),
 +        "Item",
 +        fixture,
 +        r#"
 +mod foo {
 +    pub mod bar {
 +        pub struct Item;
 +    }
 +}
 +
 +use crate::foo::bar;
 +
 +use self::foo::bar::Item;
 +
 +fn main() {
 +    Item
 +}"#,
 +    );
 +
 +    config.insert_use.prefix_kind = hir::PrefixKind::Plain;
 +    check_edit_with_config(
 +        config,
 +        "Item",
 +        fixture,
 +        r#"
 +mod foo {
 +    pub mod bar {
 +        pub struct Item;
 +    }
 +}
 +
 +use foo::bar::Item;
 +
 +use crate::foo::bar;
 +
 +fn main() {
 +    Item
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn unresolved_qualifier() {
 +    let fixture = r#"
 +mod foo {
 +    pub mod bar {
 +        pub mod baz {
 +            pub struct Item;
 +        }
 +    }
 +}
 +
 +fn main() {
 +    bar::baz::Ite$0
 +}"#;
 +
 +    check(
 +        fixture,
 +        expect![[r#"
 +        st Item (use foo::bar::baz::Item)
 +        "#]],
 +    );
 +
 +    check_edit(
 +        "Item",
 +        fixture,
 +        r#"
 +        use foo::bar;
 +
 +        mod foo {
 +            pub mod bar {
 +                pub mod baz {
 +                    pub struct Item;
 +                }
 +            }
 +        }
 +
 +        fn main() {
 +            bar::baz::Item
 +        }"#,
 +    );
 +}
 +
 +#[test]
 +fn unresolved_assoc_item_container() {
 +    let fixture = r#"
 +mod foo {
 +    pub struct Item;
 +
 +    impl Item {
 +        pub const TEST_ASSOC: usize = 3;
 +    }
 +}
 +
 +fn main() {
 +    Item::TEST_A$0
 +}"#;
 +
 +    check(
 +        fixture,
 +        expect![[r#"
 +        ct TEST_ASSOC (use foo::Item)
 +        "#]],
 +    );
 +
 +    check_edit(
 +        "TEST_ASSOC",
 +        fixture,
 +        r#"
 +use foo::Item;
 +
 +mod foo {
 +    pub struct Item;
 +
 +    impl Item {
 +        pub const TEST_ASSOC: usize = 3;
 +    }
 +}
 +
 +fn main() {
 +    Item::TEST_ASSOC
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn unresolved_assoc_item_container_with_path() {
 +    let fixture = r#"
 +mod foo {
 +    pub mod bar {
 +        pub struct Item;
 +
 +        impl Item {
 +            pub const TEST_ASSOC: usize = 3;
 +        }
 +    }
 +}
 +
 +fn main() {
 +    bar::Item::TEST_A$0
 +}"#;
 +
 +    check(
 +        fixture,
 +        expect![[r#"
 +        ct TEST_ASSOC (use foo::bar::Item)
 +    "#]],
 +    );
 +
 +    check_edit(
 +        "TEST_ASSOC",
 +        fixture,
 +        r#"
 +use foo::bar;
 +
 +mod foo {
 +    pub mod bar {
 +        pub struct Item;
 +
 +        impl Item {
 +            pub const TEST_ASSOC: usize = 3;
 +        }
 +    }
 +}
 +
 +fn main() {
 +    bar::Item::TEST_ASSOC
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn fuzzy_unresolved_path() {
 +    check(
 +        r#"
 +mod foo {
 +    pub mod bar {
 +        pub struct Item;
 +
 +        impl Item {
 +            pub const TEST_ASSOC: usize = 3;
 +        }
 +    }
 +}
 +
 +fn main() {
 +    bar::ASS$0
 +}"#,
 +        expect![[]],
 +    )
 +}
 +
 +#[test]
 +fn unqualified_assoc_items_are_omitted() {
 +    check(
 +        r#"
 +mod something {
 +    pub trait BaseTrait {
 +        fn test_function() -> i32;
 +    }
 +
 +    pub struct Item1;
 +    pub struct Item2;
 +
 +    impl BaseTrait for Item1 {
 +        fn test_function() -> i32 {
 +            1
 +        }
 +    }
 +
 +    impl BaseTrait for Item2 {
 +        fn test_function() -> i32 {
 +            2
 +        }
 +    }
 +}
 +
 +fn main() {
 +    test_f$0
 +}"#,
 +        expect![[]],
 +    )
 +}
 +
 +#[test]
 +fn case_matters() {
 +    check(
 +        r#"
 +mod foo {
 +    pub const TEST_CONST: usize = 3;
 +    pub fn test_function() -> i32 {
 +        4
 +    }
 +}
 +
 +fn main() {
 +    TES$0
 +}"#,
 +        expect![[r#"
 +        ct TEST_CONST (use foo::TEST_CONST)
 +    "#]],
 +    );
 +
 +    check(
 +        r#"
 +mod foo {
 +    pub const TEST_CONST: usize = 3;
 +    pub fn test_function() -> i32 {
 +        4
 +    }
 +}
 +
 +fn main() {
 +    tes$0
 +}"#,
 +        expect![[r#"
 +        ct TEST_CONST (use foo::TEST_CONST)
 +        fn test_function() (use foo::test_function) fn() -> i32
 +    "#]],
 +    );
 +
 +    check(
 +        r#"
 +mod foo {
 +    pub const TEST_CONST: usize = 3;
 +    pub fn test_function() -> i32 {
 +        4
 +    }
 +}
 +
 +fn main() {
 +    Te$0
 +}"#,
 +        expect![[]],
 +    );
 +}
 +
 +#[test]
 +fn no_fuzzy_during_fields_of_record_lit_syntax() {
 +    check(
 +        r#"
 +mod m {
 +    pub fn some_fn() -> i32 {
 +        42
 +    }
 +}
 +struct Foo {
 +    some_field: i32,
 +}
 +fn main() {
 +    let _ = Foo { so$0 };
 +}
 +"#,
 +        expect![[]],
 +    );
 +}
 +
 +#[test]
 +fn fuzzy_after_fields_of_record_lit_syntax() {
 +    check(
 +        r#"
 +mod m {
 +    pub fn some_fn() -> i32 {
 +        42
 +    }
 +}
 +struct Foo {
 +    some_field: i32,
 +}
 +fn main() {
 +    let _ = Foo { some_field: som$0 };
 +}
 +"#,
 +        expect![[r#"
 +                fn some_fn() (use m::some_fn) fn() -> i32
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn no_flyimports_in_traits_and_impl_declarations() {
 +    check(
 +        r#"
 +mod m {
 +    pub fn some_fn() -> i32 {
 +        42
 +    }
 +}
 +trait Foo {
 +    som$0
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +
 +    check(
 +        r#"
 +mod m {
 +    pub fn some_fn() -> i32 {
 +        42
 +    }
 +}
 +struct Foo;
 +impl Foo {
 +    som$0
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +
 +    check(
 +        r#"
 +mod m {
 +    pub fn some_fn() -> i32 {
 +        42
 +    }
 +}
 +struct Foo;
 +trait Bar {}
 +impl Bar for Foo {
 +    som$0
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +}
 +
 +#[test]
 +fn no_inherent_candidates_proposed() {
 +    check(
 +        r#"
 +mod baz {
 +    pub trait DefDatabase {
 +        fn method1(&self);
 +    }
 +    pub trait HirDatabase: DefDatabase {
 +        fn method2(&self);
 +    }
 +}
 +
 +mod bar {
 +    fn test(db: &dyn crate::baz::HirDatabase) {
 +        db.metho$0
 +    }
 +}
 +            "#,
 +        expect![[r#""#]],
 +    );
 +    check(
 +        r#"
 +mod baz {
 +    pub trait DefDatabase {
 +        fn method1(&self);
 +    }
 +    pub trait HirDatabase: DefDatabase {
 +        fn method2(&self);
 +    }
 +}
 +
 +mod bar {
 +    fn test(db: &impl crate::baz::HirDatabase) {
 +        db.metho$0
 +    }
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +    check(
 +        r#"
 +mod baz {
 +    pub trait DefDatabase {
 +        fn method1(&self);
 +    }
 +    pub trait HirDatabase: DefDatabase {
 +        fn method2(&self);
 +    }
 +}
 +
 +mod bar {
 +    fn test<T: crate::baz::HirDatabase>(db: T) {
 +        db.metho$0
 +    }
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +}
 +
 +#[test]
 +fn respects_doc_hidden() {
 +    check(
 +        r#"
 +//- /lib.rs crate:lib deps:dep
 +fn f() {
 +    ().fro$0
 +}
 +
 +//- /dep.rs crate:dep
 +#[doc(hidden)]
 +pub trait Private {
 +    fn frob(&self) {}
 +}
 +
 +impl<T> Private for T {}
 +            "#,
 +        expect![[r#""#]],
 +    );
 +    check(
 +        r#"
 +//- /lib.rs crate:lib deps:dep
 +fn f() {
 +    ().fro$0
 +}
 +
 +//- /dep.rs crate:dep
 +pub trait Private {
 +    #[doc(hidden)]
 +    fn frob(&self) {}
 +}
 +
 +impl<T> Private for T {}
 +            "#,
 +        expect![[r#""#]],
 +    );
 +}
 +
 +#[test]
 +fn regression_9760() {
 +    check(
 +        r#"
 +struct Struct;
 +fn main() {}
 +
 +mod mud {
 +    fn func() {
 +        let struct_instance = Stru$0
 +    }
 +}
 +"#,
 +        expect![[r#"
 +                st Struct (use crate::Struct)
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn flyimport_pattern() {
 +    check(
 +        r#"
 +mod module {
 +    pub struct FooStruct {}
 +    pub const FooConst: () = ();
 +    pub fn foo_fun() {}
 +}
 +fn function() {
 +    let foo$0
 +}
 +"#,
 +        expect![[r#"
 +            ct FooConst (use module::FooConst)
 +            st FooStruct (use module::FooStruct)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn flyimport_item_name() {
 +    check(
 +        r#"
 +mod module {
 +    pub struct Struct;
 +}
 +struct Str$0
 +    "#,
 +        expect![[r#""#]],
 +    );
 +}
 +
 +#[test]
 +fn flyimport_rename() {
 +    check(
 +        r#"
 +mod module {
 +    pub struct Struct;
 +}
 +use self as Str$0;
 +    "#,
 +        expect![[r#""#]],
 +    );
 +}
 +
 +#[test]
 +fn flyimport_enum_variant() {
 +    check(
 +        r#"
 +mod foo {
 +    pub struct Barbara;
 +}
 +
 +enum Foo {
 +    Barba$0()
 +}
 +}"#,
 +        expect![[r#""#]],
 +    );
 +
 +    check(
 +        r#"
 +mod foo {
 +    pub struct Barbara;
 +}
 +
 +enum Foo {
 +    Barba(Barba$0)
 +}
 +}"#,
 +        expect![[r#"
 +            st Barbara (use foo::Barbara)
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn flyimport_attribute() {
 +    check(
 +        r#"
 +//- proc_macros:identity
 +#[ide$0]
 +struct Foo;
 +"#,
 +        expect![[r#"
 +            at identity (use proc_macros::identity) proc_macro identity
 +        "#]],
 +    );
 +    check_edit(
 +        "identity",
 +        r#"
 +//- proc_macros:identity
 +#[ide$0]
 +struct Foo;
 +"#,
 +        r#"
 +use proc_macros::identity;
 +
 +#[identity]
 +struct Foo;
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn flyimport_in_type_bound_omits_types() {
 +    check(
 +        r#"
 +mod module {
 +    pub struct CompletemeStruct;
 +    pub type CompletemeType = ();
 +    pub enum CompletemeEnum {}
 +    pub trait CompletemeTrait {}
 +}
 +
 +fn f<T>() where T: Comp$0
 +"#,
 +        expect![[r#"
 +            tt CompletemeTrait (use module::CompletemeTrait)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn flyimport_source_file() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:dep
 +def$0
 +//- /lib.rs crate:dep
 +#[macro_export]
 +macro_rules! define_struct {
 +    () => {
 +        pub struct Foo;
 +    };
 +}
 +"#,
 +        expect![[r#"
 +            ma define_struct!(…) (use dep::define_struct) macro_rules! define_struct
 +        "#]],
 +    );
 +}
index 30ddbe2dc6f6010caca0c48d70e718a3178c1c90,0000000000000000000000000000000000000000..85c4dbd6625dfcfc891a073c885eab6eec98780b
mode 100644,000000..100644
--- /dev/null
@@@ -1,716 -1,0 +1,716 @@@
-         "RecordVariant {…}",
 +//! Completion tests for pattern position.
 +use expect_test::{expect, Expect};
 +
 +use crate::tests::{check_edit, completion_list, BASE_ITEMS_FIXTURE};
 +
 +fn check_empty(ra_fixture: &str, expect: Expect) {
 +    let actual = completion_list(ra_fixture);
 +    expect.assert_eq(&actual)
 +}
 +
 +fn check(ra_fixture: &str, expect: Expect) {
 +    let actual = completion_list(&format!("{}\n{}", BASE_ITEMS_FIXTURE, ra_fixture));
 +    expect.assert_eq(&actual)
 +}
 +
 +#[test]
 +fn wildcard() {
 +    check(
 +        r#"
 +fn quux() {
 +    let _$0
 +}
 +"#,
 +        expect![""],
 +    );
 +}
 +
 +#[test]
 +fn ident_rebind_pat() {
 +    check_empty(
 +        r#"
 +fn quux() {
 +    let en$0 @ x
 +}
 +"#,
 +        expect![[r#"
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn ident_ref_pat() {
 +    check_empty(
 +        r#"
 +fn quux() {
 +    let ref en$0
 +}
 +"#,
 +        expect![[r#"
 +            kw mut
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +fn quux() {
 +    let ref en$0 @ x
 +}
 +"#,
 +        expect![[r#"
 +            kw mut
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn ident_ref_mut_pat() {
 +    check_empty(
 +        r#"
 +fn quux() {
 +    let ref mut en$0
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +    check_empty(
 +        r#"
 +fn quux() {
 +    let ref mut en$0 @ x
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +}
 +
 +#[test]
 +fn ref_pat() {
 +    check_empty(
 +        r#"
 +fn quux() {
 +    let &en$0
 +}
 +"#,
 +        expect![[r#"
 +            kw mut
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +fn quux() {
 +    let &mut en$0
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +    check_empty(
 +        r#"
 +fn foo() {
 +    for &$0 in () {}
 +}
 +"#,
 +        expect![[r#"
 +            kw mut
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn refutable() {
 +    check(
 +        r#"
 +fn foo() {
 +    if let a$0
 +}
 +"#,
 +        expect![[r#"
 +            ct CONST
 +            en Enum
 +            ma makro!(…)  macro_rules! makro
 +            md module
 +            st Record
 +            st Tuple
 +            st Unit
 +            ev TupleV
 +            bn Record {…} Record { field$1 }$0
 +            bn Tuple(…)   Tuple($1)$0
 +            bn TupleV(…)  TupleV($1)$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn irrefutable() {
 +    check(
 +        r#"
 +enum SingleVariantEnum {
 +    Variant
 +}
 +use SingleVariantEnum::Variant;
 +fn foo() {
 +   let a$0
 +}
 +"#,
 +        expect![[r#"
 +            en SingleVariantEnum
 +            ma makro!(…)         macro_rules! makro
 +            md module
 +            st Record
 +            st Tuple
 +            st Unit
 +            ev Variant
 +            bn Record {…}        Record { field$1 }$0
 +            bn Tuple(…)          Tuple($1)$0
 +            bn Variant           Variant$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn in_param() {
 +    check(
 +        r#"
 +fn foo(a$0) {
 +}
 +"#,
 +        expect![[r#"
 +            ma makro!(…)  macro_rules! makro
 +            md module
 +            st Record
 +            st Tuple
 +            st Unit
 +            bn Record {…} Record { field$1 }: Record$0
 +            bn Tuple(…)   Tuple($1): Tuple$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +    check(
 +        r#"
 +fn foo(a$0: Tuple) {
 +}
 +"#,
 +        expect![[r#"
 +            ma makro!(…)  macro_rules! makro
 +            md module
 +            st Record
 +            st Tuple
 +            st Unit
 +            bn Record {…} Record { field$1 }$0
 +            bn Tuple(…)   Tuple($1)$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn only_fn_like_macros() {
 +    check_empty(
 +        r#"
 +macro_rules! m { ($e:expr) => { $e } }
 +
 +#[rustc_builtin_macro]
 +macro Clone {}
 +
 +fn foo() {
 +    let x$0
 +}
 +"#,
 +        expect![[r#"
 +            ma m!(…) macro_rules! m
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn in_simple_macro_call() {
 +    check_empty(
 +        r#"
 +macro_rules! m { ($e:expr) => { $e } }
 +enum E { X }
 +
 +fn foo() {
 +   m!(match E::X { a$0 })
 +}
 +"#,
 +        expect![[r#"
 +            en E
 +            ma m!(…) macro_rules! m
 +            bn E::X  E::X$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn omits_private_fields_pat() {
 +    check_empty(
 +        r#"
 +mod foo {
 +    pub struct Record { pub field: i32, _field: i32 }
 +    pub struct Tuple(pub u32, u32);
 +    pub struct Invisible(u32, u32);
 +}
 +use foo::*;
 +
 +fn outer() {
 +    if let a$0
 +}
 +"#,
 +        expect![[r#"
 +            md foo
 +            st Invisible
 +            st Record
 +            st Tuple
 +            bn Record {…} Record { field$1, .. }$0
 +            bn Tuple(…)   Tuple($1, ..)$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn completes_self_pats() {
 +    check_empty(
 +        r#"
 +struct Foo(i32);
 +impl Foo {
 +    fn foo() {
 +        match Foo(0) {
 +            a$0
 +        }
 +    }
 +}
 +    "#,
 +        expect![[r#"
 +            sp Self
 +            st Foo
 +            bn Foo(…)  Foo($1)$0
 +            bn Self(…) Self($1)$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn enum_qualified() {
 +    check(
 +        r#"
 +impl Enum {
 +    type AssocType = ();
 +    const ASSOC_CONST: () = ();
 +    fn assoc_fn() {}
 +}
 +fn func() {
 +    if let Enum::$0 = unknown {}
 +}
 +"#,
 +        expect![[r#"
 +            ct ASSOC_CONST const ASSOC_CONST: ()
 +            bn RecordV {…} RecordV { field$1 }$0
 +            bn TupleV(…)   TupleV($1)$0
 +            bn UnitV       UnitV$0
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn completes_in_record_field_pat() {
 +    check_empty(
 +        r#"
 +struct Foo { bar: Bar }
 +struct Bar(u32);
 +fn outer(Foo { bar: $0 }: Foo) {}
 +"#,
 +        expect![[r#"
 +            st Bar
 +            st Foo
 +            bn Bar(…)  Bar($1)$0
 +            bn Foo {…} Foo { bar$1 }$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn skips_in_record_field_pat_name() {
 +    check_empty(
 +        r#"
 +struct Foo { bar: Bar }
 +struct Bar(u32);
 +fn outer(Foo { bar$0 }: Foo) {}
 +"#,
 +        expect![[r#"
 +            kw mut
 +            kw ref
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn completes_in_fn_param() {
 +    check_empty(
 +        r#"
 +struct Foo { bar: Bar }
 +struct Bar(u32);
 +fn foo($0) {}
 +"#,
 +        expect![[r#"
 +            st Bar
 +            st Foo
 +            bn Bar(…)  Bar($1): Bar$0
 +            bn Foo {…} Foo { bar$1 }: Foo$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn completes_in_closure_param() {
 +    check_empty(
 +        r#"
 +struct Foo { bar: Bar }
 +struct Bar(u32);
 +fn foo() {
 +    |$0| {};
 +}
 +"#,
 +        expect![[r#"
 +            st Bar
 +            st Foo
 +            bn Bar(…)  Bar($1)$0
 +            bn Foo {…} Foo { bar$1 }$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn completes_no_delims_if_existing() {
 +    check_empty(
 +        r#"
 +struct Bar(u32);
 +fn foo() {
 +    match Bar(0) {
 +        B$0(b) => {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            st Bar
 +            kw crate::
 +            kw self::
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +struct Foo { bar: u32 }
 +fn foo() {
 +    match (Foo { bar: 0 }) {
 +        F$0 { bar } => {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            st Foo
 +            kw crate::
 +            kw self::
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +enum Enum {
 +    TupleVariant(u32)
 +}
 +fn foo() {
 +    match Enum::TupleVariant(0) {
 +        Enum::T$0(b) => {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            bn TupleVariant TupleVariant
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +enum Enum {
 +    RecordVariant { field: u32 }
 +}
 +fn foo() {
 +    match (Enum::RecordVariant { field: 0 }) {
 +        Enum::RecordV$0 { field } => {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            bn RecordVariant RecordVariant
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn completes_enum_variant_pat() {
 +    cov_mark::check!(enum_variant_pattern_path);
 +    check_edit(
++        "RecordVariant{}",
 +        r#"
 +enum Enum {
 +    RecordVariant { field: u32 }
 +}
 +fn foo() {
 +    match (Enum::RecordVariant { field: 0 }) {
 +        Enum::RecordV$0
 +    }
 +}
 +"#,
 +        r#"
 +enum Enum {
 +    RecordVariant { field: u32 }
 +}
 +fn foo() {
 +    match (Enum::RecordVariant { field: 0 }) {
 +        Enum::RecordVariant { field$1 }$0
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn completes_enum_variant_pat_escape() {
 +    cov_mark::check!(enum_variant_pattern_path);
 +    check_empty(
 +        r#"
 +enum Enum {
 +    A,
 +    B { r#type: i32 },
 +    r#type,
 +    r#struct { r#type: i32 },
 +}
 +fn foo() {
 +    match (Enum::A) {
 +        $0
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            en Enum
 +            bn Enum::A          Enum::A$0
 +            bn Enum::B {…}      Enum::B { r#type$1 }$0
 +            bn Enum::struct {…} Enum::r#struct { r#type$1 }$0
 +            bn Enum::type       Enum::r#type$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +
 +    check_empty(
 +        r#"
 +enum Enum {
 +    A,
 +    B { r#type: i32 },
 +    r#type,
 +    r#struct { r#type: i32 },
 +}
 +fn foo() {
 +    match (Enum::A) {
 +        Enum::$0
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            bn A          A$0
 +            bn B {…}      B { r#type$1 }$0
 +            bn struct {…} r#struct { r#type$1 }$0
 +            bn type       r#type$0
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn completes_associated_const() {
 +    check_empty(
 +        r#"
 +#[derive(PartialEq, Eq)]
 +struct Ty(u8);
 +
 +impl Ty {
 +    const ABC: Self = Self(0);
 +}
 +
 +fn f(t: Ty) {
 +    match t {
 +        Ty::$0 => {}
 +        _ => {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            ct ABC const ABC: Self
 +        "#]],
 +    );
 +
 +    check_empty(
 +        r#"
 +enum MyEnum {}
 +
 +impl MyEnum {
 +    pub const A: i32 = 123;
 +    pub const B: i32 = 456;
 +}
 +
 +fn f(e: MyEnum) {
 +    match e {
 +        MyEnum::$0 => {}
 +        _ => {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            ct A pub const A: i32
 +            ct B pub const B: i32
 +        "#]],
 +    );
 +
 +    check_empty(
 +        r#"
 +union U {
 +    i: i32,
 +    f: f32,
 +}
 +
 +impl U {
 +    pub const C: i32 = 123;
 +    pub const D: i32 = 456;
 +}
 +
 +fn f(u: U) {
 +    match u {
 +        U::$0 => {}
 +        _ => {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            ct C pub const C: i32
 +            ct D pub const D: i32
 +        "#]],
 +    );
 +
 +    check_empty(
 +        r#"
 +#[lang = "u32"]
 +impl u32 {
 +    pub const MIN: Self = 0;
 +}
 +
 +fn f(v: u32) {
 +    match v {
 +        u32::$0
 +    }
 +}
 +        "#,
 +        expect![[r#"
 +            ct MIN pub const MIN: Self
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn in_method_param() {
 +    check_empty(
 +        r#"
 +struct Ty(u8);
 +
 +impl Ty {
 +    fn foo($0)
 +}
 +"#,
 +        expect![[r#"
 +            sp Self
 +            st Ty
 +            bn &mut self
 +            bn &self
 +            bn Self(…)   Self($1): Self$0
 +            bn Ty(…)     Ty($1): Ty$0
 +            bn mut self
 +            bn self
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +struct Ty(u8);
 +
 +impl Ty {
 +    fn foo(s$0)
 +}
 +"#,
 +        expect![[r#"
 +            sp Self
 +            st Ty
 +            bn &mut self
 +            bn &self
 +            bn Self(…)   Self($1): Self$0
 +            bn Ty(…)     Ty($1): Ty$0
 +            bn mut self
 +            bn self
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +struct Ty(u8);
 +
 +impl Ty {
 +    fn foo(s$0, foo: u8)
 +}
 +"#,
 +        expect![[r#"
 +            sp Self
 +            st Ty
 +            bn &mut self
 +            bn &self
 +            bn Self(…)   Self($1): Self$0
 +            bn Ty(…)     Ty($1): Ty$0
 +            bn mut self
 +            bn self
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +struct Ty(u8);
 +
 +impl Ty {
 +    fn foo(foo: u8, b$0)
 +}
 +"#,
 +        expect![[r#"
 +            sp Self
 +            st Ty
 +            bn Self(…) Self($1): Self$0
 +            bn Ty(…)   Ty($1): Ty$0
 +            kw mut
 +            kw ref
 +        "#]],
 +    );
 +}
index f8134c552f7563295d264cc0681bbc8af49e47f7,0000000000000000000000000000000000000000..b1ee9b58d5ba16d4e06bdcc457748b9046bca50b
mode 100644,000000..100644
--- /dev/null
@@@ -1,163 -1,0 +1,163 @@@
-         tracing::info!("apply_change {:?}", change);
 +//! Applies changes to the IDE state transactionally.
 +
 +use std::sync::Arc;
 +
 +use base_db::{
 +    salsa::{Database, Durability},
 +    Change, SourceRootId,
 +};
 +use profile::{memory_usage, Bytes};
 +use rustc_hash::FxHashSet;
 +
 +use crate::{symbol_index::SymbolsDatabase, RootDatabase};
 +
 +impl RootDatabase {
 +    pub fn request_cancellation(&mut self) {
 +        let _p = profile::span("RootDatabase::request_cancellation");
 +        self.salsa_runtime_mut().synthetic_write(Durability::LOW);
 +    }
 +
 +    pub fn apply_change(&mut self, change: Change) {
 +        let _p = profile::span("RootDatabase::apply_change");
 +        self.request_cancellation();
++        tracing::trace!("apply_change {:?}", change);
 +        if let Some(roots) = &change.roots {
 +            let mut local_roots = FxHashSet::default();
 +            let mut library_roots = FxHashSet::default();
 +            for (idx, root) in roots.iter().enumerate() {
 +                let root_id = SourceRootId(idx as u32);
 +                if root.is_library {
 +                    library_roots.insert(root_id);
 +                } else {
 +                    local_roots.insert(root_id);
 +                }
 +            }
 +            self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
 +            self.set_library_roots_with_durability(Arc::new(library_roots), Durability::HIGH);
 +        }
 +        change.apply(self);
 +    }
 +
 +    // Feature: Memory Usage
 +    //
 +    // Clears rust-analyzer's internal database and prints memory usage statistics.
 +    //
 +    // |===
 +    // | Editor  | Action Name
 +    //
 +    // | VS Code | **rust-analyzer: Memory Usage (Clears Database)**
 +    // |===
 +    // image::https://user-images.githubusercontent.com/48062697/113065592-08559f00-91b1-11eb-8c96-64b88068ec02.gif[]
 +    pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> {
 +        let mut acc: Vec<(String, Bytes)> = vec![];
 +        macro_rules! purge_each_query {
 +            ($($q:path)*) => {$(
 +                let before = memory_usage().allocated;
 +                $q.in_db(self).purge();
 +                let after = memory_usage().allocated;
 +                let q: $q = Default::default();
 +                let name = format!("{:?}", q);
 +                acc.push((name, before - after));
 +            )*}
 +        }
 +        purge_each_query![
 +            // SourceDatabase
 +            base_db::ParseQuery
 +            base_db::CrateGraphQuery
 +
 +            // SourceDatabaseExt
 +            base_db::FileTextQuery
 +            base_db::FileSourceRootQuery
 +            base_db::SourceRootQuery
 +            base_db::SourceRootCratesQuery
 +
 +            // AstDatabase
 +            hir::db::AstIdMapQuery
 +            hir::db::MacroArgTextQuery
 +            hir::db::MacroDefQuery
 +            hir::db::ParseMacroExpansionQuery
 +            hir::db::MacroExpandQuery
 +            hir::db::HygieneFrameQuery
 +            hir::db::InternMacroCallQuery
 +
 +            // DefDatabase
 +            hir::db::FileItemTreeQuery
 +            hir::db::BlockDefMapQuery
 +            hir::db::CrateDefMapQueryQuery
 +            hir::db::FieldsAttrsQuery
 +            hir::db::VariantsAttrsQuery
 +            hir::db::FieldsAttrsSourceMapQuery
 +            hir::db::VariantsAttrsSourceMapQuery
 +            hir::db::StructDataQuery
 +            hir::db::UnionDataQuery
 +            hir::db::EnumDataQuery
 +            hir::db::ImplDataQuery
 +            hir::db::TraitDataQuery
 +            hir::db::TypeAliasDataQuery
 +            hir::db::FunctionDataQuery
 +            hir::db::ConstDataQuery
 +            hir::db::StaticDataQuery
 +            hir::db::BodyWithSourceMapQuery
 +            hir::db::BodyQuery
 +            hir::db::ExprScopesQuery
 +            hir::db::GenericParamsQuery
 +            hir::db::AttrsQuery
 +            hir::db::CrateLangItemsQuery
 +            hir::db::LangItemQuery
 +            hir::db::ImportMapQuery
 +
 +            // HirDatabase
 +            hir::db::InferQueryQuery
 +            hir::db::TyQuery
 +            hir::db::ValueTyQuery
 +            hir::db::ImplSelfTyQuery
 +            hir::db::ImplTraitQuery
 +            hir::db::FieldTypesQuery
 +            hir::db::CallableItemSignatureQuery
 +            hir::db::GenericPredicatesForParamQuery
 +            hir::db::GenericPredicatesQuery
 +            hir::db::GenericDefaultsQuery
 +            hir::db::InherentImplsInCrateQuery
 +            hir::db::TraitEnvironmentQuery
 +            hir::db::TraitImplsInCrateQuery
 +            hir::db::TraitImplsInDepsQuery
 +            hir::db::AssociatedTyDataQuery
 +            hir::db::AssociatedTyDataQuery
 +            hir::db::TraitDatumQuery
 +            hir::db::StructDatumQuery
 +            hir::db::ImplDatumQuery
 +            hir::db::FnDefDatumQuery
 +            hir::db::ReturnTypeImplTraitsQuery
 +            hir::db::InternCallableDefQuery
 +            hir::db::InternTypeOrConstParamIdQuery
 +            hir::db::InternImplTraitIdQuery
 +            hir::db::InternClosureQuery
 +            hir::db::AssociatedTyValueQuery
 +            hir::db::TraitSolveQueryQuery
 +            hir::db::InternTypeOrConstParamIdQuery
 +
 +            // SymbolsDatabase
 +            crate::symbol_index::ModuleSymbolsQuery
 +            crate::symbol_index::LibrarySymbolsQuery
 +            crate::symbol_index::LocalRootsQuery
 +            crate::symbol_index::LibraryRootsQuery
 +
 +            // LineIndexDatabase
 +            crate::LineIndexQuery
 +
 +            // InternDatabase
 +            hir::db::InternFunctionQuery
 +            hir::db::InternStructQuery
 +            hir::db::InternUnionQuery
 +            hir::db::InternEnumQuery
 +            hir::db::InternConstQuery
 +            hir::db::InternStaticQuery
 +            hir::db::InternTraitQuery
 +            hir::db::InternTypeAliasQuery
 +            hir::db::InternImplQuery
 +        ];
 +
 +        acc.sort_by_key(|it| std::cmp::Reverse(it.1));
 +        acc
 +    }
 +}
index 517fe3f246d08ecfb3ee8dd59401abe1a0175f62,0000000000000000000000000000000000000000..49b81265ea5be22649f65103a517d583390f27a2
mode 100644,000000..100644
--- /dev/null
@@@ -1,540 -1,0 +1,540 @@@
-     /// `Definition`. Note that some definitions, like buitin types, can't be
 +//! Rename infrastructure for rust-analyzer. It is used primarily for the
 +//! literal "rename" in the ide (look for tests there), but it is also available
 +//! as a general-purpose service. For example, it is used by the fix for the
 +//! "incorrect case" diagnostic.
 +//!
 +//! It leverages the [`crate::search`] functionality to find what needs to be
 +//! renamed. The actual renames are tricky -- field shorthands need special
 +//! attention, and, when renaming modules, you also want to rename files on the
 +//! file system.
 +//!
 +//! Another can of worms are macros:
 +//!
 +//! ```ignore
 +//! macro_rules! m { () => { fn f() {} } }
 +//! m!();
 +//! fn main() {
 +//!     f() // <- rename me
 +//! }
 +//! ```
 +//!
 +//! The correct behavior in such cases is probably to show a dialog to the user.
 +//! Our current behavior is ¯\_(ツ)_/¯.
 +use std::fmt;
 +
 +use base_db::{AnchoredPathBuf, FileId, FileRange};
 +use either::Either;
 +use hir::{FieldSource, HasSource, InFile, ModuleSource, Semantics};
 +use stdx::never;
 +use syntax::{
 +    ast::{self, HasName},
 +    AstNode, SyntaxKind, TextRange, T,
 +};
 +use text_edit::{TextEdit, TextEditBuilder};
 +
 +use crate::{
 +    defs::Definition,
 +    search::FileReference,
 +    source_change::{FileSystemEdit, SourceChange},
 +    syntax_helpers::node_ext::expr_as_name_ref,
 +    traits::convert_to_def_in_trait,
 +    RootDatabase,
 +};
 +
 +pub type Result<T, E = RenameError> = std::result::Result<T, E>;
 +
 +#[derive(Debug)]
 +pub struct RenameError(pub String);
 +
 +impl fmt::Display for RenameError {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        fmt::Display::fmt(&self.0, f)
 +    }
 +}
 +
 +#[macro_export]
 +macro_rules! _format_err {
 +    ($fmt:expr) => { RenameError(format!($fmt)) };
 +    ($fmt:expr, $($arg:tt)+) => { RenameError(format!($fmt, $($arg)+)) }
 +}
 +pub use _format_err as format_err;
 +
 +#[macro_export]
 +macro_rules! _bail {
 +    ($($tokens:tt)*) => { return Err(format_err!($($tokens)*)) }
 +}
 +pub use _bail as bail;
 +
 +impl Definition {
 +    pub fn rename(
 +        &self,
 +        sema: &Semantics<'_, RootDatabase>,
 +        new_name: &str,
 +    ) -> Result<SourceChange> {
 +        match *self {
 +            Definition::Module(module) => rename_mod(sema, module, new_name),
 +            Definition::BuiltinType(_) => {
 +                bail!("Cannot rename builtin type")
 +            }
 +            Definition::SelfType(_) => bail!("Cannot rename `Self`"),
 +            def => rename_reference(sema, def, new_name),
 +        }
 +    }
 +
 +    /// Textual range of the identifier which will change when renaming this
++    /// `Definition`. Note that some definitions, like builtin types, can't be
 +    /// renamed.
 +    pub fn range_for_rename(self, sema: &Semantics<'_, RootDatabase>) -> Option<FileRange> {
 +        let res = match self {
 +            Definition::Macro(mac) => {
 +                let src = mac.source(sema.db)?;
 +                let name = match &src.value {
 +                    Either::Left(it) => it.name()?,
 +                    Either::Right(it) => it.name()?,
 +                };
 +                src.with_value(name.syntax()).original_file_range_opt(sema.db)
 +            }
 +            Definition::Field(field) => {
 +                let src = field.source(sema.db)?;
 +                match &src.value {
 +                    FieldSource::Named(record_field) => {
 +                        let name = record_field.name()?;
 +                        src.with_value(name.syntax()).original_file_range_opt(sema.db)
 +                    }
 +                    FieldSource::Pos(_) => None,
 +                }
 +            }
 +            Definition::Module(module) => {
 +                let src = module.declaration_source(sema.db)?;
 +                let name = src.value.name()?;
 +                src.with_value(name.syntax()).original_file_range_opt(sema.db)
 +            }
 +            Definition::Function(it) => name_range(it, sema),
 +            Definition::Adt(adt) => match adt {
 +                hir::Adt::Struct(it) => name_range(it, sema),
 +                hir::Adt::Union(it) => name_range(it, sema),
 +                hir::Adt::Enum(it) => name_range(it, sema),
 +            },
 +            Definition::Variant(it) => name_range(it, sema),
 +            Definition::Const(it) => name_range(it, sema),
 +            Definition::Static(it) => name_range(it, sema),
 +            Definition::Trait(it) => name_range(it, sema),
 +            Definition::TypeAlias(it) => name_range(it, sema),
 +            Definition::Local(local) => {
 +                let src = local.source(sema.db);
 +                let name = match &src.value {
 +                    Either::Left(bind_pat) => bind_pat.name()?,
 +                    Either::Right(_) => return None,
 +                };
 +                src.with_value(name.syntax()).original_file_range_opt(sema.db)
 +            }
 +            Definition::GenericParam(generic_param) => match generic_param {
 +                hir::GenericParam::LifetimeParam(lifetime_param) => {
 +                    let src = lifetime_param.source(sema.db)?;
 +                    src.with_value(src.value.lifetime()?.syntax()).original_file_range_opt(sema.db)
 +                }
 +                _ => {
 +                    let x = match generic_param {
 +                        hir::GenericParam::TypeParam(it) => it.merge(),
 +                        hir::GenericParam::ConstParam(it) => it.merge(),
 +                        hir::GenericParam::LifetimeParam(_) => return None,
 +                    };
 +                    let src = x.source(sema.db)?;
 +                    let name = match &src.value {
 +                        Either::Left(x) => x.name()?,
 +                        Either::Right(_) => return None,
 +                    };
 +                    src.with_value(name.syntax()).original_file_range_opt(sema.db)
 +                }
 +            },
 +            Definition::Label(label) => {
 +                let src = label.source(sema.db);
 +                let lifetime = src.value.lifetime()?;
 +                src.with_value(lifetime.syntax()).original_file_range_opt(sema.db)
 +            }
 +            Definition::BuiltinType(_) => return None,
 +            Definition::SelfType(_) => return None,
 +            Definition::BuiltinAttr(_) => return None,
 +            Definition::ToolModule(_) => return None,
 +            // FIXME: This should be doable in theory
 +            Definition::DeriveHelper(_) => return None,
 +        };
 +        return res;
 +
 +        fn name_range<D>(def: D, sema: &Semantics<'_, RootDatabase>) -> Option<FileRange>
 +        where
 +            D: HasSource,
 +            D::Ast: ast::HasName,
 +        {
 +            let src = def.source(sema.db)?;
 +            let name = src.value.name()?;
 +            src.with_value(name.syntax()).original_file_range_opt(sema.db)
 +        }
 +    }
 +}
 +
 +fn rename_mod(
 +    sema: &Semantics<'_, RootDatabase>,
 +    module: hir::Module,
 +    new_name: &str,
 +) -> Result<SourceChange> {
 +    if IdentifierKind::classify(new_name)? != IdentifierKind::Ident {
 +        bail!("Invalid name `{0}`: cannot rename module to {0}", new_name);
 +    }
 +
 +    let mut source_change = SourceChange::default();
 +
 +    if module.is_crate_root(sema.db) {
 +        return Ok(source_change);
 +    }
 +
 +    let InFile { file_id, value: def_source } = module.definition_source(sema.db);
 +    if let ModuleSource::SourceFile(..) = def_source {
 +        let anchor = file_id.original_file(sema.db);
 +
 +        let is_mod_rs = module.is_mod_rs(sema.db);
 +        let has_detached_child = module.children(sema.db).any(|child| !child.is_inline(sema.db));
 +
 +        // Module exists in a named file
 +        if !is_mod_rs {
 +            let path = format!("{}.rs", new_name);
 +            let dst = AnchoredPathBuf { anchor, path };
 +            source_change.push_file_system_edit(FileSystemEdit::MoveFile { src: anchor, dst })
 +        }
 +
 +        // Rename the dir if:
 +        //  - Module source is in mod.rs
 +        //  - Module has submodules defined in separate files
 +        let dir_paths = match (is_mod_rs, has_detached_child, module.name(sema.db)) {
 +            // Go up one level since the anchor is inside the dir we're trying to rename
 +            (true, _, Some(mod_name)) => {
 +                Some((format!("../{}", mod_name), format!("../{}", new_name)))
 +            }
 +            // The anchor is on the same level as target dir
 +            (false, true, Some(mod_name)) => Some((mod_name.to_string(), new_name.to_string())),
 +            _ => None,
 +        };
 +
 +        if let Some((src, dst)) = dir_paths {
 +            let src = AnchoredPathBuf { anchor, path: src };
 +            let dst = AnchoredPathBuf { anchor, path: dst };
 +            source_change.push_file_system_edit(FileSystemEdit::MoveDir {
 +                src,
 +                src_id: anchor,
 +                dst,
 +            })
 +        }
 +    }
 +
 +    if let Some(src) = module.declaration_source(sema.db) {
 +        let file_id = src.file_id.original_file(sema.db);
 +        match src.value.name() {
 +            Some(name) => {
 +                if let Some(file_range) =
 +                    src.with_value(name.syntax()).original_file_range_opt(sema.db)
 +                {
 +                    source_change.insert_source_edit(
 +                        file_id,
 +                        TextEdit::replace(file_range.range, new_name.to_string()),
 +                    )
 +                };
 +            }
 +            _ => never!("Module source node is missing a name"),
 +        }
 +    }
 +
 +    let def = Definition::Module(module);
 +    let usages = def.usages(sema).all();
 +    let ref_edits = usages.iter().map(|(&file_id, references)| {
 +        (file_id, source_edit_from_references(references, def, new_name))
 +    });
 +    source_change.extend(ref_edits);
 +
 +    Ok(source_change)
 +}
 +
 +fn rename_reference(
 +    sema: &Semantics<'_, RootDatabase>,
 +    def: Definition,
 +    new_name: &str,
 +) -> Result<SourceChange> {
 +    let ident_kind = IdentifierKind::classify(new_name)?;
 +
 +    if matches!(
 +        def,
 +        Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_)
 +    ) {
 +        match ident_kind {
 +            IdentifierKind::Ident | IdentifierKind::Underscore => {
 +                cov_mark::hit!(rename_not_a_lifetime_ident_ref);
 +                bail!("Invalid name `{}`: not a lifetime identifier", new_name);
 +            }
 +            IdentifierKind::Lifetime => cov_mark::hit!(rename_lifetime),
 +        }
 +    } else {
 +        match ident_kind {
 +            IdentifierKind::Lifetime => {
 +                cov_mark::hit!(rename_not_an_ident_ref);
 +                bail!("Invalid name `{}`: not an identifier", new_name);
 +            }
 +            IdentifierKind::Ident => cov_mark::hit!(rename_non_local),
 +            IdentifierKind::Underscore => (),
 +        }
 +    }
 +
 +    let def = convert_to_def_in_trait(sema.db, def);
 +    let usages = def.usages(sema).all();
 +
 +    if !usages.is_empty() && ident_kind == IdentifierKind::Underscore {
 +        cov_mark::hit!(rename_underscore_multiple);
 +        bail!("Cannot rename reference to `_` as it is being referenced multiple times");
 +    }
 +    let mut source_change = SourceChange::default();
 +    source_change.extend(usages.iter().map(|(&file_id, references)| {
 +        (file_id, source_edit_from_references(references, def, new_name))
 +    }));
 +
 +    let mut insert_def_edit = |def| {
 +        let (file_id, edit) = source_edit_from_def(sema, def, new_name)?;
 +        source_change.insert_source_edit(file_id, edit);
 +        Ok(())
 +    };
 +    match def {
 +        Definition::Local(l) => l
 +            .associated_locals(sema.db)
 +            .iter()
 +            .try_for_each(|&local| insert_def_edit(Definition::Local(local))),
 +        def => insert_def_edit(def),
 +    }?;
 +    Ok(source_change)
 +}
 +
 +pub fn source_edit_from_references(
 +    references: &[FileReference],
 +    def: Definition,
 +    new_name: &str,
 +) -> TextEdit {
 +    let mut edit = TextEdit::builder();
 +    // macros can cause multiple refs to occur for the same text range, so keep track of what we have edited so far
 +    let mut edited_ranges = Vec::new();
 +    for &FileReference { range, ref name, .. } in references {
 +        let name_range = name.syntax().text_range();
 +        if name_range.len() != range.len() {
 +            // This usage comes from a different token kind that was downmapped to a NameLike in a macro
 +            // Renaming this will most likely break things syntax-wise
 +            continue;
 +        }
 +        let has_emitted_edit = match name {
 +            // if the ranges differ then the node is inside a macro call, we can't really attempt
 +            // to make special rewrites like shorthand syntax and such, so just rename the node in
 +            // the macro input
 +            ast::NameLike::NameRef(name_ref) if name_range == range => {
 +                source_edit_from_name_ref(&mut edit, name_ref, new_name, def)
 +            }
 +            ast::NameLike::Name(name) if name_range == range => {
 +                source_edit_from_name(&mut edit, name, new_name)
 +            }
 +            _ => false,
 +        };
 +        if !has_emitted_edit {
 +            if !edited_ranges.contains(&range.start()) {
 +                edit.replace(range, new_name.to_string());
 +                edited_ranges.push(range.start());
 +            }
 +        }
 +    }
 +
 +    edit.finish()
 +}
 +
 +fn source_edit_from_name(edit: &mut TextEditBuilder, name: &ast::Name, new_name: &str) -> bool {
 +    if ast::RecordPatField::for_field_name(name).is_some() {
 +        if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
 +            cov_mark::hit!(rename_record_pat_field_name_split);
 +            // Foo { ref mut field } -> Foo { new_name: ref mut field }
 +            //      ^ insert `new_name: `
 +
 +            // FIXME: instead of splitting the shorthand, recursively trigger a rename of the
 +            // other name https://github.com/rust-lang/rust-analyzer/issues/6547
 +            edit.insert(ident_pat.syntax().text_range().start(), format!("{}: ", new_name));
 +            return true;
 +        }
 +    }
 +
 +    false
 +}
 +
 +fn source_edit_from_name_ref(
 +    edit: &mut TextEditBuilder,
 +    name_ref: &ast::NameRef,
 +    new_name: &str,
 +    def: Definition,
 +) -> bool {
 +    if name_ref.super_token().is_some() {
 +        return true;
 +    }
 +
 +    if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) {
 +        let rcf_name_ref = record_field.name_ref();
 +        let rcf_expr = record_field.expr();
 +        match &(rcf_name_ref, rcf_expr.and_then(|it| expr_as_name_ref(&it))) {
 +            // field: init-expr, check if we can use a field init shorthand
 +            (Some(field_name), Some(init)) => {
 +                if field_name == name_ref {
 +                    if init.text() == new_name {
 +                        cov_mark::hit!(test_rename_field_put_init_shorthand);
 +                        // Foo { field: local } -> Foo { local }
 +                        //       ^^^^^^^ delete this
 +
 +                        // same names, we can use a shorthand here instead.
 +                        // we do not want to erase attributes hence this range start
 +                        let s = field_name.syntax().text_range().start();
 +                        let e = init.syntax().text_range().start();
 +                        edit.delete(TextRange::new(s, e));
 +                        return true;
 +                    }
 +                } else if init == name_ref {
 +                    if field_name.text() == new_name {
 +                        cov_mark::hit!(test_rename_local_put_init_shorthand);
 +                        // Foo { field: local } -> Foo { field }
 +                        //            ^^^^^^^ delete this
 +
 +                        // same names, we can use a shorthand here instead.
 +                        // we do not want to erase attributes hence this range start
 +                        let s = field_name.syntax().text_range().end();
 +                        let e = init.syntax().text_range().end();
 +                        edit.delete(TextRange::new(s, e));
 +                        return true;
 +                    }
 +                }
 +            }
 +            // init shorthand
 +            (None, Some(_)) if matches!(def, Definition::Field(_)) => {
 +                cov_mark::hit!(test_rename_field_in_field_shorthand);
 +                // Foo { field } -> Foo { new_name: field }
 +                //       ^ insert `new_name: `
 +                let offset = name_ref.syntax().text_range().start();
 +                edit.insert(offset, format!("{}: ", new_name));
 +                return true;
 +            }
 +            (None, Some(_)) if matches!(def, Definition::Local(_)) => {
 +                cov_mark::hit!(test_rename_local_in_field_shorthand);
 +                // Foo { field } -> Foo { field: new_name }
 +                //            ^ insert `: new_name`
 +                let offset = name_ref.syntax().text_range().end();
 +                edit.insert(offset, format!(": {}", new_name));
 +                return true;
 +            }
 +            _ => (),
 +        }
 +    } else if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) {
 +        let rcf_name_ref = record_field.name_ref();
 +        let rcf_pat = record_field.pat();
 +        match (rcf_name_ref, rcf_pat) {
 +            // field: rename
 +            (Some(field_name), Some(ast::Pat::IdentPat(pat)))
 +                if field_name == *name_ref && pat.at_token().is_none() =>
 +            {
 +                // field name is being renamed
 +                if let Some(name) = pat.name() {
 +                    if name.text() == new_name {
 +                        cov_mark::hit!(test_rename_field_put_init_shorthand_pat);
 +                        // Foo { field: ref mut local } -> Foo { ref mut field }
 +                        //       ^^^^^^^ delete this
 +                        //                      ^^^^^ replace this with `field`
 +
 +                        // same names, we can use a shorthand here instead/
 +                        // we do not want to erase attributes hence this range start
 +                        let s = field_name.syntax().text_range().start();
 +                        let e = pat.syntax().text_range().start();
 +                        edit.delete(TextRange::new(s, e));
 +                        edit.replace(name.syntax().text_range(), new_name.to_string());
 +                        return true;
 +                    }
 +                }
 +            }
 +            _ => (),
 +        }
 +    }
 +    false
 +}
 +
 +fn source_edit_from_def(
 +    sema: &Semantics<'_, RootDatabase>,
 +    def: Definition,
 +    new_name: &str,
 +) -> Result<(FileId, TextEdit)> {
 +    let FileRange { file_id, range } = def
 +        .range_for_rename(sema)
 +        .ok_or_else(|| format_err!("No identifier available to rename"))?;
 +
 +    let mut edit = TextEdit::builder();
 +    if let Definition::Local(local) = def {
 +        if let Either::Left(pat) = local.source(sema.db).value {
 +            // special cases required for renaming fields/locals in Record patterns
 +            if let Some(pat_field) = pat.syntax().parent().and_then(ast::RecordPatField::cast) {
 +                let name_range = pat.name().unwrap().syntax().text_range();
 +                if let Some(name_ref) = pat_field.name_ref() {
 +                    if new_name == name_ref.text() && pat.at_token().is_none() {
 +                        // Foo { field: ref mut local } -> Foo { ref mut field }
 +                        //       ^^^^^^ delete this
 +                        //                      ^^^^^ replace this with `field`
 +                        cov_mark::hit!(test_rename_local_put_init_shorthand_pat);
 +                        edit.delete(
 +                            name_ref
 +                                .syntax()
 +                                .text_range()
 +                                .cover_offset(pat.syntax().text_range().start()),
 +                        );
 +                        edit.replace(name_range, name_ref.text().to_string());
 +                    } else {
 +                        // Foo { field: ref mut local @ local 2} -> Foo { field: ref mut new_name @ local2 }
 +                        // Foo { field: ref mut local } -> Foo { field: ref mut new_name }
 +                        //                      ^^^^^ replace this with `new_name`
 +                        edit.replace(name_range, new_name.to_string());
 +                    }
 +                } else {
 +                    // Foo { ref mut field } -> Foo { field: ref mut new_name }
 +                    //      ^ insert `field: `
 +                    //               ^^^^^ replace this with `new_name`
 +                    edit.insert(
 +                        pat.syntax().text_range().start(),
 +                        format!("{}: ", pat_field.field_name().unwrap()),
 +                    );
 +                    edit.replace(name_range, new_name.to_string());
 +                }
 +            }
 +        }
 +    }
 +    if edit.is_empty() {
 +        edit.replace(range, new_name.to_string());
 +    }
 +    Ok((file_id, edit.finish()))
 +}
 +
 +#[derive(Copy, Clone, Debug, PartialEq)]
 +pub enum IdentifierKind {
 +    Ident,
 +    Lifetime,
 +    Underscore,
 +}
 +
 +impl IdentifierKind {
 +    pub fn classify(new_name: &str) -> Result<IdentifierKind> {
 +        match parser::LexedStr::single_token(new_name) {
 +            Some(res) => match res {
 +                (SyntaxKind::IDENT, _) => Ok(IdentifierKind::Ident),
 +                (T![_], _) => Ok(IdentifierKind::Underscore),
 +                (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => {
 +                    Ok(IdentifierKind::Lifetime)
 +                }
 +                (SyntaxKind::LIFETIME_IDENT, _) => {
 +                    bail!("Invalid name `{}`: not a lifetime identifier", new_name)
 +                }
 +                (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error),
 +                (_, None) => bail!("Invalid name `{}`: not an identifier", new_name),
 +            },
 +            None => bail!("Invalid name `{}`: not an identifier", new_name),
 +        }
 +    }
 +}
index 9eaabeec7a4e7e2669e6a0d5540a3896baede122,0000000000000000000000000000000000000000..2f4aa113170a6f6865a3b6e560db8aa2727cfcce
mode 100644,000000..100644
--- /dev/null
@@@ -1,785 -1,0 +1,787 @@@
-                 self.def.name(sema.db).or_else(self_kw_refs).map(|it| it.to_smol_str())
 +//! Implementation of find-usages functionality.
 +//!
 +//! It is based on the standard ide trick: first, we run a fast text search to
 +//! get a super-set of matches. Then, we we confirm each match using precise
 +//! name resolution.
 +
 +use std::{mem, sync::Arc};
 +
 +use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
 +use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility};
 +use once_cell::unsync::Lazy;
 +use rustc_hash::FxHashMap;
 +use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
 +
 +use crate::{
 +    defs::{Definition, NameClass, NameRefClass},
 +    traits::{as_trait_assoc_def, convert_to_def_in_trait},
 +    RootDatabase,
 +};
 +
 +#[derive(Debug, Default, Clone)]
 +pub struct UsageSearchResult {
 +    pub references: FxHashMap<FileId, Vec<FileReference>>,
 +}
 +
 +impl UsageSearchResult {
 +    pub fn is_empty(&self) -> bool {
 +        self.references.is_empty()
 +    }
 +
 +    pub fn len(&self) -> usize {
 +        self.references.len()
 +    }
 +
 +    pub fn iter(&self) -> impl Iterator<Item = (&FileId, &[FileReference])> + '_ {
 +        self.references.iter().map(|(file_id, refs)| (file_id, &**refs))
 +    }
 +
 +    pub fn file_ranges(&self) -> impl Iterator<Item = FileRange> + '_ {
 +        self.references.iter().flat_map(|(&file_id, refs)| {
 +            refs.iter().map(move |&FileReference { range, .. }| FileRange { file_id, range })
 +        })
 +    }
 +}
 +
 +impl IntoIterator for UsageSearchResult {
 +    type Item = (FileId, Vec<FileReference>);
 +    type IntoIter = <FxHashMap<FileId, Vec<FileReference>> as IntoIterator>::IntoIter;
 +
 +    fn into_iter(self) -> Self::IntoIter {
 +        self.references.into_iter()
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +pub struct FileReference {
 +    /// The range of the reference in the original file
 +    pub range: TextRange,
 +    /// The node of the reference in the (macro-)file
 +    pub name: ast::NameLike,
 +    pub category: Option<ReferenceCategory>,
 +}
 +
 +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 +pub enum ReferenceCategory {
 +    // FIXME: Add this variant and delete the `retain_adt_literal_usages` function.
 +    // Create
 +    Write,
 +    Read,
 +    // FIXME: Some day should be able to search in doc comments. Would probably
 +    // need to switch from enum to bitflags then?
 +    // DocComment
 +}
 +
 +/// Generally, `search_scope` returns files that might contain references for the element.
 +/// For `pub(crate)` things it's a crate, for `pub` things it's a crate and dependant crates.
 +/// In some cases, the location of the references is known to within a `TextRange`,
 +/// e.g. for things like local variables.
 +#[derive(Clone, Debug)]
 +pub struct SearchScope {
 +    entries: FxHashMap<FileId, Option<TextRange>>,
 +}
 +
 +impl SearchScope {
 +    fn new(entries: FxHashMap<FileId, Option<TextRange>>) -> SearchScope {
 +        SearchScope { entries }
 +    }
 +
 +    /// Build a search scope spanning the entire crate graph of files.
 +    fn crate_graph(db: &RootDatabase) -> SearchScope {
 +        let mut entries = FxHashMap::default();
 +
 +        let graph = db.crate_graph();
 +        for krate in graph.iter() {
 +            let root_file = graph[krate].root_file_id;
 +            let source_root_id = db.file_source_root(root_file);
 +            let source_root = db.source_root(source_root_id);
 +            entries.extend(source_root.iter().map(|id| (id, None)));
 +        }
 +        SearchScope { entries }
 +    }
 +
 +    /// Build a search scope spanning all the reverse dependencies of the given crate.
 +    fn reverse_dependencies(db: &RootDatabase, of: hir::Crate) -> SearchScope {
 +        let mut entries = FxHashMap::default();
 +        for rev_dep in of.transitive_reverse_dependencies(db) {
 +            let root_file = rev_dep.root_file(db);
 +            let source_root_id = db.file_source_root(root_file);
 +            let source_root = db.source_root(source_root_id);
 +            entries.extend(source_root.iter().map(|id| (id, None)));
 +        }
 +        SearchScope { entries }
 +    }
 +
 +    /// Build a search scope spanning the given crate.
 +    fn krate(db: &RootDatabase, of: hir::Crate) -> SearchScope {
 +        let root_file = of.root_file(db);
 +        let source_root_id = db.file_source_root(root_file);
 +        let source_root = db.source_root(source_root_id);
 +        SearchScope {
 +            entries: source_root.iter().map(|id| (id, None)).collect::<FxHashMap<_, _>>(),
 +        }
 +    }
 +
 +    /// Build a search scope spanning the given module and all its submodules.
 +    fn module_and_children(db: &RootDatabase, module: hir::Module) -> SearchScope {
 +        let mut entries = FxHashMap::default();
 +
 +        let (file_id, range) = {
 +            let InFile { file_id, value } = module.definition_source(db);
 +            if let Some((file_id, call_source)) = file_id.original_call_node(db) {
 +                (file_id, Some(call_source.text_range()))
 +            } else {
 +                (
 +                    file_id.original_file(db),
 +                    match value {
 +                        ModuleSource::SourceFile(_) => None,
 +                        ModuleSource::Module(it) => Some(it.syntax().text_range()),
 +                        ModuleSource::BlockExpr(it) => Some(it.syntax().text_range()),
 +                    },
 +                )
 +            }
 +        };
 +        entries.insert(file_id, range);
 +
 +        let mut to_visit: Vec<_> = module.children(db).collect();
 +        while let Some(module) = to_visit.pop() {
 +            if let InFile { file_id, value: ModuleSource::SourceFile(_) } =
 +                module.definition_source(db)
 +            {
 +                entries.insert(file_id.original_file(db), None);
 +            }
 +            to_visit.extend(module.children(db));
 +        }
 +        SearchScope { entries }
 +    }
 +
 +    /// Build an empty search scope.
 +    pub fn empty() -> SearchScope {
 +        SearchScope::new(FxHashMap::default())
 +    }
 +
 +    /// Build a empty search scope spanning the given file.
 +    pub fn single_file(file: FileId) -> SearchScope {
 +        SearchScope::new(std::iter::once((file, None)).collect())
 +    }
 +
 +    /// Build a empty search scope spanning the text range of the given file.
 +    pub fn file_range(range: FileRange) -> SearchScope {
 +        SearchScope::new(std::iter::once((range.file_id, Some(range.range))).collect())
 +    }
 +
 +    /// Build a empty search scope spanning the given files.
 +    pub fn files(files: &[FileId]) -> SearchScope {
 +        SearchScope::new(files.iter().map(|f| (*f, None)).collect())
 +    }
 +
 +    pub fn intersection(&self, other: &SearchScope) -> SearchScope {
 +        let (mut small, mut large) = (&self.entries, &other.entries);
 +        if small.len() > large.len() {
 +            mem::swap(&mut small, &mut large)
 +        }
 +
 +        let intersect_ranges =
 +            |r1: Option<TextRange>, r2: Option<TextRange>| -> Option<Option<TextRange>> {
 +                match (r1, r2) {
 +                    (None, r) | (r, None) => Some(r),
 +                    (Some(r1), Some(r2)) => r1.intersect(r2).map(Some),
 +                }
 +            };
 +        let res = small
 +            .iter()
 +            .filter_map(|(&file_id, &r1)| {
 +                let &r2 = large.get(&file_id)?;
 +                let r = intersect_ranges(r1, r2)?;
 +                Some((file_id, r))
 +            })
 +            .collect();
 +
 +        SearchScope::new(res)
 +    }
 +}
 +
 +impl IntoIterator for SearchScope {
 +    type Item = (FileId, Option<TextRange>);
 +    type IntoIter = std::collections::hash_map::IntoIter<FileId, Option<TextRange>>;
 +
 +    fn into_iter(self) -> Self::IntoIter {
 +        self.entries.into_iter()
 +    }
 +}
 +
 +impl Definition {
 +    fn search_scope(&self, db: &RootDatabase) -> SearchScope {
 +        let _p = profile::span("search_scope");
 +
 +        if let Definition::BuiltinType(_) = self {
 +            return SearchScope::crate_graph(db);
 +        }
 +
 +        // def is crate root
 +        // FIXME: We don't do searches for crates currently, as a crate does not actually have a single name
 +        if let &Definition::Module(module) = self {
 +            if module.is_crate_root(db) {
 +                return SearchScope::reverse_dependencies(db, module.krate());
 +            }
 +        }
 +
 +        let module = match self.module(db) {
 +            Some(it) => it,
 +            None => return SearchScope::empty(),
 +        };
 +        let InFile { file_id, value: module_source } = module.definition_source(db);
 +        let file_id = file_id.original_file(db);
 +
 +        if let Definition::Local(var) = self {
 +            let def = match var.parent(db) {
 +                DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()),
 +                DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()),
 +                DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()),
 +            };
 +            return match def {
 +                Some(def) => SearchScope::file_range(def.as_ref().original_file_range(db)),
 +                None => SearchScope::single_file(file_id),
 +            };
 +        }
 +
 +        if let Definition::SelfType(impl_) = self {
 +            return match impl_.source(db).map(|src| src.syntax().cloned()) {
 +                Some(def) => SearchScope::file_range(def.as_ref().original_file_range(db)),
 +                None => SearchScope::single_file(file_id),
 +            };
 +        }
 +
 +        if let Definition::GenericParam(hir::GenericParam::LifetimeParam(param)) = self {
 +            let def = match param.parent(db) {
 +                hir::GenericDef::Function(it) => it.source(db).map(|src| src.syntax().cloned()),
 +                hir::GenericDef::Adt(it) => it.source(db).map(|src| src.syntax().cloned()),
 +                hir::GenericDef::Trait(it) => it.source(db).map(|src| src.syntax().cloned()),
 +                hir::GenericDef::TypeAlias(it) => it.source(db).map(|src| src.syntax().cloned()),
 +                hir::GenericDef::Impl(it) => it.source(db).map(|src| src.syntax().cloned()),
 +                hir::GenericDef::Variant(it) => it.source(db).map(|src| src.syntax().cloned()),
 +                hir::GenericDef::Const(it) => it.source(db).map(|src| src.syntax().cloned()),
 +            };
 +            return match def {
 +                Some(def) => SearchScope::file_range(def.as_ref().original_file_range(db)),
 +                None => SearchScope::single_file(file_id),
 +            };
 +        }
 +
 +        if let Definition::Macro(macro_def) = self {
 +            return match macro_def.kind(db) {
 +                hir::MacroKind::Declarative => {
 +                    if macro_def.attrs(db).by_key("macro_export").exists() {
 +                        SearchScope::reverse_dependencies(db, module.krate())
 +                    } else {
 +                        SearchScope::krate(db, module.krate())
 +                    }
 +                }
 +                hir::MacroKind::BuiltIn => SearchScope::crate_graph(db),
 +                hir::MacroKind::Derive | hir::MacroKind::Attr | hir::MacroKind::ProcMacro => {
 +                    SearchScope::reverse_dependencies(db, module.krate())
 +                }
 +            };
 +        }
 +
 +        if let Definition::DeriveHelper(_) = self {
 +            return SearchScope::reverse_dependencies(db, module.krate());
 +        }
 +
 +        let vis = self.visibility(db);
 +        if let Some(Visibility::Public) = vis {
 +            return SearchScope::reverse_dependencies(db, module.krate());
 +        }
 +        if let Some(Visibility::Module(module)) = vis {
 +            return SearchScope::module_and_children(db, module.into());
 +        }
 +
 +        let range = match module_source {
 +            ModuleSource::Module(m) => Some(m.syntax().text_range()),
 +            ModuleSource::BlockExpr(b) => Some(b.syntax().text_range()),
 +            ModuleSource::SourceFile(_) => None,
 +        };
 +        match range {
 +            Some(range) => SearchScope::file_range(FileRange { file_id, range }),
 +            None => SearchScope::single_file(file_id),
 +        }
 +    }
 +
 +    pub fn usages<'a>(self, sema: &'a Semantics<'_, RootDatabase>) -> FindUsages<'a> {
 +        FindUsages {
 +            local_repr: match self {
 +                Definition::Local(local) => Some(local.representative(sema.db)),
 +                _ => None,
 +            },
 +            def: self,
 +            trait_assoc_def: as_trait_assoc_def(sema.db, self),
 +            sema,
 +            scope: None,
 +            include_self_kw_refs: None,
 +            search_self_mod: false,
 +        }
 +    }
 +}
 +
 +#[derive(Clone)]
 +pub struct FindUsages<'a> {
 +    def: Definition,
 +    /// If def is an assoc item from a trait or trait impl, this is the corresponding item of the trait definition
 +    trait_assoc_def: Option<Definition>,
 +    sema: &'a Semantics<'a, RootDatabase>,
 +    scope: Option<SearchScope>,
 +    include_self_kw_refs: Option<hir::Type>,
 +    local_repr: Option<hir::Local>,
 +    search_self_mod: bool,
 +}
 +
 +impl<'a> FindUsages<'a> {
 +    /// Enable searching for `Self` when the definition is a type or `self` for modules.
 +    pub fn include_self_refs(mut self) -> FindUsages<'a> {
 +        self.include_self_kw_refs = def_to_ty(self.sema, &self.def);
 +        self.search_self_mod = true;
 +        self
 +    }
 +
 +    /// Limit the search to a given [`SearchScope`].
 +    pub fn in_scope(self, scope: SearchScope) -> FindUsages<'a> {
 +        self.set_scope(Some(scope))
 +    }
 +
 +    /// Limit the search to a given [`SearchScope`].
 +    pub fn set_scope(mut self, scope: Option<SearchScope>) -> FindUsages<'a> {
 +        assert!(self.scope.is_none());
 +        self.scope = scope;
 +        self
 +    }
 +
 +    pub fn at_least_one(&self) -> bool {
 +        let mut found = false;
 +        self.search(&mut |_, _| {
 +            found = true;
 +            true
 +        });
 +        found
 +    }
 +
 +    pub fn all(self) -> UsageSearchResult {
 +        let mut res = UsageSearchResult::default();
 +        self.search(&mut |file_id, reference| {
 +            res.references.entry(file_id).or_default().push(reference);
 +            false
 +        });
 +        res
 +    }
 +
 +    fn search(&self, sink: &mut dyn FnMut(FileId, FileReference) -> bool) {
 +        let _p = profile::span("FindUsages:search");
 +        let sema = self.sema;
 +
 +        let search_scope = {
 +            let base = self.trait_assoc_def.unwrap_or(self.def).search_scope(sema.db);
 +            match &self.scope {
 +                None => base,
 +                Some(scope) => base.intersection(scope),
 +            }
 +        };
 +
 +        let name = match self.def {
 +            // special case crate modules as these do not have a proper name
 +            Definition::Module(module) if module.is_crate_root(self.sema.db) => {
 +                // FIXME: This assumes the crate name is always equal to its display name when it really isn't
 +                module
 +                    .krate()
 +                    .display_name(self.sema.db)
 +                    .map(|crate_name| crate_name.crate_name().as_smol_str().clone())
 +            }
 +            _ => {
 +                let self_kw_refs = || {
 +                    self.include_self_kw_refs.as_ref().and_then(|ty| {
 +                        ty.as_adt()
 +                            .map(|adt| adt.name(self.sema.db))
 +                            .or_else(|| ty.as_builtin().map(|builtin| builtin.name()))
 +                    })
 +                };
++                // We need to unescape the name in case it is written without "r#" in earlier
++                // editions of Rust where it isn't a keyword.
++                self.def.name(sema.db).or_else(self_kw_refs).map(|it| it.unescaped().to_smol_str())
 +            }
 +        };
 +        let name = match &name {
 +            Some(s) => s.as_str(),
 +            None => return,
 +        };
 +
 +        // these can't be closures because rust infers the lifetimes wrong ...
 +        fn match_indices<'a>(
 +            text: &'a str,
 +            name: &'a str,
 +            search_range: TextRange,
 +        ) -> impl Iterator<Item = TextSize> + 'a {
 +            text.match_indices(name).filter_map(move |(idx, _)| {
 +                let offset: TextSize = idx.try_into().unwrap();
 +                if !search_range.contains_inclusive(offset) {
 +                    return None;
 +                }
 +                Some(offset)
 +            })
 +        }
 +
 +        fn scope_files<'a>(
 +            sema: &'a Semantics<'_, RootDatabase>,
 +            scope: &'a SearchScope,
 +        ) -> impl Iterator<Item = (Arc<String>, FileId, TextRange)> + 'a {
 +            scope.entries.iter().map(|(&file_id, &search_range)| {
 +                let text = sema.db.file_text(file_id);
 +                let search_range =
 +                    search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
 +
 +                (text, file_id, search_range)
 +            })
 +        }
 +
 +        // FIXME: There should be optimization potential here
 +        // Currently we try to descend everything we find which
 +        // means we call `Semantics::descend_into_macros` on
 +        // every textual hit. That function is notoriously
 +        // expensive even for things that do not get down mapped
 +        // into macros.
 +        for (text, file_id, search_range) in scope_files(sema, &search_scope) {
 +            let tree = Lazy::new(move || sema.parse(file_id).syntax().clone());
 +
 +            // Search for occurrences of the items name
 +            for offset in match_indices(&text, name, search_range) {
 +                for name in sema.find_nodes_at_offset_with_descend(&tree, offset) {
 +                    if match name {
 +                        ast::NameLike::NameRef(name_ref) => self.found_name_ref(&name_ref, sink),
 +                        ast::NameLike::Name(name) => self.found_name(&name, sink),
 +                        ast::NameLike::Lifetime(lifetime) => self.found_lifetime(&lifetime, sink),
 +                    } {
 +                        return;
 +                    }
 +                }
 +            }
 +            // Search for occurrences of the `Self` referring to our type
 +            if let Some(self_ty) = &self.include_self_kw_refs {
 +                for offset in match_indices(&text, "Self", search_range) {
 +                    for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
 +                        if self.found_self_ty_name_ref(self_ty, &name_ref, sink) {
 +                            return;
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +
 +        // Search for `super` and `crate` resolving to our module
 +        match self.def {
 +            Definition::Module(module) => {
 +                let scope = search_scope
 +                    .intersection(&SearchScope::module_and_children(self.sema.db, module));
 +
 +                let is_crate_root = module.is_crate_root(self.sema.db);
 +
 +                for (text, file_id, search_range) in scope_files(sema, &scope) {
 +                    let tree = Lazy::new(move || sema.parse(file_id).syntax().clone());
 +
 +                    for offset in match_indices(&text, "super", search_range) {
 +                        for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
 +                            if self.found_name_ref(&name_ref, sink) {
 +                                return;
 +                            }
 +                        }
 +                    }
 +                    if is_crate_root {
 +                        for offset in match_indices(&text, "crate", search_range) {
 +                            for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
 +                                if self.found_name_ref(&name_ref, sink) {
 +                                    return;
 +                                }
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +            _ => (),
 +        }
 +
 +        // search for module `self` references in our module's definition source
 +        match self.def {
 +            Definition::Module(module) if self.search_self_mod => {
 +                let src = module.definition_source(sema.db);
 +                let file_id = src.file_id.original_file(sema.db);
 +                let (file_id, search_range) = match src.value {
 +                    ModuleSource::Module(m) => (file_id, Some(m.syntax().text_range())),
 +                    ModuleSource::BlockExpr(b) => (file_id, Some(b.syntax().text_range())),
 +                    ModuleSource::SourceFile(_) => (file_id, None),
 +                };
 +
 +                let search_range = if let Some(&range) = search_scope.entries.get(&file_id) {
 +                    match (range, search_range) {
 +                        (None, range) | (range, None) => range,
 +                        (Some(range), Some(search_range)) => match range.intersect(search_range) {
 +                            Some(range) => Some(range),
 +                            None => return,
 +                        },
 +                    }
 +                } else {
 +                    return;
 +                };
 +
 +                let text = sema.db.file_text(file_id);
 +                let search_range =
 +                    search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
 +
 +                let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
 +
 +                for offset in match_indices(&text, "self", search_range) {
 +                    for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
 +                        if self.found_self_module_name_ref(&name_ref, sink) {
 +                            return;
 +                        }
 +                    }
 +                }
 +            }
 +            _ => {}
 +        }
 +    }
 +
 +    fn found_self_ty_name_ref(
 +        &self,
 +        self_ty: &hir::Type,
 +        name_ref: &ast::NameRef,
 +        sink: &mut dyn FnMut(FileId, FileReference) -> bool,
 +    ) -> bool {
 +        match NameRefClass::classify(self.sema, name_ref) {
 +            Some(NameRefClass::Definition(Definition::SelfType(impl_)))
 +                if impl_.self_ty(self.sema.db) == *self_ty =>
 +            {
 +                let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::NameRef(name_ref.clone()),
 +                    category: None,
 +                };
 +                sink(file_id, reference)
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    fn found_self_module_name_ref(
 +        &self,
 +        name_ref: &ast::NameRef,
 +        sink: &mut dyn FnMut(FileId, FileReference) -> bool,
 +    ) -> bool {
 +        match NameRefClass::classify(self.sema, name_ref) {
 +            Some(NameRefClass::Definition(def @ Definition::Module(_))) if def == self.def => {
 +                let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::NameRef(name_ref.clone()),
 +                    category: None,
 +                };
 +                sink(file_id, reference)
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    fn found_lifetime(
 +        &self,
 +        lifetime: &ast::Lifetime,
 +        sink: &mut dyn FnMut(FileId, FileReference) -> bool,
 +    ) -> bool {
 +        match NameRefClass::classify_lifetime(self.sema, lifetime) {
 +            Some(NameRefClass::Definition(def)) if def == self.def => {
 +                let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::Lifetime(lifetime.clone()),
 +                    category: None,
 +                };
 +                sink(file_id, reference)
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    fn found_name_ref(
 +        &self,
 +        name_ref: &ast::NameRef,
 +        sink: &mut dyn FnMut(FileId, FileReference) -> bool,
 +    ) -> bool {
 +        match NameRefClass::classify(self.sema, name_ref) {
 +            Some(NameRefClass::Definition(def @ Definition::Local(local)))
 +                if matches!(
 +                    self.local_repr, Some(repr) if repr == local.representative(self.sema.db)
 +                ) =>
 +            {
 +                let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::NameRef(name_ref.clone()),
 +                    category: ReferenceCategory::new(&def, name_ref),
 +                };
 +                sink(file_id, reference)
 +            }
 +            Some(NameRefClass::Definition(def))
 +                if match self.trait_assoc_def {
 +                    Some(trait_assoc_def) => {
 +                        // we have a trait assoc item, so force resolve all assoc items to their trait version
 +                        convert_to_def_in_trait(self.sema.db, def) == trait_assoc_def
 +                    }
 +                    None => self.def == def,
 +                } =>
 +            {
 +                let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::NameRef(name_ref.clone()),
 +                    category: ReferenceCategory::new(&def, name_ref),
 +                };
 +                sink(file_id, reference)
 +            }
 +            Some(NameRefClass::Definition(def)) if self.include_self_kw_refs.is_some() => {
 +                if self.include_self_kw_refs == def_to_ty(self.sema, &def) {
 +                    let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
 +                    let reference = FileReference {
 +                        range,
 +                        name: ast::NameLike::NameRef(name_ref.clone()),
 +                        category: ReferenceCategory::new(&def, name_ref),
 +                    };
 +                    sink(file_id, reference)
 +                } else {
 +                    false
 +                }
 +            }
 +            Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => {
 +                let field = Definition::Field(field);
 +                let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
 +                let access = match self.def {
 +                    Definition::Field(_) if field == self.def => {
 +                        ReferenceCategory::new(&field, name_ref)
 +                    }
 +                    Definition::Local(_) if matches!(self.local_repr, Some(repr) if repr == local.representative(self.sema.db)) => {
 +                        ReferenceCategory::new(&Definition::Local(local), name_ref)
 +                    }
 +                    _ => return false,
 +                };
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::NameRef(name_ref.clone()),
 +                    category: access,
 +                };
 +                sink(file_id, reference)
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    fn found_name(
 +        &self,
 +        name: &ast::Name,
 +        sink: &mut dyn FnMut(FileId, FileReference) -> bool,
 +    ) -> bool {
 +        match NameClass::classify(self.sema, name) {
 +            Some(NameClass::PatFieldShorthand { local_def: _, field_ref })
 +                if matches!(
 +                    self.def, Definition::Field(_) if Definition::Field(field_ref) == self.def
 +                ) =>
 +            {
 +                let FileRange { file_id, range } = self.sema.original_range(name.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::Name(name.clone()),
 +                    // FIXME: mutable patterns should have `Write` access
 +                    category: Some(ReferenceCategory::Read),
 +                };
 +                sink(file_id, reference)
 +            }
 +            Some(NameClass::ConstReference(def)) if self.def == def => {
 +                let FileRange { file_id, range } = self.sema.original_range(name.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::Name(name.clone()),
 +                    category: None,
 +                };
 +                sink(file_id, reference)
 +            }
 +            Some(NameClass::Definition(def @ Definition::Local(local))) if def != self.def => {
 +                if matches!(
 +                    self.local_repr,
 +                    Some(repr) if local.representative(self.sema.db) == repr
 +                ) {
 +                    let FileRange { file_id, range } = self.sema.original_range(name.syntax());
 +                    let reference = FileReference {
 +                        range,
 +                        name: ast::NameLike::Name(name.clone()),
 +                        category: None,
 +                    };
 +                    return sink(file_id, reference);
 +                }
 +                false
 +            }
 +            Some(NameClass::Definition(def)) if def != self.def => {
 +                // if the def we are looking for is a trait (impl) assoc item, we'll have to resolve the items to trait definition assoc item
 +                if !matches!(
 +                    self.trait_assoc_def,
 +                    Some(trait_assoc_def)
 +                        if convert_to_def_in_trait(self.sema.db, def) == trait_assoc_def
 +                ) {
 +                    return false;
 +                }
 +                let FileRange { file_id, range } = self.sema.original_range(name.syntax());
 +                let reference = FileReference {
 +                    range,
 +                    name: ast::NameLike::Name(name.clone()),
 +                    category: None,
 +                };
 +                sink(file_id, reference)
 +            }
 +            _ => false,
 +        }
 +    }
 +}
 +
 +fn def_to_ty(sema: &Semantics<'_, RootDatabase>, def: &Definition) -> Option<hir::Type> {
 +    match def {
 +        Definition::Adt(adt) => Some(adt.ty(sema.db)),
 +        Definition::TypeAlias(it) => Some(it.ty(sema.db)),
 +        Definition::BuiltinType(it) => Some(it.ty(sema.db)),
 +        Definition::SelfType(it) => Some(it.self_ty(sema.db)),
 +        _ => None,
 +    }
 +}
 +
 +impl ReferenceCategory {
 +    fn new(def: &Definition, r: &ast::NameRef) -> Option<ReferenceCategory> {
 +        // Only Locals and Fields have accesses for now.
 +        if !matches!(def, Definition::Local(_) | Definition::Field(_)) {
 +            return None;
 +        }
 +
 +        let mode = r.syntax().ancestors().find_map(|node| {
 +        match_ast! {
 +            match node {
 +                ast::BinExpr(expr) => {
 +                    if matches!(expr.op_kind()?, ast::BinaryOp::Assignment { .. }) {
 +                        // If the variable or field ends on the LHS's end then it's a Write (covers fields and locals).
 +                        // FIXME: This is not terribly accurate.
 +                        if let Some(lhs) = expr.lhs() {
 +                            if lhs.syntax().text_range().end() == r.syntax().text_range().end() {
 +                                return Some(ReferenceCategory::Write);
 +                            }
 +                        }
 +                    }
 +                    Some(ReferenceCategory::Read)
 +                },
 +                _ => None
 +            }
 +        }
 +    });
 +
 +        // Default Locals and Fields to read
 +        mode.or(Some(ReferenceCategory::Read))
 +    }
 +}
index 9e66fbfb7522439995e301b9c1b638b720a3f564,0000000000000000000000000000000000000000..5fcaf405b14b94887cc6e81c1dd05db061eac143
mode 100644,000000..100644
--- /dev/null
@@@ -1,1012 -1,0 +1,1012 @@@
-     // ExprValidator::validate_match(..) checks types of top level patterns incorrecly.
 +use hir::InFile;
 +
 +use crate::{Diagnostic, DiagnosticsContext};
 +
 +// Diagnostic: missing-match-arm
 +//
 +// This diagnostic is triggered if `match` block is missing one or more match arms.
 +pub(crate) fn missing_match_arms(
 +    ctx: &DiagnosticsContext<'_>,
 +    d: &hir::MissingMatchArms,
 +) -> Diagnostic {
 +    Diagnostic::new(
 +        "missing-match-arm",
 +        format!("missing match arm: {}", d.uncovered_patterns),
 +        ctx.sema.diagnostics_display_range(InFile::new(d.file, d.match_expr.clone().into())).range,
 +    )
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::check_diagnostics;
 +
 +    fn check_diagnostics_no_bails(ra_fixture: &str) {
 +        cov_mark::check_count!(validate_match_bailed_out, 0);
 +        crate::tests::check_diagnostics(ra_fixture)
 +    }
 +
 +    #[test]
 +    fn empty_tuple() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match () { }
 +        //^^ error: missing match arm: type `()` is non-empty
 +    match (()) { }
 +        //^^^^ error: missing match arm: type `()` is non-empty
 +
 +    match () { _ => (), }
 +    match () { () => (), }
 +    match (()) { (()) => (), }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn tuple_of_two_empty_tuple() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match ((), ()) { }
 +        //^^^^^^^^ error: missing match arm: type `((), ())` is non-empty
 +
 +    match ((), ()) { ((), ()) => (), }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn boolean() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn test_main() {
 +    match false { }
 +        //^^^^^ error: missing match arm: type `bool` is non-empty
 +    match false { true => (), }
 +        //^^^^^ error: missing match arm: `false` not covered
 +    match (false, true) {}
 +        //^^^^^^^^^^^^^ error: missing match arm: type `(bool, bool)` is non-empty
 +    match (false, true) { (true, true) => (), }
 +        //^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
 +    match (false, true) {
 +        //^^^^^^^^^^^^^ error: missing match arm: `(true, true)` not covered
 +        (false, true) => (),
 +        (false, false) => (),
 +        (true, false) => (),
 +    }
 +    match (false, true) { (true, _x) => (), }
 +        //^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
 +
 +    match false { true => (), false => (), }
 +    match (false, true) {
 +        (false, _) => (),
 +        (true, false) => (),
 +        (_, true) => (),
 +    }
 +    match (false, true) {
 +        (true, true) => (),
 +        (true, false) => (),
 +        (false, true) => (),
 +        (false, false) => (),
 +    }
 +    match (false, true) {
 +        (true, _x) => (),
 +        (false, true) => (),
 +        (false, false) => (),
 +    }
 +    match (false, true, false) {
 +        (false, ..) => (),
 +        (true, ..) => (),
 +    }
 +    match (false, true, false) {
 +        (.., false) => (),
 +        (.., true) => (),
 +    }
 +    match (false, true, false) { (..) => (), }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn tuple_of_tuple_and_bools() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match (false, ((), false)) {}
 +        //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: type `(bool, ((), bool))` is non-empty
 +    match (false, ((), false)) { (true, ((), true)) => (), }
 +        //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
 +    match (false, ((), false)) { (true, _) => (), }
 +        //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
 +
 +    match (false, ((), false)) {
 +        (true, ((), true)) => (),
 +        (true, ((), false)) => (),
 +        (false, ((), true)) => (),
 +        (false, ((), false)) => (),
 +    }
 +    match (false, ((), false)) {
 +        (true, ((), true)) => (),
 +        (true, ((), false)) => (),
 +        (false, _) => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enums() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either { A, B, }
 +
 +fn main() {
 +    match Either::A { }
 +        //^^^^^^^^^ error: missing match arm: `A` and `B` not covered
 +    match Either::B { Either::A => (), }
 +        //^^^^^^^^^ error: missing match arm: `B` not covered
 +
 +    match &Either::B {
 +        //^^^^^^^^^^ error: missing match arm: `&B` not covered
 +        Either::A => (),
 +    }
 +
 +    match Either::B {
 +        Either::A => (), Either::B => (),
 +    }
 +    match &Either::B {
 +        Either::A => (), Either::B => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_containing_bool() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either { A(bool), B }
 +
 +fn main() {
 +    match Either::B { }
 +        //^^^^^^^^^ error: missing match arm: `A(_)` and `B` not covered
 +    match Either::B {
 +        //^^^^^^^^^ error: missing match arm: `A(false)` not covered
 +        Either::A(true) => (), Either::B => ()
 +    }
 +
 +    match Either::B {
 +        Either::A(true) => (),
 +        Either::A(false) => (),
 +        Either::B => (),
 +    }
 +    match Either::B {
 +        Either::B => (),
 +        _ => (),
 +    }
 +    match Either::B {
 +        Either::A(_) => (),
 +        Either::B => (),
 +    }
 +
 +}
 +        "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_different_sizes() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either { A(bool), B(bool, bool) }
 +
 +fn main() {
 +    match Either::A(false) {
 +        //^^^^^^^^^^^^^^^^ error: missing match arm: `B(true, _)` not covered
 +        Either::A(_) => (),
 +        Either::B(false, _) => (),
 +    }
 +
 +    match Either::A(false) {
 +        Either::A(_) => (),
 +        Either::B(true, _) => (),
 +        Either::B(false, _) => (),
 +    }
 +    match Either::A(false) {
 +        Either::A(true) | Either::A(false) => (),
 +        Either::B(true, _) => (),
 +        Either::B(false, _) => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn tuple_of_enum_no_diagnostic() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either { A(bool), B(bool, bool) }
 +enum Either2 { C, D }
 +
 +fn main() {
 +    match (Either::A(false), Either2::C) {
 +        (Either::A(true), _) | (Either::A(false), _) => (),
 +        (Either::B(true, _), Either2::C) => (),
 +        (Either::B(false, _), Either2::C) => (),
 +        (Either::B(_, _), Either2::D) => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn or_pattern_no_diagnostic() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either {A, B}
 +
 +fn main() {
 +    match (Either::A, Either::B) {
 +        (Either::A | Either::B, _) => (),
 +    }
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn mismatched_types() {
 +        cov_mark::check_count!(validate_match_bailed_out, 4);
 +        // Match statements with arms that don't match the
 +        // expression pattern do not fire this diagnostic.
 +        check_diagnostics(
 +            r#"
 +enum Either { A, B }
 +enum Either2 { C, D }
 +
 +fn main() {
 +    match Either::A {
 +        Either2::C => (),
 +        Either2::D => (),
 +    }
 +    match (true, false) {
 +        (true, false, true) => (),
 +        (true) => (),
 +      // ^^^^  error: expected (bool, bool), found bool
 +    }
 +    match (true, false) { (true,) => {} }
 +    match (0) { () => () }
 +    match Unresolved::Bar { Unresolved::Baz => () }
 +}
 +        "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn mismatched_types_in_or_patterns() {
 +        cov_mark::check_count!(validate_match_bailed_out, 2);
 +        check_diagnostics(
 +            r#"
 +fn main() {
 +    match false { true | () => {} }
 +    match (false,) { (true | (),) => {} }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn malformed_match_arm_tuple_enum_missing_pattern() {
 +        // We are testing to be sure we don't panic here when the match
 +        // arm `Either::B` is missing its pattern.
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either { A, B(u32) }
 +
 +fn main() {
 +    match Either::A {
 +        Either::A => (),
 +        Either::B() => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn malformed_match_arm_extra_fields() {
 +        cov_mark::check_count!(validate_match_bailed_out, 2);
 +        check_diagnostics(
 +            r#"
 +enum A { B(isize, isize), C }
 +fn main() {
 +    match A::B(1, 2) {
 +        A::B(_, _, _) => (),
 +    }
 +    match A::B(1, 2) {
 +        A::C(_) => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn expr_diverges() {
 +        cov_mark::check_count!(validate_match_bailed_out, 2);
 +        check_diagnostics(
 +            r#"
 +enum Either { A, B }
 +
 +fn main() {
 +    match loop {} {
 +        Either::A => (),
 +        Either::B => (),
 +    }
 +    match loop {} {
 +        Either::A => (),
 +    }
 +    match loop { break Foo::A } {
 +        //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `B` not covered
 +        Either::A => (),
 +    }
 +    match loop { break Foo::A } {
 +        Either::A => (),
 +        Either::B => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn expr_partially_diverges() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either<T> { A(T), B }
 +
 +fn foo() -> Either<!> { Either::B }
 +fn main() -> u32 {
 +    match foo() {
 +        Either::A(val) => val,
 +        Either::B => 0,
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_record() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either { A { foo: bool }, B }
 +
 +fn main() {
 +    let a = Either::A { foo: true };
 +    match a { }
 +        //^ error: missing match arm: `A { .. }` and `B` not covered
 +    match a { Either::A { foo: true } => () }
 +        //^ error: missing match arm: `B` not covered
 +    match a {
 +        Either::A { } => (),
 +      //^^^^^^^^^ 💡 error: missing structure fields:
 +      //        | - foo
 +        Either::B => (),
 +    }
 +    match a {
 +        //^ error: missing match arm: `B` not covered
 +        Either::A { } => (),
 +    } //^^^^^^^^^ 💡 error: missing structure fields:
 +      //        | - foo
 +
 +    match a {
 +        Either::A { foo: true } => (),
 +        Either::A { foo: false } => (),
 +        Either::B => (),
 +    }
 +    match a {
 +        Either::A { foo: _ } => (),
 +        Either::B => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_record_fields_out_of_order() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either {
 +    A { foo: bool, bar: () },
 +    B,
 +}
 +
 +fn main() {
 +    let a = Either::A { foo: true, bar: () };
 +    match a {
 +        //^ error: missing match arm: `B` not covered
 +        Either::A { bar: (), foo: false } => (),
 +        Either::A { foo: true, bar: () } => (),
 +    }
 +
 +    match a {
 +        Either::A { bar: (), foo: false } => (),
 +        Either::A { foo: true, bar: () } => (),
 +        Either::B => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_record_ellipsis() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either {
 +    A { foo: bool, bar: bool },
 +    B,
 +}
 +
 +fn main() {
 +    let a = Either::B;
 +    match a {
 +        //^ error: missing match arm: `A { foo: false, .. }` not covered
 +        Either::A { foo: true, .. } => (),
 +        Either::B => (),
 +    }
 +    match a {
 +        //^ error: missing match arm: `B` not covered
 +        Either::A { .. } => (),
 +    }
 +
 +    match a {
 +        Either::A { foo: true, .. } => (),
 +        Either::A { foo: false, .. } => (),
 +        Either::B => (),
 +    }
 +
 +    match a {
 +        Either::A { .. } => (),
 +        Either::B => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_tuple_partial_ellipsis() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either {
 +    A(bool, bool, bool, bool),
 +    B,
 +}
 +
 +fn main() {
 +    match Either::B {
 +        //^^^^^^^^^ error: missing match arm: `A(false, _, _, true)` not covered
 +        Either::A(true, .., true) => (),
 +        Either::A(true, .., false) => (),
 +        Either::A(false, .., false) => (),
 +        Either::B => (),
 +    }
 +    match Either::B {
 +        //^^^^^^^^^ error: missing match arm: `A(false, _, _, false)` not covered
 +        Either::A(true, .., true) => (),
 +        Either::A(true, .., false) => (),
 +        Either::A(.., true) => (),
 +        Either::B => (),
 +    }
 +
 +    match Either::B {
 +        Either::A(true, .., true) => (),
 +        Either::A(true, .., false) => (),
 +        Either::A(false, .., true) => (),
 +        Either::A(false, .., false) => (),
 +        Either::B => (),
 +    }
 +    match Either::B {
 +        Either::A(true, .., true) => (),
 +        Either::A(true, .., false) => (),
 +        Either::A(.., true) => (),
 +        Either::A(.., false) => (),
 +        Either::B => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn never() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Never {}
 +
 +fn enum_(never: Never) {
 +    match never {}
 +}
 +fn enum_ref(never: &Never) {
 +    match never {}
 +        //^^^^^ error: missing match arm: type `&Never` is non-empty
 +}
 +fn bang(never: !) {
 +    match never {}
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn unknown_type() {
 +        cov_mark::check_count!(validate_match_bailed_out, 1);
 +
 +        check_diagnostics(
 +            r#"
 +enum Option<T> { Some(T), None }
 +
 +fn main() {
 +    // `Never` is deliberately not defined so that it's an uninferred type.
 +    match Option::<Never>::None {
 +        None => (),
 +        Some(never) => match never {},
 +    }
 +    match Option::<Never>::None {
 +        //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `None` not covered
 +        Option::Some(_never) => {},
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match (false, true, false) {
 +        //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(true, _, _)` not covered
 +        (false, ..) => (),
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match (false, true, false) {
 +        //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(_, _, true)` not covered
 +        (.., false) => (),
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match (false, true, false) {
 +        //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(false, _, _)` not covered
 +        (true, .., false) => (),
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn record_struct() {
 +        check_diagnostics_no_bails(
 +            r#"struct Foo { a: bool }
 +fn main(f: Foo) {
 +    match f {}
 +        //^ error: missing match arm: type `Foo` is non-empty
 +    match f { Foo { a: true } => () }
 +        //^ error: missing match arm: `Foo { a: false }` not covered
 +    match &f { Foo { a: true } => () }
 +        //^^ error: missing match arm: `&Foo { a: false }` not covered
 +    match f { Foo { a: _ } => () }
 +    match f {
 +        Foo { a: true } => (),
 +        Foo { a: false } => (),
 +    }
 +    match &f {
 +        Foo { a: true } => (),
 +        Foo { a: false } => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn tuple_struct() {
 +        check_diagnostics_no_bails(
 +            r#"struct Foo(bool);
 +fn main(f: Foo) {
 +    match f {}
 +        //^ error: missing match arm: type `Foo` is non-empty
 +    match f { Foo(true) => () }
 +        //^ error: missing match arm: `Foo(false)` not covered
 +    match f {
 +        Foo(true) => (),
 +        Foo(false) => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn unit_struct() {
 +        check_diagnostics_no_bails(
 +            r#"struct Foo;
 +fn main(f: Foo) {
 +    match f {}
 +        //^ error: missing match arm: type `Foo` is non-empty
 +    match f { Foo => () }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn record_struct_ellipsis() {
 +        check_diagnostics_no_bails(
 +            r#"struct Foo { foo: bool, bar: bool }
 +fn main(f: Foo) {
 +    match f { Foo { foo: true, .. } => () }
 +        //^ error: missing match arm: `Foo { foo: false, .. }` not covered
 +    match f {
 +        //^ error: missing match arm: `Foo { foo: false, bar: true }` not covered
 +        Foo { foo: true, .. } => (),
 +        Foo { bar: false, .. } => ()
 +    }
 +    match f { Foo { .. } => () }
 +    match f {
 +        Foo { foo: true, .. } => (),
 +        Foo { foo: false, .. } => ()
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn internal_or() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    enum Either { A(bool), B }
 +    match Either::B {
 +        //^^^^^^^^^ error: missing match arm: `B` not covered
 +        Either::A(true | false) => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_panic_at_unimplemented_subpattern_type() {
 +        cov_mark::check_count!(validate_match_bailed_out, 1);
 +
 +        check_diagnostics(
 +            r#"
 +struct S { a: char}
 +fn main(v: S) {
 +    match v { S{ a }      => {} }
 +    match v { S{ a: _x }  => {} }
 +    match v { S{ a: 'a' } => {} }
 +    match v { S{..}       => {} }
 +    match v { _           => {} }
 +    match v { }
 +        //^ error: missing match arm: type `S` is non-empty
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn binding() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match true {
 +        _x @ true => {}
 +        false     => {}
 +    }
 +    match true { _x @ true => {} }
 +        //^^^^ error: missing match arm: `false` not covered
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn binding_ref_has_correct_type() {
 +        cov_mark::check_count!(validate_match_bailed_out, 1);
 +
 +        // Asserts `PatKind::Binding(ref _x): bool`, not &bool.
 +        // If that's not true match checking will panic with "incompatible constructors"
 +        // FIXME: make facilities to test this directly like `tests::check_infer(..)`
 +        check_diagnostics(
 +            r#"
 +enum Foo { A }
 +fn main() {
 +    // FIXME: this should not bail out but current behavior is such as the old algorithm.
++    // ExprValidator::validate_match(..) checks types of top level patterns incorrectly.
 +    match Foo::A {
 +        ref _x => {}
 +        Foo::A => {}
 +    }
 +    match (true,) {
 +        (ref _x,) => {}
 +        (true,) => {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_non_exhaustive() {
 +        check_diagnostics_no_bails(
 +            r#"
 +//- /lib.rs crate:lib
 +#[non_exhaustive]
 +pub enum E { A, B }
 +fn _local() {
 +    match E::A { _ => {} }
 +    match E::A {
 +        E::A => {}
 +        E::B => {}
 +    }
 +    match E::A {
 +        E::A | E::B => {}
 +    }
 +}
 +
 +//- /main.rs crate:main deps:lib
 +use lib::E;
 +fn main() {
 +    match E::A { _ => {} }
 +    match E::A {
 +        //^^^^ error: missing match arm: `_` not covered
 +        E::A => {}
 +        E::B => {}
 +    }
 +    match E::A {
 +        //^^^^ error: missing match arm: `_` not covered
 +        E::A | E::B => {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn match_guard() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match true {
 +        true if false => {}
 +        true          => {}
 +        false         => {}
 +    }
 +    match true {
 +        //^^^^ error: missing match arm: `true` not covered
 +        true if false => {}
 +        false         => {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn pattern_type_is_of_substitution() {
 +        check_diagnostics_no_bails(
 +            r#"
 +struct Foo<T>(T);
 +struct Bar;
 +fn main() {
 +    match Foo(Bar) {
 +        _ | Foo(Bar) => {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn record_struct_no_such_field() {
 +        cov_mark::check_count!(validate_match_bailed_out, 1);
 +
 +        check_diagnostics(
 +            r#"
 +struct Foo { }
 +fn main(f: Foo) {
 +    match f { Foo { bar } => () }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn match_ergonomics_issue_9095() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Foo<T> { A(T) }
 +fn main() {
 +    match &Foo::A(true) {
 +        _ => {}
 +        Foo::A(_) => {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn normalize_field_ty() {
 +        check_diagnostics_no_bails(
 +            r"
 +trait Trait { type Projection; }
 +enum E {Foo, Bar}
 +struct A;
 +impl Trait for A { type Projection = E; }
 +struct Next<T: Trait>(T::Projection);
 +static __: () = {
 +    let n: Next<A> = Next(E::Foo);
 +    match n { Next(E::Foo) => {} }
 +    //    ^ error: missing match arm: `Next(Bar)` not covered
 +    match n { Next(E::Foo | E::Bar) => {} }
 +    match n { Next(E::Foo | _     ) => {} }
 +    match n { Next(_      | E::Bar) => {} }
 +    match n {      _ | Next(E::Bar) => {} }
 +    match &n { Next(E::Foo | E::Bar) => {} }
 +    match &n {      _ | Next(E::Bar) => {} }
 +};",
 +        );
 +    }
 +
 +    #[test]
 +    fn binding_mode_by_ref() {
 +        check_diagnostics_no_bails(
 +            r"
 +enum E{ A, B }
 +fn foo() {
 +    match &E::A {
 +        E::A => {}
 +        x => {}
 +    }
 +}",
 +        );
 +    }
 +
 +    #[test]
 +    fn macro_or_pat() {
 +        check_diagnostics_no_bails(
 +            r#"
 +macro_rules! m {
 +    () => {
 +        Enum::Type1 | Enum::Type2
 +    };
 +}
 +
 +enum Enum {
 +    Type1,
 +    Type2,
 +    Type3,
 +}
 +
 +fn f(ty: Enum) {
 +    match ty {
 +        //^^ error: missing match arm: `Type3` not covered
 +        m!() => (),
 +    }
 +
 +    match ty {
 +        m!() | Enum::Type3 => ()
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn unexpected_ty_fndef() {
 +        cov_mark::check!(validate_match_bailed_out);
 +        check_diagnostics(
 +            r"
 +enum Exp {
 +    Tuple(()),
 +}
 +fn f() {
 +    match __unknown {
 +        Exp::Tuple => {}
 +    }
 +}",
 +        );
 +    }
 +
 +    mod false_negatives {
 +        //! The implementation of match checking here is a work in progress. As we roll this out, we
 +        //! prefer false negatives to false positives (ideally there would be no false positives). This
 +        //! test module should document known false negatives. Eventually we will have a complete
 +        //! implementation of match checking and this module will be empty.
 +        //!
 +        //! The reasons for documenting known false negatives:
 +        //!
 +        //!   1. It acts as a backlog of work that can be done to improve the behavior of the system.
 +        //!   2. It ensures the code doesn't panic when handling these cases.
 +        use super::*;
 +
 +        #[test]
 +        fn integers() {
 +            cov_mark::check_count!(validate_match_bailed_out, 1);
 +
 +            // We don't currently check integer exhaustiveness.
 +            check_diagnostics(
 +                r#"
 +fn main() {
 +    match 5 {
 +        10 => (),
 +        11..20 => (),
 +    }
 +}
 +"#,
 +            );
 +        }
 +
 +        #[test]
 +        fn reference_patterns_at_top_level() {
 +            cov_mark::check_count!(validate_match_bailed_out, 1);
 +
 +            check_diagnostics(
 +                r#"
 +fn main() {
 +    match &false {
 +        &true => {}
 +    }
 +}
 +            "#,
 +            );
 +        }
 +
 +        #[test]
 +        fn reference_patterns_in_fields() {
 +            cov_mark::check_count!(validate_match_bailed_out, 2);
 +
 +            check_diagnostics(
 +                r#"
 +fn main() {
 +    match (&false,) {
 +        (true,) => {}
 +    }
 +    match (&false,) {
 +        (&true,) => {}
 +    }
 +}
 +            "#,
 +            );
 +        }
 +    }
 +}
index d6cd5783f05ef0cf2a90f449c65f07a5c2dba6f0,0000000000000000000000000000000000000000..36a648fe4a8ea3eb8a3519f9ae189c0b30c26e18
mode 100644,000000..100644
--- /dev/null
@@@ -1,1754 -1,0 +1,1788 @@@
 +use std::mem::discriminant;
 +
 +use crate::{doc_links::token_as_doc_comment, FilePosition, NavigationTarget, RangeInfo, TryToNav};
 +use hir::{AsAssocItem, AssocItem, Semantics};
 +use ide_db::{
 +    base_db::{AnchoredPath, FileId, FileLoader},
 +    defs::{Definition, IdentClass},
 +    helpers::pick_best_token,
 +    RootDatabase,
 +};
 +use itertools::Itertools;
 +use syntax::{ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, T};
 +
 +// Feature: Go to Definition
 +//
 +// Navigates to the definition of an identifier.
 +//
 +// For outline modules, this will navigate to the source file of the module.
 +//
 +// |===
 +// | Editor  | Shortcut
 +//
 +// | VS Code | kbd:[F12]
 +// |===
 +//
 +// image::https://user-images.githubusercontent.com/48062697/113065563-025fbe00-91b1-11eb-83e4-a5a703610b23.gif[]
 +pub(crate) fn goto_definition(
 +    db: &RootDatabase,
 +    position: FilePosition,
 +) -> Option<RangeInfo<Vec<NavigationTarget>>> {
 +    let sema = &Semantics::new(db);
 +    let file = sema.parse(position.file_id).syntax().clone();
 +    let original_token =
 +        pick_best_token(file.token_at_offset(position.offset), |kind| match kind {
 +            IDENT
 +            | INT_NUMBER
 +            | LIFETIME_IDENT
 +            | T![self]
 +            | T![super]
 +            | T![crate]
 +            | T![Self]
 +            | COMMENT => 4,
 +            // index and prefix ops
 +            T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3,
 +            kind if kind.is_keyword() => 2,
 +            T!['('] | T![')'] => 2,
 +            kind if kind.is_trivia() => 0,
 +            _ => 1,
 +        })?;
 +    if let Some(doc_comment) = token_as_doc_comment(&original_token) {
 +        return doc_comment.get_definition_with_descend_at(sema, position.offset, |def, _, _| {
 +            let nav = def.try_to_nav(db)?;
 +            Some(RangeInfo::new(original_token.text_range(), vec![nav]))
 +        });
 +    }
 +    let navs = sema
 +        .descend_into_macros(original_token.clone())
 +        .into_iter()
 +        .filter_map(|token| {
 +            let parent = token.parent()?;
 +            if let Some(tt) = ast::TokenTree::cast(parent) {
 +                if let Some(x) = try_lookup_include_path(sema, tt, token.clone(), position.file_id)
 +                {
 +                    return Some(vec![x]);
 +                }
 +            }
 +            Some(
 +                IdentClass::classify_token(sema, &token)?
 +                    .definitions()
 +                    .into_iter()
 +                    .flat_map(|def| {
 +                        try_filter_trait_item_definition(sema, &def)
 +                            .unwrap_or_else(|| def_to_nav(sema.db, def))
 +                    })
 +                    .collect(),
 +            )
 +        })
 +        .flatten()
 +        .unique()
 +        .collect::<Vec<NavigationTarget>>();
 +
 +    Some(RangeInfo::new(original_token.text_range(), navs))
 +}
 +
 +fn try_lookup_include_path(
 +    sema: &Semantics<'_, RootDatabase>,
 +    tt: ast::TokenTree,
 +    token: SyntaxToken,
 +    file_id: FileId,
 +) -> Option<NavigationTarget> {
 +    let token = ast::String::cast(token)?;
 +    let path = token.value()?.into_owned();
 +    let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
 +    let name = macro_call.path()?.segment()?.name_ref()?;
 +    if !matches!(&*name.text(), "include" | "include_str" | "include_bytes") {
 +        return None;
 +    }
 +    let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
 +    let size = sema.db.file_text(file_id).len().try_into().ok()?;
 +    Some(NavigationTarget {
 +        file_id,
 +        full_range: TextRange::new(0.into(), size),
 +        name: path.into(),
 +        focus_range: None,
 +        kind: None,
 +        container_name: None,
 +        description: None,
 +        docs: None,
 +    })
 +}
 +/// finds the trait definition of an impl'd item, except function
 +/// e.g.
 +/// ```rust
 +/// trait A { type a; }
 +/// struct S;
 +/// impl A for S { type a = i32; } // <-- on this associate type, will get the location of a in the trait
 +/// ```
 +fn try_filter_trait_item_definition(
 +    sema: &Semantics<'_, RootDatabase>,
 +    def: &Definition,
 +) -> Option<Vec<NavigationTarget>> {
 +    let db = sema.db;
 +    let assoc = def.as_assoc_item(db)?;
 +    match assoc {
 +        AssocItem::Function(..) => None,
 +        AssocItem::Const(..) | AssocItem::TypeAlias(..) => {
 +            let imp = match assoc.container(db) {
 +                hir::AssocItemContainer::Impl(imp) => imp,
 +                _ => return None,
 +            };
 +            let trait_ = imp.trait_(db)?;
 +            let name = def.name(db)?;
 +            let discri_value = discriminant(&assoc);
 +            trait_
 +                .items(db)
 +                .iter()
 +                .filter(|itm| discriminant(*itm) == discri_value)
 +                .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten())
 +                .map(|it| vec![it])
 +        }
 +    }
 +}
 +
 +fn def_to_nav(db: &RootDatabase, def: Definition) -> Vec<NavigationTarget> {
 +    def.try_to_nav(db).map(|it| vec![it]).unwrap_or_default()
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use ide_db::base_db::FileRange;
 +    use itertools::Itertools;
 +
 +    use crate::fixture;
 +
 +    #[track_caller]
 +    fn check(ra_fixture: &str) {
 +        let (analysis, position, expected) = fixture::annotations(ra_fixture);
 +        let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
 +        if navs.is_empty() {
 +            panic!("unresolved reference")
 +        }
 +
 +        let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
 +        let navs = navs
 +            .into_iter()
 +            .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
 +            .sorted_by_key(cmp)
 +            .collect::<Vec<_>>();
 +        let expected = expected
 +            .into_iter()
 +            .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range })
 +            .sorted_by_key(cmp)
 +            .collect::<Vec<_>>();
 +        assert_eq!(expected, navs);
 +    }
 +
 +    fn check_unresolved(ra_fixture: &str) {
 +        let (analysis, position) = fixture::position(ra_fixture);
 +        let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
 +
 +        assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {:?}", navs)
 +    }
 +
 +    #[test]
 +    fn goto_def_if_items_same_name() {
 +        check(
 +            r#"
 +trait Trait {
 +    type A;
 +    const A: i32;
 +        //^
 +}
 +
 +struct T;
 +impl Trait for T {
 +    type A = i32;
 +    const A$0: i32 = -9;
 +}"#,
 +        );
 +    }
 +    #[test]
 +    fn goto_def_in_mac_call_in_attr_invoc() {
 +        check(
 +            r#"
 +//- proc_macros: identity
 +pub struct Struct {
 +        // ^^^^^^
 +    field: i32,
 +}
 +
 +macro_rules! identity {
 +    ($($tt:tt)*) => {$($tt)*};
 +}
 +
 +#[proc_macros::identity]
 +fn function() {
 +    identity!(Struct$0 { field: 0 });
 +}
 +
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_def_for_extern_crate() {
 +        check(
 +            r#"
 +//- /main.rs crate:main deps:std
 +extern crate std$0;
 +//- /std/lib.rs crate:std
 +// empty
 +//^file
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_def_for_renamed_extern_crate() {
 +        check(
 +            r#"
 +//- /main.rs crate:main deps:std
 +extern crate std as abc$0;
 +//- /std/lib.rs crate:std
 +// empty
 +//^file
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_def_in_items() {
 +        check(
 +            r#"
 +struct Foo;
 +     //^^^
 +enum E { X(Foo$0) }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_at_start_of_item() {
 +        check(
 +            r#"
 +struct Foo;
 +     //^^^
 +enum E { X($0Foo) }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_definition_resolves_correct_name() {
 +        check(
 +            r#"
 +//- /lib.rs
 +use a::Foo;
 +mod a;
 +mod b;
 +enum E { X(Foo$0) }
 +
 +//- /a.rs
 +struct Foo;
 +     //^^^
 +//- /b.rs
 +struct Foo;
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_module_declaration() {
 +        check(
 +            r#"
 +//- /lib.rs
 +mod $0foo;
 +
 +//- /foo.rs
 +// empty
 +//^file
 +"#,
 +        );
 +
 +        check(
 +            r#"
 +//- /lib.rs
 +mod $0foo;
 +
 +//- /foo/mod.rs
 +// empty
 +//^file
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_macros() {
 +        check(
 +            r#"
 +macro_rules! foo { () => { () } }
 +           //^^^
 +fn bar() {
 +    $0foo!();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_macros_from_other_crates() {
 +        check(
 +            r#"
 +//- /lib.rs crate:main deps:foo
 +use foo::foo;
 +fn bar() {
 +    $0foo!();
 +}
 +
 +//- /foo/lib.rs crate:foo
 +#[macro_export]
 +macro_rules! foo { () => { () } }
 +           //^^^
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_macros_in_use_tree() {
 +        check(
 +            r#"
 +//- /lib.rs crate:main deps:foo
 +use foo::foo$0;
 +
 +//- /foo/lib.rs crate:foo
 +#[macro_export]
 +macro_rules! foo { () => { () } }
 +           //^^^
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_macro_defined_fn_with_arg() {
 +        check(
 +            r#"
 +//- /lib.rs
 +macro_rules! define_fn {
 +    ($name:ident) => (fn $name() {})
 +}
 +
 +define_fn!(foo);
 +         //^^^
 +
 +fn bar() {
 +   $0foo();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_macro_defined_fn_no_arg() {
 +        check(
 +            r#"
 +//- /lib.rs
 +macro_rules! define_fn {
 +    () => (fn foo() {})
 +}
 +
 +  define_fn!();
 +//^^^^^^^^^^^^^
 +
 +fn bar() {
 +   $0foo();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_definition_works_for_macro_inside_pattern() {
 +        check(
 +            r#"
 +//- /lib.rs
 +macro_rules! foo {() => {0}}
 +           //^^^
 +
 +fn bar() {
 +    match (0,1) {
 +        ($0foo!(), _) => {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_definition_works_for_macro_inside_match_arm_lhs() {
 +        check(
 +            r#"
 +//- /lib.rs
 +macro_rules! foo {() => {0}}
 +           //^^^
 +fn bar() {
 +    match 0 {
 +        $0foo!() => {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_use_alias() {
 +        check(
 +            r#"
 +//- /lib.rs crate:main deps:foo
 +use foo as bar$0;
 +
 +//- /foo/lib.rs crate:foo
 +// empty
 +//^file
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_use_alias_foo_macro() {
 +        check(
 +            r#"
 +//- /lib.rs crate:main deps:foo
 +use foo::foo as bar$0;
 +
 +//- /foo/lib.rs crate:foo
 +#[macro_export]
 +macro_rules! foo { () => { () } }
 +           //^^^
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_methods() {
 +        check(
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn frobnicate(&self) { }
 +     //^^^^^^^^^^
 +}
 +
 +fn bar(foo: &Foo) {
 +    foo.frobnicate$0();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_fields() {
 +        check(
 +            r#"
 +struct Foo {
 +    spam: u32,
 +} //^^^^
 +
 +fn bar(foo: &Foo) {
 +    foo.spam$0;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_record_fields() {
 +        check(
 +            r#"
 +//- /lib.rs
 +struct Foo {
 +    spam: u32,
 +} //^^^^
 +
 +fn bar() -> Foo {
 +    Foo {
 +        spam$0: 0,
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_record_pat_fields() {
 +        check(
 +            r#"
 +//- /lib.rs
 +struct Foo {
 +    spam: u32,
 +} //^^^^
 +
 +fn bar(foo: Foo) -> Foo {
 +    let Foo { spam$0: _, } = foo
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_record_fields_macros() {
 +        check(
 +            r"
 +macro_rules! m { () => { 92 };}
 +struct Foo { spam: u32 }
 +           //^^^^
 +
 +fn bar() -> Foo {
 +    Foo { spam$0: m!() }
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_for_tuple_fields() {
 +        check(
 +            r#"
 +struct Foo(u32);
 +         //^^^
 +
 +fn bar() {
 +    let foo = Foo(0);
 +    foo.$00;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_ufcs_inherent_methods() {
 +        check(
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn frobnicate() { }
 +}    //^^^^^^^^^^
 +
 +fn bar(foo: &Foo) {
 +    Foo::frobnicate$0();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_ufcs_trait_methods_through_traits() {
 +        check(
 +            r#"
 +trait Foo {
 +    fn frobnicate();
 +}    //^^^^^^^^^^
 +
 +fn bar() {
 +    Foo::frobnicate$0();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_ufcs_trait_methods_through_self() {
 +        check(
 +            r#"
 +struct Foo;
 +trait Trait {
 +    fn frobnicate();
 +}    //^^^^^^^^^^
 +impl Trait for Foo {}
 +
 +fn bar() {
 +    Foo::frobnicate$0();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_definition_on_self() {
 +        check(
 +            r#"
 +struct Foo;
 +impl Foo {
 +   //^^^
 +    pub fn new() -> Self {
 +        Self$0 {}
 +    }
 +}
 +"#,
 +        );
 +        check(
 +            r#"
 +struct Foo;
 +impl Foo {
 +   //^^^
 +    pub fn new() -> Self$0 {
 +        Self {}
 +    }
 +}
 +"#,
 +        );
 +
 +        check(
 +            r#"
 +enum Foo { A }
 +impl Foo {
 +   //^^^
 +    pub fn new() -> Self$0 {
 +        Foo::A
 +    }
 +}
 +"#,
 +        );
 +
 +        check(
 +            r#"
 +enum Foo { A }
 +impl Foo {
 +   //^^^
 +    pub fn thing(a: &Self$0) {
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_definition_on_self_in_trait_impl() {
 +        check(
 +            r#"
 +struct Foo;
 +trait Make {
 +    fn new() -> Self;
 +}
 +impl Make for Foo {
 +            //^^^
 +    fn new() -> Self {
 +        Self$0 {}
 +    }
 +}
 +"#,
 +        );
 +
 +        check(
 +            r#"
 +struct Foo;
 +trait Make {
 +    fn new() -> Self;
 +}
 +impl Make for Foo {
 +            //^^^
 +    fn new() -> Self$0 {
 +        Self {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_when_used_on_definition_name_itself() {
 +        check(
 +            r#"
 +struct Foo$0 { value: u32 }
 +     //^^^
 +            "#,
 +        );
 +
 +        check(
 +            r#"
 +struct Foo {
 +    field$0: string,
 +} //^^^^^
 +"#,
 +        );
 +
 +        check(
 +            r#"
 +fn foo_test$0() { }
 + //^^^^^^^^
 +"#,
 +        );
 +
 +        check(
 +            r#"
 +enum Foo$0 { Variant }
 +   //^^^
 +"#,
 +        );
 +
 +        check(
 +            r#"
 +enum Foo {
 +    Variant1,
 +    Variant2$0,
 +  //^^^^^^^^
 +    Variant3,
 +}
 +"#,
 +        );
 +
 +        check(
 +            r#"
 +static INNER$0: &str = "";
 +     //^^^^^
 +"#,
 +        );
 +
 +        check(
 +            r#"
 +const INNER$0: &str = "";
 +    //^^^^^
 +"#,
 +        );
 +
 +        check(
 +            r#"
 +type Thing$0 = Option<()>;
 +   //^^^^^
 +"#,
 +        );
 +
 +        check(
 +            r#"
 +trait Foo$0 { }
 +    //^^^
 +"#,
 +        );
 +
 +        check(
 +            r#"
 +mod bar$0 { }
 +  //^^^
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_from_macro() {
 +        check(
 +            r#"
 +macro_rules! id {
 +    ($($tt:tt)*) => { $($tt)* }
 +}
 +fn foo() {}
 + //^^^
 +id! {
 +    fn bar() {
 +        fo$0o();
 +    }
 +}
 +mod confuse_index { fn foo(); }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_through_format() {
 +        check(
 +            r#"
 +#[macro_export]
 +macro_rules! format {
 +    ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
 +}
 +#[rustc_builtin_macro]
 +#[macro_export]
 +macro_rules! format_args {
 +    ($fmt:expr) => ({ /* compiler built-in */ });
 +    ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
 +}
 +pub mod __export {
 +    pub use crate::format_args;
 +    fn foo() {} // for index confusion
 +}
 +fn foo() -> i8 {}
 + //^^^
 +fn test() {
 +    format!("{}", fo$0o())
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_through_included_file() {
 +        check(
 +            r#"
 +//- /main.rs
 +#[rustc_builtin_macro]
 +macro_rules! include {}
 +
 +  include!("foo.rs");
 +//^^^^^^^^^^^^^^^^^^^
 +
 +fn f() {
 +    foo$0();
 +}
 +
 +mod confuse_index {
 +    pub fn foo() {}
 +}
 +
 +//- /foo.rs
 +fn foo() {}
 +        "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_for_type_param() {
 +        check(
 +            r#"
 +struct Foo<T: Clone> { t: $0T }
 +         //^
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_within_macro() {
 +        check(
 +            r#"
 +macro_rules! id {
 +    ($($tt:tt)*) => ($($tt)*)
 +}
 +
 +fn foo() {
 +    let x = 1;
 +      //^
 +    id!({
 +        let y = $0x;
 +        let z = y;
 +    });
 +}
 +"#,
 +        );
 +
 +        check(
 +            r#"
 +macro_rules! id {
 +    ($($tt:tt)*) => ($($tt)*)
 +}
 +
 +fn foo() {
 +    let x = 1;
 +    id!({
 +        let y = x;
 +          //^
 +        let z = $0y;
 +    });
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_in_local_fn() {
 +        check(
 +            r#"
 +fn main() {
 +    fn foo() {
 +        let x = 92;
 +          //^
 +        $0x;
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_in_local_macro() {
 +        check(
 +            r#"
 +fn bar() {
 +    macro_rules! foo { () => { () } }
 +               //^^^
 +    $0foo!();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_field_init_shorthand() {
 +        check(
 +            r#"
 +struct Foo { x: i32 }
 +           //^
 +fn main() {
 +    let x = 92;
 +      //^
 +    Foo { x$0 };
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_def_for_enum_variant_field() {
 +        check(
 +            r#"
 +enum Foo {
 +    Bar { x: i32 }
 +        //^
 +}
 +fn baz(foo: Foo) {
 +    match foo {
 +        Foo::Bar { x$0 } => x
 +                 //^
 +    };
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_enum_variant_self_pattern_const() {
 +        check(
 +            r#"
 +enum Foo { Bar }
 +         //^^^
 +impl Foo {
 +    fn baz(self) {
 +        match self { Self::Bar$0 => {} }
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_enum_variant_self_pattern_record() {
 +        check(
 +            r#"
 +enum Foo { Bar { val: i32 } }
 +         //^^^
 +impl Foo {
 +    fn baz(self) -> i32 {
 +        match self { Self::Bar$0 { val } => {} }
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_enum_variant_self_expr_const() {
 +        check(
 +            r#"
 +enum Foo { Bar }
 +         //^^^
 +impl Foo {
 +    fn baz(self) { Self::Bar$0; }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_enum_variant_self_expr_record() {
 +        check(
 +            r#"
 +enum Foo { Bar { val: i32 } }
 +         //^^^
 +impl Foo {
 +    fn baz(self) { Self::Bar$0 {val: 4}; }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_type_alias_generic_parameter() {
 +        check(
 +            r#"
 +type Alias<T> = T$0;
 +         //^
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_def_for_macro_container() {
 +        check(
 +            r#"
 +//- /lib.rs crate:main deps:foo
 +foo::module$0::mac!();
 +
 +//- /foo/lib.rs crate:foo
 +pub mod module {
 +      //^^^^^^
 +    #[macro_export]
 +    macro_rules! _mac { () => { () } }
 +    pub use crate::_mac as mac;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_assoc_ty_in_path() {
 +        check(
 +            r#"
 +trait Iterator {
 +    type Item;
 +       //^^^^
 +}
 +
 +fn f() -> impl Iterator<Item$0 = u8> {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_super_assoc_ty_in_path() {
 +        check(
 +            r#"
 +trait Super {
 +    type Item;
 +       //^^^^
 +}
 +
 +trait Sub: Super {}
 +
 +fn f() -> impl Sub<Item$0 = u8> {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn unknown_assoc_ty() {
 +        check_unresolved(
 +            r#"
 +trait Iterator { type Item; }
 +fn f() -> impl Iterator<Invalid$0 = u8> {}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_def_for_assoc_ty_in_path_multiple() {
 +        check(
 +            r#"
 +trait Iterator {
 +    type A;
 +       //^
 +    type B;
 +}
 +
 +fn f() -> impl Iterator<A$0 = u8, B = ()> {}
 +"#,
 +        );
 +        check(
 +            r#"
 +trait Iterator {
 +    type A;
 +    type B;
 +       //^
 +}
 +
 +fn f() -> impl Iterator<A = u8, B$0 = ()> {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_assoc_ty_ufcs() {
 +        check(
 +            r#"
 +trait Iterator {
 +    type Item;
 +       //^^^^
 +}
 +
 +fn g() -> <() as Iterator<Item$0 = ()>>::Item {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_for_assoc_ty_ufcs_multiple() {
 +        check(
 +            r#"
 +trait Iterator {
 +    type A;
 +       //^
 +    type B;
 +}
 +
 +fn g() -> <() as Iterator<A$0 = (), B = u8>>::B {}
 +"#,
 +        );
 +        check(
 +            r#"
 +trait Iterator {
 +    type A;
 +    type B;
 +       //^
 +}
 +
 +fn g() -> <() as Iterator<A = (), B$0 = u8>>::A {}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_self_param_ty_specified() {
 +        check(
 +            r#"
 +struct Foo {}
 +
 +impl Foo {
 +    fn bar(self: &Foo) {
 +         //^^^^
 +        let foo = sel$0f;
 +    }
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_self_param_on_decl() {
 +        check(
 +            r#"
 +struct Foo {}
 +
 +impl Foo {
 +    fn bar(&self$0) {
 +          //^^^^
 +    }
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_lifetime_param_on_decl() {
 +        check(
 +            r#"
 +fn foo<'foobar$0>(_: &'foobar ()) {
 +     //^^^^^^^
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_lifetime_param_decl() {
 +        check(
 +            r#"
 +fn foo<'foobar>(_: &'foobar$0 ()) {
 +     //^^^^^^^
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_lifetime_param_decl_nested() {
 +        check(
 +            r#"
 +fn foo<'foobar>(_: &'foobar ()) {
 +    fn foo<'foobar>(_: &'foobar$0 ()) {}
 +         //^^^^^^^
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_lifetime_hrtb() {
 +        // FIXME: requires the HIR to somehow track these hrtb lifetimes
 +        check_unresolved(
 +            r#"
 +trait Foo<T> {}
 +fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {}
 +                    //^^
 +"#,
 +        );
 +        check_unresolved(
 +            r#"
 +trait Foo<T> {}
 +fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {}
 +                    //^^
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_lifetime_hrtb_for_type() {
 +        // FIXME: requires ForTypes to be implemented
 +        check_unresolved(
 +            r#"trait Foo<T> {}
 +fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {}
 +                       //^^
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_label() {
 +        check(
 +            r#"
 +fn foo<'foo>(_: &'foo ()) {
 +    'foo: {
 +  //^^^^
 +        'bar: loop {
 +            break 'foo$0;
 +        }
 +    }
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_def_for_intra_doc_link_same_file() {
 +        check(
 +            r#"
 +/// Blah, [`bar`](bar) .. [`foo`](foo$0) has [`bar`](bar)
 +pub fn bar() { }
 +
 +/// You might want to see [`std::fs::read()`] too.
 +pub fn foo() { }
 +     //^^^
 +
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_def_for_intra_doc_link_inner() {
 +        check(
 +            r#"
 +//- /main.rs
 +mod m;
 +struct S;
 +     //^
 +
 +//- /m.rs
 +//! [`super::S$0`]
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_incomplete_field() {
 +        check(
 +            r#"
 +struct A { a: u32 }
 +         //^
 +fn foo() { A { a$0: }; }
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_proc_macro() {
 +        check(
 +            r#"
 +//- /main.rs crate:main deps:mac
 +use mac::fn_macro;
 +
 +fn_macro$0!();
 +
 +//- /mac.rs crate:mac
 +#![crate_type="proc-macro"]
 +#[proc_macro]
 +fn fn_macro() {}
 + //^^^^^^^^
 +            "#,
 +        )
 +    }
 +
 +    #[test]
 +    fn goto_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
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_ident_from_pat_macro() {
 +        check(
 +            r#"
 +macro_rules! pat {
 +    ($name:ident) => { Enum::Variant1($name) }
 +}
 +
 +enum Enum {
 +    Variant1(u8),
 +    Variant2,
 +}
 +
 +fn f(e: Enum) {
 +    match e {
 +        pat!(bind) => {
 +           //^^^^
 +            bind$0
 +        }
 +        Enum::Variant2 => {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_include() {
 +        check(
 +            r#"
 +//- /main.rs
 +fn main() {
 +    let str = include_str!("foo.txt$0");
 +}
 +//- /foo.txt
 +// empty
 +//^file
 +"#,
 +        );
 +    }
 +    #[cfg(test)]
 +    mod goto_impl_of_trait_fn {
 +        use super::check;
 +        #[test]
 +        fn cursor_on_impl() {
 +            check(
 +                r#"
 +trait Twait {
 +    fn a();
 +}
 +
 +struct Stwuct;
 +
 +impl Twait for Stwuct {
 +    fn a$0();
 +     //^
 +}
 +        "#,
 +            );
 +        }
 +        #[test]
 +        fn method_call() {
 +            check(
 +                r#"
 +trait Twait {
 +    fn a(&self);
 +}
 +
 +struct Stwuct;
 +
 +impl Twait for Stwuct {
 +    fn a(&self){};
 +     //^
 +}
 +fn f() {
 +    let s = Stwuct;
 +    s.a$0();
 +}
 +        "#,
 +            );
 +        }
 +        #[test]
 +        fn path_call() {
 +            check(
 +                r#"
 +trait Twait {
 +    fn a(&self);
 +}
 +
 +struct Stwuct;
 +
 +impl Twait for Stwuct {
 +    fn a(&self){};
 +     //^
 +}
 +fn f() {
 +    let s = Stwuct;
 +    Stwuct::a$0(&s);
 +}
 +        "#,
 +            );
 +        }
 +        #[test]
 +        fn where_clause_can_work() {
 +            check(
 +                r#"
 +trait G {
 +    fn g(&self);
 +}
 +trait Bound{}
 +trait EA{}
 +struct Gen<T>(T);
 +impl <T:EA> G for Gen<T> {
 +    fn g(&self) {
 +    }
 +}
 +impl <T> G for Gen<T>
 +where T : Bound
 +{
 +    fn g(&self){
 +     //^
 +    }
 +}
 +struct A;
 +impl Bound for A{}
 +fn f() {
 +    let gen = Gen::<A>(A);
 +    gen.g$0();
 +}
 +                "#,
 +            );
 +        }
 +        #[test]
 +        fn wc_case_is_ok() {
 +            check(
 +                r#"
 +trait G {
 +    fn g(&self);
 +}
 +trait BParent{}
 +trait Bound: BParent{}
 +struct Gen<T>(T);
 +impl <T> G for Gen<T>
 +where T : Bound
 +{
 +    fn g(&self){
 +     //^
 +    }
 +}
 +struct A;
 +impl Bound for A{}
 +fn f() {
 +    let gen = Gen::<A>(A);
 +    gen.g$0();
 +}
 +"#,
 +            );
 +        }
 +
 +        #[test]
 +        fn method_call_defaulted() {
 +            check(
 +                r#"
 +trait Twait {
 +    fn a(&self) {}
 +     //^
 +}
 +
 +struct Stwuct;
 +
 +impl Twait for Stwuct {
 +}
 +fn f() {
 +    let s = Stwuct;
 +    s.a$0();
 +}
 +        "#,
 +            );
 +        }
 +
 +        #[test]
 +        fn method_call_on_generic() {
 +            check(
 +                r#"
 +trait Twait {
 +    fn a(&self) {}
 +     //^
 +}
 +
 +fn f<T: Twait>(s: T) {
 +    s.a$0();
 +}
 +        "#,
 +            );
 +        }
 +    }
 +
 +    #[test]
 +    fn goto_def_of_trait_impl_const() {
 +        check(
 +            r#"
 +trait Twait {
 +    const NOMS: bool;
 +       // ^^^^
 +}
 +
 +struct Stwuct;
 +
 +impl Twait for Stwuct {
 +    const NOMS$0: bool = true;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_of_trait_impl_type_alias() {
 +        check(
 +            r#"
 +trait Twait {
 +    type IsBad;
 +      // ^^^^^
 +}
 +
 +struct Stwuct;
 +
 +impl Twait for Stwuct {
 +    type IsBad$0 = !;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_derive_input() {
 +        check(
 +            r#"
 +        //- minicore:derive
 +        #[rustc_builtin_macro]
 +        pub macro Copy {}
 +               // ^^^^
 +        #[derive(Copy$0)]
 +        struct Foo;
 +                    "#,
 +        );
 +        check(
 +            r#"
 +//- minicore:derive
 +#[rustc_builtin_macro]
 +pub macro Copy {}
 +       // ^^^^
 +#[cfg_attr(feature = "false", derive)]
 +#[derive(Copy$0)]
 +struct Foo;
 +            "#,
 +        );
 +        check(
 +            r#"
 +//- minicore:derive
 +mod foo {
 +    #[rustc_builtin_macro]
 +    pub macro Copy {}
 +           // ^^^^
 +}
 +#[derive(foo::Copy$0)]
 +struct Foo;
 +            "#,
 +        );
 +        check(
 +            r#"
 +//- minicore:derive
 +mod foo {
 + // ^^^
 +    #[rustc_builtin_macro]
 +    pub macro Copy {}
 +}
 +#[derive(foo$0::Copy)]
 +struct Foo;
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_def_in_macro_multi() {
 +        check(
 +            r#"
 +struct Foo {
 +    foo: ()
 +  //^^^
 +}
 +macro_rules! foo {
 +    ($ident:ident) => {
 +        fn $ident(Foo { $ident }: Foo) {}
 +    }
 +}
 +foo!(foo$0);
 +   //^^^
 +   //^^^
 +"#,
 +        );
 +        check(
 +            r#"
 +fn bar() {}
 + //^^^
 +struct bar;
 +     //^^^
 +macro_rules! foo {
 +    ($ident:ident) => {
 +        fn foo() {
 +            let _: $ident = $ident;
 +        }
 +    }
 +}
 +
 +foo!(bar$0);
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_await_poll() {
 +        check(
 +            r#"
 +//- minicore: future
 +
 +struct MyFut;
 +
 +impl core::future::Future for MyFut {
 +    type Output = ();
 +
 +    fn poll(
 +     //^^^^
 +        self: std::pin::Pin<&mut Self>,
 +        cx: &mut std::task::Context<'_>
 +    ) -> std::task::Poll<Self::Output>
 +    {
 +        ()
 +    }
 +}
 +
 +fn f() {
 +    MyFut.await$0;
 +}
 +"#,
 +        );
 +    }
 +
++    #[test]
++    fn goto_await_into_future_poll() {
++        check(
++            r#"
++//- minicore: future
++
++struct Futurable;
++
++impl core::future::IntoFuture for Futurable {
++    type IntoFuture = MyFut;
++}
++
++struct MyFut;
++
++impl core::future::Future for MyFut {
++    type Output = ();
++
++    fn poll(
++     //^^^^
++        self: std::pin::Pin<&mut Self>,
++        cx: &mut std::task::Context<'_>
++    ) -> std::task::Poll<Self::Output>
++    {
++        ()
++    }
++}
++
++fn f() {
++    Futurable.await$0;
++}
++"#,
++        );
++    }
++
 +    #[test]
 +    fn goto_try_op() {
 +        check(
 +            r#"
 +//- minicore: try
 +
 +struct Struct;
 +
 +impl core::ops::Try for Struct {
 +    fn branch(
 +     //^^^^^^
 +        self
 +    ) {}
 +}
 +
 +fn f() {
 +    Struct?$0;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_index_op() {
 +        check(
 +            r#"
 +//- minicore: index
 +
 +struct Struct;
 +
 +impl core::ops::Index<usize> for Struct {
 +    fn index(
 +     //^^^^^
 +        self
 +    ) {}
 +}
 +
 +fn f() {
 +    Struct[0]$0;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_prefix_op() {
 +        check(
 +            r#"
 +//- minicore: deref
 +
 +struct Struct;
 +
 +impl core::ops::Deref for Struct {
 +    fn deref(
 +     //^^^^^
 +        self
 +    ) {}
 +}
 +
 +fn f() {
 +    $0*Struct;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_bin_op() {
 +        check(
 +            r#"
 +//- minicore: add
 +
 +struct Struct;
 +
 +impl core::ops::Add for Struct {
 +    fn add(
 +     //^^^
 +        self
 +    ) {}
 +}
 +
 +fn f() {
 +    Struct +$0 Struct;
 +}
 +"#,
 +        );
 +    }
 +}
index 3ada181f1ed2ba63a3e69d775af8a9bc3c35ab25,0000000000000000000000000000000000000000..3687b597fc642f6ad17cd8b9443341192cd8d28b
mode 100644,000000..100644
--- /dev/null
@@@ -1,400 -1,0 +1,403 @@@
 +mod render;
 +
 +#[cfg(test)]
 +mod tests;
 +
 +use std::iter;
 +
 +use either::Either;
 +use hir::{HasSource, Semantics};
 +use ide_db::{
 +    base_db::FileRange,
 +    defs::{Definition, IdentClass, OperatorClass},
 +    famous_defs::FamousDefs,
 +    helpers::pick_best_token,
 +    FxIndexSet, RootDatabase,
 +};
 +use itertools::Itertools;
 +use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, T};
 +
 +use crate::{
 +    doc_links::token_as_doc_comment,
 +    markup::Markup,
 +    runnables::{runnable_fn, runnable_mod},
 +    FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav,
 +};
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub struct HoverConfig {
 +    pub links_in_hover: bool,
 +    pub documentation: Option<HoverDocFormat>,
++    pub keywords: bool,
 +}
 +
 +impl HoverConfig {
 +    fn markdown(&self) -> bool {
 +        matches!(self.documentation, Some(HoverDocFormat::Markdown))
 +    }
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum HoverDocFormat {
 +    Markdown,
 +    PlainText,
 +}
 +
 +#[derive(Debug, Clone)]
 +pub enum HoverAction {
 +    Runnable(Runnable),
 +    Implementation(FilePosition),
 +    Reference(FilePosition),
 +    GoToType(Vec<HoverGotoTypeData>),
 +}
 +
 +impl HoverAction {
 +    fn goto_type_from_targets(db: &RootDatabase, targets: Vec<hir::ModuleDef>) -> Self {
 +        let targets = targets
 +            .into_iter()
 +            .filter_map(|it| {
 +                Some(HoverGotoTypeData {
 +                    mod_path: render::path(
 +                        db,
 +                        it.module(db)?,
 +                        it.name(db).map(|name| name.to_string()),
 +                    ),
 +                    nav: it.try_to_nav(db)?,
 +                })
 +            })
 +            .collect();
 +        HoverAction::GoToType(targets)
 +    }
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq, Hash)]
 +pub struct HoverGotoTypeData {
 +    pub mod_path: String,
 +    pub nav: NavigationTarget,
 +}
 +
 +/// Contains the results when hovering over an item
 +#[derive(Debug, Default)]
 +pub struct HoverResult {
 +    pub markup: Markup,
 +    pub actions: Vec<HoverAction>,
 +}
 +
 +// Feature: Hover
 +//
 +// Shows additional information, like the type of an expression or the documentation for a definition when "focusing" code.
 +// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
 +//
 +// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[]
 +pub(crate) fn hover(
 +    db: &RootDatabase,
 +    FileRange { file_id, range }: FileRange,
 +    config: &HoverConfig,
 +) -> Option<RangeInfo<HoverResult>> {
 +    let sema = &hir::Semantics::new(db);
 +    let file = sema.parse(file_id).syntax().clone();
 +
 +    if !range.is_empty() {
 +        return hover_ranged(&file, range, sema, config);
 +    }
 +    let offset = range.start();
 +
 +    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] => 4,
 +        // index and prefix ops
 +        T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3,
 +        kind if kind.is_keyword() => 2,
 +        T!['('] | T![')'] => 2,
 +        kind if kind.is_trivia() => 0,
 +        _ => 1,
 +    })?;
 +
 +    if let Some(doc_comment) = token_as_doc_comment(&original_token) {
 +        cov_mark::hit!(no_highlight_on_comment_hover);
 +        return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| {
 +            let res = hover_for_definition(sema, file_id, def, &node, config)?;
 +            Some(RangeInfo::new(range, res))
 +        });
 +    }
 +
 +    let in_attr = matches!(original_token.parent().and_then(ast::TokenTree::cast), Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind())));
++    // prefer descending the same token kind in attribute expansions, in normal macros text
++    // equivalency is more important
 +    let descended = if in_attr {
 +        [sema.descend_into_macros_with_kind_preference(original_token.clone())].into()
 +    } else {
 +        sema.descend_into_macros_with_same_text(original_token.clone())
 +    };
 +
 +    // FIXME: Definition should include known lints and the like instead of having this special case here
 +    let hovered_lint = descended.iter().find_map(|token| {
 +        let attr = token.parent_ancestors().find_map(ast::Attr::cast)?;
 +        render::try_for_lint(&attr, token)
 +    });
 +    if let Some(res) = hovered_lint {
 +        return Some(RangeInfo::new(original_token.text_range(), res));
 +    }
 +
 +    let result = descended
 +        .iter()
 +        .filter_map(|token| {
 +            let node = token.parent()?;
 +            let class = IdentClass::classify_token(sema, token)?;
 +            if let IdentClass::Operator(OperatorClass::Await(_)) = class {
 +                // It's better for us to fall back to the keyword hover here,
 +                // rendering poll is very confusing
 +                return None;
 +            }
 +            Some(class.definitions().into_iter().zip(iter::once(node).cycle()))
 +        })
 +        .flatten()
 +        .unique_by(|&(def, _)| def)
 +        .filter_map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config))
 +        .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
 +            acc.actions.extend(actions);
 +            acc.markup = Markup::from(format!("{}\n---\n{}", acc.markup, markup));
 +            acc
 +        });
 +
 +    if result.is_none() {
 +        // fallbacks, show keywords or types
 +
 +        let res = descended.iter().find_map(|token| render::keyword(sema, config, token));
 +        if let Some(res) = res {
 +            return Some(RangeInfo::new(original_token.text_range(), res));
 +        }
 +        let res = descended
 +            .iter()
 +            .find_map(|token| hover_type_fallback(sema, config, token, &original_token));
 +        if let Some(_) = res {
 +            return res;
 +        }
 +    }
 +    result.map(|mut res: HoverResult| {
 +        res.actions = dedupe_or_merge_hover_actions(res.actions);
 +        RangeInfo::new(original_token.text_range(), res)
 +    })
 +}
 +
 +pub(crate) fn hover_for_definition(
 +    sema: &Semantics<'_, RootDatabase>,
 +    file_id: FileId,
 +    definition: Definition,
 +    node: &SyntaxNode,
 +    config: &HoverConfig,
 +) -> Option<HoverResult> {
 +    let famous_defs = match &definition {
 +        Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(node)?.krate())),
 +        _ => None,
 +    };
 +    render::definition(sema.db, definition, famous_defs.as_ref(), config).map(|markup| {
 +        HoverResult {
 +            markup: render::process_markup(sema.db, definition, &markup, config),
 +            actions: show_implementations_action(sema.db, definition)
 +                .into_iter()
 +                .chain(show_fn_references_action(sema.db, definition))
 +                .chain(runnable_action(sema, definition, file_id))
 +                .chain(goto_type_action_for_def(sema.db, definition))
 +                .collect(),
 +        }
 +    })
 +}
 +
 +fn hover_ranged(
 +    file: &SyntaxNode,
 +    range: syntax::TextRange,
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &HoverConfig,
 +) -> Option<RangeInfo<HoverResult>> {
 +    // FIXME: make this work in attributes
 +    let expr_or_pat = file.covering_element(range).ancestors().find_map(|it| {
 +        match_ast! {
 +            match it {
 +                ast::Expr(expr) => Some(Either::Left(expr)),
 +                ast::Pat(pat) => Some(Either::Right(pat)),
 +                _ => None,
 +            }
 +        }
 +    })?;
 +    let res = match &expr_or_pat {
 +        Either::Left(ast::Expr::TryExpr(try_expr)) => render::try_expr(sema, config, try_expr),
 +        Either::Left(ast::Expr::PrefixExpr(prefix_expr))
 +            if prefix_expr.op_kind() == Some(ast::UnaryOp::Deref) =>
 +        {
 +            render::deref_expr(sema, config, prefix_expr)
 +        }
 +        _ => None,
 +    };
 +    let res = res.or_else(|| render::type_info(sema, config, &expr_or_pat));
 +    res.map(|it| {
 +        let range = match expr_or_pat {
 +            Either::Left(it) => it.syntax().text_range(),
 +            Either::Right(it) => it.syntax().text_range(),
 +        };
 +        RangeInfo::new(range, it)
 +    })
 +}
 +
 +fn hover_type_fallback(
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &HoverConfig,
 +    token: &SyntaxToken,
 +    original_token: &SyntaxToken,
 +) -> Option<RangeInfo<HoverResult>> {
 +    let node =
 +        token.parent_ancestors().take_while(|it| !ast::Item::can_cast(it.kind())).find(|n| {
 +            ast::Expr::can_cast(n.kind())
 +                || ast::Pat::can_cast(n.kind())
 +                || ast::Type::can_cast(n.kind())
 +        })?;
 +
 +    let expr_or_pat = match_ast! {
 +        match node {
 +            ast::Expr(it) => Either::Left(it),
 +            ast::Pat(it) => Either::Right(it),
 +            // If this node is a MACRO_CALL, it means that `descend_into_macros_many` failed to resolve.
 +            // (e.g expanding a builtin macro). So we give up here.
 +            ast::MacroCall(_it) => return None,
 +            _ => return None,
 +        }
 +    };
 +
 +    let res = render::type_info(sema, config, &expr_or_pat)?;
 +    let range = sema
 +        .original_range_opt(&node)
 +        .map(|frange| frange.range)
 +        .unwrap_or_else(|| original_token.text_range());
 +    Some(RangeInfo::new(range, res))
 +}
 +
 +fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
 +    fn to_action(nav_target: NavigationTarget) -> HoverAction {
 +        HoverAction::Implementation(FilePosition {
 +            file_id: nav_target.file_id,
 +            offset: nav_target.focus_or_full_range().start(),
 +        })
 +    }
 +
 +    let adt = match def {
 +        Definition::Trait(it) => return it.try_to_nav(db).map(to_action),
 +        Definition::Adt(it) => Some(it),
 +        Definition::SelfType(it) => it.self_ty(db).as_adt(),
 +        _ => None,
 +    }?;
 +    adt.try_to_nav(db).map(to_action)
 +}
 +
 +fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
 +    match def {
 +        Definition::Function(it) => it.try_to_nav(db).map(|nav_target| {
 +            HoverAction::Reference(FilePosition {
 +                file_id: nav_target.file_id,
 +                offset: nav_target.focus_or_full_range().start(),
 +            })
 +        }),
 +        _ => None,
 +    }
 +}
 +
 +fn runnable_action(
 +    sema: &hir::Semantics<'_, RootDatabase>,
 +    def: Definition,
 +    file_id: FileId,
 +) -> Option<HoverAction> {
 +    match def {
 +        Definition::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable),
 +        Definition::Function(func) => {
 +            let src = func.source(sema.db)?;
 +            if src.file_id != file_id.into() {
 +                cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment);
 +                cov_mark::hit!(hover_macro_generated_struct_fn_doc_attr);
 +                return None;
 +            }
 +
 +            runnable_fn(sema, func).map(HoverAction::Runnable)
 +        }
 +        _ => None,
 +    }
 +}
 +
 +fn goto_type_action_for_def(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
 +    let mut targets: Vec<hir::ModuleDef> = Vec::new();
 +    let mut push_new_def = |item: hir::ModuleDef| {
 +        if !targets.contains(&item) {
 +            targets.push(item);
 +        }
 +    };
 +
 +    if let Definition::GenericParam(hir::GenericParam::TypeParam(it)) = def {
 +        it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into()));
 +    } else {
 +        let ty = match def {
 +            Definition::Local(it) => it.ty(db),
 +            Definition::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db),
 +            Definition::Field(field) => field.ty(db),
 +            Definition::Function(function) => function.ret_type(db),
 +            _ => return None,
 +        };
 +
 +        walk_and_push_ty(db, &ty, &mut push_new_def);
 +    }
 +
 +    Some(HoverAction::goto_type_from_targets(db, targets))
 +}
 +
 +fn walk_and_push_ty(
 +    db: &RootDatabase,
 +    ty: &hir::Type,
 +    push_new_def: &mut dyn FnMut(hir::ModuleDef),
 +) {
 +    ty.walk(db, |t| {
 +        if let Some(adt) = t.as_adt() {
 +            push_new_def(adt.into());
 +        } else if let Some(trait_) = t.as_dyn_trait() {
 +            push_new_def(trait_.into());
 +        } else if let Some(traits) = t.as_impl_traits(db) {
 +            traits.for_each(|it| push_new_def(it.into()));
 +        } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
 +            push_new_def(trait_.into());
 +        }
 +    });
 +}
 +
 +fn dedupe_or_merge_hover_actions(actions: Vec<HoverAction>) -> Vec<HoverAction> {
 +    let mut deduped_actions = Vec::with_capacity(actions.len());
 +    let mut go_to_type_targets = FxIndexSet::default();
 +
 +    let mut seen_implementation = false;
 +    let mut seen_reference = false;
 +    let mut seen_runnable = false;
 +    for action in actions {
 +        match action {
 +            HoverAction::GoToType(targets) => {
 +                go_to_type_targets.extend(targets);
 +            }
 +            HoverAction::Implementation(..) => {
 +                if !seen_implementation {
 +                    seen_implementation = true;
 +                    deduped_actions.push(action);
 +                }
 +            }
 +            HoverAction::Reference(..) => {
 +                if !seen_reference {
 +                    seen_reference = true;
 +                    deduped_actions.push(action);
 +                }
 +            }
 +            HoverAction::Runnable(..) => {
 +                if !seen_runnable {
 +                    seen_runnable = true;
 +                    deduped_actions.push(action);
 +                }
 +            }
 +        };
 +    }
 +
 +    if !go_to_type_targets.is_empty() {
 +        deduped_actions.push(HoverAction::GoToType(go_to_type_targets.into_iter().collect()));
 +    }
 +
 +    deduped_actions
 +}
index 6c50a4e6adc0ef663856331f022dcc63000e0f77,0000000000000000000000000000000000000000..d52adaee535f99371b3ca9547ef380fb9cfa65d6
mode 100644,000000..100644
--- /dev/null
@@@ -1,563 -1,0 +1,563 @@@
-     if !token.kind().is_keyword() || !config.documentation.is_some() {
 +//! Logic for rendering the different hover messages
 +use std::fmt::Display;
 +
 +use either::Either;
 +use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HirDisplay, Semantics, TypeInfo};
 +use ide_db::{
 +    base_db::SourceDatabase,
 +    defs::Definition,
 +    famous_defs::FamousDefs,
 +    generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
 +    RootDatabase,
 +};
 +use itertools::Itertools;
 +use stdx::format_to;
 +use syntax::{
 +    algo, ast, match_ast, AstNode, Direction,
 +    SyntaxKind::{LET_EXPR, LET_STMT},
 +    SyntaxToken, T,
 +};
 +
 +use crate::{
 +    doc_links::{remove_links, rewrite_links},
 +    hover::walk_and_push_ty,
 +    markdown_remove::remove_markdown,
 +    HoverAction, HoverConfig, HoverResult, Markup,
 +};
 +
 +pub(super) fn type_info(
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &HoverConfig,
 +    expr_or_pat: &Either<ast::Expr, ast::Pat>,
 +) -> Option<HoverResult> {
 +    let TypeInfo { original, adjusted } = match expr_or_pat {
 +        Either::Left(expr) => sema.type_of_expr(expr)?,
 +        Either::Right(pat) => sema.type_of_pat(pat)?,
 +    };
 +
 +    let mut res = HoverResult::default();
 +    let mut targets: Vec<hir::ModuleDef> = Vec::new();
 +    let mut push_new_def = |item: hir::ModuleDef| {
 +        if !targets.contains(&item) {
 +            targets.push(item);
 +        }
 +    };
 +    walk_and_push_ty(sema.db, &original, &mut push_new_def);
 +
 +    res.markup = if let Some(adjusted_ty) = adjusted {
 +        walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def);
 +        let original = original.display(sema.db).to_string();
 +        let adjusted = adjusted_ty.display(sema.db).to_string();
 +        let static_text_diff_len = "Coerced to: ".len() - "Type: ".len();
 +        format!(
 +            "{bt_start}Type: {:>apad$}\nCoerced to: {:>opad$}\n{bt_end}",
 +            original,
 +            adjusted,
 +            apad = static_text_diff_len + adjusted.len().max(original.len()),
 +            opad = original.len(),
 +            bt_start = if config.markdown() { "```text\n" } else { "" },
 +            bt_end = if config.markdown() { "```\n" } else { "" }
 +        )
 +        .into()
 +    } else {
 +        if config.markdown() {
 +            Markup::fenced_block(&original.display(sema.db))
 +        } else {
 +            original.display(sema.db).to_string().into()
 +        }
 +    };
 +    res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
 +    Some(res)
 +}
 +
 +pub(super) fn try_expr(
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &HoverConfig,
 +    try_expr: &ast::TryExpr,
 +) -> Option<HoverResult> {
 +    let inner_ty = sema.type_of_expr(&try_expr.expr()?)?.original;
 +    let mut ancestors = try_expr.syntax().ancestors();
 +    let mut body_ty = loop {
 +        let next = ancestors.next()?;
 +        break match_ast! {
 +            match next {
 +                ast::Fn(fn_) => sema.to_def(&fn_)?.ret_type(sema.db),
 +                ast::Item(__) => return None,
 +                ast::ClosureExpr(closure) => sema.type_of_expr(&closure.body()?)?.original,
 +                ast::BlockExpr(block_expr) => if matches!(block_expr.modifier(), Some(ast::BlockModifier::Async(_) | ast::BlockModifier::Try(_)| ast::BlockModifier::Const(_))) {
 +                    sema.type_of_expr(&block_expr.into())?.original
 +                } else {
 +                    continue;
 +                },
 +                _ => continue,
 +            }
 +        };
 +    };
 +
 +    if inner_ty == body_ty {
 +        return None;
 +    }
 +
 +    let mut inner_ty = inner_ty;
 +    let mut s = "Try Target".to_owned();
 +
 +    let adts = inner_ty.as_adt().zip(body_ty.as_adt());
 +    if let Some((hir::Adt::Enum(inner), hir::Adt::Enum(body))) = adts {
 +        let famous_defs = FamousDefs(sema, sema.scope(try_expr.syntax())?.krate());
 +        // special case for two options, there is no value in showing them
 +        if let Some(option_enum) = famous_defs.core_option_Option() {
 +            if inner == option_enum && body == option_enum {
 +                cov_mark::hit!(hover_try_expr_opt_opt);
 +                return None;
 +            }
 +        }
 +
 +        // special case two results to show the error variants only
 +        if let Some(result_enum) = famous_defs.core_result_Result() {
 +            if inner == result_enum && body == result_enum {
 +                let error_type_args =
 +                    inner_ty.type_arguments().nth(1).zip(body_ty.type_arguments().nth(1));
 +                if let Some((inner, body)) = error_type_args {
 +                    inner_ty = inner;
 +                    body_ty = body;
 +                    s = "Try Error".to_owned();
 +                }
 +            }
 +        }
 +    }
 +
 +    let mut res = HoverResult::default();
 +
 +    let mut targets: Vec<hir::ModuleDef> = Vec::new();
 +    let mut push_new_def = |item: hir::ModuleDef| {
 +        if !targets.contains(&item) {
 +            targets.push(item);
 +        }
 +    };
 +    walk_and_push_ty(sema.db, &inner_ty, &mut push_new_def);
 +    walk_and_push_ty(sema.db, &body_ty, &mut push_new_def);
 +    res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
 +
 +    let inner_ty = inner_ty.display(sema.db).to_string();
 +    let body_ty = body_ty.display(sema.db).to_string();
 +    let ty_len_max = inner_ty.len().max(body_ty.len());
 +
 +    let l = "Propagated as: ".len() - " Type: ".len();
 +    let static_text_len_diff = l as isize - s.len() as isize;
 +    let tpad = static_text_len_diff.max(0) as usize;
 +    let ppad = static_text_len_diff.min(0).abs() as usize;
 +
 +    res.markup = format!(
 +        "{bt_start}{} Type: {:>pad0$}\nPropagated as: {:>pad1$}\n{bt_end}",
 +        s,
 +        inner_ty,
 +        body_ty,
 +        pad0 = ty_len_max + tpad,
 +        pad1 = ty_len_max + ppad,
 +        bt_start = if config.markdown() { "```text\n" } else { "" },
 +        bt_end = if config.markdown() { "```\n" } else { "" }
 +    )
 +    .into();
 +    Some(res)
 +}
 +
 +pub(super) fn deref_expr(
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &HoverConfig,
 +    deref_expr: &ast::PrefixExpr,
 +) -> Option<HoverResult> {
 +    let inner_ty = sema.type_of_expr(&deref_expr.expr()?)?.original;
 +    let TypeInfo { original, adjusted } =
 +        sema.type_of_expr(&ast::Expr::from(deref_expr.clone()))?;
 +
 +    let mut res = HoverResult::default();
 +    let mut targets: Vec<hir::ModuleDef> = Vec::new();
 +    let mut push_new_def = |item: hir::ModuleDef| {
 +        if !targets.contains(&item) {
 +            targets.push(item);
 +        }
 +    };
 +    walk_and_push_ty(sema.db, &inner_ty, &mut push_new_def);
 +    walk_and_push_ty(sema.db, &original, &mut push_new_def);
 +
 +    res.markup = if let Some(adjusted_ty) = adjusted {
 +        walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def);
 +        let original = original.display(sema.db).to_string();
 +        let adjusted = adjusted_ty.display(sema.db).to_string();
 +        let inner = inner_ty.display(sema.db).to_string();
 +        let type_len = "To type: ".len();
 +        let coerced_len = "Coerced to: ".len();
 +        let deref_len = "Dereferenced from: ".len();
 +        let max_len = (original.len() + type_len)
 +            .max(adjusted.len() + coerced_len)
 +            .max(inner.len() + deref_len);
 +        format!(
 +            "{bt_start}Dereferenced from: {:>ipad$}\nTo type: {:>apad$}\nCoerced to: {:>opad$}\n{bt_end}",
 +            inner,
 +            original,
 +            adjusted,
 +            ipad = max_len - deref_len,
 +            apad = max_len - type_len,
 +            opad = max_len - coerced_len,
 +            bt_start = if config.markdown() { "```text\n" } else { "" },
 +            bt_end = if config.markdown() { "```\n" } else { "" }
 +        )
 +        .into()
 +    } else {
 +        let original = original.display(sema.db).to_string();
 +        let inner = inner_ty.display(sema.db).to_string();
 +        let type_len = "To type: ".len();
 +        let deref_len = "Dereferenced from: ".len();
 +        let max_len = (original.len() + type_len).max(inner.len() + deref_len);
 +        format!(
 +            "{bt_start}Dereferenced from: {:>ipad$}\nTo type: {:>apad$}\n{bt_end}",
 +            inner,
 +            original,
 +            ipad = max_len - deref_len,
 +            apad = max_len - type_len,
 +            bt_start = if config.markdown() { "```text\n" } else { "" },
 +            bt_end = if config.markdown() { "```\n" } else { "" }
 +        )
 +        .into()
 +    };
 +    res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
 +
 +    Some(res)
 +}
 +
 +pub(super) fn keyword(
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &HoverConfig,
 +    token: &SyntaxToken,
 +) -> Option<HoverResult> {
++    if !token.kind().is_keyword() || !config.documentation.is_some() || !config.keywords {
 +        return None;
 +    }
 +    let parent = token.parent()?;
 +    let famous_defs = FamousDefs(sema, sema.scope(&parent)?.krate());
 +
 +    let KeywordHint { description, keyword_mod, actions } = keyword_hints(sema, token, parent);
 +
 +    let doc_owner = find_std_module(&famous_defs, &keyword_mod)?;
 +    let docs = doc_owner.attrs(sema.db).docs()?;
 +    let markup = process_markup(
 +        sema.db,
 +        Definition::Module(doc_owner),
 +        &markup(Some(docs.into()), description, None)?,
 +        config,
 +    );
 +    Some(HoverResult { markup, actions })
 +}
 +
 +pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option<HoverResult> {
 +    let (path, tt) = attr.as_simple_call()?;
 +    if !tt.syntax().text_range().contains(token.text_range().start()) {
 +        return None;
 +    }
 +    let (is_clippy, lints) = match &*path {
 +        "feature" => (false, FEATURES),
 +        "allow" | "deny" | "forbid" | "warn" => {
 +            let is_clippy = algo::non_trivia_sibling(token.clone().into(), Direction::Prev)
 +                .filter(|t| t.kind() == T![:])
 +                .and_then(|t| algo::non_trivia_sibling(t, Direction::Prev))
 +                .filter(|t| t.kind() == T![:])
 +                .and_then(|t| algo::non_trivia_sibling(t, Direction::Prev))
 +                .map_or(false, |t| {
 +                    t.kind() == T![ident] && t.into_token().map_or(false, |t| t.text() == "clippy")
 +                });
 +            if is_clippy {
 +                (true, CLIPPY_LINTS)
 +            } else {
 +                (false, DEFAULT_LINTS)
 +            }
 +        }
 +        _ => return None,
 +    };
 +
 +    let tmp;
 +    let needle = if is_clippy {
 +        tmp = format!("clippy::{}", token.text());
 +        &tmp
 +    } else {
 +        &*token.text()
 +    };
 +
 +    let lint =
 +        lints.binary_search_by_key(&needle, |lint| lint.label).ok().map(|idx| &lints[idx])?;
 +    Some(HoverResult {
 +        markup: Markup::from(format!("```\n{}\n```\n___\n\n{}", lint.label, lint.description)),
 +        ..Default::default()
 +    })
 +}
 +
 +pub(super) fn process_markup(
 +    db: &RootDatabase,
 +    def: Definition,
 +    markup: &Markup,
 +    config: &HoverConfig,
 +) -> Markup {
 +    let markup = markup.as_str();
 +    let markup = if !config.markdown() {
 +        remove_markdown(markup)
 +    } else if config.links_in_hover {
 +        rewrite_links(db, markup, def)
 +    } else {
 +        remove_links(markup)
 +    };
 +    Markup::from(markup)
 +}
 +
 +fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> {
 +    match def {
 +        Definition::Field(f) => Some(f.parent_def(db).name(db)),
 +        Definition::Local(l) => l.parent(db).name(db),
 +        Definition::Function(f) => match f.as_assoc_item(db)?.container(db) {
 +            hir::AssocItemContainer::Trait(t) => Some(t.name(db)),
 +            hir::AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)),
 +        },
 +        Definition::Variant(e) => Some(e.parent_enum(db).name(db)),
 +        _ => None,
 +    }
 +    .map(|name| name.to_string())
 +}
 +
 +pub(super) fn path(db: &RootDatabase, module: hir::Module, item_name: Option<String>) -> String {
 +    let crate_name =
 +        db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string());
 +    let module_path = module
 +        .path_to_root(db)
 +        .into_iter()
 +        .rev()
 +        .flat_map(|it| it.name(db).map(|name| name.to_string()));
 +    crate_name.into_iter().chain(module_path).chain(item_name).join("::")
 +}
 +
 +pub(super) fn definition(
 +    db: &RootDatabase,
 +    def: Definition,
 +    famous_defs: Option<&FamousDefs<'_, '_>>,
 +    config: &HoverConfig,
 +) -> Option<Markup> {
 +    let mod_path = definition_mod_path(db, &def);
 +    let (label, docs) = match def {
 +        Definition::Macro(it) => label_and_docs(db, it),
 +        Definition::Field(it) => label_and_docs(db, it),
 +        Definition::Module(it) => label_and_docs(db, it),
 +        Definition::Function(it) => label_and_docs(db, it),
 +        Definition::Adt(it) => label_and_docs(db, it),
 +        Definition::Variant(it) => label_and_docs(db, it),
 +        Definition::Const(it) => label_value_and_docs(db, it, |it| {
 +            let body = it.eval(db);
 +            match body {
 +                Ok(x) => Some(format!("{}", x)),
 +                Err(_) => it.value(db).map(|x| format!("{}", x)),
 +            }
 +        }),
 +        Definition::Static(it) => label_value_and_docs(db, it, |it| it.value(db)),
 +        Definition::Trait(it) => label_and_docs(db, it),
 +        Definition::TypeAlias(it) => label_and_docs(db, it),
 +        Definition::BuiltinType(it) => {
 +            return famous_defs
 +                .and_then(|fd| builtin(fd, it))
 +                .or_else(|| Some(Markup::fenced_block(&it.name())))
 +        }
 +        Definition::Local(it) => return local(db, it),
 +        Definition::SelfType(impl_def) => {
 +            impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))?
 +        }
 +        Definition::GenericParam(it) => label_and_docs(db, it),
 +        Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))),
 +        // FIXME: We should be able to show more info about these
 +        Definition::BuiltinAttr(it) => return render_builtin_attr(db, it),
 +        Definition::ToolModule(it) => return Some(Markup::fenced_block(&it.name(db))),
 +        Definition::DeriveHelper(it) => (format!("derive_helper {}", it.name(db)), None),
 +    };
 +
 +    let docs = match config.documentation {
 +        Some(_) => docs.or_else(|| {
 +            // docs are missing, for assoc items of trait impls try to fall back to the docs of the
 +            // original item of the trait
 +            let assoc = def.as_assoc_item(db)?;
 +            let trait_ = assoc.containing_trait_impl(db)?;
 +            let name = Some(assoc.name(db)?);
 +            let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?;
 +            item.docs(db)
 +        }),
 +        None => None,
 +    };
 +    let docs = docs.filter(|_| config.documentation.is_some()).map(Into::into);
 +    markup(docs, label, mod_path)
 +}
 +
 +fn render_builtin_attr(db: &RootDatabase, attr: hir::BuiltinAttr) -> Option<Markup> {
 +    let name = attr.name(db);
 +    let desc = format!("#[{}]", name);
 +
 +    let AttributeTemplate { word, list, name_value_str } = match attr.template(db) {
 +        Some(template) => template,
 +        None => return Some(Markup::fenced_block(&attr.name(db))),
 +    };
 +    let mut docs = "Valid forms are:".to_owned();
 +    if word {
 +        format_to!(docs, "\n - #\\[{}]", name);
 +    }
 +    if let Some(list) = list {
 +        format_to!(docs, "\n - #\\[{}({})]", name, list);
 +    }
 +    if let Some(name_value_str) = name_value_str {
 +        format_to!(docs, "\n - #\\[{} = {}]", name, name_value_str);
 +    }
 +    markup(Some(docs.replace('*', "\\*")), desc, None)
 +}
 +
 +fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>)
 +where
 +    D: HasAttrs + HirDisplay,
 +{
 +    let label = def.display(db).to_string();
 +    let docs = def.attrs(db).docs();
 +    (label, docs)
 +}
 +
 +fn label_value_and_docs<D, E, V>(
 +    db: &RootDatabase,
 +    def: D,
 +    value_extractor: E,
 +) -> (String, Option<hir::Documentation>)
 +where
 +    D: HasAttrs + HirDisplay,
 +    E: Fn(&D) -> Option<V>,
 +    V: Display,
 +{
 +    let label = if let Some(value) = value_extractor(&def) {
 +        format!("{} = {}", def.display(db), value)
 +    } else {
 +        def.display(db).to_string()
 +    };
 +    let docs = def.attrs(db).docs();
 +    (label, docs)
 +}
 +
 +fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
 +    if let Definition::GenericParam(_) = def {
 +        return None;
 +    }
 +    def.module(db).map(|module| path(db, module, definition_owner_name(db, def)))
 +}
 +
 +fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Option<Markup> {
 +    let mut buf = String::new();
 +
 +    if let Some(mod_path) = mod_path {
 +        if !mod_path.is_empty() {
 +            format_to!(buf, "```rust\n{}\n```\n\n", mod_path);
 +        }
 +    }
 +    format_to!(buf, "```rust\n{}\n```", desc);
 +
 +    if let Some(doc) = docs {
 +        format_to!(buf, "\n___\n\n{}", doc);
 +    }
 +    Some(buf.into())
 +}
 +
 +fn builtin(famous_defs: &FamousDefs<'_, '_>, builtin: hir::BuiltinType) -> Option<Markup> {
 +    // std exposes prim_{} modules with docstrings on the root to document the builtins
 +    let primitive_mod = format!("prim_{}", builtin.name());
 +    let doc_owner = find_std_module(famous_defs, &primitive_mod)?;
 +    let docs = doc_owner.attrs(famous_defs.0.db).docs()?;
 +    markup(Some(docs.into()), builtin.name().to_string(), None)
 +}
 +
 +fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option<hir::Module> {
 +    let db = famous_defs.0.db;
 +    let std_crate = famous_defs.std()?;
 +    let std_root_module = std_crate.root_module(db);
 +    std_root_module
 +        .children(db)
 +        .find(|module| module.name(db).map_or(false, |module| module.to_string() == name))
 +}
 +
 +fn local(db: &RootDatabase, it: hir::Local) -> Option<Markup> {
 +    let ty = it.ty(db);
 +    let ty = ty.display_truncated(db, None);
 +    let is_mut = if it.is_mut(db) { "mut " } else { "" };
 +    let desc = match it.source(db).value {
 +        Either::Left(ident) => {
 +            let name = it.name(db);
 +            let let_kw = if ident
 +                .syntax()
 +                .parent()
 +                .map_or(false, |p| p.kind() == LET_STMT || p.kind() == LET_EXPR)
 +            {
 +                "let "
 +            } else {
 +                ""
 +            };
 +            format!("{}{}{}: {}", let_kw, is_mut, name, ty)
 +        }
 +        Either::Right(_) => format!("{}self: {}", is_mut, ty),
 +    };
 +    markup(None, desc, None)
 +}
 +
 +struct KeywordHint {
 +    description: String,
 +    keyword_mod: String,
 +    actions: Vec<HoverAction>,
 +}
 +
 +impl KeywordHint {
 +    fn new(description: String, keyword_mod: String) -> Self {
 +        Self { description, keyword_mod, actions: Vec::default() }
 +    }
 +}
 +
 +fn keyword_hints(
 +    sema: &Semantics<'_, RootDatabase>,
 +    token: &SyntaxToken,
 +    parent: syntax::SyntaxNode,
 +) -> KeywordHint {
 +    match token.kind() {
 +        T![await] | T![loop] | T![match] | T![unsafe] | T![as] | T![try] | T![if] | T![else] => {
 +            let keyword_mod = format!("{}_keyword", token.text());
 +
 +            match ast::Expr::cast(parent).and_then(|site| sema.type_of_expr(&site)) {
 +                // ignore the unit type ()
 +                Some(ty) if !ty.adjusted.as_ref().unwrap_or(&ty.original).is_unit() => {
 +                    let mut targets: Vec<hir::ModuleDef> = Vec::new();
 +                    let mut push_new_def = |item: hir::ModuleDef| {
 +                        if !targets.contains(&item) {
 +                            targets.push(item);
 +                        }
 +                    };
 +                    walk_and_push_ty(sema.db, &ty.original, &mut push_new_def);
 +
 +                    let ty = ty.adjusted();
 +                    let description = format!("{}: {}", token.text(), ty.display(sema.db));
 +
 +                    KeywordHint {
 +                        description,
 +                        keyword_mod,
 +                        actions: vec![HoverAction::goto_type_from_targets(sema.db, targets)],
 +                    }
 +                }
 +                _ => KeywordHint {
 +                    description: token.text().to_string(),
 +                    keyword_mod,
 +                    actions: Vec::new(),
 +                },
 +            }
 +        }
 +        T![fn] => {
 +            let module = match ast::FnPtrType::cast(parent) {
 +                // treat fn keyword inside function pointer type as primitive
 +                Some(_) => format!("prim_{}", token.text()),
 +                None => format!("{}_keyword", token.text()),
 +            };
 +            KeywordHint::new(token.text().to_string(), module)
 +        }
 +        T![Self] => KeywordHint::new(token.text().to_string(), "self_upper_keyword".into()),
 +        _ => KeywordHint::new(token.text().to_string(), format!("{}_keyword", token.text())),
 +    }
 +}
index c6274264b8f1a55770cd1a478bc8559a5c7ff9c3,0000000000000000000000000000000000000000..685eb4521ebdaf7f10ee93be5f92d346d76f2c1d
mode 100644,000000..100644
--- /dev/null
@@@ -1,5087 -1,0 +1,5115 @@@
-             &HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::Markdown) },
 +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) },
++            &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: false, documentation: Some(HoverDocFormat::Markdown) },
++            &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: true, documentation: Some(HoverDocFormat::PlainText) },
++            &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::Markdown) },
++            &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: false, documentation: Some(HoverDocFormat::Markdown) },
++            &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) },
++            &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> {
 +    /// 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() {
 +    // 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
 +        "#]],
 +    );
 +}
 +
 +#[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>
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[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
 +            ```
 +        "#]],
 +    );
 +}
index cc79ee55b7dac2be43bf41ae084af390ae198b0e,0000000000000000000000000000000000000000..9e5eb909508f624e051042623de24232070a78ed
mode 100644,000000..100644
--- /dev/null
@@@ -1,321 -1,0 +1,324 @@@
-         let hover_config =
-             HoverConfig { links_in_hover: true, documentation: Some(HoverDocFormat::Markdown) };
 +//! 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);
 +        } else {
 +            continue;
 +        };
 +    }
 +    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 bf0835ed7e0d3a1f2a5f675e2f67754483e6d5ab,0000000000000000000000000000000000000000..d2bbbf6d26ab4cc9e23893fdad52de346ba88dac
mode 100644,000000..100644
--- /dev/null
@@@ -1,26 -1,0 +1,30 @@@
- use hir::{Function, Semantics};
++use hir::{DefWithBody, Semantics};
 +use ide_db::base_db::FilePosition;
 +use ide_db::RootDatabase;
 +use syntax::{algo::find_node_at_offset, ast, AstNode};
 +
 +// Feature: View Hir
 +//
 +// |===
 +// | Editor  | Action Name
 +//
 +// | VS Code | **rust-analyzer: View Hir**
 +// |===
 +// image::https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif[]
 +pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String {
 +    body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_string())
 +}
 +
 +fn body_hir(db: &RootDatabase, position: FilePosition) -> Option<String> {
 +    let sema = Semantics::new(db);
 +    let source_file = sema.parse(position.file_id);
 +
-     let function = find_node_at_offset::<ast::Fn>(source_file.syntax(), position.offset)?;
-     let function: Function = sema.to_def(&function)?;
-     Some(function.debug_hir(db))
++    let item = find_node_at_offset::<ast::Item>(source_file.syntax(), position.offset)?;
++    let def: DefWithBody = match item {
++        ast::Item::Fn(it) => sema.to_def(&it)?.into(),
++        ast::Item::Const(it) => sema.to_def(&it)?.into(),
++        ast::Item::Static(it) => sema.to_def(&it)?.into(),
++        _ => return None,
++    };
++    Some(def.debug_hir(db))
 +}
index 5020e9abaf31502ea80fdecc6971d9ee1b712ea9,0000000000000000000000000000000000000000..c1aa14d6b7e74d715920d9a2dea2992bd0cbf4e3
mode 100644,000000..100644
--- /dev/null
@@@ -1,914 -1,0 +1,914 @@@
-     /// Number of tokens of seperator parsed
 +//! An NFA-based parser, which is porting from rustc mbe parsing code
 +//!
 +//! See <https://github.com/rust-lang/rust/blob/70b18bc2cbac4712020019f5bf57c00905373205/compiler/rustc_expand/src/mbe/macro_parser.rs>
 +//! Here is a quick intro to how the parser works, copied from rustc:
 +//!
 +//! A 'position' is a dot in the middle of a matcher, usually represented as a
 +//! dot. For example `· a $( a )* a b` is a position, as is `a $( · a )* a b`.
 +//!
 +//! The parser walks through the input a character at a time, maintaining a list
 +//! of threads consistent with the current position in the input string: `cur_items`.
 +//!
 +//! As it processes them, it fills up `eof_items` with threads that would be valid if
 +//! the macro invocation is now over, `bb_items` with threads that are waiting on
 +//! a Rust non-terminal like `$e:expr`, and `next_items` with threads that are waiting
 +//! on a particular token. Most of the logic concerns moving the · through the
 +//! repetitions indicated by Kleene stars. The rules for moving the · without
 +//! consuming any input are called epsilon transitions. It only advances or calls
 +//! out to the real Rust parser when no `cur_items` threads remain.
 +//!
 +//! Example:
 +//!
 +//! ```text, ignore
 +//! Start parsing a a a a b against [· a $( a )* a b].
 +//!
 +//! Remaining input: a a a a b
 +//! next: [· a $( a )* a b]
 +//!
 +//! - - - Advance over an a. - - -
 +//!
 +//! Remaining input: a a a b
 +//! cur: [a · $( a )* a b]
 +//! Descend/Skip (first item).
 +//! next: [a $( · a )* a b]  [a $( a )* · a b].
 +//!
 +//! - - - Advance over an a. - - -
 +//!
 +//! Remaining input: a a b
 +//! cur: [a $( a · )* a b]  [a $( a )* a · b]
 +//! Follow epsilon transition: Finish/Repeat (first item)
 +//! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
 +//!
 +//! - - - Advance over an a. - - - (this looks exactly like the last step)
 +//!
 +//! Remaining input: a b
 +//! cur: [a $( a · )* a b]  [a $( a )* a · b]
 +//! Follow epsilon transition: Finish/Repeat (first item)
 +//! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
 +//!
 +//! - - - Advance over an a. - - - (this looks exactly like the last step)
 +//!
 +//! Remaining input: b
 +//! cur: [a $( a · )* a b]  [a $( a )* a · b]
 +//! Follow epsilon transition: Finish/Repeat (first item)
 +//! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
 +//!
 +//! - - - Advance over a b. - - -
 +//!
 +//! Remaining input: ''
 +//! eof: [a $( a )* a b ·]
 +//! ```
 +
 +use std::rc::Rc;
 +
 +use smallvec::{smallvec, SmallVec};
 +use syntax::SmolStr;
 +
 +use crate::{
 +    expander::{Binding, Bindings, ExpandResult, Fragment},
 +    parser::{Op, RepeatKind, Separator},
 +    tt_iter::TtIter,
 +    ExpandError, MetaTemplate,
 +};
 +
 +impl Bindings {
 +    fn push_optional(&mut self, name: &SmolStr) {
 +        // FIXME: Do we have a better way to represent an empty token ?
 +        // Insert an empty subtree for empty token
 +        let tt = tt::Subtree::default().into();
 +        self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt)));
 +    }
 +
 +    fn push_empty(&mut self, name: &SmolStr) {
 +        self.inner.insert(name.clone(), Binding::Empty);
 +    }
 +
 +    fn bindings(&self) -> impl Iterator<Item = &Binding> {
 +        self.inner.values()
 +    }
 +}
 +
 +#[derive(Clone, Debug, Default, PartialEq, Eq)]
 +pub(super) struct Match {
 +    pub(super) bindings: Bindings,
 +    /// We currently just keep the first error and count the rest to compare matches.
 +    pub(super) err: Option<ExpandError>,
 +    pub(super) err_count: usize,
 +    /// How many top-level token trees were left to match.
 +    pub(super) unmatched_tts: usize,
 +    /// The number of bound variables
 +    pub(super) bound_count: usize,
 +}
 +
 +impl Match {
 +    fn add_err(&mut self, err: ExpandError) {
 +        let prev_err = self.err.take();
 +        self.err = prev_err.or(Some(err));
 +        self.err_count += 1;
 +    }
 +}
 +
 +/// Matching errors are added to the `Match`.
 +pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree) -> Match {
 +    let mut res = match_loop(pattern, input);
 +    res.bound_count = count(res.bindings.bindings());
 +    return res;
 +
 +    fn count<'a>(bindings: impl Iterator<Item = &'a Binding>) -> usize {
 +        bindings
 +            .map(|it| match it {
 +                Binding::Fragment(_) => 1,
 +                Binding::Empty => 1,
 +                Binding::Nested(it) => count(it.iter()),
 +            })
 +            .sum()
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +enum BindingKind {
 +    Empty(SmolStr),
 +    Optional(SmolStr),
 +    Fragment(SmolStr, Fragment),
 +    Nested(usize, usize),
 +}
 +
 +#[derive(Debug, Clone)]
 +struct BindingsIdx(usize, usize);
 +
 +#[derive(Debug, Clone)]
 +enum LinkNode<T> {
 +    Node(T),
 +    Parent { idx: usize, len: usize },
 +}
 +
 +#[derive(Default)]
 +struct BindingsBuilder {
 +    nodes: Vec<Vec<LinkNode<Rc<BindingKind>>>>,
 +    nested: Vec<Vec<LinkNode<usize>>>,
 +}
 +
 +impl BindingsBuilder {
 +    fn alloc(&mut self) -> BindingsIdx {
 +        let idx = self.nodes.len();
 +        self.nodes.push(Vec::new());
 +        let nidx = self.nested.len();
 +        self.nested.push(Vec::new());
 +        BindingsIdx(idx, nidx)
 +    }
 +
 +    fn copy(&mut self, bindings: &BindingsIdx) -> BindingsIdx {
 +        let idx = copy_parent(bindings.0, &mut self.nodes);
 +        let nidx = copy_parent(bindings.1, &mut self.nested);
 +        return BindingsIdx(idx, nidx);
 +
 +        fn copy_parent<T>(idx: usize, target: &mut Vec<Vec<LinkNode<T>>>) -> usize
 +        where
 +            T: Clone,
 +        {
 +            let new_idx = target.len();
 +            let len = target[idx].len();
 +            if len < 4 {
 +                target.push(target[idx].clone())
 +            } else {
 +                target.push(vec![LinkNode::Parent { idx, len }]);
 +            }
 +            new_idx
 +        }
 +    }
 +
 +    fn push_empty(&mut self, idx: &mut BindingsIdx, var: &SmolStr) {
 +        self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Empty(var.clone()))));
 +    }
 +
 +    fn push_optional(&mut self, idx: &mut BindingsIdx, var: &SmolStr) {
 +        self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Optional(var.clone()))));
 +    }
 +
 +    fn push_fragment(&mut self, idx: &mut BindingsIdx, var: &SmolStr, fragment: Fragment) {
 +        self.nodes[idx.0]
 +            .push(LinkNode::Node(Rc::new(BindingKind::Fragment(var.clone(), fragment))));
 +    }
 +
 +    fn push_nested(&mut self, parent: &mut BindingsIdx, child: &BindingsIdx) {
 +        let BindingsIdx(idx, nidx) = self.copy(child);
 +        self.nodes[parent.0].push(LinkNode::Node(Rc::new(BindingKind::Nested(idx, nidx))));
 +    }
 +
 +    fn push_default(&mut self, idx: &mut BindingsIdx) {
 +        self.nested[idx.1].push(LinkNode::Node(idx.0));
 +        let new_idx = self.nodes.len();
 +        self.nodes.push(Vec::new());
 +        idx.0 = new_idx;
 +    }
 +
 +    fn build(self, idx: &BindingsIdx) -> Bindings {
 +        let mut bindings = Bindings::default();
 +        self.build_inner(&mut bindings, &self.nodes[idx.0]);
 +        bindings
 +    }
 +
 +    fn build_inner(&self, bindings: &mut Bindings, link_nodes: &[LinkNode<Rc<BindingKind>>]) {
 +        let mut nodes = Vec::new();
 +        self.collect_nodes(link_nodes, &mut nodes);
 +
 +        for cmd in nodes {
 +            match &**cmd {
 +                BindingKind::Empty(name) => {
 +                    bindings.push_empty(name);
 +                }
 +                BindingKind::Optional(name) => {
 +                    bindings.push_optional(name);
 +                }
 +                BindingKind::Fragment(name, fragment) => {
 +                    bindings.inner.insert(name.clone(), Binding::Fragment(fragment.clone()));
 +                }
 +                BindingKind::Nested(idx, nested_idx) => {
 +                    let mut nested_nodes = Vec::new();
 +                    self.collect_nested(*idx, *nested_idx, &mut nested_nodes);
 +
 +                    for (idx, iter) in nested_nodes.into_iter().enumerate() {
 +                        for (key, value) in &iter.inner {
 +                            let bindings = bindings
 +                                .inner
 +                                .entry(key.clone())
 +                                .or_insert_with(|| Binding::Nested(Vec::new()));
 +
 +                            if let Binding::Nested(it) = bindings {
 +                                // insert empty nested bindings before this one
 +                                while it.len() < idx {
 +                                    it.push(Binding::Nested(Vec::new()));
 +                                }
 +                                it.push(value.clone());
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn collect_nested_ref<'a>(
 +        &'a self,
 +        id: usize,
 +        len: usize,
 +        nested_refs: &mut Vec<&'a Vec<LinkNode<Rc<BindingKind>>>>,
 +    ) {
 +        self.nested[id].iter().take(len).for_each(|it| match it {
 +            LinkNode::Node(id) => nested_refs.push(&self.nodes[*id]),
 +            LinkNode::Parent { idx, len } => self.collect_nested_ref(*idx, *len, nested_refs),
 +        });
 +    }
 +
 +    fn collect_nested(&self, idx: usize, nested_idx: usize, nested: &mut Vec<Bindings>) {
 +        let last = &self.nodes[idx];
 +        let mut nested_refs = Vec::new();
 +        self.nested[nested_idx].iter().for_each(|it| match *it {
 +            LinkNode::Node(idx) => nested_refs.push(&self.nodes[idx]),
 +            LinkNode::Parent { idx, len } => self.collect_nested_ref(idx, len, &mut nested_refs),
 +        });
 +        nested_refs.push(last);
 +
 +        nested_refs.into_iter().for_each(|iter| {
 +            let mut child_bindings = Bindings::default();
 +            self.build_inner(&mut child_bindings, iter);
 +            nested.push(child_bindings)
 +        })
 +    }
 +
 +    fn collect_nodes_ref<'a>(
 +        &'a self,
 +        id: usize,
 +        len: usize,
 +        nodes: &mut Vec<&'a Rc<BindingKind>>,
 +    ) {
 +        self.nodes[id].iter().take(len).for_each(|it| match it {
 +            LinkNode::Node(it) => nodes.push(it),
 +            LinkNode::Parent { idx, len } => self.collect_nodes_ref(*idx, *len, nodes),
 +        });
 +    }
 +
 +    fn collect_nodes<'a>(
 +        &'a self,
 +        link_nodes: &'a [LinkNode<Rc<BindingKind>>],
 +        nodes: &mut Vec<&'a Rc<BindingKind>>,
 +    ) {
 +        link_nodes.iter().for_each(|it| match it {
 +            LinkNode::Node(it) => nodes.push(it),
 +            LinkNode::Parent { idx, len } => self.collect_nodes_ref(*idx, *len, nodes),
 +        });
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +struct MatchState<'t> {
 +    /// The position of the "dot" in this matcher
 +    dot: OpDelimitedIter<'t>,
 +
 +    /// Token subtree stack
 +    /// When matching against matchers with nested delimited submatchers (e.g., `pat ( pat ( .. )
 +    /// pat ) pat`), we need to keep track of the matchers we are descending into. This stack does
 +    /// that where the bottom of the stack is the outermost matcher.
 +    stack: SmallVec<[OpDelimitedIter<'t>; 4]>,
 +
 +    /// The "parent" matcher position if we are in a repetition. That is, the matcher position just
 +    /// before we enter the repetition.
 +    up: Option<Box<MatchState<'t>>>,
 +
 +    /// The separator if we are in a repetition.
 +    sep: Option<Separator>,
 +
 +    /// The KleeneOp of this sequence if we are in a repetition.
 +    sep_kind: Option<RepeatKind>,
 +
++    /// Number of tokens of separator parsed
 +    sep_parsed: Option<usize>,
 +
 +    /// Matched meta variables bindings
 +    bindings: BindingsIdx,
 +
 +    /// Cached result of meta variable parsing
 +    meta_result: Option<(TtIter<'t>, ExpandResult<Option<Fragment>>)>,
 +
 +    /// Is error occuried in this state, will `poised` to "parent"
 +    is_error: bool,
 +}
 +
 +/// Process the matcher positions of `cur_items` until it is empty. In the process, this will
 +/// produce more items in `next_items`, `eof_items`, and `bb_items`.
 +///
 +/// For more info about the how this happens, see the module-level doc comments and the inline
 +/// comments of this function.
 +///
 +/// # Parameters
 +///
 +/// - `src`: the current token of the parser.
 +/// - `stack`: the "parent" frames of the token tree
 +/// - `res`: the match result to store errors
 +/// - `cur_items`: the set of current items to be processed. This should be empty by the end of a
 +///   successful execution of this function.
 +/// - `next_items`: the set of newly generated items. These are used to replenish `cur_items` in
 +///   the function `parse`.
 +/// - `eof_items`: the set of items that would be valid if this was the EOF.
 +/// - `bb_items`: the set of items that are waiting for the black-box parser.
 +/// - `error_items`: the set of items in errors, used for error-resilient parsing
 +fn match_loop_inner<'t>(
 +    src: TtIter<'t>,
 +    stack: &[TtIter<'t>],
 +    res: &mut Match,
 +    bindings_builder: &mut BindingsBuilder,
 +    cur_items: &mut SmallVec<[MatchState<'t>; 1]>,
 +    bb_items: &mut SmallVec<[MatchState<'t>; 1]>,
 +    next_items: &mut Vec<MatchState<'t>>,
 +    eof_items: &mut SmallVec<[MatchState<'t>; 1]>,
 +    error_items: &mut SmallVec<[MatchState<'t>; 1]>,
 +) {
 +    macro_rules! try_push {
 +        ($items: expr, $it:expr) => {
 +            if $it.is_error {
 +                error_items.push($it);
 +            } else {
 +                $items.push($it);
 +            }
 +        };
 +    }
 +
 +    while let Some(mut item) = cur_items.pop() {
 +        while item.dot.is_eof() {
 +            match item.stack.pop() {
 +                Some(frame) => {
 +                    item.dot = frame;
 +                    item.dot.next();
 +                }
 +                None => break,
 +            }
 +        }
 +        let op = match item.dot.peek() {
 +            None => {
 +                // We are at or past the end of the matcher of `item`.
 +                if item.up.is_some() {
 +                    if item.sep_parsed.is_none() {
 +                        // Get the `up` matcher
 +                        let mut new_pos = *item.up.clone().unwrap();
 +                        new_pos.bindings = bindings_builder.copy(&new_pos.bindings);
 +                        // Add matches from this repetition to the `matches` of `up`
 +                        bindings_builder.push_nested(&mut new_pos.bindings, &item.bindings);
 +
 +                        // Move the "dot" past the repetition in `up`
 +                        new_pos.dot.next();
 +                        new_pos.is_error = new_pos.is_error || item.is_error;
 +                        cur_items.push(new_pos);
 +                    }
 +
 +                    // Check if we need a separator.
 +                    // We check the separator one by one
 +                    let sep_idx = *item.sep_parsed.as_ref().unwrap_or(&0);
 +                    let sep_len = item.sep.as_ref().map_or(0, Separator::tt_count);
 +                    if item.sep.is_some() && sep_idx != sep_len {
 +                        let sep = item.sep.as_ref().unwrap();
 +                        if src.clone().expect_separator(sep, sep_idx) {
 +                            item.dot.next();
 +                            item.sep_parsed = Some(sep_idx + 1);
 +                            try_push!(next_items, item);
 +                        }
 +                    }
 +                    // We don't need a separator. Move the "dot" back to the beginning of the matcher
 +                    // and try to match again UNLESS we are only allowed to have _one_ repetition.
 +                    else if item.sep_kind != Some(RepeatKind::ZeroOrOne) {
 +                        item.dot = item.dot.reset();
 +                        item.sep_parsed = None;
 +                        bindings_builder.push_default(&mut item.bindings);
 +                        cur_items.push(item);
 +                    }
 +                } else {
 +                    // If we are not in a repetition, then being at the end of a matcher means that we have
 +                    // reached the potential end of the input.
 +                    try_push!(eof_items, item);
 +                }
 +                continue;
 +            }
 +            Some(it) => it,
 +        };
 +
 +        // We are in the middle of a matcher.
 +        match op {
 +            OpDelimited::Op(Op::Repeat { tokens, kind, separator }) => {
 +                if matches!(kind, RepeatKind::ZeroOrMore | RepeatKind::ZeroOrOne) {
 +                    let mut new_item = item.clone();
 +                    new_item.bindings = bindings_builder.copy(&new_item.bindings);
 +                    new_item.dot.next();
 +                    collect_vars(
 +                        &mut |s| {
 +                            bindings_builder.push_empty(&mut new_item.bindings, &s);
 +                        },
 +                        tokens,
 +                    );
 +                    cur_items.push(new_item);
 +                }
 +                cur_items.push(MatchState {
 +                    dot: tokens.iter_delimited(None),
 +                    stack: Default::default(),
 +                    up: Some(Box::new(item)),
 +                    sep: separator.clone(),
 +                    sep_kind: Some(*kind),
 +                    sep_parsed: None,
 +                    bindings: bindings_builder.alloc(),
 +                    meta_result: None,
 +                    is_error: false,
 +                })
 +            }
 +            OpDelimited::Op(Op::Subtree { tokens, delimiter }) => {
 +                if let Ok(subtree) = src.clone().expect_subtree() {
 +                    if subtree.delimiter_kind() == delimiter.map(|it| it.kind) {
 +                        item.stack.push(item.dot);
 +                        item.dot = tokens.iter_delimited(delimiter.as_ref());
 +                        cur_items.push(item);
 +                    }
 +                }
 +            }
 +            OpDelimited::Op(Op::Var { kind, name, .. }) => {
 +                if let Some(kind) = kind {
 +                    let mut fork = src.clone();
 +                    let match_res = match_meta_var(kind.as_str(), &mut fork);
 +                    match match_res.err {
 +                        None => {
 +                            // Some meta variables are optional (e.g. vis)
 +                            if match_res.value.is_some() {
 +                                item.meta_result = Some((fork, match_res));
 +                                try_push!(bb_items, item);
 +                            } else {
 +                                bindings_builder.push_optional(&mut item.bindings, name);
 +                                item.dot.next();
 +                                cur_items.push(item);
 +                            }
 +                        }
 +                        Some(err) => {
 +                            res.add_err(err);
 +                            if let Some(fragment) = match_res.value {
 +                                bindings_builder.push_fragment(&mut item.bindings, name, fragment);
 +                            }
 +                            item.is_error = true;
 +                            error_items.push(item);
 +                        }
 +                    }
 +                }
 +            }
 +            OpDelimited::Op(Op::Leaf(leaf)) => {
 +                if let Err(err) = match_leaf(leaf, &mut src.clone()) {
 +                    res.add_err(err);
 +                    item.is_error = true;
 +                } else {
 +                    item.dot.next();
 +                }
 +                try_push!(next_items, item);
 +            }
 +            OpDelimited::Op(Op::Ignore { .. } | Op::Index { .. }) => {}
 +            OpDelimited::Open => {
 +                if matches!(src.clone().next(), Some(tt::TokenTree::Subtree(..))) {
 +                    item.dot.next();
 +                    try_push!(next_items, item);
 +                }
 +            }
 +            OpDelimited::Close => {
 +                let is_delim_closed = src.peek_n(0).is_none() && !stack.is_empty();
 +                if is_delim_closed {
 +                    item.dot.next();
 +                    try_push!(next_items, item);
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
 +    let mut src = TtIter::new(src);
 +    let mut stack: SmallVec<[TtIter<'_>; 1]> = SmallVec::new();
 +    let mut res = Match::default();
 +    let mut error_recover_item = None;
 +
 +    let mut bindings_builder = BindingsBuilder::default();
 +
 +    let mut cur_items = smallvec![MatchState {
 +        dot: pattern.iter_delimited(None),
 +        stack: Default::default(),
 +        up: None,
 +        sep: None,
 +        sep_kind: None,
 +        sep_parsed: None,
 +        bindings: bindings_builder.alloc(),
 +        is_error: false,
 +        meta_result: None,
 +    }];
 +
 +    let mut next_items = vec![];
 +
 +    loop {
 +        let mut bb_items = SmallVec::new();
 +        let mut eof_items = SmallVec::new();
 +        let mut error_items = SmallVec::new();
 +
 +        stdx::always!(next_items.is_empty());
 +
 +        match_loop_inner(
 +            src.clone(),
 +            &stack,
 +            &mut res,
 +            &mut bindings_builder,
 +            &mut cur_items,
 +            &mut bb_items,
 +            &mut next_items,
 +            &mut eof_items,
 +            &mut error_items,
 +        );
 +        stdx::always!(cur_items.is_empty());
 +
 +        if !error_items.is_empty() {
 +            error_recover_item = error_items.pop().map(|it| it.bindings);
 +        } else if let [state, ..] = &*eof_items {
 +            error_recover_item = Some(state.bindings.clone());
 +        }
 +
 +        // We need to do some post processing after the `match_loop_inner`.
 +        // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
 +        // either the parse is ambiguous (which should never happen) or there is a syntax error.
 +        if src.peek_n(0).is_none() && stack.is_empty() {
 +            if let [state] = &*eof_items {
 +                // remove all errors, because it is the correct answer !
 +                res = Match::default();
 +                res.bindings = bindings_builder.build(&state.bindings);
 +            } else {
 +                // Error recovery
 +                if let Some(item) = error_recover_item {
 +                    res.bindings = bindings_builder.build(&item);
 +                }
 +                res.add_err(ExpandError::UnexpectedToken);
 +            }
 +            return res;
 +        }
 +
 +        // If there are no possible next positions AND we aren't waiting for the black-box parser,
 +        // then there is a syntax error.
 +        //
 +        // Another possibility is that we need to call out to parse some rust nonterminal
 +        // (black-box) parser. However, if there is not EXACTLY ONE of these, something is wrong.
 +        let has_leftover_tokens = (bb_items.is_empty() && next_items.is_empty())
 +            || !(bb_items.is_empty() || next_items.is_empty())
 +            || bb_items.len() > 1;
 +        if has_leftover_tokens {
 +            res.unmatched_tts += src.len();
 +            while let Some(it) = stack.pop() {
 +                src = it;
 +                res.unmatched_tts += src.len();
 +            }
 +            res.add_err(ExpandError::LeftoverTokens);
 +
 +            if let Some(error_reover_item) = error_recover_item {
 +                res.bindings = bindings_builder.build(&error_reover_item);
 +            }
 +            return res;
 +        }
 +        // Dump all possible `next_items` into `cur_items` for the next iteration.
 +        else if !next_items.is_empty() {
 +            // Now process the next token
 +            cur_items.extend(next_items.drain(..));
 +
 +            match src.next() {
 +                Some(tt::TokenTree::Subtree(subtree)) => {
 +                    stack.push(src.clone());
 +                    src = TtIter::new(subtree);
 +                }
 +                None => {
 +                    if let Some(iter) = stack.pop() {
 +                        src = iter;
 +                    }
 +                }
 +                _ => (),
 +            }
 +        }
 +        // Finally, we have the case where we need to call the black-box parser to get some
 +        // nonterminal.
 +        else {
 +            stdx::always!(bb_items.len() == 1);
 +            let mut item = bb_items.pop().unwrap();
 +
 +            if let Some(OpDelimited::Op(Op::Var { name, .. })) = item.dot.peek() {
 +                let (iter, match_res) = item.meta_result.take().unwrap();
 +                match match_res.value {
 +                    Some(fragment) => {
 +                        bindings_builder.push_fragment(&mut item.bindings, name, fragment);
 +                    }
 +                    None if match_res.err.is_none() => {
 +                        bindings_builder.push_optional(&mut item.bindings, name);
 +                    }
 +                    None => {}
 +                }
 +                if let Some(err) = match_res.err {
 +                    res.add_err(err);
 +                }
 +                src = iter.clone();
 +                item.dot.next();
 +            } else {
 +                unreachable!()
 +            }
 +            cur_items.push(item);
 +        }
 +        stdx::always!(!cur_items.is_empty());
 +    }
 +}
 +
 +fn match_leaf(lhs: &tt::Leaf, src: &mut TtIter<'_>) -> Result<(), ExpandError> {
 +    let rhs = src
 +        .expect_leaf()
 +        .map_err(|()| ExpandError::binding_error(format!("expected leaf: `{lhs}`")))?;
 +    match (lhs, rhs) {
 +        (
 +            tt::Leaf::Punct(tt::Punct { char: lhs, .. }),
 +            tt::Leaf::Punct(tt::Punct { char: rhs, .. }),
 +        ) if lhs == rhs => Ok(()),
 +        (
 +            tt::Leaf::Ident(tt::Ident { text: lhs, .. }),
 +            tt::Leaf::Ident(tt::Ident { text: rhs, .. }),
 +        ) if lhs == rhs => Ok(()),
 +        (
 +            tt::Leaf::Literal(tt::Literal { text: lhs, .. }),
 +            tt::Leaf::Literal(tt::Literal { text: rhs, .. }),
 +        ) if lhs == rhs => Ok(()),
 +        _ => Err(ExpandError::UnexpectedToken),
 +    }
 +}
 +
 +fn match_meta_var(kind: &str, input: &mut TtIter<'_>) -> ExpandResult<Option<Fragment>> {
 +    let fragment = match kind {
 +        "path" => parser::PrefixEntryPoint::Path,
 +        "ty" => parser::PrefixEntryPoint::Ty,
 +        // FIXME: These two should actually behave differently depending on the edition.
 +        //
 +        // https://doc.rust-lang.org/edition-guide/rust-2021/or-patterns-macro-rules.html
 +        "pat" | "pat_param" => parser::PrefixEntryPoint::Pat,
 +        "stmt" => parser::PrefixEntryPoint::Stmt,
 +        "block" => parser::PrefixEntryPoint::Block,
 +        "meta" => parser::PrefixEntryPoint::MetaItem,
 +        "item" => parser::PrefixEntryPoint::Item,
 +        "vis" => parser::PrefixEntryPoint::Vis,
 +        "expr" => {
 +            // `expr` should not match underscores.
 +            // HACK: Macro expansion should not be done using "rollback and try another alternative".
 +            // rustc [explicitly checks the next token][0].
 +            // [0]: https://github.com/rust-lang/rust/blob/f0c4da499/compiler/rustc_expand/src/mbe/macro_parser.rs#L576
 +            match input.peek_n(0) {
 +                Some(tt::TokenTree::Leaf(tt::Leaf::Ident(it))) if it.text == "_" => {
 +                    return ExpandResult::only_err(ExpandError::NoMatchingRule)
 +                }
 +                _ => {}
 +            };
 +            return input
 +                .expect_fragment(parser::PrefixEntryPoint::Expr)
 +                .map(|tt| tt.map(Fragment::Expr));
 +        }
 +        _ => {
 +            let tt_result = match kind {
 +                "ident" => input
 +                    .expect_ident()
 +                    .map(|ident| tt::Leaf::from(ident.clone()).into())
 +                    .map_err(|()| ExpandError::binding_error("expected ident")),
 +                "tt" => input
 +                    .expect_tt()
 +                    .map_err(|()| ExpandError::binding_error("expected token tree")),
 +                "lifetime" => input
 +                    .expect_lifetime()
 +                    .map_err(|()| ExpandError::binding_error("expected lifetime")),
 +                "literal" => {
 +                    let neg = input.eat_char('-');
 +                    input
 +                        .expect_literal()
 +                        .map(|literal| {
 +                            let lit = literal.clone();
 +                            match neg {
 +                                None => lit.into(),
 +                                Some(neg) => tt::TokenTree::Subtree(tt::Subtree {
 +                                    delimiter: None,
 +                                    token_trees: vec![neg, lit.into()],
 +                                }),
 +                            }
 +                        })
 +                        .map_err(|()| ExpandError::binding_error("expected literal"))
 +                }
 +                _ => Err(ExpandError::UnexpectedToken),
 +            };
 +            return tt_result.map(|it| Some(Fragment::Tokens(it))).into();
 +        }
 +    };
 +    input.expect_fragment(fragment).map(|it| it.map(Fragment::Tokens))
 +}
 +
 +fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate) {
 +    for op in pattern.iter() {
 +        match op {
 +            Op::Var { name, .. } => collector_fun(name.clone()),
 +            Op::Leaf(_) => (),
 +            Op::Subtree { tokens, .. } => collect_vars(collector_fun, tokens),
 +            Op::Repeat { tokens, .. } => collect_vars(collector_fun, tokens),
 +            Op::Ignore { .. } | Op::Index { .. } => {}
 +        }
 +    }
 +}
 +impl MetaTemplate {
 +    fn iter_delimited<'a>(&'a self, delimited: Option<&'a tt::Delimiter>) -> OpDelimitedIter<'a> {
 +        OpDelimitedIter { inner: &self.0, idx: 0, delimited }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy)]
 +enum OpDelimited<'a> {
 +    Op(&'a Op),
 +    Open,
 +    Close,
 +}
 +
 +#[derive(Debug, Clone, Copy)]
 +struct OpDelimitedIter<'a> {
 +    inner: &'a [Op],
 +    delimited: Option<&'a tt::Delimiter>,
 +    idx: usize,
 +}
 +
 +impl<'a> OpDelimitedIter<'a> {
 +    fn is_eof(&self) -> bool {
 +        let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 };
 +        self.idx >= len
 +    }
 +
 +    fn peek(&self) -> Option<OpDelimited<'a>> {
 +        match self.delimited {
 +            None => self.inner.get(self.idx).map(OpDelimited::Op),
 +            Some(_) => match self.idx {
 +                0 => Some(OpDelimited::Open),
 +                i if i == self.inner.len() + 1 => Some(OpDelimited::Close),
 +                i => self.inner.get(i - 1).map(OpDelimited::Op),
 +            },
 +        }
 +    }
 +
 +    fn reset(&self) -> Self {
 +        Self { inner: self.inner, idx: 0, delimited: self.delimited }
 +    }
 +}
 +
 +impl<'a> Iterator for OpDelimitedIter<'a> {
 +    type Item = OpDelimited<'a>;
 +
 +    fn next(&mut self) -> Option<Self::Item> {
 +        let res = self.peek();
 +        self.idx += 1;
 +        res
 +    }
 +
 +    fn size_hint(&self) -> (usize, Option<usize>) {
 +        let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 };
 +        let remain = len.saturating_sub(self.idx);
 +        (remain, Some(remain))
 +    }
 +}
 +
 +impl<'a> TtIter<'a> {
 +    fn expect_separator(&mut self, separator: &Separator, idx: usize) -> bool {
 +        let mut fork = self.clone();
 +        let ok = match separator {
 +            Separator::Ident(lhs) if idx == 0 => match fork.expect_ident_or_underscore() {
 +                Ok(rhs) => rhs.text == lhs.text,
 +                Err(_) => false,
 +            },
 +            Separator::Literal(lhs) if idx == 0 => match fork.expect_literal() {
 +                Ok(rhs) => match rhs {
 +                    tt::Leaf::Literal(rhs) => rhs.text == lhs.text,
 +                    tt::Leaf::Ident(rhs) => rhs.text == lhs.text,
 +                    tt::Leaf::Punct(_) => false,
 +                },
 +                Err(_) => false,
 +            },
 +            Separator::Puncts(lhss) if idx < lhss.len() => match fork.expect_punct() {
 +                Ok(rhs) => rhs.char == lhss[idx].char,
 +                Err(_) => false,
 +            },
 +            _ => false,
 +        };
 +        if ok {
 +            *self = fork;
 +        }
 +        ok
 +    }
 +
 +    fn expect_tt(&mut self) -> Result<tt::TokenTree, ()> {
 +        match self.peek_n(0) {
 +            Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) if punct.char == '\'' => {
 +                return self.expect_lifetime();
 +            }
 +            _ => (),
 +        }
 +
 +        let tt = self.next().ok_or(())?.clone();
 +        let punct = match tt {
 +            tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if punct.spacing == tt::Spacing::Joint => {
 +                punct
 +            }
 +            _ => return Ok(tt),
 +        };
 +
 +        let (second, third) = match (self.peek_n(0), self.peek_n(1)) {
 +            (
 +                Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))),
 +                Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p3))),
 +            ) if p2.spacing == tt::Spacing::Joint => (p2.char, Some(p3.char)),
 +            (Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))), _) => (p2.char, None),
 +            _ => return Ok(tt),
 +        };
 +
 +        match (punct.char, second, third) {
 +            ('.', '.', Some('.' | '=')) | ('<', '<', Some('=')) | ('>', '>', Some('=')) => {
 +                let tt2 = self.next().unwrap().clone();
 +                let tt3 = self.next().unwrap().clone();
 +                Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2, tt3] }.into())
 +            }
 +            ('-' | '!' | '*' | '/' | '&' | '%' | '^' | '+' | '<' | '=' | '>' | '|', '=', _)
 +            | ('-' | '=' | '>', '>', _)
 +            | (':', ':', _)
 +            | ('.', '.', _)
 +            | ('&', '&', _)
 +            | ('<', '<', _)
 +            | ('|', '|', _) => {
 +                let tt2 = self.next().unwrap().clone();
 +                Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2] }.into())
 +            }
 +            _ => Ok(tt),
 +        }
 +    }
 +
 +    fn expect_lifetime(&mut self) -> Result<tt::TokenTree, ()> {
 +        let punct = self.expect_punct()?;
 +        if punct.char != '\'' {
 +            return Err(());
 +        }
 +        let ident = self.expect_ident_or_underscore()?;
 +
 +        Ok(tt::Subtree {
 +            delimiter: None,
 +            token_trees: vec![
 +                tt::Leaf::Punct(*punct).into(),
 +                tt::Leaf::Ident(ident.clone()).into(),
 +            ],
 +        }
 +        .into())
 +    }
 +
 +    fn eat_char(&mut self, c: char) -> Option<tt::TokenTree> {
 +        let mut fork = self.clone();
 +        match fork.expect_char(c) {
 +            Ok(_) => {
 +                let tt = self.next().cloned();
 +                *self = fork;
 +                tt
 +            }
 +            Err(_) => None,
 +        }
 +    }
 +}
index e3f83084ac8ac90a74558040c9578019e947a267,0000000000000000000000000000000000000000..b81b7432f6554f255743a85b38696a83dfc0fc53
mode 100644,000000..100644
--- /dev/null
@@@ -1,159 -1,0 +1,159 @@@
- //! In this crate, we are conserned with "real world" project models.
 +//! 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, 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!("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())
 +}
index daabb299f76cb0f18f454e3012dafc711d8e0c59,0000000000000000000000000000000000000000..8d6f50f5587c5ad0e8248702e66ba69c9187eced
mode 100644,000000..100644
--- /dev/null
@@@ -1,1042 -1,0 +1,1042 @@@
-             // N.B. if this line is ommitted, we try to analyse over 4_800_000 crates
 +//! Handles lowering of build-system specific workspace information (`cargo
 +//! metadata` or `rust-project.json`) into representation stored in the salsa
 +//! database -- `CrateGraph`.
 +
 +use std::{collections::VecDeque, fmt, fs, process::Command};
 +
 +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;
 +
 +use crate::{
 +    build_scripts::BuildScriptOutput,
 +    cargo_workspace::{DepKind, PackageData, RustcSource},
 +    cfg_flag::CfgFlag,
 +    rustc_cfg,
 +    sysroot::SysrootCrate,
 +    utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath, 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())?
 +            }
 +            ProjectManifest::CargoToml(cargo_toml) => {
 +                let cargo_version = utf8_stdout({
 +                    let mut cmd = Command::new(toolchain::cargo());
 +                    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 = if config.no_sysroot {
 +                    None
 +                } else {
 +                    Some(Sysroot::discover(cargo_toml.parent()).with_context(|| {
 +                        format!(
 +                            "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
 +                            cargo_toml.display()
 +                        )
 +                    })?)
 +                };
 +
 +                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),
 +                    None => None,
 +                };
 +
 +                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());
 +
 +                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>,
 +    ) -> 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,
 +        };
 +
 +        let rustc_cfg = rustc_cfg::get(None, target);
 +        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"))?,
 +        )?;
 +        let rustc_cfg = rustc_cfg::get(None, None);
 +        Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
 +    }
 +
 +    pub fn run_build_scripts(
 +        &self,
 +        config: &CargoConfig,
 +        progress: &dyn Fn(String),
 +    ) -> Result<WorkspaceBuildScripts> {
 +        match self {
 +            ProjectWorkspace::Cargo { cargo, toolchain, .. } => {
 +                WorkspaceBuildScripts::run(config, cargo, progress, toolchain).with_context(|| {
 +                    format!("Failed to run build scripts for {}", &cargo.workspace_root().display())
 +                })
 +            }
 +            ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFiles { .. } => {
 +                Ok(WorkspaceBuildScripts::default())
 +            }
 +        }
 +    }
 +
 +    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> {
 +        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(sysroot.as_ref().into_iter().flat_map(|sysroot| {
 +                    sysroot.crates().map(move |krate| PackageRoot {
 +                        is_local: false,
 +                        include: vec![sysroot[krate].root.parent().to_path_buf()],
 +                        exclude: Vec::new(),
 +                    })
 +                }))
 +                .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(sysroot.iter().map(|sysroot| PackageRoot {
 +                        is_local: false,
 +                        include: vec![sysroot.src_root().to_path_buf()],
 +                        exclude: Vec::new(),
 +                    }))
 +                    .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(sysroot.crates().map(|krate| PackageRoot {
 +                    is_local: false,
 +                    include: vec![sysroot[krate].root.parent().to_path_buf()],
 +                    exclude: Vec::new(),
 +                }))
 +                .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>,
 +    ) -> 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,
 +            ),
 +            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>,
 +) -> 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: FxHashMap<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)))
 +                }
 +                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() }
 +                    } else {
 +                        CrateOrigin::CratesIo { repo: 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);
 +                }
 +                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(
 +                rustc_workspace,
 +                load,
 +                &mut crate_graph,
 +                &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,
 +            None,
 +            cfg_options.clone(),
 +            cfg_options.clone(),
 +            Env::default(),
 +            Ok(Vec::new()),
 +            false,
 +            CrateOrigin::CratesIo { repo: None },
 +        );
 +
 +        public_deps.add(detached_file_crate, &mut crate_graph);
 +    }
 +    crate_graph
 +}
 +
 +fn handle_rustc_crates(
 +    rustc_workspace: &CargoWorkspace,
 +    load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
 +    crate_graph: &mut CrateGraph,
 +    cfg_options: &CfgOptions,
 +    override_cfg: &CfgOverrides,
 +    load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
 +    pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>,
 +    public_deps: &SysrootPublicDeps,
 +    cargo: &CargoWorkspace,
 +    pkg_crates: &FxHashMap<la_arena::Idx<crate::PackageData>, 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 dependended on a diamond pattern
++            // N.B. if this line is omitted, we try to analyse 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() },
 +    )
 +}
 +
 +#[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 0b69f75bc0db0ef87829b7594d28b5e39d6bb242,0000000000000000000000000000000000000000..298814af5a465679eaf033982061c9f8da010b9f
mode 100644,000000..100644
--- /dev/null
@@@ -1,155 -1,0 +1,155 @@@
-         // As the value should only affect chalk crates, we'd better mannually
 +//! Simple logger that logs either to stderr or to a file, using `tracing_subscriber`
 +//! filter syntax and `tracing_appender` for non blocking output.
 +
 +use std::{
 +    fmt,
 +    fs::File,
 +    io::{self, Stderr},
 +    sync::Arc,
 +};
 +
 +use rust_analyzer::Result;
 +use tracing::{level_filters::LevelFilter, Event, Subscriber};
 +use tracing_log::NormalizeEvent;
 +use tracing_subscriber::{
 +    fmt::{
 +        format::Writer, writer::BoxMakeWriter, FmtContext, FormatEvent, FormatFields,
 +        FormattedFields, MakeWriter,
 +    },
 +    layer::SubscriberExt,
 +    registry::LookupSpan,
 +    util::SubscriberInitExt,
 +    EnvFilter, Registry,
 +};
 +use tracing_tree::HierarchicalLayer;
 +
 +pub(crate) struct Logger {
 +    filter: EnvFilter,
 +    file: Option<File>,
 +}
 +
 +struct MakeWriterStderr;
 +
 +impl<'a> MakeWriter<'a> for MakeWriterStderr {
 +    type Writer = Stderr;
 +
 +    fn make_writer(&'a self) -> Self::Writer {
 +        io::stderr()
 +    }
 +}
 +
 +impl Logger {
 +    pub(crate) fn new(file: Option<File>, filter: Option<&str>) -> Logger {
 +        let filter = filter.map_or(EnvFilter::default(), EnvFilter::new);
 +
 +        Logger { filter, file }
 +    }
 +
 +    pub(crate) fn install(self) -> Result<()> {
 +        // The meaning of CHALK_DEBUG I suspected is to tell chalk crates
 +        // (i.e. chalk-solve, chalk-ir, chalk-recursive) how to filter tracing
 +        // logs. But now we can only have just one filter, which means we have to
 +        // merge chalk filter to our main filter (from RA_LOG env).
 +        //
 +        // The acceptable syntax of CHALK_DEBUG is `target[span{field=value}]=level`.
++        // As the value should only affect chalk crates, we'd better manually
 +        // specify the target. And for simplicity, CHALK_DEBUG only accept the value
 +        // that specify level.
 +        let chalk_level_dir = std::env::var("CHALK_DEBUG")
 +            .map(|val| {
 +                val.parse::<LevelFilter>().expect(
 +                    "invalid CHALK_DEBUG value, expect right log level (like debug or trace)",
 +                )
 +            })
 +            .ok();
 +
 +        let chalk_layer = HierarchicalLayer::default()
 +            .with_indent_lines(true)
 +            .with_ansi(false)
 +            .with_indent_amount(2)
 +            .with_writer(io::stderr);
 +
 +        let writer = match self.file {
 +            Some(file) => BoxMakeWriter::new(Arc::new(file)),
 +            None => BoxMakeWriter::new(io::stderr),
 +        };
 +        let ra_fmt_layer =
 +            tracing_subscriber::fmt::layer().event_format(LoggerFormatter).with_writer(writer);
 +
 +        match chalk_level_dir {
 +            Some(val) => {
 +                Registry::default()
 +                    .with(
 +                        self.filter
 +                            .add_directive(format!("chalk_solve={}", val).parse()?)
 +                            .add_directive(format!("chalk_ir={}", val).parse()?)
 +                            .add_directive(format!("chalk_recursive={}", val).parse()?),
 +                    )
 +                    .with(ra_fmt_layer)
 +                    .with(chalk_layer)
 +                    .init();
 +            }
 +            None => {
 +                Registry::default().with(self.filter).with(ra_fmt_layer).init();
 +            }
 +        };
 +
 +        Ok(())
 +    }
 +}
 +
 +#[derive(Debug)]
 +struct LoggerFormatter;
 +
 +impl<S, N> FormatEvent<S, N> for LoggerFormatter
 +where
 +    S: Subscriber + for<'a> LookupSpan<'a>,
 +    N: for<'a> FormatFields<'a> + 'static,
 +{
 +    fn format_event(
 +        &self,
 +        ctx: &FmtContext<'_, S, N>,
 +        mut writer: Writer<'_>,
 +        event: &Event<'_>,
 +    ) -> fmt::Result {
 +        // Write level and target
 +        let level = *event.metadata().level();
 +
 +        // If this event is issued from `log` crate, then the value of target is
 +        // always "log". `tracing-log` has hard coded it for some reason, so we
 +        // need to extract it using `normalized_metadata` method which is part of
 +        // `tracing_log::NormalizeEvent`.
 +        let target = match event.normalized_metadata() {
 +            // This event is issued from `log` crate
 +            Some(log) => log.target(),
 +            None => event.metadata().target(),
 +        };
 +        write!(writer, "[{} {}] ", level, target)?;
 +
 +        // Write spans and fields of each span
 +        ctx.visit_spans(|span| {
 +            write!(writer, "{}", span.name())?;
 +
 +            let ext = span.extensions();
 +
 +            // `FormattedFields` is a a formatted representation of the span's
 +            // fields, which is stored in its extensions by the `fmt` layer's
 +            // `new_span` method. The fields will have been formatted
 +            // by the same field formatter that's provided to the event
 +            // formatter in the `FmtContext`.
 +            let fields = &ext.get::<FormattedFields<N>>().expect("will never be `None`");
 +
 +            if !fields.is_empty() {
 +                write!(writer, "{{{}}}", fields)?;
 +            }
 +            write!(writer, ": ")?;
 +
 +            Ok(())
 +        })?;
 +
 +        // Write fields on the event
 +        ctx.field_format().format_fields(writer.by_ref(), event)?;
 +
 +        writeln!(writer)
 +    }
 +}
index 1629c1dd328a69348f06299449291b90f06a4c39,0000000000000000000000000000000000000000..6649f42b4ef9e6cade85b71105ecda9b535dda32
mode 100644,000000..100644
--- /dev/null
@@@ -1,1986 -1,0 +1,1995 @@@
- // *parts* of VS Code's `package.json` config from this.
 +//! 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::{ffi::OsString, fmt, iter, path::PathBuf};
 +
 +use flycheck::FlycheckConfig;
 +use ide::{
 +    AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
 +    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, 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
-         hover_documentation_enable: bool       = "true",
++// *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",
 +        /// 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",
 +        /// List of features to activate.
 +        ///
 +        /// Set this to `"all"` to pass `--all-features` to cargo.
 +        cargo_features: CargoFeatures      = "[]",
 +        /// Whether to pass `--no-default-features` to cargo.
 +        cargo_noDefaultFeatures: bool    = "false",
 +        /// Internal config for debugging, disables loading of sysroot crates.
 +        cargo_noSysroot: bool            = "false",
 +        /// 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>               = "[]",
 +        /// List of features to activate. Defaults to
 +        /// `#rust-analyzer.cargo.features#`.
 +        ///
 +        /// Set to `"all"` to pass `--all-features` to Cargo.
 +        checkOnSave_features: Option<CargoFeatures>      = "null",
 +        /// 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",
 +        /// 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",
 +        /// 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",
 +
 +        /// 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",
 +
 +        /// 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,
 +}
 +
 +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(),
 +        }
 +    }
 +
 +    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 lru_capacity(&self) -> Option<usize> {
 +        self.data.lru_capacity
 +    }
 +
 +    pub fn proc_macro_srv(&self) -> Option<(AbsPathBuf, Vec<OsString>)> {
 +        if !self.data.procMacro_enable {
 +            return None;
 +        }
 +        let path = match &self.data.procMacro_server {
 +            Some(it) => self.root_path.join(it),
 +            None => AbsPathBuf::assert(std::env::current_exe().ok()?),
 +        };
 +        Some((path, vec!["proc-macro".into()]))
 +    }
 +
 +    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))
 +            }
 +        });
 +
 +        CargoConfig {
 +            no_default_features: self.data.cargo_noDefaultFeatures,
 +            all_features: matches!(self.data.cargo_features, CargoFeatures::All),
 +            features: match &self.data.cargo_features {
 +                CargoFeatures::All => vec![],
 +                CargoFeatures::Listed(it) => it.clone(),
 +            },
 +            target: self.data.cargo_target.clone(),
 +            no_sysroot: self.data.cargo_noSysroot,
 +            rustc_source,
 +            unset_test_crates: UnsetTestCrates::Only(self.data.cargo_unsetTest.clone()),
 +            wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper,
 +            run_build_script_command: self.data.cargo_buildScripts_overrideCommand.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 }
 +            }
 +            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),
 +                    CargoFeatures::All
 +                ),
 +                features: match self
 +                    .data
 +                    .checkOnSave_features
 +                    .clone()
 +                    .unwrap_or_else(|| self.data.cargo_features.clone())
 +                {
 +                    CargoFeatures::All => vec![],
 +                    CargoFeatures::Listed(it) => it,
 +                },
 +                extra_args: self.data.checkOnSave_extraArgs.clone(),
 +            },
 +        };
 +        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(),
 +            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 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(),
 +        }
 +    }
 +
 +    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,
 +        }
 +    }
 +
 +    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_strings(&self) -> bool {
 +        self.data.semanticHighlighting_strings_enable
 +    }
 +
 +    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 CargoFeatures {
 +    #[serde(deserialize_with = "de_unit_v::all")]
 +    All,
 +    Listed(Vec<String>),
 +}
 +
 +#[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."
 +            ]
 +        },
 +        "CargoFeatures" => set! {
 +            "anyOf": [
 +                {
 +                    "type": "string",
 +                    "enum": [
 +                        "all"
 +                    ],
 +                    "enumDescriptions": [
 +                        "Pass `--all-features` to cargo",
 +                    ]
 +                },
 +                {
 +                    "type": "array",
 +                    "items": { "type": "string" }
 +                }
 +            ],
 +        },
 +        "Option<CargoFeatures>" => 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",
 +            ],
 +        },
 +        _ => 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 b5f6aef2e1a84e60abb268aeebf86bd6be85301c,0000000000000000000000000000000000000000..c55bbbbe6ef7c2c442e8593179daebe778e70303
mode 100644,000000..100644
--- /dev/null
@@@ -1,385 -1,0 +1,384 @@@
- use ide_db::base_db::{CrateId, FileLoader, SourceDatabase, SourceDatabaseExt};
 +//! 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};
-         let mut fs_refresh_changes = Vec::new();
++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 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>>,
 +
 +    pub(crate) flycheck: Vec<FlycheckHandle>,
 +    pub(crate) flycheck_sender: Sender<flycheck::Message>,
 +    pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
 +
 +    pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<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, FxHashMap<FileId, LineEndings>)>>,
 +    pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
 +}
 +
 +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: Vec::new(),
 +            flycheck_sender,
 +            flycheck_receiver,
 +
 +            vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::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");
-                         fs_refresh_changes.push((path, file.file_id));
 +        // 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 changed_files = vfs.take_changes();
 +            if changed_files.is_empty() {
 +                return 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) {
-             let workspace_structure_change =
-                 fs_refresh_changes.into_iter().find(|&(_, file_id)| {
-                     !raw_database.source_root(raw_database.file_source_root(file_id)).is_library
-                 });
-             if let Some((path, _)) = workspace_structure_change {
++                        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),
 +        }
 +    }
 +
 +    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());
 +        }
 +    }
 +
 +    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 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 943d043bc1995dbfc3eb49bde756cf4fdd0c1e8f,0000000000000000000000000000000000000000..e0bcc80b31cb9893192d53408f31b08f3fb34c8e
mode 100644,000000..100644
--- /dev/null
@@@ -1,1893 -1,0 +1,1909 @@@
-         if let Some(offset) = offset {
-             if !runnable.nav.full_range.contains_inclusive(offset) {
-                 continue;
-             }
 +//! 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, 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_id = match snap.analysis.crate_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)? {
-     let mut rustfmt = match snap.config.rustfmt() {
++        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 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().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,
 +        },
 +        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.map(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(),
 +    ))
 +}
 +
 +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 highlights = snap.analysis.highlight(file_id)?;
 +    let highlight_strings = snap.config.highlighting_strings();
 +    let semantic_tokens =
 +        to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings);
 +
 +    // 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 highlights = snap.analysis.highlight(file_id)?;
 +    let highlight_strings = snap.config.highlighting_strings();
 +    let semantic_tokens =
 +        to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings);
 +
 +    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(frange)?;
 +    let highlight_strings = snap.config.highlighting_strings();
 +    let semantic_tokens =
 +        to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings);
 +    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)?;
 +    let crate_ids = snap.analysis.crate_for(file_id)?;
 +
 +    let line_index = snap.file_line_index(file_id)?;
 +
-     let mut rustfmt = rustfmt
++    let mut command = match snap.config.rustfmt() {
 +        RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => {
 +            let mut cmd = process::Command::new(toolchain::rustfmt());
 +            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(&crate_id) = crate_ids.first() {
 +                // Assume all crates are in the same edition
 +                let edition = snap.analysis.crate_edition(crate_id)?;
 +                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.args(args);
 +            cmd
 +        }
 +    };
 +
-         .context(format!("Failed to spawn {:?}", rustfmt))?;
++    let mut rustfmt = command
 +        .stdin(Stdio::piped())
 +        .stdout(Stdio::piped())
 +        .stderr(Stdio::piped())
 +        .spawn()
-                 tracing::info!("rustfmt exited with status 1, assuming parse error and ignoring");
++        .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 5f0e108624b2ef4991cbd065c4611d49b8c2613e,0000000000000000000000000000000000000000..e61c8b643d2dee940af7ae4fdcad4c7974d3583b
mode 100644,000000..100644
--- /dev/null
@@@ -1,549 -1,0 +1,557 @@@
 +//! rust-analyzer extensions to the LSP.
 +
 +use std::{collections::HashMap, path::PathBuf};
 +
 +use lsp_types::request::Request;
 +use lsp_types::{
 +    notification::Notification, CodeActionKind, DocumentOnTypeFormattingParams,
 +    PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams,
 +};
 +use serde::{Deserialize, Serialize};
 +
 +pub enum AnalyzerStatus {}
 +
 +impl Request for AnalyzerStatus {
 +    type Params = AnalyzerStatusParams;
 +    type Result = String;
 +    const METHOD: &'static str = "rust-analyzer/analyzerStatus";
 +}
 +
 +#[derive(Deserialize, Serialize, Debug)]
 +#[serde(rename_all = "camelCase")]
 +pub struct AnalyzerStatusParams {
 +    pub text_document: Option<TextDocumentIdentifier>,
 +}
 +
 +pub enum MemoryUsage {}
 +
 +impl Request for MemoryUsage {
 +    type Params = ();
 +    type Result = String;
 +    const METHOD: &'static str = "rust-analyzer/memoryUsage";
 +}
 +
 +pub enum ShuffleCrateGraph {}
 +
 +impl Request for ShuffleCrateGraph {
 +    type Params = ();
 +    type Result = ();
 +    const METHOD: &'static str = "rust-analyzer/shuffleCrateGraph";
 +}
 +
 +pub enum ReloadWorkspace {}
 +
 +impl Request for ReloadWorkspace {
 +    type Params = ();
 +    type Result = ();
 +    const METHOD: &'static str = "rust-analyzer/reloadWorkspace";
 +}
 +
 +pub enum SyntaxTree {}
 +
 +impl Request for SyntaxTree {
 +    type Params = SyntaxTreeParams;
 +    type Result = String;
 +    const METHOD: &'static str = "rust-analyzer/syntaxTree";
 +}
 +
 +#[derive(Deserialize, Serialize, Debug)]
 +#[serde(rename_all = "camelCase")]
 +pub struct SyntaxTreeParams {
 +    pub text_document: TextDocumentIdentifier,
 +    pub range: Option<Range>,
 +}
 +
 +pub enum ViewHir {}
 +
 +impl Request for ViewHir {
 +    type Params = lsp_types::TextDocumentPositionParams;
 +    type Result = String;
 +    const METHOD: &'static str = "rust-analyzer/viewHir";
 +}
 +
 +pub enum ViewFileText {}
 +
 +impl Request for ViewFileText {
 +    type Params = lsp_types::TextDocumentIdentifier;
 +    type Result = String;
 +    const METHOD: &'static str = "rust-analyzer/viewFileText";
 +}
 +
 +#[derive(Deserialize, Serialize, Debug)]
 +#[serde(rename_all = "camelCase")]
 +pub struct ViewCrateGraphParams {
 +    /// Include *all* crates, not just crates in the workspace.
 +    pub full: bool,
 +}
 +
 +pub enum ViewCrateGraph {}
 +
 +impl Request for ViewCrateGraph {
 +    type Params = ViewCrateGraphParams;
 +    type Result = String;
 +    const METHOD: &'static str = "rust-analyzer/viewCrateGraph";
 +}
 +
 +#[derive(Deserialize, Serialize, Debug)]
 +#[serde(rename_all = "camelCase")]
 +pub struct ViewItemTreeParams {
 +    pub text_document: TextDocumentIdentifier,
 +}
 +
 +pub enum ViewItemTree {}
 +
 +impl Request for ViewItemTree {
 +    type Params = ViewItemTreeParams;
 +    type Result = String;
 +    const METHOD: &'static str = "rust-analyzer/viewItemTree";
 +}
 +
 +pub enum ExpandMacro {}
 +
 +impl Request for ExpandMacro {
 +    type Params = ExpandMacroParams;
 +    type Result = Option<ExpandedMacro>;
 +    const METHOD: &'static str = "rust-analyzer/expandMacro";
 +}
 +
 +#[derive(Deserialize, Serialize, Debug)]
 +#[serde(rename_all = "camelCase")]
 +pub struct ExpandMacroParams {
 +    pub text_document: TextDocumentIdentifier,
 +    pub position: Position,
 +}
 +
 +#[derive(Deserialize, Serialize, Debug)]
 +#[serde(rename_all = "camelCase")]
 +pub struct ExpandedMacro {
 +    pub name: String,
 +    pub expansion: String,
 +}
 +
++pub enum CancelFlycheck {}
++
++impl Request for CancelFlycheck {
++    type Params = ();
++    type Result = ();
++    const METHOD: &'static str = "rust-analyzer/cancelFlycheck";
++}
++
 +pub enum MatchingBrace {}
 +
 +impl Request for MatchingBrace {
 +    type Params = MatchingBraceParams;
 +    type Result = Vec<Position>;
 +    const METHOD: &'static str = "experimental/matchingBrace";
 +}
 +
 +#[derive(Deserialize, Serialize, Debug)]
 +#[serde(rename_all = "camelCase")]
 +pub struct MatchingBraceParams {
 +    pub text_document: TextDocumentIdentifier,
 +    pub positions: Vec<Position>,
 +}
 +
 +pub enum ParentModule {}
 +
 +impl Request for ParentModule {
 +    type Params = lsp_types::TextDocumentPositionParams;
 +    type Result = Option<lsp_types::GotoDefinitionResponse>;
 +    const METHOD: &'static str = "experimental/parentModule";
 +}
 +
 +pub enum JoinLines {}
 +
 +impl Request for JoinLines {
 +    type Params = JoinLinesParams;
 +    type Result = Vec<lsp_types::TextEdit>;
 +    const METHOD: &'static str = "experimental/joinLines";
 +}
 +
 +#[derive(Deserialize, Serialize, Debug)]
 +#[serde(rename_all = "camelCase")]
 +pub struct JoinLinesParams {
 +    pub text_document: TextDocumentIdentifier,
 +    pub ranges: Vec<Range>,
 +}
 +
 +pub enum OnEnter {}
 +
 +impl Request for OnEnter {
 +    type Params = lsp_types::TextDocumentPositionParams;
 +    type Result = Option<Vec<SnippetTextEdit>>;
 +    const METHOD: &'static str = "experimental/onEnter";
 +}
 +
 +pub enum Runnables {}
 +
 +impl Request for Runnables {
 +    type Params = RunnablesParams;
 +    type Result = Vec<Runnable>;
 +    const METHOD: &'static str = "experimental/runnables";
 +}
 +
 +#[derive(Serialize, Deserialize, Debug)]
 +#[serde(rename_all = "camelCase")]
 +pub struct RunnablesParams {
 +    pub text_document: TextDocumentIdentifier,
 +    pub position: Option<Position>,
 +}
 +
 +#[derive(Deserialize, Serialize, Debug)]
 +#[serde(rename_all = "camelCase")]
 +pub struct Runnable {
 +    pub label: String,
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub location: Option<lsp_types::LocationLink>,
 +    pub kind: RunnableKind,
 +    pub args: CargoRunnable,
 +}
 +
 +#[derive(Serialize, Deserialize, Debug)]
 +#[serde(rename_all = "lowercase")]
 +pub enum RunnableKind {
 +    Cargo,
 +}
 +
 +#[derive(Deserialize, Serialize, Debug)]
 +#[serde(rename_all = "camelCase")]
 +pub struct CargoRunnable {
 +    // command to be executed instead of cargo
 +    pub override_cargo: Option<String>,
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub workspace_root: Option<PathBuf>,
 +    // command, --package and --lib stuff
 +    pub cargo_args: Vec<String>,
 +    // user-specified additional cargo args, like `--release`.
 +    pub cargo_extra_args: Vec<String>,
 +    // stuff after --
 +    pub executable_args: Vec<String>,
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub expect_test: Option<bool>,
 +}
 +
 +pub enum RelatedTests {}
 +
 +impl Request for RelatedTests {
 +    type Params = lsp_types::TextDocumentPositionParams;
 +    type Result = Vec<TestInfo>;
 +    const METHOD: &'static str = "rust-analyzer/relatedTests";
 +}
 +
 +#[derive(Debug, Deserialize, Serialize)]
 +pub struct TestInfo {
 +    pub runnable: Runnable,
 +}
 +
 +#[derive(Serialize, Deserialize, Debug)]
 +#[serde(rename_all = "camelCase")]
 +pub struct InlayHintsParams {
 +    pub text_document: TextDocumentIdentifier,
 +    pub range: Option<lsp_types::Range>,
 +}
 +
 +pub enum Ssr {}
 +
 +impl Request for Ssr {
 +    type Params = SsrParams;
 +    type Result = lsp_types::WorkspaceEdit;
 +    const METHOD: &'static str = "experimental/ssr";
 +}
 +
 +#[derive(Debug, Deserialize, Serialize)]
 +#[serde(rename_all = "camelCase")]
 +pub struct SsrParams {
 +    pub query: String,
 +    pub parse_only: bool,
 +
 +    /// File position where SSR was invoked. Paths in `query` will be resolved relative to this
 +    /// position.
 +    #[serde(flatten)]
 +    pub position: lsp_types::TextDocumentPositionParams,
 +
 +    /// Current selections. Search/replace will be restricted to these if non-empty.
 +    pub selections: Vec<lsp_types::Range>,
 +}
 +
 +pub enum ServerStatusNotification {}
 +
 +impl Notification for ServerStatusNotification {
 +    type Params = ServerStatusParams;
 +    const METHOD: &'static str = "experimental/serverStatus";
 +}
 +
 +#[derive(Deserialize, Serialize, PartialEq, Eq, Clone)]
 +pub struct ServerStatusParams {
 +    pub health: Health,
 +    pub quiescent: bool,
 +    pub message: Option<String>,
 +}
 +
 +#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
 +#[serde(rename_all = "camelCase")]
 +pub enum Health {
 +    Ok,
 +    Warning,
 +    Error,
 +}
 +
 +pub enum CodeActionRequest {}
 +
 +impl Request for CodeActionRequest {
 +    type Params = lsp_types::CodeActionParams;
 +    type Result = Option<Vec<CodeAction>>;
 +    const METHOD: &'static str = "textDocument/codeAction";
 +}
 +
 +pub enum CodeActionResolveRequest {}
 +impl Request for CodeActionResolveRequest {
 +    type Params = CodeAction;
 +    type Result = CodeAction;
 +    const METHOD: &'static str = "codeAction/resolve";
 +}
 +
 +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
 +#[serde(rename_all = "camelCase")]
 +pub struct CodeAction {
 +    pub title: String,
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub group: Option<String>,
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub kind: Option<CodeActionKind>,
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub command: Option<lsp_types::Command>,
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub edit: Option<SnippetWorkspaceEdit>,
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub is_preferred: Option<bool>,
 +
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub data: Option<CodeActionData>,
 +}
 +
 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
 +#[serde(rename_all = "camelCase")]
 +pub struct CodeActionData {
 +    pub code_action_params: lsp_types::CodeActionParams,
 +    pub id: String,
 +}
 +
 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
 +#[serde(rename_all = "camelCase")]
 +pub struct SnippetWorkspaceEdit {
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub changes: Option<HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>>>,
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub document_changes: Option<Vec<SnippetDocumentChangeOperation>>,
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub change_annotations:
 +        Option<HashMap<lsp_types::ChangeAnnotationIdentifier, lsp_types::ChangeAnnotation>>,
 +}
 +
 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
 +#[serde(untagged, rename_all = "lowercase")]
 +pub enum SnippetDocumentChangeOperation {
 +    Op(lsp_types::ResourceOp),
 +    Edit(SnippetTextDocumentEdit),
 +}
 +
 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
 +#[serde(rename_all = "camelCase")]
 +pub struct SnippetTextDocumentEdit {
 +    pub text_document: lsp_types::OptionalVersionedTextDocumentIdentifier,
 +    pub edits: Vec<SnippetTextEdit>,
 +}
 +
 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
 +#[serde(rename_all = "camelCase")]
 +pub struct SnippetTextEdit {
 +    pub range: Range,
 +    pub new_text: String,
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub insert_text_format: Option<lsp_types::InsertTextFormat>,
 +    /// The annotation id if this is an annotated
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub annotation_id: Option<lsp_types::ChangeAnnotationIdentifier>,
 +}
 +
 +pub enum HoverRequest {}
 +
 +impl Request for HoverRequest {
 +    type Params = HoverParams;
 +    type Result = Option<Hover>;
 +    const METHOD: &'static str = "textDocument/hover";
 +}
 +
 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
 +#[serde(rename_all = "camelCase")]
 +pub struct HoverParams {
 +    pub text_document: TextDocumentIdentifier,
 +    pub position: PositionOrRange,
 +
 +    #[serde(flatten)]
 +    pub work_done_progress_params: WorkDoneProgressParams,
 +}
 +
 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
 +#[serde(untagged)]
 +pub enum PositionOrRange {
 +    Position(lsp_types::Position),
 +    Range(lsp_types::Range),
 +}
 +
 +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
 +pub struct Hover {
 +    #[serde(flatten)]
 +    pub hover: lsp_types::Hover,
 +    #[serde(skip_serializing_if = "Vec::is_empty")]
 +    pub actions: Vec<CommandLinkGroup>,
 +}
 +
 +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
 +pub struct CommandLinkGroup {
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub title: Option<String>,
 +    pub commands: Vec<CommandLink>,
 +}
 +
 +// LSP v3.15 Command does not have a `tooltip` field, vscode supports one.
 +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
 +pub struct CommandLink {
 +    #[serde(flatten)]
 +    pub command: lsp_types::Command,
 +    #[serde(skip_serializing_if = "Option::is_none")]
 +    pub tooltip: Option<String>,
 +}
 +
 +pub enum ExternalDocs {}
 +
 +impl Request for ExternalDocs {
 +    type Params = lsp_types::TextDocumentPositionParams;
 +    type Result = Option<lsp_types::Url>;
 +    const METHOD: &'static str = "experimental/externalDocs";
 +}
 +
 +pub enum OpenCargoToml {}
 +
 +impl Request for OpenCargoToml {
 +    type Params = OpenCargoTomlParams;
 +    type Result = Option<lsp_types::GotoDefinitionResponse>;
 +    const METHOD: &'static str = "experimental/openCargoToml";
 +}
 +
 +#[derive(Serialize, Deserialize, Debug)]
 +#[serde(rename_all = "camelCase")]
 +pub struct OpenCargoTomlParams {
 +    pub text_document: TextDocumentIdentifier,
 +}
 +
 +/// Information about CodeLens, that is to be resolved.
 +#[derive(Debug, Serialize, Deserialize)]
 +#[serde(rename_all = "camelCase")]
 +pub(crate) enum CodeLensResolveData {
 +    Impls(lsp_types::request::GotoImplementationParams),
 +    References(lsp_types::TextDocumentPositionParams),
 +}
 +
 +pub fn supports_utf8(caps: &lsp_types::ClientCapabilities) -> bool {
 +    caps.offset_encoding.as_deref().unwrap_or_default().iter().any(|it| it == "utf-8")
 +}
 +
 +pub enum MoveItem {}
 +
 +impl Request for MoveItem {
 +    type Params = MoveItemParams;
 +    type Result = Vec<SnippetTextEdit>;
 +    const METHOD: &'static str = "experimental/moveItem";
 +}
 +
 +#[derive(Serialize, Deserialize, Debug)]
 +#[serde(rename_all = "camelCase")]
 +pub struct MoveItemParams {
 +    pub direction: MoveItemDirection,
 +    pub text_document: TextDocumentIdentifier,
 +    pub range: Range,
 +}
 +
 +#[derive(Serialize, Deserialize, Debug)]
 +pub enum MoveItemDirection {
 +    Up,
 +    Down,
 +}
 +
 +#[derive(Debug)]
 +pub enum WorkspaceSymbol {}
 +
 +impl Request for WorkspaceSymbol {
 +    type Params = WorkspaceSymbolParams;
 +    type Result = Option<Vec<lsp_types::SymbolInformation>>;
 +    const METHOD: &'static str = "workspace/symbol";
 +}
 +
 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
 +#[serde(rename_all = "camelCase")]
 +pub struct WorkspaceSymbolParams {
 +    #[serde(flatten)]
 +    pub partial_result_params: PartialResultParams,
 +
 +    #[serde(flatten)]
 +    pub work_done_progress_params: WorkDoneProgressParams,
 +
 +    /// A non-empty query string
 +    pub query: String,
 +
 +    pub search_scope: Option<WorkspaceSymbolSearchScope>,
 +
 +    pub search_kind: Option<WorkspaceSymbolSearchKind>,
 +}
 +
 +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
 +#[serde(rename_all = "camelCase")]
 +pub enum WorkspaceSymbolSearchScope {
 +    Workspace,
 +    WorkspaceAndDependencies,
 +}
 +
 +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
 +#[serde(rename_all = "camelCase")]
 +pub enum WorkspaceSymbolSearchKind {
 +    OnlyTypes,
 +    AllSymbols,
 +}
 +
 +/// The document on type formatting request is sent from the client to
 +/// the server to format parts of the document during typing.  This is
 +/// almost same as lsp_types::request::OnTypeFormatting, but the
 +/// result has SnippetTextEdit in it instead of TextEdit.
 +#[derive(Debug)]
 +pub enum OnTypeFormatting {}
 +
 +impl Request for OnTypeFormatting {
 +    type Params = DocumentOnTypeFormattingParams;
 +    type Result = Option<Vec<SnippetTextEdit>>;
 +    const METHOD: &'static str = "textDocument/onTypeFormatting";
 +}
 +
 +#[derive(Debug, Serialize, Deserialize)]
 +pub struct CompletionResolveData {
 +    pub position: lsp_types::TextDocumentPositionParams,
 +    pub imports: Vec<CompletionImport>,
 +}
 +
 +#[derive(Debug, Serialize, Deserialize)]
 +pub struct InlayHintResolveData {
 +    pub text_document: TextDocumentIdentifier,
 +    pub position: PositionOrRange,
 +}
 +
 +#[derive(Debug, Serialize, Deserialize)]
 +pub struct CompletionImport {
 +    pub full_import_path: String,
 +    pub imported_name: String,
 +}
 +
 +#[derive(Debug, Deserialize, Default)]
 +pub struct ClientCommandOptions {
 +    pub commands: Vec<String>,
 +}
index 77419998249f41fc49f2d66e1fc3f43a83ff6765,0000000000000000000000000000000000000000..f187547019a13524416a7676c72c30e85fa748b9
mode 100644,000000..100644
--- /dev/null
@@@ -1,881 -1,0 +1,882 @@@
-                 self.flycheck.iter().for_each(FlycheckHandle::update);
 +//! 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;
 +use ide_db::base_db::{SourceDatabase, 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");
 +
 +        tracing::debug!("handle_event({:?})", 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("Indexing", state, message, Some(fraction));
 +                }
 +            }
 +            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
-                                     flycheck.update();
++                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 diagnostics =
 +                    self.diagnostics.diagnostics_for(file_id).cloned().collect::<Vec<_>>();
 +                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),
 +            Task::Retry(req) => self.on_request(req),
 +            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("Fetching", state, msg, 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 {
 +                    self.report_progress("Loading", state, msg, 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)),
 +                )
 +            }
 +        }
 +    }
 +
 +    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) => {
 +                            tracing::error!("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::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)
 +                };
 +                self.report_progress(&title, state, message, None);
 +            }
 +        }
 +    }
 +
 +    /// 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(())
 +            })?
 +            .on::<lsp_types::notification::WorkDoneProgressCancel>(|_this, _params| {
 +                // 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 {
 +                        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 mut updated = false;
 +                if let Ok(vfs_path) = from_proto::vfs_path(&params.text_document.uri) {
 +                    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.update();
++                                    flycheck.restart();
 +                                    continue;
 +                                }
 +                            }
 +                        }
 +                    }
 +
 +                    // 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()));
 +                        }
 +                    }
 +                }
 +
 +                // No specific flycheck was triggered, so let's trigger all of them.
 +                if !updated {
 +                    for flycheck in &this.flycheck {
++                        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 a047f61fa03cbc177de53a1eaab12ca2b96b02fd,0000000000000000000000000000000000000000..ec3d3d444c365822f5c9d7efea9e8268f1bb36b1
mode 100644,000000..100644
--- /dev/null
@@@ -1,15 -1,0 +1,15 @@@
- //! Things which exist to solve practial issues, but which shouldn't exist.
++//! Things which exist to solve practical issues, but which shouldn't exist.
 +//!
 +//! Please avoid adding new usages of the functions in this module
 +
 +use crate::{ast, AstNode};
 +
 +pub fn parse_expr_from_str(s: &str) -> Option<ast::Expr> {
 +    let s = s.trim();
 +    let file = ast::SourceFile::parse(&format!("const _: () = {};", s));
 +    let expr = file.syntax_node().descendants().find_map(ast::Expr::cast)?;
 +    if expr.syntax().text() != s {
 +        return None;
 +    }
 +    Some(expr)
 +}
index f48d1ec66aae5a8e7093ee3d9caab98059793756,0000000000000000000000000000000000000000..6df29db4745d37840acc569b2e934b15fd06155f
mode 100644,000000..100644
--- /dev/null
@@@ -1,669 -1,0 +1,684 @@@
 +//! 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:
 +//!     sized:
 +//!     unsize: sized
 +//!     coerce_unsized: unsize
 +//!     slice:
 +//!     range:
 +//!     deref: sized
 +//!     deref_mut: deref
 +//!     index: sized
 +//!     fn:
 +//!     try:
 +//!     pin:
 +//!     future: pin
 +//!     option:
 +//!     result:
 +//!     iterator: option
 +//!     iterators: iterator, fn
 +//!     default: sized
 +//!     hash:
 +//!     clone: sized
 +//!     copy: clone
 +//!     from: sized
 +//!     eq: sized
 +//!     ord: eq, option
 +//!     derive:
 +//!     fmt: result
 +//!     bool_impl: option, fn
 +//!     add:
 +//!     as_ref: sized
 +//!     drop:
 +
 +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 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;
 +        }
 +        // 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),
 +        }
 +        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;
 +            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> {
 +            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: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,
 +    }
 +}
 +// 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::{Take, FilterMap};
 +
 +    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 9ee4415dcada091b4bd4ff50de7376964cef1423,0000000000000000000000000000000000000000..fcc693a7ddac16908a14beaf99c946e9553462cf
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,20 @@@
- notify = "=5.0.0-pre.15"
 +[package]
 +name = "vfs-notify"
 +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"
 +jod-thread = "0.1.2"
 +walkdir = "2.3.2"
 +crossbeam-channel = "0.5.5"
++notify = "=5.0.0-pre.16"
 +
 +vfs = { path = "../vfs", version = "0.0.0" }
 +paths = { path = "../paths", version = "0.0.0" }
index d6d9c66159fe1fa624c742d69a9ecfbbd3918de2,0000000000000000000000000000000000000000..c95304e55ac105e7e4264c9d58a6b689063fd226
mode 100644,000000..100644
--- /dev/null
@@@ -1,239 -1,0 +1,242 @@@
- use notify::{RecommendedWatcher, RecursiveMode, Watcher};
 +//! An implementation of `loader::Handle`, based on `walkdir` and `notify`.
 +//!
 +//! The file watching bits here are untested and quite probably buggy. For this
 +//! reason, by default we don't watch files and rely on editor's file watching
 +//! capabilities.
 +//!
 +//! Hopefully, one day a reliable file watching/walking crate appears on
 +//! crates.io, and we can reduce this to trivial glue code.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +use std::fs;
 +
 +use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
-                             let watcher = log_notify_error(RecommendedWatcher::new(move |event| {
-                                 watcher_sender.send(event).unwrap();
-                             }));
++use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
 +use paths::{AbsPath, AbsPathBuf};
 +use vfs::loader;
 +use walkdir::WalkDir;
 +
 +#[derive(Debug)]
 +pub struct NotifyHandle {
 +    // Relative order of fields below is significant.
 +    sender: Sender<Message>,
 +    _thread: jod_thread::JoinHandle,
 +}
 +
 +#[derive(Debug)]
 +enum Message {
 +    Config(loader::Config),
 +    Invalidate(AbsPathBuf),
 +}
 +
 +impl loader::Handle for NotifyHandle {
 +    fn spawn(sender: loader::Sender) -> NotifyHandle {
 +        let actor = NotifyActor::new(sender);
 +        let (sender, receiver) = unbounded::<Message>();
 +        let thread = jod_thread::Builder::new()
 +            .name("VfsLoader".to_owned())
 +            .spawn(move || actor.run(receiver))
 +            .expect("failed to spawn thread");
 +        NotifyHandle { sender, _thread: thread }
 +    }
 +
 +    fn set_config(&mut self, config: loader::Config) {
 +        self.sender.send(Message::Config(config)).unwrap();
 +    }
 +
 +    fn invalidate(&mut self, path: AbsPathBuf) {
 +        self.sender.send(Message::Invalidate(path)).unwrap();
 +    }
 +
 +    fn load_sync(&mut self, path: &AbsPath) -> Option<Vec<u8>> {
 +        read(path)
 +    }
 +}
 +
 +type NotifyEvent = notify::Result<notify::Event>;
 +
 +struct NotifyActor {
 +    sender: loader::Sender,
 +    watched_entries: Vec<loader::Entry>,
 +    // Drop order is significant.
 +    watcher: Option<(RecommendedWatcher, Receiver<NotifyEvent>)>,
 +}
 +
 +#[derive(Debug)]
 +enum Event {
 +    Message(Message),
 +    NotifyEvent(NotifyEvent),
 +}
 +
 +impl NotifyActor {
 +    fn new(sender: loader::Sender) -> NotifyActor {
 +        NotifyActor { sender, watched_entries: Vec::new(), watcher: None }
 +    }
 +
 +    fn next_event(&self, receiver: &Receiver<Message>) -> Option<Event> {
 +        let watcher_receiver = self.watcher.as_ref().map(|(_, receiver)| receiver);
 +        select! {
 +            recv(receiver) -> it => it.ok().map(Event::Message),
 +            recv(watcher_receiver.unwrap_or(&never())) -> it => Some(Event::NotifyEvent(it.unwrap())),
 +        }
 +    }
 +
 +    fn run(mut self, inbox: Receiver<Message>) {
 +        while let Some(event) = self.next_event(&inbox) {
 +            tracing::debug!(?event, "vfs-notify event");
 +            match event {
 +                Event::Message(msg) => match msg {
 +                    Message::Config(config) => {
 +                        self.watcher = None;
 +                        if !config.watch.is_empty() {
 +                            let (watcher_sender, watcher_receiver) = unbounded();
++                            let watcher = log_notify_error(RecommendedWatcher::new(
++                                move |event| {
++                                    watcher_sender.send(event).unwrap();
++                                },
++                                Config::default(),
++                            ));
 +                            self.watcher = watcher.map(|it| (it, watcher_receiver));
 +                        }
 +
 +                        let config_version = config.version;
 +
 +                        let n_total = config.load.len();
 +                        self.send(loader::Message::Progress { n_total, n_done: 0, config_version });
 +
 +                        self.watched_entries.clear();
 +
 +                        for (i, entry) in config.load.into_iter().enumerate() {
 +                            let watch = config.watch.contains(&i);
 +                            if watch {
 +                                self.watched_entries.push(entry.clone());
 +                            }
 +                            let files = self.load_entry(entry, watch);
 +                            self.send(loader::Message::Loaded { files });
 +                            self.send(loader::Message::Progress {
 +                                n_total,
 +                                n_done: i + 1,
 +                                config_version,
 +                            });
 +                        }
 +                    }
 +                    Message::Invalidate(path) => {
 +                        let contents = read(path.as_path());
 +                        let files = vec![(path, contents)];
 +                        self.send(loader::Message::Loaded { files });
 +                    }
 +                },
 +                Event::NotifyEvent(event) => {
 +                    if let Some(event) = log_notify_error(event) {
 +                        let files = event
 +                            .paths
 +                            .into_iter()
 +                            .map(|path| AbsPathBuf::try_from(path).unwrap())
 +                            .filter_map(|path| {
 +                                let meta = fs::metadata(&path).ok()?;
 +                                if meta.file_type().is_dir()
 +                                    && self
 +                                        .watched_entries
 +                                        .iter()
 +                                        .any(|entry| entry.contains_dir(&path))
 +                                {
 +                                    self.watch(path);
 +                                    return None;
 +                                }
 +
 +                                if !meta.file_type().is_file() {
 +                                    return None;
 +                                }
 +                                if !self
 +                                    .watched_entries
 +                                    .iter()
 +                                    .any(|entry| entry.contains_file(&path))
 +                                {
 +                                    return None;
 +                                }
 +
 +                                let contents = read(&path);
 +                                Some((path, contents))
 +                            })
 +                            .collect();
 +                        self.send(loader::Message::Loaded { files });
 +                    }
 +                }
 +            }
 +        }
 +    }
 +    fn load_entry(
 +        &mut self,
 +        entry: loader::Entry,
 +        watch: bool,
 +    ) -> Vec<(AbsPathBuf, Option<Vec<u8>>)> {
 +        match entry {
 +            loader::Entry::Files(files) => files
 +                .into_iter()
 +                .map(|file| {
 +                    if watch {
 +                        self.watch(file.clone());
 +                    }
 +                    let contents = read(file.as_path());
 +                    (file, contents)
 +                })
 +                .collect::<Vec<_>>(),
 +            loader::Entry::Directories(dirs) => {
 +                let mut res = Vec::new();
 +
 +                for root in &dirs.include {
 +                    let walkdir =
 +                        WalkDir::new(root).follow_links(true).into_iter().filter_entry(|entry| {
 +                            if !entry.file_type().is_dir() {
 +                                return true;
 +                            }
 +                            let path = AbsPath::assert(entry.path());
 +                            root == path
 +                                || dirs.exclude.iter().chain(&dirs.include).all(|it| it != path)
 +                        });
 +
 +                    let files = walkdir.filter_map(|it| it.ok()).filter_map(|entry| {
 +                        let is_dir = entry.file_type().is_dir();
 +                        let is_file = entry.file_type().is_file();
 +                        let abs_path = AbsPathBuf::assert(entry.into_path());
 +                        if is_dir && watch {
 +                            self.watch(abs_path.clone());
 +                        }
 +                        if !is_file {
 +                            return None;
 +                        }
 +                        let ext = abs_path.extension().unwrap_or_default();
 +                        if dirs.extensions.iter().all(|it| it.as_str() != ext) {
 +                            return None;
 +                        }
 +                        Some(abs_path)
 +                    });
 +
 +                    res.extend(files.map(|file| {
 +                        let contents = read(file.as_path());
 +                        (file, contents)
 +                    }));
 +                }
 +                res
 +            }
 +        }
 +    }
 +
 +    fn watch(&mut self, path: AbsPathBuf) {
 +        if let Some((watcher, _)) = &mut self.watcher {
 +            log_notify_error(watcher.watch(path.as_ref(), RecursiveMode::NonRecursive));
 +        }
 +    }
 +    fn send(&mut self, msg: loader::Message) {
 +        (self.sender)(msg);
 +    }
 +}
 +
 +fn read(path: &AbsPath) -> Option<Vec<u8>> {
 +    std::fs::read(path).ok()
 +}
 +
 +fn log_notify_error<T>(res: notify::Result<T>) -> Option<T> {
 +    res.map_err(|err| tracing::warn!("notify error: {}", err)).ok()
 +}
index 10fae41d081c70fdf5dc20586e48133f48ed13a9,0000000000000000000000000000000000000000..7badb1c363b44b46cfa0b74766a6fd74eae9d878
mode 100644,000000..100644
--- /dev/null
@@@ -1,221 -1,0 +1,221 @@@
- /// For more informations see the [crate-level](crate) documentation.
 +//! # Virtual File System
 +//!
 +//! VFS stores all files read by rust-analyzer. Reading file contents from VFS
 +//! always returns the same contents, unless VFS was explicitly modified with
 +//! [`set_file_contents`]. All changes to VFS are logged, and can be retrieved via
 +//! [`take_changes`] method. The pack of changes is then pushed to `salsa` and
 +//! triggers incremental recomputation.
 +//!
 +//! Files in VFS are identified with [`FileId`]s -- interned paths. The notion of
 +//! the path, [`VfsPath`] is somewhat abstract: at the moment, it is represented
 +//! as an [`std::path::PathBuf`] internally, but this is an implementation detail.
 +//!
 +//! VFS doesn't do IO or file watching itself. For that, see the [`loader`]
 +//! module. [`loader::Handle`] is an object-safe trait which abstracts both file
 +//! loading and file watching. [`Handle`] is dynamically configured with a set of
 +//! directory entries which should be scanned and watched. [`Handle`] then
 +//! asynchronously pushes file changes. Directory entries are configured in
 +//! free-form via list of globs, it's up to the [`Handle`] to interpret the globs
 +//! in any specific way.
 +//!
 +//! VFS stores a flat list of files. [`file_set::FileSet`] can partition this list
 +//! of files into disjoint sets of files. Traversal-like operations (including
 +//! getting the neighbor file by the relative path) are handled by the [`FileSet`].
 +//! [`FileSet`]s are also pushed to salsa and cause it to re-check `mod foo;`
 +//! declarations when files are created or deleted.
 +//!
 +//! [`FileSet`] and [`loader::Entry`] play similar, but different roles.
 +//! Both specify the "set of paths/files", one is geared towards file watching,
 +//! the other towards salsa changes. In particular, single [`FileSet`]
 +//! may correspond to several [`loader::Entry`]. For example, a crate from
 +//! crates.io which uses code generation would have two [`Entries`] -- for sources
 +//! in `~/.cargo`, and for generated code in `./target/debug/build`. It will
 +//! have a single [`FileSet`] which unions the two sources.
 +//!
 +//! [`set_file_contents`]: Vfs::set_file_contents
 +//! [`take_changes`]: Vfs::take_changes
 +//! [`FileSet`]: file_set::FileSet
 +//! [`Handle`]: loader::Handle
 +//! [`Entries`]: loader::Entry
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +mod anchored_path;
 +pub mod file_set;
 +pub mod loader;
 +mod path_interner;
 +mod vfs_path;
 +
 +use std::{fmt, mem};
 +
 +use crate::path_interner::PathInterner;
 +
 +pub use crate::{
 +    anchored_path::{AnchoredPath, AnchoredPathBuf},
 +    vfs_path::VfsPath,
 +};
 +pub use paths::{AbsPath, AbsPathBuf};
 +
 +/// Handle to a file in [`Vfs`]
 +///
 +/// Most functions in rust-analyzer use this when they need to refer to a file.
 +#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
 +pub struct FileId(pub u32);
 +
 +/// Storage for all files read by rust-analyzer.
 +///
++/// For more information see the [crate-level](crate) documentation.
 +#[derive(Default)]
 +pub struct Vfs {
 +    interner: PathInterner,
 +    data: Vec<Option<Vec<u8>>>,
 +    changes: Vec<ChangedFile>,
 +}
 +
 +/// Changed file in the [`Vfs`].
 +pub struct ChangedFile {
 +    /// Id of the changed file
 +    pub file_id: FileId,
 +    /// Kind of change
 +    pub change_kind: ChangeKind,
 +}
 +
 +impl ChangedFile {
 +    /// Returns `true` if the change is not [`Delete`](ChangeKind::Delete).
 +    pub fn exists(&self) -> bool {
 +        self.change_kind != ChangeKind::Delete
 +    }
 +
 +    /// Returns `true` if the change is [`Create`](ChangeKind::Create) or
 +    /// [`Delete`](ChangeKind::Delete).
 +    pub fn is_created_or_deleted(&self) -> bool {
 +        matches!(self.change_kind, ChangeKind::Create | ChangeKind::Delete)
 +    }
 +}
 +
 +/// Kind of [file change](ChangedFile).
 +#[derive(Eq, PartialEq, Copy, Clone, Debug)]
 +pub enum ChangeKind {
 +    /// The file was (re-)created
 +    Create,
 +    /// The file was modified
 +    Modify,
 +    /// The file was deleted
 +    Delete,
 +}
 +
 +impl Vfs {
 +    /// Amount of files currently stored.
 +    ///
 +    /// Note that this includes deleted files.
 +    pub fn len(&self) -> usize {
 +        self.data.len()
 +    }
 +
 +    /// Id of the given path if it exists in the `Vfs` and is not deleted.
 +    pub fn file_id(&self, path: &VfsPath) -> Option<FileId> {
 +        self.interner.get(path).filter(|&it| self.get(it).is_some())
 +    }
 +
 +    /// File path corresponding to the given `file_id`.
 +    ///
 +    /// # Panics
 +    ///
 +    /// Panics if the id is not present in the `Vfs`.
 +    pub fn file_path(&self, file_id: FileId) -> VfsPath {
 +        self.interner.lookup(file_id).clone()
 +    }
 +
 +    /// File content corresponding to the given `file_id`.
 +    ///
 +    /// # Panics
 +    ///
 +    /// Panics if the id is not present in the `Vfs`, or if the corresponding file is
 +    /// deleted.
 +    pub fn file_contents(&self, file_id: FileId) -> &[u8] {
 +        self.get(file_id).as_deref().unwrap()
 +    }
 +
 +    /// Returns an iterator over the stored ids and their corresponding paths.
 +    ///
 +    /// This will skip deleted files.
 +    pub fn iter(&self) -> impl Iterator<Item = (FileId, &VfsPath)> + '_ {
 +        (0..self.data.len())
 +            .map(|it| FileId(it as u32))
 +            .filter(move |&file_id| self.get(file_id).is_some())
 +            .map(move |file_id| {
 +                let path = self.interner.lookup(file_id);
 +                (file_id, path)
 +            })
 +    }
 +
 +    /// Update the `path` with the given `contents`. `None` means the file was deleted.
 +    ///
 +    /// Returns `true` if the file was modified, and saves the [change](ChangedFile).
 +    ///
 +    /// If the path does not currently exists in the `Vfs`, allocates a new
 +    /// [`FileId`] for it.
 +    pub fn set_file_contents(&mut self, path: VfsPath, contents: Option<Vec<u8>>) -> bool {
 +        let file_id = self.alloc_file_id(path);
 +        let change_kind = match (&self.get(file_id), &contents) {
 +            (None, None) => return false,
 +            (None, Some(_)) => ChangeKind::Create,
 +            (Some(_), None) => ChangeKind::Delete,
 +            (Some(old), Some(new)) if old == new => return false,
 +            (Some(_), Some(_)) => ChangeKind::Modify,
 +        };
 +
 +        *self.get_mut(file_id) = contents;
 +        self.changes.push(ChangedFile { file_id, change_kind });
 +        true
 +    }
 +
 +    /// Returns `true` if the `Vfs` contains [changes](ChangedFile).
 +    pub fn has_changes(&self) -> bool {
 +        !self.changes.is_empty()
 +    }
 +
 +    /// Drain and returns all the changes in the `Vfs`.
 +    pub fn take_changes(&mut self) -> Vec<ChangedFile> {
 +        mem::take(&mut self.changes)
 +    }
 +
 +    /// Returns the id associated with `path`
 +    ///
 +    /// - If `path` does not exists in the `Vfs`, allocate a new id for it, associated with a
 +    /// deleted file;
 +    /// - Else, returns `path`'s id.
 +    ///
 +    /// Does not record a change.
 +    fn alloc_file_id(&mut self, path: VfsPath) -> FileId {
 +        let file_id = self.interner.intern(path);
 +        let idx = file_id.0 as usize;
 +        let len = self.data.len().max(idx + 1);
 +        self.data.resize_with(len, || None);
 +        file_id
 +    }
 +
 +    /// Returns the content associated with the given `file_id`.
 +    ///
 +    /// # Panics
 +    ///
 +    /// Panics if no file is associated to that id.
 +    fn get(&self, file_id: FileId) -> &Option<Vec<u8>> {
 +        &self.data[file_id.0 as usize]
 +    }
 +
 +    /// Mutably returns the content associated with the given `file_id`.
 +    ///
 +    /// # Panics
 +    ///
 +    /// Panics if no file is associated to that id.
 +    fn get_mut(&mut self, file_id: FileId) -> &mut Option<Vec<u8>> {
 +        &mut self.data[file_id.0 as usize]
 +    }
 +}
 +
 +impl fmt::Debug for Vfs {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        f.debug_struct("Vfs").field("n_files", &self.data.len()).finish()
 +    }
 +}
index 51e26c58a9175d4c8c17efa58df77249a73860cd,0000000000000000000000000000000000000000..c173a239feab361b0a99d0fbab1a3e88cab4b62d
mode 100644,000000..100644
--- /dev/null
@@@ -1,497 -1,0 +1,497 @@@
- This easiness is misleading -- serializable types impose significant backwards compatability constraints.
 +# Architecture
 +
 +This document describes the high-level architecture of rust-analyzer.
 +If you want to familiarize yourself with the code base, you are just in the right place!
 +
 +You might also enjoy ["Explaining Rust Analyzer"](https://www.youtube.com/playlist?list=PLhb66M_x9UmrqXhQuIpWC5VgTdrGxMx3y) series on YouTube.
 +It goes deeper than what is covered in this document, but will take some time to watch.
 +
 +See also these implementation-related blog posts:
 +
 +* https://rust-analyzer.github.io/blog/2019/11/13/find-usages.html
 +* https://rust-analyzer.github.io/blog/2020/07/20/three-architectures-for-responsive-ide.html
 +* https://rust-analyzer.github.io/blog/2020/09/16/challeging-LR-parsing.html
 +* https://rust-analyzer.github.io/blog/2020/09/28/how-to-make-a-light-bulb.html
 +* https://rust-analyzer.github.io/blog/2020/10/24/introducing-ungrammar.html
 +
 +For older, by now mostly outdated stuff, see the [guide](./guide.md) and [another playlist](https://www.youtube.com/playlist?list=PL85XCvVPmGQho7MZkdW-wtPtuJcFpzycE).
 +
 +
 +## Bird's Eye View
 +
 +![](https://user-images.githubusercontent.com/4789492/107129398-0ab70f00-687a-11eb-9bfc-d4eb023aec06.png)
 +
 +On the highest level, rust-analyzer is a thing which accepts input source code from the client and produces a structured semantic model of the code.
 +
 +More specifically, input data consists of a set of test files (`(PathBuf, String)` pairs) and information about project structure, captured in the so called `CrateGraph`.
 +The crate graph specifies which files are crate roots, which cfg flags are specified for each crate and what dependencies exist between the crates.
 +This is the input (ground) state.
 +The analyzer keeps all this input data in memory and never does any IO.
 +Because the input data is source code, which typically measures in tens of megabytes at most, keeping everything in memory is OK.
 +
 +A "structured semantic model" is basically an object-oriented representation of modules, functions and types which appear in the source code.
 +This representation is fully "resolved": all expressions have types, all references are bound to declarations, etc.
 +This is derived state.
 +
 +The client can submit a small delta of input data (typically, a change to a single file) and get a fresh code model which accounts for changes.
 +
 +The underlying engine makes sure that model is computed lazily (on-demand) and can be quickly updated for small modifications.
 +
 +## Entry Points
 +
 +`crates/rust-analyzer/src/bin/main.rs` contains the main function which spawns LSP.
 +This is *the* entry point, but it front-loads a lot of complexity, so it's fine to just skim through it.
 +
 +`crates/rust-analyzer/src/handlers.rs` implements all LSP requests and is a great place to start if you are already familiar with LSP.
 +
 +`Analysis` and `AnalysisHost` types define the main API for consumers of IDE services.
 +
 +## Code Map
 +
 +This section talks briefly about various important directories and data structures.
 +Pay attention to the **Architecture Invariant** sections.
 +They often talk about things which are deliberately absent in the source code.
 +
 +Note also which crates are **API Boundaries**.
 +Remember, [rules at the boundary are different](https://www.tedinski.com/2018/02/06/system-boundaries.html).
 +
 +### `xtask`
 +
 +This is rust-analyzer's "build system".
 +We use cargo to compile rust code, but there are also various other tasks, like release management or local installation.
 +They are handled by Rust code in the xtask directory.
 +
 +### `editors/code`
 +
 +VS Code plugin.
 +
 +### `lib/`
 +
 +rust-analyzer independent libraries which we publish to crates.io.
 +It's not heavily utilized at the moment.
 +
 +### `crates/parser`
 +
 +It is a hand-written recursive descent parser, which produces a sequence of events like "start node X", "finish node Y".
 +It works similarly to
 +[kotlin's parser](https://github.com/JetBrains/kotlin/blob/4d951de616b20feca92f3e9cc9679b2de9e65195/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinParsing.java),
 +which is a good source of inspiration for dealing with syntax errors and incomplete input.
 +Original [libsyntax parser](https://github.com/rust-lang/rust/blob/6b99adeb11313197f409b4f7c4083c2ceca8a4fe/src/libsyntax/parse/parser.rs) is what we use for the definition of the Rust language.
 +`TreeSink` and `TokenSource` traits bridge the tree-agnostic parser from `grammar` with `rowan` trees.
 +
 +**Architecture Invariant:** the parser is independent of the particular tree structure and particular representation of the tokens.
 +It transforms one flat stream of events into another flat stream of events.
 +Token independence allows us to parse out both text-based source code and `tt`-based macro input.
 +Tree independence allows us to more easily vary the syntax tree implementation.
 +It should also unlock efficient light-parsing approaches.
 +For example, you can extract the set of names defined in a file (for typo correction) without building a syntax tree.
 +
 +**Architecture Invariant:** parsing never fails, the parser produces `(T, Vec<Error>)` rather than `Result<T, Error>`.
 +
 +### `crates/syntax`
 +
 +Rust syntax tree structure and parser.
 +See [RFC](https://github.com/rust-lang/rfcs/pull/2256) and [./syntax.md](./syntax.md) for some design notes.
 +
 +- [rowan](https://github.com/rust-analyzer/rowan) library is used for constructing syntax trees.
 +- `ast` provides a type safe API on top of the raw `rowan` tree.
 +- `ungrammar` description of the grammar, which is used to generate `syntax_kinds` and `ast` modules, using `cargo test -p xtask` command.
 +
 +Tests for ra_syntax are mostly data-driven.
 +`test_data/parser` contains subdirectories with a bunch of `.rs` (test vectors) and `.txt` files with corresponding syntax trees.
 +During testing, we check `.rs` against `.txt`.
 +If the `.txt` file is missing, it is created (this is how you update tests).
 +Additionally, running the xtask test suite with `cargo test -p xtask` will walk the grammar module and collect all `// test test_name` comments into files inside `test_data/parser/inline` directory.
 +
 +To update test data, run with `UPDATE_EXPECT` variable:
 +
 +```bash
 +env UPDATE_EXPECT=1 cargo qt
 +```
 +
 +After adding a new inline test you need to run `cargo test -p xtask` and also update the test data as described above.
 +
 +Note [`api_walkthrough`](https://github.com/rust-lang/rust-analyzer/blob/2fb6af89eb794f775de60b82afe56b6f986c2a40/crates/ra_syntax/src/lib.rs#L190-L348)
 +in particular: it shows off various methods of working with syntax tree.
 +
 +See [#93](https://github.com/rust-lang/rust-analyzer/pull/93) for an example PR which fixes a bug in the grammar.
 +
 +**Architecture Invariant:** `syntax` crate is completely independent from the rest of rust-analyzer. It knows nothing about salsa or LSP.
 +This is important because it is possible to make useful tooling using only the syntax tree.
 +Without semantic information, you don't need to be able to _build_ code, which makes the tooling more robust.
 +See also https://web.stanford.edu/~mlfbrown/paper.pdf.
 +You can view the `syntax` crate as an entry point to rust-analyzer.
 +`syntax` crate is an **API Boundary**.
 +
 +**Architecture Invariant:** syntax tree is a value type.
 +The tree is fully determined by the contents of its syntax nodes, it doesn't need global context (like an interner) and doesn't store semantic info.
 +Using the tree as a store for semantic info is convenient in traditional compilers, but doesn't work nicely in the IDE.
 +Specifically, assists and refactors require transforming syntax trees, and that becomes awkward if you need to do something with the semantic info.
 +
 +**Architecture Invariant:** syntax tree is built for a single file.
 +This is to enable parallel parsing of all files.
 +
 +**Architecture Invariant:**  Syntax trees are by design incomplete and do not enforce well-formedness.
 +If an AST method returns an `Option`, it *can* be `None` at runtime, even if this is forbidden by the grammar.
 +
 +### `crates/base_db`
 +
 +We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and on-demand computation.
 +Roughly, you can think of salsa as a key-value store, but it can also compute derived values using specified functions.
 +The `base_db` crate provides basic infrastructure for interacting with salsa.
 +Crucially, it defines most of the "input" queries: facts supplied by the client of the analyzer.
 +Reading the docs of the `base_db::input` module should be useful: everything else is strictly derived from those inputs.
 +
 +**Architecture Invariant:** particularities of the build system are *not* the part of the ground state.
 +In particular, `base_db` knows nothing about cargo.
 +For example, `cfg` flags are a part of `base_db`, but `feature`s are not.
 +A `foo` feature is a Cargo-level concept, which is lowered by Cargo to `--cfg feature=foo` argument on the command line.
 +The `CrateGraph` structure is used to represent the dependencies between the crates abstractly.
 +
 +**Architecture Invariant:** `base_db` doesn't know about file system and file paths.
 +Files are represented with opaque `FileId`, there's no operation to get an `std::path::Path` out of the `FileId`.
 +
 +### `crates/hir_expand`, `crates/hir_def`, `crates/hir_ty`
 +
 +These crates are the *brain* of rust-analyzer.
 +This is the compiler part of the IDE.
 +
 +`hir_xxx` crates have a strong [ECS](https://en.wikipedia.org/wiki/Entity_component_system) flavor, in that they work with raw ids and directly query the database.
 +There's little abstraction here.
 +These crates integrate deeply with salsa and chalk.
 +
 +Name resolution, macro expansion and type inference all happen here.
 +These crates also define various intermediate representations of the core.
 +
 +`ItemTree` condenses a single `SyntaxTree` into a "summary" data structure, which is stable over modifications to function bodies.
 +
 +`DefMap` contains the module tree of a crate and stores module scopes.
 +
 +`Body` stores information about expressions.
 +
 +**Architecture Invariant:** these crates are not, and will never be, an api boundary.
 +
 +**Architecture Invariant:** these crates explicitly care about being incremental.
 +The core invariant we maintain is "typing inside a function's body never invalidates global derived data".
 +i.e., if you change the body of `foo`, all facts about `bar` should remain intact.
 +
 +**Architecture Invariant:** hir exists only in context of particular crate instance with specific CFG flags.
 +The same syntax may produce several instances of HIR if the crate participates in the crate graph more than once.
 +
 +### `crates/hir`
 +
 +The top-level `hir` crate is an **API Boundary**.
 +If you think about "using rust-analyzer as a library", `hir` crate is most likely the façade you'll be talking to.
 +
 +It wraps ECS-style internal API into a more OO-flavored API (with an extra `db` argument for each call).
 +
 +**Architecture Invariant:** `hir` provides a static, fully resolved view of the code.
 +While internal `hir_*` crates _compute_ things, `hir`, from the outside, looks like an inert data structure.
 +
 +`hir` also handles the delicate task of going from syntax to the corresponding `hir`.
 +Remember that the mapping here is one-to-many.
 +See `Semantics` type and `source_to_def` module.
 +
 +Note in particular a curious recursive structure in `source_to_def`.
 +We first resolve the parent _syntax_ node to the parent _hir_ element.
 +Then we ask the _hir_ parent what _syntax_ children does it have.
 +Then we look for our node in the set of children.
 +
 +This is the heart of many IDE features, like goto definition, which start with figuring out the hir node at the cursor.
 +This is some kind of (yet unnamed) uber-IDE pattern, as it is present in Roslyn and Kotlin as well.
 +
 +### `crates/ide`
 +
 +The `ide` crate builds on top of `hir` semantic model to provide high-level IDE features like completion or goto definition.
 +It is an **API Boundary**.
 +If you want to use IDE parts of rust-analyzer via LSP, custom flatbuffers-based protocol or just as a library in your text editor, this is the right API.
 +
 +**Architecture Invariant:** `ide` crate's API is build out of POD types with public fields.
 +The API uses editor's terminology, it talks about offsets and string labels rather than in terms of definitions or types.
 +It is effectively the view in MVC and viewmodel in [MVVM](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel).
 +All arguments and return types are conceptually serializable.
 +In particular, syntax trees and hir types are generally absent from the API (but are used heavily in the implementation).
 +Shout outs to LSP developers for popularizing the idea that "UI" is a good place to draw a boundary at.
 +
 +`ide` is also the first crate which has the notion of change over time.
 +`AnalysisHost` is a state to which you can transactionally `apply_change`.
 +`Analysis` is an immutable snapshot of the state.
 +
 +Internally, `ide` is split across several crates. `ide_assists`, `ide_completion` and `ide_ssr` implement large isolated features.
 +`ide_db` implements common IDE functionality (notably, reference search is implemented here).
 +The `ide` contains a public API/façade, as well as implementation for a plethora of smaller features.
 +
 +**Architecture Invariant:** `ide` crate strives to provide a _perfect_ API.
 +Although at the moment it has only one consumer, the LSP server, LSP *does not* influence its API design.
 +Instead, we keep in mind a hypothetical _ideal_ client -- an IDE tailored specifically for rust, every nook and cranny of which is packed with Rust-specific goodies.
 +
 +### `crates/rust-analyzer`
 +
 +This crate defines the `rust-analyzer` binary, so it is the **entry point**.
 +It implements the language server.
 +
 +**Architecture Invariant:** `rust-analyzer` is the only crate that knows about LSP and JSON serialization.
 +If you want to expose a data structure `X` from ide to LSP, don't make it serializable.
 +Instead, create a serializable counterpart in `rust-analyzer` crate and manually convert between the two.
 +
 +`GlobalState` is the state of the server.
 +The `main_loop` defines the server event loop which accepts requests and sends responses.
 +Requests that modify the state or might block user's typing are handled on the main thread.
 +All other requests are processed in background.
 +
 +**Architecture Invariant:** the server is stateless, a-la HTTP.
 +Sometimes state needs to be preserved between requests.
 +For example, "what is the `edit` for the fifth completion item of the last completion edit?".
 +For this, the second request should include enough info to re-create the context from scratch.
 +This generally means including all the parameters of the original request.
 +
 +`reload` module contains the code that handles configuration and Cargo.toml changes.
 +This is a tricky business.
 +
 +**Architecture Invariant:** `rust-analyzer` should be partially available even when the build is broken.
 +Reloading process should not prevent IDE features from working.
 +
 +### `crates/toolchain`, `crates/project_model`, `crates/flycheck`
 +
 +These crates deal with invoking `cargo` to learn about project structure and get compiler errors for the "check on save" feature.
 +
 +They use `crates/path` heavily instead of `std::path`.
 +A single `rust-analyzer` process can serve many projects, so it is important that server's current directory does not leak.
 +
 +### `crates/mbe`, `crates/tt`, `crates/proc_macro_api`, `crates/proc_macro_srv`
 +
 +These crates implement macros as token tree -> token tree transforms.
 +They are independent from the rest of the code.
 +
 +`tt` crate defined `TokenTree`, a single token or a delimited sequence of token trees.
 +`mbe` crate contains tools for transforming between syntax trees and token tree.
 +And it also handles the actual parsing and expansion of declarative macro (a-la "Macros By Example" or mbe).
 +
 +For proc macros, the client-server model are used.
 +We pass an argument `--proc-macro` to `rust-analyzer` binary to start a separate process  (`proc_macro_srv`).
 +And the client (`proc_macro_api`) provides an interface to talk to that server separately.
 +
 +And then token trees are passed from client, and the server will load the corresponding dynamic library (which built by `cargo`).
 +And due to the fact the api for getting result from proc macro are always unstable in `rustc`,
 +we maintain our own copy (and paste) of that part of code to allow us to build the whole thing in stable rust.
 +
 + **Architecture Invariant:**
 +Bad proc macros may panic or segfault accidentally. So we run it in another process and recover it from fatal error.
 +And they may be non-deterministic which conflict how `salsa` works, so special attention is required.
 +
 +### `crates/cfg`
 +
 +This crate is responsible for parsing, evaluation and general definition of `cfg` attributes.
 +
 +### `crates/vfs`, `crates/vfs-notify`
 +
 +These crates implement a virtual file system.
 +They provide consistent snapshots of the underlying file system and insulate messy OS paths.
 +
 +**Architecture Invariant:** vfs doesn't assume a single unified file system.
 +i.e., a single rust-analyzer process can act as a remote server for two different machines, where the same `/tmp/foo.rs` path points to different files.
 +For this reason, all path APIs generally take some existing path as a "file system witness".
 +
 +### `crates/stdx`
 +
 +This crate contains various non-rust-analyzer specific utils, which could have been in std, as well
 +as copies of unstable std items we would like to make use of already, like `std::str::split_once`.
 +
 +### `crates/profile`
 +
 +This crate contains utilities for CPU and memory profiling.
 +
 +
 +## Cross-Cutting Concerns
 +
 +This sections talks about the things which are everywhere and nowhere in particular.
 +
 +### Stability Guarantees
 +
 +One of the reasons rust-analyzer moves relatively fast is that we don't introduce new stability guarantees.
 +Instead, as much as possible we leverage existing ones.
 +
 +Examples:
 +
 +* The `ide` API of rust-analyzer are explicitly unstable, but the LSP interface is stable, and here we just implement a stable API managed by someone else.
 +* Rust language and Cargo are stable, and they are the primary inputs to rust-analyzer.
 +* The `rowan` library is published to crates.io, but it is deliberately kept under `1.0` and always makes semver-incompatible upgrades
 +
 +Another important example is that rust-analyzer isn't run on CI, so, unlike `rustc` and `clippy`, it is actually ok for us to change runtime behavior.
 +
 +At some point we might consider opening up APIs or allowing crates.io libraries to include rust-analyzer specific annotations, but that's going to be a big commitment on our side.
 +
 +Exceptions:
 +
 +* `rust-project.json` is a de-facto stable format for non-cargo build systems.
 +  It is probably ok enough, but was definitely stabilized implicitly.
 +  Lesson for the future: when designing API which could become a stability boundary, don't wait for the first users until you stabilize it.
 +  By the time you have first users, it is already de-facto stable.
 +  And the users will first use the thing, and *then* inform you that now you have users.
 +  The sad thing is that stuff should be stable before someone uses it for the first time, or it should contain explicit opt-in.
 +* We ship some LSP extensions, and we try to keep those somewhat stable.
 +  Here, we need to work with a finite set of editor maintainers, so not providing rock-solid guarantees works.
 +
 +### Code generation
 +
 +Some components in this repository are generated through automatic processes.
 +Generated code is updated automatically on `cargo test`.
 +Generated code is generally committed to the git repository.
 +
 +In particular, we generate:
 +
 +* API for working with syntax trees (`syntax::ast`, the [`ungrammar`](https://github.com/rust-analyzer/ungrammar) crate).
 +* Various sections of the manual:
 +
 +    * features
 +    * assists
 +    * config
 +
 +* Documentation tests for assists
 +
 +See the `sourcegen` crate for details.
 +
 +**Architecture Invariant:** we avoid bootstrapping.
 +For codegen we need to parse Rust code.
 +Using rust-analyzer for that would work and would be fun, but it would also complicate the build process a lot.
 +For that reason, we use syn and manual string parsing.
 +
 +### Cancellation
 +
 +Let's say that the IDE is in the process of computing syntax highlighting, when the user types `foo`.
 +What should happen?
 +`rust-analyzer`s answer is that the highlighting process should be cancelled -- its results are now stale, and it also blocks modification of the inputs.
 +
 +The salsa database maintains a global revision counter.
 +When applying a change, salsa bumps this counter and waits until all other threads using salsa finish.
 +If a thread does salsa-based computation and notices that the counter is incremented, it panics with a special value (see `Canceled::throw`).
 +That is, rust-analyzer requires unwinding.
 +
 +`ide` is the boundary where the panic is caught and transformed into a `Result<T, Cancelled>`.
 +
 +### Testing
 +
 +rust-analyzer has three interesting [system boundaries](https://www.tedinski.com/2018/04/10/making-tests-a-positive-influence-on-design.html) to concentrate tests on.
 +
 +The outermost boundary is the `rust-analyzer` crate, which defines an LSP interface in terms of stdio.
 +We do integration testing of this component, by feeding it with a stream of LSP requests and checking responses.
 +These tests are known as "heavy", because they interact with Cargo and read real files from disk.
 +For this reason, we try to avoid writing too many tests on this boundary: in a statically typed language, it's hard to make an error in the protocol itself if messages are themselves typed.
 +Heavy tests are only run when `RUN_SLOW_TESTS` env var is set.
 +
 +The middle, and most important, boundary is `ide`.
 +Unlike `rust-analyzer`, which exposes API, `ide` uses Rust API and is intended for use by various tools.
 +A typical test creates an `AnalysisHost`, calls some `Analysis` functions and compares the results against expectation.
 +
 +The innermost and most elaborate boundary is `hir`.
 +It has a much richer vocabulary of types than `ide`, but the basic testing setup is the same: we create a database, run some queries, assert result.
 +
 +For comparisons, we use the `expect` crate for snapshot testing.
 +
 +To test various analysis corner cases and avoid forgetting about old tests, we use so-called marks.
 +See the `marks` module in the `test_utils` crate for more.
 +
 +**Architecture Invariant:** rust-analyzer tests do not use libcore or libstd.
 +All required library code must be a part of the tests.
 +This ensures fast test execution.
 +
 +**Architecture Invariant:** tests are data driven and do not test the API.
 +Tests which directly call various API functions are a liability, because they make refactoring the API significantly more complicated.
 +So most of the tests look like this:
 +
 +```rust
 +#[track_caller]
 +fn check(input: &str, expect: expect_test::Expect) {
 +    // The single place that actually exercises a particular API
 +}
 +
 +#[test]
 +fn foo() {
 +    check("foo", expect![["bar"]]);
 +}
 +
 +#[test]
 +fn spam() {
 +    check("spam", expect![["eggs"]]);
 +}
 +// ...and a hundred more tests that don't care about the specific API at all.
 +```
 +
 +To specify input data, we use a single string literal in a special format, which can describe a set of rust files.
 +See the `Fixture` its module for fixture examples and documentation.
 +
 +**Architecture Invariant:** all code invariants are tested by `#[test]` tests.
 +There's no additional checks in CI, formatting and tidy tests are run with `cargo test`.
 +
 +**Architecture Invariant:** tests do not depend on any kind of external resources, they are perfectly reproducible.
 +
 +
 +### Performance Testing
 +
 +TBA, take a look at the `metrics` xtask and `#[test] fn benchmark_xxx()` functions.
 +
 +### Error Handling
 +
 +**Architecture Invariant:** core parts of rust-analyzer (`ide`/`hir`) don't interact with the outside world and thus can't fail.
 +Only parts touching LSP are allowed to do IO.
 +
 +Internals of rust-analyzer need to deal with broken code, but this is not an error condition.
 +rust-analyzer is robust: various analysis compute `(T, Vec<Error>)` rather than `Result<T, Error>`.
 +
 +rust-analyzer is a complex long-running process.
 +It will always have bugs and panics.
 +But a panic in an isolated feature should not bring down the whole process.
 +Each LSP-request is protected by a `catch_unwind`.
 +We use `always` and `never` macros instead of `assert` to gracefully recover from impossible conditions.
 +
 +### Observability
 +
 +rust-analyzer is a long-running process, so it is important to understand what's going on inside.
 +We have several instruments for that.
 +
 +The event loop that runs rust-analyzer is very explicit.
 +Rather than spawning futures or scheduling callbacks (open), the event loop accepts an `enum` of possible events (closed).
 +It's easy to see all the things that trigger rust-analyzer processing, together with their performance
 +
 +rust-analyzer includes a simple hierarchical profiler (`hprof`).
 +It is enabled with `RA_PROFILE='*>50'` env var (log all (`*`) actions which take more than `50` ms) and produces output like:
 +
 +```
 +85ms - handle_completion
 +    68ms - import_on_the_fly
 +        67ms - import_assets::search_for_relative_paths
 +             0ms - crate_def_map:wait (804 calls)
 +             0ms - find_path (16 calls)
 +             2ms - find_similar_imports (1 calls)
 +             0ms - generic_params_query (334 calls)
 +            59ms - trait_solve_query (186 calls)
 +         0ms - Semantics::analyze_impl (1 calls)
 +         1ms - render_resolution (8 calls)
 +     0ms - Semantics::analyze_impl (5 calls)
 +```
 +
 +This is cheap enough to enable in production.
 +
 +
 +Similarly, we save live object counting (`RA_COUNT=1`).
 +It is not cheap enough to enable in prod, and this is a bug which should be fixed.
 +
 +### Configurability
 +
 +rust-analyzer strives to be as configurable as possible while offering reasonable defaults where no configuration exists yet.
 +There will always be features that some people find more annoying than helpful, so giving the users the ability to tweak or disable these is a big part of offering a good user experience.
 +Mind the code--architecture gap: at the moment, we are using fewer feature flags than we really should.
 +
 +### Serialization
 +
 +In Rust, it is easy (often too easy) to add serialization to any type by adding `#[derive(Serialize)]`.
++This easiness is misleading -- serializable types impose significant backwards compatibility constraints.
 +If a type is serializable, then it is a part of some IPC boundary.
 +You often don't control the other side of this boundary, so changing serializable types is hard.
 +
 +For this reason, the types in `ide`, `base_db` and below are not serializable by design.
 +If such types need to cross an IPC boundary, then the client of rust-analyzer needs to provide custom, client-specific serialization format.
 +This isolates backwards compatibility and migration concerns to a specific client.
 +
 +For example, `rust-project.json` is it's own format -- it doesn't include `CrateGraph` as is.
 +Instead, it creates a `CrateGraph` by calling appropriate constructing functions.
index 5040643d34a32338eebf6451785387e5c2e5ad23,0000000000000000000000000000000000000000..6d2c7d7b06349aa0ac63493351107cfe350303dc
mode 100644,000000..100644
--- /dev/null
@@@ -1,761 -1,0 +1,761 @@@
- lsp_ext.rs hash: 2a188defec26cc7c
 +<!---
++lsp_ext.rs hash: 7b710095d773b978
 +
 +If you need to change the above hash to make the test pass, please check if you
 +need to adjust this doc as well and ping this issue:
 +
 +  https://github.com/rust-lang/rust-analyzer/issues/4604
 +
 +--->
 +
 +# LSP Extensions
 +
 +This document describes LSP extensions used by rust-analyzer.
 +It's a best effort document, when in doubt, consult the source (and send a PR with clarification ;-) ).
 +We aim to upstream all non Rust-specific extensions to the protocol, but this is not a top priority.
 +All capabilities are enabled via the `experimental` field of `ClientCapabilities` or `ServerCapabilities`.
 +Requests which we hope to upstream live under `experimental/` namespace.
 +Requests, which are likely to always remain specific to `rust-analyzer` are under `rust-analyzer/` namespace.
 +
 +If you want to be notified about the changes to this document, subscribe to [#4604](https://github.com/rust-lang/rust-analyzer/issues/4604).
 +
 +## UTF-8 offsets
 +
 +rust-analyzer supports clangd's extension for opting into UTF-8 as the coordinate space for offsets (by default, LSP uses UTF-16 offsets).
 +
 +https://clangd.llvm.org/extensions.html#utf-8-offsets
 +
 +## Configuration in `initializationOptions`
 +
 +**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/567
 +
 +The `initializationOptions` field of the `InitializeParams` of the initialization request should contain the `"rust-analyzer"` section of the configuration.
 +
 +`rust-analyzer` normally sends a `"workspace/configuration"` request with `{ "items": ["rust-analyzer"] }` payload.
 +However, the server can't do this during initialization.
 +At the same time some essential configuration parameters are needed early on, before servicing requests.
 +For this reason, we ask that `initializationOptions` contains the configuration, as if the server did make a `"workspace/configuration"` request.
 +
 +If a language client does not know about `rust-analyzer`'s configuration options it can get sensible defaults by doing any of the following:
 + * Not sending `initializationOptions`
 + * Sending `"initializationOptions": null`
 + * Sending `"initializationOptions": {}`
 +
 +## Snippet `TextEdit`
 +
 +**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/724
 +
 +**Experimental Client Capability:** `{ "snippetTextEdit": boolean }`
 +
 +If this capability is set, `WorkspaceEdit`s returned from `codeAction` requests and `TextEdit`s returned from `textDocument/onTypeFormatting` requests might contain `SnippetTextEdit`s instead of usual `TextEdit`s:
 +
 +```typescript
 +interface SnippetTextEdit extends TextEdit {
 +    insertTextFormat?: InsertTextFormat;
 +    annotationId?: ChangeAnnotationIdentifier;
 +}
 +```
 +
 +```typescript
 +export interface TextDocumentEdit {
 +    textDocument: OptionalVersionedTextDocumentIdentifier;
 +    edits: (TextEdit | SnippetTextEdit)[];
 +}
 +```
 +
 +When applying such code action or text edit, the editor should insert snippet, with tab stops and placeholder.
 +At the moment, rust-analyzer guarantees that only a single edit will have `InsertTextFormat.Snippet`.
 +
 +### Example
 +
 +"Add `derive`" code action transforms `struct S;` into `#[derive($0)] struct S;`
 +
 +### Unresolved Questions
 +
 +* Where exactly are `SnippetTextEdit`s allowed (only in code actions at the moment)?
 +* Can snippets span multiple files (so far, no)?
 +
 +## `CodeAction` Groups
 +
 +**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/994
 +
 +**Experimental Client Capability:** `{ "codeActionGroup": boolean }`
 +
 +If this capability is set, `CodeAction`s returned from the server contain an additional field, `group`:
 +
 +```typescript
 +interface CodeAction {
 +    title: string;
 +    group?: string;
 +    ...
 +}
 +```
 +
 +All code-actions with the same `group` should be grouped under single (extendable) entry in lightbulb menu.
 +The set of actions `[ { title: "foo" }, { group: "frobnicate", title: "bar" }, { group: "frobnicate", title: "baz" }]` should be rendered as
 +
 +```
 +💡
 +  +-------------+
 +  | foo         |
 +  +-------------+-----+
 +  | frobnicate >| bar |
 +  +-------------+-----+
 +                | baz |
 +                +-----+
 +```
 +
 +Alternatively, selecting `frobnicate` could present a user with an additional menu to choose between `bar` and `baz`.
 +
 +### Example
 +
 +```rust
 +fn main() {
 +    let x: Entry/*cursor here*/ = todo!();
 +}
 +```
 +
 +Invoking code action at this position will yield two code actions for importing `Entry` from either `collections::HashMap` or `collection::BTreeMap`, grouped under a single "import" group.
 +
 +### Unresolved Questions
 +
 +* Is a fixed two-level structure enough?
 +* Should we devise a general way to encode custom interaction protocols for GUI refactorings?
 +
 +## Parent Module
 +
 +**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/1002
 +
 +**Experimental Server Capability:** `{ "parentModule": boolean }`
 +
 +This request is sent from client to server to handle "Goto Parent Module" editor action.
 +
 +**Method:** `experimental/parentModule`
 +
 +**Request:** `TextDocumentPositionParams`
 +
 +**Response:** `Location | Location[] | LocationLink[] | null`
 +
 +
 +### Example
 +
 +```rust
 +// src/main.rs
 +mod foo;
 +// src/foo.rs
 +
 +/* cursor here*/
 +```
 +
 +`experimental/parentModule` returns a single `Link` to the `mod foo;` declaration.
 +
 +### Unresolved Question
 +
 +* An alternative would be to use a more general "gotoSuper" request, which would work for super methods, super classes and super modules.
 +  This is the approach IntelliJ Rust is taking.
 +  However, experience shows that super module (which generally has a feeling of navigation between files) should be separate.
 +  If you want super module, but the cursor happens to be inside an overridden function, the behavior with single "gotoSuper" request is surprising.
 +
 +## Join Lines
 +
 +**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/992
 +
 +**Experimental Server Capability:** `{ "joinLines": boolean }`
 +
 +This request is sent from client to server to handle "Join Lines" editor action.
 +
 +**Method:** `experimental/joinLines`
 +
 +**Request:**
 +
 +```typescript
 +interface JoinLinesParams {
 +    textDocument: TextDocumentIdentifier,
 +    /// Currently active selections/cursor offsets.
 +    /// This is an array to support multiple cursors.
 +    ranges: Range[],
 +}
 +```
 +
 +**Response:** `TextEdit[]`
 +
 +### Example
 +
 +```rust
 +fn main() {
 +    /*cursor here*/let x = {
 +        92
 +    };
 +}
 +```
 +
 +`experimental/joinLines` yields (curly braces are automagically removed)
 +
 +```rust
 +fn main() {
 +    let x = 92;
 +}
 +```
 +
 +### Unresolved Question
 +
 +* What is the position of the cursor after `joinLines`?
 +  Currently, this is left to editor's discretion, but it might be useful to specify on the server via snippets.
 +  However, it then becomes unclear how it works with multi cursor.
 +
 +## On Enter
 +
 +**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/1001
 +
 +**Experimental Server Capability:** `{ "onEnter": boolean }`
 +
 +This request is sent from client to server to handle the <kbd>Enter</kbd> key press.
 +
 +**Method:** `experimental/onEnter`
 +
 +**Request:**: `TextDocumentPositionParams`
 +
 +**Response:**
 +
 +```typescript
 +SnippetTextEdit[]
 +```
 +
 +### Example
 +
 +```rust
 +fn main() {
 +    // Some /*cursor here*/ docs
 +    let x = 92;
 +}
 +```
 +
 +`experimental/onEnter` returns the following snippet
 +
 +```rust
 +fn main() {
 +    // Some
 +    // $0 docs
 +    let x = 92;
 +}
 +```
 +
 +The primary goal of `onEnter` is to handle automatic indentation when opening a new line.
 +This is not yet implemented.
 +The secondary goal is to handle fixing up syntax, like continuing doc strings and comments, and escaping `\n` in string literals.
 +
 +As proper cursor positioning is raison-d'etat for `onEnter`, it uses `SnippetTextEdit`.
 +
 +### Unresolved Question
 +
 +* How to deal with synchronicity of the request?
 +  One option is to require the client to block until the server returns the response.
 +  Another option is to do a OT-style merging of edits from client and server.
 +  A third option is to do a record-replay: client applies heuristic on enter immediately, then applies all user's keypresses.
 +  When the server is ready with the response, the client rollbacks all the changes and applies the recorded actions on top of the correct response.
 +* How to deal with multiple carets?
 +* Should we extend this to arbitrary typed events and not just `onEnter`?
 +
 +## Structural Search Replace (SSR)
 +
 +**Experimental Server Capability:** `{ "ssr": boolean }`
 +
 +This request is sent from client to server to handle structural search replace -- automated syntax tree based transformation of the source.
 +
 +**Method:** `experimental/ssr`
 +
 +**Request:**
 +
 +```typescript
 +interface SsrParams {
 +    /// Search query.
 +    /// The specific syntax is specified outside of the protocol.
 +    query: string,
 +    /// If true, only check the syntax of the query and don't compute the actual edit.
 +    parseOnly: boolean,
 +    /// The current text document. This and `position` will be used to determine in what scope
 +    /// paths in `query` should be resolved.
 +    textDocument: TextDocumentIdentifier;
 +    /// Position where SSR was invoked.
 +    position: Position;
 +    /// Current selections. Search/replace will be restricted to these if non-empty.
 +    selections: Range[];
 +}
 +```
 +
 +**Response:**
 +
 +```typescript
 +WorkspaceEdit
 +```
 +
 +### Example
 +
 +SSR with query `foo($a, $b) ==>> ($a).foo($b)` will transform, eg `foo(y + 5, z)` into `(y + 5).foo(z)`.
 +
 +### Unresolved Question
 +
 +* Probably needs search without replace mode
 +* Needs a way to limit the scope to certain files.
 +
 +## Matching Brace
 +
 +**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/999
 +
 +**Experimental Server Capability:** `{ "matchingBrace": boolean }`
 +
 +This request is sent from client to server to handle "Matching Brace" editor action.
 +
 +**Method:** `experimental/matchingBrace`
 +
 +**Request:**
 +
 +```typescript
 +interface MatchingBraceParams {
 +    textDocument: TextDocumentIdentifier,
 +    /// Position for each cursor
 +    positions: Position[],
 +}
 +```
 +
 +**Response:**
 +
 +```typescript
 +Position[]
 +```
 +
 +### Example
 +
 +```rust
 +fn main() {
 +    let x: Vec<()>/*cursor here*/ = vec![]
 +}
 +```
 +
 +`experimental/matchingBrace` yields the position of `<`.
 +In many cases, matching braces can be handled by the editor.
 +However, some cases (like disambiguating between generics and comparison operations) need a real parser.
 +Moreover, it would be cool if editors didn't need to implement even basic language parsing
 +
 +### Unresolved Question
 +
 +* Should we return a nested brace structure, to allow paredit-like actions of jump *out* of the current brace pair?
 +  This is how `SelectionRange` request works.
 +* Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs?
 +
 +## Runnables
 +
 +**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/944
 +
 +**Experimental Server Capability:** `{ "runnables": { "kinds": string[] } }`
 +
 +This request is sent from client to server to get the list of things that can be run (tests, binaries, `cargo check -p`).
 +
 +**Method:** `experimental/runnables`
 +
 +**Request:**
 +
 +```typescript
 +interface RunnablesParams {
 +    textDocument: TextDocumentIdentifier;
 +    /// If null, compute runnables for the whole file.
 +    position?: Position;
 +}
 +```
 +
 +**Response:** `Runnable[]`
 +
 +```typescript
 +interface Runnable {
 +    label: string;
 +    /// If this Runnable is associated with a specific function/module, etc, the location of this item
 +    location?: LocationLink;
 +    /// Running things is necessary technology specific, `kind` needs to be advertised via server capabilities,
 +    // the type of `args` is specific to `kind`. The actual running is handled by the client.
 +    kind: string;
 +    args: any;
 +}
 +```
 +
 +rust-analyzer supports only one `kind`, `"cargo"`. The `args` for `"cargo"` look like this:
 +
 +```typescript
 +{
 +    workspaceRoot?: string;
 +    cargoArgs: string[];
 +    cargoExtraArgs: string[];
 +    executableArgs: string[];
 +    expectTest?: boolean;
 +    overrideCargo?: string;
 +}
 +```
 +
 +## Open External Documentation
 +
 +This request is sent from client to server to get a URL to documentation for the symbol under the cursor, if available.
 +
 +**Method** `experimental/externalDocs`
 +
 +**Request:**: `TextDocumentPositionParams`
 +
 +**Response** `string | null`
 +
 +
 +## Analyzer Status
 +
 +**Method:** `rust-analyzer/analyzerStatus`
 +
 +**Request:**
 +
 +```typescript
 +interface AnalyzerStatusParams {
 +    /// If specified, show dependencies of the current file.
 +    textDocument?: TextDocumentIdentifier;
 +}
 +```
 +
 +**Response:** `string`
 +
 +Returns internal status message, mostly for debugging purposes.
 +
 +## Reload Workspace
 +
 +**Method:** `rust-analyzer/reloadWorkspace`
 +
 +**Request:** `null`
 +
 +**Response:** `null`
 +
 +Reloads project information (that is, re-executes `cargo metadata`).
 +
 +## Server Status
 +
 +**Experimental Client Capability:** `{ "serverStatusNotification": boolean }`
 +
 +**Method:** `experimental/serverStatus`
 +
 +**Notification:**
 +
 +```typescript
 +interface ServerStatusParams {
 +    /// `ok` means that the server is completely functional.
 +    ///
 +    /// `warning` means that the server is partially functional.
 +    /// It can answer correctly to most requests, but some results
 +    /// might be wrong due to, for example, some missing dependencies.
 +    ///
 +    /// `error` means that the server is not functional. For example,
 +    /// there's a fatal build configuration problem. The server might
 +    /// still give correct answers to simple requests, but most results
 +    /// will be incomplete or wrong.
 +    health: "ok" | "warning" | "error",
 +    /// Is there any pending background work which might change the status?
 +    /// For example, are dependencies being downloaded?
 +    quiescent: boolean,
 +    /// Explanatory message to show on hover.
 +    message?: string,
 +}
 +```
 +
 +This notification is sent from server to client.
 +The client can use it to display *persistent* status to the user (in modline).
 +It is similar to the `showMessage`, but is intended for stares rather than point-in-time events.
 +
 +Note that this functionality is intended primarily to inform the end user about the state of the server.
 +In particular, it's valid for the client to completely ignore this extension.
 +Clients are discouraged from but are allowed to use the `health` status to decide if it's worth sending a request to the server.
 +
 +## Syntax Tree
 +
 +**Method:** `rust-analyzer/syntaxTree`
 +
 +**Request:**
 +
 +```typescript
 +interface SyntaxTreeParams {
 +    textDocument: TextDocumentIdentifier,
 +    range?: Range,
 +}
 +```
 +
 +**Response:** `string`
 +
 +Returns textual representation of a parse tree for the file/selected region.
 +Primarily for debugging, but very useful for all people working on rust-analyzer itself.
 +
 +## View Hir
 +
 +**Method:** `rust-analyzer/viewHir`
 +
 +**Request:** `TextDocumentPositionParams`
 +
 +**Response:** `string`
 +
 +Returns a textual representation of the HIR of the function containing the cursor.
 +For debugging or when working on rust-analyzer itself.
 +
 +## View File Text
 +
 +**Method:** `rust-analyzer/viewFileText`
 +
 +**Request:** `TextDocumentIdentifier`
 +
 +**Response:** `string`
 +
 +Returns the text of a file as seen by the server.
 +This is for debugging file sync problems.
 +
 +## View ItemTree
 +
 +**Method:** `rust-analyzer/viewItemTree`
 +
 +**Request:**
 +
 +```typescript
 +interface ViewItemTreeParams {
 +    textDocument: TextDocumentIdentifier,
 +}
 +```
 +
 +**Response:** `string`
 +
 +Returns a textual representation of the `ItemTree` of the currently open file, for debugging.
 +
 +## View Crate Graph
 +
 +**Method:** `rust-analyzer/viewCrateGraph`
 +
 +**Request:**
 +
 +```typescript
 +interface ViewCrateGraphParams {
 +    full: boolean,
 +}
 +```
 +
 +**Response:** `string`
 +
 +Renders rust-analyzer's crate graph as an SVG image.
 +
 +If `full` is `true`, the graph includes non-workspace crates (crates.io dependencies as well as sysroot crates).
 +
 +## Shuffle Crate Graph
 +
 +**Method:** `rust-analyzer/shuffleCrateGraph`
 +
 +**Request:** `null`
 +
 +Shuffles the crate IDs in the crate graph, for debugging purposes.
 +
 +## Expand Macro
 +
 +**Method:** `rust-analyzer/expandMacro`
 +
 +**Request:**
 +
 +```typescript
 +interface ExpandMacroParams {
 +    textDocument: TextDocumentIdentifier,
 +    position: Position,
 +}
 +```
 +
 +**Response:**
 +
 +```typescript
 +interface ExpandedMacro {
 +    name: string,
 +    expansion: string,
 +}
 +```
 +
 +Expands macro call at a given position.
 +
 +## Hover Actions
 +
 +**Experimental Client Capability:** `{ "hoverActions": boolean }`
 +
 +If this capability is set, `Hover` request returned from the server might contain an additional field, `actions`:
 +
 +```typescript
 +interface Hover {
 +    ...
 +    actions?: CommandLinkGroup[];
 +}
 +
 +interface CommandLink extends Command {
 +    /**
 +     * A tooltip for the command, when represented in the UI.
 +     */
 +    tooltip?: string;
 +}
 +
 +interface CommandLinkGroup {
 +    title?: string;
 +    commands: CommandLink[];
 +}
 +```
 +
 +Such actions on the client side are appended to a hover bottom as command links:
 +```
 +  +-----------------------------+
 +  | Hover content               |
 +  |                             |
 +  +-----------------------------+
 +  | _Action1_ | _Action2_       |  <- first group, no TITLE
 +  +-----------------------------+
 +  | TITLE _Action1_ | _Action2_ |  <- second group
 +  +-----------------------------+
 +  ...
 +```
 +
 +## Open Cargo.toml
 +
 +**Upstream Issue:** https://github.com/rust-lang/rust-analyzer/issues/6462
 +
 +**Experimental Server Capability:** `{ "openCargoToml": boolean }`
 +
 +This request is sent from client to server to open the current project's Cargo.toml
 +
 +**Method:** `experimental/openCargoToml`
 +
 +**Request:** `OpenCargoTomlParams`
 +
 +**Response:** `Location | null`
 +
 +
 +### Example
 +
 +```rust
 +// Cargo.toml
 +[package]
 +// src/main.rs
 +
 +/* cursor here*/
 +```
 +
 +`experimental/openCargoToml` returns a single `Link` to the start of the `[package]` keyword.
 +
 +## Related tests
 +
 +This request is sent from client to server to get the list of tests for the specified position.
 +
 +**Method:** `rust-analyzer/relatedTests`
 +
 +**Request:** `TextDocumentPositionParams`
 +
 +**Response:** `TestInfo[]`
 +
 +```typescript
 +interface TestInfo {
 +    runnable: Runnable;
 +}
 +```
 +
 +## Hover Range
 +
 +**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/377
 +
 +**Experimental Server Capability:** { "hoverRange": boolean }
 +
 +This extension allows passing a `Range` as a `position` field of `HoverParams`.
 +The primary use-case is to use the hover request to show the type of the expression currently selected.
 +
 +```typescript
 +interface HoverParams extends WorkDoneProgressParams {
 +    textDocument: TextDocumentIdentifier;
 +    position: Range | Position;
 +}
 +```
 +Whenever the client sends a `Range`, it is understood as the current selection and any hover included in the range will show the type of the expression if possible.
 +
 +### Example
 +
 +```rust
 +fn main() {
 +    let expression = $01 + 2 * 3$0;
 +}
 +```
 +
 +Triggering a hover inside the selection above will show a result of `i32`.
 +
 +## Move Item
 +
 +**Upstream Issue:** https://github.com/rust-lang/rust-analyzer/issues/6823
 +
 +This request is sent from client to server to move item under cursor or selection in some direction.
 +
 +**Method:** `experimental/moveItem`
 +
 +**Request:** `MoveItemParams`
 +
 +**Response:** `SnippetTextEdit[]`
 +
 +```typescript
 +export interface MoveItemParams {
 +    textDocument: TextDocumentIdentifier,
 +    range: Range,
 +    direction: Direction
 +}
 +
 +export const enum Direction {
 +    Up = "Up",
 +    Down = "Down"
 +}
 +```
 +
 +## Workspace Symbols Filtering
 +
 +**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/941
 +
 +**Experimental Server Capability:** `{ "workspaceSymbolScopeKindFiltering": boolean }`
 +
 +Extends the existing `workspace/symbol` request with ability to filter symbols by broad scope and kind of symbol.
 +If this capability is set, `workspace/symbol` parameter gains two new optional fields:
 +
 +
 +```typescript
 +interface WorkspaceSymbolParams {
 +    /**
 +     * Return only the symbols defined in the specified scope.
 +     */
 +    searchScope?: WorkspaceSymbolSearchScope;
 +    /**
 +     * Return only the symbols of specified kinds.
 +     */
 +    searchKind?: WorkspaceSymbolSearchKind;
 +    ...
 +}
 +
 +const enum WorkspaceSymbolSearchScope {
 +    Workspace = "workspace",
 +    WorkspaceAndDependencies = "workspaceAndDependencies"
 +}
 +
 +const enum WorkspaceSymbolSearchKind {
 +    OnlyTypes = "onlyTypes",
 +    AllSymbols = "allSymbols"
 +}
 +```
 +
 +## Client Commands
 +
 +**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/642
 +
 +**Experimental Client Capability:** `{ "commands?": ClientCommandOptions }`
 +
 +Certain LSP types originating on the server, notably code lenses, embed commands.
 +Commands can be serviced either by the server or by the client.
 +However, the server doesn't know which commands are available on the client.
 +
 +This extensions allows the client to communicate this info.
 +
 +
 +```typescript
 +export interface ClientCommandOptions {
 +    /**
 +     * The commands to be executed on the client
 +     */
 +    commands: string[];
 +}
 +```
index b0f2f1614dbf88703164b751e2667aed5d95d95e,0000000000000000000000000000000000000000..751ec79af0fd4f2bcb644017d6209eaecde5e4fb
mode 100644,000000..100644
--- /dev/null
@@@ -1,620 -1,0 +1,630 @@@
 +[[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.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.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.noSysroot]]rust-analyzer.cargo.noSysroot (default: `false`)::
 ++
 +--
 +Internal config for debugging, disables loading of sysroot crates.
 +--
 +[[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.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.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.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.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.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.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 fbdc69c80137646c98187022e39030e4a791762d,0000000000000000000000000000000000000000..67eabc313c832b75478a5d303e57104f21df50a8
mode 100644,000000..100644
--- /dev/null
@@@ -1,1618 -1,0 +1,1628 @@@
-                     "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\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.",
 +{
 +    "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.0-next.14"
 +    },
 +    "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",
 +        "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.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.toggleInlayHints",
 +                "title": "Toggle inlay hints",
 +                "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.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.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.noSysroot": {
 +                    "markdownDescription": "Internal config for debugging, disables loading of sysroot crates.",
 +                    "default": false,
 +                    "type": "boolean"
 +                },
 +                "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.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.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.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.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.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.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.toggleInlayHints",
 +                    "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 1b793bb0b15c87af9f2d28fc210bf24c6b3c3eea,0000000000000000000000000000000000000000..a21b304bbdaa0d92242924779cdc99ee995b4e27
mode 100644,000000..100644
--- /dev/null
@@@ -1,966 -1,0 +1,972 @@@
-         readonly uri = vscode.Uri.parse("rust-analyzer-hir://viewHir/hir.txt");
 +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>();
 +
 +        provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
 +            if (!vscode.window.activeTextEditor) return "";
 +
 +            const params: ra.AnalyzerStatusParams = {};
 +            const doc = ctx.activeRustEditor?.document;
 +            if (doc != null) {
 +                params.textDocument =
 +                    ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(doc);
 +            }
 +            return ctx.client.sendRequest(ra.analyzerStatus, params);
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
 +    ctx.pushCleanup(
 +        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 "";
 +
 +            return ctx.client.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;
 +        }
 +    })();
 +
 +    ctx.pushCleanup(
 +        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 (!client) return;
 +
 +        await client.sendRequest(ra.shuffleCrateGraph);
 +    };
 +}
 +
 +export function matchingBrace(ctx: Ctx): Cmd {
 +    return async () => {
 +        const editor = ctx.activeRustEditor;
 +        const client = ctx.client;
 +        if (!editor || !client) return;
 +
 +        const response = await client.sendRequest(ra.matchingBrace, {
 +            textDocument: ctx.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;
 +        const client = ctx.client;
 +        if (!editor || !client) return;
 +
 +        const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, {
 +            ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)),
 +            textDocument: ctx.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;
 +        const client = ctx.client;
 +        if (!editor || !client) return;
 +
 +        const lcEdits = await client.sendRequest(ra.moveItem, {
 +            range: client.code2ProtocolConverter.asRange(editor.selection),
 +            textDocument: ctx.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;
 +        const client = ctx.client;
 +
 +        if (!editor || !client) return false;
 +
 +        const lcEdits = await client
 +            .sendRequest(ra.onEnter, {
 +                textDocument: ctx.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;
 +        const client = ctx.client;
 +        if (!editor || !client) return;
 +        if (!(isRustDocument(editor.document) || isCargoTomlDocument(editor.document))) return;
 +
 +        const locations = await client.sendRequest(ra.parentModule, {
 +            textDocument: ctx.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;
 +        const client = ctx.client;
 +        if (!editor || !client) return;
 +
 +        const response = await client.sendRequest(ra.openCargoToml, {
 +            textDocument: ctx.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 client = ctx.client;
 +        if (!editor || !client) return;
 +
 +        const position = editor.selection.active;
 +        const selections = editor.selections;
 +        const textDocument = ctx.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 () => {
 +        const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" });
 +        const versionString = stdout.slice(`rust-analyzer `.length).trim();
 +
 +        void vscode.window.showInformationMessage(`rust-analyzer version: ${versionString}`);
 +    };
 +}
 +
 +export function toggleInlayHints(_ctx: Ctx): Cmd {
 +    return async () => {
 +        const config = vscode.workspace.getConfiguration("editor.inlayHints", {
 +            languageId: "rust",
 +        });
 +
 +        const value = config.get("enabled");
 +        let stringValue;
 +        if (typeof value === "string") {
 +            stringValue = value;
 +        } else {
 +            stringValue = value ? "on" : "off";
 +        }
 +        const nextValues: Record<string, string> = {
 +            on: "off",
 +            off: "on",
 +            onUnlessPressed: "offUnlessPressed",
 +            offUnlessPressed: "onUnlessPressed",
 +        };
 +        const nextValue = nextValues[stringValue] ?? "on";
 +        await config.update("enabled", nextValue, vscode.ConfigurationTarget.Global);
 +    };
 +}
 +
 +// 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);
 +            }
 +        }
 +
 +        provideTextDocumentContent(
 +            uri: vscode.Uri,
 +            ct: vscode.CancellationToken
 +        ): vscode.ProviderResult<string> {
 +            const rustEditor = ctx.activeRustEditor;
 +            if (!rustEditor) return "";
 +
 +            // When the range based query is enabled we take the range of the selection
 +            const range =
 +                uri.query === "range=true" && !rustEditor.selection.isEmpty
 +                    ? ctx.client.code2ProtocolConverter.asRange(rustEditor.selection)
 +                    : null;
 +
 +            const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range };
 +            return ctx.client.sendRequest(ra.syntaxTree, params, ct);
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
 +    void new AstInspector(ctx);
 +
 +    ctx.pushCleanup(
 +        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-syntax-tree", tdcp)
 +    );
 +    ctx.pushCleanup(
 +        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 {
-                     /* Disable the graphviz backgroud and fill the polygons */
++        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);
 +            }
 +        }
 +
 +        provideTextDocumentContent(
 +            _uri: vscode.Uri,
 +            ct: vscode.CancellationToken
 +        ): vscode.ProviderResult<string> {
 +            const rustEditor = ctx.activeRustEditor;
 +            const client = ctx.client;
 +            if (!rustEditor || !client) return "";
 +
 +            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;
 +        }
 +    })();
 +
 +    ctx.pushCleanup(
 +        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);
 +            }
 +        }
 +
 +        provideTextDocumentContent(
 +            _uri: vscode.Uri,
 +            ct: vscode.CancellationToken
 +        ): vscode.ProviderResult<string> {
 +            const rustEditor = ctx.activeRustEditor;
 +            const client = ctx.client;
 +            if (!rustEditor || !client) return "";
 +
 +            const params = client.code2ProtocolConverter.asTextDocumentIdentifier(
 +                rustEditor.document
 +            );
 +            return client.sendRequest(ra.viewFileText, params, ct);
 +        }
 +
 +        get onDidChange(): vscode.Event<vscode.Uri> {
 +            return this.eventEmitter.event;
 +        }
 +    })();
 +
 +    ctx.pushCleanup(
 +        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);
 +            }
 +        }
 +
 +        provideTextDocumentContent(
 +            _uri: vscode.Uri,
 +            ct: vscode.CancellationToken
 +        ): vscode.ProviderResult<string> {
 +            const rustEditor = ctx.activeRustEditor;
 +            const client = ctx.client;
 +            if (!rustEditor || !client) return "";
 +
 +            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;
 +        }
 +    })();
 +
 +    ctx.pushCleanup(
 +        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 dot = await ctx.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;
 +            const client = ctx.client;
 +            if (!editor || !client) return "";
 +
 +            const position = editor.selection.active;
 +
 +            const expanded = await client.sendRequest(ra.expandMacro, {
 +                textDocument: ctx.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;
 +        }
 +    })();
 +
 +    ctx.pushCleanup(
 +        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 {
 +    return async () => ctx.client.sendRequest(ra.reloadWorkspace);
 +}
 +
 +async function showReferencesImpl(
 +    client: LanguageClient,
 +    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[]) => {
 +        await showReferencesImpl(ctx.client, 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) => {
 +        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 vscode.window.showTextDocument(uri, { selection: range });
 +        }
 +    };
 +}
 +
 +export function openDocs(ctx: Ctx): Cmd {
 +    return async () => {
 +        const client = ctx.client;
 +        const editor = vscode.window.activeTextEditor;
 +        if (!editor || !client) {
 +            return;
 +        }
 +
 +        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 () => {
++        await ctx.client.sendRequest(ra.cancelFlycheck);
++    };
++}
++
 +export function resolveCodeAction(ctx: Ctx): Cmd {
 +    const client = ctx.client;
 +    return async (params: lc.CodeAction) => {
 +        params.command = undefined;
 +        const item = await client.sendRequest(lc.CodeActionResolveRequest.type, params);
 +        if (!item.edit) {
 +            return;
 +        }
 +        const itemEdit = item.edit;
 +        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 {
 +    const client = ctx.client;
 +
 +    return async () => {
 +        const editor = ctx.activeRustEditor;
 +        if (!editor || !client) return;
 +
 +        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);
 +    };
 +}
 +
 +export function linkToCommand(ctx: Ctx): Cmd {
 +    return async (commandId: string) => {
 +        const link = LINKED_COMMANDS.get(commandId);
 +        if (ctx.client && link) {
 +            const { command, arguments: args = [] } = link;
 +            await vscode.commands.executeCommand(command, ...args);
 +        }
 +    };
 +}
index 1c58040d58c2b4cc4d493937d8200135d4652fa7,0000000000000000000000000000000000000000..b83582a344a9841ae61063a88f0cbde0864ef4e9
mode 100644,000000..100644
--- /dev/null
@@@ -1,402 -1,0 +1,396 @@@
- const NIGHTLY_TAG = "nightly";
 +import path = require("path");
 +import * as vscode from "vscode";
 +import { Env } from "./client";
 +import { log } from "./util";
 +
 +export type UpdatesChannel = "stable" | "nightly";
 +
-     get currentExtensionIsNightly() {
-         return this.package.releaseTag === NIGHTLY_TAG;
-     }
 +export type RunnableEnvCfg =
 +    | undefined
 +    | Record<string, string>
 +    | { mask?: string; env: Record<string, string> }[];
 +
 +export class Config {
 +    readonly extensionId = "rust-lang.rust-analyzer";
 +
 +    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",
 +        "files",
 +        "lens", // works as lens.*
 +    ]
 +        .map((opt) => `${this.rootSection}.${opt}`)
 +        .concat(this.requiresWorkspaceReloadOpts);
 +
 +    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();
 +    }
 +
 +    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();
 +
 +        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) {
 +            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);
 +            }
 +        }
 +    }
 +
 +    // 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() {
 +        return this.get<RunnableEnvCfg>("runnableEnv");
 +    }
 +
 +    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"),
 +        };
 +    }
 +}
 +
 +export async function updateConfig(config: vscode.WorkspaceConfiguration) {
 +    const renames = [
 +        ["assist.allowMergingIntoGlobImports", "imports.merge.glob"],
 +        ["assist.exprFillDefault", "assist.expressionFillDefault"],
 +        ["assist.importEnforceGranularity", "imports.granularity.enforce"],
 +        ["assist.importGranularity", "imports.granularity.group"],
 +        ["assist.importMergeBehavior", "imports.granularity.group"],
 +        ["assist.importMergeBehaviour", "imports.granularity.group"],
 +        ["assist.importGroup", "imports.group.enable"],
 +        ["assist.importPrefix", "imports.prefix"],
 +        ["primeCaches.enable", "cachePriming.enable"],
 +        ["cache.warmup", "cachePriming.enable"],
 +        ["cargo.loadOutDirsFromCheck", "cargo.buildScripts.enable"],
 +        ["cargo.runBuildScripts", "cargo.buildScripts.enable"],
 +        ["cargo.runBuildScriptsCommand", "cargo.buildScripts.overrideCommand"],
 +        ["cargo.useRustcWrapperForBuildScripts", "cargo.buildScripts.useRustcWrapper"],
 +        ["completion.snippets", "completion.snippets.custom"],
 +        ["diagnostics.enableExperimental", "diagnostics.experimental.enable"],
 +        ["experimental.procAttrMacros", "procMacro.attributes.enable"],
 +        ["highlighting.strings", "semanticHighlighting.strings.enable"],
 +        ["highlightRelated.breakPoints", "highlightRelated.breakPoints.enable"],
 +        ["highlightRelated.exitPoints", "highlightRelated.exitPoints.enable"],
 +        ["highlightRelated.yieldPoints", "highlightRelated.yieldPoints.enable"],
 +        ["highlightRelated.references", "highlightRelated.references.enable"],
 +        ["hover.documentation", "hover.documentation.enable"],
 +        ["hover.linksInHover", "hover.links.enable"],
 +        ["hoverActions.linksInHover", "hover.links.enable"],
 +        ["hoverActions.debug", "hover.actions.debug.enable"],
 +        ["hoverActions.enable", "hover.actions.enable.enable"],
 +        ["hoverActions.gotoTypeDef", "hover.actions.gotoTypeDef.enable"],
 +        ["hoverActions.implementations", "hover.actions.implementations.enable"],
 +        ["hoverActions.references", "hover.actions.references.enable"],
 +        ["hoverActions.run", "hover.actions.run.enable"],
 +        ["inlayHints.chainingHints", "inlayHints.chainingHints.enable"],
 +        ["inlayHints.closureReturnTypeHints", "inlayHints.closureReturnTypeHints.enable"],
 +        ["inlayHints.hideNamedConstructorHints", "inlayHints.typeHints.hideNamedConstructor"],
 +        ["inlayHints.parameterHints", "inlayHints.parameterHints.enable"],
 +        ["inlayHints.reborrowHints", "inlayHints.reborrowHints.enable"],
 +        ["inlayHints.typeHints", "inlayHints.typeHints.enable"],
 +        ["lruCapacity", "lru.capacity"],
 +        ["runnables.cargoExtraArgs", "runnables.extraArgs"],
 +        ["runnables.overrideCargo", "runnables.command"],
 +        ["rustcSource", "rustc.source"],
 +        ["rustfmt.enableRangeFormatting", "rustfmt.rangeFormatting.enable"],
 +    ];
 +
 +    for (const [oldKey, newKey] of renames) {
 +        const inspect = config.inspect(oldKey);
 +        if (inspect !== undefined) {
 +            const valMatrix = [
 +                {
 +                    val: inspect.globalValue,
 +                    langVal: inspect.globalLanguageValue,
 +                    target: vscode.ConfigurationTarget.Global,
 +                },
 +                {
 +                    val: inspect.workspaceFolderValue,
 +                    langVal: inspect.workspaceFolderLanguageValue,
 +                    target: vscode.ConfigurationTarget.WorkspaceFolder,
 +                },
 +                {
 +                    val: inspect.workspaceValue,
 +                    langVal: inspect.workspaceLanguageValue,
 +                    target: vscode.ConfigurationTarget.Workspace,
 +                },
 +            ];
 +            for (const { val, langVal, target } of valMatrix) {
 +                const patch = (val: unknown) => {
 +                    // some of the updates we do only append "enable" or "custom"
 +                    // that means on the next run we would find these again, but as objects with
 +                    // these properties causing us to destroy the config
 +                    // so filter those already updated ones out
 +                    return (
 +                        val !== undefined &&
 +                        !(
 +                            typeof val === "object" &&
 +                            val !== null &&
 +                            (oldKey === "completion.snippets" || !val.hasOwnProperty("custom"))
 +                        )
 +                    );
 +                };
 +                if (patch(val)) {
 +                    await config.update(newKey, val, target, false);
 +                    await config.update(oldKey, undefined, target, false);
 +                }
 +                if (patch(langVal)) {
 +                    await config.update(newKey, langVal, target, true);
 +                    await config.update(oldKey, undefined, target, true);
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +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),
 +                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 {
 +    // 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 "";
 +            }
 +        },
 +
 +        workspaceFolderBasename: () => {
 +            const workspaceFolder = computeVscodeVar("workspaceFolder");
 +            if (workspaceFolder) {
 +                return path.basename(workspaceFolder);
 +            } else {
 +                return "";
 +            }
 +        },
 +
 +        cwd: () => process.cwd(),
 +
 +        // 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 + "}";
 +    }
 +}
index f80af78a74a15016cec2572ab392ec9748876752,0000000000000000000000000000000000000000..875261c48a60e4f4c22c7b35865267aa5de5f8f4
mode 100644,000000..100644
--- /dev/null
@@@ -1,180 -1,0 +1,184 @@@
- export const relatedTests = new lc.RequestType<lc.TextDocumentPositionParams, TestInfo[], void>(
-     "rust-analyzer/relatedTests"
- );
- export interface SsrParams {
-     query: string;
-     parseOnly: boolean;
-     textDocument: lc.TextDocumentIdentifier;
-     position: lc.Position;
-     selections: readonly lc.Range[];
- }
- export const ssr = new lc.RequestType<SsrParams, lc.WorkspaceEdit, void>("experimental/ssr");
 +/**
 + * This file mirrors `crates/rust-analyzer/src/lsp_ext.rs` declarations.
 + */
 +
 +import * as lc from "vscode-languageclient";
 +
 +export interface AnalyzerStatusParams {
 +    textDocument?: lc.TextDocumentIdentifier;
 +}
 +export const analyzerStatus = new lc.RequestType<AnalyzerStatusParams, string, void>(
 +    "rust-analyzer/analyzerStatus"
 +);
 +export const memoryUsage = new lc.RequestType0<string, void>("rust-analyzer/memoryUsage");
 +export const shuffleCrateGraph = new lc.RequestType0<null, void>("rust-analyzer/shuffleCrateGraph");
 +
 +export interface ServerStatusParams {
 +    health: "ok" | "warning" | "error";
 +    quiescent: boolean;
 +    message?: string;
 +}
 +export const serverStatus = new lc.NotificationType<ServerStatusParams>(
 +    "experimental/serverStatus"
 +);
 +
 +export const reloadWorkspace = new lc.RequestType0<null, void>("rust-analyzer/reloadWorkspace");
 +
 +export const hover = new lc.RequestType<HoverParams, lc.Hover | null, void>("textDocument/hover");
 +
 +export interface HoverParams extends lc.WorkDoneProgressParams {
 +    textDocument: lc.TextDocumentIdentifier;
 +    position: lc.Range | lc.Position;
 +}
 +
 +export interface SyntaxTreeParams {
 +    textDocument: lc.TextDocumentIdentifier;
 +    range: lc.Range | null;
 +}
 +export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>(
 +    "rust-analyzer/syntaxTree"
 +);
 +
 +export const viewHir = new lc.RequestType<lc.TextDocumentPositionParams, string, void>(
 +    "rust-analyzer/viewHir"
 +);
 +
 +export const viewFileText = new lc.RequestType<lc.TextDocumentIdentifier, string, void>(
 +    "rust-analyzer/viewFileText"
 +);
 +
 +export interface ViewItemTreeParams {
 +    textDocument: lc.TextDocumentIdentifier;
 +}
 +
 +export const viewItemTree = new lc.RequestType<ViewItemTreeParams, string, void>(
 +    "rust-analyzer/viewItemTree"
 +);
 +
 +export interface ViewCrateGraphParams {
 +    full: boolean;
 +}
 +
 +export const viewCrateGraph = new lc.RequestType<ViewCrateGraphParams, string, void>(
 +    "rust-analyzer/viewCrateGraph"
 +);
 +
 +export interface ExpandMacroParams {
 +    textDocument: lc.TextDocumentIdentifier;
 +    position: lc.Position;
 +}
 +export interface ExpandedMacro {
 +    name: string;
 +    expansion: string;
 +}
 +export const expandMacro = new lc.RequestType<ExpandMacroParams, ExpandedMacro | null, void>(
 +    "rust-analyzer/expandMacro"
 +);
 +
++export const relatedTests = new lc.RequestType<lc.TextDocumentPositionParams, TestInfo[], void>(
++    "rust-analyzer/relatedTests"
++);
++
++export const cancelFlycheck = new lc.RequestType0<void, void>("rust-analyzer/cancelFlycheck");
++
++// Experimental extensions
++
++export interface SsrParams {
++    query: string;
++    parseOnly: boolean;
++    textDocument: lc.TextDocumentIdentifier;
++    position: lc.Position;
++    selections: readonly lc.Range[];
++}
++export const ssr = new lc.RequestType<SsrParams, lc.WorkspaceEdit, void>("experimental/ssr");
++
 +export interface MatchingBraceParams {
 +    textDocument: lc.TextDocumentIdentifier;
 +    positions: lc.Position[];
 +}
 +export const matchingBrace = new lc.RequestType<MatchingBraceParams, lc.Position[], void>(
 +    "experimental/matchingBrace"
 +);
 +
 +export const parentModule = new lc.RequestType<
 +    lc.TextDocumentPositionParams,
 +    lc.LocationLink[] | null,
 +    void
 +>("experimental/parentModule");
 +
 +export interface JoinLinesParams {
 +    textDocument: lc.TextDocumentIdentifier;
 +    ranges: lc.Range[];
 +}
 +export const joinLines = new lc.RequestType<JoinLinesParams, lc.TextEdit[], void>(
 +    "experimental/joinLines"
 +);
 +
 +export const onEnter = new lc.RequestType<lc.TextDocumentPositionParams, lc.TextEdit[], void>(
 +    "experimental/onEnter"
 +);
 +
 +export interface RunnablesParams {
 +    textDocument: lc.TextDocumentIdentifier;
 +    position: lc.Position | null;
 +}
 +
 +export interface Runnable {
 +    label: string;
 +    location?: lc.LocationLink;
 +    kind: "cargo";
 +    args: {
 +        workspaceRoot?: string;
 +        cargoArgs: string[];
 +        cargoExtraArgs: string[];
 +        executableArgs: string[];
 +        expectTest?: boolean;
 +        overrideCargo?: string;
 +    };
 +}
 +export const runnables = new lc.RequestType<RunnablesParams, Runnable[], void>(
 +    "experimental/runnables"
 +);
 +
 +export interface TestInfo {
 +    runnable: Runnable;
 +}
 +
 +export interface CommandLink extends lc.Command {
 +    /**
 +     * A tooltip for the command, when represented in the UI.
 +     */
 +    tooltip?: string;
 +}
 +
 +export interface CommandLinkGroup {
 +    title?: string;
 +    commands: CommandLink[];
 +}
 +
 +export const openDocs = new lc.RequestType<lc.TextDocumentPositionParams, string | void, void>(
 +    "experimental/externalDocs"
 +);
 +
 +export const openCargoToml = new lc.RequestType<OpenCargoTomlParams, lc.Location, void>(
 +    "experimental/openCargoToml"
 +);
 +
 +export interface OpenCargoTomlParams {
 +    textDocument: lc.TextDocumentIdentifier;
 +}
 +
 +export const moveItem = new lc.RequestType<MoveItemParams, lc.TextEdit[], void>(
 +    "experimental/moveItem"
 +);
 +
 +export interface MoveItemParams {
 +    textDocument: lc.TextDocumentIdentifier;
 +    range: lc.Range;
 +    direction: Direction;
 +}
 +
 +export const enum Direction {
 +    Up = "Up",
 +    Down = "Down",
 +}
index d78b711a47a8f76628569026bcf8a961367c8ab1,0000000000000000000000000000000000000000..a9847dd2a6521ba013d76b4c7562ff89334397c9
mode 100644,000000..100644
--- /dev/null
@@@ -1,405 -1,0 +1,406 @@@
 +import * as vscode from "vscode";
 +import * as lc from "vscode-languageclient/node";
 +import * as os from "os";
 +
 +import * as commands from "./commands";
 +import { Ctx } from "./ctx";
 +import { Config } from "./config";
 +import { log, isValidExecutable, isRustDocument } from "./util";
 +import { PersistentState } from "./persistent_state";
 +import { activateTaskProvider } from "./tasks";
 +import { setContextValue } from "./util";
 +import { exec } from "child_process";
 +
 +let ctx: Ctx | undefined;
 +
 +const RUST_PROJECT_CONTEXT_NAME = "inRustProject";
 +
 +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;
 +}
 +
 +export interface RustAnalyzerExtensionApi {
 +    client: lc.LanguageClient;
 +}
 +
 +export async function activate(
 +    context: vscode.ExtensionContext
 +): Promise<RustAnalyzerExtensionApi> {
 +    // 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;
 +    });
 +}
 +
 +async function tryActivate(context: vscode.ExtensionContext): Promise<RustAnalyzerExtensionApi> {
 +    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 }';
 +
 +        log.error("Bootstrap error", err);
 +        throw new Error(message);
 +    });
 +
 +    if ((vscode.workspace.workspaceFolders || []).length === 0) {
 +        const rustDocuments = vscode.workspace.textDocuments.filter((document) =>
 +            isRustDocument(document)
 +        );
 +        if (rustDocuments.length > 0) {
 +            ctx = await Ctx.create(config, context, serverPath, {
 +                kind: "Detached Files",
 +                files: rustDocuments,
 +            });
 +        } else {
 +            throw new Error("no rust files are opened");
 +        }
 +    } 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());
 +    }
 +
 +    vscode.workspace.onDidChangeConfiguration(
 +        (_) =>
 +            ctx?.client
 +                ?.sendNotification("workspace/didChangeConfiguration", { settings: "" })
 +                .catch(log.error),
 +        null,
 +        ctx.subscriptions
 +    );
 +
 +    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);
 +    ctx.registerCommand("toggleInlayHints", commands.toggleInlayHints);
 +
 +    // 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 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;
 +    }
 +}
 +
 +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: "//! " },
 +            },
 +            {
 +                // 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 },
 +            },
 +        ],
 +    });
 +}
index bac163da9f376ed6f3d5841f20f89bf1390a9028,0000000000000000000000000000000000000000..e1ca495428024ace9a3a5f0ae86595b8c84377ae
mode 100644,000000..100644
--- /dev/null
@@@ -1,203 -1,0 +1,203 @@@
-             // it is not mentioned in docs and cannot be infered by the type signature...
 +import * as cp from "child_process";
 +import * as os from "os";
 +import * as path from "path";
 +import * as readline from "readline";
 +import * as vscode from "vscode";
 +import { execute, log, memoizeAsync } from "./util";
 +
 +interface CompilationArtifact {
 +    fileName: string;
 +    name: string;
 +    kind: string;
 +    isTest: boolean;
 +}
 +
 +export interface ArtifactSpec {
 +    cargoArgs: string[];
 +    filter?: (artifacts: CompilationArtifact[]) => CompilationArtifact[];
 +}
 +
 +export class Cargo {
 +    constructor(readonly rootFolder: string, readonly output: vscode.OutputChannel) {}
 +
 +    // Made public for testing purposes
 +    static artifactSpec(args: readonly string[]): ArtifactSpec {
 +        const cargoArgs = [...args, "--message-format=json"];
 +
 +        // arguments for a runnable from the quick pick should be updated.
 +        // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_code_lens
 +        switch (cargoArgs[0]) {
 +            case "run":
 +                cargoArgs[0] = "build";
 +                break;
 +            case "test": {
 +                if (!cargoArgs.includes("--no-run")) {
 +                    cargoArgs.push("--no-run");
 +                }
 +                break;
 +            }
 +        }
 +
 +        const result: ArtifactSpec = { cargoArgs: cargoArgs };
 +        if (cargoArgs[0] === "test" || cargoArgs[0] === "bench") {
 +            // for instance, `crates\rust-analyzer\tests\heavy_tests\main.rs` tests
 +            // produce 2 artifacts: {"kind": "bin"} and {"kind": "test"}
 +            result.filter = (artifacts) => artifacts.filter((it) => it.isTest);
 +        }
 +
 +        return result;
 +    }
 +
 +    private async getArtifacts(spec: ArtifactSpec): Promise<CompilationArtifact[]> {
 +        const artifacts: CompilationArtifact[] = [];
 +
 +        try {
 +            await this.runCargo(
 +                spec.cargoArgs,
 +                (message) => {
 +                    if (message.reason === "compiler-artifact" && message.executable) {
 +                        const isBinary = message.target.crate_types.includes("bin");
 +                        const isBuildScript = message.target.kind.includes("custom-build");
 +                        if ((isBinary && !isBuildScript) || message.profile.test) {
 +                            artifacts.push({
 +                                fileName: message.executable,
 +                                name: message.target.name,
 +                                kind: message.target.kind[0],
 +                                isTest: message.profile.test,
 +                            });
 +                        }
 +                    } else if (message.reason === "compiler-message") {
 +                        this.output.append(message.message.rendered);
 +                    }
 +                },
 +                (stderr) => this.output.append(stderr)
 +            );
 +        } catch (err) {
 +            this.output.show(true);
 +            throw new Error(`Cargo invocation has failed: ${err}`);
 +        }
 +
 +        return spec.filter?.(artifacts) ?? artifacts;
 +    }
 +
 +    async executableFromArgs(args: readonly string[]): Promise<string> {
 +        const artifacts = await this.getArtifacts(Cargo.artifactSpec(args));
 +
 +        if (artifacts.length === 0) {
 +            throw new Error("No compilation artifacts");
 +        } else if (artifacts.length > 1) {
 +            throw new Error("Multiple compilation artifacts are not supported.");
 +        }
 +
 +        return artifacts[0].fileName;
 +    }
 +
 +    private async runCargo(
 +        cargoArgs: string[],
 +        onStdoutJson: (obj: any) => void,
 +        onStderrString: (data: string) => void
 +    ): Promise<number> {
 +        const path = await cargoPath();
 +        return await new Promise((resolve, reject) => {
 +            const cargo = cp.spawn(path, cargoArgs, {
 +                stdio: ["ignore", "pipe", "pipe"],
 +                cwd: this.rootFolder,
 +            });
 +
 +            cargo.on("error", (err) => reject(new Error(`could not launch cargo: ${err}`)));
 +
 +            cargo.stderr.on("data", (chunk) => onStderrString(chunk.toString()));
 +
 +            const rl = readline.createInterface({ input: cargo.stdout });
 +            rl.on("line", (line) => {
 +                const message = JSON.parse(line);
 +                onStdoutJson(message);
 +            });
 +
 +            cargo.on("exit", (exitCode, _) => {
 +                if (exitCode === 0) resolve(exitCode);
 +                else reject(new Error(`exit code: ${exitCode}.`));
 +            });
 +        });
 +    }
 +}
 +
 +/** Mirrors `project_model::sysroot::discover_sysroot_dir()` implementation*/
 +export async function getSysroot(dir: string): Promise<string> {
 +    const rustcPath = await getPathForExecutable("rustc");
 +
 +    // do not memoize the result because the toolchain may change between runs
 +    return await execute(`${rustcPath} --print sysroot`, { cwd: dir });
 +}
 +
 +export async function getRustcId(dir: string): Promise<string> {
 +    const rustcPath = await getPathForExecutable("rustc");
 +
 +    // do not memoize the result because the toolchain may change between runs
 +    const data = await execute(`${rustcPath} -V -v`, { cwd: dir });
 +    const rx = /commit-hash:\s(.*)$/m;
 +
 +    return rx.exec(data)![1];
 +}
 +
 +/** Mirrors `toolchain::cargo()` implementation */
 +export function cargoPath(): Promise<string> {
 +    return getPathForExecutable("cargo");
 +}
 +
 +/** Mirrors `toolchain::get_path_for_executable()` implementation */
 +export const getPathForExecutable = memoizeAsync(
 +    // We apply caching to decrease file-system interactions
 +    async (executableName: "cargo" | "rustc" | "rustup"): Promise<string> => {
 +        {
 +            const envVar = process.env[executableName.toUpperCase()];
 +            if (envVar) return envVar;
 +        }
 +
 +        if (await lookupInPath(executableName)) return executableName;
 +
 +        try {
 +            // hmm, `os.homedir()` seems to be infallible
++            // it is not mentioned in docs and cannot be inferred by the type signature...
 +            const standardPath = vscode.Uri.joinPath(
 +                vscode.Uri.file(os.homedir()),
 +                ".cargo",
 +                "bin",
 +                executableName
 +            );
 +
 +            if (await isFileAtUri(standardPath)) return standardPath.fsPath;
 +        } catch (err) {
 +            log.error("Failed to read the fs info", err);
 +        }
 +        return executableName;
 +    }
 +);
 +
 +async function lookupInPath(exec: string): Promise<boolean> {
 +    const paths = process.env.PATH ?? "";
 +
 +    const candidates = paths.split(path.delimiter).flatMap((dirInPath) => {
 +        const candidate = path.join(dirInPath, exec);
 +        return os.type() === "Windows_NT" ? [candidate, `${candidate}.exe`] : [candidate];
 +    });
 +
 +    for await (const isFile of candidates.map(isFileAtPath)) {
 +        if (isFile) {
 +            return true;
 +        }
 +    }
 +    return false;
 +}
 +
 +async function isFileAtPath(path: string): Promise<boolean> {
 +    return isFileAtUri(vscode.Uri.file(path));
 +}
 +
 +async function isFileAtUri(uri: vscode.Uri): Promise<boolean> {
 +    try {
 +        return ((await vscode.workspace.fs.stat(uri)).type & vscode.FileType.File) !== 0;
 +    } catch {
 +        return false;
 +    }
 +}