]> git.lizzy.rs Git - rust.git/commitdiff
:arrow_up: rust-analyzer
authorLaurențiu Nicola <lnicola@dend.ro>
Tue, 18 Oct 2022 06:12:49 +0000 (09:12 +0300)
committerLaurențiu Nicola <lnicola@dend.ro>
Tue, 18 Oct 2022 06:12:49 +0000 (09:12 +0300)
86 files changed:
1  2 
src/tools/rust-analyzer/.github/workflows/ci.yaml
src/tools/rust-analyzer/.github/workflows/release.yaml
src/tools/rust-analyzer/Cargo.lock
src/tools/rust-analyzer/Cargo.toml
src/tools/rust-analyzer/crates/cfg/Cargo.toml
src/tools/rust-analyzer/crates/flycheck/Cargo.toml
src/tools/rust-analyzer/crates/hir-def/Cargo.toml
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/macro_expansion_tests/builtin_fn_macro.rs
src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
src/tools/rust-analyzer/crates/hir-expand/src/db.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/chalk_db.rs
src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
src/tools/rust-analyzer/crates/hir-ty/src/display.rs
src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
src/tools/rust-analyzer/crates/hir/Cargo.toml
src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
src/tools/rust-analyzer/crates/hir/src/lib.rs
src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
src/tools/rust-analyzer/crates/ide-completion/src/context.rs
src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
src/tools/rust-analyzer/crates/ide-db/Cargo.toml
src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs
src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_try_expr.rs
src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/not_implemented.rs
src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
src/tools/rust-analyzer/crates/ide/Cargo.toml
src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
src/tools/rust-analyzer/crates/mbe/Cargo.toml
src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
src/tools/rust-analyzer/crates/mbe/src/expander.rs
src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
src/tools/rust-analyzer/crates/mbe/src/lib.rs
src/tools/rust-analyzer/crates/mbe/src/parser.rs
src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
src/tools/rust-analyzer/crates/profile/Cargo.toml
src/tools/rust-analyzer/crates/project-model/Cargo.toml
src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
src/tools/rust-analyzer/crates/stdx/Cargo.toml
src/tools/rust-analyzer/crates/syntax/Cargo.toml
src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
src/tools/rust-analyzer/crates/text-edit/Cargo.toml
src/tools/rust-analyzer/crates/toolchain/Cargo.toml
src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
src/tools/rust-analyzer/docs/dev/guide.md
src/tools/rust-analyzer/docs/dev/syntax.md
src/tools/rust-analyzer/docs/user/manual.adoc
src/tools/rust-analyzer/editors/code/src/config.ts
src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
src/tools/rust-analyzer/xtask/Cargo.toml

index 1563ee0b143851435a28597c8c088621e5c4a59b,0000000000000000000000000000000000000000..bb77324378a40ae6a7844503553661a3e22a8d93
mode 100644,000000..100644
--- /dev/null
@@@ -1,156 -1,0 +1,173 @@@
-         uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
 +# Please make sure that the `needs` fields for both `end-success` and `end-failure`
 +# are updated when adding new jobs!
 +
 +name: CI
 +on:
 +  pull_request:
 +  push:
 +    branches:
 +      - auto
 +      - try
 +
 +env:
 +  CARGO_INCREMENTAL: 0
 +  CARGO_NET_RETRY: 10
 +  CI: 1
 +  RUST_BACKTRACE: short
 +  RUSTFLAGS: "-D warnings -W unreachable-pub -W bare-trait-objects"
 +  RUSTUP_MAX_RETRIES: 10
 +
 +jobs:
 +  rust:
 +    if: github.repository == 'rust-lang/rust-analyzer'
 +    name: Rust
 +    runs-on: ${{ matrix.os }}
 +    env:
 +      CC: deny_c
 +
 +    strategy:
 +      fail-fast: false
 +      matrix:
 +        os: [ubuntu-latest, windows-latest, macos-latest]
 +
 +    steps:
 +      - name: Checkout repository
 +        uses: actions/checkout@v3
 +        with:
 +          ref: ${{ github.event.pull_request.head.sha }}
 +          fetch-depth: 20
 +
 +      - name: Install Rust toolchain
 +        run: |
 +          rustup update --no-self-update stable
 +          rustup component add rustfmt rust-src
 +
 +      - name: Cache Dependencies
-       - name: Compile
++        uses: Swatinem/rust-cache@76686c56f2b581d1bb5bda44b51f7e24bd9b8b8e
 +
-         uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
++      - name: Bump opt-level
++        if: matrix.os == 'ubuntu-latest'
++        run: sed -i '/\[profile.dev]/a opt-level=1' Cargo.toml
++
++      - name: Compile (tests)
 +        run: cargo test --no-run --locked
 +
++      # It's faster to `test` before `build` ¯\_(ツ)_/¯
++      - name: Compile (rust-analyzer)
++        if: matrix.os == 'ubuntu-latest'
++        run: cargo build --quiet
++
 +      - name: Test
 +        run: cargo test -- --nocapture --quiet
 +
++      - name: Run analysis-stats on rust-analyzer
++        if: matrix.os == 'ubuntu-latest'
++        run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats .
++
++      - name: Run analysis-stats on rust std library
++        if: matrix.os == 'ubuntu-latest'
++        run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std
++
 +  # Weird targets to catch non-portable code
 +  rust-cross:
 +    if: github.repository == 'rust-lang/rust-analyzer'
 +    name: Rust Cross
 +    runs-on: ubuntu-latest
 +
 +    env:
 +      targets: "powerpc-unknown-linux-gnu x86_64-unknown-linux-musl"
 +      # The rust-analyzer binary is not expected to compile on WASM, but the IDE
 +      # crate should
 +      targets_ide: "wasm32-unknown-unknown"
 +
 +    steps:
 +      - name: Checkout repository
 +        uses: actions/checkout@v3
 +
 +      - name: Install Rust toolchain
 +        run: |
 +          rustup update --no-self-update stable
 +          rustup target add ${{ env.targets }} ${{ env.targets_ide }}
 +
 +      - name: Cache Dependencies
-         uses: actions/setup-node@v1
++        uses: Swatinem/rust-cache@76686c56f2b581d1bb5bda44b51f7e24bd9b8b8e
 +
 +      - name: Check
 +        run: |
 +          for target in ${{ env.targets }}; do
 +            cargo check --target=$target --all-targets
 +          done
 +          for target in ${{ env.targets_ide }}; do
 +            cargo check -p ide --target=$target --all-targets
 +          done
 +
 +  typescript:
 +    if: github.repository == 'rust-lang/rust-analyzer'
 +    name: TypeScript
 +    strategy:
 +      fail-fast: false
 +      matrix:
 +        os: [ubuntu-latest, windows-latest]
 +
 +    runs-on: ${{ matrix.os }}
 +
 +    steps:
 +      - name: Checkout repository
 +        uses: actions/checkout@v3
 +
 +      - name: Install Nodejs
-           node-version: 16.x
++        uses: actions/setup-node@v3
 +        with:
++          node-version: 16
 +
 +      - name: Install xvfb
 +        if: matrix.os == 'ubuntu-latest'
 +        run: sudo apt-get install -y xvfb
 +
 +      - run: npm ci
 +        working-directory: ./editors/code
 +
 +      #    - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; }
 +      #      if: runner.os == 'Linux'
 +      #      working-directory: ./editors/code
 +
 +      - run: npm run lint
 +        working-directory: ./editors/code
 +
 +      - name: Run VS Code tests (Linux)
 +        if: matrix.os == 'ubuntu-latest'
 +        env:
 +          VSCODE_CLI: 1
 +        run: xvfb-run npm test
 +        working-directory: ./editors/code
 +
 +      - name: Run VS Code tests (Windows)
 +        if: matrix.os == 'windows-latest'
 +        env:
 +          VSCODE_CLI: 1
 +        run: npm test
 +        working-directory: ./editors/code
 +
 +      - run: npm run pretest
 +        working-directory: ./editors/code
 +
 +      - run: npm run package --scripts-prepend-node-path
 +        working-directory: ./editors/code
 +
 +  end-success:
 +    name: bors build finished
 +    if: github.event.pusher.name == 'bors' && success()
 +    runs-on: ubuntu-latest
 +    needs: [rust, rust-cross, typescript]
 +    steps:
 +      - name: Mark the job as successful
 +        run: exit 0
 +
 +  end-failure:
 +    name: bors build finished
 +    if: github.event.pusher.name == 'bors' && (failure() || cancelled())
 +    runs-on: ubuntu-latest
 +    needs: [rust, rust-cross, typescript]
 +    steps:
 +      - name: Mark the job as a failure
 +        run: exit 1
index f4d472e3d5c1dc5f6382685f66d8a35193d288b8,0000000000000000000000000000000000000000..422fe29f9d5c37576060b0698aaa0c6c60aab603
mode 100644,000000..100644
--- /dev/null
@@@ -1,271 -1,0 +1,273 @@@
-         uses: actions/setup-node@v1
 +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-20.04
 +            target: x86_64-unknown-linux-gnu
 +            code-target: linux-x64
 +            container: 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 }}
 +    container: ${{ matrix.container }}
 +
 +    env:
 +      RA_TARGET: ${{ matrix.target }}
 +
 +    steps:
 +      - name: Checkout repository
 +        uses: actions/checkout@v3
 +        with:
 +          fetch-depth: ${{ env.FETCH_DEPTH }}
 +
 +      - name: Install toolchain dependencies
 +        if: matrix.container == 'ubuntu:18.04'
 +        shell: bash
 +        run: |
 +          apt-get update && apt-get install -y build-essential curl
 +          curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL "https://sh.rustup.rs" | sh -s -- --profile minimal --default-toolchain none -y
 +          echo "${CARGO_HOME:-$HOME/.cargo}/bin" >> $GITHUB_PATH
 +
 +      - 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
-           node-version: 16.x
++        uses: actions/setup-node@v3
 +        with:
-         uses: actions/setup-node@v1
++          node-version: 16
 +
 +      - 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
-           node-version: 16.x
++        uses: actions/setup-node@v3
 +        with:
++          node-version: 16
 +
 +      - 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 || true
++        timeout-minutes: 2
 +
 +      - 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 || true
++        timeout-minutes: 2
index 744330b142ab2f21fd93e7c88337ee66ba0b8657,0000000000000000000000000000000000000000..0ddea2f728d7806bb5d363b95a6214de6c88c5b4
mode 100644,000000..100644
--- /dev/null
@@@ -1,2122 -1,0 +1,2113 @@@
- version = "1.0.62"
 +# 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 = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305"
++version = "1.0.65"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.1.3"
++checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
 +
 +[[package]]
 +name = "anymap"
 +version = "1.0.0-beta.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8f1f8f5a6f3d50d89e3797d7593a50f96bb2aaa20ca0cc7be1fb673232c91d72"
 +
 +[[package]]
 +name = "arbitrary"
- checksum = "5a7924531f38b1970ff630f03eb20a2fde69db5c590c93b0f3482e95dcc5fd60"
++version = "1.1.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.84.0"
++checksum = "d86fd10d912cab78764cc44307d9cd5f164e09abbeb87fb19fb6d95937e8da5f"
 +
 +[[package]]
 +name = "arrayvec"
 +version = "0.7.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
 +
 +[[package]]
 +name = "atty"
 +version = "0.2.14"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
 +dependencies = [
 + "hermit-abi",
 + "libc",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "autocfg"
 +version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 +
 +[[package]]
 +name = "backtrace"
 +version = "0.3.66"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
 +dependencies = [
 + "addr2line",
 + "cc",
 + "cfg-if",
 + "libc",
 + "miniz_oxide",
 + "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"
 +version = "1.1.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +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 = "cf29c109d57f8d57b0e7675391be37a9285d86dd93278bd5f14a0ad3c447a6c2"
++version = "0.86.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.84.0"
++checksum = "5499d415d855b5094366a824815341893ad3de0ecb6048c430118bdae6d27402"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 + "synstructure",
 +]
 +
 +[[package]]
 +name = "chalk-ir"
- checksum = "d391763027b5e50a5e15caf6d2857ec585fd68160367bbeac9e1804209620918"
++version = "0.86.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.84.0"
++checksum = "3800118c76a48507b0eece3a01f3a429b5c478d203c493096e6040c67ab960e1"
 +dependencies = [
 + "bitflags",
 + "chalk-derive",
 + "lazy_static",
 +]
 +
 +[[package]]
 +name = "chalk-recursive"
- checksum = "afafd92dcdc7fe0ea940ee94bdd8cc5bd18f4a4a84c593d6d7025fe16c150478"
++version = "0.86.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.84.0"
++checksum = "1baf60628fd73104d1f8562586a52d48f37f1e84435aab2e62674b1fd935b8c8"
 +dependencies = [
 + "chalk-derive",
 + "chalk-ir",
 + "chalk-solve",
 + "rustc-hash",
 + "tracing",
 +]
 +
 +[[package]]
 +name = "chalk-solve"
- checksum = "3af1d111f11c91c48ace02e93e470c5bae6d2631bd112e4545317da53660d7fc"
++version = "0.86.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.9.10"
++checksum = "0e9c3c068f9358786348e58a1b94ef0a5cf90a9810fc1f10fda896f0b5d80185"
 +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-channel"
 +version = "0.5.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
 +dependencies = [
 + "cfg-if",
 + "crossbeam-utils",
 +]
 +
 +[[package]]
 +name = "crossbeam-deque"
 +version = "0.8.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
 +dependencies = [
 + "cfg-if",
 + "crossbeam-epoch",
 + "crossbeam-utils",
 +]
 +
 +[[package]]
 +name = "crossbeam-epoch"
- checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1"
++version = "0.9.11"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
-  "once_cell",
++checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348"
 +dependencies = [
 + "autocfg",
 + "cfg-if",
 + "crossbeam-utils",
 + "memoffset",
- version = "0.8.11"
 + "scopeguard",
 +]
 +
 +[[package]]
 +name = "crossbeam-utils"
- checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
++version = "0.8.12"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
-  "once_cell",
++checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac"
 +dependencies = [
 + "cfg-if",
- version = "5.3.4"
 +]
 +
 +[[package]]
 +name = "dashmap"
- checksum = "3495912c9c1ccf2e18976439f4443f3fee0fd61f424ff99fde6a66b15ecb448f"
++version = "5.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.1.3"
++checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc"
 +dependencies = [
 + "cfg-if",
 + "hashbrown",
 + "lock_api",
++ "once_cell",
 + "parking_lot_core 0.9.3",
 +]
 +
 +[[package]]
 +name = "derive_arbitrary"
- checksum = "c9a577516173adb681466d517d39bd468293bc2c2a16439375ef0f35bba45f3d"
++version = "1.1.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.1"
++checksum = "226ad66541d865d7a7173ad6a9e691c33fdb910ac723f4bc734b3e5294a1f931"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "dissimilar"
 +version = "1.0.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8c97b9233581d84b8e1e689cdd3a47b6f69770084fc246e86a7f78b0d9c1d4a5"
 +
 +[[package]]
 +name = "dot"
 +version = "0.1.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a74b6c4d4a1cff5f454164363c16b72fa12463ca6b31f4b5f2035a65fa3d5906"
 +
 +[[package]]
 +name = "drop_bomb"
 +version = "0.1.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1"
 +
 +[[package]]
 +name = "either"
 +version = "1.8.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +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",
 + "rustc-hash",
 + "serde",
 + "serde_json",
 + "stdx",
 + "toolchain",
 + "tracing",
 +]
 +
 +[[package]]
 +name = "form_urlencoded"
- checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
++version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
-  "matches",
++checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
 +dependencies = [
- version = "0.5.3"
 + "percent-encoding",
 +]
 +
 +[[package]]
 +name = "fs_extra"
 +version = "1.2.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"
 +
 +[[package]]
 +name = "fsevent-sys"
 +version = "4.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
 +dependencies = [
 + "libc",
 +]
 +
 +[[package]]
 +name = "fst"
 +version = "0.4.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
 +
 +[[package]]
 +name = "gimli"
 +version = "0.26.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
 +
 +[[package]]
 +name = "hashbrown"
 +version = "0.12.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +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-derive",
 + "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"
- checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
++version = "0.5.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.2.3"
++checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408"
 +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",
 + "memchr",
 + "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",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "text-edit",
 +]
 +
 +[[package]]
 +name = "idna"
- checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
++version = "0.3.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
-  "matches",
++checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
 +dependencies = [
- version = "0.10.3"
 + "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"
- checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
++version = "0.10.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.3"
++checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
 +dependencies = [
 + "either",
 +]
 +
 +[[package]]
 +name = "itoa"
- checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
++version = "1.0.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.2.132"
++checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
 +
 +[[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 = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
++version = "0.2.135"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.1.25"
++checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
 +
 +[[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"
- checksum = "11ca136052550448f55df7898c6dbe651c6b574fe38a0d9ea687a9f8088a2e2c"
++version = "0.1.26"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.4.7"
++checksum = "8fc093ab289b0bfda3aa1bdfab9c9542be29c7ef385cfcbe77f8c9813588eb48"
 +dependencies = [
 + "cc",
 +]
 +
 +[[package]]
 +name = "limit"
 +version = "0.0.0"
 +
 +[[package]]
 +name = "lock_api"
- checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
++version = "0.4.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- [[package]]
- name = "matches"
- version = "0.1.9"
- source = "registry+https://github.com/rust-lang/crates.io-index"
- checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
++checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
 +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.7.0"
 +dependencies = [
 + "crossbeam-channel",
 + "log",
 + "lsp-types",
 + "serde",
 + "serde_json",
 +]
 +
 +[[package]]
 +name = "lsp-types"
 +version = "0.93.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a3bcfee315dde785ba887edb540b08765fd7df75a7d948844be6bf5712246734"
 +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",
 +]
 +
- version = "0.1.29"
 +[[package]]
 +name = "mbe"
 +version = "0.0.0"
 +dependencies = [
 + "cov-mark",
 + "parser",
 + "rustc-hash",
 + "smallvec",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "tracing",
 + "tt",
 +]
 +
 +[[package]]
 +name = "memchr"
 +version = "2.5.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 +
 +[[package]]
 +name = "memmap2"
 +version = "0.5.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +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"
- checksum = "2f64ad83c969af2e732e907564deb0d0ed393cec4af80776f77dd77a1a427698"
++version = "0.1.30"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.5.3"
++checksum = "76ce6a4b40d3bff9eb3ce9881ca0737a85072f9f975886082640cd46a75cdb35"
 +dependencies = [
 + "libmimalloc-sys",
 +]
 +
 +[[package]]
 +name = "miniz_oxide"
- checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
++version = "0.5.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "5.0.0-pre.16"
++checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
 +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 = "530f6314d6904508082f4ea424a0275cf62d341e118b313663f266429cb19693"
++version = "5.0.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.13.1"
++checksum = "ed2c66da08abae1c024c01d635253e402341b4060a12e99b31c7594063bf490a"
 +dependencies = [
 + "bitflags",
 + "crossbeam-channel",
 + "filetime",
 + "fsevent-sys",
 + "inotify",
 + "kqueue",
 + "libc",
 + "mio",
 + "walkdir",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "num_cpus"
 +version = "1.13.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
 +dependencies = [
 + "hermit-abi",
 + "libc",
 +]
 +
 +[[package]]
 +name = "object"
 +version = "0.29.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
 +dependencies = [
 + "memchr",
 +]
 +
 +[[package]]
 +name = "once_cell"
- checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
++version = "1.15.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.8"
++checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
 +
 +[[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 = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22"
++version = "1.0.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "2.1.0"
++checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1"
 +
 +[[package]]
 +name = "paths"
 +version = "0.0.0"
 +
 +[[package]]
 +name = "percent-encoding"
- checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
++version = "2.2.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.46"
++checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
 +
 +[[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",
 + "paths",
 + "profile",
 + "serde",
 + "serde_json",
 + "snap",
 + "stdx",
 + "tracing",
 + "tt",
 +]
 +
 +[[package]]
 +name = "proc-macro-srv"
 +version = "0.0.0"
 +dependencies = [
 + "expect-test",
 + "libloading",
 + "mbe",
 + "memmap2",
 + "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 = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b"
++version = "1.0.47"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "10.0.2"
++checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
 +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 = "protobuf"
 +version = "3.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4ee4a7d8b91800c8f167a6268d1a1026607368e1adc84e98fe044aeb905302f7"
 +dependencies = [
 + "once_cell",
 + "protobuf-support",
 + "thiserror",
 +]
 +
 +[[package]]
 +name = "protobuf-support"
 +version = "3.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8ca157fe12fc7ee2e315f2f735e27df41b3d97cdd70ea112824dac1ffb08ee1c"
 +dependencies = [
 + "thiserror",
 +]
 +
 +[[package]]
 +name = "pulldown-cmark"
 +version = "0.9.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63"
 +dependencies = [
 + "bitflags",
 + "memchr",
 + "unicase",
 +]
 +
 +[[package]]
 +name = "pulldown-cmark-to-cmark"
- checksum = "c1353ac408192fa925228d3e60ff746167d03f4f7e54835d78ef79e08225d913"
++version = "10.0.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.15.8"
++checksum = "0194e6e1966c23cc5fd988714f85b18d548d773e81965413555d96569931833d"
 +dependencies = [
 + "pulldown-cmark",
 +]
 +
 +[[package]]
 +name = "quote"
 +version = "1.0.21"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +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"
 +version = "0.2.16"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
 +dependencies = [
 + "bitflags",
 +]
 +
 +[[package]]
 +name = "regex"
 +version = "1.6.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +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"
 +version = "0.6.27"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
 +
 +[[package]]
 +name = "rowan"
- checksum = "e88acf7b001007e9e8c989fe7449f6601d909e5dd2c56399fc158977ad6c56e8"
++version = "0.15.10"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.13"
++checksum = "5811547e7ba31e903fe48c8ceab10d40d70a101f3d15523c847cce91aa71f332"
 +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",
 + "scip",
 + "serde",
 + "serde_json",
 + "sourcegen",
 + "stdx",
 + "syntax",
 + "test-utils",
 + "threadpool",
 + "tikv-jemallocator",
 + "toolchain",
 + "tracing",
 + "tracing-log",
 + "tracing-subscriber",
 + "tracing-tree",
 + "tt",
 + "vfs",
 + "vfs-notify",
 + "winapi",
 + "xflags",
 + "xshell",
 +]
 +
 +[[package]]
 +name = "rustc-ap-rustc_lexer"
 +version = "725.0.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f950742ef8a203aa7661aad3ab880438ddeb7f95d4b837c30d65db1a2c5df68e"
 +dependencies = [
 + "unicode-xid",
 +]
 +
 +[[package]]
 +name = "rustc-demangle"
 +version = "0.1.21"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
 +
 +[[package]]
 +name = "rustc-hash"
 +version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 +
 +[[package]]
 +name = "ryu"
 +version = "1.0.11"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +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 = "scip"
 +version = "0.1.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "b2bfbb10286f69fad7c78db71004b7839bf957788359fe0c479f029f9849136b"
 +dependencies = [
 + "protobuf",
 +]
 +
 +[[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 = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711"
++version = "1.0.14"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.144"
++checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "serde"
- checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
++version = "1.0.145"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.144"
++checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
 +dependencies = [
 + "serde_derive",
 +]
 +
 +[[package]]
 +name = "serde_derive"
- checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
++version = "1.0.145"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.85"
++checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "serde_json"
- checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
++version = "1.0.86"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.9.0"
++checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074"
 +dependencies = [
 + "indexmap",
 + "itoa",
 + "ryu",
 + "serde",
 +]
 +
 +[[package]]
 +name = "serde_repr"
 +version = "0.1.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +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"
- checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
++version = "1.10.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.31"
++checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
 +
 +[[package]]
 +name = "smol_str"
 +version = "0.1.23"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7475118a28b7e3a2e157ce0131ba8c5526ea96e90ee601d9f6bb2e286a35ab44"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "snap"
 +version = "1.0.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "45456094d1983e2ee2a18fdfebce3189fa451699d0502cb8e3b49dba5ba41451"
 +
 +[[package]]
 +name = "sourcegen"
 +version = "0.0.0"
 +dependencies = [
 + "xshell",
 +]
 +
 +[[package]]
 +name = "stdx"
 +version = "0.0.0"
 +dependencies = [
 + "always-assert",
 + "backtrace",
 + "libc",
 + "miow",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "syn"
 +version = "1.0.102"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
 +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 = "thiserror"
- checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
++version = "1.0.37"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.31"
++checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
 +dependencies = [
 + "thiserror-impl",
 +]
 +
 +[[package]]
 +name = "thiserror-impl"
- checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
++version = "1.0.37"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.5.1+5.3.0-patched"
++checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[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"
- checksum = "931e876f91fed0827f863a2d153897790da0b24d882c721a79cb3beb0b903261"
++version = "0.5.2+5.3.0-patched"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.1.36"
++checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3"
 +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 = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
++version = "0.1.37"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.1.22"
++checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
 +dependencies = [
 + "cfg-if",
 + "pin-project-lite",
 + "tracing-attributes",
 + "tracing-core",
 +]
 +
 +[[package]]
 +name = "tracing-attributes"
- checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
++version = "0.1.23"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.1.29"
++checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "tracing-core"
- checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
++version = "0.1.30"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.3.15"
++checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
 +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 = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b"
++version = "0.3.16"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.0.1"
++checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
 +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"
- checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
++version = "1.0.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.1.21"
++checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
 +
 +[[package]]
 +name = "unicode-normalization"
- checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6"
++version = "0.1.22"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "1.9.0"
++checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
 +dependencies = [
 + "tinyvec",
 +]
 +
 +[[package]]
 +name = "unicode-segmentation"
- checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
++version = "1.10.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "0.2.3"
++checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
 +
 +[[package]]
 +name = "unicode-xid"
- checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
++version = "0.2.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
- version = "2.2.2"
++checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
 +
 +[[package]]
 +name = "url"
- checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
++version = "2.3.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
-  "matches",
++checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
 +dependencies = [
 + "form_urlencoded",
 + "idna",
 + "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",
 + "stdx",
 +]
 +
 +[[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.3.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cbf19f5031a1a812e96fede16f8161218883079946cea87619d3613db1efd268"
 +dependencies = [
 + "xflags-macros",
 +]
 +
 +[[package]]
 +name = "xflags-macros"
 +version = "0.3.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2afbd7f2039bb6cad2dd45f0c5dff49c0d4e26118398768b7a605524d4251809"
 +
 +[[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 6b68ca823894f90f3769a6c4dc60a6b4e1cb49a5,0000000000000000000000000000000000000000..286ef1e7dcb4dfde854c8ee20ab38575fed61264
mode 100644,000000..100644
--- /dev/null
@@@ -1,33 -1,0 +1,34 @@@
 +[workspace]
 +members = ["xtask/", "lib/*", "crates/*"]
 +exclude = ["crates/proc-macro-test/imp"]
 +
 +[profile.dev]
 +# Disabling debug info speeds up builds a bunch,
 +# and we don't rely on it for debugging that much.
 +debug = 0
 +
 +[profile.dev.package]
 +# These speed up local tests.
 +rowan.opt-level = 3
 +rustc-hash.opt-level = 3
 +smol_str.opt-level = 3
 +text-size.opt-level = 3
 +# This speeds up `cargo xtask dist`.
 +miniz_oxide.opt-level = 3
 +
 +[profile.release]
 +incremental = true
 +# Set this to 1 or 2 to get more useful backtraces in debugger.
 +debug = 0
 +
 +[patch.'crates-io']
 +# rowan = { path = "../rowan" }
 +
 +# chalk-solve = { path = "../chalk/chalk-solve" }
 +# chalk-ir = { path = "../chalk/chalk-ir" }
 +# chalk-recursive = { path = "../chalk/chalk-recursive" }
++# chalk-derive = { path = "../chalk/chalk-derive" }
 +
 +# ungrammar = { path = "../ungrammar" }
 +
 +# salsa = { path = "../salsa" }
index c9664a83ab863094701421f1aef244d5f728d95e,0000000000000000000000000000000000000000..ee1ad677a95f27ad3ff5a7d0049fb66e2c97f6a7
mode 100644,000000..100644
--- /dev/null
@@@ -1,26 -1,0 +1,26 @@@
- arbitrary = "1.1.0"
- derive_arbitrary = "1.1.0"
 +[package]
 +name = "cfg"
 +version = "0.0.0"
 +description = "TBD"
 +license = "MIT OR Apache-2.0"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
 +rustc-hash = "1.1.0"
 +
 +tt = { path = "../tt", version = "0.0.0" }
 +
 +[dev-dependencies]
 +mbe = { path = "../mbe" }
 +syntax = { path = "../syntax" }
 +expect-test = "1.4.0"
 +oorandom = "11.1.3"
 +# We depend on both individually instead of using `features = ["derive"]` to microoptimize the
 +# build graph: if the feature was enabled, syn would be built early on in the graph if `smolstr`
 +# supports `arbitrary`. This way, we avoid feature unification.
++arbitrary = "1.1.7"
++derive_arbitrary = "1.1.6"
index 688e790c5368cdbe67c15b21287681b9e2f5fa22,0000000000000000000000000000000000000000..2ad32d24837d7771f0126ac6052c5965308cccae
mode 100644,000000..100644
--- /dev/null
@@@ -1,23 -1,0 +1,23 @@@
- tracing = "0.1.35"
 +[package]
 +name = "flycheck"
 +version = "0.0.0"
 +description = "TBD"
 +license = "MIT OR Apache-2.0"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
 +crossbeam-channel = "0.5.5"
- serde_json = "1.0.81"
++tracing = "0.1.37"
 +cargo_metadata = "0.15.0"
 +rustc-hash = "1.1.0"
 +serde = { version = "1.0.137", features = ["derive"] }
++serde_json = "1.0.86"
 +jod-thread = "0.1.2"
 +
 +toolchain = { path = "../toolchain", version = "0.0.0" }
 +stdx = { path = "../stdx", version = "0.0.0" }
 +paths = { path = "../paths", version = "0.0.0" }
index e8cff2f3e6cd7190bb63b188a5063fdd022e3ec6,0000000000000000000000000000000000000000..4ad8e75970b5995909bea43cb6157b13c321b850
mode 100644,000000..100644
--- /dev/null
@@@ -1,43 -1,0 +1,43 @@@
- dashmap = { version = "=5.3.4", features = ["raw-api"] }
 +[package]
 +name = "hir-def"
 +version = "0.0.0"
 +description = "TBD"
 +license = "MIT OR Apache-2.0"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
 +anymap = "1.0.0-beta.2"
 +arrayvec = "0.7.2"
 +bitflags = "1.3.2"
 +cov-mark = "2.0.0-pre.1"
 +# We need to freeze the version of the crate, as the raw-api feature is considered unstable
- itertools = "0.10.3"
++dashmap = { version = "=5.4.0", features = ["raw-api"] }
 +drop_bomb = "0.1.5"
 +either = "1.7.0"
 +fst = { version = "0.4.7", default-features = false }
 +hashbrown = { version = "0.12.1", default-features = false }
 +indexmap = "1.9.1"
- once_cell = "1.12.0"
++itertools = "0.10.5"
 +la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
- smallvec = "1.9.0"
++once_cell = "1.15.0"
 +rustc-hash = "1.1.0"
++smallvec = "1.10.0"
 +tracing = "0.1.35"
 +
 +stdx = { path = "../stdx", version = "0.0.0" }
 +base-db = { path = "../base-db", version = "0.0.0" }
 +syntax = { path = "../syntax", version = "0.0.0" }
 +profile = { path = "../profile", version = "0.0.0" }
 +hir-expand = { path = "../hir-expand", version = "0.0.0" }
 +mbe = { path = "../mbe", version = "0.0.0" }
 +cfg = { path = "../cfg", version = "0.0.0" }
 +tt = { path = "../tt", version = "0.0.0" }
 +limit = { path = "../limit", version = "0.0.0" }
 +
 +[dev-dependencies]
 +test-utils = { path = "../test-utils" }
 +expect-test = "1.4.0"
index 2dc7714bbb540597c2cbcf881b9acdf2fba8dc74,0000000000000000000000000000000000000000..759f3b8c04b6cdb1e2ea7cd02cc52b2df7f4b894
mode 100644,000000..100644
--- /dev/null
@@@ -1,487 -1,0 +1,501 @@@
-                 params = src.value.param_list();
 +//! 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::{HasChildSource, 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>;
 +
 +pub type FieldPtr = AstPtr<ast::RecordExprField>;
 +pub type FieldSource = InFile<FieldPtr>;
 +
 +/// 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, ExprSource>,
 +
 +    pat_map: FxHashMap<PatSource, PatId>,
 +    pat_map_back: ArenaMap<PatId, PatSource>,
 +
 +    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<FieldSource, ExprId>,
 +    field_map_back: FxHashMap<ExprId, FieldSource>,
 +
 +    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: Option<ast::ParamList>,
++                params = src.value.param_list().map(|param_list| {
++                    let item_tree = f.id.item_tree(db);
++                    let func = &item_tree[f.id.value];
++                    let krate = f.container.module(db).krate;
++                    let crate_graph = db.crate_graph();
++                    (
++                        param_list,
++                        func.params.clone().map(move |param| {
++                            item_tree
++                                .attrs(db, krate, param.into())
++                                .is_cfg_enabled(&crate_graph[krate].cfg_options)
++                        }),
++                    )
++                });
 +                (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())
 +            }
 +            DefWithBodyId::VariantId(v) => {
 +                let e = v.parent.lookup(db);
 +                let src = v.parent.child_source(db);
 +                let variant = &src.value[v.local_id];
 +                (src.file_id, e.container, variant.expr())
 +            }
 +        };
 +        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, impl Iterator<Item = bool>)>,
 +        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.get(expr).cloned().ok_or(SyntheticSyntax)
 +    }
 +
 +    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.get(pat).cloned().ok_or(SyntheticSyntax)
 +    }
 +
 +    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) -> FieldSource {
 +        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 c4f91e49a6e1b4d53d3f57df2bf2cc8da2f6efdc,0000000000000000000000000000000000000000..ccc01c3efca51468eb320a664128bba7d61473e7
mode 100644,000000..100644
--- /dev/null
@@@ -1,1042 -1,0 +1,1048 @@@
-     params: Option<ast::ParamList>,
 +//! 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, ExprPtr, LabelPtr, LabelSource, PatPtr},
 +    body::{BodyDiagnostic, ExprSource, PatSource},
 +    builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
 +    db::DefDatabase,
 +    expr::{
 +        dummy_expr_id, Array, BindingAnnotation, ClosureKind, Expr, ExprId, FloatTypeWrapper,
 +        Label, LabelId, Literal, MatchArm, Movability, 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,
-         param_list: Option<ast::ParamList>,
++    params: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
 +    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,
 +        is_lowering_generator: 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,
 +    is_lowering_generator: bool,
 +}
 +
 +impl ExprCollector<'_> {
 +    fn collect(
 +        mut self,
-         if let Some(param_list) = param_list {
-             if let Some(self_param) = param_list.self_param() {
++        param_list: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
 +        body: Option<ast::Expr>,
 +    ) -> (Body, BodySourceMap) {
-             for pat in param_list.params().filter_map(|param| param.pat()) {
++        if let Some((param_list, mut attr_enabled)) = param_list {
++            if let Some(self_param) =
++                param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
++            {
 +                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()
++                .zip(attr_enabled)
++                .filter_map(|(param, enabled)| param.pat().filter(|_| enabled))
++            {
 +                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: ExprPtr) -> ExprId {
 +        let src = self.expander.to_source(ptr);
 +        let id = self.make_expr(expr, 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.body.exprs.alloc(expr)
 +    }
 +    fn missing_expr(&mut self) -> ExprId {
 +        self.alloc_expr_desugared(Expr::Missing)
 +    }
 +    fn make_expr(&mut self, expr: Expr, src: ExprSource) -> 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, src.clone());
 +        self.source_map.pat_map.insert(src, id);
 +        id
 +    }
 +    fn missing_pat(&mut self) -> PatId {
 +        self.body.pats.alloc(Pat::Missing)
 +    }
 +    fn make_pat(&mut self, pat: Pat, src: PatSource) -> 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: LabelPtr) -> 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) => {
 +                self.is_lowering_generator = true;
 +                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 prev_is_lowering_generator = self.is_lowering_generator;
 +                self.is_lowering_generator = false;
 +
 +                let body = self.collect_expr_opt(e.body());
 +
 +                let closure_kind = if self.is_lowering_generator {
 +                    let movability = if e.static_token().is_some() {
 +                        Movability::Static
 +                    } else {
 +                        Movability::Movable
 +                    };
 +                    ClosureKind::Generator(movability)
 +                } else {
 +                    ClosureKind::Closure
 +                };
 +                self.is_lowering_generator = prev_is_lowering_generator;
 +
 +                self.alloc_expr(
 +                    Expr::Closure {
 +                        args: args.into(),
 +                        arg_types: arg_types.into(),
 +                        ret_type,
 +                        body,
 +                        closure_kind,
 +                    },
 +                    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::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_macro_as_stmt(
 +        &mut self,
 +        statements: &mut Vec<Statement>,
 +        mac: ast::MacroExpr,
 +    ) -> Option<ExprId> {
 +        let mac_call = mac.macro_call()?;
 +        let syntax_ptr = AstPtr::new(&ast::Expr::from(mac));
 +        let macro_ptr = AstPtr::new(&mac_call);
 +        let expansion = self.collect_macro_call(
 +            mac_call,
 +            macro_ptr,
 +            false,
 +            |this, expansion: Option<ast::MacroStmts>| match expansion {
 +                Some(expansion) => {
 +                    expansion.statements().for_each(|stmt| this.collect_stmt(statements, stmt));
 +                    expansion.expr().and_then(|expr| match expr {
 +                        ast::Expr::MacroExpr(mac) => this.collect_macro_as_stmt(statements, mac),
 +                        expr => Some(this.collect_expr(expr)),
 +                    })
 +                }
 +                None => None,
 +            },
 +        );
 +        match expansion {
 +            Some(tail) => {
 +                // 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, tail);
 +                Some(tail)
 +            }
 +            None => None,
 +        }
 +    }
 +
 +    fn collect_stmt(&mut self, statements: &mut Vec<Statement>, s: ast::Stmt) {
 +        match s {
 +            ast::Stmt::LetStmt(stmt) => {
 +                if self.check_cfg(&stmt).is_none() {
 +                    return;
 +                }
 +                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));
 +                statements.push(Statement::Let { pat, type_ref, initializer, else_branch });
 +            }
 +            ast::Stmt::ExprStmt(stmt) => {
 +                let expr = stmt.expr();
 +                match &expr {
 +                    Some(expr) if self.check_cfg(expr).is_none() => return,
 +                    _ => (),
 +                }
 +                let has_semi = stmt.semicolon_token().is_some();
 +                // Note that macro could be expanded to multiple statements
 +                if let Some(ast::Expr::MacroExpr(mac)) = expr {
 +                    if let Some(expr) = self.collect_macro_as_stmt(statements, mac) {
 +                        statements.push(Statement::Expr { expr, has_semi })
 +                    }
 +                } else {
 +                    let expr = self.collect_expr_opt(expr);
 +                    statements.push(Statement::Expr { expr, has_semi });
 +                }
 +            }
 +            ast::Stmt::Item(_item) => (),
 +        }
 +    }
 +
 +    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::new();
 +        block.statements().for_each(|s| self.collect_stmt(&mut statements, s));
 +        let tail = block.tail_expr().and_then(|e| match e {
 +            ast::Expr::MacroExpr(mac) => self.collect_macro_as_stmt(&mut statements, mac),
 +            expr => self.maybe_collect_expr(expr),
 +        });
 +        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 4f626105a53d60f727cfd02e71b66ea95e7450ae,0000000000000000000000000000000000000000..c04cd1651926dfb86d412835c2c343e219a40e7f
mode 100644,000000..100644
--- /dev/null
@@@ -1,377 -1,0 +1,377 @@@
-         expect![[r##"
 +//! Tests for `builtin_fn_macro.rs` from `hir_expand`.
 +
 +use expect_test::expect;
 +
 +use crate::macro_expansion_tests::check;
 +
 +#[test]
 +fn test_column_expand() {
 +    check(
 +        r#"
 +#[rustc_builtin_macro]
 +macro_rules! column {() => {}}
 +
 +fn main() { column!(); }
 +"#,
 +        expect![[r##"
 +#[rustc_builtin_macro]
 +macro_rules! column {() => {}}
 +
 +fn main() { 0; }
 +"##]],
 +    );
 +}
 +
 +#[test]
 +fn test_line_expand() {
 +    check(
 +        r#"
 +#[rustc_builtin_macro]
 +macro_rules! line {() => {}}
 +
 +fn main() { line!() }
 +"#,
 +        expect![[r##"
 +#[rustc_builtin_macro]
 +macro_rules! line {() => {}}
 +
 +fn main() { 0 }
 +"##]],
 +    );
 +}
 +
 +#[test]
 +fn test_stringify_expand() {
 +    check(
 +        r#"
 +#[rustc_builtin_macro]
 +macro_rules! stringify {() => {}}
 +
 +fn main() {
 +    stringify!(
 +        a
 +        b
 +        c
 +    );
 +}
 +"#,
 +        expect![[r##"
 +#[rustc_builtin_macro]
 +macro_rules! stringify {() => {}}
 +
 +fn main() {
 +    "a b c";
 +}
 +"##]],
 +    );
 +}
 +
 +#[test]
 +fn test_env_expand() {
 +    check(
 +        r#"
 +#[rustc_builtin_macro]
 +macro_rules! env {() => {}}
 +
 +fn main() { env!("TEST_ENV_VAR"); }
 +"#,
 +        expect![[r##"
 +#[rustc_builtin_macro]
 +macro_rules! env {() => {}}
 +
 +fn main() { "__RA_UNIMPLEMENTED__"; }
 +"##]],
 +    );
 +}
 +
 +#[test]
 +fn test_option_env_expand() {
 +    check(
 +        r#"
 +#[rustc_builtin_macro]
 +macro_rules! option_env {() => {}}
 +
 +fn main() { option_env!("TEST_ENV_VAR"); }
 +"#,
- fn main() { std::option::Option::None:: < &str>; }
- "##]],
++        expect![[r#"
 +#[rustc_builtin_macro]
 +macro_rules! option_env {() => {}}
 +
-         expect![[r##"
++fn main() { $crate::option::Option::None:: < &str>; }
++"#]],
 +    );
 +}
 +
 +#[test]
 +fn test_file_expand() {
 +    check(
 +        r#"
 +#[rustc_builtin_macro]
 +macro_rules! file {() => {}}
 +
 +fn main() { file!(); }
 +"#,
 +        expect![[r##"
 +#[rustc_builtin_macro]
 +macro_rules! file {() => {}}
 +
 +fn main() { ""; }
 +"##]],
 +    );
 +}
 +
 +#[test]
 +fn test_assert_expand() {
 +    check(
 +        r#"
 +#[rustc_builtin_macro]
 +macro_rules! assert {
 +    ($cond:expr) => ({ /* compiler built-in */ });
 +    ($cond:expr, $($args:tt)*) => ({ /* compiler built-in */ })
 +}
 +
 +fn main() {
 +    assert!(true, "{} {:?}", arg1(a, b, c), arg2);
 +}
 +"#,
 +        expect![[r##"
 +#[rustc_builtin_macro]
 +macro_rules! assert {
 +    ($cond:expr) => ({ /* compiler built-in */ });
 +    ($cond:expr, $($args:tt)*) => ({ /* compiler built-in */ })
 +}
 +
 +fn main() {
 +     {
 +        if !true {
 +            $crate::panic!("{} {:?}", arg1(a, b, c), arg2);
 +        }
 +    };
 +}
 +"##]],
 +    );
 +}
 +
 +#[test]
 +fn test_compile_error_expand() {
 +    check(
 +        r#"
 +#[rustc_builtin_macro]
 +macro_rules! compile_error {
 +    ($msg:expr) => ({ /* compiler built-in */ });
 +    ($msg:expr,) => ({ /* compiler built-in */ })
 +}
 +
 +// This expands to nothing (since it's in item position), but emits an error.
 +compile_error!("error!");
 +"#,
 +        expect![[r##"
 +#[rustc_builtin_macro]
 +macro_rules! compile_error {
 +    ($msg:expr) => ({ /* compiler built-in */ });
 +    ($msg:expr,) => ({ /* compiler built-in */ })
 +}
 +
 +/* error: error! */
 +"##]],
 +    );
 +}
 +
 +#[test]
 +fn test_format_args_expand() {
 +    check(
 +        r#"
 +#[rustc_builtin_macro]
 +macro_rules! format_args {
 +    ($fmt:expr) => ({ /* compiler built-in */ });
 +    ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
 +}
 +
 +fn main() {
 +    format_args!("{} {:?}", arg1(a, b, c), arg2);
 +}
 +"#,
-     std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(arg1(a, b, c)), std::fmt::Display::fmt), std::fmt::ArgumentV1::new(&(arg2), std::fmt::Display::fmt), ]);
++        expect![[r#"
 +#[rustc_builtin_macro]
 +macro_rules! format_args {
 +    ($fmt:expr) => ({ /* compiler built-in */ });
 +    ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
 +}
 +
 +fn main() {
- "##]],
++    $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(arg1(a, b, c)), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(arg2), $crate::fmt::Display::fmt), ]);
 +}
-         expect![[r##"
++"#]],
 +    );
 +}
 +
 +#[test]
 +fn test_format_args_expand_with_comma_exprs() {
 +    check(
 +        r#"
 +#[rustc_builtin_macro]
 +macro_rules! format_args {
 +    ($fmt:expr) => ({ /* compiler built-in */ });
 +    ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
 +}
 +
 +fn main() {
 +    format_args!("{} {:?}", a::<A,B>(), b);
 +}
 +"#,
-     std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a::<A, B>()), std::fmt::Display::fmt), std::fmt::ArgumentV1::new(&(b), std::fmt::Display::fmt), ]);
++        expect![[r#"
 +#[rustc_builtin_macro]
 +macro_rules! format_args {
 +    ($fmt:expr) => ({ /* compiler built-in */ });
 +    ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
 +}
 +
 +fn main() {
- "##]],
++    $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a::<A, B>()), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(b), $crate::fmt::Display::fmt), ]);
 +}
-         expect![[r##"
++"#]],
 +    );
 +}
 +
 +#[test]
 +fn test_format_args_expand_with_broken_member_access() {
 +    check(
 +        r#"
 +#[rustc_builtin_macro]
 +macro_rules! format_args {
 +    ($fmt:expr) => ({ /* compiler built-in */ });
 +    ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
 +}
 +
 +fn main() {
 +    let _ =
 +        format_args!/*+errors*/("{} {:?}", a.);
 +}
 +"#,
- std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a.), std::fmt::Display::fmt), ]);
++        expect![[r#"
 +#[rustc_builtin_macro]
 +macro_rules! format_args {
 +    ($fmt:expr) => ({ /* compiler built-in */ });
 +    ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
 +}
 +
 +fn main() {
 +    let _ =
 +        /* parse error: expected field name or number */
- "##]],
++$crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a.), $crate::fmt::Display::fmt), ]);
 +}
++"#]],
 +    );
 +}
 +
 +#[test]
 +fn test_include_bytes_expand() {
 +    check(
 +        r#"
 +#[rustc_builtin_macro]
 +macro_rules! include_bytes {
 +    ($file:expr) => {{ /* compiler built-in */ }};
 +    ($file:expr,) => {{ /* compiler built-in */ }};
 +}
 +
 +fn main() { include_bytes("foo"); }
 +"#,
 +        expect![[r##"
 +#[rustc_builtin_macro]
 +macro_rules! include_bytes {
 +    ($file:expr) => {{ /* compiler built-in */ }};
 +    ($file:expr,) => {{ /* compiler built-in */ }};
 +}
 +
 +fn main() { include_bytes("foo"); }
 +"##]],
 +    );
 +}
 +
 +#[test]
 +fn test_concat_expand() {
 +    check(
 +        r##"
 +#[rustc_builtin_macro]
 +macro_rules! concat {}
 +
 +fn main() { concat!("foo", "r", 0, r#"bar"#, "\n", false, '"', '\0'); }
 +"##,
 +        expect![[r##"
 +#[rustc_builtin_macro]
 +macro_rules! concat {}
 +
 +fn main() { "foor0bar\nfalse\"\u{0}"; }
 +"##]],
 +    );
 +}
 +
 +#[test]
 +fn test_concat_bytes_expand() {
 +    check(
 +        r##"
 +#[rustc_builtin_macro]
 +macro_rules! concat_bytes {}
 +
 +fn main() { concat_bytes!(b'A', b"BC", [68, b'E', 70]); }
 +"##,
 +        expect![[r##"
 +#[rustc_builtin_macro]
 +macro_rules! concat_bytes {}
 +
 +fn main() { [b'A', 66, 67, 68, b'E', 70]; }
 +"##]],
 +    );
 +}
 +
 +#[test]
 +fn test_concat_with_captured_expr() {
 +    check(
 +        r##"
 +#[rustc_builtin_macro]
 +macro_rules! concat {}
 +
 +macro_rules! surprise {
 +    () => { "s" };
 +}
 +
 +macro_rules! stuff {
 +    ($string:expr) => { concat!($string) };
 +}
 +
 +fn main() { concat!(surprise!()); }
 +"##,
 +        expect![[r##"
 +#[rustc_builtin_macro]
 +macro_rules! concat {}
 +
 +macro_rules! surprise {
 +    () => { "s" };
 +}
 +
 +macro_rules! stuff {
 +    ($string:expr) => { concat!($string) };
 +}
 +
 +fn main() { "s"; }
 +"##]],
 +    );
 +}
 +
 +#[test]
 +fn test_concat_idents_expand() {
 +    check(
 +        r##"
 +#[rustc_builtin_macro]
 +macro_rules! concat_idents {}
 +
 +fn main() { concat_idents!(foo, bar); }
 +"##,
 +        expect![[r##"
 +#[rustc_builtin_macro]
 +macro_rules! concat_idents {}
 +
 +fn main() { foobar; }
 +"##]],
 +    );
 +}
index dfd470ffca6ac025e79ecb331727fd243b32769f,0000000000000000000000000000000000000000..3359c99b3961c098ef788b2ec02086160a1e9d98
mode 100644,000000..100644
--- /dev/null
@@@ -1,34 -1,0 +1,34 @@@
- itertools = "0.10.3"
 +[package]
 +name = "hir-expand"
 +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"
 +tracing = "0.1.35"
 +either = "1.7.0"
 +rustc-hash = "1.1.0"
 +la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
- smallvec = { version = "1.9.0", features = ["const_new"] }
++itertools = "0.10.5"
 +hashbrown = { version = "0.12.1", features = [
 +    "inline-more",
 +], default-features = false }
++smallvec = { version = "1.10.0", features = ["const_new"] }
 +
 +stdx = { path = "../stdx", version = "0.0.0" }
 +base-db = { path = "../base-db", version = "0.0.0" }
 +cfg = { path = "../cfg", version = "0.0.0" }
 +syntax = { path = "../syntax", version = "0.0.0" }
 +profile = { path = "../profile", version = "0.0.0" }
 +tt = { path = "../tt", version = "0.0.0" }
 +mbe = { path = "../mbe", version = "0.0.0" }
 +limit = { path = "../limit", version = "0.0.0" }
 +
 +[dev-dependencies]
 +expect-test = "1.4.0"
index 8befa7f7da7279e112671a53a47b95716a50a76a,0000000000000000000000000000000000000000..7b19518e25a8437a16c302dcb8f9399a2faebd34
mode 100644,000000..100644
--- /dev/null
@@@ -1,683 -1,0 +1,683 @@@
-     // std::fmt::Arguments::new_v1(&[], &[
-     //   std::fmt::ArgumentV1::new(&arg1,std::fmt::Display::fmt),
-     //   std::fmt::ArgumentV1::new(&arg2,std::fmt::Display::fmt),
 +//! Builtin macro
 +
 +use base_db::{AnchoredPath, Edition, FileId};
 +use cfg::CfgExpr;
 +use either::Either;
 +use mbe::{parse_exprs_with_sep, parse_to_token_tree};
 +use syntax::{
 +    ast::{self, AstToken},
 +    SmolStr,
 +};
 +
 +use crate::{db::AstDatabase, name, quote, ExpandError, ExpandResult, MacroCallId, MacroCallLoc};
 +
 +macro_rules! register_builtin {
 +    ( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),*  ) => {
 +        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +        pub enum BuiltinFnLikeExpander {
 +            $($kind),*
 +        }
 +
 +        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +        pub enum EagerExpander {
 +            $($e_kind),*
 +        }
 +
 +        impl BuiltinFnLikeExpander {
 +            pub fn expand(
 +                &self,
 +                db: &dyn AstDatabase,
 +                id: MacroCallId,
 +                tt: &tt::Subtree,
 +            ) -> ExpandResult<tt::Subtree> {
 +                let expander = match *self {
 +                    $( BuiltinFnLikeExpander::$kind => $expand, )*
 +                };
 +                expander(db, id, tt)
 +            }
 +        }
 +
 +        impl EagerExpander {
 +            pub fn expand(
 +                &self,
 +                db: &dyn AstDatabase,
 +                arg_id: MacroCallId,
 +                tt: &tt::Subtree,
 +            ) -> ExpandResult<ExpandedEager> {
 +                let expander = match *self {
 +                    $( EagerExpander::$e_kind => $e_expand, )*
 +                };
 +                expander(db, arg_id, tt)
 +            }
 +        }
 +
 +        fn find_by_name(ident: &name::Name) -> Option<Either<BuiltinFnLikeExpander, EagerExpander>> {
 +            match ident {
 +                $( id if id == &name::name![$name] => Some(Either::Left(BuiltinFnLikeExpander::$kind)), )*
 +                $( id if id == &name::name![$e_name] => Some(Either::Right(EagerExpander::$e_kind)), )*
 +                _ => return None,
 +            }
 +        }
 +    };
 +}
 +
 +#[derive(Debug, Default)]
 +pub struct ExpandedEager {
 +    pub(crate) subtree: tt::Subtree,
 +    /// The included file ID of the include macro.
 +    pub(crate) included_file: Option<FileId>,
 +}
 +
 +impl ExpandedEager {
 +    fn new(subtree: tt::Subtree) -> Self {
 +        ExpandedEager { subtree, included_file: None }
 +    }
 +}
 +
 +pub fn find_builtin_macro(
 +    ident: &name::Name,
 +) -> Option<Either<BuiltinFnLikeExpander, EagerExpander>> {
 +    find_by_name(ident)
 +}
 +
 +register_builtin! {
 +    LAZY:
 +    (column, Column) => column_expand,
 +    (file, File) => file_expand,
 +    (line, Line) => line_expand,
 +    (module_path, ModulePath) => module_path_expand,
 +    (assert, Assert) => assert_expand,
 +    (stringify, Stringify) => stringify_expand,
 +    (format_args, FormatArgs) => format_args_expand,
 +    (const_format_args, ConstFormatArgs) => format_args_expand,
 +    // format_args_nl only differs in that it adds a newline in the end,
 +    // so we use the same stub expansion for now
 +    (format_args_nl, FormatArgsNl) => format_args_expand,
 +    (llvm_asm, LlvmAsm) => asm_expand,
 +    (asm, Asm) => asm_expand,
 +    (global_asm, GlobalAsm) => global_asm_expand,
 +    (cfg, Cfg) => cfg_expand,
 +    (core_panic, CorePanic) => panic_expand,
 +    (std_panic, StdPanic) => panic_expand,
 +    (unreachable, Unreachable) => unreachable_expand,
 +    (log_syntax, LogSyntax) => log_syntax_expand,
 +    (trace_macros, TraceMacros) => trace_macros_expand,
 +
 +    EAGER:
 +    (compile_error, CompileError) => compile_error_expand,
 +    (concat, Concat) => concat_expand,
 +    (concat_idents, ConcatIdents) => concat_idents_expand,
 +    (concat_bytes, ConcatBytes) => concat_bytes_expand,
 +    (include, Include) => include_expand,
 +    (include_bytes, IncludeBytes) => include_bytes_expand,
 +    (include_str, IncludeStr) => include_str_expand,
 +    (env, Env) => env_expand,
 +    (option_env, OptionEnv) => option_env_expand
 +}
 +
 +const DOLLAR_CRATE: tt::Ident =
 +    tt::Ident { text: SmolStr::new_inline("$crate"), id: tt::TokenId::unspecified() };
 +
 +fn module_path_expand(
 +    _db: &dyn AstDatabase,
 +    _id: MacroCallId,
 +    _tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    // Just return a dummy result.
 +    ExpandResult::ok(quote! { "module::path" })
 +}
 +
 +fn line_expand(
 +    _db: &dyn AstDatabase,
 +    _id: MacroCallId,
 +    _tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    // dummy implementation for type-checking purposes
 +    let line_num = 0;
 +    let expanded = quote! {
 +        #line_num
 +    };
 +
 +    ExpandResult::ok(expanded)
 +}
 +
 +fn log_syntax_expand(
 +    _db: &dyn AstDatabase,
 +    _id: MacroCallId,
 +    _tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    ExpandResult::ok(quote! {})
 +}
 +
 +fn trace_macros_expand(
 +    _db: &dyn AstDatabase,
 +    _id: MacroCallId,
 +    _tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    ExpandResult::ok(quote! {})
 +}
 +
 +fn stringify_expand(
 +    _db: &dyn AstDatabase,
 +    _id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    let pretty = tt::pretty(&tt.token_trees);
 +
 +    let expanded = quote! {
 +        #pretty
 +    };
 +
 +    ExpandResult::ok(expanded)
 +}
 +
 +fn column_expand(
 +    _db: &dyn AstDatabase,
 +    _id: MacroCallId,
 +    _tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    // dummy implementation for type-checking purposes
 +    let col_num = 0;
 +    let expanded = quote! {
 +        #col_num
 +    };
 +
 +    ExpandResult::ok(expanded)
 +}
 +
 +fn assert_expand(
 +    _db: &dyn AstDatabase,
 +    _id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    let args = parse_exprs_with_sep(tt, ',');
 +    let expanded = match &*args {
 +        [cond, panic_args @ ..] => {
 +            let comma = tt::Subtree {
 +                delimiter: None,
 +                token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
 +                    char: ',',
 +                    spacing: tt::Spacing::Alone,
 +                    id: tt::TokenId::unspecified(),
 +                }))],
 +            };
 +            let cond = cond.clone();
 +            let panic_args = itertools::Itertools::intersperse(panic_args.iter().cloned(), comma);
 +            quote! {{
 +                if !#cond {
 +                    #DOLLAR_CRATE::panic!(##panic_args);
 +                }
 +            }}
 +        }
 +        [] => quote! {{}},
 +    };
 +
 +    ExpandResult::ok(expanded)
 +}
 +
 +fn file_expand(
 +    _db: &dyn AstDatabase,
 +    _id: MacroCallId,
 +    _tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    // FIXME: RA purposefully lacks knowledge of absolute file names
 +    // so just return "".
 +    let file_name = "";
 +
 +    let expanded = quote! {
 +        #file_name
 +    };
 +
 +    ExpandResult::ok(expanded)
 +}
 +
 +fn format_args_expand(
 +    _db: &dyn AstDatabase,
 +    _id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    // We expand `format_args!("", a1, a2)` to
 +    // ```
-         quote! { std::fmt::ArgumentV1::new(&(#arg), std::fmt::Display::fmt), }
++    // $crate::fmt::Arguments::new_v1(&[], &[
++    //   $crate::fmt::ArgumentV1::new(&arg1,$crate::fmt::Display::fmt),
++    //   $crate::fmt::ArgumentV1::new(&arg2,$crate::fmt::Display::fmt),
 +    // ])
 +    // ```,
 +    // which is still not really correct, but close enough for now
 +    let mut args = parse_exprs_with_sep(tt, ',');
 +
 +    if args.is_empty() {
 +        return ExpandResult::only_err(mbe::ExpandError::NoMatchingRule.into());
 +    }
 +    for arg in &mut args {
 +        // Remove `key =`.
 +        if matches!(arg.token_trees.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=')
 +        {
 +            // but not with `==`
 +            if !matches!(arg.token_trees.get(2), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' )
 +            {
 +                arg.token_trees.drain(..2);
 +            }
 +        }
 +    }
 +    let _format_string = args.remove(0);
 +    let arg_tts = args.into_iter().flat_map(|arg| {
-         std::fmt::Arguments::new_v1(&[], &[##arg_tts])
++        quote! { #DOLLAR_CRATE::fmt::ArgumentV1::new(&(#arg), #DOLLAR_CRATE::fmt::Display::fmt), }
 +    }.token_trees);
 +    let expanded = quote! {
-         None => quote! { std::option::Option::None::<&str> },
-         Some(s) => quote! { std::option::Some(#s) },
++        #DOLLAR_CRATE::fmt::Arguments::new_v1(&[], &[##arg_tts])
 +    };
 +    ExpandResult::ok(expanded)
 +}
 +
 +fn asm_expand(
 +    _db: &dyn AstDatabase,
 +    _id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    // We expand all assembly snippets to `format_args!` invocations to get format syntax
 +    // highlighting for them.
 +
 +    let mut literals = Vec::new();
 +    for tt in tt.token_trees.chunks(2) {
 +        match tt {
 +            [tt::TokenTree::Leaf(tt::Leaf::Literal(lit))]
 +            | [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', id: _, spacing: _ }))] =>
 +            {
 +                let krate = DOLLAR_CRATE.clone();
 +                literals.push(quote!(#krate::format_args!(#lit);));
 +            }
 +            _ => break,
 +        }
 +    }
 +
 +    let expanded = quote! {{
 +        ##literals
 +        loop {}
 +    }};
 +    ExpandResult::ok(expanded)
 +}
 +
 +fn global_asm_expand(
 +    _db: &dyn AstDatabase,
 +    _id: MacroCallId,
 +    _tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    // Expand to nothing (at item-level)
 +    ExpandResult::ok(quote! {})
 +}
 +
 +fn cfg_expand(
 +    db: &dyn AstDatabase,
 +    id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    let loc = db.lookup_intern_macro_call(id);
 +    let expr = CfgExpr::parse(tt);
 +    let enabled = db.crate_graph()[loc.krate].cfg_options.check(&expr) != Some(false);
 +    let expanded = if enabled { quote!(true) } else { quote!(false) };
 +    ExpandResult::ok(expanded)
 +}
 +
 +fn panic_expand(
 +    db: &dyn AstDatabase,
 +    id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
 +    // Expand to a macro call `$crate::panic::panic_{edition}`
 +    let mut call = if db.crate_graph()[loc.krate].edition >= Edition::Edition2021 {
 +        quote!(#DOLLAR_CRATE::panic::panic_2021!)
 +    } else {
 +        quote!(#DOLLAR_CRATE::panic::panic_2015!)
 +    };
 +
 +    // Pass the original arguments
 +    call.token_trees.push(tt::TokenTree::Subtree(tt.clone()));
 +    ExpandResult::ok(call)
 +}
 +
 +fn unreachable_expand(
 +    db: &dyn AstDatabase,
 +    id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
 +    // Expand to a macro call `$crate::panic::unreachable_{edition}`
 +    let mut call = if db.crate_graph()[loc.krate].edition >= Edition::Edition2021 {
 +        quote!(#DOLLAR_CRATE::panic::unreachable_2021!)
 +    } else {
 +        quote!(#DOLLAR_CRATE::panic::unreachable_2015!)
 +    };
 +
 +    // Pass the original arguments
 +    call.token_trees.push(tt::TokenTree::Subtree(tt.clone()));
 +    ExpandResult::ok(call)
 +}
 +
 +fn unquote_str(lit: &tt::Literal) -> Option<String> {
 +    let lit = ast::make::tokens::literal(&lit.to_string());
 +    let token = ast::String::cast(lit)?;
 +    token.value().map(|it| it.into_owned())
 +}
 +
 +fn unquote_char(lit: &tt::Literal) -> Option<char> {
 +    let lit = ast::make::tokens::literal(&lit.to_string());
 +    let token = ast::Char::cast(lit)?;
 +    token.value()
 +}
 +
 +fn unquote_byte_string(lit: &tt::Literal) -> Option<Vec<u8>> {
 +    let lit = ast::make::tokens::literal(&lit.to_string());
 +    let token = ast::ByteString::cast(lit)?;
 +    token.value().map(|it| it.into_owned())
 +}
 +
 +fn compile_error_expand(
 +    _db: &dyn AstDatabase,
 +    _id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<ExpandedEager> {
 +    let err = match &*tt.token_trees {
 +        [tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => {
 +            let text = it.text.as_str();
 +            if text.starts_with('"') && text.ends_with('"') {
 +                // FIXME: does not handle raw strings
 +                ExpandError::Other(text[1..text.len() - 1].into())
 +            } else {
 +                ExpandError::Other("`compile_error!` argument must be a string".into())
 +            }
 +        }
 +        _ => ExpandError::Other("`compile_error!` argument must be a string".into()),
 +    };
 +
 +    ExpandResult { value: ExpandedEager::new(quote! {}), err: Some(err) }
 +}
 +
 +fn concat_expand(
 +    _db: &dyn AstDatabase,
 +    _arg_id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<ExpandedEager> {
 +    let mut err = None;
 +    let mut text = String::new();
 +    for (i, mut t) in tt.token_trees.iter().enumerate() {
 +        // FIXME: hack on top of a hack: `$e:expr` captures get surrounded in parentheses
 +        // to ensure the right parsing order, so skip the parentheses here. Ideally we'd
 +        // implement rustc's model. cc https://github.com/rust-lang/rust-analyzer/pull/10623
 +        if let tt::TokenTree::Subtree(tt::Subtree { delimiter: Some(delim), token_trees }) = t {
 +            if let [tt] = &**token_trees {
 +                if delim.kind == tt::DelimiterKind::Parenthesis {
 +                    t = tt;
 +                }
 +            }
 +        }
 +
 +        match t {
 +            tt::TokenTree::Leaf(tt::Leaf::Literal(it)) if i % 2 == 0 => {
 +                // concat works with string and char literals, so remove any quotes.
 +                // It also works with integer, float and boolean literals, so just use the rest
 +                // as-is.
 +                if let Some(c) = unquote_char(it) {
 +                    text.push(c);
 +                } else {
 +                    let component = unquote_str(it).unwrap_or_else(|| it.text.to_string());
 +                    text.push_str(&component);
 +                }
 +            }
 +            // handle boolean literals
 +            tt::TokenTree::Leaf(tt::Leaf::Ident(id))
 +                if i % 2 == 0 && (id.text == "true" || id.text == "false") =>
 +            {
 +                text.push_str(id.text.as_str());
 +            }
 +            tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
 +            _ => {
 +                err.get_or_insert(mbe::ExpandError::UnexpectedToken.into());
 +            }
 +        }
 +    }
 +    ExpandResult { value: ExpandedEager::new(quote!(#text)), err }
 +}
 +
 +fn concat_bytes_expand(
 +    _db: &dyn AstDatabase,
 +    _arg_id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<ExpandedEager> {
 +    let mut bytes = Vec::new();
 +    let mut err = None;
 +    for (i, t) in tt.token_trees.iter().enumerate() {
 +        match t {
 +            tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
 +                let token = ast::make::tokens::literal(&lit.to_string());
 +                match token.kind() {
 +                    syntax::SyntaxKind::BYTE => bytes.push(token.text().to_string()),
 +                    syntax::SyntaxKind::BYTE_STRING => {
 +                        let components = unquote_byte_string(lit).unwrap_or_else(Vec::new);
 +                        components.into_iter().for_each(|x| bytes.push(x.to_string()));
 +                    }
 +                    _ => {
 +                        err.get_or_insert(mbe::ExpandError::UnexpectedToken.into());
 +                        break;
 +                    }
 +                }
 +            }
 +            tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
 +            tt::TokenTree::Subtree(tree)
 +                if tree.delimiter_kind() == Some(tt::DelimiterKind::Bracket) =>
 +            {
 +                if let Err(e) = concat_bytes_expand_subtree(tree, &mut bytes) {
 +                    err.get_or_insert(e);
 +                    break;
 +                }
 +            }
 +            _ => {
 +                err.get_or_insert(mbe::ExpandError::UnexpectedToken.into());
 +                break;
 +            }
 +        }
 +    }
 +    let ident = tt::Ident { text: bytes.join(", ").into(), id: tt::TokenId::unspecified() };
 +    ExpandResult { value: ExpandedEager::new(quote!([#ident])), err }
 +}
 +
 +fn concat_bytes_expand_subtree(
 +    tree: &tt::Subtree,
 +    bytes: &mut Vec<String>,
 +) -> Result<(), ExpandError> {
 +    for (ti, tt) in tree.token_trees.iter().enumerate() {
 +        match tt {
 +            tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
 +                let lit = ast::make::tokens::literal(&lit.to_string());
 +                match lit.kind() {
 +                    syntax::SyntaxKind::BYTE | syntax::SyntaxKind::INT_NUMBER => {
 +                        bytes.push(lit.text().to_string())
 +                    }
 +                    _ => {
 +                        return Err(mbe::ExpandError::UnexpectedToken.into());
 +                    }
 +                }
 +            }
 +            tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if ti % 2 == 1 && punct.char == ',' => (),
 +            _ => {
 +                return Err(mbe::ExpandError::UnexpectedToken.into());
 +            }
 +        }
 +    }
 +    Ok(())
 +}
 +
 +fn concat_idents_expand(
 +    _db: &dyn AstDatabase,
 +    _arg_id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<ExpandedEager> {
 +    let mut err = None;
 +    let mut ident = String::new();
 +    for (i, t) in tt.token_trees.iter().enumerate() {
 +        match t {
 +            tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => {
 +                ident.push_str(id.text.as_str());
 +            }
 +            tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
 +            _ => {
 +                err.get_or_insert(mbe::ExpandError::UnexpectedToken.into());
 +            }
 +        }
 +    }
 +    let ident = tt::Ident { text: ident.into(), id: tt::TokenId::unspecified() };
 +    ExpandResult { value: ExpandedEager::new(quote!(#ident)), err }
 +}
 +
 +fn relative_file(
 +    db: &dyn AstDatabase,
 +    call_id: MacroCallId,
 +    path_str: &str,
 +    allow_recursion: bool,
 +) -> Result<FileId, ExpandError> {
 +    let call_site = call_id.as_file().original_file(db);
 +    let path = AnchoredPath { anchor: call_site, path: path_str };
 +    let res = db
 +        .resolve_path(path)
 +        .ok_or_else(|| ExpandError::Other(format!("failed to load file `{path_str}`").into()))?;
 +    // Prevent include itself
 +    if res == call_site && !allow_recursion {
 +        Err(ExpandError::Other(format!("recursive inclusion of `{path_str}`").into()))
 +    } else {
 +        Ok(res)
 +    }
 +}
 +
 +fn parse_string(tt: &tt::Subtree) -> Result<String, ExpandError> {
 +    tt.token_trees
 +        .get(0)
 +        .and_then(|tt| match tt {
 +            tt::TokenTree::Leaf(tt::Leaf::Literal(it)) => unquote_str(it),
 +            _ => None,
 +        })
 +        .ok_or(mbe::ExpandError::ConversionError.into())
 +}
 +
 +fn include_expand(
 +    db: &dyn AstDatabase,
 +    arg_id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<ExpandedEager> {
 +    let res = (|| {
 +        let path = parse_string(tt)?;
 +        let file_id = relative_file(db, arg_id, &path, false)?;
 +
 +        let subtree =
 +            parse_to_token_tree(&db.file_text(file_id)).ok_or(mbe::ExpandError::ConversionError)?.0;
 +        Ok((subtree, file_id))
 +    })();
 +
 +    match res {
 +        Ok((subtree, file_id)) => {
 +            ExpandResult::ok(ExpandedEager { subtree, included_file: Some(file_id) })
 +        }
 +        Err(e) => ExpandResult::only_err(e),
 +    }
 +}
 +
 +fn include_bytes_expand(
 +    _db: &dyn AstDatabase,
 +    _arg_id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<ExpandedEager> {
 +    if let Err(e) = parse_string(tt) {
 +        return ExpandResult::only_err(e);
 +    }
 +
 +    // FIXME: actually read the file here if the user asked for macro expansion
 +    let res = tt::Subtree {
 +        delimiter: None,
 +        token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
 +            text: r#"b"""#.into(),
 +            id: tt::TokenId::unspecified(),
 +        }))],
 +    };
 +    ExpandResult::ok(ExpandedEager::new(res))
 +}
 +
 +fn include_str_expand(
 +    db: &dyn AstDatabase,
 +    arg_id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<ExpandedEager> {
 +    let path = match parse_string(tt) {
 +        Ok(it) => it,
 +        Err(e) => return ExpandResult::only_err(e),
 +    };
 +
 +    // FIXME: we're not able to read excluded files (which is most of them because
 +    // it's unusual to `include_str!` a Rust file), but we can return an empty string.
 +    // Ideally, we'd be able to offer a precise expansion if the user asks for macro
 +    // expansion.
 +    let file_id = match relative_file(db, arg_id, &path, true) {
 +        Ok(file_id) => file_id,
 +        Err(_) => {
 +            return ExpandResult::ok(ExpandedEager::new(quote!("")));
 +        }
 +    };
 +
 +    let text = db.file_text(file_id);
 +    let text = &*text;
 +
 +    ExpandResult::ok(ExpandedEager::new(quote!(#text)))
 +}
 +
 +fn get_env_inner(db: &dyn AstDatabase, arg_id: MacroCallId, key: &str) -> Option<String> {
 +    let krate = db.lookup_intern_macro_call(arg_id).krate;
 +    db.crate_graph()[krate].env.get(key)
 +}
 +
 +fn env_expand(
 +    db: &dyn AstDatabase,
 +    arg_id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<ExpandedEager> {
 +    let key = match parse_string(tt) {
 +        Ok(it) => it,
 +        Err(e) => return ExpandResult::only_err(e),
 +    };
 +
 +    let mut err = None;
 +    let s = get_env_inner(db, arg_id, &key).unwrap_or_else(|| {
 +        // The only variable rust-analyzer ever sets is `OUT_DIR`, so only diagnose that to avoid
 +        // unnecessary diagnostics for eg. `CARGO_PKG_NAME`.
 +        if key == "OUT_DIR" {
 +            err = Some(ExpandError::Other(
 +                r#"`OUT_DIR` not set, enable "build scripts" to fix"#.into(),
 +            ));
 +        }
 +
 +        // If the variable is unset, still return a dummy string to help type inference along.
 +        // We cannot use an empty string here, because for
 +        // `include!(concat!(env!("OUT_DIR"), "/foo.rs"))` will become
 +        // `include!("foo.rs"), which might go to infinite loop
 +        "__RA_UNIMPLEMENTED__".to_string()
 +    });
 +    let expanded = quote! { #s };
 +
 +    ExpandResult { value: ExpandedEager::new(expanded), err }
 +}
 +
 +fn option_env_expand(
 +    db: &dyn AstDatabase,
 +    arg_id: MacroCallId,
 +    tt: &tt::Subtree,
 +) -> ExpandResult<ExpandedEager> {
 +    let key = match parse_string(tt) {
 +        Ok(it) => it,
 +        Err(e) => return ExpandResult::only_err(e),
 +    };
 +
 +    let expanded = match get_env_inner(db, arg_id, &key) {
++        None => quote! { #DOLLAR_CRATE::option::Option::None::<&str> },
++        Some(s) => quote! { #DOLLAR_CRATE::option::Some(#s) },
 +    };
 +
 +    ExpandResult::ok(ExpandedEager::new(expanded))
 +}
index bc97ee15c7d3030be56a04047cbace837f8261a6,0000000000000000000000000000000000000000..87e4db03984ab9dbecf555e67e36046b7c7da5c3
mode 100644,000000..100644
--- /dev/null
@@@ -1,513 -1,0 +1,521 @@@
-     let range = rev_tmap.first_range_by_token(token_id, token_to_map.kind())?;
-     let token = node.syntax_node().covering_element(range).into_token()?;
 +//! 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 syntax_node = node.syntax_node();
++    let token = rev_tmap
++        .ranges_by_token(token_id, token_to_map.kind())
++        .filter_map(|range| syntax_node.covering_element(range).into_token())
++        .min_by_key(|t| {
++            // prefer tokens of the same kind and text
++            // Note the inversion of the score here, as we want to prefer the first token in case
++            // of all tokens having the same score
++            (t.kind() != token_to_map.kind()) as u8 + (t.text() != token_to_map.text()) as u8
++        })?;
 +    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 d7586d129b768b1e639b915df81f51aa4a5c89b5,0000000000000000000000000000000000000000..68413df420c7d7053c1f707f31fb5cc21d7affa0
mode 100644,000000..100644
--- /dev/null
@@@ -1,277 -1,0 +1,278 @@@
 +//! 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) => {};
++    (core::ops::FromResidual) => {};
 +    ($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 2679a1c3602671c35fcae81ba8f9fdef4eb90042,0000000000000000000000000000000000000000..8a735b965ab8460a49003399a12b25e13cb9830b
mode 100644,000000..100644
--- /dev/null
@@@ -1,447 -1,0 +1,449 @@@
 +//! See [`Name`].
 +
 +use std::fmt;
 +
 +use syntax::{ast, SmolStr, SyntaxKind};
 +
 +/// `Name` is a wrapper around string, which is used in hir for both references
 +/// and declarations. In theory, names should also carry hygiene info, but we are
 +/// not there yet!
 +///
 +/// Note that `Name` holds and prints escaped name i.e. prefixed with "r#" when it
 +/// is a raw identifier. Use [`unescaped()`][Name::unescaped] when you need the
 +/// name without "r#".
 +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub struct Name(Repr);
 +
 +/// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
 +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub struct UnescapedName<'a>(&'a Name);
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +enum Repr {
 +    Text(SmolStr),
 +    TupleField(usize),
 +}
 +
 +impl fmt::Display for Name {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match &self.0 {
 +            Repr::Text(text) => fmt::Display::fmt(&text, f),
 +            Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
 +        }
 +    }
 +}
 +
 +fn is_raw_identifier(name: &str) -> bool {
 +    let is_keyword = SyntaxKind::from_keyword(name).is_some();
 +    is_keyword && !matches!(name, "self" | "crate" | "super" | "Self")
 +}
 +
 +impl<'a> fmt::Display for UnescapedName<'a> {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match &self.0 .0 {
 +            Repr::Text(text) => {
 +                let text = text.strip_prefix("r#").unwrap_or(text);
 +                fmt::Display::fmt(&text, f)
 +            }
 +            Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
 +        }
 +    }
 +}
 +
 +impl<'a> UnescapedName<'a> {
 +    /// Returns the textual representation of this name as a [`SmolStr`]. Prefer using this over
 +    /// [`ToString::to_string`] if possible as this conversion is cheaper in the general case.
 +    pub fn to_smol_str(&self) -> SmolStr {
 +        match &self.0 .0 {
 +            Repr::Text(it) => {
 +                if let Some(stripped) = it.strip_prefix("r#") {
 +                    SmolStr::new(stripped)
 +                } else {
 +                    it.clone()
 +                }
 +            }
 +            Repr::TupleField(it) => SmolStr::new(&it.to_string()),
 +        }
 +    }
 +}
 +
 +impl Name {
 +    /// Note: this is private to make creating name from random string hard.
 +    /// Hopefully, this should allow us to integrate hygiene cleaner in the
 +    /// future, and to switch to interned representation of names.
 +    const fn new_text(text: SmolStr) -> Name {
 +        Name(Repr::Text(text))
 +    }
 +
 +    pub fn new_tuple_field(idx: usize) -> Name {
 +        Name(Repr::TupleField(idx))
 +    }
 +
 +    pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
 +        Self::new_text(lt.text().into())
 +    }
 +
 +    /// Shortcut to create inline plain text name
 +    const fn new_inline(text: &str) -> Name {
 +        Name::new_text(SmolStr::new_inline(text))
 +    }
 +
 +    /// Resolve a name from the text of token.
 +    fn resolve(raw_text: &str) -> Name {
 +        match raw_text.strip_prefix("r#") {
 +            // When `raw_text` starts with "r#" but the name does not coincide with any
 +            // keyword, we never need the prefix so we strip it.
 +            Some(text) if !is_raw_identifier(text) => Name::new_text(SmolStr::new(text)),
 +            // Keywords (in the current edition) *can* be used as a name in earlier editions of
 +            // Rust, e.g. "try" in Rust 2015. Even in such cases, we keep track of them in their
 +            // escaped form.
 +            None if is_raw_identifier(raw_text) => {
 +                Name::new_text(SmolStr::from_iter(["r#", raw_text]))
 +            }
 +            _ => Name::new_text(raw_text.into()),
 +        }
 +    }
 +
 +    /// A fake name for things missing in the source code.
 +    ///
 +    /// For example, `impl Foo for {}` should be treated as a trait impl for a
 +    /// type with a missing name. Similarly, `struct S { : u32 }` should have a
 +    /// single field with a missing name.
 +    ///
 +    /// Ideally, we want a `gensym` semantics for missing names -- each missing
 +    /// name is equal only to itself. It's not clear how to implement this in
 +    /// salsa though, so we punt on that bit for a moment.
 +    pub const fn missing() -> Name {
 +        Name::new_inline("[missing name]")
 +    }
 +
 +    /// Returns the tuple index this name represents if it is a tuple field.
 +    pub fn as_tuple_index(&self) -> Option<usize> {
 +        match self.0 {
 +            Repr::TupleField(idx) => Some(idx),
 +            _ => None,
 +        }
 +    }
 +
 +    /// Returns the text this name represents if it isn't a tuple field.
 +    pub fn as_text(&self) -> Option<SmolStr> {
 +        match &self.0 {
 +            Repr::Text(it) => Some(it.clone()),
 +            _ => None,
 +        }
 +    }
 +
 +    /// Returns the textual representation of this name as a [`SmolStr`].
 +    /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in
 +    /// the general case.
 +    pub fn to_smol_str(&self) -> SmolStr {
 +        match &self.0 {
 +            Repr::Text(it) => it.clone(),
 +            Repr::TupleField(it) => SmolStr::new(&it.to_string()),
 +        }
 +    }
 +
 +    pub fn unescaped(&self) -> UnescapedName<'_> {
 +        UnescapedName(self)
 +    }
 +
 +    pub fn is_escaped(&self) -> bool {
 +        match &self.0 {
 +            Repr::Text(it) => it.starts_with("r#"),
 +            Repr::TupleField(_) => false,
 +        }
 +    }
 +}
 +
 +pub trait AsName {
 +    fn as_name(&self) -> Name;
 +}
 +
 +impl AsName for ast::NameRef {
 +    fn as_name(&self) -> Name {
 +        match self.as_tuple_field() {
 +            Some(idx) => Name::new_tuple_field(idx),
 +            None => Name::resolve(&self.text()),
 +        }
 +    }
 +}
 +
 +impl AsName for ast::Name {
 +    fn as_name(&self) -> Name {
 +        Name::resolve(&self.text())
 +    }
 +}
 +
 +impl AsName for ast::NameOrNameRef {
 +    fn as_name(&self) -> Name {
 +        match self {
 +            ast::NameOrNameRef::Name(it) => it.as_name(),
 +            ast::NameOrNameRef::NameRef(it) => it.as_name(),
 +        }
 +    }
 +}
 +
 +impl AsName for tt::Ident {
 +    fn as_name(&self) -> Name {
 +        Name::resolve(&self.text)
 +    }
 +}
 +
 +impl AsName for ast::FieldKind {
 +    fn as_name(&self) -> Name {
 +        match self {
 +            ast::FieldKind::Name(nr) => nr.as_name(),
 +            ast::FieldKind::Index(idx) => {
 +                let idx = idx.text().parse::<usize>().unwrap_or(0);
 +                Name::new_tuple_field(idx)
 +            }
 +        }
 +    }
 +}
 +
 +impl AsName for base_db::Dependency {
 +    fn as_name(&self) -> Name {
 +        Name::new_text(SmolStr::new(&*self.name))
 +    }
 +}
 +
 +pub mod known {
 +    macro_rules! known_names {
 +        ($($ident:ident),* $(,)?) => {
 +            $(
 +                #[allow(bad_style)]
 +                pub const $ident: super::Name =
 +                    super::Name::new_inline(stringify!($ident));
 +            )*
 +        };
 +    }
 +
 +    known_names!(
 +        // Primitives
 +        isize,
 +        i8,
 +        i16,
 +        i32,
 +        i64,
 +        i128,
 +        usize,
 +        u8,
 +        u16,
 +        u32,
 +        u64,
 +        u128,
 +        f32,
 +        f64,
 +        bool,
 +        char,
 +        str,
 +        // Special names
 +        macro_rules,
 +        doc,
 +        cfg,
 +        cfg_attr,
 +        register_attr,
 +        register_tool,
 +        // Components of known path (value or mod name)
 +        std,
 +        core,
 +        alloc,
 +        iter,
 +        ops,
 +        future,
 +        result,
 +        boxed,
 +        option,
 +        prelude,
 +        rust_2015,
 +        rust_2018,
 +        rust_2021,
 +        v1,
 +        // Components of known path (type name)
 +        Iterator,
 +        IntoIterator,
 +        Item,
 +        IntoIter,
 +        Try,
 +        Ok,
 +        Future,
 +        IntoFuture,
 +        Result,
 +        Option,
 +        Output,
 +        Target,
 +        Box,
 +        RangeFrom,
 +        RangeFull,
 +        RangeInclusive,
 +        RangeToInclusive,
 +        RangeTo,
 +        Range,
++        Residual,
++        FromResidual,
 +        Neg,
 +        Not,
 +        None,
 +        Index,
 +        // Components of known path (function name)
 +        filter_map,
 +        next,
 +        iter_mut,
 +        len,
 +        is_empty,
 +        new,
 +        // Builtin macros
 +        asm,
 +        assert,
 +        column,
 +        compile_error,
 +        concat_idents,
 +        concat_bytes,
 +        concat,
 +        const_format_args,
 +        core_panic,
 +        env,
 +        file,
 +        format_args_nl,
 +        format_args,
 +        global_asm,
 +        include_bytes,
 +        include_str,
 +        include,
 +        line,
 +        llvm_asm,
 +        log_syntax,
 +        module_path,
 +        option_env,
 +        std_panic,
 +        stringify,
 +        trace_macros,
 +        unreachable,
 +        // Builtin derives
 +        Copy,
 +        Clone,
 +        Default,
 +        Debug,
 +        Hash,
 +        Ord,
 +        PartialOrd,
 +        Eq,
 +        PartialEq,
 +        // Builtin attributes
 +        bench,
 +        cfg_accessible,
 +        cfg_eval,
 +        crate_type,
 +        derive,
 +        global_allocator,
 +        test,
 +        test_case,
 +        recursion_limit,
 +        feature,
 +        // Safe intrinsics
 +        abort,
 +        add_with_overflow,
 +        black_box,
 +        bitreverse,
 +        bswap,
 +        caller_location,
 +        ctlz,
 +        ctpop,
 +        cttz,
 +        discriminant_value,
 +        forget,
 +        likely,
 +        maxnumf32,
 +        maxnumf64,
 +        min_align_of_val,
 +        min_align_of,
 +        minnumf32,
 +        minnumf64,
 +        mul_with_overflow,
 +        needs_drop,
 +        ptr_guaranteed_eq,
 +        ptr_guaranteed_ne,
 +        rotate_left,
 +        rotate_right,
 +        rustc_peek,
 +        saturating_add,
 +        saturating_sub,
 +        size_of_val,
 +        size_of,
 +        sub_with_overflow,
 +        type_id,
 +        type_name,
 +        unlikely,
 +        variant_count,
 +        wrapping_add,
 +        wrapping_mul,
 +        wrapping_sub,
 +        // known methods of lang items
 +        eq,
 +        ne,
 +        ge,
 +        gt,
 +        le,
 +        lt,
 +        // lang items
 +        add_assign,
 +        add,
 +        bitand_assign,
 +        bitand,
 +        bitor_assign,
 +        bitor,
 +        bitxor_assign,
 +        bitxor,
 +        branch,
 +        deref_mut,
 +        deref,
 +        div_assign,
 +        div,
 +        fn_mut,
 +        fn_once,
 +        future_trait,
 +        index,
 +        index_mut,
 +        into_future,
 +        mul_assign,
 +        mul,
 +        neg,
 +        not,
 +        owned_box,
 +        partial_ord,
 +        poll,
 +        r#fn,
 +        rem_assign,
 +        rem,
 +        shl_assign,
 +        shl,
 +        shr_assign,
 +        shr,
 +        sub_assign,
 +        sub,
 +    );
 +
 +    // self/Self cannot be used as an identifier
 +    pub const SELF_PARAM: super::Name = super::Name::new_inline("self");
 +    pub const SELF_TYPE: super::Name = super::Name::new_inline("Self");
 +
 +    pub const STATIC_LIFETIME: super::Name = super::Name::new_inline("'static");
 +
 +    #[macro_export]
 +    macro_rules! name {
 +        (self) => {
 +            $crate::name::known::SELF_PARAM
 +        };
 +        (Self) => {
 +            $crate::name::known::SELF_TYPE
 +        };
 +        ('static) => {
 +            $crate::name::known::STATIC_LIFETIME
 +        };
 +        ($ident:ident) => {
 +            $crate::name::known::$ident
 +        };
 +    }
 +}
 +
 +pub use crate::name;
index 7f143f396c765055c0a9b54702129d163866194d,0000000000000000000000000000000000000000..ed13275bab8fecd36b516048b8c8d17188123805
mode 100644,000000..100644
--- /dev/null
@@@ -1,44 -1,0 +1,45 @@@
- itertools = "0.10.3"
 +[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"
- smallvec = "1.9.0"
++itertools = "0.10.5"
 +arrayvec = "0.7.2"
- chalk-solve = { version = "0.84.0", default-features = false }
- chalk-ir = "0.84.0"
- chalk-recursive = { version = "0.84.0", default-features = false }
++smallvec = "1.10.0"
 +ena = "0.14.0"
 +tracing = "0.1.35"
 +rustc-hash = "1.1.0"
 +scoped-tls = "1.0.0"
- once_cell = "1.12.0"
++chalk-solve = { version = "0.86.0", default-features = false }
++chalk-ir = "0.86.0"
++chalk-recursive = { version = "0.86.0", default-features = false }
++chalk-derive = "0.86.0"
 +la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
- tracing-subscriber = { version = "0.3.14", default-features = false, features = [
++once_cell = "1.15.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.16", default-features = false, features = [
 +    "env-filter",
 +    "registry",
 +] }
 +tracing-tree = "0.2.1"
index 3f3f8f7d0f2a2ac9d82b02fdb0439dd978713f0c,0000000000000000000000000000000000000000..43c3451cab37bb865c74e65b0cf39027f0354892
mode 100644,000000..100644
--- /dev/null
@@@ -1,850 -1,0 +1,850 @@@
-             if projection_ty.self_type_parameter(Interner) != self_ty_shifted_in {
 +//! The implementation of `RustIrDatabase` for Chalk, which provides information
 +//! about the code that Chalk needs.
 +use std::sync::Arc;
 +
 +use cov_mark::hit;
 +use syntax::SmolStr;
 +use tracing::debug;
 +
 +use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds};
 +use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
 +
 +use base_db::CrateId;
 +use hir_def::{
 +    expr::Movability,
 +    lang_item::{lang_attr, LangItemTarget},
 +    AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId,
 +};
 +use hir_expand::name::name;
 +
 +use crate::{
 +    db::HirDatabase,
 +    display::HirDisplay,
 +    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_binders,
 +    make_single_type_binders,
 +    mapping::{from_chalk, ToChalk, TypeAliasAsValue},
 +    method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
 +    to_assoc_type_id, to_chalk_trait_id,
 +    traits::ChalkContext,
 +    utils::generics,
 +    wrap_empty_binders, AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId,
 +    Interner, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef,
 +    TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause,
 +};
 +
 +pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>;
 +pub(crate) type TraitDatum = chalk_solve::rust_ir::TraitDatum<Interner>;
 +pub(crate) type StructDatum = chalk_solve::rust_ir::AdtDatum<Interner>;
 +pub(crate) type ImplDatum = chalk_solve::rust_ir::ImplDatum<Interner>;
 +pub(crate) type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>;
 +
 +pub(crate) type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
 +pub(crate) type TraitId = chalk_ir::TraitId<Interner>;
 +pub(crate) type AdtId = chalk_ir::AdtId<Interner>;
 +pub(crate) type ImplId = chalk_ir::ImplId<Interner>;
 +pub(crate) type AssociatedTyValueId = chalk_solve::rust_ir::AssociatedTyValueId<Interner>;
 +pub(crate) type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue<Interner>;
 +pub(crate) type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>;
 +pub(crate) type Variances = chalk_ir::Variances<Interner>;
 +
 +impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
 +    fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> {
 +        self.db.associated_ty_data(id)
 +    }
 +    fn trait_datum(&self, trait_id: TraitId) -> Arc<TraitDatum> {
 +        self.db.trait_datum(self.krate, trait_id)
 +    }
 +    fn adt_datum(&self, struct_id: AdtId) -> Arc<StructDatum> {
 +        self.db.struct_datum(self.krate, struct_id)
 +    }
 +    fn adt_repr(&self, _struct_id: AdtId) -> Arc<rust_ir::AdtRepr<Interner>> {
 +        // FIXME: keep track of these
 +        Arc::new(rust_ir::AdtRepr { c: false, packed: false, int: None })
 +    }
 +    fn discriminant_type(&self, _ty: chalk_ir::Ty<Interner>) -> chalk_ir::Ty<Interner> {
 +        // FIXME: keep track of this
 +        chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::U32)).intern(Interner)
 +    }
 +    fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> {
 +        self.db.impl_datum(self.krate, impl_id)
 +    }
 +
 +    fn fn_def_datum(
 +        &self,
 +        fn_def_id: chalk_ir::FnDefId<Interner>,
 +    ) -> Arc<rust_ir::FnDefDatum<Interner>> {
 +        self.db.fn_def_datum(self.krate, fn_def_id)
 +    }
 +
 +    fn impls_for_trait(
 +        &self,
 +        trait_id: TraitId,
 +        parameters: &[chalk_ir::GenericArg<Interner>],
 +        binders: &CanonicalVarKinds<Interner>,
 +    ) -> Vec<ImplId> {
 +        debug!("impls_for_trait {:?}", trait_id);
 +        let trait_: hir_def::TraitId = from_chalk_trait_id(trait_id);
 +
 +        let ty: Ty = parameters[0].assert_ty_ref(Interner).clone();
 +
 +        fn binder_kind(
 +            ty: &Ty,
 +            binders: &CanonicalVarKinds<Interner>,
 +        ) -> Option<chalk_ir::TyVariableKind> {
 +            if let TyKind::BoundVar(bv) = ty.kind(Interner) {
 +                let binders = binders.as_slice(Interner);
 +                if bv.debruijn == DebruijnIndex::INNERMOST {
 +                    if let chalk_ir::VariableKind::Ty(tk) = binders[bv.index].kind {
 +                        return Some(tk);
 +                    }
 +                }
 +            }
 +            None
 +        }
 +
 +        let self_ty_fp = TyFingerprint::for_trait_impl(&ty);
 +        let fps: &[TyFingerprint] = match binder_kind(&ty, binders) {
 +            Some(chalk_ir::TyVariableKind::Integer) => &ALL_INT_FPS,
 +            Some(chalk_ir::TyVariableKind::Float) => &ALL_FLOAT_FPS,
 +            _ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]),
 +        };
 +
 +        fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option<Arc<TraitImpls>> {
 +            let block = module.containing_block()?;
 +            hit!(block_local_impls);
 +            db.trait_impls_in_block(block)
 +        }
 +
 +        // Note: Since we're using impls_for_trait, only impls where the trait
 +        // can be resolved should ever reach Chalk. impl_datum relies on that
 +        // and will panic if the trait can't be resolved.
 +        let in_deps = self.db.trait_impls_in_deps(self.krate);
 +        let in_self = self.db.trait_impls_in_crate(self.krate);
 +        let trait_module = trait_.module(self.db.upcast());
 +        let type_module = match self_ty_fp {
 +            Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())),
 +            Some(TyFingerprint::ForeignType(type_id)) => {
 +                Some(from_foreign_def_id(type_id).module(self.db.upcast()))
 +            }
 +            Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())),
 +            _ => None,
 +        };
 +        let impl_maps = [
 +            Some(in_deps),
 +            Some(in_self),
 +            local_impls(self.db, trait_module),
 +            type_module.and_then(|m| local_impls(self.db, m)),
 +        ];
 +
 +        let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
 +
 +        let result: Vec<_> = if fps.is_empty() {
 +            debug!("Unrestricted search for {:?} impls...", trait_);
 +            impl_maps
 +                .iter()
 +                .filter_map(|o| o.as_ref())
 +                .flat_map(|impls| impls.for_trait(trait_).map(id_to_chalk))
 +                .collect()
 +        } else {
 +            impl_maps
 +                .iter()
 +                .filter_map(|o| o.as_ref())
 +                .flat_map(|impls| {
 +                    fps.iter().flat_map(move |fp| {
 +                        impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
 +                    })
 +                })
 +                .collect()
 +        };
 +
 +        debug!("impls_for_trait returned {} impls", result.len());
 +        result
 +    }
 +    fn impl_provided_for(&self, auto_trait_id: TraitId, kind: &chalk_ir::TyKind<Interner>) -> bool {
 +        debug!("impl_provided_for {:?}, {:?}", auto_trait_id, kind);
 +        false // FIXME
 +    }
 +    fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc<AssociatedTyValue> {
 +        self.db.associated_ty_value(self.krate, id)
 +    }
 +
 +    fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<Interner>> {
 +        vec![]
 +    }
 +    fn local_impls_to_coherence_check(&self, _trait_id: TraitId) -> Vec<ImplId> {
 +        // We don't do coherence checking (yet)
 +        unimplemented!()
 +    }
 +    fn interner(&self) -> Interner {
 +        Interner
 +    }
 +    fn well_known_trait_id(
 +        &self,
 +        well_known_trait: rust_ir::WellKnownTrait,
 +    ) -> Option<chalk_ir::TraitId<Interner>> {
 +        let lang_attr = lang_attr_from_well_known_trait(well_known_trait);
 +        let trait_ = match self.db.lang_item(self.krate, lang_attr.into()) {
 +            Some(LangItemTarget::TraitId(trait_)) => trait_,
 +            _ => return None,
 +        };
 +        Some(to_chalk_trait_id(trait_))
 +    }
 +
 +    fn program_clauses_for_env(
 +        &self,
 +        environment: &chalk_ir::Environment<Interner>,
 +    ) -> chalk_ir::ProgramClauses<Interner> {
 +        self.db.program_clauses_for_chalk_env(self.krate, environment.clone())
 +    }
 +
 +    fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> {
 +        let full_id = self.db.lookup_intern_impl_trait_id(id.into());
 +        let bound = match full_id {
 +            crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
 +                let datas = self
 +                    .db
 +                    .return_type_impl_traits(func)
 +                    .expect("impl trait id without impl traits");
 +                let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders();
 +                let data = &datas.impl_traits[idx as usize];
 +                let bound = OpaqueTyDatumBound {
 +                    bounds: make_single_type_binders(data.bounds.skip_binders().to_vec()),
 +                    where_clauses: chalk_ir::Binders::empty(Interner, vec![]),
 +                };
 +                chalk_ir::Binders::new(binders, bound)
 +            }
 +            crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => {
 +                if let Some((future_trait, future_output)) = self
 +                    .db
 +                    .lang_item(self.krate, SmolStr::new_inline("future_trait"))
 +                    .and_then(|item| item.as_trait())
 +                    .and_then(|trait_| {
 +                        let alias =
 +                            self.db.trait_data(trait_).associated_type_by_name(&name![Output])?;
 +                        Some((trait_, alias))
 +                    })
 +                {
 +                    // Making up Symbol’s value as variable is void: AsyncBlock<T>:
 +                    //
 +                    // |--------------------OpaqueTyDatum-------------------|
 +                    //        |-------------OpaqueTyDatumBound--------------|
 +                    // for<T> <Self> [Future<Self>, Future::Output<Self> = T]
 +                    //     ^1  ^0            ^0                    ^0      ^1
 +                    let impl_bound = WhereClause::Implemented(TraitRef {
 +                        trait_id: to_chalk_trait_id(future_trait),
 +                        // Self type as the first parameter.
 +                        substitution: Substitution::from1(
 +                            Interner,
 +                            TyKind::BoundVar(BoundVar {
 +                                debruijn: DebruijnIndex::INNERMOST,
 +                                index: 0,
 +                            })
 +                            .intern(Interner),
 +                        ),
 +                    });
 +                    let mut binder = vec![];
 +                    binder.push(crate::wrap_empty_binders(impl_bound));
 +                    let sized_trait = self
 +                        .db
 +                        .lang_item(self.krate, SmolStr::new_inline("sized"))
 +                        .and_then(|item| item.as_trait());
 +                    if let Some(sized_trait_) = sized_trait {
 +                        let sized_bound = WhereClause::Implemented(TraitRef {
 +                            trait_id: to_chalk_trait_id(sized_trait_),
 +                            // Self type as the first parameter.
 +                            substitution: Substitution::from1(
 +                                Interner,
 +                                TyKind::BoundVar(BoundVar {
 +                                    debruijn: DebruijnIndex::INNERMOST,
 +                                    index: 0,
 +                                })
 +                                .intern(Interner),
 +                            ),
 +                        });
 +                        binder.push(crate::wrap_empty_binders(sized_bound));
 +                    }
 +                    let proj_bound = WhereClause::AliasEq(AliasEq {
 +                        alias: AliasTy::Projection(ProjectionTy {
 +                            associated_ty_id: to_assoc_type_id(future_output),
 +                            // Self type as the first parameter.
 +                            substitution: Substitution::from1(
 +                                Interner,
 +                                TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
 +                                    .intern(Interner),
 +                            ),
 +                        }),
 +                        // The parameter of the opaque type.
 +                        ty: TyKind::BoundVar(BoundVar { debruijn: DebruijnIndex::ONE, index: 0 })
 +                            .intern(Interner),
 +                    });
 +                    binder.push(crate::wrap_empty_binders(proj_bound));
 +                    let bound = OpaqueTyDatumBound {
 +                        bounds: make_single_type_binders(binder),
 +                        where_clauses: chalk_ir::Binders::empty(Interner, vec![]),
 +                    };
 +                    // The opaque type has 1 parameter.
 +                    make_single_type_binders(bound)
 +                } else {
 +                    // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback.
 +                    let bound = OpaqueTyDatumBound {
 +                        bounds: chalk_ir::Binders::empty(Interner, vec![]),
 +                        where_clauses: chalk_ir::Binders::empty(Interner, vec![]),
 +                    };
 +                    // The opaque type has 1 parameter.
 +                    make_single_type_binders(bound)
 +                }
 +            }
 +        };
 +
 +        Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound })
 +    }
 +
 +    fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> {
 +        // FIXME: actually provide the hidden type; it is relevant for auto traits
 +        TyKind::Error.intern(Interner)
 +    }
 +
 +    fn is_object_safe(&self, _trait_id: chalk_ir::TraitId<Interner>) -> bool {
 +        // FIXME: implement actual object safety
 +        true
 +    }
 +
 +    fn closure_kind(
 +        &self,
 +        _closure_id: chalk_ir::ClosureId<Interner>,
 +        _substs: &chalk_ir::Substitution<Interner>,
 +    ) -> rust_ir::ClosureKind {
 +        // Fn is the closure kind that implements all three traits
 +        rust_ir::ClosureKind::Fn
 +    }
 +    fn closure_inputs_and_output(
 +        &self,
 +        _closure_id: chalk_ir::ClosureId<Interner>,
 +        substs: &chalk_ir::Substitution<Interner>,
 +    ) -> chalk_ir::Binders<rust_ir::FnDefInputsAndOutputDatum<Interner>> {
 +        let sig_ty = substs.at(Interner, 0).assert_ty_ref(Interner).clone();
 +        let sig = &sig_ty.callable_sig(self.db).expect("first closure param should be fn ptr");
 +        let io = rust_ir::FnDefInputsAndOutputDatum {
 +            argument_types: sig.params().to_vec(),
 +            return_type: sig.ret().clone(),
 +        };
 +        chalk_ir::Binders::empty(Interner, io.shifted_in(Interner))
 +    }
 +    fn closure_upvars(
 +        &self,
 +        _closure_id: chalk_ir::ClosureId<Interner>,
 +        _substs: &chalk_ir::Substitution<Interner>,
 +    ) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> {
 +        let ty = TyBuilder::unit();
 +        chalk_ir::Binders::empty(Interner, ty)
 +    }
 +    fn closure_fn_substitution(
 +        &self,
 +        _closure_id: chalk_ir::ClosureId<Interner>,
 +        _substs: &chalk_ir::Substitution<Interner>,
 +    ) -> chalk_ir::Substitution<Interner> {
 +        Substitution::empty(Interner)
 +    }
 +
 +    fn trait_name(&self, trait_id: chalk_ir::TraitId<Interner>) -> String {
 +        let id = from_chalk_trait_id(trait_id);
 +        self.db.trait_data(id).name.to_string()
 +    }
 +    fn adt_name(&self, chalk_ir::AdtId(adt_id): AdtId) -> String {
 +        match adt_id {
 +            hir_def::AdtId::StructId(id) => self.db.struct_data(id).name.to_string(),
 +            hir_def::AdtId::EnumId(id) => self.db.enum_data(id).name.to_string(),
 +            hir_def::AdtId::UnionId(id) => self.db.union_data(id).name.to_string(),
 +        }
 +    }
 +    fn adt_size_align(&self, _id: chalk_ir::AdtId<Interner>) -> Arc<rust_ir::AdtSizeAlign> {
 +        // FIXME
 +        Arc::new(rust_ir::AdtSizeAlign::from_one_zst(false))
 +    }
 +    fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId<Interner>) -> String {
 +        let id = self.db.associated_ty_data(assoc_ty_id).name;
 +        self.db.type_alias_data(id).name.to_string()
 +    }
 +    fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId<Interner>) -> String {
 +        format!("Opaque_{}", opaque_ty_id.0)
 +    }
 +    fn fn_def_name(&self, fn_def_id: chalk_ir::FnDefId<Interner>) -> String {
 +        format!("fn_{}", fn_def_id.0)
 +    }
 +    fn generator_datum(
 +        &self,
 +        id: chalk_ir::GeneratorId<Interner>,
 +    ) -> std::sync::Arc<chalk_solve::rust_ir::GeneratorDatum<Interner>> {
 +        let (parent, expr) = self.db.lookup_intern_generator(id.into());
 +
 +        // We fill substitution with unknown type, because we only need to know whether the generic
 +        // params are types or consts to build `Binders` and those being filled up are for
 +        // `resume_type`, `yield_type`, and `return_type` of the generator in question.
 +        let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
 +
 +        let input_output = rust_ir::GeneratorInputOutputDatum {
 +            resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
 +                .intern(Interner),
 +            yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 1))
 +                .intern(Interner),
 +            return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 2))
 +                .intern(Interner),
 +            // FIXME: calculate upvars
 +            upvars: vec![],
 +        };
 +
 +        let it = subst
 +            .iter(Interner)
 +            .map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone()));
 +        let input_output = crate::make_type_and_const_binders(it, input_output);
 +
 +        let movability = match self.db.body(parent)[expr] {
 +            hir_def::expr::Expr::Closure {
 +                closure_kind: hir_def::expr::ClosureKind::Generator(movability),
 +                ..
 +            } => movability,
 +            _ => unreachable!("non generator expression interned as generator"),
 +        };
 +        let movability = match movability {
 +            Movability::Static => rust_ir::Movability::Static,
 +            Movability::Movable => rust_ir::Movability::Movable,
 +        };
 +
 +        Arc::new(rust_ir::GeneratorDatum { movability, input_output })
 +    }
 +    fn generator_witness_datum(
 +        &self,
 +        id: chalk_ir::GeneratorId<Interner>,
 +    ) -> std::sync::Arc<chalk_solve::rust_ir::GeneratorWitnessDatum<Interner>> {
 +        // FIXME: calculate inner types
 +        let inner_types =
 +            rust_ir::GeneratorWitnessExistential { types: wrap_empty_binders(vec![]) };
 +
 +        let (parent, _) = self.db.lookup_intern_generator(id.into());
 +        // See the comment in `generator_datum()` for unknown types.
 +        let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
 +        let it = subst
 +            .iter(Interner)
 +            .map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone()));
 +        let inner_types = crate::make_type_and_const_binders(it, inner_types);
 +
 +        Arc::new(rust_ir::GeneratorWitnessDatum { inner_types })
 +    }
 +
 +    fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> {
 +        &self.db
 +    }
 +}
 +
 +impl<'a> chalk_ir::UnificationDatabase<Interner> for &'a dyn HirDatabase {
 +    fn fn_def_variance(
 +        &self,
 +        fn_def_id: chalk_ir::FnDefId<Interner>,
 +    ) -> chalk_ir::Variances<Interner> {
 +        HirDatabase::fn_def_variance(*self, fn_def_id)
 +    }
 +
 +    fn adt_variance(&self, adt_id: chalk_ir::AdtId<Interner>) -> chalk_ir::Variances<Interner> {
 +        HirDatabase::adt_variance(*self, adt_id)
 +    }
 +}
 +
 +pub(crate) fn program_clauses_for_chalk_env_query(
 +    db: &dyn HirDatabase,
 +    krate: CrateId,
 +    environment: chalk_ir::Environment<Interner>,
 +) -> chalk_ir::ProgramClauses<Interner> {
 +    chalk_solve::program_clauses_for_env(&ChalkContext { db, krate }, &environment)
 +}
 +
 +pub(crate) fn associated_ty_data_query(
 +    db: &dyn HirDatabase,
 +    id: AssocTypeId,
 +) -> Arc<AssociatedTyDatum> {
 +    debug!("associated_ty_data {:?}", id);
 +    let type_alias: TypeAliasId = from_assoc_type_id(id);
 +    let trait_ = match type_alias.lookup(db.upcast()).container {
 +        ItemContainerId::TraitId(t) => t,
 +        _ => panic!("associated type not in trait"),
 +    };
 +
 +    // Lower bounds -- we could/should maybe move this to a separate query in `lower`
 +    let type_alias_data = db.type_alias_data(type_alias);
 +    let generic_params = generics(db.upcast(), type_alias.into());
 +    // let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
 +    let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
 +    let ctx = crate::TyLoweringContext::new(db, &resolver)
 +        .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
 +
 +    let trait_subst = TyBuilder::subst_for_def(db, trait_, None)
 +        .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self())
 +        .build();
 +    let pro_ty = TyBuilder::assoc_type_projection(db, type_alias, Some(trait_subst))
 +        .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, 0)
 +        .build();
 +    let self_ty = TyKind::Alias(AliasTy::Projection(pro_ty)).intern(Interner);
 +
 +    let mut bounds: Vec<_> = type_alias_data
 +        .bounds
 +        .iter()
 +        .flat_map(|bound| ctx.lower_type_bound(bound, self_ty.clone(), false))
 +        .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty))
 +        .collect();
 +
 +    if !ctx.unsized_types.borrow().contains(&self_ty) {
 +        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));
 +        let sized_bound = sized_trait.into_iter().map(|sized_trait| {
 +            let trait_bound =
 +                rust_ir::TraitBound { trait_id: sized_trait, args_no_self: Default::default() };
 +            let inline_bound = rust_ir::InlineBound::TraitBound(trait_bound);
 +            chalk_ir::Binders::empty(Interner, inline_bound)
 +        });
 +        bounds.extend(sized_bound);
 +        bounds.shrink_to_fit();
 +    }
 +
 +    // FIXME: Re-enable where clauses on associated types when an upstream chalk bug is fixed.
 +    //        (rust-analyzer#9052)
 +    // let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
 +    let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses: vec![] };
 +    let datum = AssociatedTyDatum {
 +        trait_id: to_chalk_trait_id(trait_),
 +        id,
 +        name: type_alias,
 +        binders: make_binders(db, &generic_params, bound_data),
 +    };
 +    Arc::new(datum)
 +}
 +
 +pub(crate) fn trait_datum_query(
 +    db: &dyn HirDatabase,
 +    krate: CrateId,
 +    trait_id: TraitId,
 +) -> Arc<TraitDatum> {
 +    debug!("trait_datum {:?}", trait_id);
 +    let trait_ = from_chalk_trait_id(trait_id);
 +    let trait_data = db.trait_data(trait_);
 +    debug!("trait {:?} = {:?}", trait_id, trait_data.name);
 +    let generic_params = generics(db.upcast(), trait_.into());
 +    let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +    let flags = rust_ir::TraitFlags {
 +        auto: trait_data.is_auto,
 +        upstream: trait_.lookup(db.upcast()).container.krate() != krate,
 +        non_enumerable: true,
 +        coinductive: false, // only relevant for Chalk testing
 +        // FIXME: set these flags correctly
 +        marker: false,
 +        fundamental: false,
 +    };
 +    let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars);
 +    let associated_ty_ids = trait_data.associated_types().map(to_assoc_type_id).collect();
 +    let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses };
 +    let well_known =
 +        lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name));
 +    let trait_datum = TraitDatum {
 +        id: trait_id,
 +        binders: make_binders(db, &generic_params, trait_datum_bound),
 +        flags,
 +        associated_ty_ids,
 +        well_known,
 +    };
 +    Arc::new(trait_datum)
 +}
 +
 +fn well_known_trait_from_lang_attr(name: &str) -> Option<WellKnownTrait> {
 +    Some(match name {
 +        "clone" => WellKnownTrait::Clone,
 +        "coerce_unsized" => WellKnownTrait::CoerceUnsized,
 +        "copy" => WellKnownTrait::Copy,
 +        "discriminant_kind" => WellKnownTrait::DiscriminantKind,
 +        "dispatch_from_dyn" => WellKnownTrait::DispatchFromDyn,
 +        "drop" => WellKnownTrait::Drop,
 +        "fn" => WellKnownTrait::Fn,
 +        "fn_mut" => WellKnownTrait::FnMut,
 +        "fn_once" => WellKnownTrait::FnOnce,
 +        "generator" => WellKnownTrait::Generator,
 +        "sized" => WellKnownTrait::Sized,
 +        "unpin" => WellKnownTrait::Unpin,
 +        "unsize" => WellKnownTrait::Unsize,
 +        _ => return None,
 +    })
 +}
 +
 +fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str {
 +    match attr {
 +        WellKnownTrait::Clone => "clone",
 +        WellKnownTrait::CoerceUnsized => "coerce_unsized",
 +        WellKnownTrait::Copy => "copy",
 +        WellKnownTrait::DiscriminantKind => "discriminant_kind",
 +        WellKnownTrait::DispatchFromDyn => "dispatch_from_dyn",
 +        WellKnownTrait::Drop => "drop",
 +        WellKnownTrait::Fn => "fn",
 +        WellKnownTrait::FnMut => "fn_mut",
 +        WellKnownTrait::FnOnce => "fn_once",
 +        WellKnownTrait::Generator => "generator",
 +        WellKnownTrait::Sized => "sized",
 +        WellKnownTrait::Unpin => "unpin",
 +        WellKnownTrait::Unsize => "unsize",
 +    }
 +}
 +
 +pub(crate) fn struct_datum_query(
 +    db: &dyn HirDatabase,
 +    krate: CrateId,
 +    struct_id: AdtId,
 +) -> Arc<StructDatum> {
 +    debug!("struct_datum {:?}", struct_id);
 +    let chalk_ir::AdtId(adt_id) = struct_id;
 +    let generic_params = generics(db.upcast(), adt_id.into());
 +    let upstream = adt_id.module(db.upcast()).krate() != krate;
 +    let where_clauses = {
 +        let generic_params = generics(db.upcast(), adt_id.into());
 +        let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +        convert_where_clauses(db, adt_id.into(), &bound_vars)
 +    };
 +    let flags = rust_ir::AdtFlags {
 +        upstream,
 +        // FIXME set fundamental and phantom_data flags correctly
 +        fundamental: false,
 +        phantom_data: false,
 +    };
 +    // FIXME provide enum variants properly (for auto traits)
 +    let variant = rust_ir::AdtVariantDatum {
 +        fields: Vec::new(), // FIXME add fields (only relevant for auto traits),
 +    };
 +    let struct_datum_bound = rust_ir::AdtDatumBound { variants: vec![variant], where_clauses };
 +    let struct_datum = StructDatum {
 +        // FIXME set ADT kind
 +        kind: rust_ir::AdtKind::Struct,
 +        id: struct_id,
 +        binders: make_binders(db, &generic_params, struct_datum_bound),
 +        flags,
 +    };
 +    Arc::new(struct_datum)
 +}
 +
 +pub(crate) fn impl_datum_query(
 +    db: &dyn HirDatabase,
 +    krate: CrateId,
 +    impl_id: ImplId,
 +) -> Arc<ImplDatum> {
 +    let _p = profile::span("impl_datum");
 +    debug!("impl_datum {:?}", impl_id);
 +    let impl_: hir_def::ImplId = from_chalk(db, impl_id);
 +    impl_def_datum(db, krate, impl_id, impl_)
 +}
 +
 +fn impl_def_datum(
 +    db: &dyn HirDatabase,
 +    krate: CrateId,
 +    chalk_id: ImplId,
 +    impl_id: hir_def::ImplId,
 +) -> Arc<ImplDatum> {
 +    let trait_ref = db
 +        .impl_trait(impl_id)
 +        // ImplIds for impls where the trait ref can't be resolved should never reach Chalk
 +        .expect("invalid impl passed to Chalk")
 +        .into_value_and_skipped_binders()
 +        .0;
 +    let impl_data = db.impl_data(impl_id);
 +
 +    let generic_params = generics(db.upcast(), impl_id.into());
 +    let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +    let trait_ = trait_ref.hir_trait_id();
 +    let impl_type = if impl_id.lookup(db.upcast()).container.krate() == krate {
 +        rust_ir::ImplType::Local
 +    } else {
 +        rust_ir::ImplType::External
 +    };
 +    let where_clauses = convert_where_clauses(db, impl_id.into(), &bound_vars);
 +    let negative = impl_data.is_negative;
 +    debug!(
 +        "impl {:?}: {}{} where {:?}",
 +        chalk_id,
 +        if negative { "!" } else { "" },
 +        trait_ref.display(db),
 +        where_clauses
 +    );
 +
 +    let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive };
 +
 +    let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses };
 +    let trait_data = db.trait_data(trait_);
 +    let associated_ty_value_ids = impl_data
 +        .items
 +        .iter()
 +        .filter_map(|item| match item {
 +            AssocItemId::TypeAliasId(type_alias) => Some(*type_alias),
 +            _ => None,
 +        })
 +        .filter(|&type_alias| {
 +            // don't include associated types that don't exist in the trait
 +            let name = &db.type_alias_data(type_alias).name;
 +            trait_data.associated_type_by_name(name).is_some()
 +        })
 +        .map(|type_alias| TypeAliasAsValue(type_alias).to_chalk(db))
 +        .collect();
 +    debug!("impl_datum: {:?}", impl_datum_bound);
 +    let impl_datum = ImplDatum {
 +        binders: make_binders(db, &generic_params, impl_datum_bound),
 +        impl_type,
 +        polarity,
 +        associated_ty_value_ids,
 +    };
 +    Arc::new(impl_datum)
 +}
 +
 +pub(crate) fn associated_ty_value_query(
 +    db: &dyn HirDatabase,
 +    krate: CrateId,
 +    id: AssociatedTyValueId,
 +) -> Arc<AssociatedTyValue> {
 +    let type_alias: TypeAliasAsValue = from_chalk(db, id);
 +    type_alias_associated_ty_value(db, krate, type_alias.0)
 +}
 +
 +fn type_alias_associated_ty_value(
 +    db: &dyn HirDatabase,
 +    _krate: CrateId,
 +    type_alias: TypeAliasId,
 +) -> Arc<AssociatedTyValue> {
 +    let type_alias_data = db.type_alias_data(type_alias);
 +    let impl_id = match type_alias.lookup(db.upcast()).container {
 +        ItemContainerId::ImplId(it) => it,
 +        _ => panic!("assoc ty value should be in impl"),
 +    };
 +
 +    let trait_ref = db
 +        .impl_trait(impl_id)
 +        .expect("assoc ty value should not exist")
 +        .into_value_and_skipped_binders()
 +        .0; // we don't return any assoc ty values if the impl'd trait can't be resolved
 +
 +    let assoc_ty = db
 +        .trait_data(trait_ref.hir_trait_id())
 +        .associated_type_by_name(&type_alias_data.name)
 +        .expect("assoc ty value should not exist"); // validated when building the impl data as well
 +    let (ty, binders) = db.ty(type_alias.into()).into_value_and_skipped_binders();
 +    let value_bound = rust_ir::AssociatedTyValueBound { ty };
 +    let value = rust_ir::AssociatedTyValue {
 +        impl_id: impl_id.to_chalk(db),
 +        associated_ty_id: to_assoc_type_id(assoc_ty),
 +        value: chalk_ir::Binders::new(binders, value_bound),
 +    };
 +    Arc::new(value)
 +}
 +
 +pub(crate) fn fn_def_datum_query(
 +    db: &dyn HirDatabase,
 +    _krate: CrateId,
 +    fn_def_id: FnDefId,
 +) -> Arc<FnDefDatum> {
 +    let callable_def: CallableDefId = from_chalk(db, fn_def_id);
 +    let generic_params = generics(db.upcast(), callable_def.into());
 +    let (sig, binders) = db.callable_item_signature(callable_def).into_value_and_skipped_binders();
 +    let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +    let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars);
 +    let bound = rust_ir::FnDefDatumBound {
 +        // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway
 +        inputs_and_output: chalk_ir::Binders::empty(
 +            Interner,
 +            rust_ir::FnDefInputsAndOutputDatum {
 +                argument_types: sig.params().to_vec(),
 +                return_type: sig.ret().clone(),
 +            }
 +            .shifted_in(Interner),
 +        ),
 +        where_clauses,
 +    };
 +    let datum = FnDefDatum {
 +        id: fn_def_id,
 +        sig: chalk_ir::FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: sig.is_varargs },
 +        binders: chalk_ir::Binders::new(binders, bound),
 +    };
 +    Arc::new(datum)
 +}
 +
 +pub(crate) fn fn_def_variance_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Variances {
 +    let callable_def: CallableDefId = from_chalk(db, fn_def_id);
 +    let generic_params = generics(db.upcast(), callable_def.into());
 +    Variances::from_iter(
 +        Interner,
 +        std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()),
 +    )
 +}
 +
 +pub(crate) fn adt_variance_query(
 +    db: &dyn HirDatabase,
 +    chalk_ir::AdtId(adt_id): AdtId,
 +) -> Variances {
 +    let generic_params = generics(db.upcast(), adt_id.into());
 +    Variances::from_iter(
 +        Interner,
 +        std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()),
 +    )
 +}
 +
 +pub(super) fn convert_where_clauses(
 +    db: &dyn HirDatabase,
 +    def: GenericDefId,
 +    substs: &Substitution,
 +) -> Vec<chalk_ir::QuantifiedWhereClause<Interner>> {
 +    let generic_predicates = db.generic_predicates(def);
 +    let mut result = Vec::with_capacity(generic_predicates.len());
 +    for pred in generic_predicates.iter() {
 +        result.push(pred.clone().substitute(Interner, substs));
 +    }
 +    result
 +}
 +
 +pub(super) fn generic_predicate_to_inline_bound(
 +    db: &dyn HirDatabase,
 +    pred: &QuantifiedWhereClause,
 +    self_ty: &Ty,
 +) -> Option<chalk_ir::Binders<rust_ir::InlineBound<Interner>>> {
 +    // An InlineBound is like a GenericPredicate, except the self type is left out.
 +    // We don't have a special type for this, but Chalk does.
 +    let self_ty_shifted_in = self_ty.clone().shifted_in_from(Interner, DebruijnIndex::ONE);
 +    let (pred, binders) = pred.as_ref().into_value_and_skipped_binders();
 +    match pred {
 +        WhereClause::Implemented(trait_ref) => {
 +            if trait_ref.self_type_parameter(Interner) != self_ty_shifted_in {
 +                // we can only convert predicates back to type bounds if they
 +                // have the expected self type
 +                return None;
 +            }
 +            let args_no_self = trait_ref.substitution.as_slice(Interner)[1..]
 +                .iter()
 +                .map(|ty| ty.clone().cast(Interner))
 +                .collect();
 +            let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self };
 +            Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
 +        }
 +        WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
-             let trait_ = projection_ty.trait_(db);
++            let trait_ = projection_ty.trait_(db);
++            if projection_ty.self_type_parameter(db) != self_ty_shifted_in {
 +                return None;
 +            }
 +            let args_no_self = projection_ty.substitution.as_slice(Interner)[1..]
 +                .iter()
 +                .map(|ty| ty.clone().cast(Interner))
 +                .collect();
 +            let alias_eq_bound = rust_ir::AliasEqBound {
 +                value: ty.clone(),
 +                trait_bound: rust_ir::TraitBound {
 +                    trait_id: to_chalk_trait_id(trait_),
 +                    args_no_self,
 +                },
 +                associated_ty_id: projection_ty.associated_ty_id,
 +                parameters: Vec::new(), // FIXME we don't support generic associated types yet
 +            };
 +            Some(chalk_ir::Binders::new(
 +                binders,
 +                rust_ir::InlineBound::AliasEqBound(alias_eq_bound),
 +            ))
 +        }
 +        _ => None,
 +    }
 +}
index 4f0e9dbf1e4e9f1ab313bf3bec2d533c8ae4c2f6,0000000000000000000000000000000000000000..e2099d7e509278b9b8ce8cb031c89d107f6c0972
mode 100644,000000..100644
--- /dev/null
@@@ -1,362 -1,0 +1,367 @@@
-                                     }) => &proj.self_type_parameter(Interner) == self,
 +//! Various extensions traits for Chalk types.
 +
 +use chalk_ir::{FloatTy, IntTy, Mutability, Scalar, UintTy};
 +use hir_def::{
 +    builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint},
 +    generics::TypeOrConstParamData,
 +    type_ref::Rawness,
 +    FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId,
 +};
 +use syntax::SmolStr;
 +
 +use crate::{
 +    db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
 +    from_placeholder_idx, to_chalk_trait_id, AdtId, AliasEq, AliasTy, Binders, CallableDefId,
 +    CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause,
 +    Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause,
 +};
 +
 +pub trait TyExt {
 +    fn is_unit(&self) -> bool;
 +    fn is_never(&self) -> bool;
 +    fn is_unknown(&self) -> bool;
 +    fn is_ty_var(&self) -> bool;
 +
 +    fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>;
 +    fn as_builtin(&self) -> Option<BuiltinType>;
 +    fn as_tuple(&self) -> Option<&Substitution>;
 +    fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId>;
 +    fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>;
 +    fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)>;
 +    fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId>;
 +
 +    fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId>;
 +    fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>;
 +
 +    fn strip_references(&self) -> &Ty;
 +    fn strip_reference(&self) -> &Ty;
 +
 +    /// If this is a `dyn Trait`, returns that trait.
 +    fn dyn_trait(&self) -> Option<TraitId>;
 +
 +    fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>>;
 +    fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId>;
 +
 +    /// FIXME: Get rid of this, it's not a good abstraction
 +    fn equals_ctor(&self, other: &Ty) -> bool;
 +}
 +
 +impl TyExt for Ty {
 +    fn is_unit(&self) -> bool {
 +        matches!(self.kind(Interner), TyKind::Tuple(0, _))
 +    }
 +
 +    fn is_never(&self) -> bool {
 +        matches!(self.kind(Interner), TyKind::Never)
 +    }
 +
 +    fn is_unknown(&self) -> bool {
 +        matches!(self.kind(Interner), TyKind::Error)
 +    }
 +
 +    fn is_ty_var(&self) -> bool {
 +        matches!(self.kind(Interner), TyKind::InferenceVar(_, _))
 +    }
 +
 +    fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
 +        match self.kind(Interner) {
 +            TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
 +            _ => None,
 +        }
 +    }
 +
 +    fn as_builtin(&self) -> Option<BuiltinType> {
 +        match self.kind(Interner) {
 +            TyKind::Str => Some(BuiltinType::Str),
 +            TyKind::Scalar(Scalar::Bool) => Some(BuiltinType::Bool),
 +            TyKind::Scalar(Scalar::Char) => Some(BuiltinType::Char),
 +            TyKind::Scalar(Scalar::Float(fty)) => Some(BuiltinType::Float(match fty {
 +                FloatTy::F64 => BuiltinFloat::F64,
 +                FloatTy::F32 => BuiltinFloat::F32,
 +            })),
 +            TyKind::Scalar(Scalar::Int(ity)) => Some(BuiltinType::Int(match ity {
 +                IntTy::Isize => BuiltinInt::Isize,
 +                IntTy::I8 => BuiltinInt::I8,
 +                IntTy::I16 => BuiltinInt::I16,
 +                IntTy::I32 => BuiltinInt::I32,
 +                IntTy::I64 => BuiltinInt::I64,
 +                IntTy::I128 => BuiltinInt::I128,
 +            })),
 +            TyKind::Scalar(Scalar::Uint(ity)) => Some(BuiltinType::Uint(match ity {
 +                UintTy::Usize => BuiltinUint::Usize,
 +                UintTy::U8 => BuiltinUint::U8,
 +                UintTy::U16 => BuiltinUint::U16,
 +                UintTy::U32 => BuiltinUint::U32,
 +                UintTy::U64 => BuiltinUint::U64,
 +                UintTy::U128 => BuiltinUint::U128,
 +            })),
 +            _ => None,
 +        }
 +    }
 +
 +    fn as_tuple(&self) -> Option<&Substitution> {
 +        match self.kind(Interner) {
 +            TyKind::Tuple(_, substs) => Some(substs),
 +            _ => None,
 +        }
 +    }
 +
 +    fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId> {
 +        match self.callable_def(db) {
 +            Some(CallableDefId::FunctionId(func)) => Some(func),
 +            Some(CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_)) | None => None,
 +        }
 +    }
 +    fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> {
 +        match self.kind(Interner) {
 +            TyKind::Ref(mutability, lifetime, ty) => Some((ty, lifetime.clone(), *mutability)),
 +            _ => None,
 +        }
 +    }
 +
 +    fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> {
 +        match self.kind(Interner) {
 +            TyKind::Ref(mutability, _, ty) => Some((ty, Rawness::Ref, *mutability)),
 +            TyKind::Raw(mutability, ty) => Some((ty, Rawness::RawPtr, *mutability)),
 +            _ => None,
 +        }
 +    }
 +
 +    fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> {
 +        match *self.kind(Interner) {
 +            TyKind::Adt(AdtId(adt), ..) => Some(adt.into()),
 +            TyKind::FnDef(callable, ..) => {
 +                Some(db.lookup_intern_callable_def(callable.into()).into())
 +            }
 +            TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()),
 +            TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()),
 +            _ => None,
 +        }
 +    }
 +
 +    fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> {
 +        match self.kind(Interner) {
 +            &TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())),
 +            _ => None,
 +        }
 +    }
 +
 +    fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig> {
 +        match self.kind(Interner) {
 +            TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)),
 +            TyKind::FnDef(def, parameters) => {
 +                let callable_def = db.lookup_intern_callable_def((*def).into());
 +                let sig = db.callable_item_signature(callable_def);
 +                Some(sig.substitute(Interner, parameters))
 +            }
 +            TyKind::Closure(.., substs) => {
 +                let sig_param = substs.at(Interner, 0).assert_ty_ref(Interner);
 +                sig_param.callable_sig(db)
 +            }
 +            _ => None,
 +        }
 +    }
 +
 +    fn dyn_trait(&self) -> Option<TraitId> {
 +        let trait_ref = match self.kind(Interner) {
 +            // The principal trait bound should be the first element of the bounds. This is an
 +            // invariant ensured by `TyLoweringContext::lower_dyn_trait()`.
 +            // FIXME: dyn types may not have principal trait and we don't want to return auto trait
 +            // here.
 +            TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
 +                match b.skip_binders() {
 +                    WhereClause::Implemented(trait_ref) => Some(trait_ref),
 +                    _ => None,
 +                }
 +            }),
 +            _ => None,
 +        }?;
 +        Some(from_chalk_trait_id(trait_ref.trait_id))
 +    }
 +
 +    fn strip_references(&self) -> &Ty {
 +        let mut t: &Ty = self;
 +        while let TyKind::Ref(_mutability, _lifetime, ty) = t.kind(Interner) {
 +            t = ty;
 +        }
 +        t
 +    }
 +
 +    fn strip_reference(&self) -> &Ty {
 +        self.as_reference().map_or(self, |(ty, _, _)| ty)
 +    }
 +
 +    fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> {
 +        match self.kind(Interner) {
 +            TyKind::OpaqueType(opaque_ty_id, subst) => {
 +                match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) {
 +                    ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => {
 +                        let krate = def.module(db.upcast()).krate();
 +                        if let Some(future_trait) = db
 +                            .lang_item(krate, SmolStr::new_inline("future_trait"))
 +                            .and_then(|item| item.as_trait())
 +                        {
 +                            // This is only used by type walking.
 +                            // Parameters will be walked outside, and projection predicate is not used.
 +                            // So just provide the Future trait.
 +                            let impl_bound = Binders::empty(
 +                                Interner,
 +                                WhereClause::Implemented(TraitRef {
 +                                    trait_id: to_chalk_trait_id(future_trait),
 +                                    substitution: Substitution::empty(Interner),
 +                                }),
 +                            );
 +                            Some(vec![impl_bound])
 +                        } else {
 +                            None
 +                        }
 +                    }
 +                    ImplTraitId::ReturnTypeImplTrait(func, idx) => {
 +                        db.return_type_impl_traits(func).map(|it| {
 +                            let data = (*it)
 +                                .as_ref()
 +                                .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
 +                            data.substitute(Interner, &subst).into_value_and_skipped_binders().0
 +                        })
 +                    }
 +                }
 +            }
 +            TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
 +                let predicates = match db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into())
 +                {
 +                    ImplTraitId::ReturnTypeImplTrait(func, idx) => {
 +                        db.return_type_impl_traits(func).map(|it| {
 +                            let data = (*it)
 +                                .as_ref()
 +                                .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
 +                            data.substitute(Interner, &opaque_ty.substitution)
 +                        })
 +                    }
 +                    // It always has an parameter for Future::Output type.
 +                    ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(),
 +                };
 +
 +                predicates.map(|it| it.into_value_and_skipped_binders().0)
 +            }
 +            TyKind::Placeholder(idx) => {
 +                let id = from_placeholder_idx(db, *idx);
 +                let generic_params = db.generic_params(id.parent);
 +                let param_data = &generic_params.type_or_consts[id.local_id];
 +                match param_data {
 +                    TypeOrConstParamData::TypeParamData(p) => match p.provenance {
 +                        hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
 +                            let substs = TyBuilder::placeholder_subst(db, id.parent);
 +                            let predicates = db
 +                                .generic_predicates(id.parent)
 +                                .iter()
 +                                .map(|pred| pred.clone().substitute(Interner, &substs))
 +                                .filter(|wc| match &wc.skip_binders() {
 +                                    WhereClause::Implemented(tr) => {
 +                                        &tr.self_type_parameter(Interner) == self
 +                                    }
 +                                    WhereClause::AliasEq(AliasEq {
 +                                        alias: AliasTy::Projection(proj),
 +                                        ty: _,
++                                    }) => &proj.self_type_parameter(db) == self,
 +                                    _ => false,
 +                                })
 +                                .collect::<Vec<_>>();
 +
 +                            Some(predicates)
 +                        }
 +                        _ => None,
 +                    },
 +                    _ => None,
 +                }
 +            }
 +            _ => None,
 +        }
 +    }
 +
 +    fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> {
 +        match self.kind(Interner) {
 +            TyKind::AssociatedType(id, ..) => {
 +                match from_assoc_type_id(*id).lookup(db.upcast()).container {
 +                    ItemContainerId::TraitId(trait_id) => Some(trait_id),
 +                    _ => None,
 +                }
 +            }
 +            TyKind::Alias(AliasTy::Projection(projection_ty)) => {
 +                match from_assoc_type_id(projection_ty.associated_ty_id)
 +                    .lookup(db.upcast())
 +                    .container
 +                {
 +                    ItemContainerId::TraitId(trait_id) => Some(trait_id),
 +                    _ => None,
 +                }
 +            }
 +            _ => None,
 +        }
 +    }
 +
 +    fn equals_ctor(&self, other: &Ty) -> bool {
 +        match (self.kind(Interner), other.kind(Interner)) {
 +            (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2,
 +            (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_, _), TyKind::Array(_, _)) => {
 +                true
 +            }
 +            (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2,
 +            (TyKind::OpaqueType(ty_id, ..), TyKind::OpaqueType(ty_id2, ..)) => ty_id == ty_id2,
 +            (TyKind::AssociatedType(ty_id, ..), TyKind::AssociatedType(ty_id2, ..)) => {
 +                ty_id == ty_id2
 +            }
 +            (TyKind::Foreign(ty_id, ..), TyKind::Foreign(ty_id2, ..)) => ty_id == ty_id2,
 +            (TyKind::Closure(id1, _), TyKind::Closure(id2, _)) => id1 == id2,
 +            (TyKind::Ref(mutability, ..), TyKind::Ref(mutability2, ..))
 +            | (TyKind::Raw(mutability, ..), TyKind::Raw(mutability2, ..)) => {
 +                mutability == mutability2
 +            }
 +            (
 +                TyKind::Function(FnPointer { num_binders, sig, .. }),
 +                TyKind::Function(FnPointer { num_binders: num_binders2, sig: sig2, .. }),
 +            ) => num_binders == num_binders2 && sig == sig2,
 +            (TyKind::Tuple(cardinality, _), TyKind::Tuple(cardinality2, _)) => {
 +                cardinality == cardinality2
 +            }
 +            (TyKind::Str, TyKind::Str) | (TyKind::Never, TyKind::Never) => true,
 +            (TyKind::Scalar(scalar), TyKind::Scalar(scalar2)) => scalar == scalar2,
 +            _ => false,
 +        }
 +    }
 +}
 +
 +pub trait ProjectionTyExt {
 +    fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef;
 +    fn trait_(&self, db: &dyn HirDatabase) -> TraitId;
++    fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty;
 +}
 +
 +impl ProjectionTyExt for ProjectionTy {
 +    fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
 +        TraitRef {
 +            trait_id: to_chalk_trait_id(self.trait_(db)),
 +            substitution: self.substitution.clone(),
 +        }
 +    }
 +
 +    fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
 +        match from_assoc_type_id(self.associated_ty_id).lookup(db.upcast()).container {
 +            ItemContainerId::TraitId(it) => it,
 +            _ => panic!("projection ty without parent trait"),
 +        }
 +    }
++
++    fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty {
++        self.trait_ref(db).self_type_parameter(Interner)
++    }
 +}
 +
 +pub trait TraitRefExt {
 +    fn hir_trait_id(&self) -> TraitId;
 +}
 +
 +impl TraitRefExt for TraitRef {
 +    fn hir_trait_id(&self) -> TraitId {
 +        from_chalk_trait_id(self.trait_id)
 +    }
 +}
index 7f0baf49dadce9e510a0b133d811b2fde49ff19c,0000000000000000000000000000000000000000..0221f922feb2ff396a2c602880eb1ad363dab60e
mode 100644,000000..100644
--- /dev/null
@@@ -1,1351 -1,0 +1,1361 @@@
-         self.self_type_parameter(Interner).hir_fmt(f)?;
 +//! The `HirDisplay` trait, which serves two purposes: Turning various bits from
 +//! HIR back into source code, and just displaying them for debugging/testing
 +//! purposes.
 +
 +use std::fmt::{self, Debug};
 +
 +use base_db::CrateId;
 +use chalk_ir::BoundVar;
 +use hir_def::{
 +    body,
 +    db::DefDatabase,
 +    find_path,
 +    generics::{TypeOrConstParamData, TypeParamProvenance},
 +    intern::{Internable, Interned},
 +    item_scope::ItemInNs,
 +    path::{Path, PathKind},
 +    type_ref::{ConstScalar, TraitBoundModifier, TypeBound, TypeRef},
 +    visibility::Visibility,
 +    HasModule, ItemContainerId, Lookup, ModuleId, TraitId,
 +};
 +use hir_expand::{hygiene::Hygiene, name::Name};
 +use itertools::Itertools;
 +use smallvec::SmallVec;
 +use syntax::SmolStr;
 +
 +use crate::{
 +    db::HirDatabase,
 +    from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx,
 +    mapping::from_chalk,
 +    primitive, to_assoc_type_id,
 +    utils::{self, generics},
 +    AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstValue, DomainGoal,
 +    GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability,
 +    OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar, Substitution, TraitRef,
 +    TraitRefExt, Ty, TyExt, TyKind, WhereClause,
 +};
 +
 +pub struct HirFormatter<'a> {
 +    pub db: &'a dyn HirDatabase,
 +    fmt: &'a mut dyn fmt::Write,
 +    buf: String,
 +    curr_size: usize,
 +    pub(crate) max_size: Option<usize>,
 +    omit_verbose_types: bool,
 +    display_target: DisplayTarget,
 +}
 +
 +pub trait HirDisplay {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>;
 +
 +    /// Returns a `Display`able type that is human-readable.
 +    fn into_displayable<'a>(
 +        &'a self,
 +        db: &'a dyn HirDatabase,
 +        max_size: Option<usize>,
 +        omit_verbose_types: bool,
 +        display_target: DisplayTarget,
 +    ) -> HirDisplayWrapper<'a, Self>
 +    where
 +        Self: Sized,
 +    {
 +        assert!(
 +            !matches!(display_target, DisplayTarget::SourceCode { .. }),
 +            "HirDisplayWrapper cannot fail with DisplaySourceCodeError, use HirDisplay::hir_fmt directly instead"
 +        );
 +        HirDisplayWrapper { db, t: self, max_size, omit_verbose_types, display_target }
 +    }
 +
 +    /// Returns a `Display`able type that is human-readable.
 +    /// Use this for showing types to the user (e.g. diagnostics)
 +    fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
 +    where
 +        Self: Sized,
 +    {
 +        HirDisplayWrapper {
 +            db,
 +            t: self,
 +            max_size: None,
 +            omit_verbose_types: false,
 +            display_target: DisplayTarget::Diagnostics,
 +        }
 +    }
 +
 +    /// Returns a `Display`able type that is human-readable and tries to be succinct.
 +    /// Use this for showing types to the user where space is constrained (e.g. doc popups)
 +    fn display_truncated<'a>(
 +        &'a self,
 +        db: &'a dyn HirDatabase,
 +        max_size: Option<usize>,
 +    ) -> HirDisplayWrapper<'a, Self>
 +    where
 +        Self: Sized,
 +    {
 +        HirDisplayWrapper {
 +            db,
 +            t: self,
 +            max_size,
 +            omit_verbose_types: true,
 +            display_target: DisplayTarget::Diagnostics,
 +        }
 +    }
 +
 +    /// Returns a String representation of `self` that can be inserted into the given module.
 +    /// Use this when generating code (e.g. assists)
 +    fn display_source_code<'a>(
 +        &'a self,
 +        db: &'a dyn HirDatabase,
 +        module_id: ModuleId,
 +    ) -> Result<String, DisplaySourceCodeError> {
 +        let mut result = String::new();
 +        match self.hir_fmt(&mut HirFormatter {
 +            db,
 +            fmt: &mut result,
 +            buf: String::with_capacity(20),
 +            curr_size: 0,
 +            max_size: None,
 +            omit_verbose_types: false,
 +            display_target: DisplayTarget::SourceCode { module_id },
 +        }) {
 +            Ok(()) => {}
 +            Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
 +            Err(HirDisplayError::DisplaySourceCodeError(e)) => return Err(e),
 +        };
 +        Ok(result)
 +    }
 +
 +    /// Returns a String representation of `self` for test purposes
 +    fn display_test<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
 +    where
 +        Self: Sized,
 +    {
 +        HirDisplayWrapper {
 +            db,
 +            t: self,
 +            max_size: None,
 +            omit_verbose_types: false,
 +            display_target: DisplayTarget::Test,
 +        }
 +    }
 +}
 +
 +impl<'a> HirFormatter<'a> {
 +    pub fn write_joined<T: HirDisplay>(
 +        &mut self,
 +        iter: impl IntoIterator<Item = T>,
 +        sep: &str,
 +    ) -> Result<(), HirDisplayError> {
 +        let mut first = true;
 +        for e in iter {
 +            if !first {
 +                write!(self, "{}", sep)?;
 +            }
 +            first = false;
 +
 +            // Abbreviate multiple omitted types with a single ellipsis.
 +            if self.should_truncate() {
 +                return write!(self, "{}", TYPE_HINT_TRUNCATION);
 +            }
 +
 +            e.hir_fmt(self)?;
 +        }
 +        Ok(())
 +    }
 +
 +    /// This allows using the `write!` macro directly with a `HirFormatter`.
 +    pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), HirDisplayError> {
 +        // We write to a buffer first to track output size
 +        self.buf.clear();
 +        fmt::write(&mut self.buf, args)?;
 +        self.curr_size += self.buf.len();
 +
 +        // Then we write to the internal formatter from the buffer
 +        self.fmt.write_str(&self.buf).map_err(HirDisplayError::from)
 +    }
 +
 +    pub fn write_str(&mut self, s: &str) -> Result<(), HirDisplayError> {
 +        self.fmt.write_str(s)?;
 +        Ok(())
 +    }
 +
 +    pub fn write_char(&mut self, c: char) -> Result<(), HirDisplayError> {
 +        self.fmt.write_char(c)?;
 +        Ok(())
 +    }
 +
 +    pub fn should_truncate(&self) -> bool {
 +        match self.max_size {
 +            Some(max_size) => self.curr_size >= max_size,
 +            None => false,
 +        }
 +    }
 +
 +    pub fn omit_verbose_types(&self) -> bool {
 +        self.omit_verbose_types
 +    }
 +}
 +
 +#[derive(Clone, Copy)]
 +pub enum DisplayTarget {
 +    /// Display types for inlays, doc popups, autocompletion, etc...
 +    /// Showing `{unknown}` or not qualifying paths is fine here.
 +    /// There's no reason for this to fail.
 +    Diagnostics,
 +    /// Display types for inserting them in source files.
 +    /// The generated code should compile, so paths need to be qualified.
 +    SourceCode { module_id: ModuleId },
 +    /// Only for test purpose to keep real types
 +    Test,
 +}
 +
 +impl DisplayTarget {
 +    fn is_source_code(&self) -> bool {
 +        matches!(self, Self::SourceCode { .. })
 +    }
 +    fn is_test(&self) -> bool {
 +        matches!(self, Self::Test)
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub enum DisplaySourceCodeError {
 +    PathNotFound,
 +    UnknownType,
 +    Closure,
 +    Generator,
 +}
 +
 +pub enum HirDisplayError {
 +    /// Errors that can occur when generating source code
 +    DisplaySourceCodeError(DisplaySourceCodeError),
 +    /// `FmtError` is required to be compatible with std::fmt::Display
 +    FmtError,
 +}
 +impl From<fmt::Error> for HirDisplayError {
 +    fn from(_: fmt::Error) -> Self {
 +        Self::FmtError
 +    }
 +}
 +
 +pub struct HirDisplayWrapper<'a, T> {
 +    db: &'a dyn HirDatabase,
 +    t: &'a T,
 +    max_size: Option<usize>,
 +    omit_verbose_types: bool,
 +    display_target: DisplayTarget,
 +}
 +
 +impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T>
 +where
 +    T: HirDisplay,
 +{
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match self.t.hir_fmt(&mut HirFormatter {
 +            db: self.db,
 +            fmt: f,
 +            buf: String::with_capacity(20),
 +            curr_size: 0,
 +            max_size: self.max_size,
 +            omit_verbose_types: self.omit_verbose_types,
 +            display_target: self.display_target,
 +        }) {
 +            Ok(()) => Ok(()),
 +            Err(HirDisplayError::FmtError) => Err(fmt::Error),
 +            Err(HirDisplayError::DisplaySourceCodeError(_)) => {
 +                // This should never happen
 +                panic!("HirDisplay::hir_fmt failed with DisplaySourceCodeError when calling Display::fmt!")
 +            }
 +        }
 +    }
 +}
 +
 +const TYPE_HINT_TRUNCATION: &str = "…";
 +
 +impl<T: HirDisplay> HirDisplay for &'_ T {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        HirDisplay::hir_fmt(*self, f)
 +    }
 +}
 +
 +impl<T: HirDisplay + Internable> HirDisplay for Interned<T> {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        HirDisplay::hir_fmt(self.as_ref(), f)
 +    }
 +}
 +
 +impl HirDisplay for ProjectionTy {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        if f.should_truncate() {
 +            return write!(f, "{}", TYPE_HINT_TRUNCATION);
 +        }
 +
 +        let trait_ = f.db.trait_data(self.trait_(f.db));
 +        write!(f, "<")?;
-                                         }) => &proj.self_type_parameter(Interner) == self,
++        self.self_type_parameter(f.db).hir_fmt(f)?;
 +        write!(f, " as {}", trait_.name)?;
 +        if self.substitution.len(Interner) > 1 {
 +            write!(f, "<")?;
 +            f.write_joined(&self.substitution.as_slice(Interner)[1..], ", ")?;
 +            write!(f, ">")?;
 +        }
 +        write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
 +        Ok(())
 +    }
 +}
 +
 +impl HirDisplay for OpaqueTy {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        if f.should_truncate() {
 +            return write!(f, "{}", TYPE_HINT_TRUNCATION);
 +        }
 +
 +        self.substitution.at(Interner, 0).hir_fmt(f)
 +    }
 +}
 +
 +impl HirDisplay for GenericArg {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        match self.interned() {
 +            crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
 +            crate::GenericArgData::Lifetime(lt) => lt.hir_fmt(f),
 +            crate::GenericArgData::Const(c) => c.hir_fmt(f),
 +        }
 +    }
 +}
 +
 +impl HirDisplay for Const {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        let data = self.interned();
 +        match data.value {
 +            ConstValue::BoundVar(idx) => idx.hir_fmt(f),
 +            ConstValue::InferenceVar(..) => write!(f, "#c#"),
 +            ConstValue::Placeholder(idx) => {
 +                let id = from_placeholder_idx(f.db, idx);
 +                let generics = generics(f.db.upcast(), id.parent);
 +                let param_data = &generics.params.type_or_consts[id.local_id];
 +                write!(f, "{}", param_data.name().unwrap())
 +            }
 +            ConstValue::Concrete(c) => write!(f, "{}", c.interned),
 +        }
 +    }
 +}
 +
 +impl HirDisplay for BoundVar {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        write!(f, "?{}.{}", self.debruijn.depth(), self.index)
 +    }
 +}
 +
 +impl HirDisplay for Ty {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        if f.should_truncate() {
 +            return write!(f, "{}", TYPE_HINT_TRUNCATION);
 +        }
 +
 +        match self.kind(Interner) {
 +            TyKind::Never => write!(f, "!")?,
 +            TyKind::Str => write!(f, "str")?,
 +            TyKind::Scalar(Scalar::Bool) => write!(f, "bool")?,
 +            TyKind::Scalar(Scalar::Char) => write!(f, "char")?,
 +            &TyKind::Scalar(Scalar::Float(t)) => write!(f, "{}", primitive::float_ty_to_string(t))?,
 +            &TyKind::Scalar(Scalar::Int(t)) => write!(f, "{}", primitive::int_ty_to_string(t))?,
 +            &TyKind::Scalar(Scalar::Uint(t)) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
 +            TyKind::Slice(t) => {
 +                write!(f, "[")?;
 +                t.hir_fmt(f)?;
 +                write!(f, "]")?;
 +            }
 +            TyKind::Array(t, c) => {
 +                write!(f, "[")?;
 +                t.hir_fmt(f)?;
 +                write!(f, "; ")?;
 +                c.hir_fmt(f)?;
 +                write!(f, "]")?;
 +            }
 +            TyKind::Raw(m, t) | TyKind::Ref(m, _, t) => {
 +                if matches!(self.kind(Interner), TyKind::Raw(..)) {
 +                    write!(
 +                        f,
 +                        "*{}",
 +                        match m {
 +                            Mutability::Not => "const ",
 +                            Mutability::Mut => "mut ",
 +                        }
 +                    )?;
 +                } else {
 +                    write!(
 +                        f,
 +                        "&{}",
 +                        match m {
 +                            Mutability::Not => "",
 +                            Mutability::Mut => "mut ",
 +                        }
 +                    )?;
 +                }
 +
 +                // FIXME: all this just to decide whether to use parentheses...
 +                let contains_impl_fn = |bounds: &[QuantifiedWhereClause]| {
 +                    bounds.iter().any(|bound| {
 +                        if let WhereClause::Implemented(trait_ref) = bound.skip_binders() {
 +                            let trait_ = trait_ref.hir_trait_id();
 +                            fn_traits(f.db.upcast(), trait_).any(|it| it == trait_)
 +                        } else {
 +                            false
 +                        }
 +                    })
 +                };
 +                let (preds_to_print, has_impl_fn_pred) = match t.kind(Interner) {
 +                    TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => {
 +                        let bounds = dyn_ty.bounds.skip_binders().interned();
 +                        (bounds.len(), contains_impl_fn(bounds))
 +                    }
 +                    TyKind::Alias(AliasTy::Opaque(OpaqueTy {
 +                        opaque_ty_id,
 +                        substitution: parameters,
 +                    }))
 +                    | TyKind::OpaqueType(opaque_ty_id, parameters) => {
 +                        let impl_trait_id =
 +                            f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
 +                        if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
 +                            let datas =
 +                                f.db.return_type_impl_traits(func)
 +                                    .expect("impl trait id without data");
 +                            let data = (*datas)
 +                                .as_ref()
 +                                .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
 +                            let bounds = data.substitute(Interner, parameters);
 +                            let mut len = bounds.skip_binders().len();
 +
 +                            // Don't count Sized but count when it absent
 +                            // (i.e. when explicit ?Sized bound is set).
 +                            let default_sized = SizedByDefault::Sized {
 +                                anchor: func.lookup(f.db.upcast()).module(f.db.upcast()).krate(),
 +                            };
 +                            let sized_bounds = bounds
 +                                .skip_binders()
 +                                .iter()
 +                                .filter(|b| {
 +                                    matches!(
 +                                        b.skip_binders(),
 +                                        WhereClause::Implemented(trait_ref)
 +                                            if default_sized.is_sized_trait(
 +                                                trait_ref.hir_trait_id(),
 +                                                f.db.upcast(),
 +                                            ),
 +                                    )
 +                                })
 +                                .count();
 +                            match sized_bounds {
 +                                0 => len += 1,
 +                                _ => {
 +                                    len = len.saturating_sub(sized_bounds);
 +                                }
 +                            }
 +
 +                            (len, contains_impl_fn(bounds.skip_binders()))
 +                        } else {
 +                            (0, false)
 +                        }
 +                    }
 +                    _ => (0, false),
 +                };
 +
 +                if has_impl_fn_pred && preds_to_print <= 2 {
 +                    return t.hir_fmt(f);
 +                }
 +
 +                if preds_to_print > 1 {
 +                    write!(f, "(")?;
 +                    t.hir_fmt(f)?;
 +                    write!(f, ")")?;
 +                } else {
 +                    t.hir_fmt(f)?;
 +                }
 +            }
 +            TyKind::Tuple(_, substs) => {
 +                if substs.len(Interner) == 1 {
 +                    write!(f, "(")?;
 +                    substs.at(Interner, 0).hir_fmt(f)?;
 +                    write!(f, ",)")?;
 +                } else {
 +                    write!(f, "(")?;
 +                    f.write_joined(&*substs.as_slice(Interner), ", ")?;
 +                    write!(f, ")")?;
 +                }
 +            }
 +            TyKind::Function(fn_ptr) => {
 +                let sig = CallableSig::from_fn_ptr(fn_ptr);
 +                sig.hir_fmt(f)?;
 +            }
 +            TyKind::FnDef(def, parameters) => {
 +                let def = from_chalk(f.db, *def);
 +                let sig = f.db.callable_item_signature(def).substitute(Interner, parameters);
 +                match def {
 +                    CallableDefId::FunctionId(ff) => {
 +                        write!(f, "fn {}", f.db.function_data(ff).name)?
 +                    }
 +                    CallableDefId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?,
 +                    CallableDefId::EnumVariantId(e) => {
 +                        write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)?
 +                    }
 +                };
 +                if parameters.len(Interner) > 0 {
 +                    let generics = generics(f.db.upcast(), def.into());
 +                    let (parent_params, self_param, type_params, const_params, _impl_trait_params) =
 +                        generics.provenance_split();
 +                    let total_len = parent_params + self_param + type_params + const_params;
 +                    // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
 +                    if total_len > 0 {
 +                        // `parameters` are in the order of fn's params (including impl traits),
 +                        // parent's params (those from enclosing impl or trait, if any).
 +                        let parameters = parameters.as_slice(Interner);
 +                        let fn_params_len = self_param + type_params + const_params;
 +                        let fn_params = parameters.get(..fn_params_len);
 +                        let parent_params = parameters.get(parameters.len() - parent_params..);
 +                        let params = parent_params.into_iter().chain(fn_params).flatten();
 +                        write!(f, "<")?;
 +                        f.write_joined(params, ", ")?;
 +                        write!(f, ">")?;
 +                    }
 +                }
 +                write!(f, "(")?;
 +                f.write_joined(sig.params(), ", ")?;
 +                write!(f, ")")?;
 +                let ret = sig.ret();
 +                if !ret.is_unit() {
 +                    write!(f, " -> ")?;
 +                    ret.hir_fmt(f)?;
 +                }
 +            }
 +            TyKind::Adt(AdtId(def_id), parameters) => {
 +                match f.display_target {
 +                    DisplayTarget::Diagnostics | DisplayTarget::Test => {
 +                        let name = match *def_id {
 +                            hir_def::AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
 +                            hir_def::AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
 +                            hir_def::AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
 +                        };
 +                        write!(f, "{}", name)?;
 +                    }
 +                    DisplayTarget::SourceCode { module_id } => {
 +                        if let Some(path) = find_path::find_path(
 +                            f.db.upcast(),
 +                            ItemInNs::Types((*def_id).into()),
 +                            module_id,
 +                            false,
 +                        ) {
 +                            write!(f, "{}", path)?;
 +                        } else {
 +                            return Err(HirDisplayError::DisplaySourceCodeError(
 +                                DisplaySourceCodeError::PathNotFound,
 +                            ));
 +                        }
 +                    }
 +                }
 +
 +                if parameters.len(Interner) > 0 {
 +                    let parameters_to_write = if f.display_target.is_source_code()
 +                        || f.omit_verbose_types()
 +                    {
 +                        match self
 +                            .as_generic_def(f.db)
 +                            .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
 +                            .filter(|defaults| !defaults.is_empty())
 +                        {
 +                            None => parameters.as_slice(Interner),
 +                            Some(default_parameters) => {
 +                                fn should_show(
 +                                    parameter: &GenericArg,
 +                                    default_parameters: &[Binders<GenericArg>],
 +                                    i: usize,
 +                                    parameters: &Substitution,
 +                                ) -> bool {
 +                                    if parameter.ty(Interner).map(|x| x.kind(Interner))
 +                                        == Some(&TyKind::Error)
 +                                    {
 +                                        return true;
 +                                    }
 +                                    if let Some(ConstValue::Concrete(c)) =
 +                                        parameter.constant(Interner).map(|x| x.data(Interner).value)
 +                                    {
 +                                        if c.interned == ConstScalar::Unknown {
 +                                            return true;
 +                                        }
 +                                    }
 +                                    let default_parameter = match default_parameters.get(i) {
 +                                        Some(x) => x,
 +                                        None => return true,
 +                                    };
 +                                    let actual_default =
 +                                        default_parameter.clone().substitute(Interner, &parameters);
 +                                    parameter != &actual_default
 +                                }
 +                                let mut default_from = 0;
 +                                for (i, parameter) in parameters.iter(Interner).enumerate() {
 +                                    if should_show(parameter, &default_parameters, i, parameters) {
 +                                        default_from = i + 1;
 +                                    }
 +                                }
 +                                &parameters.as_slice(Interner)[0..default_from]
 +                            }
 +                        }
 +                    } else {
 +                        parameters.as_slice(Interner)
 +                    };
 +                    if !parameters_to_write.is_empty() {
 +                        write!(f, "<")?;
 +
 +                        if f.display_target.is_source_code() {
 +                            let mut first = true;
 +                            for generic_arg in parameters_to_write {
 +                                if !first {
 +                                    write!(f, ", ")?;
 +                                }
 +                                first = false;
 +
 +                                if generic_arg.ty(Interner).map(|ty| ty.kind(Interner))
 +                                    == Some(&TyKind::Error)
 +                                {
 +                                    write!(f, "_")?;
 +                                } else {
 +                                    generic_arg.hir_fmt(f)?;
 +                                }
 +                            }
 +                        } else {
 +                            f.write_joined(parameters_to_write, ", ")?;
 +                        }
 +
 +                        write!(f, ">")?;
 +                    }
 +                }
 +            }
 +            TyKind::AssociatedType(assoc_type_id, parameters) => {
 +                let type_alias = from_assoc_type_id(*assoc_type_id);
 +                let trait_ = match type_alias.lookup(f.db.upcast()).container {
 +                    ItemContainerId::TraitId(it) => it,
 +                    _ => panic!("not an associated type"),
 +                };
 +                let trait_ = f.db.trait_data(trait_);
 +                let type_alias_data = f.db.type_alias_data(type_alias);
 +
 +                // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
 +                if f.display_target.is_test() {
 +                    write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
 +                    if parameters.len(Interner) > 0 {
 +                        write!(f, "<")?;
 +                        f.write_joined(&*parameters.as_slice(Interner), ", ")?;
 +                        write!(f, ">")?;
 +                    }
 +                } else {
 +                    let projection_ty = ProjectionTy {
 +                        associated_ty_id: to_assoc_type_id(type_alias),
 +                        substitution: parameters.clone(),
 +                    };
 +
 +                    projection_ty.hir_fmt(f)?;
 +                }
 +            }
 +            TyKind::Foreign(type_alias) => {
 +                let type_alias = f.db.type_alias_data(from_foreign_def_id(*type_alias));
 +                write!(f, "{}", type_alias.name)?;
 +            }
 +            TyKind::OpaqueType(opaque_ty_id, parameters) => {
 +                let impl_trait_id = f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
 +                match impl_trait_id {
 +                    ImplTraitId::ReturnTypeImplTrait(func, idx) => {
 +                        let datas =
 +                            f.db.return_type_impl_traits(func).expect("impl trait id without data");
 +                        let data = (*datas)
 +                            .as_ref()
 +                            .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
 +                        let bounds = data.substitute(Interner, &parameters);
 +                        let krate = func.lookup(f.db.upcast()).module(f.db.upcast()).krate();
 +                        write_bounds_like_dyn_trait_with_prefix(
 +                            "impl",
 +                            bounds.skip_binders(),
 +                            SizedByDefault::Sized { anchor: krate },
 +                            f,
 +                        )?;
 +                        // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
 +                    }
 +                    ImplTraitId::AsyncBlockTypeImplTrait(..) => {
 +                        write!(f, "impl Future<Output = ")?;
 +                        parameters.at(Interner, 0).hir_fmt(f)?;
 +                        write!(f, ">")?;
 +                    }
 +                }
 +            }
 +            TyKind::Closure(.., substs) => {
 +                if f.display_target.is_source_code() {
 +                    return Err(HirDisplayError::DisplaySourceCodeError(
 +                        DisplaySourceCodeError::Closure,
 +                    ));
 +                }
 +                let sig = substs.at(Interner, 0).assert_ty_ref(Interner).callable_sig(f.db);
 +                if let Some(sig) = sig {
 +                    if sig.params().is_empty() {
 +                        write!(f, "||")?;
 +                    } else if f.should_truncate() {
 +                        write!(f, "|{}|", TYPE_HINT_TRUNCATION)?;
 +                    } else {
 +                        write!(f, "|")?;
 +                        f.write_joined(sig.params(), ", ")?;
 +                        write!(f, "|")?;
 +                    };
 +
 +                    write!(f, " -> ")?;
 +                    sig.ret().hir_fmt(f)?;
 +                } else {
 +                    write!(f, "{{closure}}")?;
 +                }
 +            }
 +            TyKind::Placeholder(idx) => {
 +                let id = from_placeholder_idx(f.db, *idx);
 +                let generics = generics(f.db.upcast(), id.parent);
 +                let param_data = &generics.params.type_or_consts[id.local_id];
 +                match param_data {
 +                    TypeOrConstParamData::TypeParamData(p) => match p.provenance {
 +                        TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
 +                            write!(f, "{}", p.name.clone().unwrap_or_else(Name::missing))?
 +                        }
 +                        TypeParamProvenance::ArgumentImplTrait => {
 +                            let substs = generics.placeholder_subst(f.db);
 +                            let bounds =
 +                                f.db.generic_predicates(id.parent)
 +                                    .iter()
 +                                    .map(|pred| pred.clone().substitute(Interner, &substs))
 +                                    .filter(|wc| match &wc.skip_binders() {
 +                                        WhereClause::Implemented(tr) => {
 +                                            &tr.self_type_parameter(Interner) == self
 +                                        }
 +                                        WhereClause::AliasEq(AliasEq {
 +                                            alias: AliasTy::Projection(proj),
 +                                            ty: _,
-                     dyn_ty.bounds.skip_binders().interned(),
++                                        }) => &proj.self_type_parameter(f.db) == self,
 +                                        _ => false,
 +                                    })
 +                                    .collect::<Vec<_>>();
 +                            let krate = id.parent.module(f.db.upcast()).krate();
 +                            write_bounds_like_dyn_trait_with_prefix(
 +                                "impl",
 +                                &bounds,
 +                                SizedByDefault::Sized { anchor: krate },
 +                                f,
 +                            )?;
 +                        }
 +                    },
 +                    TypeOrConstParamData::ConstParamData(p) => {
 +                        write!(f, "{}", p.name)?;
 +                    }
 +                }
 +            }
 +            TyKind::BoundVar(idx) => idx.hir_fmt(f)?,
 +            TyKind::Dyn(dyn_ty) => {
++                // Reorder bounds to satisfy `write_bounds_like_dyn_trait()`'s expectation.
++                // FIXME: `Iterator::partition_in_place()` or `Vec::drain_filter()` may make it
++                // more efficient when either of them hits stable.
++                let mut bounds: SmallVec<[_; 4]> =
++                    dyn_ty.bounds.skip_binders().iter(Interner).cloned().collect();
++                let (auto_traits, others): (SmallVec<[_; 4]>, _) =
++                    bounds.drain(1..).partition(|b| b.skip_binders().trait_id().is_some());
++                bounds.extend(others);
++                bounds.extend(auto_traits);
++
 +                write_bounds_like_dyn_trait_with_prefix(
 +                    "dyn",
++                    &bounds,
 +                    SizedByDefault::NotSized,
 +                    f,
 +                )?;
 +            }
 +            TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
 +            TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
 +                let impl_trait_id = f.db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into());
 +                match impl_trait_id {
 +                    ImplTraitId::ReturnTypeImplTrait(func, idx) => {
 +                        let datas =
 +                            f.db.return_type_impl_traits(func).expect("impl trait id without data");
 +                        let data = (*datas)
 +                            .as_ref()
 +                            .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
 +                        let bounds = data.substitute(Interner, &opaque_ty.substitution);
 +                        let krate = func.lookup(f.db.upcast()).module(f.db.upcast()).krate();
 +                        write_bounds_like_dyn_trait_with_prefix(
 +                            "impl",
 +                            bounds.skip_binders(),
 +                            SizedByDefault::Sized { anchor: krate },
 +                            f,
 +                        )?;
 +                    }
 +                    ImplTraitId::AsyncBlockTypeImplTrait(..) => {
 +                        write!(f, "{{async block}}")?;
 +                    }
 +                };
 +            }
 +            TyKind::Error => {
 +                if f.display_target.is_source_code() {
 +                    return Err(HirDisplayError::DisplaySourceCodeError(
 +                        DisplaySourceCodeError::UnknownType,
 +                    ));
 +                }
 +                write!(f, "{{unknown}}")?;
 +            }
 +            TyKind::InferenceVar(..) => write!(f, "_")?,
 +            TyKind::Generator(_, subst) => {
 +                if f.display_target.is_source_code() {
 +                    return Err(HirDisplayError::DisplaySourceCodeError(
 +                        DisplaySourceCodeError::Generator,
 +                    ));
 +                }
 +
 +                let subst = subst.as_slice(Interner);
 +                let a: Option<SmallVec<[&Ty; 3]>> = subst
 +                    .get(subst.len() - 3..)
 +                    .map(|args| args.iter().map(|arg| arg.ty(Interner)).collect())
 +                    .flatten();
 +
 +                if let Some([resume_ty, yield_ty, ret_ty]) = a.as_deref() {
 +                    write!(f, "|")?;
 +                    resume_ty.hir_fmt(f)?;
 +                    write!(f, "|")?;
 +
 +                    write!(f, " yields ")?;
 +                    yield_ty.hir_fmt(f)?;
 +
 +                    write!(f, " -> ")?;
 +                    ret_ty.hir_fmt(f)?;
 +                } else {
 +                    // This *should* be unreachable, but fallback just in case.
 +                    write!(f, "{{generator}}")?;
 +                }
 +            }
 +            TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
 +        }
 +        Ok(())
 +    }
 +}
 +
 +impl HirDisplay for CallableSig {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        write!(f, "fn(")?;
 +        f.write_joined(self.params(), ", ")?;
 +        if self.is_varargs {
 +            if self.params().is_empty() {
 +                write!(f, "...")?;
 +            } else {
 +                write!(f, ", ...")?;
 +            }
 +        }
 +        write!(f, ")")?;
 +        let ret = self.ret();
 +        if !ret.is_unit() {
 +            write!(f, " -> ")?;
 +            ret.hir_fmt(f)?;
 +        }
 +        Ok(())
 +    }
 +}
 +
 +fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> {
 +    let krate = trait_.lookup(db).container.krate();
 +    utils::fn_traits(db, krate)
 +}
 +
 +#[derive(Clone, Copy, PartialEq, Eq)]
 +pub enum SizedByDefault {
 +    NotSized,
 +    Sized { anchor: CrateId },
 +}
 +
 +impl SizedByDefault {
 +    fn is_sized_trait(self, trait_: TraitId, db: &dyn DefDatabase) -> bool {
 +        match self {
 +            Self::NotSized => false,
 +            Self::Sized { anchor } => {
 +                let sized_trait = db
 +                    .lang_item(anchor, SmolStr::new_inline("sized"))
 +                    .and_then(|lang_item| lang_item.as_trait());
 +                Some(trait_) == sized_trait
 +            }
 +        }
 +    }
 +}
 +
 +pub fn write_bounds_like_dyn_trait_with_prefix(
 +    prefix: &str,
 +    predicates: &[QuantifiedWhereClause],
 +    default_sized: SizedByDefault,
 +    f: &mut HirFormatter<'_>,
 +) -> Result<(), HirDisplayError> {
 +    write!(f, "{}", prefix)?;
 +    if !predicates.is_empty()
 +        || predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
 +    {
 +        write!(f, " ")?;
 +        write_bounds_like_dyn_trait(predicates, default_sized, f)
 +    } else {
 +        Ok(())
 +    }
 +}
 +
 +fn write_bounds_like_dyn_trait(
 +    predicates: &[QuantifiedWhereClause],
 +    default_sized: SizedByDefault,
 +    f: &mut HirFormatter<'_>,
 +) -> Result<(), HirDisplayError> {
 +    // Note: This code is written to produce nice results (i.e.
 +    // corresponding to surface Rust) for types that can occur in
 +    // actual Rust. It will have weird results if the predicates
 +    // aren't as expected (i.e. self types = $0, projection
 +    // predicates for a certain trait come after the Implemented
 +    // predicate for that trait).
 +    let mut first = true;
 +    let mut angle_open = false;
 +    let mut is_fn_trait = false;
 +    let mut is_sized = false;
 +    for p in predicates.iter() {
 +        match p.skip_binders() {
 +            WhereClause::Implemented(trait_ref) => {
 +                let trait_ = trait_ref.hir_trait_id();
 +                if default_sized.is_sized_trait(trait_, f.db.upcast()) {
 +                    is_sized = true;
 +                    if matches!(default_sized, SizedByDefault::Sized { .. }) {
 +                        // Don't print +Sized, but rather +?Sized if absent.
 +                        continue;
 +                    }
 +                }
 +                if !is_fn_trait {
 +                    is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
 +                }
 +                if !is_fn_trait && angle_open {
 +                    write!(f, ">")?;
 +                    angle_open = false;
 +                }
 +                if !first {
 +                    write!(f, " + ")?;
 +                }
 +                // We assume that the self type is ^0.0 (i.e. the
 +                // existential) here, which is the only thing that's
 +                // possible in actual Rust, and hence don't print it
 +                write!(f, "{}", f.db.trait_data(trait_).name)?;
 +                if let [_, params @ ..] = &*trait_ref.substitution.as_slice(Interner) {
 +                    if is_fn_trait {
 +                        if let Some(args) =
 +                            params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple())
 +                        {
 +                            write!(f, "(")?;
 +                            f.write_joined(args.as_slice(Interner), ", ")?;
 +                            write!(f, ")")?;
 +                        }
 +                    } else if !params.is_empty() {
 +                        write!(f, "<")?;
 +                        f.write_joined(params, ", ")?;
 +                        // there might be assoc type bindings, so we leave the angle brackets open
 +                        angle_open = true;
 +                    }
 +                }
 +            }
 +            WhereClause::AliasEq(alias_eq) if is_fn_trait => {
 +                is_fn_trait = false;
 +                if !alias_eq.ty.is_unit() {
 +                    write!(f, " -> ")?;
 +                    alias_eq.ty.hir_fmt(f)?;
 +                }
 +            }
 +            WhereClause::AliasEq(AliasEq { ty, alias }) => {
 +                // in types in actual Rust, these will always come
 +                // after the corresponding Implemented predicate
 +                if angle_open {
 +                    write!(f, ", ")?;
 +                } else {
 +                    write!(f, "<")?;
 +                    angle_open = true;
 +                }
 +                if let AliasTy::Projection(proj) = alias {
 +                    let type_alias =
 +                        f.db.type_alias_data(from_assoc_type_id(proj.associated_ty_id));
 +                    write!(f, "{} = ", type_alias.name)?;
 +                }
 +                ty.hir_fmt(f)?;
 +            }
 +
 +            // FIXME implement these
 +            WhereClause::LifetimeOutlives(_) => {}
 +            WhereClause::TypeOutlives(_) => {}
 +        }
 +        first = false;
 +    }
 +    if angle_open {
 +        write!(f, ">")?;
 +    }
 +    if matches!(default_sized, SizedByDefault::Sized { .. }) {
 +        if !is_sized {
 +            write!(f, "{}?Sized", if first { "" } else { " + " })?;
 +        } else if first {
 +            write!(f, "Sized")?;
 +        }
 +    }
 +    Ok(())
 +}
 +
 +fn fmt_trait_ref(
 +    tr: &TraitRef,
 +    f: &mut HirFormatter<'_>,
 +    use_as: bool,
 +) -> Result<(), HirDisplayError> {
 +    if f.should_truncate() {
 +        return write!(f, "{}", TYPE_HINT_TRUNCATION);
 +    }
 +
 +    tr.self_type_parameter(Interner).hir_fmt(f)?;
 +    if use_as {
 +        write!(f, " as ")?;
 +    } else {
 +        write!(f, ": ")?;
 +    }
 +    write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?;
 +    if tr.substitution.len(Interner) > 1 {
 +        write!(f, "<")?;
 +        f.write_joined(&tr.substitution.as_slice(Interner)[1..], ", ")?;
 +        write!(f, ">")?;
 +    }
 +    Ok(())
 +}
 +
 +impl HirDisplay for TraitRef {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        fmt_trait_ref(self, f, false)
 +    }
 +}
 +
 +impl HirDisplay for WhereClause {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        if f.should_truncate() {
 +            return write!(f, "{}", TYPE_HINT_TRUNCATION);
 +        }
 +
 +        match self {
 +            WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
 +            WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
 +                write!(f, "<")?;
 +                fmt_trait_ref(&projection_ty.trait_ref(f.db), f, true)?;
 +                write!(
 +                    f,
 +                    ">::{} = ",
 +                    f.db.type_alias_data(from_assoc_type_id(projection_ty.associated_ty_id)).name,
 +                )?;
 +                ty.hir_fmt(f)?;
 +            }
 +            WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
 +
 +            // FIXME implement these
 +            WhereClause::TypeOutlives(..) => {}
 +            WhereClause::LifetimeOutlives(..) => {}
 +        }
 +        Ok(())
 +    }
 +}
 +
 +impl HirDisplay for LifetimeOutlives {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        self.a.hir_fmt(f)?;
 +        write!(f, ": ")?;
 +        self.b.hir_fmt(f)
 +    }
 +}
 +
 +impl HirDisplay for Lifetime {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        self.interned().hir_fmt(f)
 +    }
 +}
 +
 +impl HirDisplay for LifetimeData {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        match self {
 +            LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
 +            LifetimeData::InferenceVar(_) => write!(f, "_"),
 +            LifetimeData::Placeholder(idx) => {
 +                let id = lt_from_placeholder_idx(f.db, *idx);
 +                let generics = generics(f.db.upcast(), id.parent);
 +                let param_data = &generics.params.lifetimes[id.local_id];
 +                write!(f, "{}", param_data.name)
 +            }
 +            LifetimeData::Static => write!(f, "'static"),
 +            LifetimeData::Empty(_) => Ok(()),
 +            LifetimeData::Erased => Ok(()),
 +            LifetimeData::Phantom(_, _) => Ok(()),
 +        }
 +    }
 +}
 +
 +impl HirDisplay for DomainGoal {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        match self {
 +            DomainGoal::Holds(wc) => {
 +                write!(f, "Holds(")?;
 +                wc.hir_fmt(f)?;
 +                write!(f, ")")?;
 +            }
 +            _ => write!(f, "?")?,
 +        }
 +        Ok(())
 +    }
 +}
 +
 +pub fn write_visibility(
 +    module_id: ModuleId,
 +    vis: Visibility,
 +    f: &mut HirFormatter<'_>,
 +) -> Result<(), HirDisplayError> {
 +    match vis {
 +        Visibility::Public => write!(f, "pub "),
 +        Visibility::Module(vis_id) => {
 +            let def_map = module_id.def_map(f.db.upcast());
 +            let root_module_id = def_map.module_id(def_map.root());
 +            if vis_id == module_id {
 +                // pub(self) or omitted
 +                Ok(())
 +            } else if root_module_id == vis_id {
 +                write!(f, "pub(crate) ")
 +            } else if module_id.containing_module(f.db.upcast()) == Some(vis_id) {
 +                write!(f, "pub(super) ")
 +            } else {
 +                write!(f, "pub(in ...) ")
 +            }
 +        }
 +    }
 +}
 +
 +impl HirDisplay for TypeRef {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        match self {
 +            TypeRef::Never => write!(f, "!")?,
 +            TypeRef::Placeholder => write!(f, "_")?,
 +            TypeRef::Tuple(elems) => {
 +                write!(f, "(")?;
 +                f.write_joined(elems, ", ")?;
 +                if elems.len() == 1 {
 +                    write!(f, ",")?;
 +                }
 +                write!(f, ")")?;
 +            }
 +            TypeRef::Path(path) => path.hir_fmt(f)?,
 +            TypeRef::RawPtr(inner, mutability) => {
 +                let mutability = match mutability {
 +                    hir_def::type_ref::Mutability::Shared => "*const ",
 +                    hir_def::type_ref::Mutability::Mut => "*mut ",
 +                };
 +                write!(f, "{}", mutability)?;
 +                inner.hir_fmt(f)?;
 +            }
 +            TypeRef::Reference(inner, lifetime, mutability) => {
 +                let mutability = match mutability {
 +                    hir_def::type_ref::Mutability::Shared => "",
 +                    hir_def::type_ref::Mutability::Mut => "mut ",
 +                };
 +                write!(f, "&")?;
 +                if let Some(lifetime) = lifetime {
 +                    write!(f, "{} ", lifetime.name)?;
 +                }
 +                write!(f, "{}", mutability)?;
 +                inner.hir_fmt(f)?;
 +            }
 +            TypeRef::Array(inner, len) => {
 +                write!(f, "[")?;
 +                inner.hir_fmt(f)?;
 +                write!(f, "; {}]", len)?;
 +            }
 +            TypeRef::Slice(inner) => {
 +                write!(f, "[")?;
 +                inner.hir_fmt(f)?;
 +                write!(f, "]")?;
 +            }
 +            TypeRef::Fn(parameters, is_varargs) => {
 +                // FIXME: Function pointer qualifiers.
 +                write!(f, "fn(")?;
 +                if let Some(((_, return_type), function_parameters)) = parameters.split_last() {
 +                    for index in 0..function_parameters.len() {
 +                        let (param_name, param_type) = &function_parameters[index];
 +                        if let Some(name) = param_name {
 +                            write!(f, "{}: ", name)?;
 +                        }
 +
 +                        param_type.hir_fmt(f)?;
 +
 +                        if index != function_parameters.len() - 1 {
 +                            write!(f, ", ")?;
 +                        }
 +                    }
 +                    if *is_varargs {
 +                        write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?;
 +                    }
 +                    write!(f, ")")?;
 +                    match &return_type {
 +                        TypeRef::Tuple(tup) if tup.is_empty() => {}
 +                        _ => {
 +                            write!(f, " -> ")?;
 +                            return_type.hir_fmt(f)?;
 +                        }
 +                    }
 +                }
 +            }
 +            TypeRef::ImplTrait(bounds) => {
 +                write!(f, "impl ")?;
 +                f.write_joined(bounds, " + ")?;
 +            }
 +            TypeRef::DynTrait(bounds) => {
 +                write!(f, "dyn ")?;
 +                f.write_joined(bounds, " + ")?;
 +            }
 +            TypeRef::Macro(macro_call) => {
 +                let macro_call = macro_call.to_node(f.db.upcast());
 +                let ctx = body::LowerCtx::with_hygiene(f.db.upcast(), &Hygiene::new_unhygienic());
 +                match macro_call.path() {
 +                    Some(path) => match Path::from_src(path, &ctx) {
 +                        Some(path) => path.hir_fmt(f)?,
 +                        None => write!(f, "{{macro}}")?,
 +                    },
 +                    None => write!(f, "{{macro}}")?,
 +                }
 +                write!(f, "!(..)")?;
 +            }
 +            TypeRef::Error => write!(f, "{{error}}")?,
 +        }
 +        Ok(())
 +    }
 +}
 +
 +impl HirDisplay for TypeBound {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        match self {
 +            TypeBound::Path(path, modifier) => {
 +                match modifier {
 +                    TraitBoundModifier::None => (),
 +                    TraitBoundModifier::Maybe => write!(f, "?")?,
 +                }
 +                path.hir_fmt(f)
 +            }
 +            TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
 +            TypeBound::ForLifetime(lifetimes, path) => {
 +                write!(f, "for<{}> ", lifetimes.iter().format(", "))?;
 +                path.hir_fmt(f)
 +            }
 +            TypeBound::Error => write!(f, "{{error}}"),
 +        }
 +    }
 +}
 +
 +impl HirDisplay for Path {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        match (self.type_anchor(), self.kind()) {
 +            (Some(anchor), _) => {
 +                write!(f, "<")?;
 +                anchor.hir_fmt(f)?;
 +                write!(f, ">")?;
 +            }
 +            (_, PathKind::Plain) => {}
 +            (_, PathKind::Abs) => {}
 +            (_, PathKind::Crate) => write!(f, "crate")?,
 +            (_, PathKind::Super(0)) => write!(f, "self")?,
 +            (_, PathKind::Super(n)) => {
 +                for i in 0..*n {
 +                    if i > 0 {
 +                        write!(f, "::")?;
 +                    }
 +                    write!(f, "super")?;
 +                }
 +            }
 +            (_, PathKind::DollarCrate(id)) => {
 +                // Resolve `$crate` to the crate's display name.
 +                // FIXME: should use the dependency name instead if available, but that depends on
 +                // the crate invoking `HirDisplay`
 +                let crate_graph = f.db.crate_graph();
 +                let name = crate_graph[*id]
 +                    .display_name
 +                    .as_ref()
 +                    .map(|name| name.canonical_name())
 +                    .unwrap_or("$crate");
 +                write!(f, "{name}")?
 +            }
 +        }
 +
 +        for (seg_idx, segment) in self.segments().iter().enumerate() {
 +            if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 {
 +                write!(f, "::")?;
 +            }
 +            write!(f, "{}", segment.name)?;
 +            if let Some(generic_args) = segment.args_and_bindings {
 +                // We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
 +                // Do we actually format expressions?
 +                if generic_args.desugared_from_fn {
 +                    // First argument will be a tuple, which already includes the parentheses.
 +                    // If the tuple only contains 1 item, write it manually to avoid the trailing `,`.
 +                    if let hir_def::path::GenericArg::Type(TypeRef::Tuple(v)) =
 +                        &generic_args.args[0]
 +                    {
 +                        if v.len() == 1 {
 +                            write!(f, "(")?;
 +                            v[0].hir_fmt(f)?;
 +                            write!(f, ")")?;
 +                        } else {
 +                            generic_args.args[0].hir_fmt(f)?;
 +                        }
 +                    }
 +                    if let Some(ret) = &generic_args.bindings[0].type_ref {
 +                        if !matches!(ret, TypeRef::Tuple(v) if v.is_empty()) {
 +                            write!(f, " -> ")?;
 +                            ret.hir_fmt(f)?;
 +                        }
 +                    }
 +                    return Ok(());
 +                }
 +
 +                write!(f, "<")?;
 +                let mut first = true;
 +                for arg in &generic_args.args {
 +                    if first {
 +                        first = false;
 +                        if generic_args.has_self_type {
 +                            // FIXME: Convert to `<Ty as Trait>` form.
 +                            write!(f, "Self = ")?;
 +                        }
 +                    } else {
 +                        write!(f, ", ")?;
 +                    }
 +                    arg.hir_fmt(f)?;
 +                }
 +                for binding in &generic_args.bindings {
 +                    if first {
 +                        first = false;
 +                    } else {
 +                        write!(f, ", ")?;
 +                    }
 +                    write!(f, "{}", binding.name)?;
 +                    match &binding.type_ref {
 +                        Some(ty) => {
 +                            write!(f, " = ")?;
 +                            ty.hir_fmt(f)?
 +                        }
 +                        None => {
 +                            write!(f, ": ")?;
 +                            f.write_joined(&binding.bounds, " + ")?;
 +                        }
 +                    }
 +                }
 +                write!(f, ">")?;
 +            }
 +        }
 +        Ok(())
 +    }
 +}
 +
 +impl HirDisplay for hir_def::path::GenericArg {
 +    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
 +        match self {
 +            hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
 +            hir_def::path::GenericArg::Const(c) => write!(f, "{}", c),
 +            hir_def::path::GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
 +        }
 +    }
 +}
index 0efff651cc174f91fcdcd5af56d4ab6c10ec07ae,0000000000000000000000000000000000000000..6a5c4966f7ba5ee423b0b62273fa046ba1cbb37b
mode 100644,000000..100644
--- /dev/null
@@@ -1,1143 -1,0 +1,1134 @@@
-     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]))
-     }
 +//! Type inference, i.e. the process of walking through the code and determining
 +//! the type of each expression and pattern.
 +//!
 +//! For type inference, compare the implementations in rustc (the various
 +//! check_* methods in rustc_hir_analysis/check/mod.rs are a good entry point) and
 +//! IntelliJ-Rust (org.rust.lang.core.types.infer). Our entry point for
 +//! inference here is the `infer` function, which infers the types of all
 +//! expressions in a given function.
 +//!
 +//! During inference, types (i.e. the `Ty` struct) can contain type 'variables'
 +//! which represent currently unknown types; as we walk through the expressions,
 +//! we might determine that certain variables need to be equal to each other, or
 +//! to certain types. To record this, we use the union-find implementation from
 +//! the `ena` crate, which is extracted from rustc.
 +
 +use std::ops::Index;
 +use std::sync::Arc;
 +
 +use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
 +use hir_def::{
 +    body::Body,
 +    builtin_type::BuiltinType,
 +    data::{ConstData, StaticData},
 +    expr::{BindingAnnotation, ExprId, PatId},
 +    lang_item::LangItemTarget,
 +    path::{path, Path},
 +    resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
 +    type_ref::TypeRef,
 +    AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule,
 +    ItemContainerId, Lookup, TraitId, TypeAliasId, VariantId,
 +};
 +use hir_expand::name::{name, Name};
 +use itertools::Either;
 +use la_arena::ArenaMap;
 +use rustc_hash::FxHashMap;
 +use stdx::{always, impl_from};
 +
 +use crate::{
 +    db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany,
 +    lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal,
 +    GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, Substitution,
 +    TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
 +};
 +
 +// This lint has a false positive here. See the link below for details.
 +//
 +// https://github.com/rust-lang/rust/issues/57411
 +#[allow(unreachable_pub)]
 +pub use coerce::could_coerce;
 +#[allow(unreachable_pub)]
 +pub use unify::could_unify;
 +
 +pub(crate) mod unify;
 +mod path;
 +mod expr;
 +mod pat;
 +mod coerce;
 +mod closure;
 +
 +/// The entry point of type inference.
 +pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
 +    let _p = profile::span("infer_query");
 +    let resolver = def.resolver(db.upcast());
 +    let body = db.body(def);
 +    let mut ctx = InferenceContext::new(db, def, &body, resolver);
 +
 +    match def {
 +        DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
 +        DefWithBodyId::FunctionId(f) => ctx.collect_fn(f),
 +        DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
 +        DefWithBodyId::VariantId(v) => {
 +            ctx.return_ty = TyBuilder::builtin(match db.enum_data(v.parent).variant_body_type() {
 +                Either::Left(builtin) => BuiltinType::Int(builtin),
 +                Either::Right(builtin) => BuiltinType::Uint(builtin),
 +            });
 +        }
 +    }
 +
 +    ctx.infer_body();
 +
 +    Arc::new(ctx.resolve_all())
 +}
 +
 +/// Fully normalize all the types found within `ty` in context of `owner` body definition.
 +///
 +/// This is appropriate to use only after type-check: it assumes
 +/// that normalization will succeed, for example.
 +pub(crate) fn normalize(db: &dyn HirDatabase, owner: DefWithBodyId, ty: Ty) -> Ty {
 +    if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION) {
 +        return ty;
 +    }
 +    let krate = owner.module(db.upcast()).krate();
 +    let trait_env = owner
 +        .as_generic_def_id()
 +        .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
 +    let mut table = unify::InferenceTable::new(db, trait_env);
 +
 +    let ty_with_vars = table.normalize_associated_types_in(ty);
 +    table.resolve_obligations_as_possible();
 +    table.propagate_diverging_flag();
 +    table.resolve_completely(ty_with_vars)
 +}
 +
 +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 +enum ExprOrPatId {
 +    ExprId(ExprId),
 +    PatId(PatId),
 +}
 +impl_from!(ExprId, PatId for ExprOrPatId);
 +
 +/// Binding modes inferred for patterns.
 +/// <https://doc.rust-lang.org/reference/patterns.html#binding-modes>
 +#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 +pub enum BindingMode {
 +    Move,
 +    Ref(Mutability),
 +}
 +
 +impl BindingMode {
 +    fn convert(annotation: BindingAnnotation) -> BindingMode {
 +        match annotation {
 +            BindingAnnotation::Unannotated | BindingAnnotation::Mutable => BindingMode::Move,
 +            BindingAnnotation::Ref => BindingMode::Ref(Mutability::Not),
 +            BindingAnnotation::RefMut => BindingMode::Ref(Mutability::Mut),
 +        }
 +    }
 +}
 +
 +impl Default for BindingMode {
 +    fn default() -> Self {
 +        BindingMode::Move
 +    }
 +}
 +
 +/// Used to generalize patterns and assignee expressions.
 +trait PatLike: Into<ExprOrPatId> + Copy {
 +    type BindingMode: Copy;
 +
 +    fn infer(
 +        this: &mut InferenceContext<'_>,
 +        id: Self,
 +        expected_ty: &Ty,
 +        default_bm: Self::BindingMode,
 +    ) -> Ty;
 +}
 +
 +impl PatLike for ExprId {
 +    type BindingMode = ();
 +
 +    fn infer(
 +        this: &mut InferenceContext<'_>,
 +        id: Self,
 +        expected_ty: &Ty,
 +        _: Self::BindingMode,
 +    ) -> Ty {
 +        this.infer_assignee_expr(id, expected_ty)
 +    }
 +}
 +
 +impl PatLike for PatId {
 +    type BindingMode = BindingMode;
 +
 +    fn infer(
 +        this: &mut InferenceContext<'_>,
 +        id: Self,
 +        expected_ty: &Ty,
 +        default_bm: Self::BindingMode,
 +    ) -> Ty {
 +        this.infer_pat(id, expected_ty, default_bm)
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub(crate) struct InferOk<T> {
 +    value: T,
 +    goals: Vec<InEnvironment<Goal>>,
 +}
 +
 +impl<T> InferOk<T> {
 +    fn map<U>(self, f: impl FnOnce(T) -> U) -> InferOk<U> {
 +        InferOk { value: f(self.value), goals: self.goals }
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub(crate) struct TypeError;
 +pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
 +
 +#[derive(Debug, PartialEq, Eq, Clone)]
 +pub enum InferenceDiagnostic {
 +    NoSuchField { expr: ExprId },
 +    BreakOutsideOfLoop { expr: ExprId, is_break: bool },
++    IncorrectTryTarget { expr: ExprId },
 +    MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
++    DoesNotImplement { expr: ExprId, trait_: TraitId, ty: Ty },
 +}
 +
 +/// A mismatch between an expected and an inferred type.
 +#[derive(Clone, PartialEq, Eq, Debug, Hash)]
 +pub struct TypeMismatch {
 +    pub expected: Ty,
 +    pub actual: Ty,
 +}
 +
 +#[derive(Clone, PartialEq, Eq, Debug)]
 +struct InternedStandardTypes {
 +    unknown: Ty,
 +    bool_: Ty,
 +    unit: Ty,
 +}
 +
 +impl Default for InternedStandardTypes {
 +    fn default() -> Self {
 +        InternedStandardTypes {
 +            unknown: TyKind::Error.intern(Interner),
 +            bool_: TyKind::Scalar(Scalar::Bool).intern(Interner),
 +            unit: TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner),
 +        }
 +    }
 +}
 +/// Represents coercing a value to a different type of value.
 +///
 +/// We transform values by following a number of `Adjust` steps in order.
 +/// See the documentation on variants of `Adjust` for more details.
 +///
 +/// Here are some common scenarios:
 +///
 +/// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
 +///    Here the pointer will be dereferenced N times (where a dereference can
 +///    happen to raw or borrowed pointers or any smart pointer which implements
 +///    Deref, including Box<_>). The types of dereferences is given by
 +///    `autoderefs`. It can then be auto-referenced zero or one times, indicated
 +///    by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
 +///    `false`.
 +///
 +/// 2. A thin-to-fat coercion involves unsizing the underlying data. We start
 +///    with a thin pointer, deref a number of times, unsize the underlying data,
 +///    then autoref. The 'unsize' phase may change a fixed length array to a
 +///    dynamically sized one, a concrete object to a trait object, or statically
 +///    sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is
 +///    represented by:
 +///
 +///    ```
 +///    Deref(None) -> [i32; 4],
 +///    Borrow(AutoBorrow::Ref) -> &[i32; 4],
 +///    Unsize -> &[i32],
 +///    ```
 +///
 +///    Note that for a struct, the 'deep' unsizing of the struct is not recorded.
 +///    E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
 +///    The autoderef and -ref are the same as in the above example, but the type
 +///    stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
 +///    the underlying conversions from `[i32; 4]` to `[i32]`.
 +///
 +/// 3. Coercing a `Box<T>` to `Box<dyn Trait>` is an interesting special case. In
 +///    that case, we have the pointer we need coming in, so there are no
 +///    autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
 +///    At some point, of course, `Box` should move out of the compiler, in which
 +///    case this is analogous to transforming a struct. E.g., Box<[i32; 4]> ->
 +///    Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`.
 +#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 +pub struct Adjustment {
 +    pub kind: Adjust,
 +    pub target: Ty,
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum Adjust {
 +    /// Go from ! to any type.
 +    NeverToAny,
 +    /// Dereference once, producing a place.
 +    Deref(Option<OverloadedDeref>),
 +    /// Take the address and produce either a `&` or `*` pointer.
 +    Borrow(AutoBorrow),
 +    Pointer(PointerCast),
 +}
 +
 +/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
 +/// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`.
 +/// The target type is `U` in both cases, with the region and mutability
 +/// being those shared by both the receiver and the returned reference.
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct OverloadedDeref(pub Mutability);
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum AutoBorrow {
 +    /// Converts from T to &T.
 +    Ref(Mutability),
 +    /// Converts from T to *T.
 +    RawPtr(Mutability),
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum PointerCast {
 +    /// Go from a fn-item type to a fn-pointer type.
 +    ReifyFnPointer,
 +
 +    /// Go from a safe fn pointer to an unsafe fn pointer.
 +    UnsafeFnPointer,
 +
 +    /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
 +    /// It cannot convert a closure that requires unsafe.
 +    ClosureFnPointer(Safety),
 +
 +    /// Go from a mut raw pointer to a const raw pointer.
 +    MutToConstPointer,
 +
 +    #[allow(dead_code)]
 +    /// Go from `*const [T; N]` to `*const T`
 +    ArrayToPointer,
 +
 +    /// Unsize a pointer/reference value, e.g., `&[T; n]` to
 +    /// `&[T]`. Note that the source could be a thin or fat pointer.
 +    /// This will do things like convert thin pointers to fat
 +    /// pointers, or convert structs containing thin pointers to
 +    /// structs containing fat pointers, or convert between fat
 +    /// pointers. We don't store the details of how the transform is
 +    /// done (in fact, we don't know that, because it might depend on
 +    /// the precise type parameters). We just store the target
 +    /// type. Codegen backends and miri figure out what has to be done
 +    /// based on the precise source/target type at hand.
 +    Unsize,
 +}
 +
 +/// The result of type inference: A mapping from expressions and patterns to types.
 +#[derive(Clone, PartialEq, Eq, Debug, Default)]
 +pub struct InferenceResult {
 +    /// For each method call expr, records the function it resolves to.
 +    method_resolutions: FxHashMap<ExprId, (FunctionId, Substitution)>,
 +    /// For each field access expr, records the field it resolves to.
 +    field_resolutions: FxHashMap<ExprId, FieldId>,
 +    /// For each struct literal or pattern, records the variant it resolves to.
 +    variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
 +    /// For each associated item record what it resolves to
 +    assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
 +    pub diagnostics: Vec<InferenceDiagnostic>,
 +    pub type_of_expr: ArenaMap<ExprId, Ty>,
 +    /// For each pattern record the type it resolves to.
 +    ///
 +    /// **Note**: When a pattern type is resolved it may still contain
 +    /// unresolved or missing subpatterns or subpatterns of mismatched types.
 +    pub type_of_pat: ArenaMap<PatId, Ty>,
 +    type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
 +    /// Interned common types to return references to.
 +    standard_types: InternedStandardTypes,
 +    /// Stores the types which were implicitly dereferenced in pattern binding modes.
 +    pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
 +    pub pat_binding_modes: FxHashMap<PatId, BindingMode>,
 +    pub expr_adjustments: FxHashMap<ExprId, Vec<Adjustment>>,
 +}
 +
 +impl InferenceResult {
 +    pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> {
 +        self.method_resolutions.get(&expr).cloned()
 +    }
 +    pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> {
 +        self.field_resolutions.get(&expr).copied()
 +    }
 +    pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> {
 +        self.variant_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
 +        self.variant_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<AssocItemId> {
 +        self.assoc_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<AssocItemId> {
 +        self.assoc_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
 +        self.type_mismatches.get(&expr.into())
 +    }
 +    pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch> {
 +        self.type_mismatches.get(&pat.into())
 +    }
 +    pub fn expr_type_mismatches(&self) -> impl Iterator<Item = (ExprId, &TypeMismatch)> {
 +        self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat {
 +            ExprOrPatId::ExprId(expr) => Some((expr, mismatch)),
 +            _ => None,
 +        })
 +    }
 +    pub fn pat_type_mismatches(&self) -> impl Iterator<Item = (PatId, &TypeMismatch)> {
 +        self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat {
 +            ExprOrPatId::PatId(pat) => Some((pat, mismatch)),
 +            _ => None,
 +        })
 +    }
 +}
 +
 +impl Index<ExprId> for InferenceResult {
 +    type Output = Ty;
 +
 +    fn index(&self, expr: ExprId) -> &Ty {
 +        self.type_of_expr.get(expr).unwrap_or(&self.standard_types.unknown)
 +    }
 +}
 +
 +impl Index<PatId> for InferenceResult {
 +    type Output = Ty;
 +
 +    fn index(&self, pat: PatId) -> &Ty {
 +        self.type_of_pat.get(pat).unwrap_or(&self.standard_types.unknown)
 +    }
 +}
 +
 +/// The inference context contains all information needed during type inference.
 +#[derive(Clone, Debug)]
 +pub(crate) struct InferenceContext<'a> {
 +    pub(crate) db: &'a dyn HirDatabase,
 +    pub(crate) owner: DefWithBodyId,
 +    pub(crate) body: &'a Body,
 +    pub(crate) resolver: Resolver,
 +    table: unify::InferenceTable<'a>,
 +    trait_env: Arc<TraitEnvironment>,
 +    pub(crate) result: InferenceResult,
 +    /// The return type of the function being inferred, the closure or async block if we're
 +    /// currently within one.
 +    ///
 +    /// We might consider using a nested inference context for checking
 +    /// closures, but currently this is the only field that will change there,
 +    /// so it doesn't make sense.
 +    return_ty: Ty,
 +    /// The resume type and the yield type, respectively, of the generator being inferred.
 +    resume_yield_tys: Option<(Ty, Ty)>,
 +    diverges: Diverges,
 +    breakables: Vec<BreakableContext>,
 +}
 +
 +#[derive(Clone, Debug)]
 +struct BreakableContext {
 +    /// Whether this context contains at least one break expression.
 +    may_break: bool,
 +    /// The coercion target of the context.
 +    coerce: CoerceMany,
 +    /// The optional label of the context.
 +    label: Option<name::Name>,
 +    kind: BreakableKind,
 +}
 +
 +#[derive(Clone, Debug)]
 +enum BreakableKind {
 +    Block,
 +    Loop,
 +    /// A border is something like an async block, closure etc. Anything that prevents
 +    /// breaking/continuing through
 +    Border,
 +}
 +
 +fn find_breakable<'c>(
 +    ctxs: &'c mut [BreakableContext],
 +    label: Option<&name::Name>,
 +) -> Option<&'c mut BreakableContext> {
 +    let mut ctxs = ctxs
 +        .iter_mut()
 +        .rev()
 +        .take_while(|it| matches!(it.kind, BreakableKind::Block | BreakableKind::Loop));
 +    match label {
 +        Some(_) => ctxs.find(|ctx| ctx.label.as_ref() == label),
 +        None => ctxs.find(|ctx| matches!(ctx.kind, BreakableKind::Loop)),
 +    }
 +}
 +
 +fn find_continuable<'c>(
 +    ctxs: &'c mut [BreakableContext],
 +    label: Option<&name::Name>,
 +) -> Option<&'c mut BreakableContext> {
 +    match label {
 +        Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)),
 +        None => find_breakable(ctxs, label),
 +    }
 +}
 +
 +impl<'a> InferenceContext<'a> {
 +    fn new(
 +        db: &'a dyn HirDatabase,
 +        owner: DefWithBodyId,
 +        body: &'a Body,
 +        resolver: Resolver,
 +    ) -> Self {
 +        let krate = owner.module(db.upcast()).krate();
 +        let trait_env = owner
 +            .as_generic_def_id()
 +            .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
 +        InferenceContext {
 +            result: InferenceResult::default(),
 +            table: unify::InferenceTable::new(db, trait_env.clone()),
 +            trait_env,
 +            return_ty: TyKind::Error.intern(Interner), // set in collect_fn_signature
 +            resume_yield_tys: None,
 +            db,
 +            owner,
 +            body,
 +            resolver,
 +            diverges: Diverges::Maybe,
 +            breakables: Vec::new(),
 +        }
 +    }
 +
 +    fn resolve_all(self) -> InferenceResult {
 +        let InferenceContext { mut table, mut result, .. } = self;
 +
 +        // FIXME resolve obligations as well (use Guidance if necessary)
 +        table.resolve_obligations_as_possible();
 +
 +        // make sure diverging type variables are marked as such
 +        table.propagate_diverging_flag();
 +        for ty in result.type_of_expr.values_mut() {
 +            *ty = table.resolve_completely(ty.clone());
 +        }
 +        for ty in result.type_of_pat.values_mut() {
 +            *ty = table.resolve_completely(ty.clone());
 +        }
 +        for mismatch in result.type_mismatches.values_mut() {
 +            mismatch.expected = table.resolve_completely(mismatch.expected.clone());
 +            mismatch.actual = table.resolve_completely(mismatch.actual.clone());
 +        }
 +        for (_, subst) in result.method_resolutions.values_mut() {
 +            *subst = table.resolve_completely(subst.clone());
 +        }
 +        for adjustment in result.expr_adjustments.values_mut().flatten() {
 +            adjustment.target = table.resolve_completely(adjustment.target.clone());
 +        }
 +        for adjustment in result.pat_adjustments.values_mut().flatten() {
 +            *adjustment = table.resolve_completely(adjustment.clone());
 +        }
 +        result
 +    }
 +
 +    fn collect_const(&mut self, data: &ConstData) {
 +        self.return_ty = self.make_ty(&data.type_ref);
 +    }
 +
 +    fn collect_static(&mut self, data: &StaticData) {
 +        self.return_ty = self.make_ty(&data.type_ref);
 +    }
 +
 +    fn collect_fn(&mut self, func: FunctionId) {
 +        let data = self.db.function_data(func);
 +        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
 +            .with_impl_trait_mode(ImplTraitLoweringMode::Param);
 +        let param_tys =
 +            data.params.iter().map(|(_, type_ref)| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
 +        for (ty, pat) in param_tys.into_iter().zip(self.body.params.iter()) {
 +            let ty = self.insert_type_vars(ty);
 +            let ty = self.normalize_associated_types_in(ty);
 +
 +            self.infer_pat(*pat, &ty, BindingMode::default());
 +        }
 +        let error_ty = &TypeRef::Error;
 +        let return_ty = if data.has_async_kw() {
 +            data.async_ret_type.as_deref().unwrap_or(error_ty)
 +        } else {
 +            &*data.ret_type
 +        };
 +        let return_ty = self.make_ty_with_mode(return_ty, ImplTraitLoweringMode::Opaque);
 +        self.return_ty = return_ty;
 +
 +        if let Some(rpits) = self.db.return_type_impl_traits(func) {
 +            // RPIT opaque types use substitution of their parent function.
 +            let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
 +            self.return_ty = fold_tys(
 +                self.return_ty.clone(),
 +                |ty, _| {
 +                    let opaque_ty_id = match ty.kind(Interner) {
 +                        TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id,
 +                        _ => return ty,
 +                    };
 +                    let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
 +                        ImplTraitId::ReturnTypeImplTrait(_, idx) => idx,
 +                        _ => unreachable!(),
 +                    };
 +                    let bounds = (*rpits).map_ref(|rpits| {
 +                        rpits.impl_traits[idx as usize].bounds.map_ref(|it| it.into_iter())
 +                    });
 +                    let var = self.table.new_type_var();
 +                    let var_subst = Substitution::from1(Interner, var.clone());
 +                    for bound in bounds {
 +                        let predicate =
 +                            bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders);
 +                        let (var_predicate, binders) = predicate
 +                            .substitute(Interner, &var_subst)
 +                            .into_value_and_skipped_binders();
 +                        always!(binders.len(Interner) == 0); // quantified where clauses not yet handled
 +                        self.push_obligation(var_predicate.cast(Interner));
 +                    }
 +                    var
 +                },
 +                DebruijnIndex::INNERMOST,
 +            );
 +        }
 +    }
 +
 +    fn infer_body(&mut self) {
 +        self.infer_expr_coerce(self.body.body_expr, &Expectation::has_type(self.return_ty.clone()));
 +    }
 +
 +    fn write_expr_ty(&mut self, expr: ExprId, ty: Ty) {
 +        self.result.type_of_expr.insert(expr, ty);
 +    }
 +
 +    fn write_expr_adj(&mut self, expr: ExprId, adjustments: Vec<Adjustment>) {
 +        self.result.expr_adjustments.insert(expr, adjustments);
 +    }
 +
 +    fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) {
 +        self.result.method_resolutions.insert(expr, (func, subst));
 +    }
 +
 +    fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantId) {
 +        self.result.variant_resolutions.insert(id, variant);
 +    }
 +
 +    fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId) {
 +        self.result.assoc_resolutions.insert(id, item);
 +    }
 +
 +    fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
 +        self.result.type_of_pat.insert(pat, ty);
 +    }
 +
 +    fn push_diagnostic(&mut self, diagnostic: InferenceDiagnostic) {
 +        self.result.diagnostics.push(diagnostic);
 +    }
 +
 +    fn make_ty_with_mode(
 +        &mut self,
 +        type_ref: &TypeRef,
 +        impl_trait_mode: ImplTraitLoweringMode,
 +    ) -> Ty {
 +        // FIXME use right resolver for block
 +        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
 +            .with_impl_trait_mode(impl_trait_mode);
 +        let ty = ctx.lower_ty(type_ref);
 +        let ty = self.insert_type_vars(ty);
 +        self.normalize_associated_types_in(ty)
 +    }
 +
 +    fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
 +        self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed)
 +    }
 +
 +    fn err_ty(&self) -> Ty {
 +        self.result.standard_types.unknown.clone()
 +    }
 +
 +    /// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it.
 +    fn insert_const_vars_shallow(&mut self, c: Const) -> Const {
 +        let data = c.data(Interner);
 +        match data.value {
 +            ConstValue::Concrete(cc) => match cc.interned {
 +                hir_def::type_ref::ConstScalar::Unknown => {
 +                    self.table.new_const_var(data.ty.clone())
 +                }
 +                _ => c,
 +            },
 +            _ => c,
 +        }
 +    }
 +
 +    /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
 +    fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
 +        match ty.kind(Interner) {
 +            TyKind::Error => self.table.new_type_var(),
 +            TyKind::InferenceVar(..) => {
 +                let ty_resolved = self.resolve_ty_shallow(&ty);
 +                if ty_resolved.is_unknown() {
 +                    self.table.new_type_var()
 +                } else {
 +                    ty
 +                }
 +            }
 +            _ => ty,
 +        }
 +    }
 +
 +    fn insert_type_vars(&mut self, ty: Ty) -> Ty {
 +        fold_tys_and_consts(
 +            ty,
 +            |x, _| match x {
 +                Either::Left(ty) => Either::Left(self.insert_type_vars_shallow(ty)),
 +                Either::Right(c) => Either::Right(self.insert_const_vars_shallow(c)),
 +            },
 +            DebruijnIndex::INNERMOST,
 +        )
 +    }
 +
 +    fn push_obligation(&mut self, o: DomainGoal) {
 +        self.table.register_obligation(o.cast(Interner));
 +    }
 +
 +    fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
 +        self.table.unify(ty1, ty2)
 +    }
 +
 +    /// Recurses through the given type, normalizing associated types mentioned
 +    /// in it by replacing them by type variables and registering obligations to
 +    /// resolve later. This should be done once for every type we get from some
 +    /// type annotation (e.g. from a let type annotation, field type or function
 +    /// call). `make_ty` handles this already, but e.g. for field types we need
 +    /// to do it as well.
 +    fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
 +        self.table.normalize_associated_types_in(ty)
 +    }
 +
 +    fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
 +        self.table.resolve_ty_shallow(ty)
 +    }
 +
 +    fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty {
 +        self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[])
 +    }
 +
 +    fn resolve_associated_type_with_params(
 +        &mut self,
 +        inner_ty: Ty,
 +        assoc_ty: Option<TypeAliasId>,
 +        // FIXME(GATs): these are args for the trait ref, args for assoc type itself should be
 +        // handled when we support them.
 +        params: &[GenericArg],
 +    ) -> Ty {
 +        match assoc_ty {
 +            Some(res_assoc_ty) => {
 +                let trait_ = match res_assoc_ty.lookup(self.db.upcast()).container {
 +                    hir_def::ItemContainerId::TraitId(trait_) => trait_,
 +                    _ => panic!("resolve_associated_type called with non-associated type"),
 +                };
 +                let ty = self.table.new_type_var();
 +                let mut param_iter = params.iter().cloned();
 +                let trait_ref = TyBuilder::trait_ref(self.db, trait_)
 +                    .push(inner_ty)
 +                    .fill(|_| param_iter.next().unwrap())
 +                    .build();
 +                let alias_eq = AliasEq {
 +                    alias: AliasTy::Projection(ProjectionTy {
 +                        associated_ty_id: to_assoc_type_id(res_assoc_ty),
 +                        substitution: trait_ref.substitution.clone(),
 +                    }),
 +                    ty: ty.clone(),
 +                };
 +                self.push_obligation(trait_ref.cast(Interner));
 +                self.push_obligation(alias_eq.cast(Interner));
 +                ty
 +            }
 +            None => self.err_ty(),
 +        }
 +    }
 +
 +    fn resolve_variant(&mut self, path: Option<&Path>, value_ns: bool) -> (Ty, Option<VariantId>) {
 +        let path = match path {
 +            Some(path) => path,
 +            None => return (self.err_ty(), None),
 +        };
 +        let resolver = &self.resolver;
 +        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
 +        // FIXME: this should resolve assoc items as well, see this example:
 +        // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
 +        let (resolution, unresolved) = if value_ns {
 +            match resolver.resolve_path_in_value_ns(self.db.upcast(), path.mod_path()) {
 +                Some(ResolveValueResult::ValueNs(value)) => match value {
 +                    ValueNs::EnumVariantId(var) => {
 +                        let substs = ctx.substs_from_path(path, var.into(), true);
 +                        let ty = self.db.ty(var.parent.into());
 +                        let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                        return (ty, Some(var.into()));
 +                    }
 +                    ValueNs::StructId(strukt) => {
 +                        let substs = ctx.substs_from_path(path, strukt.into(), true);
 +                        let ty = self.db.ty(strukt.into());
 +                        let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                        return (ty, Some(strukt.into()));
 +                    }
 +                    ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
 +                    _ => return (self.err_ty(), None),
 +                },
 +                Some(ResolveValueResult::Partial(typens, unresolved)) => (typens, Some(unresolved)),
 +                None => return (self.err_ty(), None),
 +            }
 +        } else {
 +            match resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
 +                Some(it) => it,
 +                None => return (self.err_ty(), None),
 +            }
 +        };
 +        return match resolution {
 +            TypeNs::AdtId(AdtId::StructId(strukt)) => {
 +                let substs = ctx.substs_from_path(path, strukt.into(), true);
 +                let ty = self.db.ty(strukt.into());
 +                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
 +            }
 +            TypeNs::AdtId(AdtId::UnionId(u)) => {
 +                let substs = ctx.substs_from_path(path, u.into(), true);
 +                let ty = self.db.ty(u.into());
 +                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                forbid_unresolved_segments((ty, Some(u.into())), unresolved)
 +            }
 +            TypeNs::EnumVariantId(var) => {
 +                let substs = ctx.substs_from_path(path, var.into(), true);
 +                let ty = self.db.ty(var.parent.into());
 +                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                forbid_unresolved_segments((ty, Some(var.into())), unresolved)
 +            }
 +            TypeNs::SelfType(impl_id) => {
 +                let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
 +                let substs = generics.placeholder_subst(self.db);
 +                let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
 +                self.resolve_variant_on_alias(ty, unresolved, path)
 +            }
 +            TypeNs::TypeAliasId(it) => {
 +                let container = it.lookup(self.db.upcast()).container;
 +                let parent_subst = match container {
 +                    ItemContainerId::TraitId(id) => {
 +                        let subst = TyBuilder::subst_for_def(self.db, id, None)
 +                            .fill_with_inference_vars(&mut self.table)
 +                            .build();
 +                        Some(subst)
 +                    }
 +                    // Type aliases do not exist in impls.
 +                    _ => None,
 +                };
 +                let ty = TyBuilder::def_ty(self.db, it.into(), parent_subst)
 +                    .fill_with_inference_vars(&mut self.table)
 +                    .build();
 +                self.resolve_variant_on_alias(ty, unresolved, path)
 +            }
 +            TypeNs::AdtSelfType(_) => {
 +                // FIXME this could happen in array size expressions, once we're checking them
 +                (self.err_ty(), None)
 +            }
 +            TypeNs::GenericParam(_) => {
 +                // FIXME potentially resolve assoc type
 +                (self.err_ty(), None)
 +            }
 +            TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::TraitId(_) => {
 +                // FIXME diagnostic
 +                (self.err_ty(), None)
 +            }
 +        };
 +
 +        fn forbid_unresolved_segments(
 +            result: (Ty, Option<VariantId>),
 +            unresolved: Option<usize>,
 +        ) -> (Ty, Option<VariantId>) {
 +            if unresolved.is_none() {
 +                result
 +            } else {
 +                // FIXME diagnostic
 +                (TyKind::Error.intern(Interner), None)
 +            }
 +        }
 +    }
 +
 +    fn resolve_variant_on_alias(
 +        &mut self,
 +        ty: Ty,
 +        unresolved: Option<usize>,
 +        path: &Path,
 +    ) -> (Ty, Option<VariantId>) {
 +        let remaining = unresolved.map(|x| path.segments().skip(x).len()).filter(|x| x > &0);
 +        match remaining {
 +            None => {
 +                let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id {
 +                    AdtId::StructId(s) => Some(VariantId::StructId(s)),
 +                    AdtId::UnionId(u) => Some(VariantId::UnionId(u)),
 +                    AdtId::EnumId(_) => {
 +                        // FIXME Error E0071, expected struct, variant or union type, found enum `Foo`
 +                        None
 +                    }
 +                });
 +                (ty, variant)
 +            }
 +            Some(1) => {
 +                let segment = path.mod_path().segments().last().unwrap();
 +                // this could be an enum variant or associated type
 +                if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
 +                    let enum_data = self.db.enum_data(enum_id);
 +                    if let Some(local_id) = enum_data.variant(segment) {
 +                        let variant = EnumVariantId { parent: enum_id, local_id };
 +                        return (ty, Some(variant.into()));
 +                    }
 +                }
 +                // FIXME potentially resolve assoc type
 +                (self.err_ty(), None)
 +            }
 +            Some(_) => {
 +                // FIXME diagnostic
 +                (self.err_ty(), None)
 +            }
 +        }
 +    }
 +
 +    fn resolve_lang_item(&self, name: Name) -> Option<LangItemTarget> {
 +        let krate = self.resolver.krate();
 +        self.db.lang_item(krate, name.to_smol_str())
 +    }
 +
 +    fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
 +        let path = path![core::iter::IntoIterator];
 +        let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![IntoIter])
 +    }
 +
 +    fn resolve_iterator_item(&self) -> Option<TypeAliasId> {
 +        let path = path![core::iter::Iterator];
 +        let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Item])
 +    }
 +
 +    fn resolve_ops_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 f56108b26c45bdaea3096f4616828c28ba260d12,0000000000000000000000000000000000000000..59ab50d0717ba6d5050e28c533f3c3543a881740
mode 100644,000000..100644
--- /dev/null
@@@ -1,1533 -1,0 +1,1616 @@@
- use hir_expand::name::Name;
 +//! Type inference for expressions.
 +
 +use std::{
 +    collections::hash_map::Entry,
 +    iter::{repeat, repeat_with},
 +    mem,
 +};
 +
 +use chalk_ir::{
 +    cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
 +};
 +use hir_def::{
 +    expr::{
 +        ArithOp, Array, BinaryOp, ClosureKind, CmpOp, Expr, ExprId, LabelId, Literal, Statement,
 +        UnaryOp,
 +    },
 +    generics::TypeOrConstParamData,
 +    path::{GenericArg, GenericArgs},
 +    resolver::resolver_for_expr,
 +    ConstParamId, FieldId, ItemContainerId, Lookup,
 +};
-     infer::{coerce::CoerceMany, find_continuable, BreakableKind},
++use hir_expand::{name, name::Name};
 +use stdx::always;
 +use syntax::ast::RangeOp;
 +
 +use crate::{
 +    autoderef::{self, Autoderef},
 +    consteval,
-     static_lifetime, to_chalk_trait_id,
++    infer::{coerce::CoerceMany, find_continuable, path, BreakableKind},
 +    lower::{
 +        const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
 +    },
 +    mapping::{from_chalk, ToChalk},
 +    method_resolution::{self, lang_names_for_bin_op, VisibleFromModule},
 +    primitive::{self, UintTy},
-     AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar,
-     Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
++    static_lifetime, to_assoc_type_id, to_chalk_trait_id,
 +    utils::{generics, Generics},
-             Expr::Try { expr } => {
-                 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
-                 self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok())
++    AdtId, AliasEq, AliasTy, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner,
++    ProjectionTy, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
 +};
 +
 +use super::{
 +    coerce::auto_deref_adjust_steps, find_breakable, BindingMode, BreakableContext, Diverges,
 +    Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch,
 +};
 +
 +impl<'a> InferenceContext<'a> {
 +    pub(crate) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
 +        let ty = self.infer_expr_inner(tgt_expr, expected);
 +        if let Some(expected_ty) = expected.only_has_type(&mut self.table) {
 +            let could_unify = self.unify(&ty, &expected_ty);
 +            if !could_unify {
 +                self.result.type_mismatches.insert(
 +                    tgt_expr.into(),
 +                    TypeMismatch { expected: expected_ty, actual: ty.clone() },
 +                );
 +            }
 +        }
 +        ty
 +    }
 +
 +    /// Infer type of expression with possibly implicit coerce to the expected type.
 +    /// Return the type after possible coercion.
 +    pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
 +        let ty = self.infer_expr_inner(expr, expected);
 +        if let Some(target) = expected.only_has_type(&mut self.table) {
 +            match self.coerce(Some(expr), &ty, &target) {
 +                Ok(res) => res,
 +                Err(_) => {
 +                    self.result.type_mismatches.insert(
 +                        expr.into(),
 +                        TypeMismatch { expected: target.clone(), actual: ty.clone() },
 +                    );
 +                    target
 +                }
 +            }
 +        } else {
 +            ty
 +        }
 +    }
 +
 +    fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
 +        self.db.unwind_if_cancelled();
 +
 +        let ty = match &self.body[tgt_expr] {
 +            Expr::Missing => self.err_ty(),
 +            &Expr::If { condition, then_branch, else_branch } => {
 +                self.infer_expr(
 +                    condition,
 +                    &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
 +                );
 +
 +                let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
 +                let mut both_arms_diverge = Diverges::Always;
 +
 +                let result_ty = self.table.new_type_var();
 +                let then_ty = self.infer_expr_inner(then_branch, expected);
 +                both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe);
 +                let mut coerce = CoerceMany::new(result_ty);
 +                coerce.coerce(self, Some(then_branch), &then_ty);
 +                let else_ty = match else_branch {
 +                    Some(else_branch) => self.infer_expr_inner(else_branch, expected),
 +                    None => TyBuilder::unit(),
 +                };
 +                both_arms_diverge &= self.diverges;
 +                // FIXME: create a synthetic `else {}` so we have something to refer to here instead of None?
 +                coerce.coerce(self, else_branch, &else_ty);
 +
 +                self.diverges = condition_diverges | both_arms_diverge;
 +
 +                coerce.complete()
 +            }
 +            &Expr::Let { pat, expr } => {
 +                let input_ty = self.infer_expr(expr, &Expectation::none());
 +                self.infer_pat(pat, &input_ty, BindingMode::default());
 +                TyKind::Scalar(Scalar::Bool).intern(Interner)
 +            }
 +            Expr::Block { statements, tail, label, id: _ } => {
 +                let old_resolver = mem::replace(
 +                    &mut self.resolver,
 +                    resolver_for_expr(self.db.upcast(), self.owner, tgt_expr),
 +                );
 +                let ty = match label {
 +                    Some(_) => {
 +                        let break_ty = self.table.new_type_var();
 +                        let (breaks, ty) = self.with_breakable_ctx(
 +                            BreakableKind::Block,
 +                            break_ty.clone(),
 +                            *label,
 +                            |this| {
 +                                this.infer_block(
 +                                    tgt_expr,
 +                                    statements,
 +                                    *tail,
 +                                    &Expectation::has_type(break_ty),
 +                                )
 +                            },
 +                        );
 +                        breaks.unwrap_or(ty)
 +                    }
 +                    None => self.infer_block(tgt_expr, statements, *tail, expected),
 +                };
 +                self.resolver = old_resolver;
 +                ty
 +            }
 +            Expr::Unsafe { body } => self.infer_expr(*body, expected),
 +            Expr::Const { body } => {
 +                self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
 +                    this.infer_expr(*body, expected)
 +                })
 +                .1
 +            }
 +            Expr::TryBlock { body } => {
 +                self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
 +                    let _inner = this.infer_expr(*body, expected);
 +                });
 +                // FIXME should be std::result::Result<{inner}, _>
 +                self.err_ty()
 +            }
 +            Expr::Async { body } => {
 +                let ret_ty = self.table.new_type_var();
 +                let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
 +                let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
 +
 +                let (_, inner_ty) =
 +                    self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
 +                        this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty))
 +                    });
 +
 +                self.diverges = prev_diverges;
 +                self.return_ty = prev_ret_ty;
 +
 +                // Use the first type parameter as the output type of future.
 +                // existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
 +                let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
 +                let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
 +                TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty))
 +                    .intern(Interner)
 +            }
 +            &Expr::Loop { body, label } => {
 +                let ty = self.table.new_type_var();
 +                let (breaks, ()) =
 +                    self.with_breakable_ctx(BreakableKind::Loop, ty, label, |this| {
 +                        this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
 +                    });
 +
 +                match breaks {
 +                    Some(breaks) => {
 +                        self.diverges = Diverges::Maybe;
 +                        breaks
 +                    }
 +                    None => TyKind::Never.intern(Interner),
 +                }
 +            }
 +            &Expr::While { condition, body, label } => {
 +                self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
 +                    this.infer_expr(
 +                        condition,
 +                        &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
 +                    );
 +                    this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
 +                });
 +
 +                // the body may not run, so it diverging doesn't mean we diverge
 +                self.diverges = Diverges::Maybe;
 +                TyBuilder::unit()
 +            }
 +            &Expr::For { iterable, body, pat, label } => {
 +                let iterable_ty = self.infer_expr(iterable, &Expectation::none());
 +                let into_iter_ty =
 +                    self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
 +                let pat_ty =
 +                    self.resolve_associated_type(into_iter_ty, self.resolve_iterator_item());
 +
 +                self.infer_pat(pat, &pat_ty, BindingMode::default());
 +                self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
 +                    this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
 +                });
 +
 +                // the body may not run, so it diverging doesn't mean we diverge
 +                self.diverges = Diverges::Maybe;
 +                TyBuilder::unit()
 +            }
 +            Expr::Closure { body, args, ret_type, arg_types, closure_kind } => {
 +                assert_eq!(args.len(), arg_types.len());
 +
 +                let mut sig_tys = Vec::new();
 +
 +                // collect explicitly written argument types
 +                for arg_type in arg_types.iter() {
 +                    let arg_ty = match arg_type {
 +                        Some(type_ref) => self.make_ty(type_ref),
 +                        None => self.table.new_type_var(),
 +                    };
 +                    sig_tys.push(arg_ty);
 +                }
 +
 +                // add return type
 +                let ret_ty = match ret_type {
 +                    Some(type_ref) => self.make_ty(type_ref),
 +                    None => self.table.new_type_var(),
 +                };
 +                sig_tys.push(ret_ty.clone());
 +                let sig_ty = TyKind::Function(FnPointer {
 +                    num_binders: 0,
 +                    sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false },
 +                    substitution: FnSubst(
 +                        Substitution::from_iter(Interner, sig_tys.clone()).shifted_in(Interner),
 +                    ),
 +                })
 +                .intern(Interner);
 +
 +                let (ty, resume_yield_tys) = if matches!(closure_kind, ClosureKind::Generator(_)) {
 +                    // FIXME: report error when there are more than 1 parameter.
 +                    let resume_ty = match sig_tys.first() {
 +                        // When `sig_tys.len() == 1` the first type is the return type, not the
 +                        // first parameter type.
 +                        Some(ty) if sig_tys.len() > 1 => ty.clone(),
 +                        _ => self.result.standard_types.unit.clone(),
 +                    };
 +                    let yield_ty = self.table.new_type_var();
 +
 +                    let subst = TyBuilder::subst_for_generator(self.db, self.owner)
 +                        .push(resume_ty.clone())
 +                        .push(yield_ty.clone())
 +                        .push(ret_ty.clone())
 +                        .build();
 +
 +                    let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
 +                    let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
 +
 +                    (generator_ty, Some((resume_ty, yield_ty)))
 +                } else {
 +                    let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
 +                    let closure_ty =
 +                        TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
 +                            .intern(Interner);
 +
 +                    (closure_ty, None)
 +                };
 +
 +                // Eagerly try to relate the closure type with the expected
 +                // type, otherwise we often won't have enough information to
 +                // infer the body.
 +                self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected);
 +
 +                // Now go through the argument patterns
 +                for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
 +                    self.infer_pat(*arg_pat, &arg_ty, BindingMode::default());
 +                }
 +
 +                let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
 +                let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
 +                let prev_resume_yield_tys =
 +                    mem::replace(&mut self.resume_yield_tys, resume_yield_tys);
 +
 +                self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
 +                    this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
 +                });
 +
 +                self.diverges = prev_diverges;
 +                self.return_ty = prev_ret_ty;
 +                self.resume_yield_tys = prev_resume_yield_tys;
 +
 +                ty
 +            }
 +            Expr::Call { callee, args, .. } => {
 +                let callee_ty = self.infer_expr(*callee, &Expectation::none());
 +                let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone());
 +                let mut res = None;
 +                let mut derefed_callee = callee_ty.clone();
 +                // manual loop to be able to access `derefs.table`
 +                while let Some((callee_deref_ty, _)) = derefs.next() {
 +                    res = derefs.table.callable_sig(&callee_deref_ty, args.len());
 +                    if res.is_some() {
 +                        derefed_callee = callee_deref_ty;
 +                        break;
 +                    }
 +                }
 +                // if the function is unresolved, we use is_varargs=true to
 +                // suppress the arg count diagnostic here
 +                let is_varargs =
 +                    derefed_callee.callable_sig(self.db).map_or(false, |sig| sig.is_varargs)
 +                        || res.is_none();
 +                let (param_tys, ret_ty) = match res {
 +                    Some(res) => {
 +                        let adjustments = auto_deref_adjust_steps(&derefs);
 +                        self.write_expr_adj(*callee, adjustments);
 +                        res
 +                    }
 +                    None => (Vec::new(), self.err_ty()), // FIXME diagnostic
 +                };
 +                let indices_to_skip = self.check_legacy_const_generics(derefed_callee, args);
 +                self.register_obligations_for_call(&callee_ty);
 +
 +                let expected_inputs = self.expected_inputs_for_expected_output(
 +                    expected,
 +                    ret_ty.clone(),
 +                    param_tys.clone(),
 +                );
 +
 +                self.check_call_arguments(
 +                    tgt_expr,
 +                    args,
 +                    &expected_inputs,
 +                    &param_tys,
 +                    &indices_to_skip,
 +                    is_varargs,
 +                );
 +                self.normalize_associated_types_in(ret_ty)
 +            }
 +            Expr::MethodCall { receiver, args, method_name, generic_args } => self
 +                .infer_method_call(
 +                    tgt_expr,
 +                    *receiver,
 +                    args,
 +                    method_name,
 +                    generic_args.as_deref(),
 +                    expected,
 +                ),
 +            Expr::Match { expr, arms } => {
 +                let input_ty = self.infer_expr(*expr, &Expectation::none());
 +
 +                let expected = expected.adjust_for_branches(&mut self.table);
 +
 +                let result_ty = if arms.is_empty() {
 +                    TyKind::Never.intern(Interner)
 +                } else {
 +                    match &expected {
 +                        Expectation::HasType(ty) => ty.clone(),
 +                        _ => self.table.new_type_var(),
 +                    }
 +                };
 +                let mut coerce = CoerceMany::new(result_ty);
 +
 +                let matchee_diverges = self.diverges;
 +                let mut all_arms_diverge = Diverges::Always;
 +
 +                for arm in arms.iter() {
 +                    self.diverges = Diverges::Maybe;
 +                    let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
 +                    if let Some(guard_expr) = arm.guard {
 +                        self.infer_expr(
 +                            guard_expr,
 +                            &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
 +                        );
 +                    }
 +
 +                    let arm_ty = self.infer_expr_inner(arm.expr, &expected);
 +                    all_arms_diverge &= self.diverges;
 +                    coerce.coerce(self, Some(arm.expr), &arm_ty);
 +                }
 +
 +                self.diverges = matchee_diverges | all_arms_diverge;
 +
 +                coerce.complete()
 +            }
 +            Expr::Path(p) => {
 +                // FIXME this could be more efficient...
 +                let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
 +                self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or_else(|| self.err_ty())
 +            }
 +            Expr::Continue { label } => {
 +                if let None = find_continuable(&mut self.breakables, label.as_ref()) {
 +                    self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
 +                        expr: tgt_expr,
 +                        is_break: false,
 +                    });
 +                };
 +                TyKind::Never.intern(Interner)
 +            }
 +            Expr::Break { expr, label } => {
 +                let val_ty = if let Some(expr) = *expr {
 +                    self.infer_expr(expr, &Expectation::none())
 +                } else {
 +                    TyBuilder::unit()
 +                };
 +
 +                match find_breakable(&mut self.breakables, label.as_ref()) {
 +                    Some(ctxt) => {
 +                        // avoiding the borrowck
 +                        let mut coerce = mem::replace(
 +                            &mut ctxt.coerce,
 +                            CoerceMany::new(self.result.standard_types.unknown.clone()),
 +                        );
 +
 +                        // FIXME: create a synthetic `()` during lowering so we have something to refer to here?
 +                        coerce.coerce(self, *expr, &val_ty);
 +
 +                        let ctxt = find_breakable(&mut self.breakables, label.as_ref())
 +                            .expect("breakable stack changed during coercion");
 +                        ctxt.coerce = coerce;
 +                        ctxt.may_break = true;
 +                    }
 +                    None => {
 +                        self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
 +                            expr: tgt_expr,
 +                            is_break: true,
 +                        });
 +                    }
 +                }
 +                TyKind::Never.intern(Interner)
 +            }
 +            Expr::Return { expr } => {
 +                if let Some(expr) = expr {
 +                    self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone()));
 +                } else {
 +                    let unit = TyBuilder::unit();
 +                    let _ = self.coerce(Some(tgt_expr), &unit, &self.return_ty.clone());
 +                }
 +                TyKind::Never.intern(Interner)
 +            }
 +            Expr::Yield { expr } => {
 +                if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() {
 +                    if let Some(expr) = expr {
 +                        self.infer_expr_coerce(*expr, &Expectation::has_type(yield_ty));
 +                    } else {
 +                        let unit = self.result.standard_types.unit.clone();
 +                        let _ = self.coerce(Some(tgt_expr), &unit, &yield_ty);
 +                    }
 +                    resume_ty
 +                } else {
 +                    // FIXME: report error (yield expr in non-generator)
 +                    TyKind::Error.intern(Interner)
 +                }
 +            }
 +            Expr::RecordLit { path, fields, spread, .. } => {
 +                let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
 +                if let Some(variant) = def_id {
 +                    self.write_variant_resolution(tgt_expr.into(), variant);
 +                }
 +
 +                if let Some(t) = expected.only_has_type(&mut self.table) {
 +                    self.unify(&ty, &t);
 +                }
 +
 +                let substs = ty
 +                    .as_adt()
 +                    .map(|(_, s)| s.clone())
 +                    .unwrap_or_else(|| Substitution::empty(Interner));
 +                let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default();
 +                let variant_data = def_id.map(|it| it.variant_data(self.db.upcast()));
 +                for field in fields.iter() {
 +                    let field_def =
 +                        variant_data.as_ref().and_then(|it| match it.field(&field.name) {
 +                            Some(local_id) => Some(FieldId { parent: def_id.unwrap(), local_id }),
 +                            None => {
 +                                self.push_diagnostic(InferenceDiagnostic::NoSuchField {
 +                                    expr: field.expr,
 +                                });
 +                                None
 +                            }
 +                        });
 +                    let field_ty = field_def.map_or(self.err_ty(), |it| {
 +                        field_types[it.local_id].clone().substitute(Interner, &substs)
 +                    });
 +                    self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
 +                }
 +                if let Some(expr) = spread {
 +                    self.infer_expr(*expr, &Expectation::has_type(ty.clone()));
 +                }
 +                ty
 +            }
 +            Expr::Field { expr, name } => {
 +                let receiver_ty = self.infer_expr_inner(*expr, &Expectation::none());
 +
 +                let mut autoderef = Autoderef::new(&mut self.table, receiver_ty);
 +                let ty = autoderef.by_ref().find_map(|(derefed_ty, _)| {
 +                    let (field_id, parameters) = match derefed_ty.kind(Interner) {
 +                        TyKind::Tuple(_, substs) => {
 +                            return name.as_tuple_index().and_then(|idx| {
 +                                substs
 +                                    .as_slice(Interner)
 +                                    .get(idx)
 +                                    .map(|a| a.assert_ty_ref(Interner))
 +                                    .cloned()
 +                            });
 +                        }
 +                        TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => {
 +                            let local_id = self.db.struct_data(*s).variant_data.field(name)?;
 +                            let field = FieldId { parent: (*s).into(), local_id };
 +                            (field, parameters.clone())
 +                        }
 +                        TyKind::Adt(AdtId(hir_def::AdtId::UnionId(u)), parameters) => {
 +                            let local_id = self.db.union_data(*u).variant_data.field(name)?;
 +                            let field = FieldId { parent: (*u).into(), local_id };
 +                            (field, parameters.clone())
 +                        }
 +                        _ => return None,
 +                    };
 +                    let is_visible = self.db.field_visibilities(field_id.parent)[field_id.local_id]
 +                        .is_visible_from(self.db.upcast(), self.resolver.module());
 +                    if !is_visible {
 +                        // Write down the first field resolution even if it is not visible
 +                        // This aids IDE features for private fields like goto def and in
 +                        // case of autoderef finding an applicable field, this will be
 +                        // overwritten in a following cycle
 +                        if let Entry::Vacant(entry) = self.result.field_resolutions.entry(tgt_expr)
 +                        {
 +                            entry.insert(field_id);
 +                        }
 +                        return None;
 +                    }
 +                    // can't have `write_field_resolution` here because `self.table` is borrowed :(
 +                    self.result.field_resolutions.insert(tgt_expr, field_id);
 +                    let ty = self.db.field_types(field_id.parent)[field_id.local_id]
 +                        .clone()
 +                        .substitute(Interner, &parameters);
 +                    Some(ty)
 +                });
 +                let ty = match ty {
 +                    Some(ty) => {
 +                        let adjustments = auto_deref_adjust_steps(&autoderef);
 +                        self.write_expr_adj(*expr, adjustments);
 +                        let ty = self.insert_type_vars(ty);
 +                        let ty = self.normalize_associated_types_in(ty);
 +                        ty
 +                    }
 +                    _ => self.err_ty(),
 +                };
 +                ty
 +            }
 +            Expr::Await { expr } => {
 +                let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
 +                self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
 +            }
++            &Expr::Try { expr } => {
++                let inner_ty = self.infer_expr_inner(expr, &Expectation::none());
++                match self.resolve_try_impl_for(inner_ty.clone()) {
++                    Some((_, Some((output, residual)))) => {
++                        if let Some((_trait, false)) =
++                            self.implements_from_residual(self.return_ty.clone(), residual)
++                        {
++                            self.push_diagnostic(InferenceDiagnostic::IncorrectTryTarget {
++                                expr: tgt_expr,
++                            });
++                        }
++                        output
++                    }
++                    Some((trait_, None)) => {
++                        self.push_diagnostic(InferenceDiagnostic::DoesNotImplement {
++                            expr,
++                            trait_,
++                            ty: inner_ty,
++                        });
++                        self.err_ty()
++                    }
++                    None => self.err_ty(),
++                }
 +            }
 +            Expr::Cast { expr, type_ref } => {
 +                // FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary)
 +                let _inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
 +                let cast_ty = self.make_ty(type_ref);
 +                // FIXME check the cast...
 +                cast_ty
 +            }
 +            Expr::Ref { expr, rawness, mutability } => {
 +                let mutability = lower_to_chalk_mutability(*mutability);
 +                let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = expected
 +                    .only_has_type(&mut self.table)
 +                    .as_ref()
 +                    .and_then(|t| t.as_reference_or_ptr())
 +                {
 +                    if exp_mutability == Mutability::Mut && mutability == Mutability::Not {
 +                        // FIXME: record type error - expected mut reference but found shared ref,
 +                        // which cannot be coerced
 +                    }
 +                    if exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr {
 +                        // FIXME: record type error - expected reference but found ptr,
 +                        // which cannot be coerced
 +                    }
 +                    Expectation::rvalue_hint(&mut self.table, Ty::clone(exp_inner))
 +                } else {
 +                    Expectation::none()
 +                };
 +                let inner_ty = self.infer_expr_inner(*expr, &expectation);
 +                match rawness {
 +                    Rawness::RawPtr => TyKind::Raw(mutability, inner_ty),
 +                    Rawness::Ref => TyKind::Ref(mutability, static_lifetime(), inner_ty),
 +                }
 +                .intern(Interner)
 +            }
 +            &Expr::Box { expr } => self.infer_expr_box(expr, expected),
 +            Expr::UnaryOp { expr, op } => {
 +                let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
 +                let inner_ty = self.resolve_ty_shallow(&inner_ty);
 +                match op {
 +                    UnaryOp::Deref => {
 +                        autoderef::deref(&mut self.table, inner_ty).unwrap_or_else(|| self.err_ty())
 +                    }
 +                    UnaryOp::Neg => {
 +                        match inner_ty.kind(Interner) {
 +                            // Fast path for builtins
 +                            TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_))
 +                            | TyKind::InferenceVar(
 +                                _,
 +                                TyVariableKind::Integer | TyVariableKind::Float,
 +                            ) => inner_ty,
 +                            // Otherwise we resolve via the std::ops::Neg trait
 +                            _ => self
 +                                .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()),
 +                        }
 +                    }
 +                    UnaryOp::Not => {
 +                        match inner_ty.kind(Interner) {
 +                            // Fast path for builtins
 +                            TyKind::Scalar(Scalar::Bool | Scalar::Int(_) | Scalar::Uint(_))
 +                            | TyKind::InferenceVar(_, TyVariableKind::Integer) => inner_ty,
 +                            // Otherwise we resolve via the std::ops::Not trait
 +                            _ => self
 +                                .resolve_associated_type(inner_ty, self.resolve_ops_not_output()),
 +                        }
 +                    }
 +                }
 +            }
 +            Expr::BinaryOp { lhs, rhs, op } => match op {
 +                Some(BinaryOp::Assignment { op: None }) => {
 +                    let lhs = *lhs;
 +                    let is_ordinary = match &self.body[lhs] {
 +                        Expr::Array(_)
 +                        | Expr::RecordLit { .. }
 +                        | Expr::Tuple { .. }
 +                        | Expr::Underscore => false,
 +                        Expr::Call { callee, .. } => !matches!(&self.body[*callee], Expr::Path(_)),
 +                        _ => true,
 +                    };
 +
 +                    // In ordinary (non-destructuring) assignments, the type of
 +                    // `lhs` must be inferred first so that the ADT fields
 +                    // instantiations in RHS can be coerced to it. Note that this
 +                    // cannot happen in destructuring assignments because of how
 +                    // they are desugared.
 +                    if is_ordinary {
 +                        let lhs_ty = self.infer_expr(lhs, &Expectation::none());
 +                        self.infer_expr_coerce(*rhs, &Expectation::has_type(lhs_ty));
 +                    } else {
 +                        let rhs_ty = self.infer_expr(*rhs, &Expectation::none());
 +                        self.infer_assignee_expr(lhs, &rhs_ty);
 +                    }
 +                    self.result.standard_types.unit.clone()
 +                }
 +                Some(BinaryOp::LogicOp(_)) => {
 +                    let bool_ty = self.result.standard_types.bool_.clone();
 +                    self.infer_expr_coerce(*lhs, &Expectation::HasType(bool_ty.clone()));
 +                    let lhs_diverges = self.diverges;
 +                    self.infer_expr_coerce(*rhs, &Expectation::HasType(bool_ty.clone()));
 +                    // Depending on the LHS' value, the RHS can never execute.
 +                    self.diverges = lhs_diverges;
 +                    bool_ty
 +                }
 +                Some(op) => self.infer_overloadable_binop(*lhs, *op, *rhs, tgt_expr),
 +                _ => self.err_ty(),
 +            },
 +            Expr::Range { lhs, rhs, range_type } => {
 +                let lhs_ty = lhs.map(|e| self.infer_expr_inner(e, &Expectation::none()));
 +                let rhs_expect = lhs_ty
 +                    .as_ref()
 +                    .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone()));
 +                let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect));
 +                match (range_type, lhs_ty, rhs_ty) {
 +                    (RangeOp::Exclusive, None, None) => match self.resolve_range_full() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Inclusive, None, Some(ty)) => {
 +                        match self.resolve_range_to_inclusive() {
 +                            Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                            None => self.err_ty(),
 +                        }
 +                    }
 +                    (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Inclusive, Some(_), Some(ty)) => {
 +                        match self.resolve_range_inclusive() {
 +                            Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                            None => self.err_ty(),
 +                        }
 +                    }
 +                    (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Inclusive, _, None) => self.err_ty(),
 +                }
 +            }
 +            Expr::Index { base, index } => {
 +                let base_ty = self.infer_expr_inner(*base, &Expectation::none());
 +                let index_ty = self.infer_expr(*index, &Expectation::none());
 +
 +                if let Some(index_trait) = self.resolve_ops_index() {
 +                    let canonicalized = self.canonicalize(base_ty.clone());
 +                    let receiver_adjustments = method_resolution::resolve_indexing_op(
 +                        self.db,
 +                        self.trait_env.clone(),
 +                        canonicalized.value,
 +                        index_trait,
 +                    );
 +                    let (self_ty, adj) = receiver_adjustments
 +                        .map_or((self.err_ty(), Vec::new()), |adj| {
 +                            adj.apply(&mut self.table, base_ty)
 +                        });
 +                    self.write_expr_adj(*base, adj);
 +                    self.resolve_associated_type_with_params(
 +                        self_ty,
 +                        self.resolve_ops_index_output(),
 +                        &[GenericArgData::Ty(index_ty).intern(Interner)],
 +                    )
 +                } else {
 +                    self.err_ty()
 +                }
 +            }
 +            Expr::Tuple { exprs, .. } => {
 +                let mut tys = match expected
 +                    .only_has_type(&mut self.table)
 +                    .as_ref()
 +                    .map(|t| t.kind(Interner))
 +                {
 +                    Some(TyKind::Tuple(_, substs)) => substs
 +                        .iter(Interner)
 +                        .map(|a| a.assert_ty_ref(Interner).clone())
 +                        .chain(repeat_with(|| self.table.new_type_var()))
 +                        .take(exprs.len())
 +                        .collect::<Vec<_>>(),
 +                    _ => (0..exprs.len()).map(|_| self.table.new_type_var()).collect(),
 +                };
 +
 +                for (expr, ty) in exprs.iter().zip(tys.iter_mut()) {
 +                    self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
 +                }
 +
 +                TyKind::Tuple(tys.len(), Substitution::from_iter(Interner, tys)).intern(Interner)
 +            }
 +            Expr::Array(array) => {
 +                let elem_ty =
 +                    match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(Interner)) {
 +                        Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st.clone(),
 +                        _ => self.table.new_type_var(),
 +                    };
 +                let mut coerce = CoerceMany::new(elem_ty.clone());
 +
 +                let expected = Expectation::has_type(elem_ty.clone());
 +                let len = match array {
 +                    Array::ElementList { elements, .. } => {
 +                        for &expr in elements.iter() {
 +                            let cur_elem_ty = self.infer_expr_inner(expr, &expected);
 +                            coerce.coerce(self, Some(expr), &cur_elem_ty);
 +                        }
 +                        consteval::usize_const(Some(elements.len() as u128))
 +                    }
 +                    &Array::Repeat { initializer, repeat } => {
 +                        self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty));
 +                        self.infer_expr(
 +                            repeat,
 +                            &Expectation::has_type(
 +                                TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
 +                            ),
 +                        );
 +
 +                        if let Some(g_def) = self.owner.as_generic_def_id() {
 +                            let generics = generics(self.db.upcast(), g_def);
 +                            consteval::eval_to_const(
 +                                repeat,
 +                                ParamLoweringMode::Placeholder,
 +                                self,
 +                                || generics,
 +                                DebruijnIndex::INNERMOST,
 +                            )
 +                        } else {
 +                            consteval::usize_const(None)
 +                        }
 +                    }
 +                };
 +
 +                TyKind::Array(coerce.complete(), len).intern(Interner)
 +            }
 +            Expr::Literal(lit) => match lit {
 +                Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(Interner),
 +                Literal::String(..) => {
 +                    TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(Interner))
 +                        .intern(Interner)
 +                }
 +                Literal::ByteString(bs) => {
 +                    let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner);
 +
 +                    let len = consteval::usize_const(Some(bs.len() as u128));
 +
 +                    let array_type = TyKind::Array(byte_type, len).intern(Interner);
 +                    TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(Interner)
 +                }
 +                Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(Interner),
 +                Literal::Int(_v, ty) => match ty {
 +                    Some(int_ty) => {
 +                        TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(*int_ty)))
 +                            .intern(Interner)
 +                    }
 +                    None => self.table.new_integer_var(),
 +                },
 +                Literal::Uint(_v, ty) => match ty {
 +                    Some(int_ty) => {
 +                        TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(*int_ty)))
 +                            .intern(Interner)
 +                    }
 +                    None => self.table.new_integer_var(),
 +                },
 +                Literal::Float(_v, ty) => match ty {
 +                    Some(float_ty) => {
 +                        TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(*float_ty)))
 +                            .intern(Interner)
 +                    }
 +                    None => self.table.new_float_var(),
 +                },
 +            },
 +            Expr::Underscore => {
 +                // Underscore expressions may only appear in assignee expressions,
 +                // which are handled by `infer_assignee_expr()`, so any underscore
 +                // expression reaching this branch is an error.
 +                self.err_ty()
 +            }
 +        };
 +        // use a new type variable if we got unknown here
 +        let ty = self.insert_type_vars_shallow(ty);
 +        self.write_expr_ty(tgt_expr, ty.clone());
 +        if self.resolve_ty_shallow(&ty).is_never() {
 +            // Any expression that produces a value of type `!` must have diverged
 +            self.diverges = Diverges::Always;
 +        }
 +        ty
 +    }
 +
 +    fn infer_expr_box(&mut self, inner_expr: ExprId, expected: &Expectation) -> Ty {
 +        if let Some(box_id) = self.resolve_boxed_box() {
 +            let table = &mut self.table;
 +            let inner_exp = expected
 +                .to_option(table)
 +                .as_ref()
 +                .map(|e| e.as_adt())
 +                .flatten()
 +                .filter(|(e_adt, _)| e_adt == &box_id)
 +                .map(|(_, subts)| {
 +                    let g = subts.at(Interner, 0);
 +                    Expectation::rvalue_hint(table, Ty::clone(g.assert_ty_ref(Interner)))
 +                })
 +                .unwrap_or_else(Expectation::none);
 +
 +            let inner_ty = self.infer_expr_inner(inner_expr, &inner_exp);
 +            TyBuilder::adt(self.db, box_id)
 +                .push(inner_ty)
 +                .fill_with_defaults(self.db, || self.table.new_type_var())
 +                .build()
 +        } else {
 +            self.err_ty()
 +        }
 +    }
 +
 +    pub(super) fn infer_assignee_expr(&mut self, lhs: ExprId, rhs_ty: &Ty) -> Ty {
 +        let is_rest_expr = |expr| {
 +            matches!(
 +                &self.body[expr],
 +                Expr::Range { lhs: None, rhs: None, range_type: RangeOp::Exclusive },
 +            )
 +        };
 +
 +        let rhs_ty = self.resolve_ty_shallow(rhs_ty);
 +
 +        let ty = match &self.body[lhs] {
 +            Expr::Tuple { exprs, .. } => {
 +                // We don't consider multiple ellipses. This is analogous to
 +                // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
 +                let ellipsis = exprs.iter().position(|e| is_rest_expr(*e));
 +                let exprs: Vec<_> = exprs.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
 +
 +                self.infer_tuple_pat_like(&rhs_ty, (), ellipsis, &exprs)
 +            }
 +            Expr::Call { callee, args, .. } => {
 +                // Tuple structs
 +                let path = match &self.body[*callee] {
 +                    Expr::Path(path) => Some(path),
 +                    _ => None,
 +                };
 +
 +                // We don't consider multiple ellipses. This is analogous to
 +                // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
 +                let ellipsis = args.iter().position(|e| is_rest_expr(*e));
 +                let args: Vec<_> = args.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
 +
 +                self.infer_tuple_struct_pat_like(path, &rhs_ty, (), lhs, ellipsis, &args)
 +            }
 +            Expr::Array(Array::ElementList { elements, .. }) => {
 +                let elem_ty = match rhs_ty.kind(Interner) {
 +                    TyKind::Array(st, _) => st.clone(),
 +                    _ => self.err_ty(),
 +                };
 +
 +                // There's no need to handle `..` as it cannot be bound.
 +                let sub_exprs = elements.iter().filter(|e| !is_rest_expr(**e));
 +
 +                for e in sub_exprs {
 +                    self.infer_assignee_expr(*e, &elem_ty);
 +                }
 +
 +                match rhs_ty.kind(Interner) {
 +                    TyKind::Array(_, _) => rhs_ty.clone(),
 +                    // Even when `rhs_ty` is not an array type, this assignee
 +                    // expression is inferred to be an array (of unknown element
 +                    // type and length). This should not be just an error type,
 +                    // because we are to compute the unifiability of this type and
 +                    // `rhs_ty` in the end of this function to issue type mismatches.
 +                    _ => TyKind::Array(self.err_ty(), crate::consteval::usize_const(None))
 +                        .intern(Interner),
 +                }
 +            }
 +            Expr::RecordLit { path, fields, .. } => {
 +                let subs = fields.iter().map(|f| (f.name.clone(), f.expr));
 +
 +                self.infer_record_pat_like(path.as_deref(), &rhs_ty, (), lhs.into(), subs)
 +            }
 +            Expr::Underscore => rhs_ty.clone(),
 +            _ => {
 +                // `lhs` is a place expression, a unit struct, or an enum variant.
 +                let lhs_ty = self.infer_expr(lhs, &Expectation::none());
 +
 +                // This is the only branch where this function may coerce any type.
 +                // We are returning early to avoid the unifiability check below.
 +                let lhs_ty = self.insert_type_vars_shallow(lhs_ty);
 +                let ty = match self.coerce(None, &rhs_ty, &lhs_ty) {
 +                    Ok(ty) => ty,
 +                    Err(_) => {
 +                        self.result.type_mismatches.insert(
 +                            lhs.into(),
 +                            TypeMismatch { expected: rhs_ty.clone(), actual: lhs_ty.clone() },
 +                        );
 +                        // `rhs_ty` is returned so no further type mismatches are
 +                        // reported because of this mismatch.
 +                        rhs_ty
 +                    }
 +                };
 +                self.write_expr_ty(lhs, ty.clone());
 +                return ty;
 +            }
 +        };
 +
 +        let ty = self.insert_type_vars_shallow(ty);
 +        if !self.unify(&ty, &rhs_ty) {
 +            self.result
 +                .type_mismatches
 +                .insert(lhs.into(), TypeMismatch { expected: rhs_ty.clone(), actual: ty.clone() });
 +        }
 +        self.write_expr_ty(lhs, ty.clone());
 +        ty
 +    }
 +
 +    fn infer_overloadable_binop(
 +        &mut self,
 +        lhs: ExprId,
 +        op: BinaryOp,
 +        rhs: ExprId,
 +        tgt_expr: ExprId,
 +    ) -> Ty {
 +        let lhs_expectation = Expectation::none();
 +        let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
 +        let rhs_ty = self.table.new_type_var();
 +
 +        let trait_func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
 +            let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?;
 +            let func = self.db.trait_data(trait_id).method_by_name(&name)?;
 +            Some((trait_id, func))
 +        });
 +        let (trait_, func) = match trait_func {
 +            Some(it) => it,
 +            None => {
 +                let rhs_ty = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone());
 +                let rhs_ty = self.infer_expr_coerce(rhs, &Expectation::from_option(rhs_ty));
 +                return self
 +                    .builtin_binary_op_return_ty(op, lhs_ty, rhs_ty)
 +                    .unwrap_or_else(|| self.err_ty());
 +            }
 +        };
 +
 +        // HACK: We can use this substitution for the function because the function itself doesn't
 +        // have its own generic parameters.
 +        let subst = TyBuilder::subst_for_def(self.db, trait_, None)
 +            .push(lhs_ty.clone())
 +            .push(rhs_ty.clone())
 +            .build();
 +        self.write_method_resolution(tgt_expr, func, subst.clone());
 +
 +        let method_ty = self.db.value_ty(func.into()).substitute(Interner, &subst);
 +        self.register_obligations_for_call(&method_ty);
 +
 +        self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty.clone()));
 +
 +        let ret_ty = match method_ty.callable_sig(self.db) {
 +            Some(sig) => sig.ret().clone(),
 +            None => self.err_ty(),
 +        };
 +
 +        let ret_ty = self.normalize_associated_types_in(ret_ty);
 +
 +        // FIXME: record autoref adjustments
 +
 +        // use knowledge of built-in binary ops, which can sometimes help inference
 +        if let Some(builtin_rhs) = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone()) {
 +            self.unify(&builtin_rhs, &rhs_ty);
 +        }
 +        if let Some(builtin_ret) = self.builtin_binary_op_return_ty(op, lhs_ty, rhs_ty) {
 +            self.unify(&builtin_ret, &ret_ty);
 +        }
 +
 +        ret_ty
 +    }
 +
 +    fn infer_block(
 +        &mut self,
 +        expr: ExprId,
 +        statements: &[Statement],
 +        tail: Option<ExprId>,
 +        expected: &Expectation,
 +    ) -> Ty {
 +        for stmt in statements {
 +            match stmt {
 +                Statement::Let { pat, type_ref, initializer, else_branch } => {
 +                    let decl_ty = type_ref
 +                        .as_ref()
 +                        .map(|tr| self.make_ty(tr))
 +                        .unwrap_or_else(|| self.err_ty());
 +
 +                    // Always use the declared type when specified
 +                    let mut ty = decl_ty.clone();
 +
 +                    if let Some(expr) = initializer {
 +                        let actual_ty =
 +                            self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty.clone()));
 +                        if decl_ty.is_unknown() {
 +                            ty = actual_ty;
 +                        }
 +                    }
 +
 +                    if let Some(expr) = else_branch {
 +                        self.infer_expr_coerce(
 +                            *expr,
 +                            &Expectation::has_type(Ty::new(Interner, TyKind::Never)),
 +                        );
 +                    }
 +
 +                    self.infer_pat(*pat, &ty, BindingMode::default());
 +                }
 +                Statement::Expr { expr, .. } => {
 +                    self.infer_expr(*expr, &Expectation::none());
 +                }
 +            }
 +        }
 +
 +        if let Some(expr) = tail {
 +            self.infer_expr_coerce(expr, expected)
 +        } else {
 +            // Citing rustc: if there is no explicit tail expression,
 +            // that is typically equivalent to a tail expression
 +            // of `()` -- except if the block diverges. In that
 +            // case, there is no value supplied from the tail
 +            // expression (assuming there are no other breaks,
 +            // this implies that the type of the block will be
 +            // `!`).
 +            if self.diverges.is_always() {
 +                // we don't even make an attempt at coercion
 +                self.table.new_maybe_never_var()
 +            } else {
 +                if let Some(t) = expected.only_has_type(&mut self.table) {
 +                    if self.coerce(Some(expr), &TyBuilder::unit(), &t).is_err() {
 +                        self.result.type_mismatches.insert(
 +                            expr.into(),
 +                            TypeMismatch { expected: t.clone(), actual: TyBuilder::unit() },
 +                        );
 +                    }
 +                    t
 +                } else {
 +                    TyBuilder::unit()
 +                }
 +            }
 +        }
 +    }
 +
 +    fn infer_method_call(
 +        &mut self,
 +        tgt_expr: ExprId,
 +        receiver: ExprId,
 +        args: &[ExprId],
 +        method_name: &Name,
 +        generic_args: Option<&GenericArgs>,
 +        expected: &Expectation,
 +    ) -> Ty {
 +        let receiver_ty = self.infer_expr(receiver, &Expectation::none());
 +        let canonicalized_receiver = self.canonicalize(receiver_ty.clone());
 +
 +        let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast());
 +
 +        let resolved = method_resolution::lookup_method(
 +            &canonicalized_receiver.value,
 +            self.db,
 +            self.trait_env.clone(),
 +            &traits_in_scope,
 +            VisibleFromModule::Filter(self.resolver.module()),
 +            method_name,
 +        );
 +        let (receiver_ty, method_ty, substs) = match resolved {
 +            Some((adjust, func)) => {
 +                let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty);
 +                let generics = generics(self.db.upcast(), func.into());
 +                let substs = self.substs_for_method_call(generics, generic_args);
 +                self.write_expr_adj(receiver, adjustments);
 +                self.write_method_resolution(tgt_expr, func, substs.clone());
 +                (ty, self.db.value_ty(func.into()), substs)
 +            }
 +            None => (
 +                receiver_ty,
 +                Binders::empty(Interner, self.err_ty()),
 +                Substitution::empty(Interner),
 +            ),
 +        };
 +        let method_ty = method_ty.substitute(Interner, &substs);
 +        self.register_obligations_for_call(&method_ty);
 +        let (formal_receiver_ty, param_tys, ret_ty, is_varargs) =
 +            match method_ty.callable_sig(self.db) {
 +                Some(sig) => {
 +                    if !sig.params().is_empty() {
 +                        (
 +                            sig.params()[0].clone(),
 +                            sig.params()[1..].to_vec(),
 +                            sig.ret().clone(),
 +                            sig.is_varargs,
 +                        )
 +                    } else {
 +                        (self.err_ty(), Vec::new(), sig.ret().clone(), sig.is_varargs)
 +                    }
 +                }
 +                None => (self.err_ty(), Vec::new(), self.err_ty(), true),
 +            };
 +        self.unify(&formal_receiver_ty, &receiver_ty);
 +
 +        let expected_inputs =
 +            self.expected_inputs_for_expected_output(expected, ret_ty.clone(), param_tys.clone());
 +
 +        self.check_call_arguments(tgt_expr, args, &expected_inputs, &param_tys, &[], is_varargs);
 +        self.normalize_associated_types_in(ret_ty)
 +    }
 +
 +    fn expected_inputs_for_expected_output(
 +        &mut self,
 +        expected_output: &Expectation,
 +        output: Ty,
 +        inputs: Vec<Ty>,
 +    ) -> Vec<Ty> {
 +        if let Some(expected_ty) = expected_output.to_option(&mut self.table) {
 +            self.table.fudge_inference(|table| {
 +                if table.try_unify(&expected_ty, &output).is_ok() {
 +                    table.resolve_with_fallback(inputs, &|var, kind, _, _| match kind {
 +                        chalk_ir::VariableKind::Ty(tk) => var.to_ty(Interner, tk).cast(Interner),
 +                        chalk_ir::VariableKind::Lifetime => {
 +                            var.to_lifetime(Interner).cast(Interner)
 +                        }
 +                        chalk_ir::VariableKind::Const(ty) => {
 +                            var.to_const(Interner, ty).cast(Interner)
 +                        }
 +                    })
 +                } else {
 +                    Vec::new()
 +                }
 +            })
 +        } else {
 +            Vec::new()
 +        }
 +    }
 +
 +    fn check_call_arguments(
 +        &mut self,
 +        expr: ExprId,
 +        args: &[ExprId],
 +        expected_inputs: &[Ty],
 +        param_tys: &[Ty],
 +        skip_indices: &[u32],
 +        is_varargs: bool,
 +    ) {
 +        if args.len() != param_tys.len() + skip_indices.len() && !is_varargs {
 +            self.push_diagnostic(InferenceDiagnostic::MismatchedArgCount {
 +                call_expr: expr,
 +                expected: param_tys.len() + skip_indices.len(),
 +                found: args.len(),
 +            });
 +        }
 +
 +        // Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 --
 +        // We do this in a pretty awful way: first we type-check any arguments
 +        // that are not closures, then we type-check the closures. This is so
 +        // that we have more information about the types of arguments when we
 +        // type-check the functions. This isn't really the right way to do this.
 +        for &check_closures in &[false, true] {
 +            let mut skip_indices = skip_indices.into_iter().copied().fuse().peekable();
 +            let param_iter = param_tys.iter().cloned().chain(repeat(self.err_ty()));
 +            let expected_iter = expected_inputs
 +                .iter()
 +                .cloned()
 +                .chain(param_iter.clone().skip(expected_inputs.len()));
 +            for (idx, ((&arg, param_ty), expected_ty)) in
 +                args.iter().zip(param_iter).zip(expected_iter).enumerate()
 +            {
 +                let is_closure = matches!(&self.body[arg], Expr::Closure { .. });
 +                if is_closure != check_closures {
 +                    continue;
 +                }
 +
 +                while skip_indices.peek().map_or(false, |i| *i < idx as u32) {
 +                    skip_indices.next();
 +                }
 +                if skip_indices.peek().copied() == Some(idx as u32) {
 +                    continue;
 +                }
 +
 +                // the difference between param_ty and expected here is that
 +                // expected is the parameter when the expected *return* type is
 +                // taken into account. So in `let _: &[i32] = identity(&[1, 2])`
 +                // the expected type is already `&[i32]`, whereas param_ty is
 +                // still an unbound type variable. We don't always want to force
 +                // the parameter to coerce to the expected type (for example in
 +                // `coerce_unsize_expected_type_4`).
 +                let param_ty = self.normalize_associated_types_in(param_ty);
 +                let expected = Expectation::rvalue_hint(&mut self.table, expected_ty);
 +                // infer with the expected type we have...
 +                let ty = self.infer_expr_inner(arg, &expected);
 +
 +                // then coerce to either the expected type or just the formal parameter type
 +                let coercion_target = if let Some(ty) = expected.only_has_type(&mut self.table) {
 +                    // if we are coercing to the expectation, unify with the
 +                    // formal parameter type to connect everything
 +                    self.unify(&ty, &param_ty);
 +                    ty
 +                } else {
 +                    param_ty
 +                };
 +                if !coercion_target.is_unknown() {
 +                    if self.coerce(Some(arg), &ty, &coercion_target).is_err() {
 +                        self.result.type_mismatches.insert(
 +                            arg.into(),
 +                            TypeMismatch { expected: coercion_target, actual: ty.clone() },
 +                        );
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn substs_for_method_call(
 +        &mut self,
 +        def_generics: Generics,
 +        generic_args: Option<&GenericArgs>,
 +    ) -> Substitution {
 +        let (parent_params, self_params, type_params, const_params, impl_trait_params) =
 +            def_generics.provenance_split();
 +        assert_eq!(self_params, 0); // method shouldn't have another Self param
 +        let total_len = parent_params + type_params + const_params + impl_trait_params;
 +        let mut substs = Vec::with_capacity(total_len);
 +
 +        // handle provided arguments
 +        if let Some(generic_args) = generic_args {
 +            // if args are provided, it should be all of them, but we can't rely on that
 +            for (arg, kind_id) in generic_args
 +                .args
 +                .iter()
 +                .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
 +                .take(type_params + const_params)
 +                .zip(def_generics.iter_id())
 +            {
 +                if let Some(g) = generic_arg_to_chalk(
 +                    self.db,
 +                    kind_id,
 +                    arg,
 +                    self,
 +                    |this, type_ref| this.make_ty(type_ref),
 +                    |this, c, ty| {
 +                        const_or_path_to_chalk(
 +                            this.db,
 +                            &this.resolver,
 +                            ty,
 +                            c,
 +                            ParamLoweringMode::Placeholder,
 +                            || generics(this.db.upcast(), (&this.resolver).generic_def().unwrap()),
 +                            DebruijnIndex::INNERMOST,
 +                        )
 +                    },
 +                ) {
 +                    substs.push(g);
 +                }
 +            }
 +        };
 +
 +        // Handle everything else as unknown. This also handles generic arguments for the method's
 +        // parent (impl or trait), which should come after those for the method.
 +        for (id, data) in def_generics.iter().skip(substs.len()) {
 +            match data {
 +                TypeOrConstParamData::TypeParamData(_) => {
 +                    substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner))
 +                }
 +                TypeOrConstParamData::ConstParamData(_) => {
 +                    substs.push(
 +                        GenericArgData::Const(self.table.new_const_var(
 +                            self.db.const_param_ty(ConstParamId::from_unchecked(id)),
 +                        ))
 +                        .intern(Interner),
 +                    )
 +                }
 +            }
 +        }
 +        assert_eq!(substs.len(), total_len);
 +        Substitution::from_iter(Interner, substs)
 +    }
 +
 +    fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
 +        let callable_ty = self.resolve_ty_shallow(callable_ty);
 +        if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(Interner) {
 +            let def: CallableDefId = from_chalk(self.db, *fn_def);
 +            let generic_predicates = self.db.generic_predicates(def.into());
 +            for predicate in generic_predicates.iter() {
 +                let (predicate, binders) = predicate
 +                    .clone()
 +                    .substitute(Interner, parameters)
 +                    .into_value_and_skipped_binders();
 +                always!(binders.len(Interner) == 0); // quantified where clauses not yet handled
 +                self.push_obligation(predicate.cast(Interner));
 +            }
 +            // add obligation for trait implementation, if this is a trait method
 +            match def {
 +                CallableDefId::FunctionId(f) => {
 +                    if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container {
 +                        // construct a TraitRef
 +                        let params_len = parameters.len(Interner);
 +                        let trait_params_len = generics(self.db.upcast(), trait_.into()).len();
 +                        let substs = Substitution::from_iter(
 +                            Interner,
 +                            // The generic parameters for the trait come after those for the
 +                            // function.
 +                            &parameters.as_slice(Interner)[params_len - trait_params_len..],
 +                        );
 +                        self.push_obligation(
 +                            TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
 +                                .cast(Interner),
 +                        );
 +                    }
 +                }
 +                CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {}
 +            }
 +        }
 +    }
 +
 +    /// Returns the argument indices to skip.
 +    fn check_legacy_const_generics(&mut self, callee: Ty, args: &[ExprId]) -> Box<[u32]> {
 +        let (func, subst) = match callee.kind(Interner) {
 +            TyKind::FnDef(fn_id, subst) => {
 +                let callable = CallableDefId::from_chalk(self.db, *fn_id);
 +                let func = match callable {
 +                    CallableDefId::FunctionId(f) => f,
 +                    _ => return Default::default(),
 +                };
 +                (func, subst)
 +            }
 +            _ => return Default::default(),
 +        };
 +
 +        let data = self.db.function_data(func);
 +        if data.legacy_const_generics_indices.is_empty() {
 +            return Default::default();
 +        }
 +
 +        // only use legacy const generics if the param count matches with them
 +        if data.params.len() + data.legacy_const_generics_indices.len() != args.len() {
 +            if args.len() <= data.params.len() {
 +                return Default::default();
 +            } else {
 +                // there are more parameters than there should be without legacy
 +                // const params; use them
 +                let mut indices = data.legacy_const_generics_indices.clone();
 +                indices.sort();
 +                return indices;
 +            }
 +        }
 +
 +        // check legacy const parameters
 +        for (subst_idx, arg_idx) in data.legacy_const_generics_indices.iter().copied().enumerate() {
 +            let arg = match subst.at(Interner, subst_idx).constant(Interner) {
 +                Some(c) => c,
 +                None => continue, // not a const parameter?
 +            };
 +            if arg_idx >= args.len() as u32 {
 +                continue;
 +            }
 +            let _ty = arg.data(Interner).ty.clone();
 +            let expected = Expectation::none(); // FIXME use actual const ty, when that is lowered correctly
 +            self.infer_expr(args[arg_idx as usize], &expected);
 +            // FIXME: evaluate and unify with the const
 +        }
 +        let mut indices = data.legacy_const_generics_indices.clone();
 +        indices.sort();
 +        indices
 +    }
 +
 +    fn builtin_binary_op_return_ty(&mut self, op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Option<Ty> {
 +        let lhs_ty = self.resolve_ty_shallow(&lhs_ty);
 +        let rhs_ty = self.resolve_ty_shallow(&rhs_ty);
 +        match op {
 +            BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => {
 +                Some(TyKind::Scalar(Scalar::Bool).intern(Interner))
 +            }
 +            BinaryOp::Assignment { .. } => Some(TyBuilder::unit()),
 +            BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => {
 +                // all integer combinations are valid here
 +                if matches!(
 +                    lhs_ty.kind(Interner),
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
 +                        | TyKind::InferenceVar(_, TyVariableKind::Integer)
 +                ) && matches!(
 +                    rhs_ty.kind(Interner),
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
 +                        | TyKind::InferenceVar(_, TyVariableKind::Integer)
 +                ) {
 +                    Some(lhs_ty)
 +                } else {
 +                    None
 +                }
 +            }
 +            BinaryOp::ArithOp(_) => match (lhs_ty.kind(Interner), rhs_ty.kind(Interner)) {
 +                // (int, int) | (uint, uint) | (float, float)
 +                (TyKind::Scalar(Scalar::Int(_)), TyKind::Scalar(Scalar::Int(_)))
 +                | (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_)))
 +                | (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => {
 +                    Some(rhs_ty)
 +                }
 +                // ({int}, int) | ({int}, uint)
 +                (
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
 +                ) => Some(rhs_ty),
 +                // (int, {int}) | (uint, {int})
 +                (
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                ) => Some(lhs_ty),
 +                // ({float} | float)
 +                (
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                    TyKind::Scalar(Scalar::Float(_)),
 +                ) => Some(rhs_ty),
 +                // (float, {float})
 +                (
 +                    TyKind::Scalar(Scalar::Float(_)),
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                ) => Some(lhs_ty),
 +                // ({int}, {int}) | ({float}, {float})
 +                (
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                )
 +                | (
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                ) => Some(rhs_ty),
 +                _ => None,
 +            },
 +        }
 +    }
 +
 +    fn builtin_binary_op_rhs_expectation(&mut self, op: BinaryOp, lhs_ty: Ty) -> Option<Ty> {
 +        Some(match op {
 +            BinaryOp::LogicOp(..) => TyKind::Scalar(Scalar::Bool).intern(Interner),
 +            BinaryOp::Assignment { op: None } => lhs_ty,
 +            BinaryOp::CmpOp(CmpOp::Eq { .. }) => match self
 +                .resolve_ty_shallow(&lhs_ty)
 +                .kind(Interner)
 +            {
 +                TyKind::Scalar(_) | TyKind::Str => lhs_ty,
 +                TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
 +                _ => return None,
 +            },
 +            BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => return None,
 +            BinaryOp::CmpOp(CmpOp::Ord { .. })
 +            | BinaryOp::Assignment { op: Some(_) }
 +            | BinaryOp::ArithOp(_) => match self.resolve_ty_shallow(&lhs_ty).kind(Interner) {
 +                TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_)) => lhs_ty,
 +                TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
 +                _ => return None,
 +            },
 +        })
 +    }
 +
 +    fn with_breakable_ctx<T>(
 +        &mut self,
 +        kind: BreakableKind,
 +        ty: Ty,
 +        label: Option<LabelId>,
 +        cb: impl FnOnce(&mut Self) -> T,
 +    ) -> (Option<Ty>, T) {
 +        self.breakables.push({
 +            let label = label.map(|label| self.body[label].name.clone());
 +            BreakableContext { kind, may_break: false, coerce: CoerceMany::new(ty), label }
 +        });
 +        let res = cb(self);
 +        let ctx = self.breakables.pop().expect("breakable stack broken");
 +        (ctx.may_break.then(|| ctx.coerce.complete()), res)
 +    }
++
++    /// Check whether `ty` implements `FromResidual<r>`
++    fn implements_from_residual(&mut self, ty: Ty, r: Ty) -> Option<(hir_def::TraitId, bool)> {
++        let from_residual_trait = self
++            .resolver
++            .resolve_known_trait(self.db.upcast(), &(super::path![core::ops::FromResidual]))?;
++        let r = GenericArgData::Ty(r).intern(Interner);
++        let b = TyBuilder::trait_ref(self.db, from_residual_trait);
++        if b.remaining() != 2 {
++            return Some((from_residual_trait, false));
++        }
++        let trait_ref = b.push(ty).push(r).build();
++        Some((from_residual_trait, self.table.try_obligation(trait_ref.cast(Interner)).is_some()))
++    }
++
++    fn resolve_try_impl_for(&mut self, ty: Ty) -> Option<(hir_def::TraitId, Option<(Ty, Ty)>)> {
++        let path = path![core::ops::Try];
++        let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
++
++        let trait_ref = TyBuilder::trait_ref(self.db, trait_).push(ty).build();
++        let substitution = trait_ref.substitution.clone();
++        self.push_obligation(trait_ref.clone().cast(Interner));
++
++        let trait_data = self.db.trait_data(trait_);
++        let output = trait_data.associated_type_by_name(&name![Output]);
++        let residual = trait_data.associated_type_by_name(&name![Residual]);
++
++        let output_ty = match output {
++            Some(output) => {
++                let output_ty = self.table.new_type_var();
++                let alias_eq = AliasEq {
++                    alias: AliasTy::Projection(ProjectionTy {
++                        associated_ty_id: to_assoc_type_id(output),
++                        substitution: substitution.clone(),
++                    }),
++                    ty: output_ty.clone(),
++                };
++                self.push_obligation(alias_eq.cast(Interner));
++                output_ty
++            }
++            None => self.err_ty(),
++        };
++        let residual_ty = match residual {
++            Some(residual) => {
++                let residual_ty = self.table.new_type_var();
++                let alias_eq = AliasEq {
++                    alias: AliasTy::Projection(ProjectionTy {
++                        associated_ty_id: to_assoc_type_id(residual),
++                        substitution,
++                    }),
++                    ty: residual_ty.clone(),
++                };
++                self.push_obligation(alias_eq.cast(Interner));
++                residual_ty
++            }
++            None => self.err_ty(),
++        };
++        // FIXME: We are doing the work twice here I think?
++        Some((
++            trait_,
++            self.table.try_obligation(trait_ref.cast(Interner)).map(|_| (output_ty, residual_ty)),
++        ))
++    }
 +}
index 6ccd0b215c6e480e72e17ed62a663ffc2d02ad9c,0000000000000000000000000000000000000000..b00e3216b2d2ce7c384c09ff42f71f152a80bf1a
mode 100644,000000..100644
--- /dev/null
@@@ -1,741 -1,0 +1,740 @@@
-     IntTy, NoSolution, TyVariableKind, UniverseIndex,
 +//! Unification and canonicalization logic.
 +
 +use std::{fmt, mem, sync::Arc};
 +
 +use chalk_ir::{
 +    cast::Cast, fold::TypeFoldable, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy,
-         .expect("fold failed unexpectedly")
++    IntTy, TyVariableKind, UniverseIndex,
 +};
 +use chalk_solve::infer::ParameterEnaVariableExt;
 +use ena::unify::UnifyKey;
 +use hir_expand::name;
 +use stdx::never;
 +
 +use super::{InferOk, InferResult, InferenceContext, TypeError};
 +use crate::{
 +    db::HirDatabase, fold_tys, static_lifetime, traits::FnTrait, AliasEq, AliasTy, BoundVar,
 +    Canonical, Const, DebruijnIndex, GenericArg, GenericArgData, Goal, Guidance, InEnvironment,
 +    InferenceVar, Interner, Lifetime, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution,
 +    Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind,
 +};
 +
 +impl<'a> InferenceContext<'a> {
 +    pub(super) fn canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
 +        &mut self,
 +        t: T,
 +    ) -> Canonicalized<T>
 +    where
 +        T: HasInterner<Interner = Interner>,
 +    {
 +        self.table.canonicalize(t)
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +pub(crate) struct Canonicalized<T>
 +where
 +    T: HasInterner<Interner = Interner>,
 +{
 +    pub(crate) value: Canonical<T>,
 +    free_vars: Vec<GenericArg>,
 +}
 +
 +impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
 +    pub(super) fn apply_solution(
 +        &self,
 +        ctx: &mut InferenceTable<'_>,
 +        solution: Canonical<Substitution>,
 +    ) {
 +        // the solution may contain new variables, which we need to convert to new inference vars
 +        let new_vars = Substitution::from_iter(
 +            Interner,
 +            solution.binders.iter(Interner).map(|k| match &k.kind {
 +                VariableKind::Ty(TyVariableKind::General) => ctx.new_type_var().cast(Interner),
 +                VariableKind::Ty(TyVariableKind::Integer) => ctx.new_integer_var().cast(Interner),
 +                VariableKind::Ty(TyVariableKind::Float) => ctx.new_float_var().cast(Interner),
 +                // Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere
 +                VariableKind::Lifetime => static_lifetime().cast(Interner),
 +                VariableKind::Const(ty) => ctx.new_const_var(ty.clone()).cast(Interner),
 +            }),
 +        );
 +        for (i, v) in solution.value.iter(Interner).enumerate() {
 +            let var = self.free_vars[i].clone();
 +            if let Some(ty) = v.ty(Interner) {
 +                // eagerly replace projections in the type; we may be getting types
 +                // e.g. from where clauses where this hasn't happened yet
 +                let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), Interner));
 +                ctx.unify(var.assert_ty_ref(Interner), &ty);
 +            } else {
 +                let _ = ctx.try_unify(&var, &new_vars.apply(v.clone(), Interner));
 +            }
 +        }
 +    }
 +}
 +
 +pub fn could_unify(
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    tys: &Canonical<(Ty, Ty)>,
 +) -> bool {
 +    unify(db, env, tys).is_some()
 +}
 +
 +pub(crate) fn unify(
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    tys: &Canonical<(Ty, Ty)>,
 +) -> Option<Substitution> {
 +    let mut table = InferenceTable::new(db, env);
 +    let vars = Substitution::from_iter(
 +        Interner,
 +        tys.binders.iter(Interner).map(|x| match &x.kind {
 +            chalk_ir::VariableKind::Ty(_) => {
 +                GenericArgData::Ty(table.new_type_var()).intern(Interner)
 +            }
 +            chalk_ir::VariableKind::Lifetime => {
 +                GenericArgData::Ty(table.new_type_var()).intern(Interner)
 +            } // FIXME: maybe wrong?
 +            chalk_ir::VariableKind::Const(ty) => {
 +                GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
 +            }
 +        }),
 +    );
 +    let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner);
 +    let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner);
 +    if !table.unify(&ty1_with_vars, &ty2_with_vars) {
 +        return None;
 +    }
 +    // default any type vars that weren't unified back to their original bound vars
 +    // (kind of hacky)
 +    let find_var = |iv| {
 +        vars.iter(Interner).position(|v| match v.interned() {
 +            chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner),
 +            chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
 +            chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner),
 +        } == Some(iv))
 +    };
 +    let fallback = |iv, kind, default, binder| match kind {
 +        chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv)
 +            .map_or(default, |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner)),
 +        chalk_ir::VariableKind::Lifetime => find_var(iv)
 +            .map_or(default, |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner)),
 +        chalk_ir::VariableKind::Const(ty) => find_var(iv)
 +            .map_or(default, |i| BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner)),
 +    };
 +    Some(Substitution::from_iter(
 +        Interner,
 +        vars.iter(Interner).map(|v| table.resolve_with_fallback(v.clone(), &fallback)),
 +    ))
 +}
 +
 +#[derive(Copy, Clone, Debug)]
 +pub(crate) struct TypeVariableData {
 +    diverging: bool,
 +}
 +
 +type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>;
 +
 +#[derive(Clone)]
 +pub(crate) struct InferenceTable<'a> {
 +    pub(crate) db: &'a dyn HirDatabase,
 +    pub(crate) trait_env: Arc<TraitEnvironment>,
 +    var_unification_table: ChalkInferenceTable,
 +    type_variable_table: Vec<TypeVariableData>,
 +    pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
 +}
 +
 +pub(crate) struct InferenceTableSnapshot {
 +    var_table_snapshot: chalk_solve::infer::InferenceSnapshot<Interner>,
 +    pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
 +    type_variable_table_snapshot: Vec<TypeVariableData>,
 +}
 +
 +impl<'a> InferenceTable<'a> {
 +    pub(crate) fn new(db: &'a dyn HirDatabase, trait_env: Arc<TraitEnvironment>) -> Self {
 +        InferenceTable {
 +            db,
 +            trait_env,
 +            var_unification_table: ChalkInferenceTable::new(),
 +            type_variable_table: Vec::new(),
 +            pending_obligations: Vec::new(),
 +        }
 +    }
 +
 +    /// Chalk doesn't know about the `diverging` flag, so when it unifies two
 +    /// type variables of which one is diverging, the chosen root might not be
 +    /// diverging and we have no way of marking it as such at that time. This
 +    /// function goes through all type variables and make sure their root is
 +    /// marked as diverging if necessary, so that resolving them gives the right
 +    /// result.
 +    pub(super) fn propagate_diverging_flag(&mut self) {
 +        for i in 0..self.type_variable_table.len() {
 +            if !self.type_variable_table[i].diverging {
 +                continue;
 +            }
 +            let v = InferenceVar::from(i as u32);
 +            let root = self.var_unification_table.inference_var_root(v);
 +            if let Some(data) = self.type_variable_table.get_mut(root.index() as usize) {
 +                data.diverging = true;
 +            }
 +        }
 +    }
 +
 +    pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) {
 +        self.type_variable_table[iv.index() as usize].diverging = diverging;
 +    }
 +
 +    fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty {
 +        match kind {
 +            _ if self
 +                .type_variable_table
 +                .get(iv.index() as usize)
 +                .map_or(false, |data| data.diverging) =>
 +            {
 +                TyKind::Never
 +            }
 +            TyVariableKind::General => TyKind::Error,
 +            TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)),
 +            TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)),
 +        }
 +        .intern(Interner)
 +    }
 +
 +    pub(crate) fn canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
 +        &mut self,
 +        t: T,
 +    ) -> Canonicalized<T>
 +    where
 +        T: HasInterner<Interner = Interner>,
 +    {
 +        // try to resolve obligations before canonicalizing, since this might
 +        // result in new knowledge about variables
 +        self.resolve_obligations_as_possible();
 +        let result = self.var_unification_table.canonicalize(Interner, t);
 +        let free_vars = result
 +            .free_vars
 +            .into_iter()
 +            .map(|free_var| free_var.to_generic_arg(Interner))
 +            .collect();
 +        Canonicalized { value: result.quantified, free_vars }
 +    }
 +
 +    /// 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.
 +    pub(crate) fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
 +        fold_tys(
 +            ty,
 +            |ty, _| match ty.kind(Interner) {
 +                TyKind::Alias(AliasTy::Projection(proj_ty)) => {
 +                    self.normalize_projection_ty(proj_ty.clone())
 +                }
 +                _ => ty,
 +            },
 +            DebruijnIndex::INNERMOST,
 +        )
 +    }
 +
 +    pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
 +        let var = self.new_type_var();
 +        let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
 +        let obligation = alias_eq.cast(Interner);
 +        self.register_obligation(obligation);
 +        var
 +    }
 +
 +    fn extend_type_variable_table(&mut self, to_index: usize) {
 +        self.type_variable_table.extend(
 +            (0..1 + to_index - self.type_variable_table.len())
 +                .map(|_| TypeVariableData { diverging: false }),
 +        );
 +    }
 +
 +    fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty {
 +        let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
 +        // Chalk might have created some type variables for its own purposes that we don't know about...
 +        self.extend_type_variable_table(var.index() as usize);
 +        assert_eq!(var.index() as usize, self.type_variable_table.len() - 1);
 +        self.type_variable_table[var.index() as usize].diverging = diverging;
 +        var.to_ty_with_kind(Interner, kind)
 +    }
 +
 +    pub(crate) fn new_type_var(&mut self) -> Ty {
 +        self.new_var(TyVariableKind::General, false)
 +    }
 +
 +    pub(crate) fn new_integer_var(&mut self) -> Ty {
 +        self.new_var(TyVariableKind::Integer, false)
 +    }
 +
 +    pub(crate) fn new_float_var(&mut self) -> Ty {
 +        self.new_var(TyVariableKind::Float, false)
 +    }
 +
 +    pub(crate) fn new_maybe_never_var(&mut self) -> Ty {
 +        self.new_var(TyVariableKind::General, true)
 +    }
 +
 +    pub(crate) fn new_const_var(&mut self, ty: Ty) -> Const {
 +        let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
 +        var.to_const(Interner, ty)
 +    }
 +
 +    pub(crate) fn new_lifetime_var(&mut self) -> Lifetime {
 +        let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
 +        var.to_lifetime(Interner)
 +    }
 +
 +    pub(crate) fn resolve_with_fallback<T>(
 +        &mut self,
 +        t: T,
 +        fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
 +    ) -> T
 +    where
 +        T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
 +    {
 +        self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback)
 +    }
 +
 +    pub(crate) fn fresh_subst(&mut self, binders: &[CanonicalVarKind<Interner>]) -> Substitution {
 +        Substitution::from_iter(
 +            Interner,
 +            binders.iter().map(|kind| {
 +                let param_infer_var =
 +                    kind.map_ref(|&ui| self.var_unification_table.new_variable(ui));
 +                param_infer_var.to_generic_arg(Interner)
 +            }),
 +        )
 +    }
 +
 +    pub(crate) fn instantiate_canonical<T>(&mut self, canonical: Canonical<T>) -> T
 +    where
 +        T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + std::fmt::Debug,
 +    {
 +        let subst = self.fresh_subst(canonical.binders.as_slice(Interner));
 +        subst.apply(canonical.value, Interner)
 +    }
 +
 +    fn resolve_with_fallback_inner<T>(
 +        &mut self,
 +        var_stack: &mut Vec<InferenceVar>,
 +        t: T,
 +        fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
 +    ) -> T
 +    where
 +        T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
 +    {
 +        t.fold_with(
 +            &mut resolve::Resolver { table: self, var_stack, fallback },
 +            DebruijnIndex::INNERMOST,
 +        )
-             type Error = NoSolution;
 +    }
 +
 +    pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T
 +    where
 +        T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
 +    {
 +        self.resolve_with_fallback(t, &|_, _, d, _| d)
 +    }
 +
 +    /// Unify two types and register new trait goals that arise from that.
 +    pub(crate) fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
 +        let result = match self.try_unify(ty1, ty2) {
 +            Ok(r) => r,
 +            Err(_) => return false,
 +        };
 +        self.register_infer_ok(result);
 +        true
 +    }
 +
 +    /// Unify two types and return new trait goals arising from it, so the
 +    /// caller needs to deal with them.
 +    pub(crate) fn try_unify<T: Zip<Interner>>(&mut self, t1: &T, t2: &T) -> InferResult<()> {
 +        match self.var_unification_table.relate(
 +            Interner,
 +            &self.db,
 +            &self.trait_env.env,
 +            chalk_ir::Variance::Invariant,
 +            t1,
 +            t2,
 +        ) {
 +            Ok(result) => Ok(InferOk { goals: result.goals, value: () }),
 +            Err(chalk_ir::NoSolution) => Err(TypeError),
 +        }
 +    }
 +
 +    /// If `ty` is a type variable with known type, returns that type;
 +    /// otherwise, return ty.
 +    pub(crate) fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
 +        self.resolve_obligations_as_possible();
 +        self.var_unification_table.normalize_ty_shallow(Interner, ty).unwrap_or_else(|| ty.clone())
 +    }
 +
 +    pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot {
 +        let var_table_snapshot = self.var_unification_table.snapshot();
 +        let type_variable_table_snapshot = self.type_variable_table.clone();
 +        let pending_obligations = self.pending_obligations.clone();
 +        InferenceTableSnapshot {
 +            var_table_snapshot,
 +            pending_obligations,
 +            type_variable_table_snapshot,
 +        }
 +    }
 +
 +    pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot) {
 +        self.var_unification_table.rollback_to(snapshot.var_table_snapshot);
 +        self.type_variable_table = snapshot.type_variable_table_snapshot;
 +        self.pending_obligations = snapshot.pending_obligations;
 +    }
 +
 +    pub(crate) fn run_in_snapshot<T>(&mut self, f: impl FnOnce(&mut InferenceTable<'_>) -> T) -> T {
 +        let snapshot = self.snapshot();
 +        let result = f(self);
 +        self.rollback_to(snapshot);
 +        result
 +    }
 +
 +    /// Checks an obligation without registering it. Useful mostly to check
 +    /// whether a trait *might* be implemented before deciding to 'lock in' the
 +    /// choice (during e.g. method resolution or deref).
 +    pub(crate) fn try_obligation(&mut self, goal: Goal) -> Option<Solution> {
 +        let in_env = InEnvironment::new(&self.trait_env.env, goal);
 +        let canonicalized = self.canonicalize(in_env);
 +        let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value);
 +        solution
 +    }
 +
 +    pub(crate) fn register_obligation(&mut self, goal: Goal) {
 +        let in_env = InEnvironment::new(&self.trait_env.env, goal);
 +        self.register_obligation_in_env(in_env)
 +    }
 +
 +    fn register_obligation_in_env(&mut self, goal: InEnvironment<Goal>) {
 +        let canonicalized = self.canonicalize(goal);
 +        if !self.try_resolve_obligation(&canonicalized) {
 +            self.pending_obligations.push(canonicalized);
 +        }
 +    }
 +
 +    pub(crate) fn register_infer_ok<T>(&mut self, infer_ok: InferOk<T>) {
 +        infer_ok.goals.into_iter().for_each(|goal| self.register_obligation_in_env(goal));
 +    }
 +
 +    pub(crate) fn resolve_obligations_as_possible(&mut self) {
 +        let _span = profile::span("resolve_obligations_as_possible");
 +        let mut changed = true;
 +        let mut obligations = Vec::new();
 +        while changed {
 +            changed = false;
 +            mem::swap(&mut self.pending_obligations, &mut obligations);
 +            for canonicalized in obligations.drain(..) {
 +                if !self.check_changed(&canonicalized) {
 +                    self.pending_obligations.push(canonicalized);
 +                    continue;
 +                }
 +                changed = true;
 +                let uncanonical = chalk_ir::Substitute::apply(
 +                    &canonicalized.free_vars,
 +                    canonicalized.value.value,
 +                    Interner,
 +                );
 +                self.register_obligation_in_env(uncanonical);
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn fudge_inference<T: TypeFoldable<Interner>>(
 +        &mut self,
 +        f: impl FnOnce(&mut Self) -> T,
 +    ) -> T {
 +        use chalk_ir::fold::TypeFolder;
++
++        #[derive(chalk_derive::FallibleTypeFolder)]
++        #[has_interner(Interner)]
 +        struct VarFudger<'a, 'b> {
 +            table: &'a mut InferenceTable<'b>,
 +            highest_known_var: InferenceVar,
 +        }
 +        impl<'a, 'b> TypeFolder<Interner> for VarFudger<'a, 'b> {
-             ) -> chalk_ir::Fallible<chalk_ir::Ty<Interner>> {
-                 Ok(if var < self.highest_known_var {
 +            fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
 +                self
 +            }
 +
 +            fn interner(&self) -> Interner {
 +                Interner
 +            }
 +
 +            fn fold_inference_ty(
 +                &mut self,
 +                var: chalk_ir::InferenceVar,
 +                kind: TyVariableKind,
 +                _outer_binder: chalk_ir::DebruijnIndex,
-                 })
++            ) -> chalk_ir::Ty<Interner> {
++                if var < self.highest_known_var {
 +                    var.to_ty(Interner, kind)
 +                } else {
 +                    self.table.new_type_var()
-             ) -> chalk_ir::Fallible<chalk_ir::Lifetime<Interner>> {
-                 Ok(if var < self.highest_known_var {
++                }
 +            }
 +
 +            fn fold_inference_lifetime(
 +                &mut self,
 +                var: chalk_ir::InferenceVar,
 +                _outer_binder: chalk_ir::DebruijnIndex,
-                 })
++            ) -> chalk_ir::Lifetime<Interner> {
++                if var < self.highest_known_var {
 +                    var.to_lifetime(Interner)
 +                } else {
 +                    self.table.new_lifetime_var()
-             ) -> chalk_ir::Fallible<chalk_ir::Const<Interner>> {
-                 Ok(if var < self.highest_known_var {
++                }
 +            }
 +
 +            fn fold_inference_const(
 +                &mut self,
 +                ty: chalk_ir::Ty<Interner>,
 +                var: chalk_ir::InferenceVar,
 +                _outer_binder: chalk_ir::DebruijnIndex,
-                 })
++            ) -> chalk_ir::Const<Interner> {
++                if var < self.highest_known_var {
 +                    var.to_const(Interner, ty)
 +                } else {
 +                    self.table.new_const_var(ty)
-             .expect("fold_with with VarFudger")
++                }
 +            }
 +        }
 +
 +        let snapshot = self.snapshot();
 +        let highest_known_var = self.new_type_var().inference_var(Interner).expect("inference_var");
 +        let result = f(self);
 +        self.rollback_to(snapshot);
 +        result
 +            .fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST)
-         Fallible, NoSolution,
 +    }
 +
 +    /// This checks whether any of the free variables in the `canonicalized`
 +    /// have changed (either been unified with another variable, or with a
 +    /// value). If this is not the case, we don't need to try to solve the goal
 +    /// again -- it'll give the same result as last time.
 +    fn check_changed(&mut self, canonicalized: &Canonicalized<InEnvironment<Goal>>) -> bool {
 +        canonicalized.free_vars.iter().any(|var| {
 +            let iv = match var.data(Interner) {
 +                chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner),
 +                chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
 +                chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner),
 +            }
 +            .expect("free var is not inference var");
 +            if self.var_unification_table.probe_var(iv).is_some() {
 +                return true;
 +            }
 +            let root = self.var_unification_table.inference_var_root(iv);
 +            iv != root
 +        })
 +    }
 +
 +    fn try_resolve_obligation(
 +        &mut self,
 +        canonicalized: &Canonicalized<InEnvironment<Goal>>,
 +    ) -> bool {
 +        let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value.clone());
 +
 +        match solution {
 +            Some(Solution::Unique(canonical_subst)) => {
 +                canonicalized.apply_solution(
 +                    self,
 +                    Canonical {
 +                        binders: canonical_subst.binders,
 +                        // FIXME: handle constraints
 +                        value: canonical_subst.value.subst,
 +                    },
 +                );
 +                true
 +            }
 +            Some(Solution::Ambig(Guidance::Definite(substs))) => {
 +                canonicalized.apply_solution(self, substs);
 +                false
 +            }
 +            Some(_) => {
 +                // FIXME use this when trying to resolve everything at the end
 +                false
 +            }
 +            None => {
 +                // FIXME obligation cannot be fulfilled => diagnostic
 +                true
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn callable_sig(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> {
 +        match ty.callable_sig(self.db) {
 +            Some(sig) => Some((sig.params().to_vec(), sig.ret().clone())),
 +            None => self.callable_sig_from_fn_trait(ty, num_args),
 +        }
 +    }
 +
 +    fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> {
 +        let krate = self.trait_env.krate;
 +        let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?;
 +        let output_assoc_type =
 +            self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
 +
 +        let mut arg_tys = vec![];
 +        let arg_ty = TyBuilder::tuple(num_args)
 +            .fill(|x| {
 +                let arg = match x {
 +                    ParamKind::Type => self.new_type_var(),
 +                    ParamKind::Const(ty) => {
 +                        never!("Tuple with const parameter");
 +                        return GenericArgData::Const(self.new_const_var(ty.clone()))
 +                            .intern(Interner);
 +                    }
 +                };
 +                arg_tys.push(arg.clone());
 +                GenericArgData::Ty(arg).intern(Interner)
 +            })
 +            .build();
 +
 +        let projection = {
 +            let b = TyBuilder::subst_for_def(self.db, fn_once_trait, None);
 +            if b.remaining() != 2 {
 +                return None;
 +            }
 +            let fn_once_subst = b.push(ty.clone()).push(arg_ty).build();
 +
 +            TyBuilder::assoc_type_projection(self.db, output_assoc_type, Some(fn_once_subst))
 +                .build()
 +        };
 +
 +        let trait_env = self.trait_env.env.clone();
 +        let obligation = InEnvironment {
 +            goal: projection.trait_ref(self.db).cast(Interner),
 +            environment: trait_env,
 +        };
 +        let canonical = self.canonicalize(obligation.clone());
 +        if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() {
 +            self.register_obligation(obligation.goal);
 +            let return_ty = self.normalize_projection_ty(projection);
 +            Some((arg_tys, return_ty))
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +impl<'a> fmt::Debug for InferenceTable<'a> {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        f.debug_struct("InferenceTable").field("num_vars", &self.type_variable_table.len()).finish()
 +    }
 +}
 +
 +mod resolve {
 +    use super::InferenceTable;
 +    use crate::{
 +        ConcreteConst, Const, ConstData, ConstValue, DebruijnIndex, GenericArg, InferenceVar,
 +        Interner, Lifetime, Ty, TyVariableKind, VariableKind,
 +    };
 +    use chalk_ir::{
 +        cast::Cast,
 +        fold::{TypeFoldable, TypeFolder},
-     pub(super) struct Resolver<'a, 'b, F> {
 +    };
 +    use hir_def::type_ref::ConstScalar;
 +
-     impl<'a, 'b, 'i, F> TypeFolder<Interner> for Resolver<'a, 'b, F>
++    #[derive(chalk_derive::FallibleTypeFolder)]
++    #[has_interner(Interner)]
++    pub(super) struct Resolver<
++        'a,
++        'b,
++        F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
++    > {
 +        pub(super) table: &'a mut InferenceTable<'b>,
 +        pub(super) var_stack: &'a mut Vec<InferenceVar>,
 +        pub(super) fallback: F,
 +    }
-         F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg + 'i,
++    impl<'a, 'b, F> TypeFolder<Interner> for Resolver<'a, 'b, F>
 +    where
-         type Error = NoSolution;
++        F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
 +    {
-         ) -> Fallible<Ty> {
 +        fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
 +            self
 +        }
 +
 +        fn interner(&self) -> Interner {
 +            Interner
 +        }
 +
 +        fn fold_inference_ty(
 +            &mut self,
 +            var: InferenceVar,
 +            kind: TyVariableKind,
 +            outer_binder: DebruijnIndex,
-                 return Ok((self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
++        ) -> Ty {
 +            let var = self.table.var_unification_table.inference_var_root(var);
 +            if self.var_stack.contains(&var) {
 +                // recursive type
 +                let default = self.table.fallback_value(var, kind).cast(Interner);
-                     .clone());
++                return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
 +                    .assert_ty_ref(Interner)
-                 let result =
-                     known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly");
++                    .clone();
 +            }
 +            let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
 +                // known_ty may contain other variables that are known by now
 +                self.var_stack.push(var);
-             Ok(result)
++                let result = known_ty.fold_with(self, outer_binder);
 +                self.var_stack.pop();
 +                result.assert_ty_ref(Interner).clone()
 +            } else {
 +                let default = self.table.fallback_value(var, kind).cast(Interner);
 +                (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
 +                    .assert_ty_ref(Interner)
 +                    .clone()
 +            };
-         ) -> Fallible<Const> {
++            result
 +        }
 +
 +        fn fold_inference_const(
 +            &mut self,
 +            ty: Ty,
 +            var: InferenceVar,
 +            outer_binder: DebruijnIndex,
-                 return Ok((self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
++        ) -> Const {
 +            let var = self.table.var_unification_table.inference_var_root(var);
 +            let default = ConstData {
 +                ty: ty.clone(),
 +                value: ConstValue::Concrete(ConcreteConst { interned: ConstScalar::Unknown }),
 +            }
 +            .intern(Interner)
 +            .cast(Interner);
 +            if self.var_stack.contains(&var) {
 +                // recursive
-                     .clone());
++                return (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
 +                    .assert_const_ref(Interner)
-             let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
++                    .clone();
 +            }
-                 let result =
-                     known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly");
++            if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
 +                // known_ty may contain other variables that are known by now
 +                self.var_stack.push(var);
-             };
-             Ok(result)
++                let result = known_ty.fold_with(self, outer_binder);
 +                self.var_stack.pop();
 +                result.assert_const_ref(Interner).clone()
 +            } else {
 +                (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
 +                    .assert_const_ref(Interner)
 +                    .clone()
-         ) -> Fallible<Lifetime> {
++            }
 +        }
 +
 +        fn fold_inference_lifetime(
 +            &mut self,
 +            _var: InferenceVar,
 +            _outer_binder: DebruijnIndex,
-             Ok(crate::static_lifetime())
++        ) -> Lifetime {
 +            // fall back all lifetimes to 'static -- currently we don't deal
 +            // with any lifetimes, but we can sometimes get some lifetime
 +            // variables through Chalk's unification, and this at least makes
 +            // sure we don't leak them outside of inference
++            crate::static_lifetime()
 +        }
 +    }
 +}
index de4a5446e57f00e948bee718ae6013dcddbb99b7,0000000000000000000000000000000000000000..c4b700cbce6db78284321f80bd956e9a4e5f5165
mode 100644,000000..100644
--- /dev/null
@@@ -1,512 -1,0 +1,506 @@@
-     fn fold_with<E>(
 +//! The type system. We currently use this to infer types for completion, hover
 +//! information and various assists.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +#[allow(unused)]
 +macro_rules! eprintln {
 +    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
 +}
 +
 +mod autoderef;
 +mod builder;
 +mod chalk_db;
 +mod chalk_ext;
 +pub mod consteval;
 +mod infer;
 +mod inhabitedness;
 +mod interner;
 +mod lower;
 +mod mapping;
 +mod tls;
 +mod utils;
 +mod walk;
 +pub mod db;
 +pub mod diagnostics;
 +pub mod display;
 +pub mod method_resolution;
 +pub mod primitive;
 +pub mod traits;
 +
 +#[cfg(test)]
 +mod tests;
 +#[cfg(test)]
 +mod test_db;
 +
 +use std::sync::Arc;
 +
 +use chalk_ir::{
 +    fold::{Shift, TypeFoldable},
 +    interner::HasInterner,
 +    NoSolution,
 +};
 +use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId};
 +use itertools::Either;
 +use utils::Generics;
 +
 +use crate::{consteval::unknown_const, db::HirDatabase, utils::generics};
 +
 +pub use autoderef::autoderef;
 +pub use builder::{ParamKind, TyBuilder};
 +pub use chalk_ext::*;
 +pub use infer::{
 +    could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic,
 +    InferenceResult,
 +};
 +pub use interner::Interner;
 +pub use lower::{
 +    associated_type_shorthand_candidates, CallableDefId, ImplTraitLoweringMode, TyDefId,
 +    TyLoweringContext, ValueTyDefId,
 +};
 +pub use mapping::{
 +    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
 +    lt_from_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id,
 +    to_placeholder_idx,
 +};
 +pub use traits::TraitEnvironment;
 +pub use utils::{all_super_traits, is_fn_unsafe_to_call};
 +pub use walk::TypeWalk;
 +
 +pub use chalk_ir::{
 +    cast::Cast, AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind,
 +};
 +
 +pub type ForeignDefId = chalk_ir::ForeignDefId<Interner>;
 +pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
 +pub type FnDefId = chalk_ir::FnDefId<Interner>;
 +pub type ClosureId = chalk_ir::ClosureId<Interner>;
 +pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
 +pub type PlaceholderIndex = chalk_ir::PlaceholderIndex;
 +
 +pub type VariableKind = chalk_ir::VariableKind<Interner>;
 +pub type VariableKinds = chalk_ir::VariableKinds<Interner>;
 +pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>;
 +pub type Binders<T> = chalk_ir::Binders<T>;
 +pub type Substitution = chalk_ir::Substitution<Interner>;
 +pub type GenericArg = chalk_ir::GenericArg<Interner>;
 +pub type GenericArgData = chalk_ir::GenericArgData<Interner>;
 +
 +pub type Ty = chalk_ir::Ty<Interner>;
 +pub type TyKind = chalk_ir::TyKind<Interner>;
 +pub type DynTy = chalk_ir::DynTy<Interner>;
 +pub type FnPointer = chalk_ir::FnPointer<Interner>;
 +// pub type FnSubst = chalk_ir::FnSubst<Interner>;
 +pub use chalk_ir::FnSubst;
 +pub type ProjectionTy = chalk_ir::ProjectionTy<Interner>;
 +pub type AliasTy = chalk_ir::AliasTy<Interner>;
 +pub type OpaqueTy = chalk_ir::OpaqueTy<Interner>;
 +pub type InferenceVar = chalk_ir::InferenceVar;
 +
 +pub type Lifetime = chalk_ir::Lifetime<Interner>;
 +pub type LifetimeData = chalk_ir::LifetimeData<Interner>;
 +pub type LifetimeOutlives = chalk_ir::LifetimeOutlives<Interner>;
 +
 +pub type Const = chalk_ir::Const<Interner>;
 +pub type ConstData = chalk_ir::ConstData<Interner>;
 +pub type ConstValue = chalk_ir::ConstValue<Interner>;
 +pub type ConcreteConst = chalk_ir::ConcreteConst<Interner>;
 +
 +pub type ChalkTraitId = chalk_ir::TraitId<Interner>;
 +pub type TraitRef = chalk_ir::TraitRef<Interner>;
 +pub type QuantifiedWhereClause = Binders<WhereClause>;
 +pub type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses<Interner>;
 +pub type Canonical<T> = chalk_ir::Canonical<T>;
 +
 +pub type FnSig = chalk_ir::FnSig<Interner>;
 +
 +pub type InEnvironment<T> = chalk_ir::InEnvironment<T>;
 +pub type Environment = chalk_ir::Environment<Interner>;
 +pub type DomainGoal = chalk_ir::DomainGoal<Interner>;
 +pub type Goal = chalk_ir::Goal<Interner>;
 +pub type AliasEq = chalk_ir::AliasEq<Interner>;
 +pub type Solution = chalk_solve::Solution<Interner>;
 +pub type ConstrainedSubst = chalk_ir::ConstrainedSubst<Interner>;
 +pub type Guidance = chalk_solve::Guidance<Interner>;
 +pub type WhereClause = chalk_ir::WhereClause<Interner>;
 +
 +// FIXME: get rid of this
 +pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution {
 +    Substitution::from_iter(
 +        Interner,
 +        s.as_slice(Interner)[..std::cmp::min(s.len(Interner), n)].iter().cloned(),
 +    )
 +}
 +
 +/// Return an index of a parameter in the generic type parameter list by it's id.
 +pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<usize> {
 +    generics(db.upcast(), id.parent).param_idx(id)
 +}
 +
 +pub(crate) fn wrap_empty_binders<T>(value: T) -> Binders<T>
 +where
 +    T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
 +{
 +    Binders::empty(Interner, value.shifted_in_from(Interner, DebruijnIndex::ONE))
 +}
 +
 +pub(crate) fn make_type_and_const_binders<T: HasInterner<Interner = Interner>>(
 +    which_is_const: impl Iterator<Item = Option<Ty>>,
 +    value: T,
 +) -> Binders<T> {
 +    Binders::new(
 +        VariableKinds::from_iter(
 +            Interner,
 +            which_is_const.map(|x| {
 +                if let Some(ty) = x {
 +                    chalk_ir::VariableKind::Const(ty)
 +                } else {
 +                    chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
 +                }
 +            }),
 +        ),
 +        value,
 +    )
 +}
 +
 +pub(crate) fn make_single_type_binders<T: HasInterner<Interner = Interner>>(
 +    value: T,
 +) -> Binders<T> {
 +    Binders::new(
 +        VariableKinds::from_iter(
 +            Interner,
 +            std::iter::once(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)),
 +        ),
 +        value,
 +    )
 +}
 +
 +pub(crate) fn make_binders_with_count<T: HasInterner<Interner = Interner>>(
 +    db: &dyn HirDatabase,
 +    count: usize,
 +    generics: &Generics,
 +    value: T,
 +) -> Binders<T> {
 +    let it = generics.iter_id().take(count).map(|id| match id {
 +        Either::Left(_) => None,
 +        Either::Right(id) => Some(db.const_param_ty(id)),
 +    });
 +    crate::make_type_and_const_binders(it, value)
 +}
 +
 +pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
 +    db: &dyn HirDatabase,
 +    generics: &Generics,
 +    value: T,
 +) -> Binders<T> {
 +    make_binders_with_count(db, usize::MAX, generics, value)
 +}
 +
 +// FIXME: get rid of this, just replace it by FnPointer
 +/// A function signature as seen by type inference: Several parameter types and
 +/// one return type.
 +#[derive(Clone, PartialEq, Eq, Debug)]
 +pub struct CallableSig {
 +    params_and_return: Arc<[Ty]>,
 +    is_varargs: bool,
 +}
 +
 +has_interner!(CallableSig);
 +
 +/// A polymorphic function signature.
 +pub type PolyFnSig = Binders<CallableSig>;
 +
 +impl CallableSig {
 +    pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty, is_varargs: bool) -> CallableSig {
 +        params.push(ret);
 +        CallableSig { params_and_return: params.into(), is_varargs }
 +    }
 +
 +    pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
 +        CallableSig {
 +            // FIXME: what to do about lifetime params? -> return PolyFnSig
 +            params_and_return: fn_ptr
 +                .substitution
 +                .clone()
 +                .shifted_out_to(Interner, DebruijnIndex::ONE)
 +                .expect("unexpected lifetime vars in fn ptr")
 +                .0
 +                .as_slice(Interner)
 +                .iter()
 +                .map(|arg| arg.assert_ty_ref(Interner).clone())
 +                .collect(),
 +            is_varargs: fn_ptr.sig.variadic,
 +        }
 +    }
 +
 +    pub fn to_fn_ptr(&self) -> FnPointer {
 +        FnPointer {
 +            num_binders: 0,
 +            sig: FnSig { abi: (), safety: Safety::Safe, variadic: self.is_varargs },
 +            substitution: FnSubst(Substitution::from_iter(
 +                Interner,
 +                self.params_and_return.iter().cloned(),
 +            )),
 +        }
 +    }
 +
 +    pub fn params(&self) -> &[Ty] {
 +        &self.params_and_return[0..self.params_and_return.len() - 1]
 +    }
 +
 +    pub fn ret(&self) -> &Ty {
 +        &self.params_and_return[self.params_and_return.len() - 1]
 +    }
 +}
 +
 +impl TypeFoldable<Interner> for CallableSig {
-         folder: &mut dyn chalk_ir::fold::TypeFolder<Interner, Error = E>,
++    fn try_fold_with<E>(
 +        self,
-         let folded = vec.fold_with(folder, outer_binder)?;
++        folder: &mut dyn chalk_ir::fold::FallibleTypeFolder<Interner, Error = E>,
 +        outer_binder: DebruijnIndex,
 +    ) -> Result<Self, E> {
 +        let vec = self.params_and_return.to_vec();
-     use chalk_ir::{fold::TypeFolder, Fallible};
-     struct FreeVarFolder<F1, F2>(F1, F2);
++        let folded = vec.try_fold_with(folder, outer_binder)?;
 +        Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
 +    }
 +}
 +
 +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
 +pub enum ImplTraitId {
 +    ReturnTypeImplTrait(hir_def::FunctionId, u16),
 +    AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
 +}
 +
 +#[derive(Clone, PartialEq, Eq, Debug, Hash)]
 +pub struct ReturnTypeImplTraits {
 +    pub(crate) impl_traits: Vec<ReturnTypeImplTrait>,
 +}
 +
 +has_interner!(ReturnTypeImplTraits);
 +
 +#[derive(Clone, PartialEq, Eq, Debug, Hash)]
 +pub(crate) struct ReturnTypeImplTrait {
 +    pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
 +}
 +
 +pub fn static_lifetime() -> Lifetime {
 +    LifetimeData::Static.intern(Interner)
 +}
 +
 +pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
 +    t: T,
 +    for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
 +    for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
 +) -> T {
-             'i,
-             F1: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i,
-             F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const + 'i,
++    use chalk_ir::fold::TypeFolder;
++
++    #[derive(chalk_derive::FallibleTypeFolder)]
++    #[has_interner(Interner)]
++    struct FreeVarFolder<
++        F1: FnMut(BoundVar, DebruijnIndex) -> Ty,
++        F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
++    >(F1, F2);
 +    impl<
-         type Error = NoSolution;
++            F1: FnMut(BoundVar, DebruijnIndex) -> Ty,
++            F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
 +        > TypeFolder<Interner> for FreeVarFolder<F1, F2>
 +    {
-         fn fold_free_var_ty(
-             &mut self,
-             bound_var: BoundVar,
-             outer_binder: DebruijnIndex,
-         ) -> Fallible<Ty> {
-             Ok(self.0(bound_var, outer_binder))
 +        fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
 +            self
 +        }
 +
 +        fn interner(&self) -> Interner {
 +            Interner
 +        }
 +
-         ) -> Fallible<Const> {
-             Ok(self.1(ty, bound_var, outer_binder))
++        fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty {
++            self.0(bound_var, outer_binder)
 +        }
 +
 +        fn fold_free_var_const(
 +            &mut self,
 +            ty: Ty,
 +            bound_var: BoundVar,
 +            outer_binder: DebruijnIndex,
-         .expect("fold failed unexpectedly")
++        ) -> Const {
++            self.1(ty, bound_var, outer_binder)
 +        }
 +    }
 +    t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST)
-     use chalk_ir::{
-         fold::{TypeFolder, TypeSuperFoldable},
-         Fallible,
-     };
-     struct TyFolder<F>(F);
-     impl<'i, F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const> + 'i>
-         TypeFolder<Interner> for TyFolder<F>
 +}
 +
 +pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
 +    t: T,
 +    mut for_ty: impl FnMut(Ty, DebruijnIndex) -> Ty,
 +    binders: DebruijnIndex,
 +) -> T {
 +    fold_tys_and_consts(
 +        t,
 +        |x, d| match x {
 +            Either::Left(x) => Either::Left(for_ty(x, d)),
 +            Either::Right(x) => Either::Right(x),
 +        },
 +        binders,
 +    )
 +}
 +
 +pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
 +    t: T,
 +    f: impl FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>,
 +    binders: DebruijnIndex,
 +) -> T {
-         type Error = NoSolution;
++    use chalk_ir::fold::{TypeFolder, TypeSuperFoldable};
++    #[derive(chalk_derive::FallibleTypeFolder)]
++    #[has_interner(Interner)]
++    struct TyFolder<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>>(F);
++    impl<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>> TypeFolder<Interner>
++        for TyFolder<F>
 +    {
-         fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
-             let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
-             Ok(self.0(Either::Left(ty), outer_binder).left().unwrap())
 +        fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
 +            self
 +        }
 +
 +        fn interner(&self) -> Interner {
 +            Interner
 +        }
 +
-         fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Fallible<Const> {
-             Ok(self.0(Either::Right(c), outer_binder).right().unwrap())
++        fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty {
++            let ty = ty.super_fold_with(self.as_dyn(), outer_binder);
++            self.0(Either::Left(ty), outer_binder).left().unwrap()
 +        }
 +
-     t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
++        fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Const {
++            self.0(Either::Right(c), outer_binder).right().unwrap()
 +        }
 +    }
-         fold::{TypeFolder, TypeSuperFoldable},
++    t.fold_with(&mut TyFolder(f), binders)
 +}
 +
 +/// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
 +/// ensures there are no unbound variables or inference variables anywhere in
 +/// the `t`.
 +pub fn replace_errors_with_variables<T>(t: &T) -> Canonical<T>
 +where
 +    T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + Clone,
 +    T: HasInterner<Interner = Interner>,
 +{
 +    use chalk_ir::{
-     impl TypeFolder<Interner> for ErrorReplacer {
++        fold::{FallibleTypeFolder, TypeSuperFoldable},
 +        Fallible,
 +    };
 +    struct ErrorReplacer {
 +        vars: usize,
 +    }
-         fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
++    impl FallibleTypeFolder<Interner> for ErrorReplacer {
 +        type Error = NoSolution;
 +
-         fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
++        fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = Self::Error> {
 +            self
 +        }
 +
 +        fn interner(&self) -> Interner {
 +            Interner
 +        }
 +
-                 let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
-                 Ok(ty)
++        fn try_fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
 +            if let TyKind::Error = ty.kind(Interner) {
 +                let index = self.vars;
 +                self.vars += 1;
 +                Ok(TyKind::BoundVar(BoundVar::new(outer_binder, index)).intern(Interner))
 +            } else {
-         fn fold_inference_ty(
++                ty.try_super_fold_with(self.as_dyn(), outer_binder)
 +            }
 +        }
 +
-         fn fold_free_var_ty(
++        fn try_fold_inference_ty(
 +            &mut self,
 +            _var: InferenceVar,
 +            _kind: TyVariableKind,
 +            _outer_binder: DebruijnIndex,
 +        ) -> Fallible<Ty> {
 +            if cfg!(debug_assertions) {
 +                // we don't want to just panic here, because then the error message
 +                // won't contain the whole thing, which would not be very helpful
 +                Err(NoSolution)
 +            } else {
 +                Ok(TyKind::Error.intern(Interner))
 +            }
 +        }
 +
-         fn fold_inference_const(
++        fn try_fold_free_var_ty(
 +            &mut self,
 +            _bound_var: BoundVar,
 +            _outer_binder: DebruijnIndex,
 +        ) -> Fallible<Ty> {
 +            if cfg!(debug_assertions) {
 +                // we don't want to just panic here, because then the error message
 +                // won't contain the whole thing, which would not be very helpful
 +                Err(NoSolution)
 +            } else {
 +                Ok(TyKind::Error.intern(Interner))
 +            }
 +        }
 +
-         fn fold_free_var_const(
++        fn try_fold_inference_const(
 +            &mut self,
 +            ty: Ty,
 +            _var: InferenceVar,
 +            _outer_binder: DebruijnIndex,
 +        ) -> Fallible<Const> {
 +            if cfg!(debug_assertions) {
 +                Err(NoSolution)
 +            } else {
 +                Ok(unknown_const(ty))
 +            }
 +        }
 +
-         fn fold_inference_lifetime(
++        fn try_fold_free_var_const(
 +            &mut self,
 +            ty: Ty,
 +            _bound_var: BoundVar,
 +            _outer_binder: DebruijnIndex,
 +        ) -> Fallible<Const> {
 +            if cfg!(debug_assertions) {
 +                Err(NoSolution)
 +            } else {
 +                Ok(unknown_const(ty))
 +            }
 +        }
 +
-         fn fold_free_var_lifetime(
++        fn try_fold_inference_lifetime(
 +            &mut self,
 +            _var: InferenceVar,
 +            _outer_binder: DebruijnIndex,
 +        ) -> Fallible<Lifetime> {
 +            if cfg!(debug_assertions) {
 +                Err(NoSolution)
 +            } else {
 +                Ok(static_lifetime())
 +            }
 +        }
 +
-     let value = match t.clone().fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
++        fn try_fold_free_var_lifetime(
 +            &mut self,
 +            _bound_var: BoundVar,
 +            _outer_binder: DebruijnIndex,
 +        ) -> Fallible<Lifetime> {
 +            if cfg!(debug_assertions) {
 +                Err(NoSolution)
 +            } else {
 +                Ok(static_lifetime())
 +            }
 +        }
 +    }
 +    let mut error_replacer = ErrorReplacer { vars: 0 };
++    let value = match t.clone().try_fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
 +        Ok(t) => t,
 +        Err(_) => panic!("Encountered unbound or inference vars in {:?}", t),
 +    };
 +    let kinds = (0..error_replacer.vars).map(|_| {
 +        chalk_ir::CanonicalVarKind::new(
 +            chalk_ir::VariableKind::Ty(TyVariableKind::General),
 +            chalk_ir::UniverseIndex::ROOT,
 +        )
 +    });
 +    Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
 +}
index 3a1a3f4fdeb3b70d66d95c5415598723b6324c6c,0000000000000000000000000000000000000000..a79efeb6daa84dbc0a736ff01668dbcaa139b0e3
mode 100644,000000..100644
--- /dev/null
@@@ -1,1329 -1,0 +1,1347 @@@
 +//! This module is concerned with finding methods that a given type provides.
 +//! For details about how this works in rustc, see the method lookup page in the
 +//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
 +//! and the corresponding code mostly in rustc_hir_analysis/check/method/probe.rs.
 +use std::{iter, ops::ControlFlow, sync::Arc};
 +
 +use arrayvec::ArrayVec;
 +use base_db::{CrateId, Edition};
 +use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
 +use hir_def::{
 +    data::ImplData, item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId, ConstId,
 +    FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId,
 +    TraitId,
 +};
 +use hir_expand::name::Name;
 +use rustc_hash::{FxHashMap, FxHashSet};
 +use stdx::never;
 +
 +use crate::{
 +    autoderef::{self, AutoderefKind},
 +    db::HirDatabase,
 +    from_foreign_def_id,
 +    infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
 +    primitive::{FloatTy, IntTy, UintTy},
 +    static_lifetime,
 +    utils::all_super_traits,
 +    AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
 +    Scalar, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
 +};
 +
 +/// This is used as a key for indexing impls.
 +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 +pub enum TyFingerprint {
 +    // These are lang item impls:
 +    Str,
 +    Slice,
 +    Array,
 +    Never,
 +    RawPtr(Mutability),
 +    Scalar(Scalar),
 +    // These can have user-defined impls:
 +    Adt(hir_def::AdtId),
 +    Dyn(TraitId),
 +    ForeignType(ForeignDefId),
 +    // These only exist for trait impls
 +    Unit,
 +    Unnameable,
 +    Function(u32),
 +}
 +
 +impl TyFingerprint {
 +    /// Creates a TyFingerprint for looking up an inherent impl. Only certain
 +    /// types can have inherent impls: if we have some `struct S`, we can have
 +    /// an `impl S`, but not `impl &S`. Hence, this will return `None` for
 +    /// reference types and such.
 +    pub fn for_inherent_impl(ty: &Ty) -> Option<TyFingerprint> {
 +        let fp = match ty.kind(Interner) {
 +            TyKind::Str => TyFingerprint::Str,
 +            TyKind::Never => TyFingerprint::Never,
 +            TyKind::Slice(..) => TyFingerprint::Slice,
 +            TyKind::Array(..) => TyFingerprint::Array,
 +            TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
 +            TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
 +            TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
 +            TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
 +            TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?,
 +            _ => return None,
 +        };
 +        Some(fp)
 +    }
 +
 +    /// Creates a TyFingerprint for looking up a trait impl.
 +    pub fn for_trait_impl(ty: &Ty) -> Option<TyFingerprint> {
 +        let fp = match ty.kind(Interner) {
 +            TyKind::Str => TyFingerprint::Str,
 +            TyKind::Never => TyFingerprint::Never,
 +            TyKind::Slice(..) => TyFingerprint::Slice,
 +            TyKind::Array(..) => TyFingerprint::Array,
 +            TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
 +            TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
 +            TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
 +            TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
 +            TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?,
 +            TyKind::Ref(_, _, ty) => return TyFingerprint::for_trait_impl(ty),
 +            TyKind::Tuple(_, subst) => {
 +                let first_ty = subst.interned().get(0).map(|arg| arg.assert_ty_ref(Interner));
 +                match first_ty {
 +                    Some(ty) => return TyFingerprint::for_trait_impl(ty),
 +                    None => TyFingerprint::Unit,
 +                }
 +            }
 +            TyKind::AssociatedType(_, _)
 +            | TyKind::OpaqueType(_, _)
 +            | TyKind::FnDef(_, _)
 +            | TyKind::Closure(_, _)
 +            | TyKind::Generator(..)
 +            | TyKind::GeneratorWitness(..) => TyFingerprint::Unnameable,
 +            TyKind::Function(fn_ptr) => {
 +                TyFingerprint::Function(fn_ptr.substitution.0.len(Interner) as u32)
 +            }
 +            TyKind::Alias(_)
 +            | TyKind::Placeholder(_)
 +            | TyKind::BoundVar(_)
 +            | TyKind::InferenceVar(_, _)
 +            | TyKind::Error => return None,
 +        };
 +        Some(fp)
 +    }
 +}
 +
 +pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::I8)),
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::I16)),
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::I32)),
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::I64)),
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::I128)),
 +    TyFingerprint::Scalar(Scalar::Int(IntTy::Isize)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::U8)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::U16)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::U32)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::U64)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::U128)),
 +    TyFingerprint::Scalar(Scalar::Uint(UintTy::Usize)),
 +];
 +
 +pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [
 +    TyFingerprint::Scalar(Scalar::Float(FloatTy::F32)),
 +    TyFingerprint::Scalar(Scalar::Float(FloatTy::F64)),
 +];
 +
 +/// Trait impls defined or available in some crate.
 +#[derive(Debug, Eq, PartialEq)]
 +pub struct TraitImpls {
 +    // If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type.
 +    map: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
 +}
 +
 +impl TraitImpls {
 +    pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
 +        let _p = profile::span("trait_impls_in_crate_query").detail(|| format!("{krate:?}"));
 +        let mut impls = Self { map: FxHashMap::default() };
 +
 +        let crate_def_map = db.crate_def_map(krate);
 +        impls.collect_def_map(db, &crate_def_map);
 +        impls.shrink_to_fit();
 +
 +        Arc::new(impls)
 +    }
 +
 +    pub(crate) fn trait_impls_in_block_query(
 +        db: &dyn HirDatabase,
 +        block: BlockId,
 +    ) -> Option<Arc<Self>> {
 +        let _p = profile::span("trait_impls_in_block_query");
 +        let mut impls = Self { map: FxHashMap::default() };
 +
 +        let block_def_map = db.block_def_map(block)?;
 +        impls.collect_def_map(db, &block_def_map);
 +        impls.shrink_to_fit();
 +
 +        Some(Arc::new(impls))
 +    }
 +
 +    pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
 +        let _p = profile::span("trait_impls_in_deps_query").detail(|| format!("{krate:?}"));
 +        let crate_graph = db.crate_graph();
 +        let mut res = Self { map: FxHashMap::default() };
 +
 +        for krate in crate_graph.transitive_deps(krate) {
 +            res.merge(&db.trait_impls_in_crate(krate));
 +        }
 +        res.shrink_to_fit();
 +
 +        Arc::new(res)
 +    }
 +
 +    fn shrink_to_fit(&mut self) {
 +        self.map.shrink_to_fit();
 +        self.map.values_mut().for_each(|map| {
 +            map.shrink_to_fit();
 +            map.values_mut().for_each(Vec::shrink_to_fit);
 +        });
 +    }
 +
 +    fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
 +        for (_module_id, module_data) in def_map.modules() {
 +            for impl_id in module_data.scope.impls() {
 +                let target_trait = match db.impl_trait(impl_id) {
 +                    Some(tr) => tr.skip_binders().hir_trait_id(),
 +                    None => continue,
 +                };
 +                let self_ty = db.impl_self_ty(impl_id);
 +                let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
 +                self.map
 +                    .entry(target_trait)
 +                    .or_default()
 +                    .entry(self_ty_fp)
 +                    .or_default()
 +                    .push(impl_id);
 +            }
 +
 +            // To better support custom derives, collect impls in all unnamed const items.
 +            // const _: () = { ... };
 +            for konst in collect_unnamed_consts(db, &module_data.scope) {
 +                let body = db.body(konst.into());
 +                for (_, block_def_map) in body.blocks(db.upcast()) {
 +                    self.collect_def_map(db, &block_def_map);
 +                }
 +            }
 +        }
 +    }
 +
 +    fn merge(&mut self, other: &Self) {
 +        for (trait_, other_map) in &other.map {
 +            let map = self.map.entry(*trait_).or_default();
 +            for (fp, impls) in other_map {
 +                map.entry(*fp).or_default().extend(impls);
 +            }
 +        }
 +    }
 +
 +    /// Queries all trait impls for the given type.
 +    pub fn for_self_ty_without_blanket_impls(
 +        &self,
 +        fp: TyFingerprint,
 +    ) -> impl Iterator<Item = ImplId> + '_ {
 +        self.map
 +            .values()
 +            .flat_map(move |impls| impls.get(&Some(fp)).into_iter())
 +            .flat_map(|it| it.iter().copied())
 +    }
 +
 +    /// Queries all impls of the given trait.
 +    pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ {
 +        self.map
 +            .get(&trait_)
 +            .into_iter()
 +            .flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
 +    }
 +
 +    /// Queries all impls of `trait_` that may apply to `self_ty`.
 +    pub fn for_trait_and_self_ty(
 +        &self,
 +        trait_: TraitId,
 +        self_ty: TyFingerprint,
 +    ) -> impl Iterator<Item = ImplId> + '_ {
 +        self.map
 +            .get(&trait_)
 +            .into_iter()
 +            .flat_map(move |map| map.get(&Some(self_ty)).into_iter().chain(map.get(&None)))
 +            .flat_map(|v| v.iter().copied())
 +    }
 +
 +    pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
 +        self.map.values().flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
 +    }
 +}
 +
 +/// Inherent impls defined in some crate.
 +///
 +/// Inherent impls can only be defined in the crate that also defines the self type of the impl
 +/// (note that some primitives are considered to be defined by both libcore and liballoc).
 +///
 +/// This makes inherent impl lookup easier than trait impl lookup since we only have to consider a
 +/// single crate.
 +#[derive(Debug, Eq, PartialEq)]
 +pub struct InherentImpls {
 +    map: FxHashMap<TyFingerprint, Vec<ImplId>>,
 +}
 +
 +impl InherentImpls {
 +    pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
 +        let mut impls = Self { map: FxHashMap::default() };
 +
 +        let crate_def_map = db.crate_def_map(krate);
 +        impls.collect_def_map(db, &crate_def_map);
 +        impls.shrink_to_fit();
 +
 +        Arc::new(impls)
 +    }
 +
 +    pub(crate) fn inherent_impls_in_block_query(
 +        db: &dyn HirDatabase,
 +        block: BlockId,
 +    ) -> Option<Arc<Self>> {
 +        let mut impls = Self { map: FxHashMap::default() };
 +        if let Some(block_def_map) = db.block_def_map(block) {
 +            impls.collect_def_map(db, &block_def_map);
 +            impls.shrink_to_fit();
 +            return Some(Arc::new(impls));
 +        }
 +        None
 +    }
 +
 +    fn shrink_to_fit(&mut self) {
 +        self.map.values_mut().for_each(Vec::shrink_to_fit);
 +        self.map.shrink_to_fit();
 +    }
 +
 +    fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
 +        for (_module_id, module_data) in def_map.modules() {
 +            for impl_id in module_data.scope.impls() {
 +                let data = db.impl_data(impl_id);
 +                if data.target_trait.is_some() {
 +                    continue;
 +                }
 +
 +                let self_ty = db.impl_self_ty(impl_id);
 +                let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders());
 +                if let Some(fp) = fp {
 +                    self.map.entry(fp).or_default().push(impl_id);
 +                }
 +                // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution)
 +            }
 +
 +            // To better support custom derives, collect impls in all unnamed const items.
 +            // const _: () = { ... };
 +            for konst in collect_unnamed_consts(db, &module_data.scope) {
 +                let body = db.body(konst.into());
 +                for (_, block_def_map) in body.blocks(db.upcast()) {
 +                    self.collect_def_map(db, &block_def_map);
 +                }
 +            }
 +        }
 +    }
 +
 +    pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] {
 +        match TyFingerprint::for_inherent_impl(self_ty) {
 +            Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]),
 +            None => &[],
 +        }
 +    }
 +
 +    pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
 +        self.map.values().flat_map(|v| v.iter().copied())
 +    }
 +}
 +
 +pub(crate) fn inherent_impl_crates_query(
 +    db: &dyn HirDatabase,
 +    krate: CrateId,
 +    fp: TyFingerprint,
 +) -> ArrayVec<CrateId, 2> {
 +    let _p = profile::span("inherent_impl_crates_query");
 +    let mut res = ArrayVec::new();
 +    let crate_graph = db.crate_graph();
 +
 +    for krate in crate_graph.transitive_deps(krate) {
 +        if res.is_full() {
 +            // we don't currently look for or store more than two crates here,
 +            // so don't needlessly look at more crates than necessary.
 +            break;
 +        }
 +        let impls = db.inherent_impls_in_crate(krate);
 +        if impls.map.get(&fp).map_or(false, |v| !v.is_empty()) {
 +            res.push(krate);
 +        }
 +    }
 +
 +    res
 +}
 +
 +fn collect_unnamed_consts<'a>(
 +    db: &'a dyn HirDatabase,
 +    scope: &'a ItemScope,
 +) -> impl Iterator<Item = ConstId> + 'a {
 +    let unnamed_consts = scope.unnamed_consts();
 +
 +    // FIXME: Also treat consts named `_DERIVE_*` as unnamed, since synstructure generates those.
 +    // Should be removed once synstructure stops doing that.
 +    let synstructure_hack_consts = scope.values().filter_map(|(item, _)| match item {
 +        ModuleDefId::ConstId(id) => {
 +            let loc = id.lookup(db.upcast());
 +            let item_tree = loc.id.item_tree(db.upcast());
 +            if item_tree[loc.id.value]
 +                .name
 +                .as_ref()
 +                .map_or(false, |n| n.to_smol_str().starts_with("_DERIVE_"))
 +            {
 +                Some(id)
 +            } else {
 +                None
 +            }
 +        }
 +        _ => None,
 +    });
 +
 +    unnamed_consts.chain(synstructure_hack_consts)
 +}
 +
 +pub fn def_crates(
 +    db: &dyn HirDatabase,
 +    ty: &Ty,
 +    cur_crate: CrateId,
 +) -> Option<ArrayVec<CrateId, 2>> {
 +    let mod_to_crate_ids = |module: ModuleId| Some(iter::once(module.krate()).collect());
 +
 +    let fp = TyFingerprint::for_inherent_impl(ty);
 +
 +    match ty.kind(Interner) {
 +        TyKind::Adt(AdtId(def_id), _) => mod_to_crate_ids(def_id.module(db.upcast())),
 +        TyKind::Foreign(id) => {
 +            mod_to_crate_ids(from_foreign_def_id(*id).lookup(db.upcast()).module(db.upcast()))
 +        }
 +        TyKind::Dyn(_) => ty
 +            .dyn_trait()
 +            .and_then(|trait_| mod_to_crate_ids(GenericDefId::TraitId(trait_).module(db.upcast()))),
 +        // for primitives, there may be impls in various places (core and alloc
 +        // mostly). We just check the whole crate graph for crates with impls
 +        // (cached behind a query).
 +        TyKind::Scalar(_)
 +        | TyKind::Str
 +        | TyKind::Slice(_)
 +        | TyKind::Array(..)
 +        | TyKind::Raw(..) => {
 +            Some(db.inherent_impl_crates(cur_crate, fp.expect("fingerprint for primitive")))
 +        }
 +        _ => return None,
 +    }
 +}
 +
 +pub fn lang_names_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, Name)> {
 +    use hir_expand::name;
 +    use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering};
 +    Some(match op {
 +        BinaryOp::LogicOp(_) => return None,
 +        BinaryOp::ArithOp(aop) => match aop {
 +            ArithOp::Add => (name!(add), name!(add)),
 +            ArithOp::Mul => (name!(mul), name!(mul)),
 +            ArithOp::Sub => (name!(sub), name!(sub)),
 +            ArithOp::Div => (name!(div), name!(div)),
 +            ArithOp::Rem => (name!(rem), name!(rem)),
 +            ArithOp::Shl => (name!(shl), name!(shl)),
 +            ArithOp::Shr => (name!(shr), name!(shr)),
 +            ArithOp::BitXor => (name!(bitxor), name!(bitxor)),
 +            ArithOp::BitOr => (name!(bitor), name!(bitor)),
 +            ArithOp::BitAnd => (name!(bitand), name!(bitand)),
 +        },
 +        BinaryOp::Assignment { op: Some(aop) } => match aop {
 +            ArithOp::Add => (name!(add_assign), name!(add_assign)),
 +            ArithOp::Mul => (name!(mul_assign), name!(mul_assign)),
 +            ArithOp::Sub => (name!(sub_assign), name!(sub_assign)),
 +            ArithOp::Div => (name!(div_assign), name!(div_assign)),
 +            ArithOp::Rem => (name!(rem_assign), name!(rem_assign)),
 +            ArithOp::Shl => (name!(shl_assign), name!(shl_assign)),
 +            ArithOp::Shr => (name!(shr_assign), name!(shr_assign)),
 +            ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)),
 +            ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)),
 +            ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)),
 +        },
 +        BinaryOp::CmpOp(cop) => match cop {
 +            CmpOp::Eq { negated: false } => (name!(eq), name!(eq)),
 +            CmpOp::Eq { negated: true } => (name!(ne), name!(eq)),
 +            CmpOp::Ord { ordering: Ordering::Less, strict: false } => {
 +                (name!(le), name!(partial_ord))
 +            }
 +            CmpOp::Ord { ordering: Ordering::Less, strict: true } => {
 +                (name!(lt), name!(partial_ord))
 +            }
 +            CmpOp::Ord { ordering: Ordering::Greater, strict: false } => {
 +                (name!(ge), name!(partial_ord))
 +            }
 +            CmpOp::Ord { ordering: Ordering::Greater, strict: true } => {
 +                (name!(gt), name!(partial_ord))
 +            }
 +        },
 +        BinaryOp::Assignment { op: None } => return None,
 +    })
 +}
 +
 +/// Look up the method with the given name.
 +pub(crate) fn lookup_method(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: &Name,
 +) -> Option<(ReceiverAdjustments, FunctionId)> {
 +    iterate_method_candidates(
 +        ty,
 +        db,
 +        env,
 +        traits_in_scope,
 +        visible_from_module,
 +        Some(name),
 +        LookupMode::MethodCall,
 +        |adjustments, f| match f {
 +            AssocItemId::FunctionId(f) => Some((adjustments, f)),
 +            _ => None,
 +        },
 +    )
 +}
 +
 +/// Whether we're looking up a dotted method call (like `v.len()`) or a path
 +/// (like `Vec::new`).
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +pub enum LookupMode {
 +    /// Looking up a method call like `v.len()`: We only consider candidates
 +    /// that have a `self` parameter, and do autoderef.
 +    MethodCall,
 +    /// Looking up a path like `Vec::new` or `Vec::default`: We consider all
 +    /// candidates including associated constants, but don't do autoderef.
 +    Path,
 +}
 +
 +#[derive(Clone, Copy)]
 +pub enum VisibleFromModule {
 +    /// Filter for results that are visible from the given module
 +    Filter(ModuleId),
 +    /// Include impls from the given block.
 +    IncludeBlock(BlockId),
 +    /// Do nothing special in regards visibility
 +    None,
 +}
 +
 +impl From<Option<ModuleId>> for VisibleFromModule {
 +    fn from(module: Option<ModuleId>) -> Self {
 +        match module {
 +            Some(module) => Self::Filter(module),
 +            None => Self::None,
 +        }
 +    }
 +}
 +
 +impl From<Option<BlockId>> for VisibleFromModule {
 +    fn from(block: Option<BlockId>) -> Self {
 +        match block {
 +            Some(block) => Self::IncludeBlock(block),
 +            None => Self::None,
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Default)]
 +pub struct ReceiverAdjustments {
 +    autoref: Option<Mutability>,
 +    autoderefs: usize,
 +    unsize_array: bool,
 +}
 +
 +impl ReceiverAdjustments {
 +    pub(crate) fn apply(&self, table: &mut InferenceTable<'_>, ty: Ty) -> (Ty, Vec<Adjustment>) {
 +        let mut ty = ty;
 +        let mut adjust = Vec::new();
 +        for _ in 0..self.autoderefs {
 +            match autoderef::autoderef_step(table, ty.clone()) {
 +                None => {
 +                    never!("autoderef not possible for {:?}", ty);
 +                    ty = TyKind::Error.intern(Interner);
 +                    break;
 +                }
 +                Some((kind, new_ty)) => {
 +                    ty = new_ty.clone();
 +                    adjust.push(Adjustment {
 +                        kind: Adjust::Deref(match kind {
 +                            // FIXME should we know the mutability here?
 +                            AutoderefKind::Overloaded => Some(OverloadedDeref(Mutability::Not)),
 +                            AutoderefKind::Builtin => None,
 +                        }),
 +                        target: new_ty,
 +                    });
 +                }
 +            }
 +        }
 +        if self.unsize_array {
 +            ty = match ty.kind(Interner) {
 +                TyKind::Array(inner, _) => TyKind::Slice(inner.clone()).intern(Interner),
 +                _ => {
 +                    never!("unsize_array with non-array {:?}", ty);
 +                    ty
 +                }
 +            };
 +            // FIXME this is kind of wrong since the unsize needs to happen to a pointer/reference
 +            adjust.push(Adjustment {
 +                kind: Adjust::Pointer(PointerCast::Unsize),
 +                target: ty.clone(),
 +            });
 +        }
 +        if let Some(m) = self.autoref {
 +            ty = TyKind::Ref(m, static_lifetime(), ty).intern(Interner);
 +            adjust
 +                .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty.clone() });
 +        }
 +        (ty, adjust)
 +    }
 +
 +    fn with_autoref(&self, m: Mutability) -> ReceiverAdjustments {
 +        Self { autoref: Some(m), ..*self }
 +    }
 +}
 +
 +// This would be nicer if it just returned an iterator, but that runs into
 +// lifetime problems, because we need to borrow temp `CrateImplDefs`.
 +// FIXME add a context type here?
 +pub(crate) fn iterate_method_candidates<T>(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    mode: LookupMode,
 +    mut callback: impl FnMut(ReceiverAdjustments, AssocItemId) -> Option<T>,
 +) -> Option<T> {
 +    let mut slot = None;
 +    iterate_method_candidates_dyn(
 +        ty,
 +        db,
 +        env,
 +        traits_in_scope,
 +        visible_from_module,
 +        name,
 +        mode,
 +        &mut |adj, item| {
 +            assert!(slot.is_none());
 +            if let Some(it) = callback(adj, item) {
 +                slot = Some(it);
 +                return ControlFlow::Break(());
 +            }
 +            ControlFlow::Continue(())
 +        },
 +    );
 +    slot
 +}
 +
 +pub fn lookup_impl_method(
 +    self_ty: &Ty,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    trait_: TraitId,
 +    name: &Name,
 +) -> Option<FunctionId> {
 +    let self_ty_fp = TyFingerprint::for_trait_impl(self_ty)?;
 +    let trait_impls = db.trait_impls_in_deps(env.krate);
 +    let impls = trait_impls.for_trait_and_self_ty(trait_, self_ty_fp);
 +    let mut table = InferenceTable::new(db, env.clone());
 +    find_matching_impl(impls, &mut table, &self_ty).and_then(|data| {
 +        data.items.iter().find_map(|it| match it {
 +            AssocItemId::FunctionId(f) => (db.function_data(*f).name == *name).then(|| *f),
 +            _ => None,
 +        })
 +    })
 +}
 +
 +fn find_matching_impl(
 +    mut impls: impl Iterator<Item = ImplId>,
 +    table: &mut InferenceTable<'_>,
 +    self_ty: &Ty,
 +) -> Option<Arc<ImplData>> {
 +    let db = table.db;
 +    loop {
 +        let impl_ = impls.next()?;
 +        let r = table.run_in_snapshot(|table| {
 +            let impl_data = db.impl_data(impl_);
 +            let substs =
 +                TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
 +            let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
 +
 +            table
 +                .unify(self_ty, &impl_ty)
 +                .then(|| {
 +                    let wh_goals =
 +                        crate::chalk_db::convert_where_clauses(db, impl_.into(), &substs)
 +                            .into_iter()
 +                            .map(|b| b.cast(Interner));
 +
 +                    let goal = crate::Goal::all(Interner, wh_goals);
 +
 +                    table.try_obligation(goal).map(|_| impl_data)
 +                })
 +                .flatten()
 +        });
 +        if r.is_some() {
 +            break r;
 +        }
 +    }
 +}
 +
 +pub fn iterate_path_candidates(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    iterate_method_candidates_dyn(
 +        ty,
 +        db,
 +        env,
 +        traits_in_scope,
 +        visible_from_module,
 +        name,
 +        LookupMode::Path,
 +        // the adjustments are not relevant for path lookup
 +        &mut |_, id| callback(id),
 +    )
 +}
 +
 +pub fn iterate_method_candidates_dyn(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    mode: LookupMode,
 +    callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    match mode {
 +        LookupMode::MethodCall => {
 +            // For method calls, rust first does any number of autoderef, and
 +            // then one autoref (i.e. when the method takes &self or &mut self).
 +            // Note that when we've got a receiver like &S, even if the method
 +            // we find in the end takes &self, we still do the autoderef step
 +            // (just as rustc does an autoderef and then autoref again).
 +
 +            // We have to be careful about the order we're looking at candidates
 +            // in here. Consider the case where we're resolving `x.clone()`
 +            // where `x: &Vec<_>`. This resolves to the clone method with self
 +            // type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where
 +            // the receiver type exactly matches before cases where we have to
 +            // do autoref. But in the autoderef steps, the `&_` self type comes
 +            // up *before* the `Vec<_>` self type.
 +            //
 +            // On the other hand, we don't want to just pick any by-value method
 +            // before any by-autoref method; it's just that we need to consider
 +            // the methods by autoderef order of *receiver types*, not *self
 +            // types*.
 +
 +            let mut table = InferenceTable::new(db, env.clone());
 +            let ty = table.instantiate_canonical(ty.clone());
 +            let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
 +
 +            let result = deref_chain.into_iter().zip(adj).try_for_each(|(receiver_ty, adj)| {
 +                iterate_method_candidates_with_autoref(
 +                    &receiver_ty,
 +                    adj,
 +                    db,
 +                    env.clone(),
 +                    traits_in_scope,
 +                    visible_from_module,
 +                    name,
 +                    callback,
 +                )
 +            });
 +            result
 +        }
 +        LookupMode::Path => {
 +            // No autoderef for path lookups
 +            iterate_method_candidates_for_self_ty(
 +                ty,
 +                db,
 +                env,
 +                traits_in_scope,
 +                visible_from_module,
 +                name,
 +                callback,
 +            )
 +        }
 +    }
 +}
 +
 +fn iterate_method_candidates_with_autoref(
 +    receiver_ty: &Canonical<Ty>,
 +    first_adjustment: ReceiverAdjustments,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    if receiver_ty.value.is_general_var(Interner, &receiver_ty.binders) {
 +        // don't try to resolve methods on unknown types
 +        return ControlFlow::Continue(());
 +    }
 +
 +    iterate_method_candidates_by_receiver(
 +        receiver_ty,
 +        first_adjustment.clone(),
 +        db,
 +        env.clone(),
 +        traits_in_scope,
 +        visible_from_module,
 +        name,
 +        &mut callback,
 +    )?;
 +
 +    let refed = Canonical {
 +        value: TyKind::Ref(Mutability::Not, static_lifetime(), receiver_ty.value.clone())
 +            .intern(Interner),
 +        binders: receiver_ty.binders.clone(),
 +    };
 +
 +    iterate_method_candidates_by_receiver(
 +        &refed,
 +        first_adjustment.with_autoref(Mutability::Not),
 +        db,
 +        env.clone(),
 +        traits_in_scope,
 +        visible_from_module,
 +        name,
 +        &mut callback,
 +    )?;
 +
 +    let ref_muted = Canonical {
 +        value: TyKind::Ref(Mutability::Mut, static_lifetime(), receiver_ty.value.clone())
 +            .intern(Interner),
 +        binders: receiver_ty.binders.clone(),
 +    };
 +
 +    iterate_method_candidates_by_receiver(
 +        &ref_muted,
 +        first_adjustment.with_autoref(Mutability::Mut),
 +        db,
 +        env,
 +        traits_in_scope,
 +        visible_from_module,
 +        name,
 +        &mut callback,
 +    )
 +}
 +
 +fn iterate_method_candidates_by_receiver(
 +    receiver_ty: &Canonical<Ty>,
 +    receiver_adjustments: ReceiverAdjustments,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    let mut table = InferenceTable::new(db, env);
 +    let receiver_ty = table.instantiate_canonical(receiver_ty.clone());
 +    let snapshot = table.snapshot();
 +    // We're looking for methods with *receiver* type receiver_ty. These could
 +    // be found in any of the derefs of receiver_ty, so we have to go through
 +    // that.
 +    let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone());
 +    while let Some((self_ty, _)) = autoderef.next() {
 +        iterate_inherent_methods(
 +            &self_ty,
 +            &mut autoderef.table,
 +            name,
 +            Some(&receiver_ty),
 +            Some(receiver_adjustments.clone()),
 +            visible_from_module,
 +            &mut callback,
 +        )?
 +    }
 +
 +    table.rollback_to(snapshot);
 +
 +    let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone());
 +    while let Some((self_ty, _)) = autoderef.next() {
 +        iterate_trait_method_candidates(
 +            &self_ty,
 +            &mut autoderef.table,
 +            traits_in_scope,
 +            name,
 +            Some(&receiver_ty),
 +            Some(receiver_adjustments.clone()),
 +            &mut callback,
 +        )?
 +    }
 +
 +    ControlFlow::Continue(())
 +}
 +
 +fn iterate_method_candidates_for_self_ty(
 +    self_ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    visible_from_module: VisibleFromModule,
 +    name: Option<&Name>,
 +    mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    let mut table = InferenceTable::new(db, env);
 +    let self_ty = table.instantiate_canonical(self_ty.clone());
 +    iterate_inherent_methods(
 +        &self_ty,
 +        &mut table,
 +        name,
 +        None,
 +        None,
 +        visible_from_module,
 +        &mut callback,
 +    )?;
 +    iterate_trait_method_candidates(
 +        &self_ty,
 +        &mut table,
 +        traits_in_scope,
 +        name,
 +        None,
 +        None,
 +        callback,
 +    )
 +}
 +
 +fn iterate_trait_method_candidates(
 +    self_ty: &Ty,
 +    table: &mut InferenceTable<'_>,
 +    traits_in_scope: &FxHashSet<TraitId>,
 +    name: Option<&Name>,
 +    receiver_ty: Option<&Ty>,
 +    receiver_adjustments: Option<ReceiverAdjustments>,
 +    callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    let db = table.db;
 +    let env = table.trait_env.clone();
 +    let self_is_array = matches!(self_ty.kind(Interner), chalk_ir::TyKind::Array(..));
 +
 +    let canonical_self_ty = table.canonicalize(self_ty.clone()).value;
 +
 +    'traits: for &t in traits_in_scope {
 +        let data = db.trait_data(t);
 +
 +        // Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during
 +        // method resolution, if the receiver is an array, and we're compiling for editions before
 +        // 2021.
 +        // This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for
 +        // arrays.
 +        if data.skip_array_during_method_dispatch && self_is_array {
 +            // FIXME: this should really be using the edition of the method name's span, in case it
 +            // comes from a macro
 +            if db.crate_graph()[env.krate].edition < Edition::Edition2021 {
 +                continue;
 +            }
 +        }
 +
 +        // we'll be lazy about checking whether the type implements the
 +        // trait, but if we find out it doesn't, we'll skip the rest of the
 +        // iteration
 +        let mut known_implemented = false;
 +        for &(_, item) in data.items.iter() {
 +            // Don't pass a `visible_from_module` down to `is_valid_candidate`,
 +            // since only inherent methods should be included into visibility checking.
 +            if !is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
 +                continue;
 +            }
 +            if !known_implemented {
 +                let goal = generic_implements_goal(db, env.clone(), t, &canonical_self_ty);
 +                if db.trait_solve(env.krate, goal.cast(Interner)).is_none() {
 +                    continue 'traits;
 +                }
 +            }
 +            known_implemented = true;
 +            callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
 +        }
 +    }
 +    ControlFlow::Continue(())
 +}
 +
 +fn iterate_inherent_methods(
 +    self_ty: &Ty,
 +    table: &mut InferenceTable<'_>,
 +    name: Option<&Name>,
 +    receiver_ty: Option<&Ty>,
 +    receiver_adjustments: Option<ReceiverAdjustments>,
 +    visible_from_module: VisibleFromModule,
 +    callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +) -> ControlFlow<()> {
 +    let db = table.db;
 +    let env = table.trait_env.clone();
 +
 +    // For trait object types and placeholder types with trait bounds, the methods of the trait and
 +    // its super traits are considered inherent methods. This matters because these methods have
 +    // higher priority than the other traits' methods, which would be considered in
 +    // `iterate_trait_method_candidates()` only after this function.
 +    match self_ty.kind(Interner) {
 +        TyKind::Placeholder(_) => {
 +            let env = table.trait_env.clone();
 +            let traits = env
 +                .traits_in_scope_from_clauses(self_ty.clone())
 +                .flat_map(|t| all_super_traits(db.upcast(), t));
 +            iterate_inherent_trait_methods(
 +                self_ty,
 +                table,
 +                name,
 +                receiver_ty,
 +                receiver_adjustments.clone(),
 +                callback,
 +                traits,
 +            )?;
 +        }
 +        TyKind::Dyn(_) => {
 +            if let Some(principal_trait) = self_ty.dyn_trait() {
 +                let traits = all_super_traits(db.upcast(), principal_trait);
 +                iterate_inherent_trait_methods(
 +                    self_ty,
 +                    table,
 +                    name,
 +                    receiver_ty,
 +                    receiver_adjustments.clone(),
 +                    callback,
 +                    traits.into_iter(),
 +                )?;
 +            }
 +        }
 +        _ => {}
 +    }
 +
 +    let def_crates = match def_crates(db, self_ty, env.krate) {
 +        Some(k) => k,
 +        None => return ControlFlow::Continue(()),
 +    };
 +
 +    let (module, block) = match visible_from_module {
 +        VisibleFromModule::Filter(module) => (Some(module), module.containing_block()),
 +        VisibleFromModule::IncludeBlock(block) => (None, Some(block)),
 +        VisibleFromModule::None => (None, None),
 +    };
 +
 +    if let Some(block_id) = block {
 +        if let Some(impls) = db.inherent_impls_in_block(block_id) {
 +            impls_for_self_ty(
 +                &impls,
 +                self_ty,
 +                table,
 +                name,
 +                receiver_ty,
 +                receiver_adjustments.clone(),
 +                module,
 +                callback,
 +            )?;
 +        }
 +    }
 +
 +    for krate in def_crates {
 +        let impls = db.inherent_impls_in_crate(krate);
 +        impls_for_self_ty(
 +            &impls,
 +            self_ty,
 +            table,
 +            name,
 +            receiver_ty,
 +            receiver_adjustments.clone(),
 +            module,
 +            callback,
 +        )?;
 +    }
 +    return ControlFlow::Continue(());
 +
 +    fn iterate_inherent_trait_methods(
 +        self_ty: &Ty,
 +        table: &mut InferenceTable<'_>,
 +        name: Option<&Name>,
 +        receiver_ty: Option<&Ty>,
 +        receiver_adjustments: Option<ReceiverAdjustments>,
 +        callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +        traits: impl Iterator<Item = TraitId>,
 +    ) -> ControlFlow<()> {
 +        let db = table.db;
 +        for t in traits {
 +            let data = db.trait_data(t);
 +            for &(_, item) in data.items.iter() {
 +                // We don't pass `visible_from_module` as all trait items should be visible.
 +                if is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
 +                    callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
 +                }
 +            }
 +        }
 +        ControlFlow::Continue(())
 +    }
 +
 +    fn impls_for_self_ty(
 +        impls: &InherentImpls,
 +        self_ty: &Ty,
 +        table: &mut InferenceTable<'_>,
 +        name: Option<&Name>,
 +        receiver_ty: Option<&Ty>,
 +        receiver_adjustments: Option<ReceiverAdjustments>,
 +        visible_from_module: Option<ModuleId>,
 +        callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 +    ) -> ControlFlow<()> {
 +        let db = table.db;
 +        let impls_for_self_ty = impls.for_self_ty(self_ty);
 +        for &impl_def in impls_for_self_ty {
 +            for &item in &db.impl_data(impl_def).items {
 +                if !is_valid_candidate(table, name, receiver_ty, item, self_ty, visible_from_module)
 +                {
 +                    continue;
 +                }
 +                callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
 +            }
 +        }
 +        ControlFlow::Continue(())
 +    }
 +}
 +
 +/// Returns the receiver type for the index trait call.
 +pub fn resolve_indexing_op(
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    ty: Canonical<Ty>,
 +    index_trait: TraitId,
 +) -> Option<ReceiverAdjustments> {
 +    let mut table = InferenceTable::new(db, env.clone());
 +    let ty = table.instantiate_canonical(ty);
 +    let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
 +    for (ty, adj) in deref_chain.into_iter().zip(adj) {
 +        let goal = generic_implements_goal(db, env.clone(), index_trait, &ty);
 +        if db.trait_solve(env.krate, goal.cast(Interner)).is_some() {
++            return Some(adj);
++        }
++    }
++    None
++}
++/// Returns the receiver type for the try branch trait call.
++pub fn resolve_branch_op(
++    db: &dyn HirDatabase,
++    env: Arc<TraitEnvironment>,
++    ty: Canonical<Ty>,
++    try_trait: TraitId,
++) -> Option<ReceiverAdjustments> {
++    let mut table = InferenceTable::new(db, env.clone());
++    let ty = table.instantiate_canonical(ty);
++    let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
++    for (ty, adj) in deref_chain.into_iter().zip(adj) {
++        let goal = generic_implements_goal(db, env.clone(), try_trait, &ty);
++        if db.trait_solve(env.krate, goal.cast(Interner)).is_some() {
 +            return Some(adj);
 +        }
 +    }
 +    None
 +}
 +
 +macro_rules! check_that {
 +    ($cond:expr) => {
 +        if !$cond {
 +            return false;
 +        }
 +    };
 +}
 +
 +fn is_valid_candidate(
 +    table: &mut InferenceTable<'_>,
 +    name: Option<&Name>,
 +    receiver_ty: Option<&Ty>,
 +    item: AssocItemId,
 +    self_ty: &Ty,
 +    visible_from_module: Option<ModuleId>,
 +) -> bool {
 +    let db = table.db;
 +    match item {
 +        AssocItemId::FunctionId(m) => {
 +            is_valid_fn_candidate(table, m, name, receiver_ty, self_ty, visible_from_module)
 +        }
 +        AssocItemId::ConstId(c) => {
 +            let data = db.const_data(c);
 +            check_that!(receiver_ty.is_none());
 +
 +            check_that!(name.map_or(true, |n| data.name.as_ref() == Some(n)));
 +            check_that!(visible_from_module.map_or(true, |from_module| {
 +                let v = db.const_visibility(c).is_visible_from(db.upcast(), from_module);
 +                if !v {
 +                    cov_mark::hit!(const_candidate_not_visible);
 +                }
 +                v
 +            }));
 +            if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container {
 +                let self_ty_matches = table.run_in_snapshot(|table| {
 +                    let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
 +                        .fill_with_inference_vars(table)
 +                        .build();
 +                    table.unify(&expected_self_ty, &self_ty)
 +                });
 +                if !self_ty_matches {
 +                    cov_mark::hit!(const_candidate_self_type_mismatch);
 +                    return false;
 +                }
 +            }
 +            true
 +        }
 +        _ => false,
 +    }
 +}
 +
 +fn is_valid_fn_candidate(
 +    table: &mut InferenceTable<'_>,
 +    fn_id: FunctionId,
 +    name: Option<&Name>,
 +    receiver_ty: Option<&Ty>,
 +    self_ty: &Ty,
 +    visible_from_module: Option<ModuleId>,
 +) -> bool {
 +    let db = table.db;
 +    let data = db.function_data(fn_id);
 +
 +    check_that!(name.map_or(true, |n| n == &data.name));
 +    check_that!(visible_from_module.map_or(true, |from_module| {
 +        let v = db.function_visibility(fn_id).is_visible_from(db.upcast(), from_module);
 +        if !v {
 +            cov_mark::hit!(autoderef_candidate_not_visible);
 +        }
 +        v
 +    }));
 +
 +    table.run_in_snapshot(|table| {
 +        let container = fn_id.lookup(db.upcast()).container;
 +        let (impl_subst, expect_self_ty) = match container {
 +            ItemContainerId::ImplId(it) => {
 +                let subst =
 +                    TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
 +                let self_ty = db.impl_self_ty(it).substitute(Interner, &subst);
 +                (subst, self_ty)
 +            }
 +            ItemContainerId::TraitId(it) => {
 +                let subst =
 +                    TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
 +                let self_ty = subst.at(Interner, 0).assert_ty_ref(Interner).clone();
 +                (subst, self_ty)
 +            }
 +            _ => unreachable!(),
 +        };
 +
 +        let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
 +            .fill_with_inference_vars(table)
 +            .build();
 +
 +        check_that!(table.unify(&expect_self_ty, self_ty));
 +
 +        if let Some(receiver_ty) = receiver_ty {
 +            check_that!(data.has_self_param());
 +
 +            let sig = db.callable_item_signature(fn_id.into());
 +            let expected_receiver =
 +                sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
 +
 +            check_that!(table.unify(&receiver_ty, &expected_receiver));
 +        }
 +
 +        if let ItemContainerId::ImplId(impl_id) = container {
 +            // We need to consider the bounds on the impl to distinguish functions of the same name
 +            // for a type.
 +            let predicates = db.generic_predicates(impl_id.into());
 +            predicates
 +                .iter()
 +                .map(|predicate| {
 +                    let (p, b) = predicate
 +                        .clone()
 +                        .substitute(Interner, &impl_subst)
 +                        // Skipping the inner binders is ok, as we don't handle quantified where
 +                        // clauses yet.
 +                        .into_value_and_skipped_binders();
 +                    stdx::always!(b.len(Interner) == 0);
 +                    p
 +                })
 +                // It's ok to get ambiguity here, as we may not have enough information to prove
 +                // obligations. We'll check if the user is calling the selected method properly
 +                // later anyway.
 +                .all(|p| table.try_obligation(p.cast(Interner)).is_some())
 +        } else {
 +            // For `ItemContainerId::TraitId`, we check if `self_ty` implements the trait in
 +            // `iterate_trait_method_candidates()`.
 +            // For others, this function shouldn't be called.
 +            true
 +        }
 +    })
 +}
 +
 +pub fn implements_trait(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    trait_: TraitId,
 +) -> bool {
 +    let goal = generic_implements_goal(db, env.clone(), trait_, ty);
 +    let solution = db.trait_solve(env.krate, goal.cast(Interner));
 +
 +    solution.is_some()
 +}
 +
 +pub fn implements_trait_unique(
 +    ty: &Canonical<Ty>,
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    trait_: TraitId,
 +) -> bool {
 +    let goal = generic_implements_goal(db, env.clone(), trait_, ty);
 +    let solution = db.trait_solve(env.krate, goal.cast(Interner));
 +
 +    matches!(solution, Some(crate::Solution::Unique(_)))
 +}
 +
 +/// This creates Substs for a trait with the given Self type and type variables
 +/// for all other parameters, to query Chalk with it.
 +fn generic_implements_goal(
 +    db: &dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    trait_: TraitId,
 +    self_ty: &Canonical<Ty>,
 +) -> Canonical<InEnvironment<super::DomainGoal>> {
 +    let mut kinds = self_ty.binders.interned().to_vec();
 +    let trait_ref = TyBuilder::trait_ref(db, trait_)
 +        .push(self_ty.value.clone())
 +        .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
 +        .build();
 +    kinds.extend(trait_ref.substitution.iter(Interner).skip(1).map(|x| {
 +        let vk = match x.data(Interner) {
 +            chalk_ir::GenericArgData::Ty(_) => {
 +                chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
 +            }
 +            chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
 +            chalk_ir::GenericArgData::Const(c) => {
 +                chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
 +            }
 +        };
 +        chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
 +    }));
 +    let obligation = trait_ref.cast(Interner);
 +    Canonical {
 +        binders: CanonicalVarKinds::from_iter(Interner, kinds),
 +        value: InEnvironment::new(&env.env, obligation),
 +    }
 +}
 +
 +fn autoderef_method_receiver(
 +    table: &mut InferenceTable<'_>,
 +    ty: Ty,
 +) -> (Vec<Canonical<Ty>>, Vec<ReceiverAdjustments>) {
 +    let (mut deref_chain, mut adjustments): (Vec<_>, Vec<_>) = (Vec::new(), Vec::new());
 +    let mut autoderef = autoderef::Autoderef::new(table, ty);
 +    while let Some((ty, derefs)) = autoderef.next() {
 +        deref_chain.push(autoderef.table.canonicalize(ty).value);
 +        adjustments.push(ReceiverAdjustments {
 +            autoref: None,
 +            autoderefs: derefs,
 +            unsize_array: false,
 +        });
 +    }
 +    // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!)
 +    if let (Some((TyKind::Array(parameters, _), binders)), Some(adj)) = (
 +        deref_chain.last().map(|ty| (ty.value.kind(Interner), ty.binders.clone())),
 +        adjustments.last().cloned(),
 +    ) {
 +        let unsized_ty = TyKind::Slice(parameters.clone()).intern(Interner);
 +        deref_chain.push(Canonical { value: unsized_ty, binders });
 +        adjustments.push(ReceiverAdjustments { unsize_array: true, ..adj });
 +    }
 +    (deref_chain, adjustments)
 +}
index 240942e488d7de79adbe9e9a08e8fe6b8e44255c,0000000000000000000000000000000000000000..8a8ff08cfe8cdab81a7250bdd273175ec3a47179
mode 100644,000000..100644
--- /dev/null
@@@ -1,176 -1,0 +1,198 @@@
 +use super::check_types_source_code;
 +
 +#[test]
 +fn qualify_path_to_submodule() {
 +    check_types_source_code(
 +        r#"
 +mod foo {
 +    pub struct Foo;
 +}
 +
 +fn bar() {
 +    let foo: foo::Foo = foo::Foo;
 +    foo;
 +} //^^^ foo::Foo
 +
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn omit_default_type_parameters() {
 +    check_types_source_code(
 +        r#"
 +struct Foo<T = u8> { t: T }
 +fn main() {
 +    let foo = Foo { t: 5u8 };
 +    foo;
 +} //^^^ Foo
 +"#,
 +    );
 +
 +    check_types_source_code(
 +        r#"
 +struct Foo<K, T = u8> { k: K, t: T }
 +fn main() {
 +    let foo = Foo { k: 400, t: 5u8 };
 +    foo;
 +} //^^^ Foo<i32>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn render_raw_ptr_impl_ty() {
 +    check_types_source_code(
 +        r#"
 +//- minicore: sized
 +trait Unpin {}
 +fn foo() -> *const (impl Unpin + Sized) { loop {} }
 +fn main() {
 +    let foo = foo();
 +    foo;
 +} //^^^ *const impl Unpin
 +"#,
 +    );
 +}
 +
++#[test]
++fn render_dyn_ty_independent_of_order() {
++    check_types_source_code(
++        r#"
++auto trait Send {}
++trait A {
++    type Assoc;
++}
++trait B: A {}
++
++fn test(
++    _: &(dyn A<Assoc = ()> + Send),
++  //^ &(dyn A<Assoc = ()> + Send)
++    _: &(dyn Send + A<Assoc = ()>),
++  //^ &(dyn A<Assoc = ()> + Send)
++    _: &dyn B<Assoc = ()>,
++  //^ &(dyn B<Assoc = ()>)
++) {}
++        "#,
++    );
++}
++
 +#[test]
 +fn render_dyn_for_ty() {
 +    // FIXME
 +    check_types_source_code(
 +        r#"
 +trait Foo<'a> {}
 +
 +fn foo(foo: &dyn for<'a> Foo<'a>) {}
 +    // ^^^ &dyn Foo
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn sized_bounds_apit() {
 +    check_types_source_code(
 +        r#"
 +//- minicore: sized
 +trait Foo {}
 +trait Bar<T> {}
 +struct S<T>;
 +fn test(
 +    a: impl Foo,
 +    b: impl Foo + Sized,
 +    c: &(impl Foo + ?Sized),
 +    d: S<impl Foo>,
 +    ref_any: &impl ?Sized,
 +    empty: impl,
 +) {
 +    a;
 +  //^ impl Foo
 +    b;
 +  //^ impl Foo
 +    c;
 +  //^ &impl Foo + ?Sized
 +    d;
 +  //^ S<impl Foo>
 +    ref_any;
 +  //^^^^^^^ &impl ?Sized
 +    empty;
 +} //^^^^^ impl Sized
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn sized_bounds_rpit() {
 +    check_types_source_code(
 +        r#"
 +//- minicore: sized
 +trait Foo {}
 +fn foo1() -> impl Foo { loop {} }
 +fn foo2() -> impl Foo + Sized { loop {} }
 +fn foo3() -> impl Foo + ?Sized { loop {} }
 +fn test() {
 +    let foo = foo1();
 +    foo;
 +  //^^^ impl Foo
 +    let foo = foo2();
 +    foo;
 +  //^^^ impl Foo
 +    let foo = foo3();
 +    foo;
 +} //^^^ impl Foo + ?Sized
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn parenthesize_ptr_rpit_sized_bounds() {
 +    check_types_source_code(
 +        r#"
 +//- minicore: sized
 +trait Foo {}
 +fn foo1() -> *const impl Foo { loop {} }
 +fn foo2() -> *const (impl Foo + Sized) { loop {} }
 +fn foo3() -> *const (impl Sized + Foo) { loop {} }
 +fn foo4() -> *const (impl Foo + ?Sized) { loop {} }
 +fn foo5() -> *const (impl ?Sized + Foo) { loop {} }
 +fn test() {
 +    let foo = foo1();
 +    foo;
 +  //^^^ *const impl Foo
 +    let foo = foo2();
 +    foo;
 +  //^^^ *const impl Foo
 +    let foo = foo3();
 +    foo;
 +  //^^^ *const impl Foo
 +    let foo = foo4();
 +    foo;
 +  //^^^ *const (impl Foo + ?Sized)
 +    let foo = foo5();
 +    foo;
 +} //^^^ *const (impl Foo + ?Sized)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn sized_bounds_impl_traits_in_fn_signature() {
 +    check_types_source_code(
 +        r#"
 +//- minicore: sized
 +trait Foo {}
 +fn test(
 +    a: fn(impl Foo) -> impl Foo,
 +    b: fn(impl Foo + Sized) -> impl Foo + Sized,
 +    c: fn(&(impl Foo + ?Sized)) -> &(impl Foo + ?Sized),
 +) {
 +    a;
 +  //^ fn(impl Foo) -> impl Foo
 +    b;
 +  //^ fn(impl Foo) -> impl Foo
 +    c;
 +} //^ fn(&impl Foo + ?Sized) -> &impl Foo + ?Sized
 +"#,
 +    );
 +}
index eb04bf87783b40dc8a0c9ef78b7b42044b407a7e,0000000000000000000000000000000000000000..74de33117ee7d6dff7a4f90fb79fabd3e77cb7b9
mode 100644,000000..100644
--- /dev/null
@@@ -1,1072 -1,0 +1,1082 @@@
 +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));
 +}
 +        "#,
 +    );
 +}
++
++#[test]
++fn cfg_params() {
++    check_types(
++        r#"
++fn my_fn(#[cfg(feature = "feature")] u8: u8, u32: u32) {}
++                                           //^^^ u32
++"#,
++    );
++}
index 555b6972fb71eecb775979f640b33baa2e3a712e,0000000000000000000000000000000000000000..b91172e33422d67ad40c74ad62f4167399240754
mode 100644,000000..100644
--- /dev/null
@@@ -1,3965 -1,0 +1,3883 @@@
- #[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::*};
-     }
- }
- "#,
-     );
- }
 +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
 +"#,
 +    );
 +}
 +
- //- /main.rs crate:main deps:core
- fn test() {
-     let r: Result<i32, u64> = Result::Ok(1);
 +#[test]
 +fn infer_try_trait_v2() {
 +    check_types(
 +        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::*;
-     }
++//- minicore: try
++fn test() -> core::ops::ControlFlow<u32, f32> {
++    let r: core::ops::ControlFlow<u32, f32> = core::ops::ControlFlow::Continue(1.0);
 +    let v = r?;
++      //^ f32
++    r
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_for_loop() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:core,alloc
 +#![no_std]
 +use alloc::collections::Vec;
 +
 +fn test() {
 +    let v = Vec::new();
 +    v.push("foo");
 +    for x in v {
 +        x;
 +    } //^ &str
 +}
 +
 +//- /core.rs crate:core
 +pub mod iter {
 +    pub trait IntoIterator {
 +        type Item;
 +        type IntoIter: Iterator<Item = Self::Item>;
 +    }
 +    pub trait Iterator {
 +        type Item;
 +    }
 +}
 +pub mod prelude {
 +    pub mod rust_2018 {
 +        pub use crate::iter::*;
 +    }
 +}
 +
 +//- /alloc.rs crate:alloc deps:core
 +#![no_std]
 +pub mod collections {
 +    pub struct Vec<T> {}
 +    impl<T> Vec<T> {
 +        pub fn new() -> Self { Vec {} }
 +        pub fn push(&mut self, t: T) { }
 +    }
 +
 +    impl<T> IntoIterator for Vec<T> {
 +        type Item = T;
 +        type IntoIter = IntoIter<T>;
 +    }
 +
 +    struct IntoIter<T> {}
 +    impl<T> Iterator for IntoIter<T> {
 +        type Item = T;
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_neg() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:std
 +struct Bar;
 +struct Foo;
 +
 +impl std::ops::Neg for Bar {
 +    type Output = Foo;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = -a;
 +    b;
 +} //^ Foo
 +
 +//- /std.rs crate:std
 +#[prelude_import] use ops::*;
 +mod ops {
 +    #[lang = "neg"]
 +    pub trait Neg {
 +        type Output;
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_not() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:std
 +struct Bar;
 +struct Foo;
 +
 +impl std::ops::Not for Bar {
 +    type Output = Foo;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = !a;
 +    b;
 +} //^ Foo
 +
 +//- /std.rs crate:std
 +#[prelude_import] use ops::*;
 +mod ops {
 +    #[lang = "not"]
 +    pub trait Not {
 +        type Output;
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_from_bound_1() {
 +    check_types(
 +        r#"
 +trait Trait<T> {}
 +struct S<T>(T);
 +impl<U> Trait<U> for S<U> {}
 +fn foo<T: Trait<u32>>(t: T) {}
 +fn test() {
 +    let s = S(unknown);
 +           // ^^^^^^^ u32
 +    foo(s);
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_from_bound_2() {
 +    check_types(
 +        r#"
 +trait Trait<T> {}
 +struct S<T>(T);
 +impl<U> Trait<U> for S<U> {}
 +fn foo<U, T: Trait<U>>(t: T) -> U { loop {} }
 +fn test() {
 +    let s = S(unknown);
 +           // ^^^^^^^ u32
 +    let x: u32 = foo(s);
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_default_method_self_bound_implements_trait() {
 +    cov_mark::check!(trait_self_implements_self);
 +    check(
 +        r#"
 +trait Trait {
 +    fn foo(&self) -> i64;
 +    fn bar(&self) -> () {
 +        self.foo();
 +     // ^^^^^^^^^^ type: i64
 +    }
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_default_method_self_bound_implements_super_trait() {
 +    check(
 +        r#"
 +trait SuperTrait {
 +    fn foo(&self) -> i64;
 +}
 +trait Trait: SuperTrait {
 +    fn bar(&self) -> () {
 +        self.foo();
 +     // ^^^^^^^^^^ type: i64
 +    }
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_project_associated_type() {
 +    check_types(
 +        r#"
 +trait Iterable {
 +    type Item;
 +}
 +struct S;
 +impl Iterable for S { type Item = u32; }
 +fn test<T: Iterable>() {
 +    let x: <S as Iterable>::Item = 1;
 +                                // ^ u32
 +    let y: <T as Iterable>::Item = u;
 +                                // ^ Iterable::Item<T>
 +    let z: T::Item = u;
 +                  // ^ Iterable::Item<T>
 +    let a: <T>::Item = u;
 +                    // ^ Iterable::Item<T>
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_return_associated_type() {
 +    check_types(
 +        r#"
 +trait Iterable {
 +    type Item;
 +}
 +struct S;
 +impl Iterable for S { type Item = u32; }
 +fn foo1<T: Iterable>(t: T) -> T::Item { loop {} }
 +fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item { loop {} }
 +fn foo3<T: Iterable>(t: T) -> <T>::Item { loop {} }
 +fn test() {
 +    foo1(S);
 + // ^^^^^^^ u32
 +    foo2(S);
 + // ^^^^^^^ u32
 +    foo3(S);
 + // ^^^^^^^ u32
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn associated_type_shorthand_from_method_bound() {
 +    check_types(
 +        r#"
 +trait Iterable {
 +    type Item;
 +}
 +struct S<T>;
 +impl<T> S<T> {
 +    fn foo(self) -> T::Item where T: Iterable { loop {} }
 +}
 +fn test<T: Iterable>() {
 +    let s: S<T>;
 +    s.foo();
 + // ^^^^^^^ Iterable::Item<T>
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn associated_type_shorthand_from_self_issue_12484() {
 +    check_types(
 +        r#"
 +trait Bar {
 +    type A;
 +}
 +trait Foo {
 +    type A;
 +    fn test(a: Self::A, _: impl Bar) {
 +        a;
 +      //^ Foo::A<Self>
 +    }
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_type_bound() {
 +    check_types(
 +        r#"
 +trait Iterable {
 +    type Item;
 +}
 +fn test<T: Iterable<Item=u32>>() {
 +    let y: T::Item = unknown;
 +                  // ^^^^^^^ u32
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_const_body() {
 +    // FIXME make check_types work with other bodies
 +    check_infer(
 +        r#"
 +const A: u32 = 1 + 1;
 +static B: u64 = { let x = 1; x };
 +"#,
 +        expect![[r#"
 +            15..16 '1': u32
 +            15..20 '1 + 1': u32
 +            19..20 '1': u32
 +            38..54 '{ let ...1; x }': u64
 +            44..45 'x': u64
 +            48..49 '1': u64
 +            51..52 'x': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn tuple_struct_fields() {
 +    check_infer(
 +        r#"
 +struct S(i32, u64);
 +fn test() -> u64 {
 +    let a = S(4, 6);
 +    let b = a.0;
 +    a.1
 +}"#,
 +        expect![[r#"
 +            37..86 '{     ... a.1 }': u64
 +            47..48 'a': S
 +            51..52 'S': S(i32, u64) -> S
 +            51..58 'S(4, 6)': S
 +            53..54 '4': i32
 +            56..57 '6': u64
 +            68..69 'b': i32
 +            72..73 'a': S
 +            72..75 'a.0': i32
 +            81..82 'a': S
 +            81..84 'a.1': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn tuple_struct_with_fn() {
 +    check_infer(
 +        r#"
 +struct S(fn(u32) -> u64);
 +fn test() -> u64 {
 +    let a = S(|i| 2*i);
 +    let b = a.0(4);
 +    a.0(2)
 +}"#,
 +        expect![[r#"
 +            43..101 '{     ...0(2) }': u64
 +            53..54 'a': S
 +            57..58 'S': S(fn(u32) -> u64) -> S
 +            57..67 'S(|i| 2*i)': S
 +            59..66 '|i| 2*i': |u32| -> u64
 +            60..61 'i': u32
 +            63..64 '2': u32
 +            63..66 '2*i': u32
 +            65..66 'i': u32
 +            77..78 'b': u64
 +            81..82 'a': S
 +            81..84 'a.0': fn(u32) -> u64
 +            81..87 'a.0(4)': u64
 +            85..86 '4': u32
 +            93..94 'a': S
 +            93..96 'a.0': fn(u32) -> u64
 +            93..99 'a.0(2)': u64
 +            97..98 '2': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn indexing_arrays() {
 +    check_infer(
 +        "fn main() { &mut [9][2]; }",
 +        expect![[r#"
 +            10..26 '{ &mut...[2]; }': ()
 +            12..23 '&mut [9][2]': &mut {unknown}
 +            17..20 '[9]': [i32; 1]
 +            17..23 '[9][2]': {unknown}
 +            18..19 '9': i32
 +            21..22 '2': i32
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn infer_ops_index() {
 +    check_types(
 +        r#"
 +//- minicore: index
 +struct Bar;
 +struct Foo;
 +
 +impl core::ops::Index<u32> for Bar {
 +    type Output = Foo;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = a[1u32];
 +    b;
 +} //^ Foo
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_index_field() {
 +    check_types(
 +        r#"
 +//- minicore: index
 +struct Bar;
 +struct Foo {
 +    field: u32;
 +}
 +
 +impl core::ops::Index<u32> for Bar {
 +    type Output = Foo;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = a[1u32].field;
 +    b;
 +} //^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_index_field_autoderef() {
 +    check_types(
 +        r#"
 +//- minicore: index
 +struct Bar;
 +struct Foo {
 +    field: u32;
 +}
 +
 +impl core::ops::Index<u32> for Bar {
 +    type Output = Foo;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = (&a[1u32]).field;
 +    b;
 +} //^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_index_int() {
 +    check_types(
 +        r#"
 +//- minicore: index
 +struct Bar;
 +struct Foo;
 +
 +impl core::ops::Index<u32> for Bar {
 +    type Output = Foo;
 +}
 +
 +struct Range;
 +impl core::ops::Index<Range> for Bar {
 +    type Output = Bar;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = a[1];
 +    b;
 +  //^ Foo
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_index_autoderef() {
 +    check_types(
 +        r#"
 +//- minicore: index, slice
 +fn test() {
 +    let a = &[1u32, 2, 3];
 +    let b = a[1];
 +    b;
 +} //^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_trait() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Arc<T: ?Sized>;
 +impl<T: ?Sized> core::ops::Deref for Arc<T> {
 +    type Target = T;
 +}
 +
 +struct S;
 +impl S {
 +    fn foo(&self) -> u128 { 0 }
 +}
 +
 +fn test(s: Arc<S>) {
 +    (*s, s.foo());
 +} //^^^^^^^^^^^^^ (S, u128)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_trait_with_inference_var() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Arc<T: ?Sized>;
 +fn new_arc<T: ?Sized>() -> Arc<T> { Arc }
 +impl<T: ?Sized> core::ops::Deref for Arc<T> {
 +    type Target = T;
 +}
 +
 +struct S;
 +fn foo(a: Arc<S>) {}
 +
 +fn test() {
 +    let a = new_arc();
 +    let b = *a;
 +          //^^ S
 +    foo(a);
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_trait_infinite_recursion() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct S;
 +
 +impl core::ops::Deref for S {
 +    type Target = S;
 +}
 +
 +fn test(s: S) {
 +    s.foo();
 +} //^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_trait_with_question_mark_size() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Arc<T: ?Sized>;
 +impl<T: ?Sized> core::ops::Deref for Arc<T> {
 +    type Target = T;
 +}
 +
 +struct S;
 +impl S {
 +    fn foo(&self) -> u128 { 0 }
 +}
 +
 +fn test(s: Arc<S>) {
 +    (*s, s.foo());
 +} //^^^^^^^^^^^^^ (S, u128)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_trait_with_implicit_sized_requirement_on_inference_var() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Foo<T>;
 +impl<T> core::ops::Deref for Foo<T> {
 +    type Target = ();
 +}
 +fn test() {
 +    let foo = Foo;
 +    *foo;
 +  //^^^^ ()
 +    let _: Foo<u8> = foo;
 +}
 +"#,
 +    )
 +}
 +
 +#[test]
 +fn obligation_from_function_clause() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +trait Trait<T> {}
 +impl Trait<u32> for S {}
 +
 +fn foo<T: Trait<U>, U>(t: T) -> U { loop {} }
 +
 +fn test(s: S) {
 +    foo(s);
 +} //^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn obligation_from_method_clause() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +struct S;
 +
 +trait Trait<T> {}
 +impl Trait<isize> for S {}
 +
 +struct O;
 +impl O {
 +    fn foo<T: Trait<U>, U>(&self, t: T) -> U { loop {} }
 +}
 +
 +fn test() {
 +    O.foo(S);
 +} //^^^^^^^^ isize
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn obligation_from_self_method_clause() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +trait Trait<T> {}
 +impl Trait<i64> for S {}
 +
 +impl S {
 +    fn foo<U>(&self) -> U where Self: Trait<U> { loop {} }
 +}
 +
 +fn test() {
 +    S.foo();
 +} //^^^^^^^ i64
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn obligation_from_impl_clause() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +trait Trait<T> {}
 +impl Trait<&str> for S {}
 +
 +struct O<T>;
 +impl<U, T: Trait<U>> O<T> {
 +    fn foo(&self) -> U { loop {} }
 +}
 +
 +fn test(o: O<S>) {
 +    o.foo();
 +} //^^^^^^^ &str
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn generic_param_env_1() {
 +    check_types(
 +        r#"
 +trait Clone {}
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl Clone for S {}
 +impl<T> Trait for T where T: Clone {}
 +fn test<T: Clone>(t: T) { t.foo(); }
 +                        //^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn generic_param_env_1_not_met() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +trait Clone {}
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl Clone for S {}
 +impl<T> Trait for T where T: Clone {}
 +fn test<T>(t: T) { t.foo(); }
 +                 //^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn generic_param_env_2() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl Trait for S {}
 +fn test<T: Trait>(t: T) { t.foo(); }
 +                        //^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn generic_param_env_2_not_met() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl Trait for S {}
 +fn test<T>(t: T) { t.foo(); }
 +                 //^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn generic_param_env_deref() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +trait Trait {}
 +impl<T> core::ops::Deref for T where T: Trait {
 +    type Target = i128;
 +}
 +fn test<T: Trait>(t: T) { *t; }
 +                        //^^ i128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn associated_type_placeholder() {
 +    // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types].
 +    check_types(
 +        r#"
 +pub trait ApplyL {
 +    type Out;
 +}
 +
 +pub struct RefMutL<T>;
 +
 +impl<T> ApplyL for RefMutL<T> {
 +    type Out = <T as ApplyL>::Out;
 +}
 +
 +fn test<T: ApplyL>() {
 +    let y: <RefMutL<T> as ApplyL>::Out = no_matter;
 +    y;
 +} //^ ApplyL::Out<T>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn associated_type_placeholder_2() {
 +    check_types(
 +        r#"
 +pub trait ApplyL {
 +    type Out;
 +}
 +fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out;
 +
 +fn test<T: ApplyL>(t: T) {
 +    let y = foo(t);
 +    y;
 +} //^ ApplyL::Out<T>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn argument_impl_trait() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +    fn foo2(&self) -> i64;
 +}
 +fn bar(x: impl Trait<u16>) {}
 +struct S<T>(T);
 +impl<T> Trait<T> for S<T> {}
 +
 +fn test(x: impl Trait<u64>, y: &impl Trait<u32>) {
 +    x;
 +    y;
 +    let z = S(1);
 +    bar(z);
 +    x.foo();
 +    y.foo();
 +    z.foo();
 +    x.foo2();
 +    y.foo2();
 +    z.foo2();
 +}"#,
 +        expect![[r#"
 +            29..33 'self': &Self
 +            54..58 'self': &Self
 +            77..78 'x': impl Trait<u16>
 +            97..99 '{}': ()
 +            154..155 'x': impl Trait<u64>
 +            174..175 'y': &impl Trait<u32>
 +            195..323 '{     ...2(); }': ()
 +            201..202 'x': impl Trait<u64>
 +            208..209 'y': &impl Trait<u32>
 +            219..220 'z': S<u16>
 +            223..224 'S': S<u16>(u16) -> S<u16>
 +            223..227 'S(1)': S<u16>
 +            225..226 '1': u16
 +            233..236 'bar': fn bar(S<u16>)
 +            233..239 'bar(z)': ()
 +            237..238 'z': S<u16>
 +            245..246 'x': impl Trait<u64>
 +            245..252 'x.foo()': u64
 +            258..259 'y': &impl Trait<u32>
 +            258..265 'y.foo()': u32
 +            271..272 'z': S<u16>
 +            271..278 'z.foo()': u16
 +            284..285 'x': impl Trait<u64>
 +            284..292 'x.foo2()': i64
 +            298..299 'y': &impl Trait<u32>
 +            298..306 'y.foo2()': i64
 +            312..313 'z': S<u16>
 +            312..320 'z.foo2()': i64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn argument_impl_trait_type_args_1() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +trait Foo {
 +    // this function has an implicit Self param, an explicit type param,
 +    // and an implicit impl Trait param!
 +    fn bar<T>(x: impl Trait) -> T { loop {} }
 +}
 +fn foo<T>(x: impl Trait) -> T { loop {} }
 +struct S;
 +impl Trait for S {}
 +struct F;
 +impl Foo for F {}
 +
 +fn test() {
 +    Foo::bar(S);
 +    <F as Foo>::bar(S);
 +    F::bar(S);
 +    Foo::bar::<u32>(S);
 +    <F as Foo>::bar::<u32>(S);
 +
 +    foo(S);
 +    foo::<u32>(S);
 +    foo::<u32, i32>(S); // we should ignore the extraneous i32
 +}"#,
 +        expect![[r#"
 +            155..156 'x': impl Trait
 +            175..186 '{ loop {} }': T
 +            177..184 'loop {}': !
 +            182..184 '{}': ()
 +            199..200 'x': impl Trait
 +            219..230 '{ loop {} }': T
 +            221..228 'loop {}': !
 +            226..228 '{}': ()
 +            300..509 '{     ... i32 }': ()
 +            306..314 'Foo::bar': fn bar<{unknown}, {unknown}>(S) -> {unknown}
 +            306..317 'Foo::bar(S)': {unknown}
 +            315..316 'S': S
 +            323..338 '<F as Foo>::bar': fn bar<F, {unknown}>(S) -> {unknown}
 +            323..341 '<F as ...bar(S)': {unknown}
 +            339..340 'S': S
 +            347..353 'F::bar': fn bar<F, {unknown}>(S) -> {unknown}
 +            347..356 'F::bar(S)': {unknown}
 +            354..355 'S': S
 +            362..377 'Foo::bar::<u32>': fn bar<{unknown}, u32>(S) -> u32
 +            362..380 'Foo::b...32>(S)': u32
 +            378..379 'S': S
 +            386..408 '<F as ...:<u32>': fn bar<F, u32>(S) -> u32
 +            386..411 '<F as ...32>(S)': u32
 +            409..410 'S': S
 +            418..421 'foo': fn foo<{unknown}>(S) -> {unknown}
 +            418..424 'foo(S)': {unknown}
 +            422..423 'S': S
 +            430..440 'foo::<u32>': fn foo<u32>(S) -> u32
 +            430..443 'foo::<u32>(S)': u32
 +            441..442 'S': S
 +            449..464 'foo::<u32, i32>': fn foo<u32>(S) -> u32
 +            449..467 'foo::<...32>(S)': u32
 +            465..466 'S': S
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn argument_impl_trait_type_args_2() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +struct S;
 +impl Trait for S {}
 +struct F<T>;
 +impl<T> F<T> {
 +    fn foo<U>(self, x: impl Trait) -> (T, U) { loop {} }
 +}
 +
 +fn test() {
 +    F.foo(S);
 +    F::<u32>.foo(S);
 +    F::<u32>.foo::<i32>(S);
 +    F::<u32>.foo::<i32, u32>(S); // extraneous argument should be ignored
 +}"#,
 +        expect![[r#"
 +            87..91 'self': F<T>
 +            93..94 'x': impl Trait
 +            118..129 '{ loop {} }': (T, U)
 +            120..127 'loop {}': !
 +            125..127 '{}': ()
 +            143..283 '{     ...ored }': ()
 +            149..150 'F': F<{unknown}>
 +            149..157 'F.foo(S)': ({unknown}, {unknown})
 +            155..156 'S': S
 +            163..171 'F::<u32>': F<u32>
 +            163..178 'F::<u32>.foo(S)': (u32, {unknown})
 +            176..177 'S': S
 +            184..192 'F::<u32>': F<u32>
 +            184..206 'F::<u3...32>(S)': (u32, i32)
 +            204..205 'S': S
 +            212..220 'F::<u32>': F<u32>
 +            212..239 'F::<u3...32>(S)': (u32, i32)
 +            237..238 'S': S
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn argument_impl_trait_to_fn_pointer() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +fn foo(x: impl Trait) { loop {} }
 +struct S;
 +impl Trait for S {}
 +
 +fn test() {
 +    let f: fn(S) -> () = foo;
 +}"#,
 +        expect![[r#"
 +            22..23 'x': impl Trait
 +            37..48 '{ loop {} }': ()
 +            39..46 'loop {}': !
 +            44..46 '{}': ()
 +            90..123 '{     ...foo; }': ()
 +            100..101 'f': fn(S)
 +            117..120 'foo': fn foo(S)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn impl_trait() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +    fn foo2(&self) -> i64;
 +}
 +fn bar() -> impl Trait<u64> {}
 +
 +fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
 +    x;
 +    y;
 +    let z = bar();
 +    x.foo();
 +    y.foo();
 +    z.foo();
 +    x.foo2();
 +    y.foo2();
 +    z.foo2();
 +}"#,
 +        expect![[r#"
 +            29..33 'self': &Self
 +            54..58 'self': &Self
 +            98..100 '{}': ()
 +            110..111 'x': impl Trait<u64>
 +            130..131 'y': &impl Trait<u64>
 +            151..268 '{     ...2(); }': ()
 +            157..158 'x': impl Trait<u64>
 +            164..165 'y': &impl Trait<u64>
 +            175..176 'z': impl Trait<u64>
 +            179..182 'bar': fn bar() -> impl Trait<u64>
 +            179..184 'bar()': impl Trait<u64>
 +            190..191 'x': impl Trait<u64>
 +            190..197 'x.foo()': u64
 +            203..204 'y': &impl Trait<u64>
 +            203..210 'y.foo()': u64
 +            216..217 'z': impl Trait<u64>
 +            216..223 'z.foo()': u64
 +            229..230 'x': impl Trait<u64>
 +            229..237 'x.foo2()': i64
 +            243..244 'y': &impl Trait<u64>
 +            243..251 'y.foo2()': i64
 +            257..258 'z': impl Trait<u64>
 +            257..265 'z.foo2()': i64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn simple_return_pos_impl_trait() {
 +    cov_mark::check!(lower_rpit);
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +}
 +fn bar() -> impl Trait<u64> { loop {} }
 +
 +fn test() {
 +    let a = bar();
 +    a.foo();
 +}"#,
 +        expect![[r#"
 +            29..33 'self': &Self
 +            71..82 '{ loop {} }': !
 +            73..80 'loop {}': !
 +            78..80 '{}': ()
 +            94..129 '{     ...o(); }': ()
 +            104..105 'a': impl Trait<u64>
 +            108..111 'bar': fn bar() -> impl Trait<u64>
 +            108..113 'bar()': impl Trait<u64>
 +            119..120 'a': impl Trait<u64>
 +            119..126 'a.foo()': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn more_return_pos_impl_trait() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Iterator {
 +    type Item;
 +    fn next(&mut self) -> Self::Item;
 +}
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +}
 +fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) { loop {} }
 +fn baz<T>(t: T) -> (impl Iterator<Item = impl Trait<T>>, impl Trait<T>) { loop {} }
 +
 +fn test() {
 +    let (a, b) = bar();
 +    a.next().foo();
 +    b.foo();
 +    let (c, d) = baz(1u128);
 +    c.next().foo();
 +    d.foo();
 +}"#,
 +        expect![[r#"
 +            49..53 'self': &mut Self
 +            101..105 'self': &Self
 +            184..195 '{ loop {} }': ({unknown}, {unknown})
 +            186..193 'loop {}': !
 +            191..193 '{}': ()
 +            206..207 't': T
 +            268..279 '{ loop {} }': ({unknown}, {unknown})
 +            270..277 'loop {}': !
 +            275..277 '{}': ()
 +            291..413 '{     ...o(); }': ()
 +            301..307 '(a, b)': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
 +            302..303 'a': impl Iterator<Item = impl Trait<u32>>
 +            305..306 'b': impl Trait<u64>
 +            310..313 'bar': fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
 +            310..315 'bar()': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
 +            321..322 'a': impl Iterator<Item = impl Trait<u32>>
 +            321..329 'a.next()': impl Trait<u32>
 +            321..335 'a.next().foo()': u32
 +            341..342 'b': impl Trait<u64>
 +            341..348 'b.foo()': u64
 +            358..364 '(c, d)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
 +            359..360 'c': impl Iterator<Item = impl Trait<u128>>
 +            362..363 'd': impl Trait<u128>
 +            367..370 'baz': fn baz<u128>(u128) -> (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
 +            367..377 'baz(1u128)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
 +            371..376 '1u128': u128
 +            383..384 'c': impl Iterator<Item = impl Trait<u128>>
 +            383..391 'c.next()': impl Trait<u128>
 +            383..397 'c.next().foo()': u128
 +            403..404 'd': impl Trait<u128>
 +            403..410 'd.foo()': u128
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_from_return_pos_impl_trait() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn, sized
 +trait Trait<T> {}
 +struct Bar<T>(T);
 +impl<T> Trait<T> for Bar<T> {}
 +fn foo<const C: u8, T>() -> (impl FnOnce(&str, T), impl Trait<u8>) {
 +    (|input, t| {}, Bar(C))
 +}
 +"#,
 +        expect![[r#"
 +            134..165 '{     ...(C)) }': (|&str, T| -> (), Bar<u8>)
 +            140..163 '(|inpu...ar(C))': (|&str, T| -> (), Bar<u8>)
 +            141..154 '|input, t| {}': |&str, T| -> ()
 +            142..147 'input': &str
 +            149..150 't': T
 +            152..154 '{}': ()
 +            156..159 'Bar': Bar<u8>(u8) -> Bar<u8>
 +            156..162 'Bar(C)': Bar<u8>
 +            160..161 'C': u8
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn dyn_trait() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +    fn foo2(&self) -> i64;
 +}
 +fn bar() -> dyn Trait<u64> {}
 +
 +fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
 +    x;
 +    y;
 +    let z = bar();
 +    x.foo();
 +    y.foo();
 +    z.foo();
 +    x.foo2();
 +    y.foo2();
 +    z.foo2();
 +}"#,
 +        expect![[r#"
 +            29..33 'self': &Self
 +            54..58 'self': &Self
 +            97..99 '{}': dyn Trait<u64>
 +            109..110 'x': dyn Trait<u64>
 +            128..129 'y': &dyn Trait<u64>
 +            148..265 '{     ...2(); }': ()
 +            154..155 'x': dyn Trait<u64>
 +            161..162 'y': &dyn Trait<u64>
 +            172..173 'z': dyn Trait<u64>
 +            176..179 'bar': fn bar() -> dyn Trait<u64>
 +            176..181 'bar()': dyn Trait<u64>
 +            187..188 'x': dyn Trait<u64>
 +            187..194 'x.foo()': u64
 +            200..201 'y': &dyn Trait<u64>
 +            200..207 'y.foo()': u64
 +            213..214 'z': dyn Trait<u64>
 +            213..220 'z.foo()': u64
 +            226..227 'x': dyn Trait<u64>
 +            226..234 'x.foo2()': i64
 +            240..241 'y': &dyn Trait<u64>
 +            240..248 'y.foo2()': i64
 +            254..255 'z': dyn Trait<u64>
 +            254..262 'z.foo2()': i64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn dyn_trait_in_impl() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait<T, U> {
 +    fn foo(&self) -> (T, U);
 +}
 +struct S<T, U> {}
 +impl<T, U> S<T, U> {
 +    fn bar(&self) -> &dyn Trait<T, U> { loop {} }
 +}
 +trait Trait2<T, U> {
 +    fn baz(&self) -> (T, U);
 +}
 +impl<T, U> Trait2<T, U> for dyn Trait<T, U> { }
 +
 +fn test(s: S<u32, i32>) {
 +    s.bar().baz();
 +}"#,
 +        expect![[r#"
 +            32..36 'self': &Self
 +            102..106 'self': &S<T, U>
 +            128..139 '{ loop {} }': &dyn Trait<T, U>
 +            130..137 'loop {}': !
 +            135..137 '{}': ()
 +            175..179 'self': &Self
 +            251..252 's': S<u32, i32>
 +            267..289 '{     ...z(); }': ()
 +            273..274 's': S<u32, i32>
 +            273..280 's.bar()': &dyn Trait<u32, i32>
 +            273..286 's.bar().baz()': (u32, i32)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn dyn_trait_bare() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait {
 +    fn foo(&self) -> u64;
 +}
 +fn bar() -> Trait {}
 +
 +fn test(x: Trait, y: &Trait) -> u64 {
 +    x;
 +    y;
 +    let z = bar();
 +    x.foo();
 +    y.foo();
 +    z.foo();
 +}"#,
 +        expect![[r#"
 +            26..30 'self': &Self
 +            60..62 '{}': dyn Trait
 +            72..73 'x': dyn Trait
 +            82..83 'y': &dyn Trait
 +            100..175 '{     ...o(); }': u64
 +            106..107 'x': dyn Trait
 +            113..114 'y': &dyn Trait
 +            124..125 'z': dyn Trait
 +            128..131 'bar': fn bar() -> dyn Trait
 +            128..133 'bar()': dyn Trait
 +            139..140 'x': dyn Trait
 +            139..146 'x.foo()': u64
 +            152..153 'y': &dyn Trait
 +            152..159 'y.foo()': u64
 +            165..166 'z': dyn Trait
 +            165..172 'z.foo()': u64
 +        "#]],
 +    );
 +
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn, coerce_unsized
 +struct S;
 +impl S {
 +    fn foo(&self) {}
 +}
 +fn f(_: &Fn(S)) {}
 +fn main() {
 +    f(&|number| number.foo());
 +}
 +        "#,
 +        expect![[r#"
 +            31..35 'self': &S
 +            37..39 '{}': ()
 +            47..48 '_': &dyn Fn(S)
 +            58..60 '{}': ()
 +            71..105 '{     ...()); }': ()
 +            77..78 'f': fn f(&dyn Fn(S))
 +            77..102 'f(&|nu...foo())': ()
 +            79..101 '&|numb....foo()': &|S| -> ()
 +            80..101 '|numbe....foo()': |S| -> ()
 +            81..87 'number': S
 +            89..95 'number': S
 +            89..101 'number.foo()': ()
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn weird_bounds() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +fn test(
 +    a: impl Trait + 'lifetime,
 +    b: impl 'lifetime,
 +    c: impl (Trait),
 +    d: impl ('lifetime),
 +    e: impl ?Sized,
 +    f: impl Trait + ?Sized
 +) {}
 +"#,
 +        expect![[r#"
 +            28..29 'a': impl Trait
 +            59..60 'b': impl Sized
 +            82..83 'c': impl Trait
 +            103..104 'd': impl Sized
 +            128..129 'e': impl ?Sized
 +            148..149 'f': impl Trait + ?Sized
 +            173..175 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn error_bound_chalk() {
 +    check_types(
 +        r#"
 +trait Trait {
 +    fn foo(&self) -> u32 { 0 }
 +}
 +
 +fn test(x: (impl Trait + UnknownTrait)) {
 +    x.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn assoc_type_bindings() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait {
 +    type Type;
 +}
 +
 +fn get<T: Trait>(t: T) -> <T as Trait>::Type {}
 +fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
 +fn set<T: Trait<Type = u64>>(t: T) -> T {t}
 +
 +struct S<T>;
 +impl<T> Trait for S<T> { type Type = T; }
 +
 +fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
 +    get(x);
 +    get2(x);
 +    get(y);
 +    get2(y);
 +    get(set(S));
 +    get2(set(S));
 +    get2(S::<str>);
 +}"#,
 +        expect![[r#"
 +            49..50 't': T
 +            77..79 '{}': Trait::Type<T>
 +            111..112 't': T
 +            122..124 '{}': U
 +            154..155 't': T
 +            165..168 '{t}': T
 +            166..167 't': T
 +            256..257 'x': T
 +            262..263 'y': impl Trait<Type = i64>
 +            289..397 '{     ...r>); }': ()
 +            295..298 'get': fn get<T>(T) -> <T as Trait>::Type
 +            295..301 'get(x)': u32
 +            299..300 'x': T
 +            307..311 'get2': fn get2<u32, T>(T) -> u32
 +            307..314 'get2(x)': u32
 +            312..313 'x': T
 +            320..323 'get': fn get<impl Trait<Type = i64>>(impl Trait<Type = i64>) -> <impl Trait<Type = i64> as Trait>::Type
 +            320..326 'get(y)': i64
 +            324..325 'y': impl Trait<Type = i64>
 +            332..336 'get2': fn get2<i64, impl Trait<Type = i64>>(impl Trait<Type = i64>) -> i64
 +            332..339 'get2(y)': i64
 +            337..338 'y': impl Trait<Type = i64>
 +            345..348 'get': fn get<S<u64>>(S<u64>) -> <S<u64> as Trait>::Type
 +            345..356 'get(set(S))': u64
 +            349..352 'set': fn set<S<u64>>(S<u64>) -> S<u64>
 +            349..355 'set(S)': S<u64>
 +            353..354 'S': S<u64>
 +            362..366 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64
 +            362..374 'get2(set(S))': u64
 +            367..370 'set': fn set<S<u64>>(S<u64>) -> S<u64>
 +            367..373 'set(S)': S<u64>
 +            371..372 'S': S<u64>
 +            380..384 'get2': fn get2<str, S<str>>(S<str>) -> str
 +            380..394 'get2(S::<str>)': str
 +            385..393 'S::<str>': S<str>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn impl_trait_assoc_binding_projection_bug() {
 +    check_types(
 +        r#"
 +//- minicore: iterator
 +pub trait Language {
 +    type Kind;
 +}
 +pub enum RustLanguage {}
 +impl Language for RustLanguage {
 +    type Kind = SyntaxKind;
 +}
 +struct SyntaxNode<L> {}
 +fn foo() -> impl Iterator<Item = SyntaxNode<RustLanguage>> {}
 +
 +trait Clone {
 +    fn clone(&self) -> Self;
 +}
 +
 +fn api_walkthrough() {
 +    for node in foo() {
 +        node.clone();
 +    } //^^^^^^^^^^^^ {unknown}
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn projection_eq_within_chalk() {
 +    check_infer(
 +        r#"
 +trait Trait1 {
 +    type Type;
 +}
 +trait Trait2<T> {
 +    fn foo(self) -> T;
 +}
 +impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {}
 +
 +fn test<T: Trait1<Type = u32>>(x: T) {
 +    x.foo();
 +}"#,
 +        expect![[r#"
 +            61..65 'self': Self
 +            163..164 'x': T
 +            169..185 '{     ...o(); }': ()
 +            175..176 'x': T
 +            175..182 'x.foo()': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn where_clause_trait_in_scope_for_method_resolution() {
 +    check_types(
 +        r#"
 +mod foo {
 +    trait Trait {
 +        fn foo(&self) -> u32 { 0 }
 +    }
 +}
 +
 +fn test<T: foo::Trait>(x: T) {
 +    x.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn super_trait_method_resolution() {
 +    check_infer(
 +        r#"
 +mod foo {
 +    trait SuperTrait {
 +        fn foo(&self) -> u32 {}
 +    }
 +}
 +trait Trait1: foo::SuperTrait {}
 +trait Trait2 where Self: foo::SuperTrait {}
 +
 +fn test<T: Trait1, U: Trait2>(x: T, y: U) {
 +    x.foo();
 +    y.foo();
 +}"#,
 +        expect![[r#"
 +            49..53 'self': &Self
 +            62..64 '{}': u32
 +            181..182 'x': T
 +            187..188 'y': U
 +            193..222 '{     ...o(); }': ()
 +            199..200 'x': T
 +            199..206 'x.foo()': u32
 +            212..213 'y': U
 +            212..219 'y.foo()': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn super_trait_impl_trait_method_resolution() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +mod foo {
 +    trait SuperTrait {
 +        fn foo(&self) -> u32 {}
 +    }
 +}
 +trait Trait1: foo::SuperTrait {}
 +
 +fn test(x: &impl Trait1) {
 +    x.foo();
 +}"#,
 +        expect![[r#"
 +            49..53 'self': &Self
 +            62..64 '{}': u32
 +            115..116 'x': &impl Trait1
 +            132..148 '{     ...o(); }': ()
 +            138..139 'x': &impl Trait1
 +            138..145 'x.foo()': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn super_trait_cycle() {
 +    // This just needs to not crash
 +    check_infer(
 +        r#"
 +        trait A: B {}
 +        trait B: A {}
 +
 +        fn test<T: A>(x: T) {
 +            x.foo();
 +        }
 +        "#,
 +        expect![[r#"
 +            43..44 'x': T
 +            49..65 '{     ...o(); }': ()
 +            55..56 'x': T
 +            55..62 'x.foo()': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn super_trait_assoc_type_bounds() {
 +    check_infer(
 +        r#"
 +trait SuperTrait { type Type; }
 +trait Trait where Self: SuperTrait {}
 +
 +fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
 +fn set<T: Trait<Type = u64>>(t: T) -> T {t}
 +
 +struct S<T>;
 +impl<T> SuperTrait for S<T> { type Type = T; }
 +impl<T> Trait for S<T> {}
 +
 +fn test() {
 +    get2(set(S));
 +}"#,
 +        expect![[r#"
 +            102..103 't': T
 +            113..115 '{}': U
 +            145..146 't': T
 +            156..159 '{t}': T
 +            157..158 't': T
 +            258..279 '{     ...S)); }': ()
 +            264..268 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64
 +            264..276 'get2(set(S))': u64
 +            269..272 'set': fn set<S<u64>>(S<u64>) -> S<u64>
 +            269..275 'set(S)': S<u64>
 +            273..274 'S': S<u64>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn fn_trait() {
 +    check_infer_with_mismatches(
 +        r#"
 +trait FnOnce<Args> {
 +    type Output;
 +
 +    fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output;
 +}
 +
 +fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
 +    f.call_once((1, 2));
 +}"#,
 +        expect![[r#"
 +            56..60 'self': Self
 +            62..66 'args': Args
 +            149..150 'f': F
 +            155..183 '{     ...2)); }': ()
 +            161..162 'f': F
 +            161..180 'f.call...1, 2))': u128
 +            173..179 '(1, 2)': (u32, u64)
 +            174..175 '1': u32
 +            177..178 '2': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn fn_ptr_and_item() {
 +    check_infer_with_mismatches(
 +        r#"
 +#[lang="fn_once"]
 +trait FnOnce<Args> {
 +    type Output;
 +
 +    fn call_once(self, args: Args) -> Self::Output;
 +}
 +
 +trait Foo<T> {
 +    fn foo(&self) -> T;
 +}
 +
 +struct Bar<T>(T);
 +
 +impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> {
 +    fn foo(&self) -> (A1, R) { loop {} }
 +}
 +
 +enum Opt<T> { None, Some(T) }
 +impl<T> Opt<T> {
 +    fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> { loop {} }
 +}
 +
 +fn test() {
 +    let bar: Bar<fn(u8) -> u32>;
 +    bar.foo();
 +
 +    let opt: Opt<u8>;
 +    let f: fn(u8) -> u32;
 +    opt.map(f);
 +}"#,
 +        expect![[r#"
 +            74..78 'self': Self
 +            80..84 'args': Args
 +            139..143 'self': &Self
 +            243..247 'self': &Bar<F>
 +            260..271 '{ loop {} }': (A1, R)
 +            262..269 'loop {}': !
 +            267..269 '{}': ()
 +            355..359 'self': Opt<T>
 +            361..362 'f': F
 +            377..388 '{ loop {} }': Opt<U>
 +            379..386 'loop {}': !
 +            384..386 '{}': ()
 +            402..518 '{     ...(f); }': ()
 +            412..415 'bar': Bar<fn(u8) -> u32>
 +            441..444 'bar': Bar<fn(u8) -> u32>
 +            441..450 'bar.foo()': (u8, u32)
 +            461..464 'opt': Opt<u8>
 +            483..484 'f': fn(u8) -> u32
 +            505..508 'opt': Opt<u8>
 +            505..515 'opt.map(f)': Opt<u32>
 +            513..514 'f': fn(u8) -> u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn fn_trait_deref_with_ty_default() {
 +    check_infer(
 +        r#"
 +//- minicore: deref, fn
 +struct Foo;
 +
 +impl Foo {
 +    fn foo(&self) -> usize {}
 +}
 +
 +struct Lazy<T, F = fn() -> T>(F);
 +
 +impl<T, F> Lazy<T, F> {
 +    pub fn new(f: F) -> Lazy<T, F> {}
 +}
 +
 +impl<T, F: FnOnce() -> T> core::ops::Deref for Lazy<T, F> {
 +    type Target = T;
 +}
 +
 +fn test() {
 +    let lazy1: Lazy<Foo, _> = Lazy::new(|| Foo);
 +    let r1 = lazy1.foo();
 +
 +    fn make_foo_fn() -> Foo {}
 +    let make_foo_fn_ptr: fn() -> Foo = make_foo_fn;
 +    let lazy2: Lazy<Foo, _> = Lazy::new(make_foo_fn_ptr);
 +    let r2 = lazy2.foo();
 +}"#,
 +        expect![[r#"
 +            36..40 'self': &Foo
 +            51..53 '{}': usize
 +            131..132 'f': F
 +            151..153 '{}': Lazy<T, F>
 +            251..497 '{     ...o(); }': ()
 +            261..266 'lazy1': Lazy<Foo, || -> Foo>
 +            283..292 'Lazy::new': fn new<Foo, || -> Foo>(|| -> Foo) -> Lazy<Foo, || -> Foo>
 +            283..300 'Lazy::...| Foo)': Lazy<Foo, || -> Foo>
 +            293..299 '|| Foo': || -> Foo
 +            296..299 'Foo': Foo
 +            310..312 'r1': usize
 +            315..320 'lazy1': Lazy<Foo, || -> Foo>
 +            315..326 'lazy1.foo()': usize
 +            368..383 'make_foo_fn_ptr': fn() -> Foo
 +            399..410 'make_foo_fn': fn make_foo_fn() -> Foo
 +            420..425 'lazy2': Lazy<Foo, fn() -> Foo>
 +            442..451 'Lazy::new': fn new<Foo, fn() -> Foo>(fn() -> Foo) -> Lazy<Foo, fn() -> Foo>
 +            442..468 'Lazy::...n_ptr)': Lazy<Foo, fn() -> Foo>
 +            452..467 'make_foo_fn_ptr': fn() -> Foo
 +            478..480 'r2': usize
 +            483..488 'lazy2': Lazy<Foo, fn() -> Foo>
 +            483..494 'lazy2.foo()': usize
 +            357..359 '{}': Foo
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn closure_1() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn
 +enum Option<T> { Some(T), None }
 +impl<T> Option<T> {
 +    fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { loop {} }
 +}
 +
 +fn test() {
 +    let x = Option::Some(1u32);
 +    x.map(|v| v + 1);
 +    x.map(|_v| 1u64);
 +    let y: Option<i64> = x.map(|_v| 1);
 +}"#,
 +        expect![[r#"
 +            86..90 'self': Option<T>
 +            92..93 'f': F
 +            111..122 '{ loop {} }': Option<U>
 +            113..120 'loop {}': !
 +            118..120 '{}': ()
 +            136..255 '{     ... 1); }': ()
 +            146..147 'x': Option<u32>
 +            150..162 'Option::Some': Some<u32>(u32) -> Option<u32>
 +            150..168 'Option...(1u32)': Option<u32>
 +            163..167 '1u32': u32
 +            174..175 'x': Option<u32>
 +            174..190 'x.map(...v + 1)': Option<u32>
 +            180..189 '|v| v + 1': |u32| -> u32
 +            181..182 'v': u32
 +            184..185 'v': u32
 +            184..189 'v + 1': u32
 +            188..189 '1': u32
 +            196..197 'x': Option<u32>
 +            196..212 'x.map(... 1u64)': Option<u64>
 +            202..211 '|_v| 1u64': |u32| -> u64
 +            203..205 '_v': u32
 +            207..211 '1u64': u64
 +            222..223 'y': Option<i64>
 +            239..240 'x': Option<u32>
 +            239..252 'x.map(|_v| 1)': Option<i64>
 +            245..251 '|_v| 1': |u32| -> i64
 +            246..248 '_v': u32
 +            250..251 '1': i64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn closure_2() {
 +    check_types(
 +        r#"
 +//- minicore: add, fn
 +
 +impl core::ops::Add for u64 {
 +    type Output = Self;
 +    fn add(self, rhs: u64) -> Self::Output {0}
 +}
 +
 +impl core::ops::Add for u128 {
 +    type Output = Self;
 +    fn add(self, rhs: u128) -> Self::Output {0}
 +}
 +
 +fn test<F: FnOnce(u32) -> u64>(f: F) {
 +    f(1);
 +  //  ^ u32
 +  //^^^^ u64
 +    let g = |v| v + 1;
 +              //^^^^^ u64
 +          //^^^^^^^^^ |u64| -> u64
 +    g(1u64);
 +  //^^^^^^^ u64
 +    let h = |v| 1u128 + v;
 +          //^^^^^^^^^^^^^ |u128| -> u128
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn closure_as_argument_inference_order() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn
 +fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U { loop {} }
 +fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U { loop {} }
 +
 +struct S;
 +impl S {
 +    fn method(self) -> u64;
 +
 +    fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U { loop {} }
 +    fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U { loop {} }
 +}
 +
 +fn test() {
 +    let x1 = foo1(S, |s| s.method());
 +    let x2 = foo2(|s| s.method(), S);
 +    let x3 = S.foo1(S, |s| s.method());
 +    let x4 = S.foo2(|s| s.method(), S);
 +}"#,
 +        expect![[r#"
 +            33..34 'x': T
 +            39..40 'f': F
 +            50..61 '{ loop {} }': U
 +            52..59 'loop {}': !
 +            57..59 '{}': ()
 +            95..96 'f': F
 +            101..102 'x': T
 +            112..123 '{ loop {} }': U
 +            114..121 'loop {}': !
 +            119..121 '{}': ()
 +            158..162 'self': S
 +            210..214 'self': S
 +            216..217 'x': T
 +            222..223 'f': F
 +            233..244 '{ loop {} }': U
 +            235..242 'loop {}': !
 +            240..242 '{}': ()
 +            282..286 'self': S
 +            288..289 'f': F
 +            294..295 'x': T
 +            305..316 '{ loop {} }': U
 +            307..314 'loop {}': !
 +            312..314 '{}': ()
 +            330..489 '{     ... S); }': ()
 +            340..342 'x1': u64
 +            345..349 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64
 +            345..368 'foo1(S...hod())': u64
 +            350..351 'S': S
 +            353..367 '|s| s.method()': |S| -> u64
 +            354..355 's': S
 +            357..358 's': S
 +            357..367 's.method()': u64
 +            378..380 'x2': u64
 +            383..387 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64
 +            383..406 'foo2(|...(), S)': u64
 +            388..402 '|s| s.method()': |S| -> u64
 +            389..390 's': S
 +            392..393 's': S
 +            392..402 's.method()': u64
 +            404..405 'S': S
 +            416..418 'x3': u64
 +            421..422 'S': S
 +            421..446 'S.foo1...hod())': u64
 +            428..429 'S': S
 +            431..445 '|s| s.method()': |S| -> u64
 +            432..433 's': S
 +            435..436 's': S
 +            435..445 's.method()': u64
 +            456..458 'x4': u64
 +            461..462 'S': S
 +            461..486 'S.foo2...(), S)': u64
 +            468..482 '|s| s.method()': |S| -> u64
 +            469..470 's': S
 +            472..473 's': S
 +            472..482 's.method()': u64
 +            484..485 'S': S
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn fn_item_fn_trait() {
 +    check_types(
 +        r#"
 +//- minicore: fn
 +struct S;
 +
 +fn foo() -> S { S }
 +
 +fn takes_closure<U, F: FnOnce() -> U>(f: F) -> U { f() }
 +
 +fn test() {
 +    takes_closure(foo);
 +} //^^^^^^^^^^^^^^^^^^ S
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_1() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +trait Trait {
 +    type Item;
 +}
 +
 +trait Trait2 {
 +    fn foo(&self) -> u32;
 +}
 +
 +fn test<T: Trait>() where T::Item: Trait2 {
 +    let x: T::Item = no_matter;
 +    x.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_2() {
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +    type Item;
 +}
 +
 +trait Trait2 {
 +    fn foo(&self) -> u32;
 +}
 +
 +fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
 +    let x: T::Item = no_matter;
 +    x.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_on_impl_self() {
 +    check_infer(
 +        r#"
 +//- /main.rs
 +trait Trait {
 +    type Item;
 +
 +    fn f(&self, x: Self::Item);
 +}
 +
 +struct S;
 +
 +impl Trait for S {
 +    type Item = u32;
 +    fn f(&self, x: Self::Item) { let y = x; }
 +}
 +
 +struct S2;
 +
 +impl Trait for S2 {
 +    type Item = i32;
 +    fn f(&self, x: <Self>::Item) { let y = x; }
 +}"#,
 +        expect![[r#"
 +            40..44 'self': &Self
 +            46..47 'x': Trait::Item<Self>
 +            126..130 'self': &S
 +            132..133 'x': u32
 +            147..161 '{ let y = x; }': ()
 +            153..154 'y': u32
 +            157..158 'x': u32
 +            228..232 'self': &S2
 +            234..235 'x': i32
 +            251..265 '{ let y = x; }': ()
 +            257..258 'y': i32
 +            261..262 'x': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_on_trait_self() {
 +    check_types(
 +        r#"
 +trait Trait {
 +    type Item;
 +
 +    fn f(&self) -> Self::Item { loop {} }
 +}
 +
 +struct S;
 +impl Trait for S {
 +    type Item = u32;
 +}
 +
 +fn test() {
 +    S.f();
 +} //^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_chalk_fold() {
 +    check_types(
 +        r#"
 +trait Interner {}
 +trait Fold<I: Interner, TI = I> {
 +    type Result;
 +}
 +
 +struct Ty<I: Interner> {}
 +impl<I: Interner, TI: Interner> Fold<I, TI> for Ty<I> {
 +    type Result = Ty<TI>;
 +}
 +
 +fn fold<I: Interner, T>(interner: &I, t: T) -> T::Result
 +where
 +    T: Fold<I, I>,
 +{
 +    loop {}
 +}
 +
 +fn foo<I: Interner>(interner: &I, t: Ty<I>) {
 +    fold(interner, t);
 +} //^^^^^^^^^^^^^^^^^ Ty<I>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_impl_self_ty() {
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +   fn foo(&self);
 +}
 +
 +struct S;
 +
 +impl Trait<Self> for S {}
 +
 +fn test() {
 +    S.foo();
 +} //^^^^^^^ ()
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_impl_self_ty_cycle() {
 +    check_types(
 +        r#"
 +trait Trait {
 +   fn foo(&self);
 +}
 +
 +struct S<T>;
 +
 +impl Trait for S<Self> {}
 +
 +fn test() {
 +    S.foo();
 +} //^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_cycle_1() {
 +    // This is not a cycle, because the `T: Trait2<T::Item>` bound depends only on the `T: Trait`
 +    // bound, not on itself (since only `Trait` can define `Item`).
 +    check_types(
 +        r#"
 +trait Trait {
 +    type Item;
 +}
 +
 +trait Trait2<T> {}
 +
 +fn test<T: Trait>() where T: Trait2<T::Item> {
 +    let x: T::Item = no_matter;
 +}                  //^^^^^^^^^ Trait::Item<T>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_cycle_2() {
 +    // this is a legitimate cycle
 +    check_types(
 +        r#"
 +//- /main.rs
 +trait Trait<T> {
 +    type Item;
 +}
 +
 +fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
 +    let x: T::Item = no_matter;
 +}                  //^^^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_cycle_3() {
 +    // this is a cycle for rustc; we currently accept it
 +    check_types(
 +        r#"
 +//- /main.rs
 +trait Trait {
 +    type Item;
 +    type OtherItem;
 +}
 +
 +fn test<T>() where T: Trait<OtherItem = T::Item> {
 +    let x: T::Item = no_matter;
 +}                  //^^^^^^^^^ Trait::Item<T>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_no_cycle() {
 +    // this is not a cycle
 +    check_types(
 +        r#"
 +//- /main.rs
 +trait Index {
 +    type Output;
 +}
 +
 +type Key<S: UnificationStoreBase> = <S as UnificationStoreBase>::Key;
 +
 +pub trait UnificationStoreBase: Index<Output = Key<Self>> {
 +    type Key;
 +
 +    fn len(&self) -> usize;
 +}
 +
 +pub trait UnificationStoreMut: UnificationStoreBase {
 +    fn push(&mut self, value: Self::Key);
 +}
 +
 +fn test<T>(t: T) where T: UnificationStoreMut {
 +    let x;
 +    t.push(x);
 +    let y: Key<T>;
 +    (x, y);
 +} //^^^^^^ (UnificationStoreBase::Key<T>, UnificationStoreBase::Key<T>)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn inline_assoc_type_bounds_1() {
 +    check_types(
 +        r#"
 +trait Iterator {
 +    type Item;
 +}
 +trait OtherTrait<T> {
 +    fn foo(&self) -> T;
 +}
 +
 +// workaround for Chalk assoc type normalization problems
 +pub struct S<T>;
 +impl<T: Iterator> Iterator for S<T> {
 +    type Item = <T as Iterator>::Item;
 +}
 +
 +fn test<I: Iterator<Item: OtherTrait<u32>>>() {
 +    let x: <S<I> as Iterator>::Item;
 +    x.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn inline_assoc_type_bounds_2() {
 +    check_types(
 +        r#"
 +trait Iterator {
 +    type Item;
 +}
 +
 +fn test<I: Iterator<Item: Iterator<Item = u32>>>() {
 +    let x: <<I as Iterator>::Item as Iterator>::Item;
 +    x;
 +} //^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn proc_macro_server_types() {
 +    check_infer(
 +        r#"
 +macro_rules! with_api {
 +    ($S:ident, $self:ident, $m:ident) => {
 +        $m! {
 +            TokenStream {
 +                fn new() -> $S::TokenStream;
 +            },
 +            Group {
 +            },
 +        }
 +    };
 +}
 +macro_rules! associated_item {
 +    (type TokenStream) =>
 +        (type TokenStream: 'static;);
 +    (type Group) =>
 +        (type Group: 'static;);
 +    ($($item:tt)*) => ($($item)*;)
 +}
 +macro_rules! declare_server_traits {
 +    ($($name:ident {
 +        $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
 +    }),* $(,)?) => {
 +        pub trait Types {
 +            $(associated_item!(type $name);)*
 +        }
 +
 +        $(pub trait $name: Types {
 +            $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)*
 +        })*
 +
 +        pub trait Server: Types $(+ $name)* {}
 +        impl<S: Types $(+ $name)*> Server for S {}
 +    }
 +}
 +
 +with_api!(Self, self_, declare_server_traits);
 +struct G {}
 +struct T {}
 +struct RustAnalyzer;
 +impl Types for RustAnalyzer {
 +    type TokenStream = T;
 +    type Group = G;
 +}
 +
 +fn make<T>() -> T { loop {} }
 +impl TokenStream for RustAnalyzer {
 +    fn new() -> Self::TokenStream {
 +        let group: Self::Group = make();
 +        make()
 +    }
 +}"#,
 +        expect![[r#"
 +            1075..1086 '{ loop {} }': T
 +            1077..1084 'loop {}': !
 +            1082..1084 '{}': ()
 +            1157..1220 '{     ...     }': T
 +            1171..1176 'group': G
 +            1192..1196 'make': fn make<G>() -> G
 +            1192..1198 'make()': G
 +            1208..1212 'make': fn make<T>() -> T
 +            1208..1214 'make()': T
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn unify_impl_trait() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Trait<T> {}
 +
 +fn foo(x: impl Trait<u32>) { loop {} }
 +fn bar<T>(x: impl Trait<T>) -> T { loop {} }
 +
 +struct S<T>(T);
 +impl<T> Trait<T> for S<T> {}
 +
 +fn default<T>() -> T { loop {} }
 +
 +fn test() -> impl Trait<i32> {
 +    let s1 = S(default());
 +    foo(s1);
 +    let x: i32 = bar(S(default()));
 +    S(default())
 +}"#,
 +        expect![[r#"
 +            26..27 'x': impl Trait<u32>
 +            46..57 '{ loop {} }': ()
 +            48..55 'loop {}': !
 +            53..55 '{}': ()
 +            68..69 'x': impl Trait<T>
 +            91..102 '{ loop {} }': T
 +            93..100 'loop {}': !
 +            98..100 '{}': ()
 +            171..182 '{ loop {} }': T
 +            173..180 'loop {}': !
 +            178..180 '{}': ()
 +            213..309 '{     ...t()) }': S<i32>
 +            223..225 's1': S<u32>
 +            228..229 'S': S<u32>(u32) -> S<u32>
 +            228..240 'S(default())': S<u32>
 +            230..237 'default': fn default<u32>() -> u32
 +            230..239 'default()': u32
 +            246..249 'foo': fn foo(S<u32>)
 +            246..253 'foo(s1)': ()
 +            250..252 's1': S<u32>
 +            263..264 'x': i32
 +            272..275 'bar': fn bar<i32>(S<i32>) -> i32
 +            272..289 'bar(S(...lt()))': i32
 +            276..277 'S': S<i32>(i32) -> S<i32>
 +            276..288 'S(default())': S<i32>
 +            278..285 'default': fn default<i32>() -> i32
 +            278..287 'default()': i32
 +            295..296 'S': S<i32>(i32) -> S<i32>
 +            295..307 'S(default())': S<i32>
 +            297..304 'default': fn default<i32>() -> i32
 +            297..306 'default()': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn assoc_types_from_bounds() {
 +    check_infer(
 +        r#"
 +//- minicore: fn
 +trait T {
 +    type O;
 +}
 +
 +impl T for () {
 +    type O = ();
 +}
 +
 +fn f<X, F>(_v: F)
 +where
 +    X: T,
 +    F: FnOnce(&X::O),
 +{ }
 +
 +fn main() {
 +    f::<(), _>(|z| { z; });
 +}"#,
 +        expect![[r#"
 +            72..74 '_v': F
 +            117..120 '{ }': ()
 +            132..163 '{     ... }); }': ()
 +            138..148 'f::<(), _>': fn f<(), |&()| -> ()>(|&()| -> ())
 +            138..160 'f::<()... z; })': ()
 +            149..159 '|z| { z; }': |&()| -> ()
 +            150..151 'z': &()
 +            153..159 '{ z; }': ()
 +            155..156 'z': &()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn associated_type_bound() {
 +    check_types(
 +        r#"
 +pub trait Trait {
 +    type Item: OtherTrait<u32>;
 +}
 +pub trait OtherTrait<T> {
 +    fn foo(&self) -> T;
 +}
 +
 +// this is just a workaround for chalk#234
 +pub struct S<T>;
 +impl<T: Trait> Trait for S<T> {
 +    type Item = <T as Trait>::Item;
 +}
 +
 +fn test<T: Trait>() {
 +    let y: <S<T> as Trait>::Item = no_matter;
 +    y.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn dyn_trait_through_chalk() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Box<T: ?Sized> {}
 +impl<T: ?Sized> core::ops::Deref for Box<T> {
 +    type Target = T;
 +}
 +trait Trait {
 +    fn foo(&self);
 +}
 +
 +fn test(x: Box<dyn Trait>) {
 +    x.foo();
 +} //^^^^^^^ ()
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn string_to_owned() {
 +    check_types(
 +        r#"
 +struct String {}
 +pub trait ToOwned {
 +    type Owned;
 +    fn to_owned(&self) -> Self::Owned;
 +}
 +impl ToOwned for str {
 +    type Owned = String;
 +}
 +fn test() {
 +    "foo".to_owned();
 +} //^^^^^^^^^^^^^^^^ String
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn iterator_chain() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn, option
 +pub trait Iterator {
 +    type Item;
 +
 +    fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
 +    where
 +        F: FnMut(Self::Item) -> Option<B>,
 +    { loop {} }
 +
 +    fn for_each<F>(self, f: F)
 +    where
 +        F: FnMut(Self::Item),
 +    { loop {} }
 +}
 +
 +pub trait IntoIterator {
 +    type Item;
 +    type IntoIter: Iterator<Item = Self::Item>;
 +    fn into_iter(self) -> Self::IntoIter;
 +}
 +
 +pub struct FilterMap<I, F> { }
 +impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
 +where
 +    F: FnMut(I::Item) -> Option<B>,
 +{
 +    type Item = B;
 +}
 +
 +#[stable(feature = "rust1", since = "1.0.0")]
 +impl<I: Iterator> IntoIterator for I {
 +    type Item = I::Item;
 +    type IntoIter = I;
 +
 +    fn into_iter(self) -> I {
 +        self
 +    }
 +}
 +
 +struct Vec<T> {}
 +impl<T> Vec<T> {
 +    fn new() -> Self { loop {} }
 +}
 +
 +impl<T> IntoIterator for Vec<T> {
 +    type Item = T;
 +    type IntoIter = IntoIter<T>;
 +}
 +
 +pub struct IntoIter<T> { }
 +impl<T> Iterator for IntoIter<T> {
 +    type Item = T;
 +}
 +
 +fn main() {
 +    Vec::<i32>::new().into_iter()
 +    .filter_map(|x| if x > 0 { Some(x as u32) } else { None })
 +    .for_each(|y| { y; });
 +}"#,
 +        expect![[r#"
 +            61..65 'self': Self
 +            67..68 'f': F
 +            152..163 '{ loop {} }': FilterMap<Self, F>
 +            154..161 'loop {}': !
 +            159..161 '{}': ()
 +            184..188 'self': Self
 +            190..191 'f': F
 +            240..251 '{ loop {} }': ()
 +            242..249 'loop {}': !
 +            247..249 '{}': ()
 +            360..364 'self': Self
 +            689..693 'self': I
 +            700..720 '{     ...     }': I
 +            710..714 'self': I
 +            779..790 '{ loop {} }': Vec<T>
 +            781..788 'loop {}': !
 +            786..788 '{}': ()
 +            977..1104 '{     ... }); }': ()
 +            983..998 'Vec::<i32>::new': fn new<i32>() -> Vec<i32>
 +            983..1000 'Vec::<...:new()': Vec<i32>
 +            983..1012 'Vec::<...iter()': IntoIter<i32>
 +            983..1075 'Vec::<...one })': FilterMap<IntoIter<i32>, |i32| -> Option<u32>>
 +            983..1101 'Vec::<... y; })': ()
 +            1029..1074 '|x| if...None }': |i32| -> Option<u32>
 +            1030..1031 'x': i32
 +            1033..1074 'if x >...None }': Option<u32>
 +            1036..1037 'x': i32
 +            1036..1041 'x > 0': bool
 +            1040..1041 '0': i32
 +            1042..1060 '{ Some...u32) }': Option<u32>
 +            1044..1048 'Some': Some<u32>(u32) -> Option<u32>
 +            1044..1058 'Some(x as u32)': Option<u32>
 +            1049..1050 'x': i32
 +            1049..1057 'x as u32': u32
 +            1066..1074 '{ None }': Option<u32>
 +            1068..1072 'None': Option<u32>
 +            1090..1100 '|y| { y; }': |u32| -> ()
 +            1091..1092 'y': u32
 +            1094..1100 '{ y; }': ()
 +            1096..1097 'y': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn nested_assoc() {
 +    check_types(
 +        r#"
 +struct Bar;
 +struct Foo;
 +
 +trait A {
 +    type OutputA;
 +}
 +
 +impl A for Bar {
 +    type OutputA = Foo;
 +}
 +
 +trait B {
 +    type Output;
 +    fn foo() -> Self::Output;
 +}
 +
 +impl<T:A> B for T {
 +    type Output = T::OutputA;
 +    fn foo() -> Self::Output { loop {} }
 +}
 +
 +fn main() {
 +    Bar::foo();
 +} //^^^^^^^^^^ Foo
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_object_no_coercion() {
 +    check_infer_with_mismatches(
 +        r#"
 +trait Foo {}
 +
 +fn foo(x: &dyn Foo) {}
 +
 +fn test(x: &dyn Foo) {
 +    foo(x);
 +}"#,
 +        expect![[r#"
 +            21..22 'x': &dyn Foo
 +            34..36 '{}': ()
 +            46..47 'x': &dyn Foo
 +            59..74 '{     foo(x); }': ()
 +            65..68 'foo': fn foo(&dyn Foo)
 +            65..71 'foo(x)': ()
 +            69..70 'x': &dyn Foo
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn builtin_copy() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: copy
 +struct IsCopy;
 +impl Copy for IsCopy {}
 +struct NotCopy;
 +
 +trait Test { fn test(&self) -> bool; }
 +impl<T: Copy> Test for T {}
 +
 +fn test() {
 +    IsCopy.test();
 +    NotCopy.test();
 +    (IsCopy, IsCopy).test();
 +    (IsCopy, NotCopy).test();
 +}"#,
 +        expect![[r#"
 +            78..82 'self': &Self
 +            134..235 '{     ...t(); }': ()
 +            140..146 'IsCopy': IsCopy
 +            140..153 'IsCopy.test()': bool
 +            159..166 'NotCopy': NotCopy
 +            159..173 'NotCopy.test()': {unknown}
 +            179..195 '(IsCop...sCopy)': (IsCopy, IsCopy)
 +            179..202 '(IsCop...test()': bool
 +            180..186 'IsCopy': IsCopy
 +            188..194 'IsCopy': IsCopy
 +            208..225 '(IsCop...tCopy)': (IsCopy, NotCopy)
 +            208..232 '(IsCop...test()': {unknown}
 +            209..215 'IsCopy': IsCopy
 +            217..224 'NotCopy': NotCopy
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn builtin_fn_def_copy() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: copy
 +fn foo() {}
 +fn bar<T: Copy>(T) -> T {}
 +struct Struct(usize);
 +enum Enum { Variant(usize) }
 +
 +trait Test { fn test(&self) -> bool; }
 +impl<T: Copy> Test for T {}
 +
 +fn test() {
 +    foo.test();
 +    bar.test();
 +    Struct.test();
 +    Enum::Variant.test();
 +}"#,
 +        expect![[r#"
 +            9..11 '{}': ()
 +            28..29 'T': {unknown}
 +            36..38 '{}': T
 +            36..38: expected T, got ()
 +            113..117 'self': &Self
 +            169..249 '{     ...t(); }': ()
 +            175..178 'foo': fn foo()
 +            175..185 'foo.test()': bool
 +            191..194 'bar': fn bar<{unknown}>({unknown}) -> {unknown}
 +            191..201 'bar.test()': bool
 +            207..213 'Struct': Struct(usize) -> Struct
 +            207..220 'Struct.test()': bool
 +            226..239 'Enum::Variant': Variant(usize) -> Enum
 +            226..246 'Enum::...test()': bool
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn builtin_fn_ptr_copy() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: copy
 +trait Test { fn test(&self) -> bool; }
 +impl<T: Copy> Test for T {}
 +
 +fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) {
 +    f1.test();
 +    f2.test();
 +    f3.test();
 +}"#,
 +        expect![[r#"
 +            22..26 'self': &Self
 +            76..78 'f1': fn()
 +            86..88 'f2': fn(usize) -> u8
 +            107..109 'f3': fn(u8, u8) -> &u8
 +            130..178 '{     ...t(); }': ()
 +            136..138 'f1': fn()
 +            136..145 'f1.test()': bool
 +            151..153 'f2': fn(usize) -> u8
 +            151..160 'f2.test()': bool
 +            166..168 'f3': fn(u8, u8) -> &u8
 +            166..175 'f3.test()': bool
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn builtin_sized() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Test { fn test(&self) -> bool; }
 +impl<T: Sized> Test for T {}
 +
 +fn test() {
 +    1u8.test();
 +    (*"foo").test(); // not Sized
 +    (1u8, 1u8).test();
 +    (1u8, *"foo").test(); // not Sized
 +}"#,
 +        expect![[r#"
 +            22..26 'self': &Self
 +            79..194 '{     ...ized }': ()
 +            85..88 '1u8': u8
 +            85..95 '1u8.test()': bool
 +            101..116 '(*"foo").test()': {unknown}
 +            102..108 '*"foo"': str
 +            103..108 '"foo"': &str
 +            135..145 '(1u8, 1u8)': (u8, u8)
 +            135..152 '(1u8, ...test()': bool
 +            136..139 '1u8': u8
 +            141..144 '1u8': u8
 +            158..171 '(1u8, *"foo")': (u8, str)
 +            158..178 '(1u8, ...test()': {unknown}
 +            159..162 '1u8': u8
 +            164..170 '*"foo"': str
 +            165..170 '"foo"': &str
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn integer_range_iterate() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:core
 +fn test() {
 +    for x in 0..100 { x; }
 +}                   //^ i32
 +
 +//- /core.rs crate:core
 +pub mod ops {
 +    pub struct Range<Idx> {
 +        pub start: Idx,
 +        pub end: Idx,
 +    }
 +}
 +
 +pub mod iter {
 +    pub trait Iterator {
 +        type Item;
 +    }
 +
 +    pub trait IntoIterator {
 +        type Item;
 +        type IntoIter: Iterator<Item = Self::Item>;
 +    }
 +
 +    impl<T> IntoIterator for T where T: Iterator {
 +        type Item = <T as Iterator>::Item;
 +        type IntoIter = Self;
 +    }
 +}
 +
 +trait Step {}
 +impl Step for i32 {}
 +impl Step for i64 {}
 +
 +impl<A: Step> iter::Iterator for ops::Range<A> {
 +    type Item = A;
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_closure_arg() {
 +    check_infer(
 +        r#"
 +//- /lib.rs
 +
 +enum Option<T> {
 +    None,
 +    Some(T)
 +}
 +
 +fn foo() {
 +    let s = Option::None;
 +    let f = |x: Option<i32>| {};
 +    (&f)(s)
 +}"#,
 +        expect![[r#"
 +            52..126 '{     ...)(s) }': ()
 +            62..63 's': Option<i32>
 +            66..78 'Option::None': Option<i32>
 +            88..89 'f': |Option<i32>| -> ()
 +            92..111 '|x: Op...2>| {}': |Option<i32>| -> ()
 +            93..94 'x': Option<i32>
 +            109..111 '{}': ()
 +            117..124 '(&f)(s)': ()
 +            118..120 '&f': &|Option<i32>| -> ()
 +            119..120 'f': |Option<i32>| -> ()
 +            122..123 's': Option<i32>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn dyn_fn_param_informs_call_site_closure_signature() {
 +    cov_mark::check!(dyn_fn_param_informs_call_site_closure_signature);
 +    check_types(
 +        r#"
 +//- minicore: fn, coerce_unsized
 +struct S;
 +impl S {
 +    fn inherent(&self) -> u8 { 0 }
 +}
 +fn take_dyn_fn(f: &dyn Fn(S)) {}
 +
 +fn f() {
 +    take_dyn_fn(&|x| { x.inherent(); });
 +                     //^^^^^^^^^^^^ u8
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_fn_trait_arg() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn, option
 +fn foo<F, T>(f: F) -> T
 +where
 +    F: Fn(Option<i32>) -> T,
 +{
 +    let s = None;
 +    f(s)
 +}
 +"#,
 +        expect![[r#"
 +            13..14 'f': F
 +            59..89 '{     ...f(s) }': T
 +            69..70 's': Option<i32>
 +            73..77 'None': Option<i32>
 +            83..84 'f': F
 +            83..87 'f(s)': T
 +            85..86 's': Option<i32>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_box_fn_arg() {
 +    // The type mismatch is because we don't define Unsize and CoerceUnsized
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn, deref, option
 +#[lang = "owned_box"]
 +pub struct Box<T: ?Sized> {
 +    inner: *mut T,
 +}
 +
 +impl<T: ?Sized> core::ops::Deref for Box<T> {
 +    type Target = T;
 +
 +    fn deref(&self) -> &T {
 +        &self.inner
 +    }
 +}
 +
 +fn foo() {
 +    let s = None;
 +    let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {});
 +    f(&s);
 +}"#,
 +        expect![[r#"
 +            154..158 'self': &Box<T>
 +            166..193 '{     ...     }': &T
 +            176..187 '&self.inner': &*mut T
 +            177..181 'self': &Box<T>
 +            177..187 'self.inner': *mut T
 +            206..296 '{     ...&s); }': ()
 +            216..217 's': Option<i32>
 +            220..224 'None': Option<i32>
 +            234..235 'f': Box<dyn FnOnce(&Option<i32>)>
 +            269..282 'box (|ps| {})': Box<|&Option<i32>| -> ()>
 +            274..281 '|ps| {}': |&Option<i32>| -> ()
 +            275..277 'ps': &Option<i32>
 +            279..281 '{}': ()
 +            288..289 'f': Box<dyn FnOnce(&Option<i32>)>
 +            288..293 'f(&s)': ()
 +            290..292 '&s': &Option<i32>
 +            291..292 's': Option<i32>
 +            269..282: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|&Option<i32>| -> ()>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_dyn_fn_output() {
 +    check_types(
 +        r#"
 +//- minicore: fn
 +fn foo() {
 +    let f: &dyn Fn() -> i32;
 +    f();
 +  //^^^ i32
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_dyn_fn_once_output() {
 +    check_types(
 +        r#"
 +//- minicore: fn
 +fn foo() {
 +    let f: dyn FnOnce() -> i32;
 +    f();
 +  //^^^ i32
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn variable_kinds_1() {
 +    check_types(
 +        r#"
 +trait Trait<T> { fn get(self, t: T) -> T; }
 +struct S;
 +impl Trait<u128> for S {}
 +impl Trait<f32> for S {}
 +fn test() {
 +    S.get(1);
 +  //^^^^^^^^ u128
 +    S.get(1.);
 +  //^^^^^^^^^ f32
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn variable_kinds_2() {
 +    check_types(
 +        r#"
 +trait Trait { fn get(self) -> Self; }
 +impl Trait for u128 {}
 +impl Trait for f32 {}
 +fn test() {
 +    1.get();
 +  //^^^^^^^ u128
 +    (1.).get();
 +  //^^^^^^^^^^ f32
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn underscore_import() {
 +    check_types(
 +        r#"
 +mod tr {
 +    pub trait Tr {
 +        fn method(&self) -> u8 { 0 }
 +    }
 +}
 +
 +struct Tr;
 +impl crate::tr::Tr for Tr {}
 +
 +use crate::tr::Tr as _;
 +fn test() {
 +    Tr.method();
 +  //^^^^^^^^^^^ u8
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn inner_use() {
 +    check_types(
 +        r#"
 +mod m {
 +    pub trait Tr {
 +        fn method(&self) -> u8 { 0 }
 +    }
 +
 +    impl Tr for () {}
 +}
 +
 +fn f() {
 +    use m::Tr;
 +
 +    ().method();
 +  //^^^^^^^^^^^ u8
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn trait_in_scope_with_inner_item() {
 +    check_infer(
 +        r#"
 +mod m {
 +    pub trait Tr {
 +        fn method(&self) -> u8 { 0 }
 +    }
 +
 +    impl Tr for () {}
 +}
 +
 +use m::Tr;
 +
 +fn f() {
 +    fn inner() {
 +        ().method();
 +      //^^^^^^^^^^^ u8
 +    }
 +}"#,
 +        expect![[r#"
 +            46..50 'self': &Self
 +            58..63 '{ 0 }': u8
 +            60..61 '0': u8
 +            115..185 '{     ...   } }': ()
 +            132..183 '{     ...     }': ()
 +            142..144 '()': ()
 +            142..153 '().method()': u8
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn inner_use_in_block() {
 +    check_types(
 +        r#"
 +mod m {
 +    pub trait Tr {
 +        fn method(&self) -> u8 { 0 }
 +    }
 +
 +    impl Tr for () {}
 +}
 +
 +fn f() {
 +    {
 +        use m::Tr;
 +
 +        ().method();
 +      //^^^^^^^^^^^ u8
 +    }
 +
 +    {
 +        ().method();
 +      //^^^^^^^^^^^ {unknown}
 +    }
 +
 +    ().method();
 +  //^^^^^^^^^^^ {unknown}
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn nested_inner_function_calling_self() {
 +    check_infer(
 +        r#"
 +struct S;
 +fn f() {
 +    fn inner() -> S {
 +        let s = inner();
 +    }
 +}"#,
 +        expect![[r#"
 +            17..73 '{     ...   } }': ()
 +            39..71 '{     ...     }': S
 +            53..54 's': S
 +            57..62 'inner': fn inner() -> S
 +            57..64 'inner()': S
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn infer_default_trait_type_parameter() {
 +    check_infer(
 +        r#"
 +struct A;
 +
 +trait Op<RHS=Self> {
 +    type Output;
 +
 +    fn do_op(self, rhs: RHS) -> Self::Output;
 +}
 +
 +impl Op for A {
 +    type Output = bool;
 +
 +    fn do_op(self, rhs: Self) -> Self::Output {
 +        true
 +    }
 +}
 +
 +fn test() {
 +    let x = A;
 +    let y = A;
 +    let r = x.do_op(y);
 +}"#,
 +        expect![[r#"
 +            63..67 'self': Self
 +            69..72 'rhs': RHS
 +            153..157 'self': A
 +            159..162 'rhs': A
 +            186..206 '{     ...     }': bool
 +            196..200 'true': bool
 +            220..277 '{     ...(y); }': ()
 +            230..231 'x': A
 +            234..235 'A': A
 +            245..246 'y': A
 +            249..250 'A': A
 +            260..261 'r': bool
 +            264..265 'x': A
 +            264..274 'x.do_op(y)': bool
 +            272..273 'y': A
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn qualified_path_as_qualified_trait() {
 +    check_infer(
 +        r#"
 +mod foo {
 +
 +    pub trait Foo {
 +        type Target;
 +    }
 +    pub trait Bar {
 +        type Output;
 +        fn boo() -> Self::Output {
 +            loop {}
 +        }
 +    }
 +}
 +
 +struct F;
 +impl foo::Foo for F {
 +    type Target = ();
 +}
 +impl foo::Bar for F {
 +    type Output = <F as foo::Foo>::Target;
 +}
 +
 +fn foo() {
 +    use foo::Bar;
 +    let x = <F as Bar>::boo();
 +}"#,
 +        expect![[r#"
 +            132..163 '{     ...     }': Bar::Output<Self>
 +            146..153 'loop {}': !
 +            151..153 '{}': ()
 +            306..358 '{     ...o(); }': ()
 +            334..335 'x': ()
 +            338..353 '<F as Bar>::boo': fn boo<F>() -> <F as Bar>::Output
 +            338..355 '<F as ...:boo()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn renamed_extern_crate_in_block() {
 +    check_types(
 +        r#"
 +//- /lib.rs crate:lib deps:serde
 +use serde::Deserialize;
 +
 +struct Foo {}
 +
 +const _ : () = {
 +    extern crate serde as _serde;
 +    impl _serde::Deserialize for Foo {
 +        fn deserialize() -> u8 { 0 }
 +    }
 +};
 +
 +fn foo() {
 +    Foo::deserialize();
 +  //^^^^^^^^^^^^^^^^^^ u8
 +}
 +
 +//- /serde.rs crate:serde
 +
 +pub trait Deserialize {
 +    fn deserialize() -> u8;
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn bin_op_with_rhs_is_self_for_assoc_bound() {
 +    check_no_mismatches(
 +        r#"//- minicore: eq
 +        fn repro<T>(t: T) -> bool
 +where
 +    T: Request,
 +    T::Output: Convertable,
 +{
 +    let a = execute(&t).convert();
 +    let b = execute(&t).convert();
 +    a.eq(&b);
 +    let a = execute(&t).convert2();
 +    let b = execute(&t).convert2();
 +    a.eq(&b)
 +}
 +fn execute<T>(t: &T) -> T::Output
 +where
 +    T: Request,
 +{
 +    <T as Request>::output()
 +}
 +trait Convertable {
 +    type TraitSelf: PartialEq<Self::TraitSelf>;
 +    type AssocAsDefaultSelf: PartialEq;
 +    fn convert(self) -> Self::AssocAsDefaultSelf;
 +    fn convert2(self) -> Self::TraitSelf;
 +}
 +trait Request {
 +    type Output;
 +    fn output() -> Self::Output;
 +}
 +     "#,
 +    );
 +}
 +
 +#[test]
 +fn bin_op_adt_with_rhs_primitive() {
 +    check_infer_with_mismatches(
 +        r#"
 +#[lang = "add"]
 +pub trait Add<Rhs = Self> {
 +    type Output;
 +    fn add(self, rhs: Rhs) -> Self::Output;
 +}
 +
 +struct Wrapper(u32);
 +impl Add<u32> for Wrapper {
 +    type Output = Self;
 +    fn add(self, rhs: u32) -> Wrapper {
 +        Wrapper(rhs)
 +    }
 +}
 +fn main(){
 +    let wrapped = Wrapper(10);
 +    let num: u32 = 2;
 +    let res = wrapped + num;
 +
 +}"#,
 +        expect![[r#"
 +            72..76 'self': Self
 +            78..81 'rhs': Rhs
 +            192..196 'self': Wrapper
 +            198..201 'rhs': u32
 +            219..247 '{     ...     }': Wrapper
 +            229..236 'Wrapper': Wrapper(u32) -> Wrapper
 +            229..241 'Wrapper(rhs)': Wrapper
 +            237..240 'rhs': u32
 +            259..345 '{     ...um;  }': ()
 +            269..276 'wrapped': Wrapper
 +            279..286 'Wrapper': Wrapper(u32) -> Wrapper
 +            279..290 'Wrapper(10)': Wrapper
 +            287..289 '10': u32
 +            300..303 'num': u32
 +            311..312 '2': u32
 +            322..325 'res': Wrapper
 +            328..335 'wrapped': Wrapper
 +            328..341 'wrapped + num': Wrapper
 +            338..341 'num': u32
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn array_length() {
 +    check_infer(
 +        r#"
 +trait T {
 +    type Output;
 +    fn do_thing(&self) -> Self::Output;
 +}
 +
 +impl T for [u8; 4] {
 +    type Output = usize;
 +    fn do_thing(&self) -> Self::Output {
 +        2
 +    }
 +}
 +
 +impl T for [u8; 2] {
 +    type Output = u8;
 +    fn do_thing(&self) -> Self::Output {
 +        2
 +    }
 +}
 +
 +fn main() {
 +    let v = [0u8; 2];
 +    let v2 = v.do_thing();
 +    let v3 = [0u8; 4];
 +    let v4 = v3.do_thing();
 +}
 +"#,
 +        expect![[r#"
 +            44..48 'self': &Self
 +            133..137 'self': &[u8; 4]
 +            155..172 '{     ...     }': usize
 +            165..166 '2': usize
 +            236..240 'self': &[u8; 2]
 +            258..275 '{     ...     }': u8
 +            268..269 '2': u8
 +            289..392 '{     ...g(); }': ()
 +            299..300 'v': [u8; 2]
 +            303..311 '[0u8; 2]': [u8; 2]
 +            304..307 '0u8': u8
 +            309..310 '2': usize
 +            321..323 'v2': u8
 +            326..327 'v': [u8; 2]
 +            326..338 'v.do_thing()': u8
 +            348..350 'v3': [u8; 4]
 +            353..361 '[0u8; 4]': [u8; 4]
 +            354..357 '0u8': u8
 +            359..360 '4': usize
 +            371..373 'v4': usize
 +            376..378 'v3': [u8; 4]
 +            376..389 'v3.do_thing()': usize
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn const_generics() {
 +    check_infer(
 +        r#"
 +trait T {
 +    type Output;
 +    fn do_thing(&self) -> Self::Output;
 +}
 +
 +impl<const L: usize> T for [u8; L] {
 +    type Output = [u8; L];
 +    fn do_thing(&self) -> Self::Output {
 +        *self
 +    }
 +}
 +
 +fn main() {
 +    let v = [0u8; 2];
 +    let v2 = v.do_thing();
 +}
 +"#,
 +        expect![[r#"
 +            44..48 'self': &Self
 +            151..155 'self': &[u8; L]
 +            173..194 '{     ...     }': [u8; L]
 +            183..188 '*self': [u8; L]
 +            184..188 'self': &[u8; L]
 +            208..260 '{     ...g(); }': ()
 +            218..219 'v': [u8; 2]
 +            222..230 '[0u8; 2]': [u8; 2]
 +            223..226 '0u8': u8
 +            228..229 '2': usize
 +            240..242 'v2': [u8; 2]
 +            245..246 'v': [u8; 2]
 +            245..257 'v.do_thing()': [u8; 2]
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn fn_returning_unit() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn
 +fn test<F: FnOnce()>(f: F) {
 +    let _: () = f();
 +}"#,
 +        expect![[r#"
 +            21..22 'f': F
 +            27..51 '{     ...f(); }': ()
 +            37..38 '_': ()
 +            45..46 'f': F
 +            45..48 'f()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn trait_in_scope_of_trait_impl() {
 +    check_infer(
 +        r#"
 +mod foo {
 +    pub trait Foo {
 +        fn foo(self);
 +        fn bar(self) -> usize { 0 }
 +    }
 +}
 +impl foo::Foo for u32 {
 +    fn foo(self) {
 +        let _x = self.bar();
 +    }
 +}
 +    "#,
 +        expect![[r#"
 +            45..49 'self': Self
 +            67..71 'self': Self
 +            82..87 '{ 0 }': usize
 +            84..85 '0': usize
 +            131..135 'self': u32
 +            137..173 '{     ...     }': ()
 +            151..153 '_x': usize
 +            156..160 'self': u32
 +            156..166 'self.bar()': usize
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_async_ret_type() {
 +    check_types(
 +        r#"
 +//- minicore: future, result
 +struct Fooey;
 +
 +impl Fooey {
 +    fn collect<B: Convert>(self) -> B {
 +        B::new()
 +    }
 +}
 +
 +trait Convert {
 +    fn new() -> Self;
 +}
 +impl Convert for u32 {
 +    fn new() -> Self { 0 }
 +}
 +
 +async fn get_accounts() -> Result<u32, ()> {
 +    let ret = Fooey.collect();
 +    //        ^^^^^^^^^^^^^^^ u32
 +    Ok(ret)
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn local_impl_1() {
 +    check!(block_local_impls);
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +}
 +
 +fn test() {
 +    struct S;
 +    impl Trait<u32> for S {
 +        fn foo(&self) -> u32 { 0 }
 +    }
 +
 +    S.foo();
 + // ^^^^^^^ u32
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn local_impl_2() {
 +    check!(block_local_impls);
 +    check_types(
 +        r#"
 +struct S;
 +
 +fn test() {
 +    trait Trait<T> {
 +        fn foo(&self) -> T;
 +    }
 +    impl Trait<u32> for S {
 +        fn foo(&self) -> u32 { 0 }
 +    }
 +
 +    S.foo();
 + // ^^^^^^^ u32
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn local_impl_3() {
 +    check!(block_local_impls);
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +}
 +
 +fn test() {
 +    struct S1;
 +    {
 +        struct S2;
 +
 +        impl Trait<S1> for S2 {
 +            fn foo(&self) -> S1 { S1 }
 +        }
 +
 +        S2.foo();
 +     // ^^^^^^^^ S1
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn associated_type_sized_bounds() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +struct Yes;
 +trait IsSized { const IS_SIZED: Yes; }
 +impl<T: Sized> IsSized for T { const IS_SIZED: Yes = Yes; }
 +
 +trait Foo {
 +    type Explicit: Sized;
 +    type Implicit;
 +    type Relaxed: ?Sized;
 +}
 +fn f<F: Foo>() {
 +    F::Explicit::IS_SIZED;
 +    F::Implicit::IS_SIZED;
 +    F::Relaxed::IS_SIZED;
 +}
 +"#,
 +        expect![[r#"
 +            104..107 'Yes': Yes
 +            212..295 '{     ...ZED; }': ()
 +            218..239 'F::Exp..._SIZED': Yes
 +            245..266 'F::Imp..._SIZED': Yes
 +            272..292 'F::Rel..._SIZED': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn dyn_map() {
 +    check_types(
 +        r#"
 +pub struct Key<K, V, P = (K, V)> {}
 +
 +pub trait Policy {
 +    type K;
 +    type V;
 +}
 +
 +impl<K, V> Policy for (K, V) {
 +    type K = K;
 +    type V = V;
 +}
 +
 +pub struct KeyMap<KEY> {}
 +
 +impl<P: Policy> KeyMap<Key<P::K, P::V, P>> {
 +    pub fn get(&self, key: &P::K) -> P::V {
 +        loop {}
 +    }
 +}
 +
 +struct Fn {}
 +struct FunctionId {}
 +
 +fn test() {
 +    let key_map: &KeyMap<Key<Fn, FunctionId>> = loop {};
 +    let key;
 +    let result = key_map.get(key);
 +      //^^^^^^ FunctionId
 +}
 +"#,
 +    )
 +}
 +
 +#[test]
 +fn dyn_multiple_auto_traits_in_different_order() {
 +    check_no_mismatches(
 +        r#"
 +auto trait Send {}
 +auto trait Sync {}
 +
 +fn f(t: &(dyn Sync + Send)) {}
 +fn g(t: &(dyn Send + Sync)) {
 +    f(t);
 +}
 +        "#,
 +    );
 +
 +    check_no_mismatches(
 +        r#"
 +auto trait Send {}
 +auto trait Sync {}
 +trait T {}
 +
 +fn f(t: &(dyn T + Send + Sync)) {}
 +fn g(t: &(dyn Sync + T + Send)) {
 +    f(t);
 +}
 +        "#,
 +    );
 +
 +    check_infer_with_mismatches(
 +        r#"
 +auto trait Send {}
 +auto trait Sync {}
 +trait T1 {}
 +trait T2 {}
 +
 +fn f(t: &(dyn T1 + T2 + Send + Sync)) {}
 +fn g(t: &(dyn Sync + T2 + T1 + Send)) {
 +    f(t);
 +}
 +        "#,
 +        expect![[r#"
 +            68..69 't': &{unknown}
 +            101..103 '{}': ()
 +            109..110 't': &{unknown}
 +            142..155 '{     f(t); }': ()
 +            148..149 'f': fn f(&{unknown})
 +            148..152 'f(t)': ()
 +            150..151 't': &{unknown}
 +        "#]],
 +    );
 +
 +    check_no_mismatches(
 +        r#"
 +auto trait Send {}
 +auto trait Sync {}
 +trait T {
 +    type Proj: Send + Sync;
 +}
 +
 +fn f(t: &(dyn T<Proj = ()>  + Send + Sync)) {}
 +fn g(t: &(dyn Sync + T<Proj = ()> + Send)) {
 +    f(t);
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn dyn_multiple_projection_bounds() {
 +    check_no_mismatches(
 +        r#"
 +trait Trait {
 +    type T;
 +    type U;
 +}
 +
 +fn f(t: &dyn Trait<T = (), U = ()>) {}
 +fn g(t: &dyn Trait<U = (), T = ()>) {
 +    f(t);
 +}
 +        "#,
 +    );
 +
 +    check_types(
 +        r#"
 +trait Trait {
 +    type T;
 +}
 +
 +fn f(t: &dyn Trait<T = (), T = ()>) {}
 +   //^&{unknown}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn dyn_duplicate_auto_trait() {
 +    check_no_mismatches(
 +        r#"
 +auto trait Send {}
 +
 +fn f(t: &(dyn Send + Send)) {}
 +fn g(t: &(dyn Send)) {
 +    f(t);
 +}
 +        "#,
 +    );
 +
 +    check_no_mismatches(
 +        r#"
 +auto trait Send {}
 +trait T {}
 +
 +fn f(t: &(dyn T + Send + Send)) {}
 +fn g(t: &(dyn T + Send)) {
 +    f(t);
 +}
 +        "#,
 +    );
 +}
index 372c3a3cca644fd0966c88bc992c5c06087ffb03,0000000000000000000000000000000000000000..c425f35acfe7e188612bbd3827104793987eca5c
mode 100644,000000..100644
--- /dev/null
@@@ -1,198 -1,0 +1,198 @@@
-     Guidance, InEnvironment, Interner, ProjectionTy, Solution, TraitRefExt, Ty, TyKind,
-     WhereClause,
 +//! Trait solving using Chalk.
 +
 +use std::{env::var, sync::Arc};
 +
 +use chalk_ir::GoalData;
 +use chalk_recursive::Cache;
 +use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};
 +
 +use base_db::CrateId;
 +use hir_def::{lang_item::LangItemTarget, TraitId};
 +use stdx::panic_context;
 +use syntax::SmolStr;
 +
 +use crate::{
 +    db::HirDatabase, infer::unify::InferenceTable, AliasEq, AliasTy, Canonical, DomainGoal, Goal,
-         if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(Interner).kind(Interner) {
++    Guidance, InEnvironment, Interner, ProjectionTy, ProjectionTyExt, Solution, TraitRefExt, Ty,
++    TyKind, WhereClause,
 +};
 +
 +/// This controls how much 'time' we give the Chalk solver before giving up.
 +const CHALK_SOLVER_FUEL: i32 = 100;
 +
 +#[derive(Debug, Copy, Clone)]
 +pub(crate) struct ChalkContext<'a> {
 +    pub(crate) db: &'a dyn HirDatabase,
 +    pub(crate) krate: CrateId,
 +}
 +
 +fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
 +    let overflow_depth =
 +        var("CHALK_OVERFLOW_DEPTH").ok().and_then(|s| s.parse().ok()).unwrap_or(500);
 +    let max_size = var("CHALK_SOLVER_MAX_SIZE").ok().and_then(|s| s.parse().ok()).unwrap_or(150);
 +    chalk_recursive::RecursiveSolver::new(overflow_depth, max_size, Some(Cache::new()))
 +}
 +
 +/// A set of clauses that we assume to be true. E.g. if we are inside this function:
 +/// ```rust
 +/// fn foo<T: Default>(t: T) {}
 +/// ```
 +/// we assume that `T: Default`.
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct TraitEnvironment {
 +    pub krate: CrateId,
 +    // FIXME make this a BTreeMap
 +    pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
 +    pub env: chalk_ir::Environment<Interner>,
 +}
 +
 +impl TraitEnvironment {
 +    pub fn empty(krate: CrateId) -> Self {
 +        TraitEnvironment {
 +            krate,
 +            traits_from_clauses: Vec::new(),
 +            env: chalk_ir::Environment::new(Interner),
 +        }
 +    }
 +
 +    pub fn traits_in_scope_from_clauses<'a>(
 +        &'a self,
 +        ty: Ty,
 +    ) -> impl Iterator<Item = TraitId> + 'a {
 +        self.traits_from_clauses
 +            .iter()
 +            .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then(|| *trait_id))
 +    }
 +}
 +
 +pub(crate) fn normalize_projection_query(
 +    db: &dyn HirDatabase,
 +    projection: ProjectionTy,
 +    env: Arc<TraitEnvironment>,
 +) -> Ty {
 +    let mut table = InferenceTable::new(db, env);
 +    let ty = table.normalize_projection_ty(projection);
 +    table.resolve_completely(ty)
 +}
 +
 +/// Solve a trait goal using Chalk.
 +pub(crate) fn trait_solve_query(
 +    db: &dyn HirDatabase,
 +    krate: CrateId,
 +    goal: Canonical<InEnvironment<Goal>>,
 +) -> Option<Solution> {
 +    let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(Interner) {
 +        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
 +            db.trait_data(it.hir_trait_id()).name.to_string()
 +        }
 +        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(),
 +        _ => "??".to_string(),
 +    });
 +    tracing::info!("trait_solve_query({:?})", goal.value.goal);
 +
 +    if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
 +        alias: AliasTy::Projection(projection_ty),
 +        ..
 +    }))) = &goal.value.goal.data(Interner)
 +    {
++        if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner) {
 +            // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
 +            return Some(Solution::Ambig(Guidance::Unknown));
 +        }
 +    }
 +
 +    // We currently don't deal with universes (I think / hope they're not yet
 +    // relevant for our use cases?)
 +    let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
 +    solve(db, krate, &u_canonical)
 +}
 +
 +fn solve(
 +    db: &dyn HirDatabase,
 +    krate: CrateId,
 +    goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
 +) -> Option<chalk_solve::Solution<Interner>> {
 +    let context = ChalkContext { db, krate };
 +    tracing::debug!("solve goal: {:?}", goal);
 +    let mut solver = create_chalk_solver();
 +
 +    let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL);
 +
 +    let should_continue = || {
 +        db.unwind_if_cancelled();
 +        let remaining = fuel.get();
 +        fuel.set(remaining - 1);
 +        if remaining == 0 {
 +            tracing::debug!("fuel exhausted");
 +        }
 +        remaining > 0
 +    };
 +
 +    let mut solve = || {
 +        let _ctx = if is_chalk_debug() || is_chalk_print() {
 +            Some(panic_context::enter(format!("solving {:?}", goal)))
 +        } else {
 +            None
 +        };
 +        let solution = if is_chalk_print() {
 +            let logging_db =
 +                LoggingRustIrDatabaseLoggingOnDrop(LoggingRustIrDatabase::new(context));
 +            solver.solve_limited(&logging_db.0, goal, &should_continue)
 +        } else {
 +            solver.solve_limited(&context, goal, &should_continue)
 +        };
 +
 +        tracing::debug!("solve({:?}) => {:?}", goal, solution);
 +
 +        solution
 +    };
 +
 +    // don't set the TLS for Chalk unless Chalk debugging is active, to make
 +    // extra sure we only use it for debugging
 +    if is_chalk_debug() {
 +        crate::tls::set_current_program(db, solve)
 +    } else {
 +        solve()
 +    }
 +}
 +
 +struct LoggingRustIrDatabaseLoggingOnDrop<'a>(LoggingRustIrDatabase<Interner, ChalkContext<'a>>);
 +
 +impl<'a> Drop for LoggingRustIrDatabaseLoggingOnDrop<'a> {
 +    fn drop(&mut self) {
 +        eprintln!("chalk program:\n{}", self.0);
 +    }
 +}
 +
 +fn is_chalk_debug() -> bool {
 +    std::env::var("CHALK_DEBUG").is_ok()
 +}
 +
 +fn is_chalk_print() -> bool {
 +    std::env::var("CHALK_PRINT").is_ok()
 +}
 +
 +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 +pub enum FnTrait {
 +    FnOnce,
 +    FnMut,
 +    Fn,
 +}
 +
 +impl FnTrait {
 +    const fn lang_item_name(self) -> &'static str {
 +        match self {
 +            FnTrait::FnOnce => "fn_once",
 +            FnTrait::FnMut => "fn_mut",
 +            FnTrait::Fn => "fn",
 +        }
 +    }
 +
 +    pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
 +        let target = db.lang_item(krate, SmolStr::new_inline(self.lang_item_name()))?;
 +        match target {
 +            LangItemTarget::TraitId(t) => Some(t),
 +            _ => None,
 +        }
 +    }
 +}
index 8e6a2441b33117c4bf924b3c00d6093eec0709a1,0000000000000000000000000000000000000000..e1418de3cdc24df1169a748178272863b1641565
mode 100644,000000..100644
--- /dev/null
@@@ -1,28 -1,0 +1,28 @@@
- itertools = "0.10.3"
- smallvec = "1.9.0"
- once_cell = "1.12.0"
 +[package]
 +name = "hir"
 +version = "0.0.0"
 +description = "TBD"
 +license = "MIT OR Apache-2.0"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
 +rustc-hash = "1.1.0"
 +either = "1.7.0"
 +arrayvec = "0.7.2"
++itertools = "0.10.5"
++smallvec = "1.10.0"
++once_cell = "1.15.0"
 +
 +stdx = { path = "../stdx", version = "0.0.0" }
 +syntax = { path = "../syntax", version = "0.0.0" }
 +base-db = { path = "../base-db", version = "0.0.0" }
 +profile = { path = "../profile", version = "0.0.0" }
 +hir-expand = { path = "../hir-expand", version = "0.0.0" }
 +hir-def = { path = "../hir-def", version = "0.0.0" }
 +hir-ty = { path = "../hir-ty", version = "0.0.0" }
 +tt = { path = "../tt", version = "0.0.0" }
 +cfg = { path = "../cfg", version = "0.0.0" }
index c5dc60f1ec5f962e319af3c48191fe2769984243,0000000000000000000000000000000000000000..6c8b3088adc0f1c56779c651136d18d06fea5712
mode 100644,000000..100644
--- /dev/null
@@@ -1,172 -1,0 +1,184 @@@
- use hir_def::path::ModPath;
 +//! Re-export diagnostics such that clients of `hir` don't have to depend on
 +//! low-level crates.
 +//!
 +//! This probably isn't the best way to do this -- ideally, diagnostics should
 +//! be expressed in terms of hir types themselves.
 +use base_db::CrateId;
 +use cfg::{CfgExpr, CfgOptions};
 +use either::Either;
++use hir_def::{path::ModPath, TraitId};
 +use hir_expand::{name::Name, HirFileId, InFile};
 +use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
 +
 +use crate::{MacroKind, Type};
 +
 +macro_rules! diagnostics {
 +    ($($diag:ident,)*) => {
 +        #[derive(Debug)]
 +        pub enum AnyDiagnostic {$(
 +            $diag(Box<$diag>),
 +        )*}
 +
 +        $(
 +            impl From<$diag> for AnyDiagnostic {
 +                fn from(d: $diag) -> AnyDiagnostic {
 +                    AnyDiagnostic::$diag(Box::new(d))
 +                }
 +            }
 +        )*
 +    };
 +}
 +
 +diagnostics![
 +    BreakOutsideOfLoop,
 +    InactiveCode,
 +    IncorrectCase,
++    IncorrectTryExpr,
 +    InvalidDeriveTarget,
 +    MacroError,
 +    MalformedDerive,
 +    MismatchedArgCount,
 +    MissingFields,
 +    MissingMatchArms,
 +    MissingUnsafe,
++    NotImplemented,
 +    NoSuchField,
 +    ReplaceFilterMapNextWithFindMap,
 +    TypeMismatch,
 +    UnimplementedBuiltinMacro,
 +    UnresolvedExternCrate,
 +    UnresolvedImport,
 +    UnresolvedMacroCall,
 +    UnresolvedModule,
 +    UnresolvedProcMacro,
 +];
 +
 +#[derive(Debug)]
 +pub struct UnresolvedModule {
 +    pub decl: InFile<AstPtr<ast::Module>>,
 +    pub candidates: Box<[String]>,
 +}
 +
 +#[derive(Debug)]
 +pub struct UnresolvedExternCrate {
 +    pub decl: InFile<AstPtr<ast::ExternCrate>>,
 +}
 +
 +#[derive(Debug)]
 +pub struct UnresolvedImport {
 +    pub decl: InFile<AstPtr<ast::UseTree>>,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct UnresolvedMacroCall {
 +    pub macro_call: InFile<SyntaxNodePtr>,
 +    pub precise_location: Option<TextRange>,
 +    pub path: ModPath,
 +    pub is_bang: bool,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct InactiveCode {
 +    pub node: InFile<SyntaxNodePtr>,
 +    pub cfg: CfgExpr,
 +    pub opts: CfgOptions,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct UnresolvedProcMacro {
 +    pub node: InFile<SyntaxNodePtr>,
 +    /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange`
 +    /// to use instead.
 +    pub precise_location: Option<TextRange>,
 +    pub macro_name: Option<String>,
 +    pub kind: MacroKind,
 +    /// The crate id of the proc-macro this macro belongs to, or `None` if the proc-macro can't be found.
 +    pub krate: CrateId,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct MacroError {
 +    pub node: InFile<SyntaxNodePtr>,
 +    pub precise_location: Option<TextRange>,
 +    pub message: String,
 +}
 +
 +#[derive(Debug)]
 +pub struct UnimplementedBuiltinMacro {
 +    pub node: InFile<SyntaxNodePtr>,
 +}
 +
 +#[derive(Debug)]
 +pub struct InvalidDeriveTarget {
 +    pub node: InFile<SyntaxNodePtr>,
 +}
 +
 +#[derive(Debug)]
 +pub struct MalformedDerive {
 +    pub node: InFile<SyntaxNodePtr>,
 +}
 +
 +#[derive(Debug)]
 +pub struct NoSuchField {
 +    pub field: InFile<AstPtr<ast::RecordExprField>>,
 +}
 +
 +#[derive(Debug)]
 +pub struct BreakOutsideOfLoop {
 +    pub expr: InFile<AstPtr<ast::Expr>>,
 +    pub is_break: bool,
 +}
 +
 +#[derive(Debug)]
 +pub struct MissingUnsafe {
 +    pub expr: InFile<AstPtr<ast::Expr>>,
 +}
 +
 +#[derive(Debug)]
 +pub struct MissingFields {
 +    pub file: HirFileId,
 +    pub field_list_parent: Either<AstPtr<ast::RecordExpr>, AstPtr<ast::RecordPat>>,
 +    pub field_list_parent_path: Option<AstPtr<ast::Path>>,
 +    pub missed_fields: Vec<Name>,
 +}
 +
 +#[derive(Debug)]
 +pub struct ReplaceFilterMapNextWithFindMap {
 +    pub file: HirFileId,
 +    /// This expression is the whole method chain up to and including `.filter_map(..).next()`.
 +    pub next_expr: AstPtr<ast::Expr>,
 +}
 +
 +#[derive(Debug)]
 +pub struct MismatchedArgCount {
 +    pub call_expr: InFile<AstPtr<ast::Expr>>,
 +    pub expected: usize,
 +    pub found: usize,
 +}
++#[derive(Debug)]
++pub struct IncorrectTryExpr {
++    pub expr: InFile<AstPtr<ast::Expr>>,
++}
++#[derive(Debug)]
++pub struct NotImplemented {
++    pub expr: InFile<AstPtr<ast::Expr>>,
++    pub trait_: TraitId,
++    pub ty: Type,
++}
 +
 +#[derive(Debug)]
 +pub struct MissingMatchArms {
 +    pub file: HirFileId,
 +    pub match_expr: AstPtr<ast::Expr>,
 +    pub uncovered_patterns: String,
 +}
 +
 +#[derive(Debug)]
 +pub struct TypeMismatch {
 +    // FIXME: add mismatches in patterns as well
 +    pub expr: InFile<AstPtr<ast::Expr>>,
 +    pub expected: Type,
 +    pub actual: Type,
 +}
 +
 +pub use hir_ty::diagnostics::IncorrectCase;
index f5324208c9a4ef12cf6704f1a9066b11c7378b27,0000000000000000000000000000000000000000..e6c5c6b5833980eaf9f8679fc5945c9ee3ec18dd
mode 100644,000000..100644
--- /dev/null
@@@ -1,3741 -1,0 +1,3757 @@@
-         AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, InvalidDeriveTarget,
-         MacroError, MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms,
-         MissingUnsafe, NoSuchField, ReplaceFilterMapNextWithFindMap, TypeMismatch,
-         UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
-         UnresolvedModule, UnresolvedProcMacro,
 +//! HIR (previously known as descriptors) provides a high-level object oriented
 +//! access to Rust code.
 +//!
 +//! The principal difference between HIR and syntax trees is that HIR is bound
 +//! to a particular crate instance. That is, it has cfg flags and features
 +//! applied. So, the relation between syntax and HIR is many-to-one.
 +//!
 +//! HIR is the public API of the all of the compiler logic above syntax trees.
 +//! It is written in "OO" style. Each type is self contained (as in, it knows it's
 +//! parents and full context). It should be "clean code".
 +//!
 +//! `hir_*` crates are the implementation of the compiler logic.
 +//! They are written in "ECS" style, with relatively little abstractions.
 +//! Many types are not self-contained, and explicitly use local indexes, arenas, etc.
 +//!
 +//! `hir` is what insulates the "we don't know how to actually write an incremental compiler"
 +//! from the ide with completions, hovers, etc. It is a (soft, internal) boundary:
 +//! <https://www.tedinski.com/2018/02/06/system-boundaries.html>.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +#![recursion_limit = "512"]
 +
 +mod semantics;
 +mod source_analyzer;
 +
 +mod from_id;
 +mod attrs;
 +mod has_source;
 +
 +pub mod diagnostics;
 +pub mod db;
 +pub mod symbols;
 +
 +mod display;
 +
 +use std::{iter, ops::ControlFlow, sync::Arc};
 +
 +use arrayvec::ArrayVec;
 +use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind};
 +use either::Either;
 +use hir_def::{
 +    adt::{ReprData, VariantData},
 +    body::{BodyDiagnostic, SyntheticSyntax},
 +    expr::{BindingAnnotation, LabelId, Pat, PatId},
 +    generics::{TypeOrConstParamData, TypeParamProvenance},
 +    item_tree::ItemTreeNode,
 +    lang_item::LangItemTarget,
 +    nameres::{self, diagnostics::DefDiagnostic},
 +    per_ns::PerNs,
 +    resolver::{HasResolver, Resolver},
 +    src::HasSource as _,
 +    AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
 +    EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
 +    LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId,
 +    TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
 +};
 +use hir_expand::{name::name, MacroCallKind};
 +use hir_ty::{
 +    all_super_traits, autoderef,
 +    consteval::{unknown_const_as_generic, ComputedExpr, ConstEvalError, ConstExt},
 +    diagnostics::BodyValidationDiagnostic,
 +    method_resolution::{self, TyFingerprint},
 +    primitive::UintTy,
 +    traits::FnTrait,
 +    AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
 +    GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
 +    TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, WhereClause,
 +};
 +use itertools::Itertools;
 +use nameres::diagnostics::DefDiagnosticKind;
 +use once_cell::unsync::Lazy;
 +use rustc_hash::FxHashSet;
 +use stdx::{impl_from, never};
 +use syntax::{
 +    ast::{self, Expr, HasAttrs as _, HasDocComments, HasName},
 +    AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T,
 +};
 +
 +use crate::db::{DefDatabase, HirDatabase};
 +
 +pub use crate::{
 +    attrs::{HasAttrs, Namespace},
 +    diagnostics::{
-             match d {
++        AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, IncorrectTryExpr,
++        InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, MissingFields,
++        MissingMatchArms, MissingUnsafe, NoSuchField, NotImplemented,
++        ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro,
++        UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, UnresolvedModule,
++        UnresolvedProcMacro,
 +    },
 +    has_source::HasSource,
 +    semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
 +};
 +
 +// Be careful with these re-exports.
 +//
 +// `hir` is the boundary between the compiler and the IDE. It should try hard to
 +// isolate the compiler from the ide, to allow the two to be refactored
 +// independently. Re-exporting something from the compiler is the sure way to
 +// breach the boundary.
 +//
 +// Generally, a refactoring which *removes* a name from this list is a good
 +// idea!
 +pub use {
 +    cfg::{CfgAtom, CfgExpr, CfgOptions},
 +    hir_def::{
 +        adt::StructKind,
 +        attr::{Attr, Attrs, AttrsWithOwner, Documentation},
 +        builtin_attr::AttributeTemplate,
 +        find_path::PrefixKind,
 +        import_map,
 +        nameres::ModuleSource,
 +        path::{ModPath, PathKind},
 +        type_ref::{Mutability, TypeRef},
 +        visibility::Visibility,
 +    },
 +    hir_expand::{
 +        name::{known, Name},
 +        ExpandResult, HirFileId, InFile, MacroFile, Origin,
 +    },
 +    hir_ty::display::HirDisplay,
 +};
 +
 +// These are negative re-exports: pub using these names is forbidden, they
 +// should remain private to hir internals.
 +#[allow(unused)]
 +use {
 +    hir_def::path::Path,
 +    hir_expand::{hygiene::Hygiene, name::AsName},
 +};
 +
 +/// hir::Crate describes a single crate. It's the main interface with which
 +/// a crate's dependencies interact. Mostly, it should be just a proxy for the
 +/// root module.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Crate {
 +    pub(crate) id: CrateId,
 +}
 +
 +#[derive(Debug)]
 +pub struct CrateDependency {
 +    pub krate: Crate,
 +    pub name: Name,
 +}
 +
 +impl Crate {
 +    pub fn origin(self, db: &dyn HirDatabase) -> CrateOrigin {
 +        db.crate_graph()[self.id].origin.clone()
 +    }
 +
 +    pub fn is_builtin(self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.origin(db), CrateOrigin::Lang(_))
 +    }
 +
 +    pub fn dependencies(self, db: &dyn HirDatabase) -> Vec<CrateDependency> {
 +        db.crate_graph()[self.id]
 +            .dependencies
 +            .iter()
 +            .map(|dep| {
 +                let krate = Crate { id: dep.crate_id };
 +                let name = dep.as_name();
 +                CrateDependency { krate, name }
 +            })
 +            .collect()
 +    }
 +
 +    pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec<Crate> {
 +        let crate_graph = db.crate_graph();
 +        crate_graph
 +            .iter()
 +            .filter(|&krate| {
 +                crate_graph[krate].dependencies.iter().any(|it| it.crate_id == self.id)
 +            })
 +            .map(|id| Crate { id })
 +            .collect()
 +    }
 +
 +    pub fn transitive_reverse_dependencies(
 +        self,
 +        db: &dyn HirDatabase,
 +    ) -> impl Iterator<Item = Crate> {
 +        db.crate_graph().transitive_rev_deps(self.id).map(|id| Crate { id })
 +    }
 +
 +    pub fn root_module(self, db: &dyn HirDatabase) -> Module {
 +        let def_map = db.crate_def_map(self.id);
 +        Module { id: def_map.module_id(def_map.root()) }
 +    }
 +
 +    pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> {
 +        let def_map = db.crate_def_map(self.id);
 +        def_map.modules().map(|(id, _)| def_map.module_id(id).into()).collect()
 +    }
 +
 +    pub fn root_file(self, db: &dyn HirDatabase) -> FileId {
 +        db.crate_graph()[self.id].root_file_id
 +    }
 +
 +    pub fn edition(self, db: &dyn HirDatabase) -> Edition {
 +        db.crate_graph()[self.id].edition
 +    }
 +
 +    pub fn version(self, db: &dyn HirDatabase) -> Option<String> {
 +        db.crate_graph()[self.id].version.clone()
 +    }
 +
 +    pub fn display_name(self, db: &dyn HirDatabase) -> Option<CrateDisplayName> {
 +        db.crate_graph()[self.id].display_name.clone()
 +    }
 +
 +    pub fn query_external_importables(
 +        self,
 +        db: &dyn DefDatabase,
 +        query: import_map::Query,
 +    ) -> impl Iterator<Item = Either<ModuleDef, Macro>> {
 +        let _p = profile::span("query_external_importables");
 +        import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| {
 +            match ItemInNs::from(item) {
 +                ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id),
 +                ItemInNs::Macros(mac_id) => Either::Right(mac_id),
 +            }
 +        })
 +    }
 +
 +    pub fn all(db: &dyn HirDatabase) -> Vec<Crate> {
 +        db.crate_graph().iter().map(|id| Crate { id }).collect()
 +    }
 +
 +    /// Try to get the root URL of the documentation of a crate.
 +    pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> {
 +        // Look for #![doc(html_root_url = "...")]
 +        let attrs = db.attrs(AttrDefId::ModuleId(self.root_module(db).into()));
 +        let doc_url = attrs.by_key("doc").find_string_value_in_tt("html_root_url");
 +        doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/")
 +    }
 +
 +    pub fn cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
 +        db.crate_graph()[self.id].cfg_options.clone()
 +    }
 +
 +    pub fn potential_cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
 +        db.crate_graph()[self.id].potential_cfg_options.clone()
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Module {
 +    pub(crate) id: ModuleId,
 +}
 +
 +/// The defs which can be visible in the module.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum ModuleDef {
 +    Module(Module),
 +    Function(Function),
 +    Adt(Adt),
 +    // Can't be directly declared, but can be imported.
 +    Variant(Variant),
 +    Const(Const),
 +    Static(Static),
 +    Trait(Trait),
 +    TypeAlias(TypeAlias),
 +    BuiltinType(BuiltinType),
 +    Macro(Macro),
 +}
 +impl_from!(
 +    Module,
 +    Function,
 +    Adt(Struct, Enum, Union),
 +    Variant,
 +    Const,
 +    Static,
 +    Trait,
 +    TypeAlias,
 +    BuiltinType,
 +    Macro
 +    for ModuleDef
 +);
 +
 +impl From<VariantDef> for ModuleDef {
 +    fn from(var: VariantDef) -> Self {
 +        match var {
 +            VariantDef::Struct(t) => Adt::from(t).into(),
 +            VariantDef::Union(t) => Adt::from(t).into(),
 +            VariantDef::Variant(t) => t.into(),
 +        }
 +    }
 +}
 +
 +impl ModuleDef {
 +    pub fn module(self, db: &dyn HirDatabase) -> Option<Module> {
 +        match self {
 +            ModuleDef::Module(it) => it.parent(db),
 +            ModuleDef::Function(it) => Some(it.module(db)),
 +            ModuleDef::Adt(it) => Some(it.module(db)),
 +            ModuleDef::Variant(it) => Some(it.module(db)),
 +            ModuleDef::Const(it) => Some(it.module(db)),
 +            ModuleDef::Static(it) => Some(it.module(db)),
 +            ModuleDef::Trait(it) => Some(it.module(db)),
 +            ModuleDef::TypeAlias(it) => Some(it.module(db)),
 +            ModuleDef::Macro(it) => Some(it.module(db)),
 +            ModuleDef::BuiltinType(_) => None,
 +        }
 +    }
 +
 +    pub fn canonical_path(&self, db: &dyn HirDatabase) -> Option<String> {
 +        let mut segments = vec![self.name(db)?];
 +        for m in self.module(db)?.path_to_root(db) {
 +            segments.extend(m.name(db))
 +        }
 +        segments.reverse();
 +        Some(segments.into_iter().join("::"))
 +    }
 +
 +    pub fn canonical_module_path(
 +        &self,
 +        db: &dyn HirDatabase,
 +    ) -> Option<impl Iterator<Item = Module>> {
 +        self.module(db).map(|it| it.path_to_root(db).into_iter().rev())
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        let name = match self {
 +            ModuleDef::Module(it) => it.name(db)?,
 +            ModuleDef::Const(it) => it.name(db)?,
 +            ModuleDef::Adt(it) => it.name(db),
 +            ModuleDef::Trait(it) => it.name(db),
 +            ModuleDef::Function(it) => it.name(db),
 +            ModuleDef::Variant(it) => it.name(db),
 +            ModuleDef::TypeAlias(it) => it.name(db),
 +            ModuleDef::Static(it) => it.name(db),
 +            ModuleDef::Macro(it) => it.name(db),
 +            ModuleDef::BuiltinType(it) => it.name(),
 +        };
 +        Some(name)
 +    }
 +
 +    pub fn diagnostics(self, db: &dyn HirDatabase) -> Vec<AnyDiagnostic> {
 +        let id = match self {
 +            ModuleDef::Adt(it) => match it {
 +                Adt::Struct(it) => it.id.into(),
 +                Adt::Enum(it) => it.id.into(),
 +                Adt::Union(it) => it.id.into(),
 +            },
 +            ModuleDef::Trait(it) => it.id.into(),
 +            ModuleDef::Function(it) => it.id.into(),
 +            ModuleDef::TypeAlias(it) => it.id.into(),
 +            ModuleDef::Module(it) => it.id.into(),
 +            ModuleDef::Const(it) => it.id.into(),
 +            ModuleDef::Static(it) => it.id.into(),
 +            ModuleDef::Variant(it) => {
 +                EnumVariantId { parent: it.parent.into(), local_id: it.id }.into()
 +            }
 +            ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => return Vec::new(),
 +        };
 +
 +        let module = match self.module(db) {
 +            Some(it) => it,
 +            None => return Vec::new(),
 +        };
 +
 +        let mut acc = Vec::new();
 +
 +        match self.as_def_with_body() {
 +            Some(def) => {
 +                def.diagnostics(db, &mut acc);
 +            }
 +            None => {
 +                for diag in hir_ty::diagnostics::incorrect_case(db, module.id.krate(), id) {
 +                    acc.push(diag.into())
 +                }
 +            }
 +        }
 +
 +        acc
 +    }
 +
 +    pub fn as_def_with_body(self) -> Option<DefWithBody> {
 +        match self {
 +            ModuleDef::Function(it) => Some(it.into()),
 +            ModuleDef::Const(it) => Some(it.into()),
 +            ModuleDef::Static(it) => Some(it.into()),
 +            ModuleDef::Variant(it) => Some(it.into()),
 +
 +            ModuleDef::Module(_)
 +            | ModuleDef::Adt(_)
 +            | ModuleDef::Trait(_)
 +            | ModuleDef::TypeAlias(_)
 +            | ModuleDef::Macro(_)
 +            | ModuleDef::BuiltinType(_) => None,
 +        }
 +    }
 +
 +    pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
 +        Some(match self {
 +            ModuleDef::Module(it) => it.attrs(db),
 +            ModuleDef::Function(it) => it.attrs(db),
 +            ModuleDef::Adt(it) => it.attrs(db),
 +            ModuleDef::Variant(it) => it.attrs(db),
 +            ModuleDef::Const(it) => it.attrs(db),
 +            ModuleDef::Static(it) => it.attrs(db),
 +            ModuleDef::Trait(it) => it.attrs(db),
 +            ModuleDef::TypeAlias(it) => it.attrs(db),
 +            ModuleDef::Macro(it) => it.attrs(db),
 +            ModuleDef::BuiltinType(_) => return None,
 +        })
 +    }
 +}
 +
 +impl HasVisibility for ModuleDef {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match *self {
 +            ModuleDef::Module(it) => it.visibility(db),
 +            ModuleDef::Function(it) => it.visibility(db),
 +            ModuleDef::Adt(it) => it.visibility(db),
 +            ModuleDef::Const(it) => it.visibility(db),
 +            ModuleDef::Static(it) => it.visibility(db),
 +            ModuleDef::Trait(it) => it.visibility(db),
 +            ModuleDef::TypeAlias(it) => it.visibility(db),
 +            ModuleDef::Variant(it) => it.visibility(db),
 +            ModuleDef::Macro(it) => it.visibility(db),
 +            ModuleDef::BuiltinType(_) => Visibility::Public,
 +        }
 +    }
 +}
 +
 +impl Module {
 +    /// Name of this module.
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        let def_map = self.id.def_map(db.upcast());
 +        let parent = def_map[self.id.local_id].parent?;
 +        def_map[parent].children.iter().find_map(|(name, module_id)| {
 +            if *module_id == self.id.local_id {
 +                Some(name.clone())
 +            } else {
 +                None
 +            }
 +        })
 +    }
 +
 +    /// Returns the crate this module is part of.
 +    pub fn krate(self) -> Crate {
 +        Crate { id: self.id.krate() }
 +    }
 +
 +    /// Topmost parent of this module. Every module has a `crate_root`, but some
 +    /// might be missing `krate`. This can happen if a module's file is not included
 +    /// in the module tree of any target in `Cargo.toml`.
 +    pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
 +        let def_map = db.crate_def_map(self.id.krate());
 +        Module { id: def_map.module_id(def_map.root()) }
 +    }
 +
 +    pub fn is_crate_root(self, db: &dyn HirDatabase) -> bool {
 +        let def_map = db.crate_def_map(self.id.krate());
 +        def_map.root() == self.id.local_id
 +    }
 +
 +    /// Iterates over all child modules.
 +    pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> {
 +        let def_map = self.id.def_map(db.upcast());
 +        let children = def_map[self.id.local_id]
 +            .children
 +            .iter()
 +            .map(|(_, module_id)| Module { id: def_map.module_id(*module_id) })
 +            .collect::<Vec<_>>();
 +        children.into_iter()
 +    }
 +
 +    /// Finds a parent module.
 +    pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> {
 +        // FIXME: handle block expressions as modules (their parent is in a different DefMap)
 +        let def_map = self.id.def_map(db.upcast());
 +        let parent_id = def_map[self.id.local_id].parent?;
 +        Some(Module { id: def_map.module_id(parent_id) })
 +    }
 +
 +    pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> {
 +        let mut res = vec![self];
 +        let mut curr = self;
 +        while let Some(next) = curr.parent(db) {
 +            res.push(next);
 +            curr = next
 +        }
 +        res
 +    }
 +
 +    /// Returns a `ModuleScope`: a set of items, visible in this module.
 +    pub fn scope(
 +        self,
 +        db: &dyn HirDatabase,
 +        visible_from: Option<Module>,
 +    ) -> Vec<(Name, ScopeDef)> {
 +        self.id.def_map(db.upcast())[self.id.local_id]
 +            .scope
 +            .entries()
 +            .filter_map(|(name, def)| {
 +                if let Some(m) = visible_from {
 +                    let filtered =
 +                        def.filter_visibility(|vis| vis.is_visible_from(db.upcast(), m.id));
 +                    if filtered.is_none() && !def.is_none() {
 +                        None
 +                    } else {
 +                        Some((name, filtered))
 +                    }
 +                } else {
 +                    Some((name, def))
 +                }
 +            })
 +            .flat_map(|(name, def)| {
 +                ScopeDef::all_items(def).into_iter().map(move |item| (name.clone(), item))
 +            })
 +            .collect()
 +    }
 +
 +    /// Fills `acc` with the module's diagnostics.
 +    pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
 +        let _p = profile::span("Module::diagnostics").detail(|| {
 +            format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
 +        });
 +        let def_map = self.id.def_map(db.upcast());
 +        for diag in def_map.diagnostics() {
 +            if diag.in_module != self.id.local_id {
 +                // FIXME: This is accidentally quadratic.
 +                continue;
 +            }
 +            emit_def_diagnostic(db, acc, diag);
 +        }
 +        for decl in self.declarations(db) {
 +            match decl {
 +                ModuleDef::Module(m) => {
 +                    // Only add diagnostics from inline modules
 +                    if def_map[m.id.local_id].origin.is_inline() {
 +                        m.diagnostics(db, acc)
 +                    }
 +                }
 +                ModuleDef::Trait(t) => {
 +                    for diag in db.trait_data_with_diagnostics(t.id).1.iter() {
 +                        emit_def_diagnostic(db, acc, diag);
 +                    }
 +                    acc.extend(decl.diagnostics(db))
 +                }
 +                ModuleDef::Adt(adt) => {
 +                    match adt {
 +                        Adt::Struct(s) => {
 +                            for diag in db.struct_data_with_diagnostics(s.id).1.iter() {
 +                                emit_def_diagnostic(db, acc, diag);
 +                            }
 +                        }
 +                        Adt::Union(u) => {
 +                            for diag in db.union_data_with_diagnostics(u.id).1.iter() {
 +                                emit_def_diagnostic(db, acc, diag);
 +                            }
 +                        }
 +                        Adt::Enum(e) => {
 +                            for v in e.variants(db) {
 +                                acc.extend(ModuleDef::Variant(v).diagnostics(db));
 +                            }
 +
 +                            for diag in db.enum_data_with_diagnostics(e.id).1.iter() {
 +                                emit_def_diagnostic(db, acc, diag);
 +                            }
 +                        }
 +                    }
 +                    acc.extend(decl.diagnostics(db))
 +                }
 +                _ => acc.extend(decl.diagnostics(db)),
 +            }
 +        }
 +
 +        for impl_def in self.impl_defs(db) {
 +            for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() {
 +                emit_def_diagnostic(db, acc, diag);
 +            }
 +
 +            for item in impl_def.items(db) {
 +                let def: DefWithBody = match item {
 +                    AssocItem::Function(it) => it.into(),
 +                    AssocItem::Const(it) => it.into(),
 +                    AssocItem::TypeAlias(_) => continue,
 +                };
 +
 +                def.diagnostics(db, acc);
 +            }
 +        }
 +    }
 +
 +    pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> {
 +        let def_map = self.id.def_map(db.upcast());
 +        let scope = &def_map[self.id.local_id].scope;
 +        scope
 +            .declarations()
 +            .map(ModuleDef::from)
 +            .chain(scope.unnamed_consts().map(|id| ModuleDef::Const(Const::from(id))))
 +            .collect()
 +    }
 +
 +    pub fn legacy_macros(self, db: &dyn HirDatabase) -> Vec<Macro> {
 +        let def_map = self.id.def_map(db.upcast());
 +        let scope = &def_map[self.id.local_id].scope;
 +        scope.legacy_macros().flat_map(|(_, it)| it).map(|&it| MacroId::from(it).into()).collect()
 +    }
 +
 +    pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> {
 +        let def_map = self.id.def_map(db.upcast());
 +        def_map[self.id.local_id].scope.impls().map(Impl::from).collect()
 +    }
 +
 +    /// Finds a path that can be used to refer to the given item from within
 +    /// this module, if possible.
 +    pub fn find_use_path(
 +        self,
 +        db: &dyn DefDatabase,
 +        item: impl Into<ItemInNs>,
 +        prefer_no_std: bool,
 +    ) -> Option<ModPath> {
 +        hir_def::find_path::find_path(db, item.into().into(), self.into(), prefer_no_std)
 +    }
 +
 +    /// Finds a path that can be used to refer to the given item from within
 +    /// this module, if possible. This is used for returning import paths for use-statements.
 +    pub fn find_use_path_prefixed(
 +        self,
 +        db: &dyn DefDatabase,
 +        item: impl Into<ItemInNs>,
 +        prefix_kind: PrefixKind,
 +        prefer_no_std: bool,
 +    ) -> Option<ModPath> {
 +        hir_def::find_path::find_path_prefixed(
 +            db,
 +            item.into().into(),
 +            self.into(),
 +            prefix_kind,
 +            prefer_no_std,
 +        )
 +    }
 +}
 +
 +fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: &DefDiagnostic) {
 +    match &diag.kind {
 +        DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => {
 +            let decl = declaration.to_node(db.upcast());
 +            acc.push(
 +                UnresolvedModule {
 +                    decl: InFile::new(declaration.file_id, AstPtr::new(&decl)),
 +                    candidates: candidates.clone(),
 +                }
 +                .into(),
 +            )
 +        }
 +        DefDiagnosticKind::UnresolvedExternCrate { ast } => {
 +            let item = ast.to_node(db.upcast());
 +            acc.push(
 +                UnresolvedExternCrate { decl: InFile::new(ast.file_id, AstPtr::new(&item)) }.into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnresolvedImport { id, index } => {
 +            let file_id = id.file_id();
 +            let item_tree = id.item_tree(db.upcast());
 +            let import = &item_tree[id.value];
 +
 +            let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index);
 +            acc.push(
 +                UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }.into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
 +            let item = ast.to_node(db.upcast());
 +            acc.push(
 +                InactiveCode {
 +                    node: ast.with_value(AstPtr::new(&item).into()),
 +                    cfg: cfg.clone(),
 +                    opts: opts.clone(),
 +                }
 +                .into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnresolvedProcMacro { ast, krate } => {
 +            let (node, precise_location, macro_name, kind) = precise_macro_call_location(ast, db);
 +            acc.push(
 +                UnresolvedProcMacro { node, precise_location, macro_name, kind, krate: *krate }
 +                    .into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
 +            let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
 +            acc.push(
 +                UnresolvedMacroCall {
 +                    macro_call: node,
 +                    precise_location,
 +                    path: path.clone(),
 +                    is_bang: matches!(ast, MacroCallKind::FnLike { .. }),
 +                }
 +                .into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::MacroError { ast, message } => {
 +            let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
 +            acc.push(MacroError { node, precise_location, message: message.clone() }.into());
 +        }
 +
 +        DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
 +            let node = ast.to_node(db.upcast());
 +            // Must have a name, otherwise we wouldn't emit it.
 +            let name = node.name().expect("unimplemented builtin macro with no name");
 +            acc.push(
 +                UnimplementedBuiltinMacro {
 +                    node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&name))),
 +                }
 +                .into(),
 +            );
 +        }
 +        DefDiagnosticKind::InvalidDeriveTarget { ast, id } => {
 +            let node = ast.to_node(db.upcast());
 +            let derive = node.attrs().nth(*id as usize);
 +            match derive {
 +                Some(derive) => {
 +                    acc.push(
 +                        InvalidDeriveTarget {
 +                            node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
 +                        }
 +                        .into(),
 +                    );
 +                }
 +                None => stdx::never!("derive diagnostic on item without derive attribute"),
 +            }
 +        }
 +        DefDiagnosticKind::MalformedDerive { ast, id } => {
 +            let node = ast.to_node(db.upcast());
 +            let derive = node.attrs().nth(*id as usize);
 +            match derive {
 +                Some(derive) => {
 +                    acc.push(
 +                        MalformedDerive {
 +                            node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
 +                        }
 +                        .into(),
 +                    );
 +                }
 +                None => stdx::never!("derive diagnostic on item without derive attribute"),
 +            }
 +        }
 +    }
 +}
 +
 +fn precise_macro_call_location(
 +    ast: &MacroCallKind,
 +    db: &dyn HirDatabase,
 +) -> (InFile<SyntaxNodePtr>, Option<TextRange>, Option<String>, MacroKind) {
 +    // FIXME: maaybe we actually want slightly different ranges for the different macro diagnostics
 +    // - e.g. the full attribute for macro errors, but only the name for name resolution
 +    match ast {
 +        MacroCallKind::FnLike { ast_id, .. } => {
 +            let node = ast_id.to_node(db.upcast());
 +            (
 +                ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
 +                node.path()
 +                    .and_then(|it| it.segment())
 +                    .and_then(|it| it.name_ref())
 +                    .map(|it| it.syntax().text_range()),
 +                node.path().and_then(|it| it.segment()).map(|it| it.to_string()),
 +                MacroKind::ProcMacro,
 +            )
 +        }
 +        MacroCallKind::Derive { ast_id, derive_attr_index, derive_index } => {
 +            let node = ast_id.to_node(db.upcast());
 +            // Compute the precise location of the macro name's token in the derive
 +            // list.
 +            let token = (|| {
 +                let derive_attr = node
 +                    .doc_comments_and_attrs()
 +                    .nth(*derive_attr_index as usize)
 +                    .and_then(Either::left)?;
 +                let token_tree = derive_attr.meta()?.token_tree()?;
 +                let group_by = token_tree
 +                    .syntax()
 +                    .children_with_tokens()
 +                    .filter_map(|elem| match elem {
 +                        syntax::NodeOrToken::Token(tok) => Some(tok),
 +                        _ => None,
 +                    })
 +                    .group_by(|t| t.kind() == T![,]);
 +                let (_, mut group) = group_by
 +                    .into_iter()
 +                    .filter(|&(comma, _)| !comma)
 +                    .nth(*derive_index as usize)?;
 +                group.find(|t| t.kind() == T![ident])
 +            })();
 +            (
 +                ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
 +                token.as_ref().map(|tok| tok.text_range()),
 +                token.as_ref().map(ToString::to_string),
 +                MacroKind::Derive,
 +            )
 +        }
 +        MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
 +            let node = ast_id.to_node(db.upcast());
 +            let attr = node
 +                .doc_comments_and_attrs()
 +                .nth((*invoc_attr_index) as usize)
 +                .and_then(Either::left)
 +                .unwrap_or_else(|| panic!("cannot find attribute #{}", invoc_attr_index));
 +
 +            (
 +                ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))),
 +                Some(attr.syntax().text_range()),
 +                attr.path()
 +                    .and_then(|path| path.segment())
 +                    .and_then(|seg| seg.name_ref())
 +                    .as_ref()
 +                    .map(ToString::to_string),
 +                MacroKind::Attr,
 +            )
 +        }
 +    }
 +}
 +
 +impl HasVisibility for Module {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        let def_map = self.id.def_map(db.upcast());
 +        let module_data = &def_map[self.id.local_id];
 +        module_data.visibility
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Field {
 +    pub(crate) parent: VariantDef,
 +    pub(crate) id: LocalFieldId,
 +}
 +
 +#[derive(Debug, PartialEq, Eq)]
 +pub enum FieldSource {
 +    Named(ast::RecordField),
 +    Pos(ast::TupleField),
 +}
 +
 +impl Field {
 +    pub fn name(&self, db: &dyn HirDatabase) -> Name {
 +        self.parent.variant_data(db).fields()[self.id].name.clone()
 +    }
 +
 +    /// Returns the type as in the signature of the struct (i.e., with
 +    /// placeholder types for type parameters). Only use this in the context of
 +    /// the field definition.
 +    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
 +        let var_id = self.parent.into();
 +        let generic_def_id: GenericDefId = match self.parent {
 +            VariantDef::Struct(it) => it.id.into(),
 +            VariantDef::Union(it) => it.id.into(),
 +            VariantDef::Variant(it) => it.parent.id.into(),
 +        };
 +        let substs = TyBuilder::placeholder_subst(db, generic_def_id);
 +        let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
 +        Type::new(db, var_id, ty)
 +    }
 +
 +    pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
 +        self.parent
 +    }
 +}
 +
 +impl HasVisibility for Field {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        let variant_data = self.parent.variant_data(db);
 +        let visibility = &variant_data.fields()[self.id].visibility;
 +        let parent_id: hir_def::VariantId = self.parent.into();
 +        visibility.resolve(db.upcast(), &parent_id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Struct {
 +    pub(crate) id: StructId,
 +}
 +
 +impl Struct {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.struct_data(self.id).name.clone()
 +    }
 +
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        db.struct_data(self.id)
 +            .variant_data
 +            .fields()
 +            .iter()
 +            .map(|(id, _)| Field { parent: self.into(), id })
 +            .collect()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +
 +    pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprData> {
 +        db.struct_data(self.id).repr.clone()
 +    }
 +
 +    pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
 +        self.variant_data(db).kind()
 +    }
 +
 +    fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        db.struct_data(self.id).variant_data.clone()
 +    }
 +}
 +
 +impl HasVisibility for Struct {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.struct_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Union {
 +    pub(crate) id: UnionId,
 +}
 +
 +impl Union {
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.union_data(self.id).name.clone()
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        db.union_data(self.id)
 +            .variant_data
 +            .fields()
 +            .iter()
 +            .map(|(id, _)| Field { parent: self.into(), id })
 +            .collect()
 +    }
 +
 +    fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        db.union_data(self.id).variant_data.clone()
 +    }
 +}
 +
 +impl HasVisibility for Union {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.union_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Enum {
 +    pub(crate) id: EnumId,
 +}
 +
 +impl Enum {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.enum_data(self.id).name.clone()
 +    }
 +
 +    pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> {
 +        db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +
 +    /// The type of the enum variant bodies.
 +    pub fn variant_body_ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::new_for_crate(
 +            self.id.lookup(db.upcast()).container.krate(),
 +            TyBuilder::builtin(match db.enum_data(self.id).variant_body_type() {
 +                Either::Left(builtin) => hir_def::builtin_type::BuiltinType::Int(builtin),
 +                Either::Right(builtin) => hir_def::builtin_type::BuiltinType::Uint(builtin),
 +            }),
 +        )
 +    }
 +
 +    pub fn is_data_carrying(self, db: &dyn HirDatabase) -> bool {
 +        self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit))
 +    }
 +}
 +
 +impl HasVisibility for Enum {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.enum_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +impl From<&Variant> for DefWithBodyId {
 +    fn from(&v: &Variant) -> Self {
 +        DefWithBodyId::VariantId(v.into())
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Variant {
 +    pub(crate) parent: Enum,
 +    pub(crate) id: LocalEnumVariantId,
 +}
 +
 +impl Variant {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.parent.module(db)
 +    }
 +
 +    pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum {
 +        self.parent
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.enum_data(self.parent.id).variants[self.id].name.clone()
 +    }
 +
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        self.variant_data(db)
 +            .fields()
 +            .iter()
 +            .map(|(id, _)| Field { parent: self.into(), id })
 +            .collect()
 +    }
 +
 +    pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
 +        self.variant_data(db).kind()
 +    }
 +
 +    pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
 +    }
 +
 +    pub fn value(self, db: &dyn HirDatabase) -> Option<Expr> {
 +        self.source(db)?.value.expr()
 +    }
 +
 +    pub fn eval(self, db: &dyn HirDatabase) -> Result<ComputedExpr, ConstEvalError> {
 +        db.const_eval_variant(self.into())
 +    }
 +}
 +
 +/// Variants inherit visibility from the parent enum.
 +impl HasVisibility for Variant {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        self.parent_enum(db).visibility(db)
 +    }
 +}
 +
 +/// A Data Type
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum Adt {
 +    Struct(Struct),
 +    Union(Union),
 +    Enum(Enum),
 +}
 +impl_from!(Struct, Union, Enum for Adt);
 +
 +impl Adt {
 +    pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
 +        let subst = db.generic_defaults(self.into());
 +        subst.iter().any(|ty| match ty.skip_binders().data(Interner) {
 +            GenericArgData::Ty(x) => x.is_unknown(),
 +            _ => false,
 +        })
 +    }
 +
 +    /// Turns this ADT into a type. Any type parameters of the ADT will be
 +    /// turned into unknown types, which is good for e.g. finding the most
 +    /// general set of completions, but will not look very nice when printed.
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let id = AdtId::from(self);
 +        Type::from_def(db, id)
 +    }
 +
 +    /// Turns this ADT into a type with the given type parameters. This isn't
 +    /// the greatest API, FIXME find a better one.
 +    pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type {
 +        let id = AdtId::from(self);
 +        let mut it = args.iter().map(|t| t.ty.clone());
 +        let ty = TyBuilder::def_ty(db, id.into(), None)
 +            .fill(|x| {
 +                let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
 +                match x {
 +                    ParamKind::Type => GenericArgData::Ty(r).intern(Interner),
 +                    ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
 +                }
 +            })
 +            .build();
 +        Type::new(db, id, ty)
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            Adt::Struct(s) => s.module(db),
 +            Adt::Union(s) => s.module(db),
 +            Adt::Enum(e) => e.module(db),
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        match self {
 +            Adt::Struct(s) => s.name(db),
 +            Adt::Union(u) => u.name(db),
 +            Adt::Enum(e) => e.name(db),
 +        }
 +    }
 +
 +    pub fn as_enum(&self) -> Option<Enum> {
 +        if let Self::Enum(v) = self {
 +            Some(*v)
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +impl HasVisibility for Adt {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match self {
 +            Adt::Struct(it) => it.visibility(db),
 +            Adt::Union(it) => it.visibility(db),
 +            Adt::Enum(it) => it.visibility(db),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum VariantDef {
 +    Struct(Struct),
 +    Union(Union),
 +    Variant(Variant),
 +}
 +impl_from!(Struct, Union, Variant for VariantDef);
 +
 +impl VariantDef {
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        match self {
 +            VariantDef::Struct(it) => it.fields(db),
 +            VariantDef::Union(it) => it.fields(db),
 +            VariantDef::Variant(it) => it.fields(db),
 +        }
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            VariantDef::Struct(it) => it.module(db),
 +            VariantDef::Union(it) => it.module(db),
 +            VariantDef::Variant(it) => it.module(db),
 +        }
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> Name {
 +        match self {
 +            VariantDef::Struct(s) => s.name(db),
 +            VariantDef::Union(u) => u.name(db),
 +            VariantDef::Variant(e) => e.name(db),
 +        }
 +    }
 +
 +    pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        match self {
 +            VariantDef::Struct(it) => it.variant_data(db),
 +            VariantDef::Union(it) => it.variant_data(db),
 +            VariantDef::Variant(it) => it.variant_data(db),
 +        }
 +    }
 +}
 +
 +/// The defs which have a body.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum DefWithBody {
 +    Function(Function),
 +    Static(Static),
 +    Const(Const),
 +    Variant(Variant),
 +}
 +impl_from!(Function, Const, Static, Variant for DefWithBody);
 +
 +impl DefWithBody {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            DefWithBody::Const(c) => c.module(db),
 +            DefWithBody::Function(f) => f.module(db),
 +            DefWithBody::Static(s) => s.module(db),
 +            DefWithBody::Variant(v) => v.module(db),
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        match self {
 +            DefWithBody::Function(f) => Some(f.name(db)),
 +            DefWithBody::Static(s) => Some(s.name(db)),
 +            DefWithBody::Const(c) => c.name(db),
 +            DefWithBody::Variant(v) => Some(v.name(db)),
 +        }
 +    }
 +
 +    /// Returns the type this def's body has to evaluate to.
 +    pub fn body_type(self, db: &dyn HirDatabase) -> Type {
 +        match self {
 +            DefWithBody::Function(it) => it.ret_type(db),
 +            DefWithBody::Static(it) => it.ty(db),
 +            DefWithBody::Const(it) => it.ty(db),
 +            DefWithBody::Variant(it) => it.parent.variant_body_ty(db),
 +        }
 +    }
 +
 +    fn id(&self) -> DefWithBodyId {
 +        match self {
 +            DefWithBody::Function(it) => it.id.into(),
 +            DefWithBody::Static(it) => it.id.into(),
 +            DefWithBody::Const(it) => it.id.into(),
 +            DefWithBody::Variant(it) => it.into(),
 +        }
 +    }
 +
 +    /// A textual representation of the HIR of this def's body for debugging purposes.
 +    pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
 +        let body = db.body(self.id());
 +        body.pretty_print(db.upcast(), self.id())
 +    }
 +
 +    pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
 +        let krate = self.module(db).id.krate();
 +
 +        let (body, source_map) = db.body_with_source_map(self.into());
 +
 +        for (_, def_map) in body.blocks(db.upcast()) {
 +            for diag in def_map.diagnostics() {
 +                emit_def_diagnostic(db, acc, diag);
 +            }
 +        }
 +
 +        for diag in source_map.diagnostics() {
 +            match diag {
 +                BodyDiagnostic::InactiveCode { node, cfg, opts } => acc.push(
 +                    InactiveCode { node: node.clone(), cfg: cfg.clone(), opts: opts.clone() }
 +                        .into(),
 +                ),
 +                BodyDiagnostic::MacroError { node, message } => acc.push(
 +                    MacroError {
 +                        node: node.clone().map(|it| it.into()),
 +                        precise_location: None,
 +                        message: message.to_string(),
 +                    }
 +                    .into(),
 +                ),
 +                BodyDiagnostic::UnresolvedProcMacro { node, krate } => acc.push(
 +                    UnresolvedProcMacro {
 +                        node: node.clone().map(|it| it.into()),
 +                        precise_location: None,
 +                        macro_name: None,
 +                        kind: MacroKind::ProcMacro,
 +                        krate: *krate,
 +                    }
 +                    .into(),
 +                ),
 +                BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push(
 +                    UnresolvedMacroCall {
 +                        macro_call: node.clone().map(|ast_ptr| ast_ptr.into()),
 +                        precise_location: None,
 +                        path: path.clone(),
 +                        is_bang: true,
 +                    }
 +                    .into(),
 +                ),
 +            }
 +        }
 +
 +        let infer = db.infer(self.into());
 +        let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1);
 +        for d in &infer.diagnostics {
-                     let field = source_map.field_syntax(*expr);
++            match *d {
 +                hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
-                 &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
++                    let field = source_map.field_syntax(expr);
 +                    acc.push(NoSuchField { field }.into())
 +                }
-                     match source_map.expr_syntax(*call_expr) {
++                hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
 +                    let expr = source_map
 +                        .expr_syntax(expr)
 +                        .expect("break outside of loop in synthetic syntax");
 +                    acc.push(BreakOutsideOfLoop { expr, is_break }.into())
 +                }
 +                hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
-                                 expected: *expected,
-                                 found: *found,
++                    match source_map.expr_syntax(call_expr) {
 +                        Ok(source_ptr) => acc.push(
 +                            MismatchedArgCount {
 +                                call_expr: source_ptr,
++                                expected: expected,
++                                found: found,
 +                            }
 +                            .into(),
 +                        ),
 +                        Err(SyntheticSyntax) => (),
 +                    }
 +                }
++                hir_ty::InferenceDiagnostic::IncorrectTryTarget { expr } => {
++                    let expr = source_map.expr_syntax(expr).expect("try in synthetic syntax");
++                    acc.push(IncorrectTryExpr { expr }.into())
++                }
++                hir_ty::InferenceDiagnostic::DoesNotImplement { expr, trait_, ref ty } => {
++                    let expr = source_map.expr_syntax(expr).expect("try in synthetic syntax");
++                    acc.push(
++                        NotImplemented {
++                            expr,
++                            trait_,
++                            ty: Type::new(db, DefWithBodyId::from(self), ty.clone()),
++                        }
++                        .into(),
++                    )
++                }
 +            }
 +        }
 +        for (expr, mismatch) in infer.expr_type_mismatches() {
 +            let expr = match source_map.expr_syntax(expr) {
 +                Ok(expr) => expr,
 +                Err(SyntheticSyntax) => continue,
 +            };
 +            acc.push(
 +                TypeMismatch {
 +                    expr,
 +                    expected: Type::new(db, DefWithBodyId::from(self), mismatch.expected.clone()),
 +                    actual: Type::new(db, DefWithBodyId::from(self), mismatch.actual.clone()),
 +                }
 +                .into(),
 +            );
 +        }
 +
 +        for expr in hir_ty::diagnostics::missing_unsafe(db, self.into()) {
 +            match source_map.expr_syntax(expr) {
 +                Ok(expr) => acc.push(MissingUnsafe { expr }.into()),
 +                Err(SyntheticSyntax) => {
 +                    // FIXME: Here and eslwhere in this file, the `expr` was
 +                    // desugared, report or assert that this doesn't happen.
 +                }
 +            }
 +        }
 +
 +        for diagnostic in BodyValidationDiagnostic::collect(db, self.into()) {
 +            match diagnostic {
 +                BodyValidationDiagnostic::RecordMissingFields {
 +                    record,
 +                    variant,
 +                    missed_fields,
 +                } => {
 +                    let variant_data = variant.variant_data(db.upcast());
 +                    let missed_fields = missed_fields
 +                        .into_iter()
 +                        .map(|idx| variant_data.fields()[idx].name.clone())
 +                        .collect();
 +
 +                    match record {
 +                        Either::Left(record_expr) => match source_map.expr_syntax(record_expr) {
 +                            Ok(source_ptr) => {
 +                                let root = source_ptr.file_syntax(db.upcast());
 +                                if let ast::Expr::RecordExpr(record_expr) =
 +                                    &source_ptr.value.to_node(&root)
 +                                {
 +                                    if record_expr.record_expr_field_list().is_some() {
 +                                        acc.push(
 +                                            MissingFields {
 +                                                file: source_ptr.file_id,
 +                                                field_list_parent: Either::Left(AstPtr::new(
 +                                                    record_expr,
 +                                                )),
 +                                                field_list_parent_path: record_expr
 +                                                    .path()
 +                                                    .map(|path| AstPtr::new(&path)),
 +                                                missed_fields,
 +                                            }
 +                                            .into(),
 +                                        )
 +                                    }
 +                                }
 +                            }
 +                            Err(SyntheticSyntax) => (),
 +                        },
 +                        Either::Right(record_pat) => match source_map.pat_syntax(record_pat) {
 +                            Ok(source_ptr) => {
 +                                if let Some(expr) = source_ptr.value.as_ref().left() {
 +                                    let root = source_ptr.file_syntax(db.upcast());
 +                                    if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) {
 +                                        if record_pat.record_pat_field_list().is_some() {
 +                                            acc.push(
 +                                                MissingFields {
 +                                                    file: source_ptr.file_id,
 +                                                    field_list_parent: Either::Right(AstPtr::new(
 +                                                        &record_pat,
 +                                                    )),
 +                                                    field_list_parent_path: record_pat
 +                                                        .path()
 +                                                        .map(|path| AstPtr::new(&path)),
 +                                                    missed_fields,
 +                                                }
 +                                                .into(),
 +                                            )
 +                                        }
 +                                    }
 +                                }
 +                            }
 +                            Err(SyntheticSyntax) => (),
 +                        },
 +                    }
 +                }
 +                BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => {
 +                    if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) {
 +                        acc.push(
 +                            ReplaceFilterMapNextWithFindMap {
 +                                file: next_source_ptr.file_id,
 +                                next_expr: next_source_ptr.value,
 +                            }
 +                            .into(),
 +                        );
 +                    }
 +                }
 +                BodyValidationDiagnostic::MissingMatchArms { match_expr, uncovered_patterns } => {
 +                    match source_map.expr_syntax(match_expr) {
 +                        Ok(source_ptr) => {
 +                            let root = source_ptr.file_syntax(db.upcast());
 +                            if let ast::Expr::MatchExpr(match_expr) =
 +                                &source_ptr.value.to_node(&root)
 +                            {
 +                                if let Some(match_expr) = match_expr.expr() {
 +                                    acc.push(
 +                                        MissingMatchArms {
 +                                            file: source_ptr.file_id,
 +                                            match_expr: AstPtr::new(&match_expr),
 +                                            uncovered_patterns,
 +                                        }
 +                                        .into(),
 +                                    );
 +                                }
 +                            }
 +                        }
 +                        Err(SyntheticSyntax) => (),
 +                    }
 +                }
 +            }
 +        }
 +
 +        let def: ModuleDef = match self {
 +            DefWithBody::Function(it) => it.into(),
 +            DefWithBody::Static(it) => it.into(),
 +            DefWithBody::Const(it) => it.into(),
 +            DefWithBody::Variant(it) => it.into(),
 +        };
 +        for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) {
 +            acc.push(diag.into())
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Function {
 +    pub(crate) id: FunctionId,
 +}
 +
 +impl Function {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.lookup(db.upcast()).module(db.upcast()).into()
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.function_data(self.id).name.clone()
 +    }
 +
 +    /// Get this function's return type
 +    pub fn ret_type(self, db: &dyn HirDatabase) -> Type {
 +        let resolver = self.id.resolver(db.upcast());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        let ty = callable_sig.ret().clone();
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    pub fn async_ret_type(self, db: &dyn HirDatabase) -> Option<Type> {
 +        if !self.is_async(db) {
 +            return None;
 +        }
 +        let resolver = self.id.resolver(db.upcast());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        let ret_ty = callable_sig.ret().clone();
 +        for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() {
 +            if let WhereClause::AliasEq(output_eq) = pred.into_value_and_skipped_binders().0 {
 +                return Type::new_with_resolver_inner(db, &resolver, output_eq.ty).into();
 +            }
 +        }
 +        never!("Async fn ret_type should be impl Future");
 +        None
 +    }
 +
 +    pub fn has_self_param(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_self_param()
 +    }
 +
 +    pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
 +        self.has_self_param(db).then(|| SelfParam { func: self.id })
 +    }
 +
 +    pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> {
 +        let environment = db.trait_environment(self.id.into());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        callable_sig
 +            .params()
 +            .iter()
 +            .enumerate()
 +            .map(|(idx, ty)| {
 +                let ty = Type { env: environment.clone(), ty: ty.clone() };
 +                Param { func: self, ty, idx }
 +            })
 +            .collect()
 +    }
 +
 +    pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> {
 +        if self.self_param(db).is_none() {
 +            return None;
 +        }
 +        Some(self.params_without_self(db))
 +    }
 +
 +    pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param> {
 +        let environment = db.trait_environment(self.id.into());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        let skip = if db.function_data(self.id).has_self_param() { 1 } else { 0 };
 +        callable_sig
 +            .params()
 +            .iter()
 +            .enumerate()
 +            .skip(skip)
 +            .map(|(idx, ty)| {
 +                let ty = Type { env: environment.clone(), ty: ty.clone() };
 +                Param { func: self, ty, idx }
 +            })
 +            .collect()
 +    }
 +
 +    pub fn is_const(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_const_kw()
 +    }
 +
 +    pub fn is_async(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_async_kw()
 +    }
 +
 +    pub fn is_unsafe_to_call(self, db: &dyn HirDatabase) -> bool {
 +        hir_ty::is_fn_unsafe_to_call(db, self.id)
 +    }
 +
 +    /// Whether this function declaration has a definition.
 +    ///
 +    /// This is false in the case of required (not provided) trait methods.
 +    pub fn has_body(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_body()
 +    }
 +
 +    pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> {
 +        let function_data = db.function_data(self.id);
 +        let attrs = &function_data.attrs;
 +        // FIXME: Store this in FunctionData flags?
 +        if !(attrs.is_proc_macro()
 +            || attrs.is_proc_macro_attribute()
 +            || attrs.is_proc_macro_derive())
 +        {
 +            return None;
 +        }
 +        let loc = self.id.lookup(db.upcast());
 +        let def_map = db.crate_def_map(loc.krate(db).into());
 +        def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() })
 +    }
 +}
 +
 +// Note: logically, this belongs to `hir_ty`, but we are not using it there yet.
 +#[derive(Clone, Copy, PartialEq, Eq)]
 +pub enum Access {
 +    Shared,
 +    Exclusive,
 +    Owned,
 +}
 +
 +impl From<hir_ty::Mutability> for Access {
 +    fn from(mutability: hir_ty::Mutability) -> Access {
 +        match mutability {
 +            hir_ty::Mutability::Not => Access::Shared,
 +            hir_ty::Mutability::Mut => Access::Exclusive,
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Debug)]
 +pub struct Param {
 +    func: Function,
 +    /// The index in parameter list, including self parameter.
 +    idx: usize,
 +    ty: Type,
 +}
 +
 +impl Param {
 +    pub fn ty(&self) -> &Type {
 +        &self.ty
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
 +        db.function_data(self.func.id).params[self.idx].0.clone()
 +    }
 +
 +    pub fn as_local(&self, db: &dyn HirDatabase) -> Option<Local> {
 +        let parent = DefWithBodyId::FunctionId(self.func.into());
 +        let body = db.body(parent);
 +        let pat_id = body.params[self.idx];
 +        if let Pat::Bind { .. } = &body[pat_id] {
 +            Some(Local { parent, pat_id: body.params[self.idx] })
 +        } else {
 +            None
 +        }
 +    }
 +
 +    pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option<ast::Pat> {
 +        self.source(db).and_then(|p| p.value.pat())
 +    }
 +
 +    pub fn source(&self, db: &dyn HirDatabase) -> Option<InFile<ast::Param>> {
 +        let InFile { file_id, value } = self.func.source(db)?;
 +        let params = value.param_list()?;
 +        if params.self_param().is_some() {
 +            params.params().nth(self.idx.checked_sub(1)?)
 +        } else {
 +            params.params().nth(self.idx)
 +        }
 +        .map(|value| InFile { file_id, value })
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct SelfParam {
 +    func: FunctionId,
 +}
 +
 +impl SelfParam {
 +    pub fn access(self, db: &dyn HirDatabase) -> Access {
 +        let func_data = db.function_data(self.func);
 +        func_data
 +            .params
 +            .first()
 +            .map(|(_, param)| match &**param {
 +                TypeRef::Reference(.., mutability) => match mutability {
 +                    hir_def::type_ref::Mutability::Shared => Access::Shared,
 +                    hir_def::type_ref::Mutability::Mut => Access::Exclusive,
 +                },
 +                _ => Access::Owned,
 +            })
 +            .unwrap_or(Access::Owned)
 +    }
 +
 +    pub fn display(self, db: &dyn HirDatabase) -> &'static str {
 +        match self.access(db) {
 +            Access::Shared => "&self",
 +            Access::Exclusive => "&mut self",
 +            Access::Owned => "self",
 +        }
 +    }
 +
 +    pub fn source(&self, db: &dyn HirDatabase) -> Option<InFile<ast::SelfParam>> {
 +        let InFile { file_id, value } = Function::from(self.func).source(db)?;
 +        value
 +            .param_list()
 +            .and_then(|params| params.self_param())
 +            .map(|value| InFile { file_id, value })
 +    }
 +
 +    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
 +        let substs = TyBuilder::placeholder_subst(db, self.func);
 +        let callable_sig =
 +            db.callable_item_signature(self.func.into()).substitute(Interner, &substs);
 +        let environment = db.trait_environment(self.func.into());
 +        let ty = callable_sig.params()[0].clone();
 +        Type { env: environment, ty }
 +    }
 +}
 +
 +impl HasVisibility for Function {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.function_visibility(self.id)
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Const {
 +    pub(crate) id: ConstId,
 +}
 +
 +impl Const {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        db.const_data(self.id).name.clone()
 +    }
 +
 +    pub fn value(self, db: &dyn HirDatabase) -> Option<ast::Expr> {
 +        self.source(db)?.value.body()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let data = db.const_data(self.id);
 +        let resolver = self.id.resolver(db.upcast());
 +        let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
 +        let ty = ctx.lower_ty(&data.type_ref);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    pub fn eval(self, db: &dyn HirDatabase) -> Result<ComputedExpr, ConstEvalError> {
 +        db.const_eval(self.id)
 +    }
 +}
 +
 +impl HasVisibility for Const {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.const_visibility(self.id)
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Static {
 +    pub(crate) id: StaticId,
 +}
 +
 +impl Static {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.static_data(self.id).name.clone()
 +    }
 +
 +    pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
 +        db.static_data(self.id).mutable
 +    }
 +
 +    pub fn value(self, db: &dyn HirDatabase) -> Option<ast::Expr> {
 +        self.source(db)?.value.body()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let data = db.static_data(self.id);
 +        let resolver = self.id.resolver(db.upcast());
 +        let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
 +        let ty = ctx.lower_ty(&data.type_ref);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +}
 +
 +impl HasVisibility for Static {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.static_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Trait {
 +    pub(crate) id: TraitId,
 +}
 +
 +impl Trait {
 +    pub fn lang(db: &dyn HirDatabase, krate: Crate, name: &Name) -> Option<Trait> {
 +        db.lang_item(krate.into(), name.to_smol_str())
 +            .and_then(LangItemTarget::as_trait)
 +            .map(Into::into)
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.trait_data(self.id).name.clone()
 +    }
 +
 +    pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
 +        db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
 +    }
 +
 +    pub fn items_with_supertraits(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
 +        let traits = all_super_traits(db.upcast(), self.into());
 +        traits.iter().flat_map(|tr| Trait::from(*tr).items(db)).collect()
 +    }
 +
 +    pub fn is_auto(self, db: &dyn HirDatabase) -> bool {
 +        db.trait_data(self.id).is_auto
 +    }
 +
 +    pub fn is_unsafe(&self, db: &dyn HirDatabase) -> bool {
 +        db.trait_data(self.id).is_unsafe
 +    }
 +
 +    pub fn type_or_const_param_count(
 +        &self,
 +        db: &dyn HirDatabase,
 +        count_required_only: bool,
 +    ) -> usize {
 +        db.generic_params(GenericDefId::from(self.id))
 +            .type_or_consts
 +            .iter()
 +            .filter(|(_, ty)| match ty {
 +                TypeOrConstParamData::TypeParamData(ty)
 +                    if ty.provenance != TypeParamProvenance::TypeParamList =>
 +                {
 +                    false
 +                }
 +                _ => true,
 +            })
 +            .filter(|(_, ty)| !count_required_only || !ty.has_default())
 +            .count()
 +    }
 +}
 +
 +impl HasVisibility for Trait {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.trait_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct TypeAlias {
 +    pub(crate) id: TypeAliasId,
 +}
 +
 +impl TypeAlias {
 +    pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
 +        let subst = db.generic_defaults(self.id.into());
 +        subst.iter().any(|ty| match ty.skip_binders().data(Interner) {
 +            GenericArgData::Ty(x) => x.is_unknown(),
 +            _ => false,
 +        })
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
 +    }
 +
 +    pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
 +        db.type_alias_data(self.id).type_ref.as_deref().cloned()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.type_alias_data(self.id).name.clone()
 +    }
 +}
 +
 +impl HasVisibility for TypeAlias {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        let function_data = db.type_alias_data(self.id);
 +        let visibility = &function_data.visibility;
 +        visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct BuiltinType {
 +    pub(crate) inner: hir_def::builtin_type::BuiltinType,
 +}
 +
 +impl BuiltinType {
 +    pub fn str() -> BuiltinType {
 +        BuiltinType { inner: hir_def::builtin_type::BuiltinType::Str }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::new_for_crate(db.crate_graph().iter().next().unwrap(), TyBuilder::builtin(self.inner))
 +    }
 +
 +    pub fn name(self) -> Name {
 +        self.inner.as_name()
 +    }
 +
 +    pub fn is_int(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Int(_))
 +    }
 +
 +    pub fn is_uint(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Uint(_))
 +    }
 +
 +    pub fn is_float(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_))
 +    }
 +
 +    pub fn is_char(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Char)
 +    }
 +
 +    pub fn is_bool(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Bool)
 +    }
 +
 +    pub fn is_str(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Str)
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum MacroKind {
 +    /// `macro_rules!` or Macros 2.0 macro.
 +    Declarative,
 +    /// A built-in or custom derive.
 +    Derive,
 +    /// A built-in function-like macro.
 +    BuiltIn,
 +    /// A procedural attribute macro.
 +    Attr,
 +    /// A function-like procedural macro.
 +    ProcMacro,
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Macro {
 +    pub(crate) id: MacroId,
 +}
 +
 +impl Macro {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.module(db.upcast()) }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        match self.id {
 +            MacroId::Macro2Id(id) => db.macro2_data(id).name.clone(),
 +            MacroId::MacroRulesId(id) => db.macro_rules_data(id).name.clone(),
 +            MacroId::ProcMacroId(id) => db.proc_macro_data(id).name.clone(),
 +        }
 +    }
 +
 +    pub fn is_macro_export(self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.id, MacroId::MacroRulesId(id) if db.macro_rules_data(id).macro_export)
 +    }
 +
 +    pub fn kind(&self, db: &dyn HirDatabase) -> MacroKind {
 +        match self.id {
 +            MacroId::Macro2Id(it) => match it.lookup(db.upcast()).expander {
 +                MacroExpander::Declarative => MacroKind::Declarative,
 +                MacroExpander::BuiltIn(_) | MacroExpander::BuiltInEager(_) => MacroKind::BuiltIn,
 +                MacroExpander::BuiltInAttr(_) => MacroKind::Attr,
 +                MacroExpander::BuiltInDerive(_) => MacroKind::Derive,
 +            },
 +            MacroId::MacroRulesId(it) => match it.lookup(db.upcast()).expander {
 +                MacroExpander::Declarative => MacroKind::Declarative,
 +                MacroExpander::BuiltIn(_) | MacroExpander::BuiltInEager(_) => MacroKind::BuiltIn,
 +                MacroExpander::BuiltInAttr(_) => MacroKind::Attr,
 +                MacroExpander::BuiltInDerive(_) => MacroKind::Derive,
 +            },
 +            MacroId::ProcMacroId(it) => match it.lookup(db.upcast()).kind {
 +                ProcMacroKind::CustomDerive => MacroKind::Derive,
 +                ProcMacroKind::FuncLike => MacroKind::ProcMacro,
 +                ProcMacroKind::Attr => MacroKind::Attr,
 +            },
 +        }
 +    }
 +
 +    pub fn is_fn_like(&self, db: &dyn HirDatabase) -> bool {
 +        match self.kind(db) {
 +            MacroKind::Declarative | MacroKind::BuiltIn | MacroKind::ProcMacro => true,
 +            MacroKind::Attr | MacroKind::Derive => false,
 +        }
 +    }
 +
 +    pub fn is_builtin_derive(&self, db: &dyn HirDatabase) -> bool {
 +        match self.id {
 +            MacroId::Macro2Id(it) => {
 +                matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInDerive(_))
 +            }
 +            MacroId::MacroRulesId(it) => {
 +                matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInDerive(_))
 +            }
 +            MacroId::ProcMacroId(_) => false,
 +        }
 +    }
 +
 +    pub fn is_attr(&self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.kind(db), MacroKind::Attr)
 +    }
 +
 +    pub fn is_derive(&self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.kind(db), MacroKind::Derive)
 +    }
 +}
 +
 +impl HasVisibility for Macro {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match self.id {
 +            MacroId::Macro2Id(id) => {
 +                let data = db.macro2_data(id);
 +                let visibility = &data.visibility;
 +                visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +            }
 +            MacroId::MacroRulesId(_) => Visibility::Public,
 +            MacroId::ProcMacroId(_) => Visibility::Public,
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 +pub enum ItemInNs {
 +    Types(ModuleDef),
 +    Values(ModuleDef),
 +    Macros(Macro),
 +}
 +
 +impl From<Macro> for ItemInNs {
 +    fn from(it: Macro) -> Self {
 +        Self::Macros(it)
 +    }
 +}
 +
 +impl From<ModuleDef> for ItemInNs {
 +    fn from(module_def: ModuleDef) -> Self {
 +        match module_def {
 +            ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => {
 +                ItemInNs::Values(module_def)
 +            }
 +            _ => ItemInNs::Types(module_def),
 +        }
 +    }
 +}
 +
 +impl ItemInNs {
 +    pub fn as_module_def(self) -> Option<ModuleDef> {
 +        match self {
 +            ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
 +            ItemInNs::Macros(_) => None,
 +        }
 +    }
 +
 +    /// Returns the crate defining this item (or `None` if `self` is built-in).
 +    pub fn krate(&self, db: &dyn HirDatabase) -> Option<Crate> {
 +        match self {
 +            ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate()),
 +            ItemInNs::Macros(id) => Some(id.module(db).krate()),
 +        }
 +    }
 +
 +    pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
 +        match self {
 +            ItemInNs::Types(it) | ItemInNs::Values(it) => it.attrs(db),
 +            ItemInNs::Macros(it) => Some(it.attrs(db)),
 +        }
 +    }
 +}
 +
 +/// Invariant: `inner.as_assoc_item(db).is_some()`
 +/// We do not actively enforce this invariant.
 +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 +pub enum AssocItem {
 +    Function(Function),
 +    Const(Const),
 +    TypeAlias(TypeAlias),
 +}
 +#[derive(Debug)]
 +pub enum AssocItemContainer {
 +    Trait(Trait),
 +    Impl(Impl),
 +}
 +pub trait AsAssocItem {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem>;
 +}
 +
 +impl AsAssocItem for Function {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        as_assoc_item(db, AssocItem::Function, self.id)
 +    }
 +}
 +impl AsAssocItem for Const {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        as_assoc_item(db, AssocItem::Const, self.id)
 +    }
 +}
 +impl AsAssocItem for TypeAlias {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        as_assoc_item(db, AssocItem::TypeAlias, self.id)
 +    }
 +}
 +impl AsAssocItem for ModuleDef {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        match self {
 +            ModuleDef::Function(it) => it.as_assoc_item(db),
 +            ModuleDef::Const(it) => it.as_assoc_item(db),
 +            ModuleDef::TypeAlias(it) => it.as_assoc_item(db),
 +            _ => None,
 +        }
 +    }
 +}
 +fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem>
 +where
 +    ID: Lookup<Data = AssocItemLoc<AST>>,
 +    DEF: From<ID>,
 +    CTOR: FnOnce(DEF) -> AssocItem,
 +    AST: ItemTreeNode,
 +{
 +    match id.lookup(db.upcast()).container {
 +        ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
 +        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
 +    }
 +}
 +
 +impl AssocItem {
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        match self {
 +            AssocItem::Function(it) => Some(it.name(db)),
 +            AssocItem::Const(it) => it.name(db),
 +            AssocItem::TypeAlias(it) => Some(it.name(db)),
 +        }
 +    }
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            AssocItem::Function(f) => f.module(db),
 +            AssocItem::Const(c) => c.module(db),
 +            AssocItem::TypeAlias(t) => t.module(db),
 +        }
 +    }
 +    pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer {
 +        let container = match self {
 +            AssocItem::Function(it) => it.id.lookup(db.upcast()).container,
 +            AssocItem::Const(it) => it.id.lookup(db.upcast()).container,
 +            AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container,
 +        };
 +        match container {
 +            ItemContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
 +            ItemContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
 +            ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
 +                panic!("invalid AssocItem")
 +            }
 +        }
 +    }
 +
 +    pub fn containing_trait(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        match self.container(db) {
 +            AssocItemContainer::Trait(t) => Some(t),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn containing_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        match self.container(db) {
 +            AssocItemContainer::Impl(i) => i.trait_(db),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn containing_trait_or_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        match self.container(db) {
 +            AssocItemContainer::Trait(t) => Some(t),
 +            AssocItemContainer::Impl(i) => i.trait_(db),
 +        }
 +    }
 +}
 +
 +impl HasVisibility for AssocItem {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match self {
 +            AssocItem::Function(f) => f.visibility(db),
 +            AssocItem::Const(c) => c.visibility(db),
 +            AssocItem::TypeAlias(t) => t.visibility(db),
 +        }
 +    }
 +}
 +
 +impl From<AssocItem> for ModuleDef {
 +    fn from(assoc: AssocItem) -> Self {
 +        match assoc {
 +            AssocItem::Function(it) => ModuleDef::Function(it),
 +            AssocItem::Const(it) => ModuleDef::Const(it),
 +            AssocItem::TypeAlias(it) => ModuleDef::TypeAlias(it),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 +pub enum GenericDef {
 +    Function(Function),
 +    Adt(Adt),
 +    Trait(Trait),
 +    TypeAlias(TypeAlias),
 +    Impl(Impl),
 +    // enum variants cannot have generics themselves, but their parent enums
 +    // can, and this makes some code easier to write
 +    Variant(Variant),
 +    // consts can have type parameters from their parents (i.e. associated consts of traits)
 +    Const(Const),
 +}
 +impl_from!(
 +    Function,
 +    Adt(Struct, Enum, Union),
 +    Trait,
 +    TypeAlias,
 +    Impl,
 +    Variant,
 +    Const
 +    for GenericDef
 +);
 +
 +impl GenericDef {
 +    pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
 +        let generics = db.generic_params(self.into());
 +        let ty_params = generics.type_or_consts.iter().map(|(local_id, _)| {
 +            let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } };
 +            match toc.split(db) {
 +                Either::Left(x) => GenericParam::ConstParam(x),
 +                Either::Right(x) => GenericParam::TypeParam(x),
 +            }
 +        });
 +        let lt_params = generics
 +            .lifetimes
 +            .iter()
 +            .map(|(local_id, _)| LifetimeParam {
 +                id: LifetimeParamId { parent: self.into(), local_id },
 +            })
 +            .map(GenericParam::LifetimeParam);
 +        lt_params.chain(ty_params).collect()
 +    }
 +
 +    pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
 +        let generics = db.generic_params(self.into());
 +        generics
 +            .type_or_consts
 +            .iter()
 +            .map(|(local_id, _)| TypeOrConstParam {
 +                id: TypeOrConstParamId { parent: self.into(), local_id },
 +            })
 +            .collect()
 +    }
 +}
 +
 +/// A single local definition.
 +///
 +/// If the definition of this is part of a "MultiLocal", that is a local that has multiple declarations due to or-patterns
 +/// then this only references a single one of those.
 +/// To retrieve the other locals you should use [`Local::associated_locals`]
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct Local {
 +    pub(crate) parent: DefWithBodyId,
 +    pub(crate) pat_id: PatId,
 +}
 +
 +impl Local {
 +    pub fn is_param(self, db: &dyn HirDatabase) -> bool {
 +        let src = self.source(db);
 +        match src.value {
 +            Either::Left(pat) => pat
 +                .syntax()
 +                .ancestors()
 +                .map(|it| it.kind())
 +                .take_while(|&kind| ast::Pat::can_cast(kind) || ast::Param::can_cast(kind))
 +                .any(ast::Param::can_cast),
 +            Either::Right(_) => true,
 +        }
 +    }
 +
 +    pub fn as_self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
 +        match self.parent {
 +            DefWithBodyId::FunctionId(func) if self.is_self(db) => Some(SelfParam { func }),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let body = db.body(self.parent);
 +        match &body[self.pat_id] {
 +            Pat::Bind { name, .. } => name.clone(),
 +            _ => {
 +                stdx::never!("hir::Local is missing a name!");
 +                Name::missing()
 +            }
 +        }
 +    }
 +
 +    pub fn is_self(self, db: &dyn HirDatabase) -> bool {
 +        self.name(db) == name![self]
 +    }
 +
 +    pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
 +        let body = db.body(self.parent);
 +        matches!(&body[self.pat_id], Pat::Bind { mode: BindingAnnotation::Mutable, .. })
 +    }
 +
 +    pub fn is_ref(self, db: &dyn HirDatabase) -> bool {
 +        let body = db.body(self.parent);
 +        matches!(
 +            &body[self.pat_id],
 +            Pat::Bind { mode: BindingAnnotation::Ref | BindingAnnotation::RefMut, .. }
 +        )
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
 +        self.parent.into()
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.parent(db).module(db)
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let def = self.parent;
 +        let infer = db.infer(def);
 +        let ty = infer[self.pat_id].clone();
 +        Type::new(db, def, ty)
 +    }
 +
 +    pub fn associated_locals(self, db: &dyn HirDatabase) -> Box<[Local]> {
 +        let body = db.body(self.parent);
 +        body.ident_patterns_for(&self.pat_id)
 +            .iter()
 +            .map(|&pat_id| Local { parent: self.parent, pat_id })
 +            .collect()
 +    }
 +
 +    /// If this local is part of a multi-local, retrieve the representative local.
 +    /// That is the local that references are being resolved to.
 +    pub fn representative(self, db: &dyn HirDatabase) -> Local {
 +        let body = db.body(self.parent);
 +        Local { pat_id: body.pattern_representative(self.pat_id), ..self }
 +    }
 +
 +    pub fn source(self, db: &dyn HirDatabase) -> InFile<Either<ast::IdentPat, ast::SelfParam>> {
 +        let (_body, source_map) = db.body_with_source_map(self.parent);
 +        let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm...
 +        let root = src.file_syntax(db.upcast());
 +        src.map(|ast| match ast {
 +            // Suspicious unwrap
 +            Either::Left(it) => Either::Left(it.cast().unwrap().to_node(&root)),
 +            Either::Right(it) => Either::Right(it.to_node(&root)),
 +        })
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct DeriveHelper {
 +    pub(crate) derive: MacroId,
 +    pub(crate) idx: usize,
 +}
 +
 +impl DeriveHelper {
 +    pub fn derive(&self) -> Macro {
 +        Macro { id: self.derive.into() }
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> Name {
 +        match self.derive {
 +            MacroId::Macro2Id(_) => None,
 +            MacroId::MacroRulesId(_) => None,
 +            MacroId::ProcMacroId(proc_macro) => db
 +                .proc_macro_data(proc_macro)
 +                .helpers
 +                .as_ref()
 +                .and_then(|it| it.get(self.idx))
 +                .cloned(),
 +        }
 +        .unwrap_or_else(|| Name::missing())
 +    }
 +}
 +
 +// FIXME: Wrong name? This is could also be a registered attribute
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct BuiltinAttr {
 +    krate: Option<CrateId>,
 +    idx: usize,
 +}
 +
 +impl BuiltinAttr {
 +    // FIXME: consider crates\hir_def\src\nameres\attr_resolution.rs?
 +    pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<Self> {
 +        if let builtin @ Some(_) = Self::builtin(name) {
 +            return builtin;
 +        }
 +        let idx = db.crate_def_map(krate.id).registered_attrs().iter().position(|it| it == name)?;
 +        Some(BuiltinAttr { krate: Some(krate.id), idx })
 +    }
 +
 +    fn builtin(name: &str) -> Option<Self> {
 +        hir_def::builtin_attr::INERT_ATTRIBUTES
 +            .iter()
 +            .position(|tool| tool.name == name)
 +            .map(|idx| BuiltinAttr { krate: None, idx })
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> SmolStr {
 +        // FIXME: Return a `Name` here
 +        match self.krate {
 +            Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx].clone(),
 +            None => SmolStr::new(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].name),
 +        }
 +    }
 +
 +    pub fn template(&self, _: &dyn HirDatabase) -> Option<AttributeTemplate> {
 +        match self.krate {
 +            Some(_) => None,
 +            None => Some(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].template),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct ToolModule {
 +    krate: Option<CrateId>,
 +    idx: usize,
 +}
 +
 +impl ToolModule {
 +    // FIXME: consider crates\hir_def\src\nameres\attr_resolution.rs?
 +    pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<Self> {
 +        if let builtin @ Some(_) = Self::builtin(name) {
 +            return builtin;
 +        }
 +        let idx = db.crate_def_map(krate.id).registered_tools().iter().position(|it| it == name)?;
 +        Some(ToolModule { krate: Some(krate.id), idx })
 +    }
 +
 +    fn builtin(name: &str) -> Option<Self> {
 +        hir_def::builtin_attr::TOOL_MODULES
 +            .iter()
 +            .position(|&tool| tool == name)
 +            .map(|idx| ToolModule { krate: None, idx })
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> SmolStr {
 +        // FIXME: Return a `Name` here
 +        match self.krate {
 +            Some(krate) => db.crate_def_map(krate).registered_tools()[self.idx].clone(),
 +            None => SmolStr::new(hir_def::builtin_attr::TOOL_MODULES[self.idx]),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct Label {
 +    pub(crate) parent: DefWithBodyId,
 +    pub(crate) label_id: LabelId,
 +}
 +
 +impl Label {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.parent(db).module(db)
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
 +        self.parent.into()
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let body = db.body(self.parent);
 +        body[self.label_id].name.clone()
 +    }
 +
 +    pub fn source(self, db: &dyn HirDatabase) -> InFile<ast::Label> {
 +        let (_body, source_map) = db.body_with_source_map(self.parent);
 +        let src = source_map.label_syntax(self.label_id);
 +        let root = src.file_syntax(db.upcast());
 +        src.map(|ast| ast.to_node(&root))
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum GenericParam {
 +    TypeParam(TypeParam),
 +    ConstParam(ConstParam),
 +    LifetimeParam(LifetimeParam),
 +}
 +impl_from!(TypeParam, ConstParam, LifetimeParam for GenericParam);
 +
 +impl GenericParam {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            GenericParam::TypeParam(it) => it.module(db),
 +            GenericParam::ConstParam(it) => it.module(db),
 +            GenericParam::LifetimeParam(it) => it.module(db),
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        match self {
 +            GenericParam::TypeParam(it) => it.name(db),
 +            GenericParam::ConstParam(it) => it.name(db),
 +            GenericParam::LifetimeParam(it) => it.name(db),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct TypeParam {
 +    pub(crate) id: TypeParamId,
 +}
 +
 +impl TypeParam {
 +    pub fn merge(self) -> TypeOrConstParam {
 +        TypeOrConstParam { id: self.id.into() }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        self.merge().name(db)
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent().module(db.upcast()).into()
 +    }
 +
 +    /// Is this type parameter implicitly introduced (eg. `Self` in a trait or an `impl Trait`
 +    /// argument)?
 +    pub fn is_implicit(self, db: &dyn HirDatabase) -> bool {
 +        let params = db.generic_params(self.id.parent());
 +        let data = &params.type_or_consts[self.id.local_id()];
 +        match data.type_param().unwrap().provenance {
 +            hir_def::generics::TypeParamProvenance::TypeParamList => false,
 +            hir_def::generics::TypeParamProvenance::TraitSelf
 +            | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => true,
 +        }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let resolver = self.id.parent().resolver(db.upcast());
 +        let ty =
 +            TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id.into())).intern(Interner);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    /// FIXME: this only lists trait bounds from the item defining the type
 +    /// parameter, not additional bounds that might be added e.g. by a method if
 +    /// the parameter comes from an impl!
 +    pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
 +        db.generic_predicates_for_param(self.id.parent(), self.id.into(), None)
 +            .iter()
 +            .filter_map(|pred| match &pred.skip_binders().skip_binders() {
 +                hir_ty::WhereClause::Implemented(trait_ref) => {
 +                    Some(Trait::from(trait_ref.hir_trait_id()))
 +                }
 +                _ => None,
 +            })
 +            .collect()
 +    }
 +
 +    pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
 +        let params = db.generic_defaults(self.id.parent());
 +        let local_idx = hir_ty::param_idx(db, self.id.into())?;
 +        let resolver = self.id.parent().resolver(db.upcast());
 +        let ty = params.get(local_idx)?.clone();
 +        let subst = TyBuilder::placeholder_subst(db, self.id.parent());
 +        let ty = ty.substitute(Interner, &subst);
 +        match ty.data(Interner) {
 +            GenericArgData::Ty(x) => Some(Type::new_with_resolver_inner(db, &resolver, x.clone())),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct LifetimeParam {
 +    pub(crate) id: LifetimeParamId,
 +}
 +
 +impl LifetimeParam {
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let params = db.generic_params(self.id.parent);
 +        params.lifetimes[self.id.local_id].name.clone()
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent.module(db.upcast()).into()
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
 +        self.id.parent.into()
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct ConstParam {
 +    pub(crate) id: ConstParamId,
 +}
 +
 +impl ConstParam {
 +    pub fn merge(self) -> TypeOrConstParam {
 +        TypeOrConstParam { id: self.id.into() }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let params = db.generic_params(self.id.parent());
 +        match params.type_or_consts[self.id.local_id()].name() {
 +            Some(x) => x.clone(),
 +            None => {
 +                never!();
 +                Name::missing()
 +            }
 +        }
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent().module(db.upcast()).into()
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
 +        self.id.parent().into()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::new(db, self.id.parent(), db.const_param_ty(self.id))
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct TypeOrConstParam {
 +    pub(crate) id: TypeOrConstParamId,
 +}
 +
 +impl TypeOrConstParam {
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let params = db.generic_params(self.id.parent);
 +        match params.type_or_consts[self.id.local_id].name() {
 +            Some(n) => n.clone(),
 +            _ => Name::missing(),
 +        }
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent.module(db.upcast()).into()
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
 +        self.id.parent.into()
 +    }
 +
 +    pub fn split(self, db: &dyn HirDatabase) -> Either<ConstParam, TypeParam> {
 +        let params = db.generic_params(self.id.parent);
 +        match &params.type_or_consts[self.id.local_id] {
 +            hir_def::generics::TypeOrConstParamData::TypeParamData(_) => {
 +                Either::Right(TypeParam { id: TypeParamId::from_unchecked(self.id) })
 +            }
 +            hir_def::generics::TypeOrConstParamData::ConstParamData(_) => {
 +                Either::Left(ConstParam { id: ConstParamId::from_unchecked(self.id) })
 +            }
 +        }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        match self.split(db) {
 +            Either::Left(x) => x.ty(db),
 +            Either::Right(x) => x.ty(db),
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Impl {
 +    pub(crate) id: ImplId,
 +}
 +
 +impl Impl {
 +    pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<Impl> {
 +        let inherent = db.inherent_impls_in_crate(krate.id);
 +        let trait_ = db.trait_impls_in_crate(krate.id);
 +
 +        inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
 +    }
 +
 +    pub fn all_for_type(db: &dyn HirDatabase, Type { ty, env }: Type) -> Vec<Impl> {
 +        let def_crates = match method_resolution::def_crates(db, &ty, env.krate) {
 +            Some(def_crates) => def_crates,
 +            None => return Vec::new(),
 +        };
 +
 +        let filter = |impl_def: &Impl| {
 +            let self_ty = impl_def.self_ty(db);
 +            let rref = self_ty.remove_ref();
 +            ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty))
 +        };
 +
 +        let fp = TyFingerprint::for_inherent_impl(&ty);
 +        let fp = match fp {
 +            Some(fp) => fp,
 +            None => return Vec::new(),
 +        };
 +
 +        let mut all = Vec::new();
 +        def_crates.iter().for_each(|&id| {
 +            all.extend(
 +                db.inherent_impls_in_crate(id)
 +                    .for_self_ty(&ty)
 +                    .iter()
 +                    .cloned()
 +                    .map(Self::from)
 +                    .filter(filter),
 +            )
 +        });
 +        for id in def_crates
 +            .iter()
 +            .flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db))
 +            .map(|Crate { id }| id)
 +            .chain(def_crates.iter().copied())
 +            .unique()
 +        {
 +            all.extend(
 +                db.trait_impls_in_crate(id)
 +                    .for_self_ty_without_blanket_impls(fp)
 +                    .map(Self::from)
 +                    .filter(filter),
 +            );
 +        }
 +        all
 +    }
 +
 +    pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec<Impl> {
 +        let krate = trait_.module(db).krate();
 +        let mut all = Vec::new();
 +        for Crate { id } in krate.transitive_reverse_dependencies(db).into_iter() {
 +            let impls = db.trait_impls_in_crate(id);
 +            all.extend(impls.for_trait(trait_.id).map(Self::from))
 +        }
 +        all
 +    }
 +
 +    // FIXME: the return type is wrong. This should be a hir version of
 +    // `TraitRef` (to account for parameters and qualifiers)
 +    pub fn trait_(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        let trait_ref = db.impl_trait(self.id)?.skip_binders().clone();
 +        let id = hir_ty::from_chalk_trait_id(trait_ref.trait_id);
 +        Some(Trait { id })
 +    }
 +
 +    pub fn self_ty(self, db: &dyn HirDatabase) -> Type {
 +        let resolver = self.id.resolver(db.upcast());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let ty = db.impl_self_ty(self.id).substitute(Interner, &substs);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
 +        db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect()
 +    }
 +
 +    pub fn is_negative(self, db: &dyn HirDatabase) -> bool {
 +        db.impl_data(self.id).is_negative
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.lookup(db.upcast()).container.into()
 +    }
 +
 +    pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> {
 +        let src = self.source(db)?;
 +        src.file_id.is_builtin_derive(db.upcast())
 +    }
 +}
 +
 +#[derive(Clone, PartialEq, Eq, Debug)]
 +pub struct Type {
 +    env: Arc<TraitEnvironment>,
 +    ty: Ty,
 +}
 +
 +impl Type {
 +    pub(crate) fn new_with_resolver(db: &dyn HirDatabase, resolver: &Resolver, ty: Ty) -> Type {
 +        Type::new_with_resolver_inner(db, resolver, ty)
 +    }
 +
 +    pub(crate) fn new_with_resolver_inner(
 +        db: &dyn HirDatabase,
 +        resolver: &Resolver,
 +        ty: Ty,
 +    ) -> Type {
 +        let environment = resolver.generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(resolver.krate())),
 +            |d| db.trait_environment(d),
 +        );
 +        Type { env: environment, ty }
 +    }
 +
 +    pub(crate) fn new_for_crate(krate: CrateId, ty: Ty) -> Type {
 +        Type { env: Arc::new(TraitEnvironment::empty(krate)), ty }
 +    }
 +
 +    pub fn reference(inner: &Type, m: Mutability) -> Type {
 +        inner.derived(
 +            TyKind::Ref(
 +                if m.is_mut() { hir_ty::Mutability::Mut } else { hir_ty::Mutability::Not },
 +                hir_ty::static_lifetime(),
 +                inner.ty.clone(),
 +            )
 +            .intern(Interner),
 +        )
 +    }
 +
 +    fn new(db: &dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty) -> Type {
 +        let resolver = lexical_env.resolver(db.upcast());
 +        let environment = resolver.generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(resolver.krate())),
 +            |d| db.trait_environment(d),
 +        );
 +        Type { env: environment, ty }
 +    }
 +
 +    fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into<TyDefId>) -> Type {
 +        let ty_def = def.into();
 +        let parent_subst = match ty_def {
 +            TyDefId::TypeAliasId(id) => match id.lookup(db.upcast()).container {
 +                ItemContainerId::TraitId(id) => {
 +                    let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
 +                    Some(subst)
 +                }
 +                ItemContainerId::ImplId(id) => {
 +                    let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
 +                    Some(subst)
 +                }
 +                _ => None,
 +            },
 +            _ => None,
 +        };
 +        let ty = TyBuilder::def_ty(db, ty_def, parent_subst).fill_with_unknown().build();
 +        Type::new(db, def, ty)
 +    }
 +
 +    pub fn new_slice(ty: Type) -> Type {
 +        Type { env: ty.env, ty: TyBuilder::slice(ty.ty) }
 +    }
 +
 +    pub fn is_unit(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Tuple(0, ..))
 +    }
 +
 +    pub fn is_bool(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Bool))
 +    }
 +
 +    pub fn is_never(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Never)
 +    }
 +
 +    pub fn is_mutable_reference(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..))
 +    }
 +
 +    pub fn is_reference(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Ref(..))
 +    }
 +
 +    pub fn as_reference(&self) -> Option<(Type, Mutability)> {
 +        let (ty, _lt, m) = self.ty.as_reference()?;
 +        let m = Mutability::from_mutable(matches!(m, hir_ty::Mutability::Mut));
 +        Some((self.derived(ty.clone()), m))
 +    }
 +
 +    pub fn is_slice(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Slice(..))
 +    }
 +
 +    pub fn is_usize(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)))
 +    }
 +
 +    pub fn remove_ref(&self) -> Option<Type> {
 +        match &self.ty.kind(Interner) {
 +            TyKind::Ref(.., ty) => Some(self.derived(ty.clone())),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn strip_references(&self) -> Type {
 +        self.derived(self.ty.strip_references().clone())
 +    }
 +
 +    pub fn strip_reference(&self) -> Type {
 +        self.derived(self.ty.strip_reference().clone())
 +    }
 +
 +    pub fn is_unknown(&self) -> bool {
 +        self.ty.is_unknown()
 +    }
 +
 +    /// Checks that particular type `ty` implements `std::future::IntoFuture` or
 +    /// `std::future::Future`.
 +    /// This function is used in `.await` syntax completion.
 +    pub fn impls_into_future(&self, db: &dyn HirDatabase) -> bool {
 +        let trait_ = db
 +            .lang_item(self.env.krate, SmolStr::new_inline("into_future"))
 +            .and_then(|it| {
 +                let into_future_fn = it.as_function()?;
 +                let assoc_item = as_assoc_item(db, AssocItem::Function, into_future_fn)?;
 +                let into_future_trait = assoc_item.containing_trait_or_trait_impl(db)?;
 +                Some(into_future_trait.id)
 +            })
 +            .or_else(|| {
 +                let future_trait =
 +                    db.lang_item(self.env.krate, SmolStr::new_inline("future_trait"))?;
 +                future_trait.as_trait()
 +            });
 +
 +        let trait_ = match trait_ {
 +            Some(it) => it,
 +            None => return false,
 +        };
 +
 +        let canonical_ty =
 +            Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
 +        method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), trait_)
 +    }
 +
 +    /// Checks that particular type `ty` implements `std::ops::FnOnce`.
 +    ///
 +    /// This function can be used to check if a particular type is callable, since FnOnce is a
 +    /// supertrait of Fn and FnMut, so all callable types implements at least FnOnce.
 +    pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool {
 +        let fnonce_trait = match FnTrait::FnOnce.get_id(db, self.env.krate) {
 +            Some(it) => it,
 +            None => return false,
 +        };
 +
 +        let canonical_ty =
 +            Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
 +        method_resolution::implements_trait_unique(
 +            &canonical_ty,
 +            db,
 +            self.env.clone(),
 +            fnonce_trait,
 +        )
 +    }
 +
 +    pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
 +        let mut it = args.iter().map(|t| t.ty.clone());
 +        let trait_ref = TyBuilder::trait_ref(db, trait_.id)
 +            .push(self.ty.clone())
 +            .fill(|x| {
 +                let r = it.next().unwrap();
 +                match x {
 +                    ParamKind::Type => GenericArgData::Ty(r).intern(Interner),
 +                    ParamKind::Const(ty) => {
 +                        // FIXME: this code is not covered in tests.
 +                        unknown_const_as_generic(ty.clone())
 +                    }
 +                }
 +            })
 +            .build();
 +
 +        let goal = Canonical {
 +            value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(Interner)),
 +            binders: CanonicalVarKinds::empty(Interner),
 +        };
 +
 +        db.trait_solve(self.env.krate, goal).is_some()
 +    }
 +
 +    pub fn normalize_trait_assoc_type(
 +        &self,
 +        db: &dyn HirDatabase,
 +        args: &[Type],
 +        alias: TypeAlias,
 +    ) -> Option<Type> {
 +        let mut args = args.iter();
 +        let trait_id = match alias.id.lookup(db.upcast()).container {
 +            ItemContainerId::TraitId(id) => id,
 +            _ => unreachable!("non assoc type alias reached in normalize_trait_assoc_type()"),
 +        };
 +        let parent_subst = TyBuilder::subst_for_def(db, trait_id, None)
 +            .push(self.ty.clone())
 +            .fill(|x| {
 +                // FIXME: this code is not covered in tests.
 +                match x {
 +                    ParamKind::Type => {
 +                        GenericArgData::Ty(args.next().unwrap().ty.clone()).intern(Interner)
 +                    }
 +                    ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
 +                }
 +            })
 +            .build();
 +        // FIXME: We don't handle GATs yet.
 +        let projection = TyBuilder::assoc_type_projection(db, alias.id, Some(parent_subst)).build();
 +
 +        let ty = db.normalize_projection(projection, self.env.clone());
 +        if ty.is_unknown() {
 +            None
 +        } else {
 +            Some(self.derived(ty))
 +        }
 +    }
 +
 +    pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
 +        let lang_item = db.lang_item(self.env.krate, SmolStr::new_inline("copy"));
 +        let copy_trait = match lang_item {
 +            Some(LangItemTarget::TraitId(it)) => it,
 +            _ => return false,
 +        };
 +        self.impls_trait(db, copy_trait.into(), &[])
 +    }
 +
 +    pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
 +        let callee = match self.ty.kind(Interner) {
 +            TyKind::Closure(id, _) => Callee::Closure(*id),
 +            TyKind::Function(_) => Callee::FnPtr,
 +            _ => Callee::Def(self.ty.callable_def(db)?),
 +        };
 +
 +        let sig = self.ty.callable_sig(db)?;
 +        Some(Callable { ty: self.clone(), sig, callee, is_bound_method: false })
 +    }
 +
 +    pub fn is_closure(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::Closure { .. })
 +    }
 +
 +    pub fn is_fn(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::FnDef(..) | TyKind::Function { .. })
 +    }
 +
 +    pub fn is_array(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::Array(..))
 +    }
 +
 +    pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
 +        let adt_id = match *self.ty.kind(Interner) {
 +            TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id,
 +            _ => return false,
 +        };
 +
 +        let adt = adt_id.into();
 +        match adt {
 +            Adt::Struct(s) => matches!(s.repr(db), Some(ReprData { packed: true, .. })),
 +            _ => false,
 +        }
 +    }
 +
 +    pub fn is_raw_ptr(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::Raw(..))
 +    }
 +
 +    pub fn contains_unknown(&self) -> bool {
 +        return go(&self.ty);
 +
 +        fn go(ty: &Ty) -> bool {
 +            match ty.kind(Interner) {
 +                TyKind::Error => true,
 +
 +                TyKind::Adt(_, substs)
 +                | TyKind::AssociatedType(_, substs)
 +                | TyKind::Tuple(_, substs)
 +                | TyKind::OpaqueType(_, substs)
 +                | TyKind::FnDef(_, substs)
 +                | TyKind::Closure(_, substs) => {
 +                    substs.iter(Interner).filter_map(|a| a.ty(Interner)).any(go)
 +                }
 +
 +                TyKind::Array(_ty, len) if len.is_unknown() => true,
 +                TyKind::Array(ty, _)
 +                | TyKind::Slice(ty)
 +                | TyKind::Raw(_, ty)
 +                | TyKind::Ref(_, _, ty) => go(ty),
 +
 +                TyKind::Scalar(_)
 +                | TyKind::Str
 +                | TyKind::Never
 +                | TyKind::Placeholder(_)
 +                | TyKind::BoundVar(_)
 +                | TyKind::InferenceVar(_, _)
 +                | TyKind::Dyn(_)
 +                | TyKind::Function(_)
 +                | TyKind::Alias(_)
 +                | TyKind::Foreign(_)
 +                | TyKind::Generator(..)
 +                | TyKind::GeneratorWitness(..) => false,
 +            }
 +        }
 +    }
 +
 +    pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
 +        let (variant_id, substs) = match self.ty.kind(Interner) {
 +            TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), substs) => ((*s).into(), substs),
 +            TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), substs) => ((*u).into(), substs),
 +            _ => return Vec::new(),
 +        };
 +
 +        db.field_types(variant_id)
 +            .iter()
 +            .map(|(local_id, ty)| {
 +                let def = Field { parent: variant_id.into(), id: local_id };
 +                let ty = ty.clone().substitute(Interner, substs);
 +                (def, self.derived(ty))
 +            })
 +            .collect()
 +    }
 +
 +    pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> {
 +        if let TyKind::Tuple(_, substs) = &self.ty.kind(Interner) {
 +            substs
 +                .iter(Interner)
 +                .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone()))
 +                .collect()
 +        } else {
 +            Vec::new()
 +        }
 +    }
 +
 +    pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
 +        self.autoderef_(db).map(move |ty| self.derived(ty))
 +    }
 +
 +    fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a {
 +        // There should be no inference vars in types passed here
 +        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 +        let environment = self.env.clone();
 +        autoderef(db, environment, canonical).map(|canonical| canonical.value)
 +    }
 +
 +    // This would be nicer if it just returned an iterator, but that runs into
 +    // lifetime problems, because we need to borrow temp `CrateImplDefs`.
 +    pub fn iterate_assoc_items<T>(
 +        &self,
 +        db: &dyn HirDatabase,
 +        krate: Crate,
 +        mut callback: impl FnMut(AssocItem) -> Option<T>,
 +    ) -> Option<T> {
 +        let mut slot = None;
 +        self.iterate_assoc_items_dyn(db, krate, &mut |assoc_item_id| {
 +            slot = callback(assoc_item_id.into());
 +            slot.is_some()
 +        });
 +        slot
 +    }
 +
 +    fn iterate_assoc_items_dyn(
 +        &self,
 +        db: &dyn HirDatabase,
 +        krate: Crate,
 +        callback: &mut dyn FnMut(AssocItemId) -> bool,
 +    ) {
 +        let def_crates = match method_resolution::def_crates(db, &self.ty, krate.id) {
 +            Some(it) => it,
 +            None => return,
 +        };
 +        for krate in def_crates {
 +            let impls = db.inherent_impls_in_crate(krate);
 +
 +            for impl_def in impls.for_self_ty(&self.ty) {
 +                for &item in db.impl_data(*impl_def).items.iter() {
 +                    if callback(item) {
 +                        return;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    pub fn type_arguments(&self) -> impl Iterator<Item = Type> + '_ {
 +        self.ty
 +            .strip_references()
 +            .as_adt()
 +            .into_iter()
 +            .flat_map(|(_, substs)| substs.iter(Interner))
 +            .filter_map(|arg| arg.ty(Interner).cloned())
 +            .map(move |ty| self.derived(ty))
 +    }
 +
 +    pub fn iterate_method_candidates<T>(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        // FIXME this can be retrieved from `scope`, except autoimport uses this
 +        // to specify a different set, so the method needs to be split
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        mut callback: impl FnMut(Function) -> Option<T>,
 +    ) -> Option<T> {
 +        let _p = profile::span("iterate_method_candidates");
 +        let mut slot = None;
 +
 +        self.iterate_method_candidates_dyn(
 +            db,
 +            scope,
 +            traits_in_scope,
 +            with_local_impls,
 +            name,
 +            &mut |assoc_item_id| {
 +                if let AssocItemId::FunctionId(func) = assoc_item_id {
 +                    if let Some(res) = callback(func.into()) {
 +                        slot = Some(res);
 +                        return ControlFlow::Break(());
 +                    }
 +                }
 +                ControlFlow::Continue(())
 +            },
 +        );
 +        slot
 +    }
 +
 +    fn iterate_method_candidates_dyn(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
 +    ) {
 +        // There should be no inference vars in types passed here
 +        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 +
 +        let krate = scope.krate();
 +        let environment = scope.resolver().generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(krate.id)),
 +            |d| db.trait_environment(d),
 +        );
 +
 +        method_resolution::iterate_method_candidates_dyn(
 +            &canonical,
 +            db,
 +            environment,
 +            traits_in_scope,
 +            with_local_impls.and_then(|b| b.id.containing_block()).into(),
 +            name,
 +            method_resolution::LookupMode::MethodCall,
 +            &mut |_adj, id| callback(id),
 +        );
 +    }
 +
 +    pub fn iterate_path_candidates<T>(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        mut callback: impl FnMut(AssocItem) -> Option<T>,
 +    ) -> Option<T> {
 +        let _p = profile::span("iterate_path_candidates");
 +        let mut slot = None;
 +        self.iterate_path_candidates_dyn(
 +            db,
 +            scope,
 +            traits_in_scope,
 +            with_local_impls,
 +            name,
 +            &mut |assoc_item_id| {
 +                if let Some(res) = callback(assoc_item_id.into()) {
 +                    slot = Some(res);
 +                    return ControlFlow::Break(());
 +                }
 +                ControlFlow::Continue(())
 +            },
 +        );
 +        slot
 +    }
 +
 +    fn iterate_path_candidates_dyn(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
 +    ) {
 +        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 +
 +        let krate = scope.krate();
 +        let environment = scope.resolver().generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(krate.id)),
 +            |d| db.trait_environment(d),
 +        );
 +
 +        method_resolution::iterate_path_candidates(
 +            &canonical,
 +            db,
 +            environment,
 +            traits_in_scope,
 +            with_local_impls.and_then(|b| b.id.containing_block()).into(),
 +            name,
 +            &mut |id| callback(id),
 +        );
 +    }
 +
 +    pub fn as_adt(&self) -> Option<Adt> {
 +        let (adt, _subst) = self.ty.as_adt()?;
 +        Some(adt.into())
 +    }
 +
 +    pub fn as_builtin(&self) -> Option<BuiltinType> {
 +        self.ty.as_builtin().map(|inner| BuiltinType { inner })
 +    }
 +
 +    pub fn as_dyn_trait(&self) -> Option<Trait> {
 +        self.ty.dyn_trait().map(Into::into)
 +    }
 +
 +    /// If a type can be represented as `dyn Trait`, returns all traits accessible via this type,
 +    /// or an empty iterator otherwise.
 +    pub fn applicable_inherent_traits<'a>(
 +        &'a self,
 +        db: &'a dyn HirDatabase,
 +    ) -> impl Iterator<Item = Trait> + 'a {
 +        let _p = profile::span("applicable_inherent_traits");
 +        self.autoderef_(db)
 +            .filter_map(|ty| ty.dyn_trait())
 +            .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id))
 +            .map(Trait::from)
 +    }
 +
 +    pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Trait> + 'a {
 +        let _p = profile::span("env_traits");
 +        self.autoderef_(db)
 +            .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_)))
 +            .flat_map(|ty| {
 +                self.env
 +                    .traits_in_scope_from_clauses(ty)
 +                    .flat_map(|t| hir_ty::all_super_traits(db.upcast(), t))
 +            })
 +            .map(Trait::from)
 +    }
 +
 +    pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<impl Iterator<Item = Trait>> {
 +        self.ty.impl_trait_bounds(db).map(|it| {
 +            it.into_iter().filter_map(|pred| match pred.skip_binders() {
 +                hir_ty::WhereClause::Implemented(trait_ref) => {
 +                    Some(Trait::from(trait_ref.hir_trait_id()))
 +                }
 +                _ => None,
 +            })
 +        })
 +    }
 +
 +    pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> {
 +        self.ty.associated_type_parent_trait(db).map(Into::into)
 +    }
 +
 +    fn derived(&self, ty: Ty) -> Type {
 +        Type { env: self.env.clone(), ty }
 +    }
 +
 +    pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) {
 +        // TypeWalk::walk for a Ty at first visits parameters and only after that the Ty itself.
 +        // We need a different order here.
 +
 +        fn walk_substs(
 +            db: &dyn HirDatabase,
 +            type_: &Type,
 +            substs: &Substitution,
 +            cb: &mut impl FnMut(Type),
 +        ) {
 +            for ty in substs.iter(Interner).filter_map(|a| a.ty(Interner)) {
 +                walk_type(db, &type_.derived(ty.clone()), cb);
 +            }
 +        }
 +
 +        fn walk_bounds(
 +            db: &dyn HirDatabase,
 +            type_: &Type,
 +            bounds: &[QuantifiedWhereClause],
 +            cb: &mut impl FnMut(Type),
 +        ) {
 +            for pred in bounds {
 +                if let WhereClause::Implemented(trait_ref) = pred.skip_binders() {
 +                    cb(type_.clone());
 +                    // skip the self type. it's likely the type we just got the bounds from
 +                    for ty in
 +                        trait_ref.substitution.iter(Interner).skip(1).filter_map(|a| a.ty(Interner))
 +                    {
 +                        walk_type(db, &type_.derived(ty.clone()), cb);
 +                    }
 +                }
 +            }
 +        }
 +
 +        fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
 +            let ty = type_.ty.strip_references();
 +            match ty.kind(Interner) {
 +                TyKind::Adt(_, substs) => {
 +                    cb(type_.derived(ty.clone()));
 +                    walk_substs(db, type_, substs, cb);
 +                }
 +                TyKind::AssociatedType(_, substs) => {
 +                    if ty.associated_type_parent_trait(db).is_some() {
 +                        cb(type_.derived(ty.clone()));
 +                    }
 +                    walk_substs(db, type_, substs, cb);
 +                }
 +                TyKind::OpaqueType(_, subst) => {
 +                    if let Some(bounds) = ty.impl_trait_bounds(db) {
 +                        walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
 +                    }
 +
 +                    walk_substs(db, type_, subst, cb);
 +                }
 +                TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
 +                    if let Some(bounds) = ty.impl_trait_bounds(db) {
 +                        walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
 +                    }
 +
 +                    walk_substs(db, type_, &opaque_ty.substitution, cb);
 +                }
 +                TyKind::Placeholder(_) => {
 +                    if let Some(bounds) = ty.impl_trait_bounds(db) {
 +                        walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
 +                    }
 +                }
 +                TyKind::Dyn(bounds) => {
 +                    walk_bounds(
 +                        db,
 +                        &type_.derived(ty.clone()),
 +                        bounds.bounds.skip_binders().interned(),
 +                        cb,
 +                    );
 +                }
 +
 +                TyKind::Ref(_, _, ty)
 +                | TyKind::Raw(_, ty)
 +                | TyKind::Array(ty, _)
 +                | TyKind::Slice(ty) => {
 +                    walk_type(db, &type_.derived(ty.clone()), cb);
 +                }
 +
 +                TyKind::FnDef(_, substs)
 +                | TyKind::Tuple(_, substs)
 +                | TyKind::Closure(.., substs) => {
 +                    walk_substs(db, type_, substs, cb);
 +                }
 +                TyKind::Function(hir_ty::FnPointer { substitution, .. }) => {
 +                    walk_substs(db, type_, &substitution.0, cb);
 +                }
 +
 +                _ => {}
 +            }
 +        }
 +
 +        walk_type(db, self, &mut cb);
 +    }
 +
 +    pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
 +        let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
 +        hir_ty::could_unify(db, self.env.clone(), &tys)
 +    }
 +
 +    pub fn could_coerce_to(&self, db: &dyn HirDatabase, to: &Type) -> bool {
 +        let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), to.ty.clone()));
 +        hir_ty::could_coerce(db, self.env.clone(), &tys)
 +    }
 +
 +    pub fn as_type_param(&self, db: &dyn HirDatabase) -> Option<TypeParam> {
 +        match self.ty.kind(Interner) {
 +            TyKind::Placeholder(p) => Some(TypeParam {
 +                id: TypeParamId::from_unchecked(hir_ty::from_placeholder_idx(db, *p)),
 +            }),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub struct Callable {
 +    ty: Type,
 +    sig: CallableSig,
 +    callee: Callee,
 +    pub(crate) is_bound_method: bool,
 +}
 +
 +#[derive(Debug)]
 +enum Callee {
 +    Def(CallableDefId),
 +    Closure(ClosureId),
 +    FnPtr,
 +}
 +
 +pub enum CallableKind {
 +    Function(Function),
 +    TupleStruct(Struct),
 +    TupleEnumVariant(Variant),
 +    Closure,
 +    FnPtr,
 +}
 +
 +impl Callable {
 +    pub fn kind(&self) -> CallableKind {
 +        use Callee::*;
 +        match self.callee {
 +            Def(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()),
 +            Def(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()),
 +            Def(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()),
 +            Closure(_) => CallableKind::Closure,
 +            FnPtr => CallableKind::FnPtr,
 +        }
 +    }
 +    pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> {
 +        let func = match self.callee {
 +            Callee::Def(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
 +            _ => return None,
 +        };
 +        let src = func.lookup(db.upcast()).source(db.upcast());
 +        let param_list = src.value.param_list()?;
 +        param_list.self_param()
 +    }
 +    pub fn n_params(&self) -> usize {
 +        self.sig.params().len() - if self.is_bound_method { 1 } else { 0 }
 +    }
 +    pub fn params(
 +        &self,
 +        db: &dyn HirDatabase,
 +    ) -> Vec<(Option<Either<ast::SelfParam, ast::Pat>>, Type)> {
 +        let types = self
 +            .sig
 +            .params()
 +            .iter()
 +            .skip(if self.is_bound_method { 1 } else { 0 })
 +            .map(|ty| self.ty.derived(ty.clone()));
 +        let map_param = |it: ast::Param| it.pat().map(Either::Right);
 +        let patterns = match self.callee {
 +            Callee::Def(CallableDefId::FunctionId(func)) => {
 +                let src = func.lookup(db.upcast()).source(db.upcast());
 +                src.value.param_list().map(|param_list| {
 +                    param_list
 +                        .self_param()
 +                        .map(|it| Some(Either::Left(it)))
 +                        .filter(|_| !self.is_bound_method)
 +                        .into_iter()
 +                        .chain(param_list.params().map(map_param))
 +                })
 +            }
 +            Callee::Closure(closure_id) => match closure_source(db, closure_id) {
 +                Some(src) => src.param_list().map(|param_list| {
 +                    param_list
 +                        .self_param()
 +                        .map(|it| Some(Either::Left(it)))
 +                        .filter(|_| !self.is_bound_method)
 +                        .into_iter()
 +                        .chain(param_list.params().map(map_param))
 +                }),
 +                None => None,
 +            },
 +            _ => None,
 +        };
 +        patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect()
 +    }
 +    pub fn return_type(&self) -> Type {
 +        self.ty.derived(self.sig.ret().clone())
 +    }
 +}
 +
 +fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option<ast::ClosureExpr> {
 +    let (owner, expr_id) = db.lookup_intern_closure(closure.into());
 +    let (_, source_map) = db.body_with_source_map(owner);
 +    let ast = source_map.expr_syntax(expr_id).ok()?;
 +    let root = ast.file_syntax(db.upcast());
 +    let expr = ast.value.to_node(&root);
 +    match expr {
 +        ast::Expr::ClosureExpr(it) => Some(it),
 +        _ => None,
 +    }
 +}
 +
 +#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 +pub enum BindingMode {
 +    Move,
 +    Ref(Mutability),
 +}
 +
 +/// For IDE only
 +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 +pub enum ScopeDef {
 +    ModuleDef(ModuleDef),
 +    GenericParam(GenericParam),
 +    ImplSelfType(Impl),
 +    AdtSelfType(Adt),
 +    Local(Local),
 +    Label(Label),
 +    Unknown,
 +}
 +
 +impl ScopeDef {
 +    pub fn all_items(def: PerNs) -> ArrayVec<Self, 3> {
 +        let mut items = ArrayVec::new();
 +
 +        match (def.take_types(), def.take_values()) {
 +            (Some(m1), None) => items.push(ScopeDef::ModuleDef(m1.into())),
 +            (None, Some(m2)) => items.push(ScopeDef::ModuleDef(m2.into())),
 +            (Some(m1), Some(m2)) => {
 +                // Some items, like unit structs and enum variants, are
 +                // returned as both a type and a value. Here we want
 +                // to de-duplicate them.
 +                if m1 != m2 {
 +                    items.push(ScopeDef::ModuleDef(m1.into()));
 +                    items.push(ScopeDef::ModuleDef(m2.into()));
 +                } else {
 +                    items.push(ScopeDef::ModuleDef(m1.into()));
 +                }
 +            }
 +            (None, None) => {}
 +        };
 +
 +        if let Some(macro_def_id) = def.take_macros() {
 +            items.push(ScopeDef::ModuleDef(ModuleDef::Macro(macro_def_id.into())));
 +        }
 +
 +        if items.is_empty() {
 +            items.push(ScopeDef::Unknown);
 +        }
 +
 +        items
 +    }
 +
 +    pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
 +        match self {
 +            ScopeDef::ModuleDef(it) => it.attrs(db),
 +            ScopeDef::GenericParam(it) => Some(it.attrs(db)),
 +            ScopeDef::ImplSelfType(_)
 +            | ScopeDef::AdtSelfType(_)
 +            | ScopeDef::Local(_)
 +            | ScopeDef::Label(_)
 +            | ScopeDef::Unknown => None,
 +        }
 +    }
 +
 +    pub fn krate(&self, db: &dyn HirDatabase) -> Option<Crate> {
 +        match self {
 +            ScopeDef::ModuleDef(it) => it.module(db).map(|m| m.krate()),
 +            ScopeDef::GenericParam(it) => Some(it.module(db).krate()),
 +            ScopeDef::ImplSelfType(_) => None,
 +            ScopeDef::AdtSelfType(it) => Some(it.module(db).krate()),
 +            ScopeDef::Local(it) => Some(it.module(db).krate()),
 +            ScopeDef::Label(it) => Some(it.module(db).krate()),
 +            ScopeDef::Unknown => None,
 +        }
 +    }
 +}
 +
 +impl From<ItemInNs> for ScopeDef {
 +    fn from(item: ItemInNs) -> Self {
 +        match item {
 +            ItemInNs::Types(id) => ScopeDef::ModuleDef(id),
 +            ItemInNs::Values(id) => ScopeDef::ModuleDef(id),
 +            ItemInNs::Macros(id) => ScopeDef::ModuleDef(ModuleDef::Macro(id)),
 +        }
 +    }
 +}
 +
 +pub trait HasVisibility {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility;
 +    fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool {
 +        let vis = self.visibility(db);
 +        vis.is_visible_from(db.upcast(), module.id)
 +    }
 +}
 +
 +/// Trait for obtaining the defining crate of an item.
 +pub trait HasCrate {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate;
 +}
 +
 +impl<T: hir_def::HasModule> HasCrate for T {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db.upcast()).krate().into()
 +    }
 +}
 +
 +impl HasCrate for AssocItem {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Struct {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Union {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Field {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.parent_def(db).module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Variant {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Function {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Const {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for TypeAlias {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Type {
 +    fn krate(&self, _db: &dyn HirDatabase) -> Crate {
 +        self.env.krate.into()
 +    }
 +}
 +
 +impl HasCrate for Macro {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Trait {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Static {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Adt {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Module {
 +    fn krate(&self, _: &dyn HirDatabase) -> Crate {
 +        Module::krate(*self)
 +    }
 +}
index fca09d384c6efcea3a1ea987629bd6a8c7b319f7,0000000000000000000000000000000000000000..57a41f3d9a9378faa7c03994b83e53be9fdfc229
mode 100644,000000..100644
--- /dev/null
@@@ -1,31 -1,0 +1,31 @@@
- itertools = "0.10.3"
 +[package]
 +name = "ide-assists"
 +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.5"
 +either = "1.7.0"
 +
 +stdx = { path = "../stdx", version = "0.0.0" }
 +syntax = { path = "../syntax", version = "0.0.0" }
 +text-edit = { path = "../text-edit", version = "0.0.0" }
 +profile = { path = "../profile", version = "0.0.0" }
 +ide-db = { path = "../ide-db", version = "0.0.0" }
 +hir = { path = "../hir", version = "0.0.0" }
 +
 +[dev-dependencies]
 +test-utils = { path = "../test-utils" }
 +sourcegen = { path = "../sourcegen" }
 +expect-test = "1.4.0"
 +
 +[features]
 +in-rust-tree = []
index e257218ba937686275d3c8f78f998d0f49e4d073,0000000000000000000000000000000000000000..678dc877d1381c69028953ac882dedc9d606b1e1
mode 100644,000000..100644
--- /dev/null
@@@ -1,1295 -1,0 +1,1311 @@@
 +use std::cmp::Reverse;
 +
 +use hir::{db::HirDatabase, Module};
 +use ide_db::{
 +    helpers::mod_path_to_ast,
 +    imports::{
 +        import_assets::{ImportAssets, ImportCandidate, LocatedImport},
 +        insert_use::{insert_use, ImportScope},
 +    },
 +};
 +use syntax::{ast, AstNode, NodeOrToken, SyntaxElement};
 +
 +use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
 +
 +// Feature: Auto Import
 +//
 +// Using the `auto-import` assist it is possible to insert missing imports for unresolved items.
 +// When inserting an import it will do so in a structured manner by keeping imports grouped,
 +// separated by a newline in the following order:
 +//
 +// - `std` and `core`
 +// - External Crates
 +// - Current Crate, paths prefixed by `crate`
 +// - Current Module, paths prefixed by `self`
 +// - Super Module, paths prefixed by `super`
 +//
 +// Example:
 +// ```rust
 +// use std::fs::File;
 +//
 +// use itertools::Itertools;
 +// use syntax::ast;
 +//
 +// use crate::utils::insert_use;
 +//
 +// use self::auto_import;
 +//
 +// use super::AssistContext;
 +// ```
 +//
 +// .Import Granularity
 +//
 +// It is possible to configure how use-trees are merged with the `imports.granularity.group` setting.
 +// It has the following configurations:
 +//
 +// - `crate`: Merge imports from the same crate into a single use statement. This kind of
 +//  nesting is only supported in Rust versions later than 1.24.
 +// - `module`: Merge imports from the same module into a single use statement.
 +// - `item`: Don't merge imports at all, creating one import per item.
 +// - `preserve`: Do not change the granularity of any imports. For auto-import this has the same
 +//  effect as `item`.
 +//
 +// In `VS Code` the configuration for this is `rust-analyzer.imports.granularity.group`.
 +//
 +// .Import Prefix
 +//
 +// The style of imports in the same crate is configurable through the `imports.prefix` setting.
 +// It has the following configurations:
 +//
 +// - `crate`: This setting will force paths to be always absolute, starting with the `crate`
 +//  prefix, unless the item is defined outside of the current crate.
 +// - `self`: This setting will force paths that are relative to the current module to always
 +//  start with `self`. This will result in paths that always start with either `crate`, `self`,
 +//  `super` or an extern crate identifier.
 +// - `plain`: This setting does not impose any restrictions in imports.
 +//
 +// In `VS Code` the configuration for this is `rust-analyzer.imports.prefix`.
 +//
 +// image::https://user-images.githubusercontent.com/48062697/113020673-b85be580-917a-11eb-9022-59585f35d4f8.gif[]
 +
 +// Assist: auto_import
 +//
 +// If the name is unresolved, provides all possible imports for it.
 +//
 +// ```
 +// fn main() {
 +//     let map = HashMap$0::new();
 +// }
 +// # pub mod std { pub mod collections { pub struct HashMap { } } }
 +// ```
 +// ->
 +// ```
 +// use std::collections::HashMap;
 +//
 +// fn main() {
 +//     let map = HashMap::new();
 +// }
 +// # pub mod std { pub mod collections { pub struct HashMap { } } }
 +// ```
 +pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
 +    let mut proposed_imports = import_assets.search_for_imports(
 +        &ctx.sema,
 +        ctx.config.insert_use.prefix_kind,
 +        ctx.config.prefer_no_std,
 +    );
 +    if proposed_imports.is_empty() {
 +        return None;
 +    }
 +
 +    let range = match &syntax_under_caret {
 +        NodeOrToken::Node(node) => ctx.sema.original_range(node).range,
 +        NodeOrToken::Token(token) => token.text_range(),
 +    };
 +    let group_label = group_label(import_assets.import_candidate());
 +    let scope = ImportScope::find_insert_use_container(
 +        &match syntax_under_caret {
 +            NodeOrToken::Node(it) => it,
 +            NodeOrToken::Token(it) => it.parent()?,
 +        },
 +        &ctx.sema,
 +    )?;
 +
 +    // we aren't interested in different namespaces
 +    proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
 +
 +    let current_node = match ctx.covering_element() {
 +        NodeOrToken::Node(node) => Some(node),
 +        NodeOrToken::Token(token) => token.parent(),
 +    };
 +
 +    let current_module =
 +        current_node.as_ref().and_then(|node| ctx.sema.scope(node)).map(|scope| scope.module());
 +
 +    // prioritize more relevant imports
 +    proposed_imports
 +        .sort_by_key(|import| Reverse(relevance_score(ctx, import, current_module.as_ref())));
 +
 +    for import in proposed_imports {
 +        acc.add_group(
 +            &group_label,
 +            AssistId("auto_import", AssistKind::QuickFix),
 +            format!("Import `{}`", import.import_path),
 +            range,
 +            |builder| {
 +                let scope = match scope.clone() {
 +                    ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
 +                    ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
 +                    ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
 +                };
 +                insert_use(&scope, mod_path_to_ast(&import.import_path), &ctx.config.insert_use);
 +            },
 +        );
 +    }
 +    Some(())
 +}
 +
 +pub(super) fn find_importable_node(
 +    ctx: &AssistContext<'_>,
 +) -> Option<(ImportAssets, SyntaxElement)> {
 +    if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
 +        ImportAssets::for_exact_path(&path_under_caret, &ctx.sema)
 +            .zip(Some(path_under_caret.syntax().clone().into()))
 +    } else if let Some(method_under_caret) =
 +        ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
 +    {
 +        ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
 +            .zip(Some(method_under_caret.syntax().clone().into()))
++    } else if let Some(_) = ctx.find_node_at_offset_with_descend::<ast::Param>() {
++        None
 +    } else if let Some(pat) = ctx
 +        .find_node_at_offset_with_descend::<ast::IdentPat>()
 +        .filter(ast::IdentPat::is_simple_ident)
 +    {
 +        ImportAssets::for_ident_pat(&ctx.sema, &pat).zip(Some(pat.syntax().clone().into()))
 +    } else {
 +        None
 +    }
 +}
 +
 +fn group_label(import_candidate: &ImportCandidate) -> GroupLabel {
 +    let name = match import_candidate {
 +        ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
 +        ImportCandidate::TraitAssocItem(candidate) => {
 +            format!("Import a trait for item {}", candidate.assoc_item_name.text())
 +        }
 +        ImportCandidate::TraitMethod(candidate) => {
 +            format!("Import a trait for method {}", candidate.assoc_item_name.text())
 +        }
 +    };
 +    GroupLabel(name)
 +}
 +
 +/// Determine how relevant a given import is in the current context. Higher scores are more
 +/// relevant.
 +fn relevance_score(
 +    ctx: &AssistContext<'_>,
 +    import: &LocatedImport,
 +    current_module: Option<&Module>,
 +) -> i32 {
 +    let mut score = 0;
 +
 +    let db = ctx.db();
 +
 +    let item_module = match import.item_to_import {
 +        hir::ItemInNs::Types(item) | hir::ItemInNs::Values(item) => item.module(db),
 +        hir::ItemInNs::Macros(makro) => Some(makro.module(db)),
 +    };
 +
 +    match item_module.zip(current_module) {
 +        // get the distance between the imported path and the current module
 +        // (prefer items that are more local)
 +        Some((item_module, current_module)) => {
 +            score -= module_distance_hueristic(db, &current_module, &item_module) as i32;
 +        }
 +
 +        // could not find relevant modules, so just use the length of the path as an estimate
 +        None => return -(2 * import.import_path.len() as i32),
 +    }
 +
 +    score
 +}
 +
 +/// A heuristic that gives a higher score to modules that are more separated.
 +fn module_distance_hueristic(db: &dyn HirDatabase, current: &Module, item: &Module) -> usize {
 +    // get the path starting from the item to the respective crate roots
 +    let mut current_path = current.path_to_root(db);
 +    let mut item_path = item.path_to_root(db);
 +
 +    // we want paths going from the root to the item
 +    current_path.reverse();
 +    item_path.reverse();
 +
 +    // length of the common prefix of the two paths
 +    let prefix_length = current_path.iter().zip(&item_path).take_while(|(a, b)| a == b).count();
 +
 +    // how many modules differ between the two paths (all modules, removing any duplicates)
 +    let distinct_length = current_path.len() + item_path.len() - 2 * prefix_length;
 +
 +    // cost of importing from another crate
 +    let crate_boundary_cost = if current.krate() == item.krate() {
 +        0
 +    } else if item.krate().is_builtin(db) {
 +        2
 +    } else {
 +        4
 +    };
 +
 +    distinct_length + crate_boundary_cost
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use super::*;
 +
 +    use hir::Semantics;
 +    use ide_db::{
 +        assists::AssistResolveStrategy,
 +        base_db::{fixture::WithFixture, FileRange},
 +        RootDatabase,
 +    };
 +
 +    use crate::tests::{
 +        check_assist, check_assist_not_applicable, check_assist_target, TEST_CONFIG,
 +    };
 +
 +    fn check_auto_import_order(before: &str, order: &[&str]) {
 +        let (db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(before);
 +        let frange = FileRange { file_id, range: range_or_offset.into() };
 +
 +        let sema = Semantics::new(&db);
 +        let config = TEST_CONFIG;
 +        let ctx = AssistContext::new(sema, &config, frange);
 +        let mut acc = Assists::new(&ctx, AssistResolveStrategy::All);
 +        auto_import(&mut acc, &ctx);
 +        let assists = acc.finish();
 +
 +        let labels = assists.iter().map(|assist| assist.label.to_string()).collect::<Vec<_>>();
 +
 +        assert_eq!(labels, order);
 +    }
 +
++    #[test]
++    fn ignore_parameter_name() {
++        check_assist_not_applicable(
++            auto_import,
++            r"
++            mod foo {
++                pub mod bar {}
++            }
++
++            fn foo(bar$0: &str) {}
++            ",
++        );
++    }
++
 +    #[test]
 +    fn prefer_shorter_paths() {
 +        let before = r"
 +//- /main.rs crate:main deps:foo,bar
 +HashMap$0::new();
 +
 +//- /lib.rs crate:foo
 +pub mod collections { pub struct HashMap; }
 +
 +//- /lib.rs crate:bar
 +pub mod collections { pub mod hash_map { pub struct HashMap; } }
 +        ";
 +
 +        check_auto_import_order(
 +            before,
 +            &["Import `foo::collections::HashMap`", "Import `bar::collections::hash_map::HashMap`"],
 +        )
 +    }
 +
 +    #[test]
 +    fn prefer_same_crate() {
 +        let before = r"
 +//- /main.rs crate:main deps:foo
 +HashMap$0::new();
 +
 +mod collections {
 +    pub mod hash_map {
 +        pub struct HashMap;
 +    }
 +}
 +
 +//- /lib.rs crate:foo
 +pub struct HashMap;
 +        ";
 +
 +        check_auto_import_order(
 +            before,
 +            &["Import `collections::hash_map::HashMap`", "Import `foo::HashMap`"],
 +        )
 +    }
 +
 +    #[test]
 +    fn not_applicable_if_scope_inside_macro() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +mod bar {
 +    pub struct Baz;
 +}
 +macro_rules! foo {
 +    ($it:ident) => {
 +        mod __ {
 +            fn __(x: $it) {}
 +        }
 +    };
 +}
 +foo! {
 +    Baz$0
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn applicable_in_attributes() {
 +        check_assist(
 +            auto_import,
 +            r"
 +//- proc_macros: identity
 +#[proc_macros::identity]
 +mod foo {
 +    mod bar {
 +        const _: Baz$0 = ();
 +    }
 +}
 +mod baz {
 +    pub struct Baz;
 +}
 +",
 +            r"
 +#[proc_macros::identity]
 +mod foo {
 +    mod bar {
 +        use crate::baz::Baz;
 +
 +        const _: Baz = ();
 +    }
 +}
 +mod baz {
 +    pub struct Baz;
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn applicable_when_found_an_import_partial() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            mod std {
 +                pub mod fmt {
 +                    pub struct Formatter;
 +                }
 +            }
 +
 +            use std::fmt;
 +
 +            $0Formatter
 +            ",
 +            r"
 +            mod std {
 +                pub mod fmt {
 +                    pub struct Formatter;
 +                }
 +            }
 +
 +            use std::fmt::{self, Formatter};
 +
 +            Formatter
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn applicable_when_found_an_import() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            $0PubStruct
 +
 +            pub mod PubMod {
 +                pub struct PubStruct;
 +            }
 +            ",
 +            r"
 +            use PubMod::PubStruct;
 +
 +            PubStruct
 +
 +            pub mod PubMod {
 +                pub struct PubStruct;
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn applicable_when_found_an_import_in_macros() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            macro_rules! foo {
 +                ($i:ident) => { fn foo(a: $i) {} }
 +            }
 +            foo!(Pub$0Struct);
 +
 +            pub mod PubMod {
 +                pub struct PubStruct;
 +            }
 +            ",
 +            r"
 +            use PubMod::PubStruct;
 +
 +            macro_rules! foo {
 +                ($i:ident) => { fn foo(a: $i) {} }
 +            }
 +            foo!(PubStruct);
 +
 +            pub mod PubMod {
 +                pub struct PubStruct;
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn applicable_when_found_multiple_imports() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            PubSt$0ruct
 +
 +            pub mod PubMod1 {
 +                pub struct PubStruct;
 +            }
 +            pub mod PubMod2 {
 +                pub struct PubStruct;
 +            }
 +            pub mod PubMod3 {
 +                pub struct PubStruct;
 +            }
 +            ",
 +            r"
 +            use PubMod3::PubStruct;
 +
 +            PubStruct
 +
 +            pub mod PubMod1 {
 +                pub struct PubStruct;
 +            }
 +            pub mod PubMod2 {
 +                pub struct PubStruct;
 +            }
 +            pub mod PubMod3 {
 +                pub struct PubStruct;
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_already_imported_types() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            use PubMod::PubStruct;
 +
 +            PubStruct$0
 +
 +            pub mod PubMod {
 +                pub struct PubStruct;
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_types_with_private_paths() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            PrivateStruct$0
 +
 +            pub mod PubMod {
 +                struct PrivateStruct;
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_when_no_imports_found() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            "
 +            PubStruct$0",
 +        );
 +    }
 +
 +    #[test]
 +    fn function_import() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            test_function$0
 +
 +            pub mod PubMod {
 +                pub fn test_function() {};
 +            }
 +            ",
 +            r"
 +            use PubMod::test_function;
 +
 +            test_function
 +
 +            pub mod PubMod {
 +                pub fn test_function() {};
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn macro_import() {
 +        check_assist(
 +            auto_import,
 +            r"
 +//- /lib.rs crate:crate_with_macro
 +#[macro_export]
 +macro_rules! foo {
 +    () => ()
 +}
 +
 +//- /main.rs crate:main deps:crate_with_macro
 +fn main() {
 +    foo$0
 +}
 +",
 +            r"use crate_with_macro::foo;
 +
 +fn main() {
 +    foo
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn auto_import_target() {
 +        check_assist_target(
 +            auto_import,
 +            r"
 +            struct AssistInfo {
 +                group_label: Option<$0GroupLabel>,
 +            }
 +
 +            mod m { pub struct GroupLabel; }
 +            ",
 +            "GroupLabel",
 +        )
 +    }
 +
 +    #[test]
 +    fn not_applicable_when_path_start_is_imported() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            pub mod mod1 {
 +                pub mod mod2 {
 +                    pub mod mod3 {
 +                        pub struct TestStruct;
 +                    }
 +                }
 +            }
 +
 +            use mod1::mod2;
 +            fn main() {
 +                mod2::mod3::TestStruct$0
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_imported_function() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            pub mod test_mod {
 +                pub fn test_function() {}
 +            }
 +
 +            use test_mod::test_function;
 +            fn main() {
 +                test_function$0
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn associated_struct_function() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub struct TestStruct {}
 +                impl TestStruct {
 +                    pub fn test_function() {}
 +                }
 +            }
 +
 +            fn main() {
 +                TestStruct::test_function$0
 +            }
 +            ",
 +            r"
 +            use test_mod::TestStruct;
 +
 +            mod test_mod {
 +                pub struct TestStruct {}
 +                impl TestStruct {
 +                    pub fn test_function() {}
 +                }
 +            }
 +
 +            fn main() {
 +                TestStruct::test_function
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn associated_struct_const() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub struct TestStruct {}
 +                impl TestStruct {
 +                    const TEST_CONST: u8 = 42;
 +                }
 +            }
 +
 +            fn main() {
 +                TestStruct::TEST_CONST$0
 +            }
 +            ",
 +            r"
 +            use test_mod::TestStruct;
 +
 +            mod test_mod {
 +                pub struct TestStruct {}
 +                impl TestStruct {
 +                    const TEST_CONST: u8 = 42;
 +                }
 +            }
 +
 +            fn main() {
 +                TestStruct::TEST_CONST
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn associated_trait_function() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_function();
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_function() {}
 +                }
 +            }
 +
 +            fn main() {
 +                test_mod::TestStruct::test_function$0
 +            }
 +            ",
 +            r"
 +            use test_mod::TestTrait;
 +
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_function();
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_function() {}
 +                }
 +            }
 +
 +            fn main() {
 +                test_mod::TestStruct::test_function
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_imported_trait_for_function() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_function();
 +                }
 +                pub trait TestTrait2 {
 +                    fn test_function();
 +                }
 +                pub enum TestEnum {
 +                    One,
 +                    Two,
 +                }
 +                impl TestTrait2 for TestEnum {
 +                    fn test_function() {}
 +                }
 +                impl TestTrait for TestEnum {
 +                    fn test_function() {}
 +                }
 +            }
 +
 +            use test_mod::TestTrait2;
 +            fn main() {
 +                test_mod::TestEnum::test_function$0;
 +            }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn associated_trait_const() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    const TEST_CONST: u8;
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    const TEST_CONST: u8 = 42;
 +                }
 +            }
 +
 +            fn main() {
 +                test_mod::TestStruct::TEST_CONST$0
 +            }
 +            ",
 +            r"
 +            use test_mod::TestTrait;
 +
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    const TEST_CONST: u8;
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    const TEST_CONST: u8 = 42;
 +                }
 +            }
 +
 +            fn main() {
 +                test_mod::TestStruct::TEST_CONST
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_imported_trait_for_const() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    const TEST_CONST: u8;
 +                }
 +                pub trait TestTrait2 {
 +                    const TEST_CONST: f64;
 +                }
 +                pub enum TestEnum {
 +                    One,
 +                    Two,
 +                }
 +                impl TestTrait2 for TestEnum {
 +                    const TEST_CONST: f64 = 42.0;
 +                }
 +                impl TestTrait for TestEnum {
 +                    const TEST_CONST: u8 = 42;
 +                }
 +            }
 +
 +            use test_mod::TestTrait2;
 +            fn main() {
 +                test_mod::TestEnum::TEST_CONST$0;
 +            }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn trait_method() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_method(&self);
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_method(&self) {}
 +                }
 +            }
 +
 +            fn main() {
 +                let test_struct = test_mod::TestStruct {};
 +                test_struct.test_meth$0od()
 +            }
 +            ",
 +            r"
 +            use test_mod::TestTrait;
 +
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_method(&self);
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_method(&self) {}
 +                }
 +            }
 +
 +            fn main() {
 +                let test_struct = test_mod::TestStruct {};
 +                test_struct.test_method()
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn trait_method_cross_crate() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            //- /main.rs crate:main deps:dep
 +            fn main() {
 +                let test_struct = dep::test_mod::TestStruct {};
 +                test_struct.test_meth$0od()
 +            }
 +            //- /dep.rs crate:dep
 +            pub mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_method(&self);
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_method(&self) {}
 +                }
 +            }
 +            ",
 +            r"
 +            use dep::test_mod::TestTrait;
 +
 +            fn main() {
 +                let test_struct = dep::test_mod::TestStruct {};
 +                test_struct.test_method()
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn assoc_fn_cross_crate() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            //- /main.rs crate:main deps:dep
 +            fn main() {
 +                dep::test_mod::TestStruct::test_func$0tion
 +            }
 +            //- /dep.rs crate:dep
 +            pub mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_function();
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_function() {}
 +                }
 +            }
 +            ",
 +            r"
 +            use dep::test_mod::TestTrait;
 +
 +            fn main() {
 +                dep::test_mod::TestStruct::test_function
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn assoc_const_cross_crate() {
 +        check_assist(
 +            auto_import,
 +            r"
 +            //- /main.rs crate:main deps:dep
 +            fn main() {
 +                dep::test_mod::TestStruct::CONST$0
 +            }
 +            //- /dep.rs crate:dep
 +            pub mod test_mod {
 +                pub trait TestTrait {
 +                    const CONST: bool;
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    const CONST: bool = true;
 +                }
 +            }
 +            ",
 +            r"
 +            use dep::test_mod::TestTrait;
 +
 +            fn main() {
 +                dep::test_mod::TestStruct::CONST
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn assoc_fn_as_method_cross_crate() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            //- /main.rs crate:main deps:dep
 +            fn main() {
 +                let test_struct = dep::test_mod::TestStruct {};
 +                test_struct.test_func$0tion()
 +            }
 +            //- /dep.rs crate:dep
 +            pub mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_function();
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_function() {}
 +                }
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn private_trait_cross_crate() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            //- /main.rs crate:main deps:dep
 +            fn main() {
 +                let test_struct = dep::test_mod::TestStruct {};
 +                test_struct.test_meth$0od()
 +            }
 +            //- /dep.rs crate:dep
 +            pub mod test_mod {
 +                trait TestTrait {
 +                    fn test_method(&self);
 +                }
 +                pub struct TestStruct {}
 +                impl TestTrait for TestStruct {
 +                    fn test_method(&self) {}
 +                }
 +            }
 +            ",
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_imported_trait_for_method() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +            mod test_mod {
 +                pub trait TestTrait {
 +                    fn test_method(&self);
 +                }
 +                pub trait TestTrait2 {
 +                    fn test_method(&self);
 +                }
 +                pub enum TestEnum {
 +                    One,
 +                    Two,
 +                }
 +                impl TestTrait2 for TestEnum {
 +                    fn test_method(&self) {}
 +                }
 +                impl TestTrait for TestEnum {
 +                    fn test_method(&self) {}
 +                }
 +            }
 +
 +            use test_mod::TestTrait2;
 +            fn main() {
 +                let one = test_mod::TestEnum::One;
 +                one.test$0_method();
 +            }
 +            ",
 +        )
 +    }
 +
 +    #[test]
 +    fn dep_import() {
 +        check_assist(
 +            auto_import,
 +            r"
 +//- /lib.rs crate:dep
 +pub struct Struct;
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    Struct$0
 +}
 +",
 +            r"use dep::Struct;
 +
 +fn main() {
 +    Struct
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn whole_segment() {
 +        // Tests that only imports whose last segment matches the identifier get suggested.
 +        check_assist(
 +            auto_import,
 +            r"
 +//- /lib.rs crate:dep
 +pub mod fmt {
 +    pub trait Display {}
 +}
 +
 +pub fn panic_fmt() {}
 +
 +//- /main.rs crate:main deps:dep
 +struct S;
 +
 +impl f$0mt::Display for S {}
 +",
 +            r"use dep::fmt;
 +
 +struct S;
 +
 +impl fmt::Display for S {}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn macro_generated() {
 +        // Tests that macro-generated items are suggested from external crates.
 +        check_assist(
 +            auto_import,
 +            r"
 +//- /lib.rs crate:dep
 +macro_rules! mac {
 +    () => {
 +        pub struct Cheese;
 +    };
 +}
 +
 +mac!();
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    Cheese$0;
 +}
 +",
 +            r"use dep::Cheese;
 +
 +fn main() {
 +    Cheese;
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn casing() {
 +        // Tests that differently cased names don't interfere and we only suggest the matching one.
 +        check_assist(
 +            auto_import,
 +            r"
 +//- /lib.rs crate:dep
 +pub struct FMT;
 +pub struct fmt;
 +
 +//- /main.rs crate:main deps:dep
 +fn main() {
 +    FMT$0;
 +}
 +",
 +            r"use dep::FMT;
 +
 +fn main() {
 +    FMT;
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn inner_items() {
 +        check_assist(
 +            auto_import,
 +            r#"
 +mod baz {
 +    pub struct Foo {}
 +}
 +
 +mod bar {
 +    fn bar() {
 +        Foo$0;
 +        println!("Hallo");
 +    }
 +}
 +"#,
 +            r#"
 +mod baz {
 +    pub struct Foo {}
 +}
 +
 +mod bar {
 +    use crate::baz::Foo;
 +
 +    fn bar() {
 +        Foo;
 +        println!("Hallo");
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn uses_abs_path_with_extern_crate_clash() {
 +        cov_mark::check!(ambiguous_crate_start);
 +        check_assist(
 +            auto_import,
 +            r#"
 +//- /main.rs crate:main deps:foo
 +mod foo {}
 +
 +const _: () = {
 +    Foo$0
 +};
 +//- /foo.rs crate:foo
 +pub struct Foo
 +"#,
 +            r#"
 +use ::foo::Foo;
 +
 +mod foo {}
 +
 +const _: () = {
 +    Foo
 +};
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn works_on_ident_patterns() {
 +        check_assist(
 +            auto_import,
 +            r#"
 +mod foo {
 +    pub struct Foo {}
 +}
 +fn foo() {
 +    let Foo$0;
 +}
 +"#,
 +            r#"
 +use foo::Foo;
 +
 +mod foo {
 +    pub struct Foo {}
 +}
 +fn foo() {
 +    let Foo;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn works_in_derives() {
 +        check_assist(
 +            auto_import,
 +            r#"
 +//- minicore:derive
 +mod foo {
 +    #[rustc_builtin_macro]
 +    pub macro Copy {}
 +}
 +#[derive(Copy$0)]
 +struct Foo;
 +"#,
 +            r#"
 +use foo::Copy;
 +
 +mod foo {
 +    #[rustc_builtin_macro]
 +    pub macro Copy {}
 +}
 +#[derive(Copy)]
 +struct Foo;
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn works_in_use_start() {
 +        check_assist(
 +            auto_import,
 +            r#"
 +mod bar {
 +    pub mod foo {
 +        pub struct Foo;
 +    }
 +}
 +use foo$0::Foo;
 +"#,
 +            r#"
 +mod bar {
 +    pub mod foo {
 +        pub struct Foo;
 +    }
 +}
 +use bar::foo;
 +use foo::Foo;
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_in_non_start_use() {
 +        check_assist_not_applicable(
 +            auto_import,
 +            r"
 +mod bar {
 +    pub mod foo {
 +        pub struct Foo;
 +    }
 +}
 +use foo::Foo$0;
 +",
 +        );
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8d11e0bac9413f24b8dcfbc72faff73e0bd602ef
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,822 @@@
++use either::Either;
++use ide_db::defs::Definition;
++use itertools::Itertools;
++use syntax::{
++    ast::{self, AstNode, HasGenericParams, HasVisibility},
++    match_ast, SyntaxKind, SyntaxNode,
++};
++
++use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists};
++
++// Assist: convert_named_struct_to_tuple_struct
++//
++// Converts struct with named fields to tuple struct, and analogously for enum variants with named
++// fields.
++//
++// ```
++// struct Point$0 { x: f32, y: f32 }
++//
++// impl Point {
++//     pub fn new(x: f32, y: f32) -> Self {
++//         Point { x, y }
++//     }
++//
++//     pub fn x(&self) -> f32 {
++//         self.x
++//     }
++//
++//     pub fn y(&self) -> f32 {
++//         self.y
++//     }
++// }
++// ```
++// ->
++// ```
++// struct Point(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
++//     }
++// }
++// ```
++pub(crate) fn convert_named_struct_to_tuple_struct(
++    acc: &mut Assists,
++    ctx: &AssistContext<'_>,
++) -> Option<()> {
++    let strukt = ctx
++        .find_node_at_offset::<ast::Struct>()
++        .map(Either::Left)
++        .or_else(|| ctx.find_node_at_offset::<ast::Variant>().map(Either::Right))?;
++    let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
++    let record_fields = match field_list {
++        ast::FieldList::RecordFieldList(it) => it,
++        ast::FieldList::TupleFieldList(_) => return None,
++    };
++    let strukt_def = match &strukt {
++        Either::Left(s) => Either::Left(ctx.sema.to_def(s)?),
++        Either::Right(v) => Either::Right(ctx.sema.to_def(v)?),
++    };
++    let target = strukt.as_ref().either(|s| s.syntax(), |v| v.syntax()).text_range();
++
++    acc.add(
++        AssistId("convert_named_struct_to_tuple_struct", AssistKind::RefactorRewrite),
++        "Convert to tuple struct",
++        target,
++        |edit| {
++            edit_field_references(ctx, edit, record_fields.fields());
++            edit_struct_references(ctx, edit, strukt_def);
++            edit_struct_def(ctx, edit, &strukt, record_fields);
++        },
++    )
++}
++
++fn edit_struct_def(
++    ctx: &AssistContext<'_>,
++    edit: &mut SourceChangeBuilder,
++    strukt: &Either<ast::Struct, ast::Variant>,
++    record_fields: ast::RecordFieldList,
++) {
++    let tuple_fields = record_fields
++        .fields()
++        .filter_map(|f| Some(ast::make::tuple_field(f.visibility(), f.ty()?)));
++    let tuple_fields = ast::make::tuple_field_list(tuple_fields);
++    let record_fields_text_range = record_fields.syntax().text_range();
++
++    edit.edit_file(ctx.file_id());
++    edit.replace(record_fields_text_range, tuple_fields.syntax().text());
++
++    if let Either::Left(strukt) = strukt {
++        if let Some(w) = strukt.where_clause() {
++            let mut where_clause = w.to_string();
++            if where_clause.ends_with(',') {
++                where_clause.pop();
++            }
++            where_clause.push(';');
++
++            edit.delete(w.syntax().text_range());
++            edit.insert(record_fields_text_range.end(), ast::make::tokens::single_newline().text());
++            edit.insert(record_fields_text_range.end(), where_clause);
++            edit.insert(record_fields_text_range.end(), ast::make::tokens::single_newline().text());
++
++            if let Some(tok) = strukt
++                .generic_param_list()
++                .and_then(|l| l.r_angle_token())
++                .and_then(|tok| tok.next_token())
++                .filter(|tok| tok.kind() == SyntaxKind::WHITESPACE)
++            {
++                edit.delete(tok.text_range());
++            }
++        } else {
++            edit.insert(record_fields_text_range.end(), ";");
++        }
++    }
++
++    if let Some(tok) = record_fields
++        .l_curly_token()
++        .and_then(|tok| tok.prev_token())
++        .filter(|tok| tok.kind() == SyntaxKind::WHITESPACE)
++    {
++        edit.delete(tok.text_range())
++    }
++}
++
++fn edit_struct_references(
++    ctx: &AssistContext<'_>,
++    edit: &mut SourceChangeBuilder,
++    strukt: Either<hir::Struct, hir::Variant>,
++) {
++    let strukt_def = match strukt {
++        Either::Left(s) => Definition::Adt(hir::Adt::Struct(s)),
++        Either::Right(v) => Definition::Variant(v),
++    };
++    let usages = strukt_def.usages(&ctx.sema).include_self_refs().all();
++
++    let edit_node = |edit: &mut SourceChangeBuilder, node: SyntaxNode| -> Option<()> {
++        match_ast! {
++            match node {
++                ast::RecordPat(record_struct_pat) => {
++                    edit.replace(
++                        record_struct_pat.syntax().text_range(),
++                        ast::make::tuple_struct_pat(
++                            record_struct_pat.path()?,
++                            record_struct_pat
++                                .record_pat_field_list()?
++                                .fields()
++                                .filter_map(|pat| pat.pat())
++                        )
++                        .to_string()
++                    );
++                },
++                ast::RecordExpr(record_expr) => {
++                    let path = record_expr.path()?;
++                    let args = record_expr
++                        .record_expr_field_list()?
++                        .fields()
++                        .filter_map(|f| f.expr())
++                        .join(", ");
++
++                    edit.replace(record_expr.syntax().text_range(), format!("{path}({args})"));
++                },
++                _ => return None,
++            }
++        }
++        Some(())
++    };
++
++    for (file_id, refs) in usages {
++        edit.edit_file(file_id);
++        for r in refs {
++            for node in r.name.syntax().ancestors() {
++                if edit_node(edit, node).is_some() {
++                    break;
++                }
++            }
++        }
++    }
++}
++
++fn edit_field_references(
++    ctx: &AssistContext<'_>,
++    edit: &mut SourceChangeBuilder,
++    fields: impl Iterator<Item = ast::RecordField>,
++) {
++    for (index, field) in fields.enumerate() {
++        let field = match ctx.sema.to_def(&field) {
++            Some(it) => it,
++            None => continue,
++        };
++        let def = Definition::Field(field);
++        let usages = def.usages(&ctx.sema).all();
++        for (file_id, refs) in usages {
++            edit.edit_file(file_id);
++            for r in refs {
++                if let Some(name_ref) = r.name.as_name_ref() {
++                    // Only edit the field reference if it's part of a `.field` access
++                    if name_ref.syntax().parent().and_then(ast::FieldExpr::cast).is_some() {
++                        edit.replace(name_ref.syntax().text_range(), index.to_string());
++                    }
++                }
++            }
++        }
++    }
++}
++
++#[cfg(test)]
++mod tests {
++    use crate::tests::{check_assist, check_assist_not_applicable};
++
++    use super::*;
++
++    #[test]
++    fn not_applicable_other_than_record_struct() {
++        check_assist_not_applicable(convert_named_struct_to_tuple_struct, r#"struct Foo$0(u32)"#);
++        check_assist_not_applicable(convert_named_struct_to_tuple_struct, r#"struct Foo$0;"#);
++    }
++
++    #[test]
++    fn convert_simple_struct() {
++        check_assist(
++            convert_named_struct_to_tuple_struct,
++            r#"
++struct Inner;
++struct A$0 { inner: Inner }
++
++impl A {
++    fn new(inner: Inner) -> A {
++        A { inner }
++    }
++
++    fn new_with_default() -> A {
++        A::new(Inner)
++    }
++
++    fn into_inner(self) -> Inner {
++        self.inner
++    }
++}"#,
++            r#"
++struct Inner;
++struct A(Inner);
++
++impl A {
++    fn new(inner: Inner) -> A {
++        A(inner)
++    }
++
++    fn new_with_default() -> A {
++        A::new(Inner)
++    }
++
++    fn into_inner(self) -> Inner {
++        self.0
++    }
++}"#,
++        );
++    }
++
++    #[test]
++    fn convert_struct_referenced_via_self_kw() {
++        check_assist(
++            convert_named_struct_to_tuple_struct,
++            r#"
++struct Inner;
++struct A$0 { inner: Inner }
++
++impl A {
++    fn new(inner: Inner) -> Self {
++        Self { inner }
++    }
++
++    fn new_with_default() -> Self {
++        Self::new(Inner)
++    }
++
++    fn into_inner(self) -> Inner {
++        self.inner
++    }
++}"#,
++            r#"
++struct Inner;
++struct A(Inner);
++
++impl A {
++    fn new(inner: Inner) -> Self {
++        Self(inner)
++    }
++
++    fn new_with_default() -> Self {
++        Self::new(Inner)
++    }
++
++    fn into_inner(self) -> Inner {
++        self.0
++    }
++}"#,
++        );
++    }
++
++    #[test]
++    fn convert_destructured_struct() {
++        check_assist(
++            convert_named_struct_to_tuple_struct,
++            r#"
++struct Inner;
++struct A$0 { inner: Inner }
++
++impl A {
++    fn into_inner(self) -> Inner {
++        let A { inner: a } = self;
++        a
++    }
++
++    fn into_inner_via_self(self) -> Inner {
++        let Self { inner } = self;
++        inner
++    }
++}"#,
++            r#"
++struct Inner;
++struct A(Inner);
++
++impl A {
++    fn into_inner(self) -> Inner {
++        let A(a) = self;
++        a
++    }
++
++    fn into_inner_via_self(self) -> Inner {
++        let Self(inner) = self;
++        inner
++    }
++}"#,
++        );
++    }
++
++    #[test]
++    fn convert_struct_with_visibility() {
++        check_assist(
++            convert_named_struct_to_tuple_struct,
++            r#"
++struct A$0 {
++    pub first: u32,
++    pub(crate) second: u64
++}
++
++impl A {
++    fn new() -> A {
++        A { first: 42, second: 42 }
++    }
++
++    fn into_first(self) -> u32 {
++        self.first
++    }
++
++    fn into_second(self) -> u64 {
++        self.second
++    }
++}"#,
++            r#"
++struct A(pub u32, pub(crate) u64);
++
++impl A {
++    fn new() -> A {
++        A(42, 42)
++    }
++
++    fn into_first(self) -> u32 {
++        self.0
++    }
++
++    fn into_second(self) -> u64 {
++        self.1
++    }
++}"#,
++        );
++    }
++
++    #[test]
++    fn convert_struct_with_wrapped_references() {
++        check_assist(
++            convert_named_struct_to_tuple_struct,
++            r#"
++struct Inner$0 { uint: u32 }
++struct Outer { inner: Inner }
++
++impl Outer {
++    fn new() -> Self {
++        Self { inner: Inner { uint: 42 } }
++    }
++
++    fn into_inner(self) -> u32 {
++        self.inner.uint
++    }
++
++    fn into_inner_destructed(self) -> u32 {
++        let Outer { inner: Inner { uint: x } } = self;
++        x
++    }
++}"#,
++            r#"
++struct Inner(u32);
++struct Outer { inner: Inner }
++
++impl Outer {
++    fn new() -> Self {
++        Self { inner: Inner(42) }
++    }
++
++    fn into_inner(self) -> u32 {
++        self.inner.0
++    }
++
++    fn into_inner_destructed(self) -> u32 {
++        let Outer { inner: Inner(x) } = self;
++        x
++    }
++}"#,
++        );
++
++        check_assist(
++            convert_named_struct_to_tuple_struct,
++            r#"
++struct Inner { uint: u32 }
++struct Outer$0 { inner: Inner }
++
++impl Outer {
++    fn new() -> Self {
++        Self { inner: Inner { uint: 42 } }
++    }
++
++    fn into_inner(self) -> u32 {
++        self.inner.uint
++    }
++
++    fn into_inner_destructed(self) -> u32 {
++        let Outer { inner: Inner { uint: x } } = self;
++        x
++    }
++}"#,
++            r#"
++struct Inner { uint: u32 }
++struct Outer(Inner);
++
++impl Outer {
++    fn new() -> Self {
++        Self(Inner { uint: 42 })
++    }
++
++    fn into_inner(self) -> u32 {
++        self.0.uint
++    }
++
++    fn into_inner_destructed(self) -> u32 {
++        let Outer(Inner { uint: x }) = self;
++        x
++    }
++}"#,
++        );
++    }
++
++    #[test]
++    fn convert_struct_with_multi_file_references() {
++        check_assist(
++            convert_named_struct_to_tuple_struct,
++            r#"
++//- /main.rs
++struct Inner;
++struct A$0 { inner: Inner }
++
++mod foo;
++
++//- /foo.rs
++use crate::{A, Inner};
++fn f() {
++    let a = A { inner: Inner };
++}
++"#,
++            r#"
++//- /main.rs
++struct Inner;
++struct A(Inner);
++
++mod foo;
++
++//- /foo.rs
++use crate::{A, Inner};
++fn f() {
++    let a = A(Inner);
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn convert_struct_with_where_clause() {
++        check_assist(
++            convert_named_struct_to_tuple_struct,
++            r#"
++struct Wrap$0<T>
++where
++    T: Display,
++{ field1: T }
++"#,
++            r#"
++struct Wrap<T>(T)
++where
++    T: Display;
++
++"#,
++        );
++    }
++
++    #[test]
++    fn not_applicable_other_than_record_variant() {
++        check_assist_not_applicable(
++            convert_named_struct_to_tuple_struct,
++            r#"enum Enum { Variant$0(usize) };"#,
++        );
++        check_assist_not_applicable(
++            convert_named_struct_to_tuple_struct,
++            r#"enum Enum { Variant$0 }"#,
++        );
++    }
++
++    #[test]
++    fn convert_simple_variant() {
++        check_assist(
++            convert_named_struct_to_tuple_struct,
++            r#"
++enum A {
++    $0Variant { field1: usize },
++}
++
++impl A {
++    fn new(value: usize) -> A {
++        A::Variant { field1: value }
++    }
++
++    fn new_with_default() -> A {
++        A::new(Default::default())
++    }
++
++    fn value(self) -> usize {
++        match self {
++            A::Variant { field1: value } => value,
++        }
++    }
++}"#,
++            r#"
++enum A {
++    Variant(usize),
++}
++
++impl A {
++    fn new(value: usize) -> A {
++        A::Variant(value)
++    }
++
++    fn new_with_default() -> A {
++        A::new(Default::default())
++    }
++
++    fn value(self) -> usize {
++        match self {
++            A::Variant(value) => value,
++        }
++    }
++}"#,
++        );
++    }
++
++    #[test]
++    fn convert_variant_referenced_via_self_kw() {
++        check_assist(
++            convert_named_struct_to_tuple_struct,
++            r#"
++enum A {
++    $0Variant { field1: usize },
++}
++
++impl A {
++    fn new(value: usize) -> A {
++        Self::Variant { field1: value }
++    }
++
++    fn new_with_default() -> A {
++        Self::new(Default::default())
++    }
++
++    fn value(self) -> usize {
++        match self {
++            Self::Variant { field1: value } => value,
++        }
++    }
++}"#,
++            r#"
++enum A {
++    Variant(usize),
++}
++
++impl A {
++    fn new(value: usize) -> A {
++        Self::Variant(value)
++    }
++
++    fn new_with_default() -> A {
++        Self::new(Default::default())
++    }
++
++    fn value(self) -> usize {
++        match self {
++            Self::Variant(value) => value,
++        }
++    }
++}"#,
++        );
++    }
++
++    #[test]
++    fn convert_destructured_variant() {
++        check_assist(
++            convert_named_struct_to_tuple_struct,
++            r#"
++enum A {
++    $0Variant { field1: usize },
++}
++
++impl A {
++    fn into_inner(self) -> usize {
++        let A::Variant { field1: first } = self;
++        first
++    }
++
++    fn into_inner_via_self(self) -> usize {
++        let Self::Variant { field1: first } = self;
++        first
++    }
++}"#,
++            r#"
++enum A {
++    Variant(usize),
++}
++
++impl A {
++    fn into_inner(self) -> usize {
++        let A::Variant(first) = self;
++        first
++    }
++
++    fn into_inner_via_self(self) -> usize {
++        let Self::Variant(first) = self;
++        first
++    }
++}"#,
++        );
++    }
++
++    #[test]
++    fn convert_variant_with_wrapped_references() {
++        check_assist(
++            convert_named_struct_to_tuple_struct,
++            r#"
++enum Inner {
++    $0Variant { field1: usize },
++}
++enum Outer {
++    Variant(Inner),
++}
++
++impl Outer {
++    fn new() -> Self {
++        Self::Variant(Inner::Variant { field1: 42 })
++    }
++
++    fn into_inner_destructed(self) -> u32 {
++        let Outer::Variant(Inner::Variant { field1: x }) = self;
++        x
++    }
++}"#,
++            r#"
++enum Inner {
++    Variant(usize),
++}
++enum Outer {
++    Variant(Inner),
++}
++
++impl Outer {
++    fn new() -> Self {
++        Self::Variant(Inner::Variant(42))
++    }
++
++    fn into_inner_destructed(self) -> u32 {
++        let Outer::Variant(Inner::Variant(x)) = self;
++        x
++    }
++}"#,
++        );
++
++        check_assist(
++            convert_named_struct_to_tuple_struct,
++            r#"
++enum Inner {
++    Variant(usize),
++}
++enum Outer {
++    $0Variant { field1: Inner },
++}
++
++impl Outer {
++    fn new() -> Self {
++        Self::Variant { field1: Inner::Variant(42) }
++    }
++
++    fn into_inner_destructed(self) -> u32 {
++        let Outer::Variant { field1: Inner::Variant(x) } = self;
++        x
++    }
++}"#,
++            r#"
++enum Inner {
++    Variant(usize),
++}
++enum Outer {
++    Variant(Inner),
++}
++
++impl Outer {
++    fn new() -> Self {
++        Self::Variant(Inner::Variant(42))
++    }
++
++    fn into_inner_destructed(self) -> u32 {
++        let Outer::Variant(Inner::Variant(x)) = self;
++        x
++    }
++}"#,
++        );
++    }
++
++    #[test]
++    fn convert_variant_with_multi_file_references() {
++        check_assist(
++            convert_named_struct_to_tuple_struct,
++            r#"
++//- /main.rs
++struct Inner;
++enum A {
++    $0Variant { field1: Inner },
++}
++
++mod foo;
++
++//- /foo.rs
++use crate::{A, Inner};
++fn f() {
++    let a = A::Variant { field1: Inner };
++}
++"#,
++            r#"
++//- /main.rs
++struct Inner;
++enum A {
++    Variant(Inner),
++}
++
++mod foo;
++
++//- /foo.rs
++use crate::{A, Inner};
++fn f() {
++    let a = A::Variant(Inner);
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn convert_directly_used_variant() {
++        check_assist(
++            convert_named_struct_to_tuple_struct,
++            r#"
++//- /main.rs
++struct Inner;
++enum A {
++    $0Variant { field1: Inner },
++}
++
++mod foo;
++
++//- /foo.rs
++use crate::{A::Variant, Inner};
++fn f() {
++    let a = Variant { field1: Inner };
++}
++"#,
++            r#"
++//- /main.rs
++struct Inner;
++enum A {
++    Variant(Inner),
++}
++
++mod foo;
++
++//- /foo.rs
++use crate::{A::Variant, Inner};
++fn f() {
++    let a = Variant(Inner);
++}
++"#,
++        );
++    }
++}
index 8d5cab283d0616d3297e864a782f61e4965975cd,0000000000000000000000000000000000000000..970e948dfd930f4226be3c9697f0e19dead8d044
mode 100644,000000..100644
--- /dev/null
@@@ -1,1098 -1,0 +1,1068 @@@
- use itertools::{Itertools, Position};
 +use std::iter;
 +
 +use either::Either;
 +use hir::{Module, ModuleDef, Name, Variant};
 +use ide_db::{
 +    defs::Definition,
 +    helpers::mod_path_to_ast,
 +    imports::insert_use::{insert_use, ImportScope, InsertUseConfig},
 +    search::FileReference,
 +    FxHashSet, RootDatabase,
 +};
-         .map(|generics| {
-             let mut generic_str = String::with_capacity(8);
-             for (p, more) in generics.generic_params().with_position().map(|p| match p {
-                 Position::First(p) | Position::Middle(p) => (p, true),
-                 Position::Last(p) | Position::Only(p) => (p, false),
-             }) {
-                 match p {
-                     ast::GenericParam::ConstParam(konst) => {
-                         if let Some(name) = konst.name() {
-                             generic_str.push_str(name.text().as_str());
-                         }
-                     }
-                     ast::GenericParam::LifetimeParam(lt) => {
-                         if let Some(lt) = lt.lifetime() {
-                             generic_str.push_str(lt.text().as_str());
-                         }
-                     }
-                     ast::GenericParam::TypeParam(ty) => {
-                         if let Some(name) = ty.name() {
-                             generic_str.push_str(name.text().as_str());
-                         }
-                     }
-                 }
-                 if more {
-                     generic_str.push_str(", ");
-                 }
-             }
-             make::ty(&format!("{}<{}>", &name.text(), &generic_str))
-         })
++use itertools::Itertools;
 +use syntax::{
 +    ast::{
 +        self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, HasAttrs, HasGenericParams,
 +        HasName, HasVisibility,
 +    },
 +    match_ast, ted, SyntaxElement,
 +    SyntaxKind::*,
 +    SyntaxNode, T,
 +};
 +
 +use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists};
 +
 +// Assist: extract_struct_from_enum_variant
 +//
 +// Extracts a struct from enum variant.
 +//
 +// ```
 +// enum A { $0One(u32, u32) }
 +// ```
 +// ->
 +// ```
 +// struct One(u32, u32);
 +//
 +// enum A { One(One) }
 +// ```
 +pub(crate) fn extract_struct_from_enum_variant(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +) -> Option<()> {
 +    let variant = ctx.find_node_at_offset::<ast::Variant>()?;
 +    let field_list = extract_field_list_if_applicable(&variant)?;
 +
 +    let variant_name = variant.name()?;
 +    let variant_hir = ctx.sema.to_def(&variant)?;
 +    if existing_definition(ctx.db(), &variant_name, &variant_hir) {
 +        cov_mark::hit!(test_extract_enum_not_applicable_if_struct_exists);
 +        return None;
 +    }
 +
 +    let enum_ast = variant.parent_enum();
 +    let enum_hir = ctx.sema.to_def(&enum_ast)?;
 +    let target = variant.syntax().text_range();
 +    acc.add(
 +        AssistId("extract_struct_from_enum_variant", AssistKind::RefactorRewrite),
 +        "Extract struct from enum variant",
 +        target,
 +        |builder| {
 +            let variant_hir_name = variant_hir.name(ctx.db());
 +            let enum_module_def = ModuleDef::from(enum_hir);
 +            let usages = Definition::Variant(variant_hir).usages(&ctx.sema).all();
 +
 +            let mut visited_modules_set = FxHashSet::default();
 +            let current_module = enum_hir.module(ctx.db());
 +            visited_modules_set.insert(current_module);
 +            // record file references of the file the def resides in, we only want to swap to the edited file in the builder once
 +            let mut def_file_references = None;
 +            for (file_id, references) in usages {
 +                if file_id == ctx.file_id() {
 +                    def_file_references = Some(references);
 +                    continue;
 +                }
 +                builder.edit_file(file_id);
 +                let processed = process_references(
 +                    ctx,
 +                    builder,
 +                    &mut visited_modules_set,
 +                    &enum_module_def,
 +                    &variant_hir_name,
 +                    references,
 +                );
 +                processed.into_iter().for_each(|(path, node, import)| {
 +                    apply_references(ctx.config.insert_use, path, node, import)
 +                });
 +            }
 +            builder.edit_file(ctx.file_id());
 +
 +            let variant = builder.make_mut(variant.clone());
 +            if let Some(references) = def_file_references {
 +                let processed = process_references(
 +                    ctx,
 +                    builder,
 +                    &mut visited_modules_set,
 +                    &enum_module_def,
 +                    &variant_hir_name,
 +                    references,
 +                );
 +                processed.into_iter().for_each(|(path, node, import)| {
 +                    apply_references(ctx.config.insert_use, path, node, import)
 +                });
 +            }
 +
 +            let generic_params = enum_ast
 +                .generic_param_list()
 +                .and_then(|known_generics| extract_generic_params(&known_generics, &field_list));
 +            let generics = generic_params.as_ref().map(|generics| generics.clone_for_update());
 +            let def =
 +                create_struct_def(variant_name.clone(), &variant, &field_list, generics, &enum_ast);
 +
 +            let enum_ast = variant.parent_enum();
 +            let indent = enum_ast.indent_level();
 +            def.reindent_to(indent);
 +
 +            ted::insert_all(
 +                ted::Position::before(enum_ast.syntax()),
 +                vec![
 +                    def.syntax().clone().into(),
 +                    make::tokens::whitespace(&format!("\n\n{indent}")).into(),
 +                ],
 +            );
 +
 +            update_variant(&variant, generic_params.map(|g| g.clone_for_update()));
 +        },
 +    )
 +}
 +
 +fn extract_field_list_if_applicable(
 +    variant: &ast::Variant,
 +) -> Option<Either<ast::RecordFieldList, ast::TupleFieldList>> {
 +    match variant.kind() {
 +        ast::StructKind::Record(field_list) if field_list.fields().next().is_some() => {
 +            Some(Either::Left(field_list))
 +        }
 +        ast::StructKind::Tuple(field_list) if field_list.fields().count() > 1 => {
 +            Some(Either::Right(field_list))
 +        }
 +        _ => None,
 +    }
 +}
 +
 +fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Variant) -> bool {
 +    variant
 +        .parent_enum(db)
 +        .module(db)
 +        .scope(db, None)
 +        .into_iter()
 +        .filter(|(_, def)| match def {
 +            // only check type-namespace
 +            hir::ScopeDef::ModuleDef(def) => matches!(
 +                def,
 +                ModuleDef::Module(_)
 +                    | ModuleDef::Adt(_)
 +                    | ModuleDef::Variant(_)
 +                    | ModuleDef::Trait(_)
 +                    | ModuleDef::TypeAlias(_)
 +                    | ModuleDef::BuiltinType(_)
 +            ),
 +            _ => false,
 +        })
 +        .any(|(name, _)| name.to_string() == variant_name.to_string())
 +}
 +
 +fn extract_generic_params(
 +    known_generics: &ast::GenericParamList,
 +    field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
 +) -> Option<ast::GenericParamList> {
 +    let mut generics = known_generics.generic_params().map(|param| (param, false)).collect_vec();
 +
 +    let tagged_one = match field_list {
 +        Either::Left(field_list) => field_list
 +            .fields()
 +            .filter_map(|f| f.ty())
 +            .fold(false, |tagged, ty| tag_generics_in_variant(&ty, &mut generics) || tagged),
 +        Either::Right(field_list) => field_list
 +            .fields()
 +            .filter_map(|f| f.ty())
 +            .fold(false, |tagged, ty| tag_generics_in_variant(&ty, &mut generics) || tagged),
 +    };
 +
 +    let generics = generics.into_iter().filter_map(|(param, tag)| tag.then(|| param));
 +    tagged_one.then(|| make::generic_param_list(generics))
 +}
 +
 +fn tag_generics_in_variant(ty: &ast::Type, generics: &mut [(ast::GenericParam, bool)]) -> bool {
 +    let mut tagged_one = false;
 +
 +    for token in ty.syntax().descendants_with_tokens().filter_map(SyntaxElement::into_token) {
 +        for (param, tag) in generics.iter_mut().filter(|(_, tag)| !tag) {
 +            match param {
 +                ast::GenericParam::LifetimeParam(lt)
 +                    if matches!(token.kind(), T![lifetime_ident]) =>
 +                {
 +                    if let Some(lt) = lt.lifetime() {
 +                        if lt.text().as_str() == token.text() {
 +                            *tag = true;
 +                            tagged_one = true;
 +                            break;
 +                        }
 +                    }
 +                }
 +                param if matches!(token.kind(), T![ident]) => {
 +                    if match param {
 +                        ast::GenericParam::ConstParam(konst) => konst
 +                            .name()
 +                            .map(|name| name.text().as_str() == token.text())
 +                            .unwrap_or_default(),
 +                        ast::GenericParam::TypeParam(ty) => ty
 +                            .name()
 +                            .map(|name| name.text().as_str() == token.text())
 +                            .unwrap_or_default(),
 +                        ast::GenericParam::LifetimeParam(lt) => lt
 +                            .lifetime()
 +                            .map(|lt| lt.text().as_str() == token.text())
 +                            .unwrap_or_default(),
 +                    } {
 +                        *tag = true;
 +                        tagged_one = true;
 +                        break;
 +                    }
 +                }
 +                _ => (),
 +            }
 +        }
 +    }
 +
 +    tagged_one
 +}
 +
 +fn create_struct_def(
 +    name: ast::Name,
 +    variant: &ast::Variant,
 +    field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
 +    generics: Option<ast::GenericParamList>,
 +    enum_: &ast::Enum,
 +) -> ast::Struct {
 +    let enum_vis = enum_.visibility();
 +
 +    let insert_vis = |node: &'_ SyntaxNode, vis: &'_ SyntaxNode| {
 +        let vis = vis.clone_for_update();
 +        ted::insert(ted::Position::before(node), vis);
 +    };
 +
 +    // for fields without any existing visibility, use visibility of enum
 +    let field_list: ast::FieldList = match field_list {
 +        Either::Left(field_list) => {
 +            let field_list = field_list.clone_for_update();
 +
 +            if let Some(vis) = &enum_vis {
 +                field_list
 +                    .fields()
 +                    .filter(|field| field.visibility().is_none())
 +                    .filter_map(|field| field.name())
 +                    .for_each(|it| insert_vis(it.syntax(), vis.syntax()));
 +            }
 +
 +            field_list.into()
 +        }
 +        Either::Right(field_list) => {
 +            let field_list = field_list.clone_for_update();
 +
 +            if let Some(vis) = &enum_vis {
 +                field_list
 +                    .fields()
 +                    .filter(|field| field.visibility().is_none())
 +                    .filter_map(|field| field.ty())
 +                    .for_each(|it| insert_vis(it.syntax(), vis.syntax()));
 +            }
 +
 +            field_list.into()
 +        }
 +    };
 +    field_list.reindent_to(IndentLevel::single());
 +
 +    let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update();
 +
 +    // take comments from variant
 +    ted::insert_all(
 +        ted::Position::first_child_of(strukt.syntax()),
 +        take_all_comments(variant.syntax()),
 +    );
 +
 +    // copy attributes from enum
 +    ted::insert_all(
 +        ted::Position::first_child_of(strukt.syntax()),
 +        enum_
 +            .attrs()
 +            .flat_map(|it| {
 +                vec![it.syntax().clone_for_update().into(), make::tokens::single_newline().into()]
 +            })
 +            .collect(),
 +    );
 +
 +    strukt
 +}
 +
 +fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList>) -> Option<()> {
 +    let name = variant.name()?;
 +    let ty = generics
 +        .filter(|generics| generics.generic_params().count() > 0)
++        .map(|generics| make::ty(&format!("{}{}", &name.text(), generics.to_generic_args())))
 +        .unwrap_or_else(|| make::ty(&name.text()));
 +
 +    // change from a record to a tuple field list
 +    let tuple_field = make::tuple_field(None, ty);
 +    let field_list = make::tuple_field_list(iter::once(tuple_field)).clone_for_update();
 +    ted::replace(variant.field_list()?.syntax(), field_list.syntax());
 +
 +    // remove any ws after the name
 +    if let Some(ws) = name
 +        .syntax()
 +        .siblings_with_tokens(syntax::Direction::Next)
 +        .find_map(|tok| tok.into_token().filter(|tok| tok.kind() == WHITESPACE))
 +    {
 +        ted::remove(SyntaxElement::Token(ws));
 +    }
 +
 +    Some(())
 +}
 +
 +// Note: this also detaches whitespace after comments,
 +// since `SyntaxNode::splice_children` (and by extension `ted::insert_all_raw`)
 +// detaches nodes. If we only took the comments, we'd leave behind the old whitespace.
 +fn take_all_comments(node: &SyntaxNode) -> Vec<SyntaxElement> {
 +    let mut remove_next_ws = false;
 +    node.children_with_tokens()
 +        .filter_map(move |child| match child.kind() {
 +            COMMENT => {
 +                remove_next_ws = true;
 +                child.detach();
 +                Some(child)
 +            }
 +            WHITESPACE if remove_next_ws => {
 +                remove_next_ws = false;
 +                child.detach();
 +                Some(make::tokens::single_newline().into())
 +            }
 +            _ => {
 +                remove_next_ws = false;
 +                None
 +            }
 +        })
 +        .collect()
 +}
 +
 +fn apply_references(
 +    insert_use_cfg: InsertUseConfig,
 +    segment: ast::PathSegment,
 +    node: SyntaxNode,
 +    import: Option<(ImportScope, hir::ModPath)>,
 +) {
 +    if let Some((scope, path)) = import {
 +        insert_use(&scope, mod_path_to_ast(&path), &insert_use_cfg);
 +    }
 +    // deep clone to prevent cycle
 +    let path = make::path_from_segments(iter::once(segment.clone_subtree()), false);
 +    ted::insert_raw(ted::Position::before(segment.syntax()), path.clone_for_update().syntax());
 +    ted::insert_raw(ted::Position::before(segment.syntax()), make::token(T!['(']));
 +    ted::insert_raw(ted::Position::after(&node), make::token(T![')']));
 +}
 +
 +fn process_references(
 +    ctx: &AssistContext<'_>,
 +    builder: &mut SourceChangeBuilder,
 +    visited_modules: &mut FxHashSet<Module>,
 +    enum_module_def: &ModuleDef,
 +    variant_hir_name: &Name,
 +    refs: Vec<FileReference>,
 +) -> Vec<(ast::PathSegment, SyntaxNode, Option<(ImportScope, hir::ModPath)>)> {
 +    // we have to recollect here eagerly as we are about to edit the tree we need to calculate the changes
 +    // and corresponding nodes up front
 +    refs.into_iter()
 +        .flat_map(|reference| {
 +            let (segment, scope_node, module) = reference_to_node(&ctx.sema, reference)?;
 +            let segment = builder.make_mut(segment);
 +            let scope_node = builder.make_syntax_mut(scope_node);
 +            if !visited_modules.contains(&module) {
 +                let mod_path = module.find_use_path_prefixed(
 +                    ctx.sema.db,
 +                    *enum_module_def,
 +                    ctx.config.insert_use.prefix_kind,
 +                    ctx.config.prefer_no_std,
 +                );
 +                if let Some(mut mod_path) = mod_path {
 +                    mod_path.pop_segment();
 +                    mod_path.push_segment(variant_hir_name.clone());
 +                    let scope = ImportScope::find_insert_use_container(&scope_node, &ctx.sema)?;
 +                    visited_modules.insert(module);
 +                    return Some((segment, scope_node, Some((scope, mod_path))));
 +                }
 +            }
 +            Some((segment, scope_node, None))
 +        })
 +        .collect()
 +}
 +
 +fn reference_to_node(
 +    sema: &hir::Semantics<'_, RootDatabase>,
 +    reference: FileReference,
 +) -> Option<(ast::PathSegment, SyntaxNode, hir::Module)> {
 +    let segment =
 +        reference.name.as_name_ref()?.syntax().parent().and_then(ast::PathSegment::cast)?;
 +    let parent = segment.parent_path().syntax().parent()?;
 +    let expr_or_pat = match_ast! {
 +        match parent {
 +            ast::PathExpr(_it) => parent.parent()?,
 +            ast::RecordExpr(_it) => parent,
 +            ast::TupleStructPat(_it) => parent,
 +            ast::RecordPat(_it) => parent,
 +            _ => return None,
 +        }
 +    };
 +    let module = sema.scope(&expr_or_pat)?.module();
 +    Some((segment, expr_or_pat, module))
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn test_extract_struct_several_fields_tuple() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "enum A { $0One(u32, u32) }",
 +            r#"struct One(u32, u32);
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_several_fields_named() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "enum A { $0One { foo: u32, bar: u32 } }",
 +            r#"struct One{ foo: u32, bar: u32 }
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_one_field_named() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "enum A { $0One { foo: u32 } }",
 +            r#"struct One{ foo: u32 }
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_carries_over_generics() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r"enum En<T> { Var { a: T$0 } }",
 +            r#"struct Var<T>{ a: T }
 +
 +enum En<T> { Var(Var<T>) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_carries_over_attributes() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +#[derive(Debug)]
 +#[derive(Clone)]
 +enum Enum { Variant{ field: u32$0 } }"#,
 +            r#"
 +#[derive(Debug)]
 +#[derive(Clone)]
 +struct Variant{ field: u32 }
 +
 +#[derive(Debug)]
 +#[derive(Clone)]
 +enum Enum { Variant(Variant) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_indent_to_parent_enum() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum Enum {
 +    Variant {
 +        field: u32$0
 +    }
 +}"#,
 +            r#"
 +struct Variant{
 +    field: u32
 +}
 +
 +enum Enum {
 +    Variant(Variant)
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_indent_to_parent_enum_in_mod() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +mod indenting {
 +    enum Enum {
 +        Variant {
 +            field: u32$0
 +        }
 +    }
 +}"#,
 +            r#"
 +mod indenting {
 +    struct Variant{
 +        field: u32
 +    }
 +
 +    enum Enum {
 +        Variant(Variant)
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_keep_comments_and_attrs_one_field_named() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum A {
 +    $0One {
 +        // leading comment
 +        /// doc comment
 +        #[an_attr]
 +        foo: u32
 +        // trailing comment
 +    }
 +}"#,
 +            r#"
 +struct One{
 +    // leading comment
 +    /// doc comment
 +    #[an_attr]
 +    foo: u32
 +    // trailing comment
 +}
 +
 +enum A {
 +    One(One)
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_keep_comments_and_attrs_several_fields_named() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum A {
 +    $0One {
 +        // comment
 +        /// doc
 +        #[attr]
 +        foo: u32,
 +        // comment
 +        #[attr]
 +        /// doc
 +        bar: u32
 +    }
 +}"#,
 +            r#"
 +struct One{
 +    // comment
 +    /// doc
 +    #[attr]
 +    foo: u32,
 +    // comment
 +    #[attr]
 +    /// doc
 +    bar: u32
 +}
 +
 +enum A {
 +    One(One)
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_keep_comments_and_attrs_several_fields_tuple() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "enum A { $0One(/* comment */ #[attr] u32, /* another */ u32 /* tail */) }",
 +            r#"
 +struct One(/* comment */ #[attr] u32, /* another */ u32 /* tail */);
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_move_struct_variant_comments() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum A {
 +    /* comment */
 +    // other
 +    /// comment
 +    #[attr]
 +    $0One {
 +        a: u32
 +    }
 +}"#,
 +            r#"
 +/* comment */
 +// other
 +/// comment
 +struct One{
 +    a: u32
 +}
 +
 +enum A {
 +    #[attr]
 +    One(One)
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_move_tuple_variant_comments() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum A {
 +    /* comment */
 +    // other
 +    /// comment
 +    #[attr]
 +    $0One(u32, u32)
 +}"#,
 +            r#"
 +/* comment */
 +// other
 +/// comment
 +struct One(u32, u32);
 +
 +enum A {
 +    #[attr]
 +    One(One)
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_keep_existing_visibility_named() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "enum A { $0One{ a: u32, pub(crate) b: u32, pub(super) c: u32, d: u32 } }",
 +            r#"
 +struct One{ a: u32, pub(crate) b: u32, pub(super) c: u32, d: u32 }
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_keep_existing_visibility_tuple() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "enum A { $0One(u32, pub(crate) u32, pub(super) u32, u32) }",
 +            r#"
 +struct One(u32, pub(crate) u32, pub(super) u32, u32);
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_enum_variant_name_value_namespace() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"const One: () = ();
 +enum A { $0One(u32, u32) }"#,
 +            r#"const One: () = ();
 +struct One(u32, u32);
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_no_visibility() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "enum A { $0One(u32, u32) }",
 +            r#"
 +struct One(u32, u32);
 +
 +enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_pub_visibility() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "pub enum A { $0One(u32, u32) }",
 +            r#"
 +pub struct One(pub u32, pub u32);
 +
 +pub enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_pub_in_mod_visibility() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "pub(in something) enum A { $0One{ a: u32, b: u32 } }",
 +            r#"
 +pub(in something) struct One{ pub(in something) a: u32, pub(in something) b: u32 }
 +
 +pub(in something) enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_pub_crate_visibility() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            "pub(crate) enum A { $0One{ a: u32, b: u32, c: u32 } }",
 +            r#"
 +pub(crate) struct One{ pub(crate) a: u32, pub(crate) b: u32, pub(crate) c: u32 }
 +
 +pub(crate) enum A { One(One) }"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_with_complex_imports() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"mod my_mod {
 +    fn another_fn() {
 +        let m = my_other_mod::MyEnum::MyField(1, 1);
 +    }
 +
 +    pub mod my_other_mod {
 +        fn another_fn() {
 +            let m = MyEnum::MyField(1, 1);
 +        }
 +
 +        pub enum MyEnum {
 +            $0MyField(u8, u8),
 +        }
 +    }
 +}
 +
 +fn another_fn() {
 +    let m = my_mod::my_other_mod::MyEnum::MyField(1, 1);
 +}"#,
 +            r#"use my_mod::my_other_mod::MyField;
 +
 +mod my_mod {
 +    use self::my_other_mod::MyField;
 +
 +    fn another_fn() {
 +        let m = my_other_mod::MyEnum::MyField(MyField(1, 1));
 +    }
 +
 +    pub mod my_other_mod {
 +        fn another_fn() {
 +            let m = MyEnum::MyField(MyField(1, 1));
 +        }
 +
 +        pub struct MyField(pub u8, pub u8);
 +
 +        pub enum MyEnum {
 +            MyField(MyField),
 +        }
 +    }
 +}
 +
 +fn another_fn() {
 +    let m = my_mod::my_other_mod::MyEnum::MyField(MyField(1, 1));
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn extract_record_fix_references() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum E {
 +    $0V { i: i32, j: i32 }
 +}
 +
 +fn f() {
 +    let E::V { i, j } = E::V { i: 9, j: 2 };
 +}
 +"#,
 +            r#"
 +struct V{ i: i32, j: i32 }
 +
 +enum E {
 +    V(V)
 +}
 +
 +fn f() {
 +    let E::V(V { i, j }) = E::V(V { i: 9, j: 2 });
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn extract_record_fix_references2() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum E {
 +    $0V(i32, i32)
 +}
 +
 +fn f() {
 +    let E::V(i, j) = E::V(9, 2);
 +}
 +"#,
 +            r#"
 +struct V(i32, i32);
 +
 +enum E {
 +    V(V)
 +}
 +
 +fn f() {
 +    let E::V(V(i, j)) = E::V(V(9, 2));
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_several_files() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +//- /main.rs
 +enum E {
 +    $0V(i32, i32)
 +}
 +mod foo;
 +
 +//- /foo.rs
 +use crate::E;
 +fn f() {
 +    let e = E::V(9, 2);
 +}
 +"#,
 +            r#"
 +//- /main.rs
 +struct V(i32, i32);
 +
 +enum E {
 +    V(V)
 +}
 +mod foo;
 +
 +//- /foo.rs
 +use crate::{E, V};
 +fn f() {
 +    let e = E::V(V(9, 2));
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_several_files_record() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +//- /main.rs
 +enum E {
 +    $0V { i: i32, j: i32 }
 +}
 +mod foo;
 +
 +//- /foo.rs
 +use crate::E;
 +fn f() {
 +    let e = E::V { i: 9, j: 2 };
 +}
 +"#,
 +            r#"
 +//- /main.rs
 +struct V{ i: i32, j: i32 }
 +
 +enum E {
 +    V(V)
 +}
 +mod foo;
 +
 +//- /foo.rs
 +use crate::{E, V};
 +fn f() {
 +    let e = E::V(V { i: 9, j: 2 });
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_record_nested_call_exp() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum A { $0One { a: u32, b: u32 } }
 +
 +struct B(A);
 +
 +fn foo() {
 +    let _ = B(A::One { a: 1, b: 2 });
 +}
 +"#,
 +            r#"
 +struct One{ a: u32, b: u32 }
 +
 +enum A { One(One) }
 +
 +struct B(A);
 +
 +fn foo() {
 +    let _ = B(A::One(One { a: 1, b: 2 }));
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_enum_not_applicable_for_element_with_no_fields() {
 +        check_assist_not_applicable(extract_struct_from_enum_variant, r#"enum A { $0One }"#);
 +    }
 +
 +    #[test]
 +    fn test_extract_enum_not_applicable_if_struct_exists() {
 +        cov_mark::check!(test_extract_enum_not_applicable_if_struct_exists);
 +        check_assist_not_applicable(
 +            extract_struct_from_enum_variant,
 +            r#"
 +struct One;
 +enum A { $0One(u8, u32) }
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_not_applicable_one_field() {
 +        check_assist_not_applicable(extract_struct_from_enum_variant, r"enum A { $0One(u32) }");
 +    }
 +
 +    #[test]
 +    fn test_extract_not_applicable_no_field_tuple() {
 +        check_assist_not_applicable(extract_struct_from_enum_variant, r"enum A { $0None() }");
 +    }
 +
 +    #[test]
 +    fn test_extract_not_applicable_no_field_named() {
 +        check_assist_not_applicable(extract_struct_from_enum_variant, r"enum A { $0None {} }");
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_only_copies_needed_generics() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum X<'a, 'b, 'x> {
 +    $0A { a: &'a &'x mut () },
 +    B { b: &'b () },
 +    C { c: () },
 +}
 +"#,
 +            r#"
 +struct A<'a, 'x>{ a: &'a &'x mut () }
 +
 +enum X<'a, 'b, 'x> {
 +    A(A<'a, 'x>),
 +    B { b: &'b () },
 +    C { c: () },
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_with_liftime_type_const() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum X<'b, T, V, const C: usize> {
 +    $0A { a: T, b: X<'b>, c: [u8; C] },
 +    D { d: V },
 +}
 +"#,
 +            r#"
 +struct A<'b, T, const C: usize>{ a: T, b: X<'b>, c: [u8; C] }
 +
 +enum X<'b, T, V, const C: usize> {
 +    A(A<'b, T, C>),
 +    D { d: V },
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_without_generics() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum X<'a, 'b> {
 +    A { a: &'a () },
 +    B { b: &'b () },
 +    $0C { c: () },
 +}
 +"#,
 +            r#"
 +struct C{ c: () }
 +
 +enum X<'a, 'b> {
 +    A { a: &'a () },
 +    B { b: &'b () },
 +    C(C),
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_extract_struct_keeps_trait_bounds() {
 +        check_assist(
 +            extract_struct_from_enum_variant,
 +            r#"
 +enum En<T: TraitT, V: TraitV> {
 +    $0A { a: T },
 +    B { b: V },
 +}
 +"#,
 +            r#"
 +struct A<T: TraitT>{ a: T }
 +
 +enum En<T: TraitT, V: TraitV> {
 +    A(A<T>),
 +    B { b: V },
 +}
 +"#,
 +        );
 +    }
 +}
index e26c76da1891649c0a035706e5eb278aa325b99e,0000000000000000000000000000000000000000..8b67982f9158234b91afa04bf28c691b543b2d10
mode 100644,000000..100644
--- /dev/null
@@@ -1,1857 -1,0 +1,1848 @@@
- use hir::{HasSource, HirDisplay, Module, Semantics, TypeInfo};
++use hir::{Adt, HasSource, HirDisplay, Module, Semantics, TypeInfo};
 +use ide_db::{
 +    base_db::FileId,
 +    defs::{Definition, NameRefClass},
 +    famous_defs::FamousDefs,
 +    FxHashMap, FxHashSet, RootDatabase, SnippetCap,
 +};
 +use stdx::to_lower_snake_case;
 +use syntax::{
 +    ast::{
 +        self,
 +        edit::{AstNodeEdit, IndentLevel},
 +        make, AstNode, CallExpr, HasArgList, HasModuleItem,
 +    },
 +    SyntaxKind, SyntaxNode, TextRange, TextSize,
 +};
 +
 +use crate::{
 +    utils::convert_reference_type,
 +    utils::{find_struct_impl, render_snippet, Cursor},
 +    AssistContext, AssistId, AssistKind, Assists,
 +};
 +
 +// Assist: generate_function
 +//
 +// Adds a stub function with a signature matching the function under the cursor.
 +//
 +// ```
 +// struct Baz;
 +// fn baz() -> Baz { Baz }
 +// fn foo() {
 +//     bar$0("", baz());
 +// }
 +//
 +// ```
 +// ->
 +// ```
 +// struct Baz;
 +// fn baz() -> Baz { Baz }
 +// fn foo() {
 +//     bar("", baz());
 +// }
 +//
 +// fn bar(arg: &str, baz: Baz) ${0:-> _} {
 +//     todo!()
 +// }
 +//
 +// ```
 +pub(crate) fn generate_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    gen_fn(acc, ctx).or_else(|| gen_method(acc, ctx))
 +}
 +
 +fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
 +    let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
 +    let path = path_expr.path()?;
 +    let name_ref = path.segment()?.name_ref()?;
 +    if ctx.sema.resolve_path(&path).is_some() {
 +        // The function call already resolves, no need to add a function
 +        return None;
 +    }
 +
 +    let fn_name = &*name_ref.text();
 +    let TargetInfo { target_module, adt_name, target, file, insert_offset } =
 +        fn_target_info(ctx, path, &call, fn_name)?;
 +    let function_builder = FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target)?;
 +    let text_range = call.syntax().text_range();
 +    let label = format!("Generate {} function", function_builder.fn_name);
 +    add_func_to_accumulator(
 +        acc,
 +        ctx,
 +        text_range,
 +        function_builder,
 +        insert_offset,
 +        file,
 +        adt_name,
 +        label,
 +    )
 +}
 +
 +struct TargetInfo {
 +    target_module: Option<Module>,
 +    adt_name: Option<hir::Name>,
 +    target: GeneratedFunctionTarget,
 +    file: FileId,
 +    insert_offset: TextSize,
 +}
 +
 +impl TargetInfo {
 +    fn new(
 +        target_module: Option<Module>,
 +        adt_name: Option<hir::Name>,
 +        target: GeneratedFunctionTarget,
 +        file: FileId,
 +        insert_offset: TextSize,
 +    ) -> Self {
 +        Self { target_module, adt_name, target, file, insert_offset }
 +    }
 +}
 +
 +fn fn_target_info(
 +    ctx: &AssistContext<'_>,
 +    path: ast::Path,
 +    call: &CallExpr,
 +    fn_name: &str,
 +) -> Option<TargetInfo> {
 +    match path.qualifier() {
 +        Some(qualifier) => match ctx.sema.resolve_path(&qualifier) {
 +            Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => {
 +                get_fn_target_info(ctx, &Some(module), call.clone())
 +            }
 +            Some(hir::PathResolution::Def(hir::ModuleDef::Adt(adt))) => {
 +                if let hir::Adt::Enum(_) = adt {
 +                    // Don't suggest generating function if the name starts with an uppercase letter
 +                    if fn_name.starts_with(char::is_uppercase) {
 +                        return None;
 +                    }
 +                }
 +
 +                assoc_fn_target_info(ctx, call, adt, fn_name)
 +            }
 +            Some(hir::PathResolution::SelfType(impl_)) => {
 +                let adt = impl_.self_ty(ctx.db()).as_adt()?;
 +                assoc_fn_target_info(ctx, call, adt, fn_name)
 +            }
 +            _ => None,
 +        },
 +        _ => get_fn_target_info(ctx, &None, call.clone()),
 +    }
 +}
 +
 +fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
 +    if ctx.sema.resolve_method_call(&call).is_some() {
 +        return None;
 +    }
 +
 +    let fn_name = call.name_ref()?;
 +    let adt = ctx.sema.type_of_expr(&call.receiver()?)?.original().strip_references().as_adt()?;
 +
 +    let current_module = ctx.sema.scope(call.syntax())?.module();
 +    let target_module = adt.module(ctx.sema.db);
 +
 +    if current_module.krate() != target_module.krate() {
 +        return None;
 +    }
 +    let (impl_, file) = get_adt_source(ctx, &adt, fn_name.text().as_str())?;
-     let (target, insert_offset) = get_method_target(ctx, &target_module, &impl_)?;
++    let (target, insert_offset) = get_method_target(ctx, &impl_, &adt)?;
++
 +    let function_builder =
 +        FunctionBuilder::from_method_call(ctx, &call, &fn_name, target_module, target)?;
 +    let text_range = call.syntax().text_range();
 +    let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
 +    let label = format!("Generate {} method", function_builder.fn_name);
 +    add_func_to_accumulator(
 +        acc,
 +        ctx,
 +        text_range,
 +        function_builder,
 +        insert_offset,
 +        file,
 +        adt_name,
 +        label,
 +    )
 +}
 +
 +fn add_func_to_accumulator(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +    text_range: TextRange,
 +    function_builder: FunctionBuilder,
 +    insert_offset: TextSize,
 +    file: FileId,
 +    adt_name: Option<hir::Name>,
 +    label: String,
 +) -> Option<()> {
 +    acc.add(AssistId("generate_function", AssistKind::Generate), label, text_range, |builder| {
-         let function_template = function_builder.render();
++        let indent = IndentLevel::from_node(function_builder.target.syntax());
++        let function_template = function_builder.render(adt_name.is_some());
 +        let mut func = function_template.to_string(ctx.config.snippet_cap);
 +        if let Some(name) = adt_name {
-             func = format!("\nimpl {} {{\n{}\n}}", name, func);
++            func = format!("\n{}impl {} {{\n{}\n{}}}", indent, name, func, indent);
 +        }
 +        builder.edit_file(file);
 +        match ctx.config.snippet_cap {
 +            Some(cap) => builder.insert_snippet(cap, insert_offset, func),
 +            None => builder.insert(insert_offset, func),
 +        }
 +    })
 +}
 +
 +fn get_adt_source(
 +    ctx: &AssistContext<'_>,
 +    adt: &hir::Adt,
 +    fn_name: &str,
 +) -> Option<(Option<ast::Impl>, FileId)> {
 +    let range = adt.source(ctx.sema.db)?.syntax().original_file_range(ctx.sema.db);
 +    let file = ctx.sema.parse(range.file_id);
 +    let adt_source =
 +        ctx.sema.find_node_at_offset_with_macros(file.syntax(), range.range.start())?;
 +    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 {
++    fn render(self, is_method: bool) -> FunctionTemplate {
 +        let placeholder_expr = make::ext::expr_todo();
 +        let fn_body = make::block_expr(vec![], Some(placeholder_expr));
 +        let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None };
 +        let mut fn_def = make::fn_(
 +            visibility,
 +            self.fn_name,
 +            self.type_params,
 +            self.params,
 +            fn_body,
 +            self.ret_type,
 +            self.is_async,
 +        );
 +        let leading_ws;
 +        let trailing_ws;
 +
 +        match self.target {
 +            GeneratedFunctionTarget::BehindItem(it) => {
-                 let indent = IndentLevel::from_node(&it);
-                 leading_ws = format!("\n\n{}", indent);
++                let mut indent = IndentLevel::from_node(&it);
++                if is_method {
++                    indent = indent + 1;
++                    leading_ws = format!("{}", indent);
++                } else {
++                    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>,
++    adt: &Adt,
 +) -> 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
++            GeneratedFunctionTarget::BehindItem(adt.source(ctx.sema.db)?.syntax().value.clone())
 +        }
 +    };
 +    Some((target.clone(), get_insert_offset(&target)))
 +}
 +
 +fn assoc_fn_target_info(
 +    ctx: &AssistContext<'_>,
 +    call: &CallExpr,
 +    adt: hir::Adt,
 +    fn_name: &str,
 +) -> Option<TargetInfo> {
 +    let current_module = ctx.sema.scope(call.syntax())?.module();
 +    let module = adt.module(ctx.sema.db);
 +    let target_module = if current_module == module { None } else { Some(module) };
 +    if current_module.krate() != module.krate() {
 +        return None;
 +    }
 +    let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?;
-     let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?;
++    let (target, insert_offset) = get_method_target(ctx, &impl_, &adt)?;
 +    let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
 +    Some(TargetInfo::new(target_module, adt_name, target, file, insert_offset))
 +}
 +
 +fn get_insert_offset(target: &GeneratedFunctionTarget) -> TextSize {
 +    match &target {
 +        GeneratedFunctionTarget::BehindItem(it) => it.text_range().end(),
 +        GeneratedFunctionTarget::InEmptyItemList(it) => it.text_range().start() + TextSize::of('{'),
 +    }
 +}
 +
 +#[derive(Clone)]
 +enum GeneratedFunctionTarget {
 +    BehindItem(SyntaxNode),
 +    InEmptyItemList(SyntaxNode),
 +}
 +
 +impl GeneratedFunctionTarget {
 +    fn syntax(&self) -> &SyntaxNode {
 +        match self {
 +            GeneratedFunctionTarget::BehindItem(it) => it,
 +            GeneratedFunctionTarget::InEmptyItemList(it) => it,
 +        }
 +    }
 +}
 +
 +/// Computes the type variables and arguments required for the generated function
 +fn fn_args(
 +    ctx: &AssistContext<'_>,
 +    target_module: hir::Module,
 +    call: ast::CallableExpr,
 +) -> Option<(Option<ast::GenericParamList>, ast::ParamList)> {
 +    let mut arg_names = Vec::new();
 +    let mut arg_types = Vec::new();
 +    for arg in call.arg_list()?.args() {
 +        arg_names.push(fn_arg_name(&ctx.sema, &arg));
 +        arg_types.push(fn_arg_type(ctx, target_module, &arg));
 +    }
 +    deduplicate_arg_names(&mut arg_names);
 +    let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| {
 +        make::param(make::ext::simple_ident_pat(make::name(&name)).into(), make::ty(&ty))
 +    });
 +
 +    Some((
 +        None,
 +        make::param_list(
 +            match call {
 +                ast::CallableExpr::Call(_) => None,
 +                ast::CallableExpr::MethodCall(_) => Some(make::self_param()),
 +            },
 +            params,
 +        ),
 +    ))
 +}
 +
 +/// Makes duplicate argument names unique by appending incrementing numbers.
 +///
 +/// ```
 +/// let mut names: Vec<String> =
 +///     vec!["foo".into(), "foo".into(), "bar".into(), "baz".into(), "bar".into()];
 +/// deduplicate_arg_names(&mut names);
 +/// let expected: Vec<String> =
 +///     vec!["foo_1".into(), "foo_2".into(), "bar_1".into(), "baz".into(), "bar_2".into()];
 +/// assert_eq!(names, expected);
 +/// ```
 +fn deduplicate_arg_names(arg_names: &mut Vec<String>) {
 +    let mut arg_name_counts = FxHashMap::default();
 +    for name in arg_names.iter() {
 +        *arg_name_counts.entry(name).or_insert(0) += 1;
 +    }
 +    let duplicate_arg_names: FxHashSet<String> = arg_name_counts
 +        .into_iter()
 +        .filter(|(_, count)| *count >= 2)
 +        .map(|(name, _)| name.clone())
 +        .collect();
 +
 +    let mut counter_per_name = FxHashMap::default();
 +    for arg_name in arg_names.iter_mut() {
 +        if duplicate_arg_names.contains(arg_name) {
 +            let counter = counter_per_name.entry(arg_name.clone()).or_insert(1);
 +            arg_name.push('_');
 +            arg_name.push_str(&counter.to_string());
 +            *counter += 1;
 +        }
 +    }
 +}
 +
 +fn fn_arg_name(sema: &Semantics<'_, RootDatabase>, arg_expr: &ast::Expr) -> String {
 +    let name = (|| match arg_expr {
 +        ast::Expr::CastExpr(cast_expr) => Some(fn_arg_name(sema, &cast_expr.expr()?)),
 +        expr => {
 +            let name_ref = expr
 +                .syntax()
 +                .descendants()
 +                .filter_map(ast::NameRef::cast)
 +                .filter(|name| name.ident_token().is_some())
 +                .last()?;
 +            if let Some(NameRefClass::Definition(Definition::Const(_) | Definition::Static(_))) =
 +                NameRefClass::classify(sema, &name_ref)
 +            {
 +                return Some(name_ref.to_string().to_lowercase());
 +            };
 +            Some(to_lower_snake_case(&name_ref.to_string()))
 +        }
 +    })();
 +    match name {
 +        Some(mut name) if name.starts_with(|c: char| c.is_ascii_digit()) => {
 +            name.insert_str(0, "arg");
 +            name
 +        }
 +        Some(name) => name,
 +        None => "arg".to_string(),
 +    }
 +}
 +
 +fn fn_arg_type(ctx: &AssistContext<'_>, target_module: hir::Module, fn_arg: &ast::Expr) -> String {
 +    fn maybe_displayed_type(
 +        ctx: &AssistContext<'_>,
 +        target_module: hir::Module,
 +        fn_arg: &ast::Expr,
 +    ) -> Option<String> {
 +        let ty = ctx.sema.type_of_expr(fn_arg)?.adjusted();
 +        if ty.is_unknown() {
 +            return None;
 +        }
 +
 +        if ty.is_reference() || ty.is_mutable_reference() {
 +            let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(fn_arg.syntax())?.krate());
 +            convert_reference_type(ty.strip_references(), ctx.db(), famous_defs)
 +                .map(|conversion| conversion.convert_type(ctx.db()))
 +                .or_else(|| ty.display_source_code(ctx.db(), target_module.into()).ok())
 +        } else {
 +            ty.display_source_code(ctx.db(), target_module.into()).ok()
 +        }
 +    }
 +
 +    maybe_displayed_type(ctx, target_module, fn_arg).unwrap_or_else(|| String::from("_"))
 +}
 +
 +/// Returns the position inside the current mod or file
 +/// directly after the current block
 +/// We want to write the generated function directly after
 +/// fns, impls or macro calls, but inside mods
 +fn next_space_for_fn_after_call_site(expr: ast::CallableExpr) -> Option<GeneratedFunctionTarget> {
 +    let mut ancestors = expr.syntax().ancestors().peekable();
 +    let mut last_ancestor: Option<SyntaxNode> = None;
 +    while let Some(next_ancestor) = ancestors.next() {
 +        match next_ancestor.kind() {
 +            SyntaxKind::SOURCE_FILE => {
 +                break;
 +            }
 +            SyntaxKind::ITEM_LIST => {
 +                if ancestors.peek().map(|a| a.kind()) == Some(SyntaxKind::MODULE) {
 +                    break;
 +                }
 +            }
 +            _ => {}
 +        }
 +        last_ancestor = Some(next_ancestor);
 +    }
 +    last_ancestor.map(GeneratedFunctionTarget::BehindItem)
 +}
 +
 +fn next_space_for_fn_in_module(
 +    db: &dyn hir::db::AstDatabase,
 +    module_source: &hir::InFile<hir::ModuleSource>,
 +) -> Option<(FileId, GeneratedFunctionTarget)> {
 +    let file = module_source.file_id.original_file(db);
 +    let assist_item = match &module_source.value {
 +        hir::ModuleSource::SourceFile(it) => match it.items().last() {
 +            Some(last_item) => GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()),
 +            None => GeneratedFunctionTarget::BehindItem(it.syntax().clone()),
 +        },
 +        hir::ModuleSource::Module(it) => match it.item_list().and_then(|it| it.items().last()) {
 +            Some(last_item) => GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()),
 +            None => GeneratedFunctionTarget::InEmptyItemList(it.item_list()?.syntax().clone()),
 +        },
 +        hir::ModuleSource::BlockExpr(it) => {
 +            if let Some(last_item) =
 +                it.statements().take_while(|stmt| matches!(stmt, ast::Stmt::Item(_))).last()
 +            {
 +                GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())
 +            } else {
 +                GeneratedFunctionTarget::InEmptyItemList(it.syntax().clone())
 +            }
 +        }
 +    };
 +    Some((file, assist_item))
 +}
 +
 +fn next_space_for_fn_in_impl(impl_: &ast::Impl) -> Option<GeneratedFunctionTarget> {
 +    if let Some(last_item) = impl_.assoc_item_list().and_then(|it| it.assoc_items().last()) {
 +        Some(GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()))
 +    } else {
 +        Some(GeneratedFunctionTarget::InEmptyItemList(impl_.assoc_item_list()?.syntax().clone()))
 +    }
 +}
 +
 +fn module_is_descendant(module: &hir::Module, ans: &hir::Module, ctx: &AssistContext<'_>) -> bool {
 +    if module == ans {
 +        return true;
 +    }
 +    for c in ans.children(ctx.sema.db) {
 +        if module_is_descendant(module, &c, ctx) {
 +            return true;
 +        }
 +    }
 +    false
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_not_applicable};
 +
 +    use super::*;
 +
 +    #[test]
 +    fn add_function_with_no_args() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    bar$0();
 +}
 +",
 +            r"
 +fn foo() {
 +    bar();
 +}
 +
 +fn bar() ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_from_method() {
 +        // This ensures that the function is correctly generated
 +        // in the next outer mod or file
 +        check_assist(
 +            generate_function,
 +            r"
 +impl Foo {
 +    fn foo() {
 +        bar$0();
 +    }
 +}
 +",
 +            r"
 +impl Foo {
 +    fn foo() {
 +        bar();
 +    }
 +}
 +
 +fn bar() ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_directly_after_current_block() {
 +        // The new fn should not be created at the end of the file or module
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo1() {
 +    bar$0();
 +}
 +
 +fn foo2() {}
 +",
 +            r"
 +fn foo1() {
 +    bar();
 +}
 +
 +fn bar() ${0:-> _} {
 +    todo!()
 +}
 +
 +fn foo2() {}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_no_args_in_same_module() {
 +        check_assist(
 +            generate_function,
 +            r"
 +mod baz {
 +    fn foo() {
 +        bar$0();
 +    }
 +}
 +",
 +            r"
 +mod baz {
 +    fn foo() {
 +        bar();
 +    }
 +
 +    fn bar() ${0:-> _} {
 +        todo!()
 +    }
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_upper_camel_case_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct BazBaz;
 +fn foo() {
 +    bar$0(BazBaz);
 +}
 +",
 +            r"
 +struct BazBaz;
 +fn foo() {
 +    bar(BazBaz);
 +}
 +
 +fn bar(baz_baz: BazBaz) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn add_function_with_upper_camel_case_arg_as_cast() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct BazBaz;
 +fn foo() {
 +    bar$0(&BazBaz as *const BazBaz);
 +}
 +",
 +            r"
 +struct BazBaz;
 +fn foo() {
 +    bar(&BazBaz as *const BazBaz);
 +}
 +
 +fn bar(baz_baz: *const BazBaz) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn add_function_with_function_call_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct Baz;
 +fn baz() -> Baz { todo!() }
 +fn foo() {
 +    bar$0(baz());
 +}
 +",
 +            r"
 +struct Baz;
 +fn baz() -> Baz { todo!() }
 +fn foo() {
 +    bar(baz());
 +}
 +
 +fn bar(baz: Baz) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn add_function_with_method_call_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct Baz;
 +impl Baz {
 +    fn foo(&self) -> Baz {
 +        ba$0r(self.baz())
 +    }
 +    fn baz(&self) -> Baz {
 +        Baz
 +    }
 +}
 +",
 +            r"
 +struct Baz;
 +impl Baz {
 +    fn foo(&self) -> Baz {
 +        bar(self.baz())
 +    }
 +    fn baz(&self) -> Baz {
 +        Baz
 +    }
 +}
 +
 +fn bar(baz: Baz) -> Baz {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_string_literal_arg() {
 +        check_assist(
 +            generate_function,
 +            r#"
 +fn foo() {
 +    $0bar("bar")
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    bar("bar")
 +}
 +
 +fn bar(arg: &str) {
 +    ${0:todo!()}
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_char_literal_arg() {
 +        check_assist(
 +            generate_function,
 +            r#"
 +fn foo() {
 +    $0bar('x')
 +}
 +"#,
 +            r#"
 +fn foo() {
 +    bar('x')
 +}
 +
 +fn bar(arg: char) {
 +    ${0:todo!()}
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_int_literal_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    $0bar(42)
 +}
 +",
 +            r"
 +fn foo() {
 +    bar(42)
 +}
 +
 +fn bar(arg: i32) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_cast_int_literal_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    $0bar(42 as u8)
 +}
 +",
 +            r"
 +fn foo() {
 +    bar(42 as u8)
 +}
 +
 +fn bar(arg: u8) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn name_of_cast_variable_is_used() {
 +        // Ensures that the name of the cast type isn't used
 +        // in the generated function signature.
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    let x = 42;
 +    bar$0(x as u8)
 +}
 +",
 +            r"
 +fn foo() {
 +    let x = 42;
 +    bar(x as u8)
 +}
 +
 +fn bar(x: u8) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_variable_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    let worble = ();
 +    $0bar(worble)
 +}
 +",
 +            r"
 +fn foo() {
 +    let worble = ();
 +    bar(worble)
 +}
 +
 +fn bar(worble: ()) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_impl_trait_arg() {
 +        check_assist(
 +            generate_function,
 +            r#"
 +//- minicore: sized
 +trait Foo {}
 +fn foo() -> impl Foo {
 +    todo!()
 +}
 +fn baz() {
 +    $0bar(foo())
 +}
 +"#,
 +            r#"
 +trait Foo {}
 +fn foo() -> impl Foo {
 +    todo!()
 +}
 +fn baz() {
 +    bar(foo())
 +}
 +
 +fn bar(foo: impl Foo) {
 +    ${0:todo!()}
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn borrowed_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct Baz;
 +fn baz() -> Baz { todo!() }
 +
 +fn foo() {
 +    bar$0(&baz())
 +}
 +",
 +            r"
 +struct Baz;
 +fn baz() -> Baz { todo!() }
 +
 +fn foo() {
 +    bar(&baz())
 +}
 +
 +fn bar(baz: &Baz) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_qualified_path_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +mod Baz {
 +    pub struct Bof;
 +    pub fn baz() -> Bof { Bof }
 +}
 +fn foo() {
 +    $0bar(Baz::baz())
 +}
 +",
 +            r"
 +mod Baz {
 +    pub struct Bof;
 +    pub fn baz() -> Bof { Bof }
 +}
 +fn foo() {
 +    bar(Baz::baz())
 +}
 +
 +fn bar(baz: Baz::Bof) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_generic_arg() {
 +        // FIXME: This is wrong, generated `bar` should include generic parameter.
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo<T>(t: T) {
 +    $0bar(t)
 +}
 +",
 +            r"
 +fn foo<T>(t: T) {
 +    bar(t)
 +}
 +
 +fn bar(t: T) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_fn_arg() {
 +        // FIXME: The argument in `bar` is wrong.
 +        check_assist(
 +            generate_function,
 +            r"
 +struct Baz;
 +impl Baz {
 +    fn new() -> Self { Baz }
 +}
 +fn foo() {
 +    $0bar(Baz::new);
 +}
 +",
 +            r"
 +struct Baz;
 +impl Baz {
 +    fn new() -> Self { Baz }
 +}
 +fn foo() {
 +    bar(Baz::new);
 +}
 +
 +fn bar(new: fn) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_closure_arg() {
 +        // FIXME: The argument in `bar` is wrong.
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    let closure = |x: i64| x - 1;
 +    $0bar(closure)
 +}
 +",
 +            r"
 +fn foo() {
 +    let closure = |x: i64| x - 1;
 +    bar(closure)
 +}
 +
 +fn bar(closure: _) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn unresolveable_types_default_to_placeholder() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    $0bar(baz)
 +}
 +",
 +            r"
 +fn foo() {
 +    bar(baz)
 +}
 +
 +fn bar(baz: _) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn arg_names_dont_overlap() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct Baz;
 +fn baz() -> Baz { Baz }
 +fn foo() {
 +    $0bar(baz(), baz())
 +}
 +",
 +            r"
 +struct Baz;
 +fn baz() -> Baz { Baz }
 +fn foo() {
 +    bar(baz(), baz())
 +}
 +
 +fn bar(baz_1: Baz, baz_2: Baz) {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn arg_name_counters_start_at_1_per_name() {
 +        check_assist(
 +            generate_function,
 +            r#"
 +struct Baz;
 +fn baz() -> Baz { Baz }
 +fn foo() {
 +    $0bar(baz(), baz(), "foo", "bar")
 +}
 +"#,
 +            r#"
 +struct Baz;
 +fn baz() -> Baz { Baz }
 +fn foo() {
 +    bar(baz(), baz(), "foo", "bar")
 +}
 +
 +fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) {
 +    ${0:todo!()}
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_in_module() {
 +        check_assist(
 +            generate_function,
 +            r"
 +mod bar {}
 +
 +fn foo() {
 +    bar::my_fn$0()
 +}
 +",
 +            r"
 +mod bar {
 +    pub(crate) fn my_fn() {
 +        ${0:todo!()}
 +    }
 +}
 +
 +fn foo() {
 +    bar::my_fn()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn qualified_path_uses_correct_scope() {
 +        check_assist(
 +            generate_function,
 +            r#"
 +mod foo {
 +    pub struct Foo;
 +}
 +fn bar() {
 +    use foo::Foo;
 +    let foo = Foo;
 +    baz$0(foo)
 +}
 +"#,
 +            r#"
 +mod foo {
 +    pub struct Foo;
 +}
 +fn bar() {
 +    use foo::Foo;
 +    let foo = Foo;
 +    baz(foo)
 +}
 +
 +fn baz(foo: foo::Foo) {
 +    ${0:todo!()}
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_in_module_containing_other_items() {
 +        check_assist(
 +            generate_function,
 +            r"
 +mod bar {
 +    fn something_else() {}
 +}
 +
 +fn foo() {
 +    bar::my_fn$0()
 +}
 +",
 +            r"
 +mod bar {
 +    fn something_else() {}
 +
 +    pub(crate) fn my_fn() {
 +        ${0:todo!()}
 +    }
 +}
 +
 +fn foo() {
 +    bar::my_fn()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_in_nested_module() {
 +        check_assist(
 +            generate_function,
 +            r"
 +mod bar {
 +    mod baz {}
 +}
 +
 +fn foo() {
 +    bar::baz::my_fn$0()
 +}
 +",
 +            r"
 +mod bar {
 +    mod baz {
 +        pub(crate) fn my_fn() {
 +            ${0:todo!()}
 +        }
 +    }
 +}
 +
 +fn foo() {
 +    bar::baz::my_fn()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_in_another_file() {
 +        check_assist(
 +            generate_function,
 +            r"
 +//- /main.rs
 +mod foo;
 +
 +fn main() {
 +    foo::bar$0()
 +}
 +//- /foo.rs
 +",
 +            r"
 +
 +
 +pub(crate) fn bar() {
 +    ${0:todo!()}
 +}",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_return_type() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn main() {
 +    let x: u32 = foo$0();
 +}
 +",
 +            r"
 +fn main() {
 +    let x: u32 = foo();
 +}
 +
 +fn foo() -> u32 {
 +    ${0:todo!()}
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_not_applicable_if_function_already_exists() {
 +        check_assist_not_applicable(
 +            generate_function,
 +            r"
 +fn foo() {
 +    bar$0();
 +}
 +
 +fn bar() {}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_not_applicable_if_unresolved_variable_in_call_is_selected() {
 +        check_assist_not_applicable(
 +            // bar is resolved, but baz isn't.
 +            // The assist is only active if the cursor is on an unresolved path,
 +            // but the assist should only be offered if the path is a function call.
 +            generate_function,
 +            r#"
 +fn foo() {
 +    bar(b$0az);
 +}
 +
 +fn bar(baz: ()) {}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn create_method_with_no_args() {
 +        check_assist(
 +            generate_function,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {
 +        self.bar()$0;
 +    }
 +}
 +"#,
 +            r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {
 +        self.bar();
 +    }
 +
 +    fn bar(&self) ${0:-> _} {
 +        todo!()
 +    }
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn create_function_with_async() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn foo() {
 +    $0bar(42).await();
 +}
 +",
 +            r"
 +fn foo() {
 +    bar(42).await();
 +}
 +
 +async fn bar(arg: i32) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_method() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +fn foo() {S.bar$0();}
 +",
 +            r"
 +struct S;
- fn foo() {S.bar();}
 +impl S {
- fn bar(&self) ${0:-> _} {
-     todo!()
- }
++    fn bar(&self) ${0:-> _} {
++        todo!()
++    }
 +}
++fn foo() {S.bar();}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_method_within_an_impl() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +fn foo() {S.bar$0();}
 +impl S {}
 +
 +",
 +            r"
 +struct S;
 +fn foo() {S.bar();}
 +impl S {
 +    fn bar(&self) ${0:-> _} {
 +        todo!()
 +    }
 +}
 +
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_method_from_different_module() {
 +        check_assist(
 +            generate_function,
 +            r"
 +mod s {
 +    pub struct S;
 +}
 +fn foo() {s::S.bar$0();}
 +",
 +            r"
 +mod s {
 +    pub struct S;
- impl S {
-     pub(crate) fn bar(&self) ${0:-> _} {
-         todo!()
++    impl S {
++        pub(crate) fn bar(&self) ${0:-> _} {
++            todo!()
++        }
 +    }
 +}
- }
 +fn foo() {s::S.bar();}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_method_from_descendant_module() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +mod s {
 +    fn foo() {
 +        super::S.bar$0();
 +    }
 +}
 +
 +",
 +            r"
 +struct S;
++impl S {
++    fn bar(&self) ${0:-> _} {
++        todo!()
++    }
++}
 +mod s {
 +    fn foo() {
 +        super::S.bar();
 +    }
 +}
- 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!()
- }
++    fn bar(&self) ${0:-> _} {
++        todo!()
++    }
 +}
++fn foo() {S.bar();}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_static_method() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +fn foo() {S::bar$0();}
 +",
 +            r"
 +struct S;
- fn foo() {S::bar();}
 +impl S {
- fn bar() ${0:-> _} {
-     todo!()
- }
++    fn bar() ${0:-> _} {
++        todo!()
++    }
 +}
++fn foo() {S::bar();}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_static_method_within_an_impl() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +fn foo() {S::bar$0();}
 +impl S {}
 +
 +",
 +            r"
 +struct S;
 +fn foo() {S::bar();}
 +impl S {
 +    fn bar() ${0:-> _} {
 +        todo!()
 +    }
 +}
 +
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_static_method_from_different_module() {
 +        check_assist(
 +            generate_function,
 +            r"
 +mod s {
 +    pub struct S;
 +}
 +fn foo() {s::S::bar$0();}
 +",
 +            r"
 +mod s {
 +    pub struct S;
- impl S {
-     pub(crate) fn bar() ${0:-> _} {
-         todo!()
++    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!()
- }
++    fn bar() ${0:-> _} {
++        todo!()
++    }
 +}
++fn foo() {S::bar();}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn create_static_method_within_an_impl_with_self_syntax() {
 +        check_assist(
 +            generate_function,
 +            r"
 +struct S;
 +impl S {
 +    fn foo(&self) {
 +        Self::bar$0();
 +    }
 +}
 +",
 +            r"
 +struct S;
 +impl S {
 +    fn foo(&self) {
 +        Self::bar();
 +    }
 +
 +    fn bar() ${0:-> _} {
 +        todo!()
 +    }
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn no_panic_on_invalid_global_path() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn main() {
 +    ::foo$0();
 +}
 +",
 +            r"
 +fn main() {
 +    ::foo();
 +}
 +
 +fn foo() ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn handle_tuple_indexing() {
 +        check_assist(
 +            generate_function,
 +            r"
 +fn main() {
 +    let a = ((),);
 +    foo$0(a.0);
 +}
 +",
 +            r"
 +fn main() {
 +    let a = ((),);
 +    foo(a.0);
 +}
 +
 +fn foo(a: ()) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_const_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +const VALUE: usize = 0;
 +fn main() {
 +    foo$0(VALUE);
 +}
 +",
 +            r"
 +const VALUE: usize = 0;
 +fn main() {
 +    foo(VALUE);
 +}
 +
 +fn foo(value: usize) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_static_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +static VALUE: usize = 0;
 +fn main() {
 +    foo$0(VALUE);
 +}
 +",
 +            r"
 +static VALUE: usize = 0;
 +fn main() {
 +    foo(VALUE);
 +}
 +
 +fn foo(value: usize) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn add_function_with_static_mut_arg() {
 +        check_assist(
 +            generate_function,
 +            r"
 +static mut VALUE: usize = 0;
 +fn main() {
 +    foo$0(VALUE);
 +}
 +",
 +            r"
 +static mut VALUE: usize = 0;
 +fn main() {
 +    foo(VALUE);
 +}
 +
 +fn foo(value: usize) ${0:-> _} {
 +    todo!()
 +}
 +",
 +        )
 +    }
 +
 +    #[test]
 +    fn not_applicable_for_enum_variant() {
 +        check_assist_not_applicable(
 +            generate_function,
 +            r"
 +enum Foo {}
 +fn main() {
 +    Foo::Bar$0(true)
 +}
 +",
 +        );
 +    }
 +
 +    #[test]
 +    fn applicable_for_enum_method() {
 +        check_assist(
 +            generate_function,
 +            r"
 +enum Foo {}
 +fn main() {
 +    Foo::new$0();
 +}
 +",
 +            r"
 +enum Foo {}
- fn main() {
-     Foo::new();
- }
 +impl Foo {
- fn new() ${0:-> _} {
-     todo!()
++    fn new() ${0:-> _} {
++        todo!()
++    }
 +}
++fn main() {
++    Foo::new();
 +}
 +",
 +        )
 +    }
 +}
index 68287a20bf8068ac45677908396ee9bf06c366fb,0000000000000000000000000000000000000000..307cea3d0a4f875aee3a92d954c133c0688c22c1
mode 100644,000000..100644
--- /dev/null
@@@ -1,177 -1,0 +1,190 @@@
 +use syntax::ast::{self, AstNode, HasName};
 +
 +use crate::{utils::generate_impl_text, AssistContext, AssistId, AssistKind, Assists};
 +
 +// Assist: generate_impl
 +//
 +// Adds a new inherent impl for a type.
 +//
 +// ```
 +// struct Ctx<T: Clone> {
 +//     data: T,$0
 +// }
 +// ```
 +// ->
 +// ```
 +// struct Ctx<T: Clone> {
 +//     data: T,
 +// }
 +//
 +// impl<T: Clone> Ctx<T> {
 +//     $0
 +// }
 +// ```
 +pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 +    let nominal = ctx.find_node_at_offset::<ast::Adt>()?;
 +    let name = nominal.name()?;
 +    let target = nominal.syntax().text_range();
 +
 +    acc.add(
 +        AssistId("generate_impl", AssistKind::Generate),
 +        format!("Generate impl for `{}`", name),
 +        target,
 +        |edit| {
 +            let start_offset = nominal.syntax().text_range().end();
 +            match ctx.config.snippet_cap {
 +                Some(cap) => {
 +                    let snippet = generate_impl_text(&nominal, "    $0");
 +                    edit.insert_snippet(cap, start_offset, snippet);
 +                }
 +                None => {
 +                    let snippet = generate_impl_text(&nominal, "");
 +                    edit.insert(start_offset, snippet);
 +                }
 +            }
 +        },
 +    )
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::{check_assist, check_assist_target};
 +
 +    use super::*;
 +
++    // FIXME: break up into separate test fns
 +    #[test]
 +    fn test_add_impl() {
 +        check_assist(
 +            generate_impl,
 +            "struct Foo {$0}\n",
 +            "struct Foo {}\n\nimpl Foo {\n    $0\n}\n",
 +        );
 +        check_assist(
 +            generate_impl,
 +            "struct Foo<T: Clone> {$0}",
 +            "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n    $0\n}",
 +        );
 +        check_assist(
 +            generate_impl,
 +            "struct Foo<'a, T: Foo<'a>> {$0}",
 +            "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n    $0\n}",
 +        );
 +        check_assist(
 +            generate_impl,
 +            r#"
 +            struct MyOwnArray<T, const S: usize> {}$0"#,
 +            r#"
 +            struct MyOwnArray<T, const S: usize> {}
 +
 +            impl<T, const S: usize> MyOwnArray<T, S> {
 +                $0
 +            }"#,
 +        );
 +        check_assist(
 +            generate_impl,
 +            r#"
 +            #[cfg(feature = "foo")]
 +            struct Foo<'a, T: Foo<'a>> {$0}"#,
 +            r#"
 +            #[cfg(feature = "foo")]
 +            struct Foo<'a, T: Foo<'a>> {}
 +
 +            #[cfg(feature = "foo")]
 +            impl<'a, T: Foo<'a>> Foo<'a, T> {
 +                $0
 +            }"#,
 +        );
 +
 +        check_assist(
 +            generate_impl,
 +            r#"
 +            #[cfg(not(feature = "foo"))]
 +            struct Foo<'a, T: Foo<'a>> {$0}"#,
 +            r#"
 +            #[cfg(not(feature = "foo"))]
 +            struct Foo<'a, T: Foo<'a>> {}
 +
 +            #[cfg(not(feature = "foo"))]
 +            impl<'a, T: Foo<'a>> Foo<'a, T> {
 +                $0
 +            }"#,
 +        );
 +
 +        check_assist(
 +            generate_impl,
 +            r#"
 +            struct Defaulted<T = i32> {}$0"#,
 +            r#"
 +            struct Defaulted<T = i32> {}
 +
 +            impl<T> Defaulted<T> {
 +                $0
 +            }"#,
 +        );
 +
 +        check_assist(
 +            generate_impl,
 +            r#"
 +            struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}$0"#,
 +            r#"
 +            struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}
 +
 +            impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> Defaulted<'a, 'b, T, S> {
 +                $0
 +            }"#,
 +        );
 +
++        check_assist(
++            generate_impl,
++            r#"
++            struct Defaulted<const N: i32 = 0> {}$0"#,
++            r#"
++            struct Defaulted<const N: i32 = 0> {}
++
++            impl<const N: i32> Defaulted<N> {
++                $0
++            }"#,
++        );
++
 +        check_assist(
 +            generate_impl,
 +            r#"pub trait Trait {}
 +struct Struct<T>$0
 +where
 +    T: Trait,
 +{
 +    inner: T,
 +}"#,
 +            r#"pub trait Trait {}
 +struct Struct<T>
 +where
 +    T: Trait,
 +{
 +    inner: T,
 +}
 +
 +impl<T> Struct<T>
 +where
 +    T: Trait,
 +{
 +    $0
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_impl_target() {
 +        check_assist_target(
 +            generate_impl,
 +            "
 +struct SomeThingIrrelevant;
 +/// Has a lifetime parameter
 +struct Foo<'a, T: Foo<'a>> {$0}
 +struct EvenMoreIrrelevant;
 +",
 +            "/// Has a lifetime parameter
 +struct Foo<'a, T: Foo<'a>> {}",
 +        );
 +    }
 +}
index 82bcc3dfa5d9a97c03142218498b715a0b75318b,0000000000000000000000000000000000000000..a07318cefad273dbdb4410b12a670f06f86107f9
mode 100644,000000..100644
--- /dev/null
@@@ -1,321 -1,0 +1,323 @@@
 +//! `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_named_struct_to_tuple_struct;
 +    mod convert_to_guarded_return;
 +    mod convert_two_arm_bool_match_to_matches_macro;
 +    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 move_format_string_arg;
 +    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 replace_or_with_or_else;
 +    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 unmerge_match_arm;
 +    mod unwrap_tuple;
 +    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_named_struct_to_tuple_struct::convert_named_struct_to_tuple_struct,
 +            convert_to_guarded_return::convert_to_guarded_return,
 +            convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
 +            convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro,
 +            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_format_string_arg::move_format_string_arg,
 +            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_or_with_or_else::replace_or_else_with_or,
 +            replace_or_with_or_else::replace_or_with_or_else,
 +            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_match_arm::unmerge_match_arm,
 +            unmerge_use::unmerge_use,
 +            unnecessary_async::unnecessary_async,
 +            unwrap_block::unwrap_block,
 +            unwrap_result_return_type::unwrap_result_return_type,
 +            unwrap_tuple::unwrap_tuple,
 +            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 a3bb66e379eb81887f221b9cdb54d73bdc9e3b19,0000000000000000000000000000000000000000..f7f2417d0745d7a4088ed75a11f7241875bb5663
mode 100644,000000..100644
--- /dev/null
@@@ -1,563 -1,0 +1,564 @@@
 +mod generated;
 +#[cfg(not(feature = "in-rust-tree"))]
 +mod sourcegen;
 +
 +use expect_test::expect;
 +use hir::{db::DefDatabase, Semantics};
 +use ide_db::{
 +    base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt},
 +    imports::insert_use::{ImportGranularity, InsertUseConfig},
 +    source_change::FileSystemEdit,
 +    RootDatabase, SnippetCap,
 +};
 +use stdx::{format_to, trim_indent};
 +use syntax::TextRange;
 +use test_utils::{assert_eq_text, extract_offset};
 +
 +use crate::{
 +    assists, handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind,
 +    AssistResolveStrategy, Assists, SingleResolve,
 +};
 +
 +pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
 +    snippet_cap: SnippetCap::new(true),
 +    allowed: None,
 +    insert_use: InsertUseConfig {
 +        granularity: ImportGranularity::Crate,
 +        prefix_kind: hir::PrefixKind::Plain,
 +        enforce_granularity: true,
 +        group: true,
 +        skip_glob_imports: true,
 +    },
 +    prefer_no_std: false,
 +};
 +
 +pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
 +    RootDatabase::with_single_file(text)
 +}
 +
 +#[track_caller]
 +pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_after: &str) {
 +    let ra_fixture_after = trim_indent(ra_fixture_after);
 +    check(assist, ra_fixture_before, ExpectedResult::After(&ra_fixture_after), None);
 +}
 +
 +// There is no way to choose what assist within a group you want to test against,
 +// so this is here to allow you choose.
 +pub(crate) fn check_assist_by_label(
 +    assist: Handler,
 +    ra_fixture_before: &str,
 +    ra_fixture_after: &str,
 +    label: &str,
 +) {
 +    let ra_fixture_after = trim_indent(ra_fixture_after);
 +    check(assist, ra_fixture_before, ExpectedResult::After(&ra_fixture_after), Some(label));
 +}
 +
 +// FIXME: instead of having a separate function here, maybe use
 +// `extract_ranges` and mark the target as `<target> </target>` in the
 +// fixture?
 +#[track_caller]
 +pub(crate) fn check_assist_target(assist: Handler, ra_fixture: &str, target: &str) {
 +    check(assist, ra_fixture, ExpectedResult::Target(target), None);
 +}
 +
 +#[track_caller]
 +pub(crate) fn check_assist_not_applicable(assist: Handler, ra_fixture: &str) {
 +    check(assist, ra_fixture, ExpectedResult::NotApplicable, None);
 +}
 +
 +/// Check assist in unresolved state. Useful to check assists for lazy computation.
 +#[track_caller]
 +pub(crate) fn check_assist_unresolved(assist: Handler, ra_fixture: &str) {
 +    check(assist, ra_fixture, ExpectedResult::Unresolved, None);
 +}
 +
 +#[track_caller]
 +fn check_doc_test(assist_id: &str, before: &str, after: &str) {
 +    let after = trim_indent(after);
 +    let (db, file_id, selection) = RootDatabase::with_range_or_offset(before);
 +    let before = db.file_text(file_id).to_string();
 +    let frange = FileRange { file_id, range: selection.into() };
 +
 +    let assist = assists(&db, &TEST_CONFIG, AssistResolveStrategy::All, frange)
 +        .into_iter()
 +        .find(|assist| assist.id.0 == assist_id)
 +        .unwrap_or_else(|| {
 +            panic!(
 +                "\n\nAssist is not applicable: {}\nAvailable assists: {}",
 +                assist_id,
 +                assists(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange)
 +                    .into_iter()
 +                    .map(|assist| assist.id.0)
 +                    .collect::<Vec<_>>()
 +                    .join(", ")
 +            )
 +        });
 +
 +    let actual = {
 +        let source_change = assist
 +            .source_change
 +            .filter(|it| !it.source_file_edits.is_empty() || !it.file_system_edits.is_empty())
 +            .expect("Assist did not contain any source changes");
 +        let mut actual = before;
 +        if let Some(source_file_edit) = source_change.get_source_edit(file_id) {
 +            source_file_edit.apply(&mut actual);
 +        }
 +        actual
 +    };
 +    assert_eq_text!(&after, &actual);
 +}
 +
 +enum ExpectedResult<'a> {
 +    NotApplicable,
 +    Unresolved,
 +    After(&'a str),
 +    Target(&'a str),
 +}
 +
 +#[track_caller]
 +fn check(handler: Handler, before: &str, expected: ExpectedResult<'_>, assist_label: Option<&str>) {
 +    let (mut db, file_with_caret_id, range_or_offset) = RootDatabase::with_range_or_offset(before);
 +    db.set_enable_proc_attr_macros(true);
 +    let text_without_caret = db.file_text(file_with_caret_id).to_string();
 +
 +    let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() };
 +
 +    let sema = Semantics::new(&db);
 +    let config = TEST_CONFIG;
 +    let ctx = AssistContext::new(sema, &config, frange);
 +    let resolve = match expected {
 +        ExpectedResult::Unresolved => AssistResolveStrategy::None,
 +        _ => AssistResolveStrategy::All,
 +    };
 +    let mut acc = Assists::new(&ctx, resolve);
 +    handler(&mut acc, &ctx);
 +    let mut res = acc.finish();
 +
 +    let assist = match assist_label {
 +        Some(label) => res.into_iter().find(|resolved| resolved.label == label),
 +        None => res.pop(),
 +    };
 +
 +    match (assist, expected) {
 +        (Some(assist), ExpectedResult::After(after)) => {
 +            let source_change = assist
 +                .source_change
 +                .filter(|it| !it.source_file_edits.is_empty() || !it.file_system_edits.is_empty())
 +                .expect("Assist did not contain any source changes");
 +            let skip_header = source_change.source_file_edits.len() == 1
 +                && source_change.file_system_edits.len() == 0;
 +
 +            let mut buf = String::new();
 +            for (file_id, edit) in source_change.source_file_edits {
 +                let mut text = db.file_text(file_id).as_ref().to_owned();
 +                edit.apply(&mut text);
 +                if !skip_header {
 +                    let sr = db.file_source_root(file_id);
 +                    let sr = db.source_root(sr);
 +                    let path = sr.path_for_file(&file_id).unwrap();
 +                    format_to!(buf, "//- {}\n", path)
 +                }
 +                buf.push_str(&text);
 +            }
 +
 +            for file_system_edit in source_change.file_system_edits {
 +                let (dst, contents) = match file_system_edit {
 +                    FileSystemEdit::CreateFile { dst, initial_contents } => (dst, initial_contents),
 +                    FileSystemEdit::MoveFile { src, dst } => {
 +                        (dst, db.file_text(src).as_ref().to_owned())
 +                    }
 +                    FileSystemEdit::MoveDir { src, src_id, dst } => {
 +                        // temporary placeholder for MoveDir since we are not using MoveDir in ide assists yet.
 +                        (dst, format!("{:?}\n{:?}", src_id, src))
 +                    }
 +                };
 +                let sr = db.file_source_root(dst.anchor);
 +                let sr = db.source_root(sr);
 +                let mut base = sr.path_for_file(&dst.anchor).unwrap().clone();
 +                base.pop();
 +                let created_file_path = base.join(&dst.path).unwrap();
 +                format_to!(buf, "//- {}\n", created_file_path);
 +                buf.push_str(&contents);
 +            }
 +
 +            assert_eq_text!(after, &buf);
 +        }
 +        (Some(assist), ExpectedResult::Target(target)) => {
 +            let range = assist.target;
 +            assert_eq_text!(&text_without_caret[range], target);
 +        }
 +        (Some(assist), ExpectedResult::Unresolved) => assert!(
 +            assist.source_change.is_none(),
 +            "unresolved assist should not contain source changes"
 +        ),
 +        (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"),
 +        (
 +            None,
 +            ExpectedResult::After(_) | ExpectedResult::Target(_) | ExpectedResult::Unresolved,
 +        ) => {
 +            panic!("code action is not applicable")
 +        }
 +        (None, ExpectedResult::NotApplicable) => (),
 +    };
 +}
 +
 +fn labels(assists: &[Assist]) -> String {
 +    let mut labels = assists
 +        .iter()
 +        .map(|assist| {
 +            let mut label = match &assist.group {
 +                Some(g) => g.0.clone(),
 +                None => assist.label.to_string(),
 +            };
 +            label.push('\n');
 +            label
 +        })
 +        .collect::<Vec<_>>();
 +    labels.dedup();
 +    labels.into_iter().collect::<String>()
 +}
 +
 +#[test]
 +fn assist_order_field_struct() {
 +    let before = "struct Foo { $0bar: u32 }";
 +    let (before_cursor_pos, before) = extract_offset(before);
 +    let (db, file_id) = with_single_file(&before);
 +    let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) };
 +    let assists = assists(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange);
 +    let mut assists = assists.iter();
 +
 +    assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)");
 +    assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method");
 +    assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method");
 +    assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method");
++    assert_eq!(assists.next().expect("expected assist").label, "Convert to tuple struct");
 +    assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`");
 +}
 +
 +#[test]
 +fn assist_order_if_expr() {
 +    let (db, frange) = RootDatabase::with_range(
 +        r#"
 +pub fn test_some_range(a: int) -> bool {
 +    if let 2..6 = $05$0 {
 +        true
 +    } else {
 +        false
 +    }
 +}
 +"#,
 +    );
 +
 +    let assists = assists(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange);
 +    let expected = labels(&assists);
 +
 +    expect![[r#"
 +        Convert integer base
 +        Extract into variable
 +        Extract into function
 +        Replace if let with match
 +    "#]]
 +    .assert_eq(&expected);
 +}
 +
 +#[test]
 +fn assist_filter_works() {
 +    let (db, frange) = RootDatabase::with_range(
 +        r#"
 +pub fn test_some_range(a: int) -> bool {
 +    if let 2..6 = $05$0 {
 +        true
 +    } else {
 +        false
 +    }
 +}
 +"#,
 +    );
 +    {
 +        let mut cfg = TEST_CONFIG;
 +        cfg.allowed = Some(vec![AssistKind::Refactor]);
 +
 +        let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange);
 +        let expected = labels(&assists);
 +
 +        expect![[r#"
 +            Convert integer base
 +            Extract into variable
 +            Extract into function
 +            Replace if let with match
 +        "#]]
 +        .assert_eq(&expected);
 +    }
 +
 +    {
 +        let mut cfg = TEST_CONFIG;
 +        cfg.allowed = Some(vec![AssistKind::RefactorExtract]);
 +        let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange);
 +        let expected = labels(&assists);
 +
 +        expect![[r#"
 +            Extract into variable
 +            Extract into function
 +        "#]]
 +        .assert_eq(&expected);
 +    }
 +
 +    {
 +        let mut cfg = TEST_CONFIG;
 +        cfg.allowed = Some(vec![AssistKind::QuickFix]);
 +        let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange);
 +        let expected = labels(&assists);
 +
 +        expect![[r#""#]].assert_eq(&expected);
 +    }
 +}
 +
 +#[test]
 +fn various_resolve_strategies() {
 +    let (db, frange) = RootDatabase::with_range(
 +        r#"
 +pub fn test_some_range(a: int) -> bool {
 +    if let 2..6 = $05$0 {
 +        true
 +    } else {
 +        false
 +    }
 +}
 +"#,
 +    );
 +
 +    let mut cfg = TEST_CONFIG;
 +    cfg.allowed = Some(vec![AssistKind::RefactorExtract]);
 +
 +    {
 +        let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange);
 +        assert_eq!(2, assists.len());
 +        let mut assists = assists.into_iter();
 +
 +        let extract_into_variable_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_variable",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into variable",
 +                group: None,
 +                target: 59..60,
 +                source_change: None,
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_variable_assist);
 +
 +        let extract_into_function_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_function",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into function",
 +                group: None,
 +                target: 59..60,
 +                source_change: None,
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_function_assist);
 +    }
 +
 +    {
 +        let assists = assists(
 +            &db,
 +            &cfg,
 +            AssistResolveStrategy::Single(SingleResolve {
 +                assist_id: "SOMETHING_MISMATCHING".to_string(),
 +                assist_kind: AssistKind::RefactorExtract,
 +            }),
 +            frange,
 +        );
 +        assert_eq!(2, assists.len());
 +        let mut assists = assists.into_iter();
 +
 +        let extract_into_variable_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_variable",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into variable",
 +                group: None,
 +                target: 59..60,
 +                source_change: None,
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_variable_assist);
 +
 +        let extract_into_function_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_function",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into function",
 +                group: None,
 +                target: 59..60,
 +                source_change: None,
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_function_assist);
 +    }
 +
 +    {
 +        let assists = assists(
 +            &db,
 +            &cfg,
 +            AssistResolveStrategy::Single(SingleResolve {
 +                assist_id: "extract_variable".to_string(),
 +                assist_kind: AssistKind::RefactorExtract,
 +            }),
 +            frange,
 +        );
 +        assert_eq!(2, assists.len());
 +        let mut assists = assists.into_iter();
 +
 +        let extract_into_variable_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_variable",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into variable",
 +                group: None,
 +                target: 59..60,
 +                source_change: Some(
 +                    SourceChange {
 +                        source_file_edits: {
 +                            FileId(
 +                                0,
 +                            ): TextEdit {
 +                                indels: [
 +                                    Indel {
 +                                        insert: "let $0var_name = 5;\n    ",
 +                                        delete: 45..45,
 +                                    },
 +                                    Indel {
 +                                        insert: "var_name",
 +                                        delete: 59..60,
 +                                    },
 +                                ],
 +                            },
 +                        },
 +                        file_system_edits: [],
 +                        is_snippet: true,
 +                    },
 +                ),
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_variable_assist);
 +
 +        let extract_into_function_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_function",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into function",
 +                group: None,
 +                target: 59..60,
 +                source_change: None,
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_function_assist);
 +    }
 +
 +    {
 +        let assists = assists(&db, &cfg, AssistResolveStrategy::All, frange);
 +        assert_eq!(2, assists.len());
 +        let mut assists = assists.into_iter();
 +
 +        let extract_into_variable_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_variable",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into variable",
 +                group: None,
 +                target: 59..60,
 +                source_change: Some(
 +                    SourceChange {
 +                        source_file_edits: {
 +                            FileId(
 +                                0,
 +                            ): TextEdit {
 +                                indels: [
 +                                    Indel {
 +                                        insert: "let $0var_name = 5;\n    ",
 +                                        delete: 45..45,
 +                                    },
 +                                    Indel {
 +                                        insert: "var_name",
 +                                        delete: 59..60,
 +                                    },
 +                                ],
 +                            },
 +                        },
 +                        file_system_edits: [],
 +                        is_snippet: true,
 +                    },
 +                ),
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_variable_assist);
 +
 +        let extract_into_function_assist = assists.next().unwrap();
 +        expect![[r#"
 +            Assist {
 +                id: AssistId(
 +                    "extract_function",
 +                    RefactorExtract,
 +                ),
 +                label: "Extract into function",
 +                group: None,
 +                target: 59..60,
 +                source_change: Some(
 +                    SourceChange {
 +                        source_file_edits: {
 +                            FileId(
 +                                0,
 +                            ): TextEdit {
 +                                indels: [
 +                                    Indel {
 +                                        insert: "fun_name()",
 +                                        delete: 59..60,
 +                                    },
 +                                    Indel {
 +                                        insert: "\n\nfn $0fun_name() -> i32 {\n    5\n}",
 +                                        delete: 110..110,
 +                                    },
 +                                ],
 +                            },
 +                        },
 +                        file_system_edits: [],
 +                        is_snippet: true,
 +                    },
 +                ),
 +                trigger_signature_help: false,
 +            }
 +        "#]]
 +        .assert_debug_eq(&extract_into_function_assist);
 +    }
 +}
index d403f86c6d8c9ff9cc20c1d2c51e2a5ebbb12d57,0000000000000000000000000000000000000000..2c4000efe0fa25a9f0c159d0c5f2f046ab04c9b5
mode 100644,000000..100644
--- /dev/null
@@@ -1,2420 -1,0 +1,2461 @@@
 +//! 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_named_struct_to_tuple_struct() {
++    check_doc_test(
++        "convert_named_struct_to_tuple_struct",
++        r#####"
++struct Point$0 { x: f32, y: f32 }
++
++impl Point {
++    pub fn new(x: f32, y: f32) -> Self {
++        Point { x, y }
++    }
++
++    pub fn x(&self) -> f32 {
++        self.x
++    }
++
++    pub fn y(&self) -> f32 {
++        self.y
++    }
++}
++"#####,
++        r#####"
++struct Point(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
++    }
++}
++"#####,
++    )
++}
++
 +#[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_two_arm_bool_match_to_matches_macro() {
 +    check_doc_test(
 +        "convert_two_arm_bool_match_to_matches_macro",
 +        r#####"
 +fn main() {
 +    match scrutinee$0 {
 +        Some(val) if val.cond() => true,
 +        _ => false,
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    matches!(scrutinee, Some(val) if val.cond())
 +}
 +"#####,
 +    )
 +}
 +
 +#[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#####"
 +
 +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_format_string_arg() {
 +    check_doc_test(
 +        "move_format_string_arg",
 +        r#####"
 +macro_rules! format_args {
 +    ($lit:literal $(tt:tt)*) => { 0 },
 +}
 +macro_rules! print {
 +    ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
 +}
 +
 +fn main() {
 +    print!("{x + 1}$0");
 +}
 +"#####,
 +        r#####"
 +macro_rules! format_args {
 +    ($lit:literal $(tt:tt)*) => { 0 },
 +}
 +macro_rules! print {
 +    ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
 +}
 +
 +fn main() {
 +    print!("{}"$0, x + 1);
 +}
 +"#####,
 +    )
 +}
 +
 +#[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_or_else_with_or() {
 +    check_doc_test(
 +        "replace_or_else_with_or",
 +        r#####"
 +//- minicore:option
 +fn foo() {
 +    let a = Some(1);
 +    a.unwra$0p_or_else(|| 2);
 +}
 +"#####,
 +        r#####"
 +fn foo() {
 +    let a = Some(1);
 +    a.unwrap_or(2);
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_or_with_or_else() {
 +    check_doc_test(
 +        "replace_or_with_or_else",
 +        r#####"
 +//- minicore:option
 +fn foo() {
 +    let a = Some(1);
 +    a.unwra$0p_or(2);
 +}
 +"#####,
 +        r#####"
 +fn foo() {
 +    let a = Some(1);
 +    a.unwrap_or_else(|| 2);
 +}
 +"#####,
 +    )
 +}
 +
 +#[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_match_arm() {
 +    check_doc_test(
 +        "unmerge_match_arm",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move(..) $0| Action::Stop => foo(),
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move(..) => foo(),
 +        Action::Stop => foo(),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[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_unwrap_tuple() {
 +    check_doc_test(
 +        "unwrap_tuple",
 +        r#####"
 +//- minicore: result
 +fn main() {
 +    $0let (foo, bar) = ("Foo", "Bar");
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let foo = "Foo";
 +    let bar = "Bar";
 +}
 +"#####,
 +    )
 +}
 +
 +#[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 4ab6e2627fa75413837b55be578c1a237a4147c3,0000000000000000000000000000000000000000..38396cd7d7bafd47c36e4d4d473915cdc41f827a
mode 100644,000000..100644
--- /dev/null
@@@ -1,703 -1,0 +1,703 @@@
- use itertools::Itertools;
 +//! Assorted functions shared by several assists.
 +
 +use std::ops;
 +
-     ted, AstNode, AstToken, Direction, SmolStr, SourceFile,
 +pub(crate) use gen_trait_fn_body::gen_trait_fn_body;
 +use hir::{db::HirDatabase, HirDisplay, Semantics};
 +use ide_db::{famous_defs::FamousDefs, path_transform::PathTransform, RootDatabase, SnippetCap};
 +use stdx::format_to;
 +use syntax::{
 +    ast::{
 +        self,
 +        edit::{self, AstNodeEdit},
 +        edit_in_place::{AttrsOwnerEdit, Removable},
 +        make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
 +    },
-     let generic_params = adt.generic_param_list();
++    ted, AstNode, AstToken, Direction, SourceFile,
 +    SyntaxKind::*,
 +    SyntaxNode, TextRange, TextSize, T,
 +};
 +
 +use crate::assist_context::{AssistContext, SourceChangeBuilder};
 +
 +pub(crate) mod suggest_name;
 +mod gen_trait_fn_body;
 +
 +pub(crate) fn unwrap_trivial_block(block_expr: ast::BlockExpr) -> ast::Expr {
 +    extract_trivial_expression(&block_expr)
 +        .filter(|expr| !expr.syntax().text().contains_char('\n'))
 +        .unwrap_or_else(|| block_expr.into())
 +}
 +
 +pub fn extract_trivial_expression(block_expr: &ast::BlockExpr) -> Option<ast::Expr> {
 +    if block_expr.modifier().is_some() {
 +        return None;
 +    }
 +    let stmt_list = block_expr.stmt_list()?;
 +    let has_anything_else = |thing: &SyntaxNode| -> bool {
 +        let mut non_trivial_children =
 +            stmt_list.syntax().children_with_tokens().filter(|it| match it.kind() {
 +                WHITESPACE | T!['{'] | T!['}'] => false,
 +                _ => it.as_node() != Some(thing),
 +            });
 +        non_trivial_children.next().is_some()
 +    };
 +
 +    if let Some(expr) = stmt_list.tail_expr() {
 +        if has_anything_else(expr.syntax()) {
 +            return None;
 +        }
 +        return Some(expr);
 +    }
 +    // Unwrap `{ continue; }`
 +    let stmt = stmt_list.statements().next()?;
 +    if let ast::Stmt::ExprStmt(expr_stmt) = stmt {
 +        if has_anything_else(expr_stmt.syntax()) {
 +            return None;
 +        }
 +        let expr = expr_stmt.expr()?;
 +        if matches!(expr.syntax().kind(), CONTINUE_EXPR | BREAK_EXPR | RETURN_EXPR) {
 +            return Some(expr);
 +        }
 +    }
 +    None
 +}
 +
 +/// This is a method with a heuristics to support test methods annotated with custom test annotations, such as
 +/// `#[test_case(...)]`, `#[tokio::test]` and similar.
 +/// Also a regular `#[test]` annotation is supported.
 +///
 +/// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test,
 +/// but it's better than not to have the runnables for the tests at all.
 +pub fn test_related_attribute(fn_def: &ast::Fn) -> Option<ast::Attr> {
 +    fn_def.attrs().find_map(|attr| {
 +        let path = attr.path()?;
 +        let text = path.syntax().text().to_string();
 +        if text.starts_with("test") || text.ends_with("test") {
 +            Some(attr)
 +        } else {
 +            None
 +        }
 +    })
 +}
 +
 +#[derive(Copy, Clone, PartialEq)]
 +pub enum DefaultMethods {
 +    Only,
 +    No,
 +}
 +
 +pub fn filter_assoc_items(
 +    sema: &Semantics<'_, RootDatabase>,
 +    items: &[hir::AssocItem],
 +    default_methods: DefaultMethods,
 +) -> Vec<ast::AssocItem> {
 +    fn has_def_name(item: &ast::AssocItem) -> bool {
 +        match item {
 +            ast::AssocItem::Fn(def) => def.name(),
 +            ast::AssocItem::TypeAlias(def) => def.name(),
 +            ast::AssocItem::Const(def) => def.name(),
 +            ast::AssocItem::MacroCall(_) => None,
 +        }
 +        .is_some()
 +    }
 +
 +    items
 +        .iter()
 +        // Note: This throws away items with no source.
 +        .filter_map(|&i| {
 +            let item = match i {
 +                hir::AssocItem::Function(i) => ast::AssocItem::Fn(sema.source(i)?.value),
 +                hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(sema.source(i)?.value),
 +                hir::AssocItem::Const(i) => ast::AssocItem::Const(sema.source(i)?.value),
 +            };
 +            Some(item)
 +        })
 +        .filter(has_def_name)
 +        .filter(|it| match it {
 +            ast::AssocItem::Fn(def) => matches!(
 +                (default_methods, def.body()),
 +                (DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None)
 +            ),
 +            _ => default_methods == DefaultMethods::No,
 +        })
 +        .collect::<Vec<_>>()
 +}
 +
 +pub fn add_trait_assoc_items_to_impl(
 +    sema: &Semantics<'_, RootDatabase>,
 +    items: Vec<ast::AssocItem>,
 +    trait_: hir::Trait,
 +    impl_: ast::Impl,
 +    target_scope: hir::SemanticsScope<'_>,
 +) -> (ast::Impl, ast::AssocItem) {
 +    let source_scope = sema.scope_for_def(trait_);
 +
 +    let transform = PathTransform::trait_impl(&target_scope, &source_scope, trait_, impl_.clone());
 +
 +    let items = items.into_iter().map(|assoc_item| {
 +        transform.apply(assoc_item.syntax());
 +        assoc_item.remove_attrs_and_docs();
 +        assoc_item
 +    });
 +
 +    let res = impl_.clone_for_update();
 +
 +    let assoc_item_list = res.get_or_create_assoc_item_list();
 +    let mut first_item = None;
 +    for item in items {
 +        first_item.get_or_insert_with(|| item.clone());
 +        match &item {
 +            ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
 +                let body = make::block_expr(None, Some(make::ext::expr_todo()))
 +                    .indent(edit::IndentLevel(1));
 +                ted::replace(fn_.get_or_create_body().syntax(), body.clone_for_update().syntax())
 +            }
 +            ast::AssocItem::TypeAlias(type_alias) => {
 +                if let Some(type_bound_list) = type_alias.type_bound_list() {
 +                    type_bound_list.remove()
 +                }
 +            }
 +            _ => {}
 +        }
 +
 +        assoc_item_list.add_item(item)
 +    }
 +
 +    (res, first_item.unwrap())
 +}
 +
 +#[derive(Clone, Copy, Debug)]
 +pub(crate) enum Cursor<'a> {
 +    Replace(&'a SyntaxNode),
 +    Before(&'a SyntaxNode),
 +}
 +
 +impl<'a> Cursor<'a> {
 +    fn node(self) -> &'a SyntaxNode {
 +        match self {
 +            Cursor::Replace(node) | Cursor::Before(node) => node,
 +        }
 +    }
 +}
 +
 +pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor<'_>) -> String {
 +    assert!(cursor.node().ancestors().any(|it| it == *node));
 +    let range = cursor.node().text_range() - node.text_range().start();
 +    let range: ops::Range<usize> = range.into();
 +
 +    let mut placeholder = cursor.node().to_string();
 +    escape(&mut placeholder);
 +    let tab_stop = match cursor {
 +        Cursor::Replace(placeholder) => format!("${{0:{}}}", placeholder),
 +        Cursor::Before(placeholder) => format!("$0{}", placeholder),
 +    };
 +
 +    let mut buf = node.to_string();
 +    buf.replace_range(range, &tab_stop);
 +    return buf;
 +
 +    fn escape(buf: &mut String) {
 +        stdx::replace(buf, '{', r"\{");
 +        stdx::replace(buf, '}', r"\}");
 +        stdx::replace(buf, '$', r"\$");
 +    }
 +}
 +
 +pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
 +    node.children_with_tokens()
 +        .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
 +        .map(|it| it.text_range().start())
 +        .unwrap_or_else(|| node.text_range().start())
 +}
 +
 +pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr {
 +    invert_special_case(&expr).unwrap_or_else(|| make::expr_prefix(T![!], expr))
 +}
 +
 +fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
 +    match expr {
 +        ast::Expr::BinExpr(bin) => {
 +            let bin = bin.clone_for_update();
 +            let op_token = bin.op_token()?;
 +            let rev_token = match op_token.kind() {
 +                T![==] => T![!=],
 +                T![!=] => T![==],
 +                T![<] => T![>=],
 +                T![<=] => T![>],
 +                T![>] => T![<=],
 +                T![>=] => T![<],
 +                // Parenthesize other expressions before prefixing `!`
 +                _ => return Some(make::expr_prefix(T![!], make::expr_paren(expr.clone()))),
 +            };
 +            ted::replace(op_token, make::token(rev_token));
 +            Some(bin.into())
 +        }
 +        ast::Expr::MethodCallExpr(mce) => {
 +            let receiver = mce.receiver()?;
 +            let method = mce.name_ref()?;
 +            let arg_list = mce.arg_list()?;
 +
 +            let method = match method.text().as_str() {
 +                "is_some" => "is_none",
 +                "is_none" => "is_some",
 +                "is_ok" => "is_err",
 +                "is_err" => "is_ok",
 +                _ => return None,
 +            };
 +            Some(make::expr_method_call(receiver, make::name_ref(method), arg_list))
 +        }
 +        ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::UnaryOp::Not => match pe.expr()? {
 +            ast::Expr::ParenExpr(parexpr) => parexpr.expr(),
 +            _ => pe.expr(),
 +        },
 +        ast::Expr::Literal(lit) => match lit.kind() {
 +            ast::LiteralKind::Bool(b) => match b {
 +                true => Some(ast::Expr::Literal(make::expr_literal("false"))),
 +                false => Some(ast::Expr::Literal(make::expr_literal("true"))),
 +            },
 +            _ => None,
 +        },
 +        _ => None,
 +    }
 +}
 +
 +pub(crate) fn next_prev() -> impl Iterator<Item = Direction> {
 +    [Direction::Next, Direction::Prev].into_iter()
 +}
 +
 +pub(crate) fn does_pat_match_variant(pat: &ast::Pat, var: &ast::Pat) -> bool {
 +    let first_node_text = |pat: &ast::Pat| pat.syntax().first_child().map(|node| node.text());
 +
 +    let pat_head = match pat {
 +        ast::Pat::IdentPat(bind_pat) => match bind_pat.pat() {
 +            Some(p) => first_node_text(&p),
 +            None => return pat.syntax().text() == var.syntax().text(),
 +        },
 +        pat => first_node_text(pat),
 +    };
 +
 +    let var_head = first_node_text(var);
 +
 +    pat_head == var_head
 +}
 +
 +pub(crate) fn does_nested_pattern(pat: &ast::Pat) -> bool {
 +    let depth = calc_depth(pat, 0);
 +
 +    if 1 < depth {
 +        return true;
 +    }
 +    false
 +}
 +
 +fn calc_depth(pat: &ast::Pat, depth: usize) -> usize {
 +    match pat {
 +        ast::Pat::IdentPat(_)
 +        | ast::Pat::BoxPat(_)
 +        | ast::Pat::RestPat(_)
 +        | ast::Pat::LiteralPat(_)
 +        | ast::Pat::MacroPat(_)
 +        | ast::Pat::OrPat(_)
 +        | ast::Pat::ParenPat(_)
 +        | ast::Pat::PathPat(_)
 +        | ast::Pat::WildcardPat(_)
 +        | ast::Pat::RangePat(_)
 +        | ast::Pat::RecordPat(_)
 +        | ast::Pat::RefPat(_)
 +        | ast::Pat::SlicePat(_)
 +        | ast::Pat::TuplePat(_)
 +        | ast::Pat::ConstBlockPat(_) => depth,
 +
 +        // FIXME: Other patterns may also be nested. Currently it simply supports only `TupleStructPat`
 +        ast::Pat::TupleStructPat(pat) => {
 +            let mut max_depth = depth;
 +            for p in pat.fields() {
 +                let d = calc_depth(&p, depth + 1);
 +                if d > max_depth {
 +                    max_depth = d
 +                }
 +            }
 +            max_depth
 +        }
 +    }
 +}
 +
 +// Uses a syntax-driven approach to find any impl blocks for the struct that
 +// exist within the module/file
 +//
 +// Returns `None` if we've found an existing fn
 +//
 +// FIXME: change the new fn checking to a more semantic approach when that's more
 +// viable (e.g. we process proc macros, etc)
 +// FIXME: this partially overlaps with `find_impl_block_*`
 +pub(crate) fn find_struct_impl(
 +    ctx: &AssistContext<'_>,
 +    adt: &ast::Adt,
 +    name: &str,
 +) -> Option<Option<ast::Impl>> {
 +    let db = ctx.db();
 +    let module = adt.syntax().parent()?;
 +
 +    let struct_def = ctx.sema.to_def(adt)?;
 +
 +    let block = module.descendants().filter_map(ast::Impl::cast).find_map(|impl_blk| {
 +        let blk = ctx.sema.to_def(&impl_blk)?;
 +
 +        // FIXME: handle e.g. `struct S<T>; impl<U> S<U> {}`
 +        // (we currently use the wrong type parameter)
 +        // also we wouldn't want to use e.g. `impl S<u32>`
 +
 +        let same_ty = match blk.self_ty(db).as_adt() {
 +            Some(def) => def == struct_def,
 +            None => false,
 +        };
 +        let not_trait_impl = blk.trait_(db).is_none();
 +
 +        if !(same_ty && not_trait_impl) {
 +            None
 +        } else {
 +            Some(impl_blk)
 +        }
 +    });
 +
 +    if let Some(ref impl_blk) = block {
 +        if has_fn(impl_blk, name) {
 +            return None;
 +        }
 +    }
 +
 +    Some(block)
 +}
 +
 +fn has_fn(imp: &ast::Impl, rhs_name: &str) -> bool {
 +    if let Some(il) = imp.assoc_item_list() {
 +        for item in il.assoc_items() {
 +            if let ast::AssocItem::Fn(f) = item {
 +                if let Some(name) = f.name() {
 +                    if name.text().eq_ignore_ascii_case(rhs_name) {
 +                        return true;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    false
 +}
 +
 +/// Find the start of the `impl` block for the given `ast::Impl`.
 +//
 +// FIXME: this partially overlaps with `find_struct_impl`
 +pub(crate) fn find_impl_block_start(impl_def: ast::Impl, buf: &mut String) -> Option<TextSize> {
 +    buf.push('\n');
 +    let start = impl_def.assoc_item_list().and_then(|it| it.l_curly_token())?.text_range().end();
 +    Some(start)
 +}
 +
 +/// Find the end of the `impl` block for the given `ast::Impl`.
 +//
 +// FIXME: this partially overlaps with `find_struct_impl`
 +pub(crate) fn find_impl_block_end(impl_def: ast::Impl, buf: &mut String) -> Option<TextSize> {
 +    buf.push('\n');
 +    let end = impl_def
 +        .assoc_item_list()
 +        .and_then(|it| it.r_curly_token())?
 +        .prev_sibling_or_token()?
 +        .text_range()
 +        .end();
 +    Some(end)
 +}
 +
 +// Generates the surrounding `impl Type { <code> }` including type and lifetime
 +// parameters
 +pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String {
 +    generate_impl_text_inner(adt, None, code)
 +}
 +
 +// Generates the surrounding `impl <trait> for Type { <code> }` including type
 +// and lifetime parameters
 +pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &str) -> String {
 +    generate_impl_text_inner(adt, Some(trait_text), code)
 +}
 +
 +fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str) -> String {
-     adt.attrs()
-         .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false))
-         .for_each(|attr| buf.push_str(format!("{}\n", attr).as_str()));
++    // Ensure lifetime params are before type & const params
++    let generic_params = adt.generic_param_list().map(|generic_params| {
++        let lifetime_params =
++            generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
++        let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| {
++            // remove defaults since they can't be specified in impls
++            match param {
++                ast::TypeOrConstParam::Type(param) => {
++                    let param = param.clone_for_update();
++                    param.remove_default();
++                    Some(ast::GenericParam::TypeParam(param))
++                }
++                ast::TypeOrConstParam::Const(param) => {
++                    let param = param.clone_for_update();
++                    param.remove_default();
++                    Some(ast::GenericParam::ConstParam(param))
++                }
++            }
++        });
++
++        make::generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
++    });
++
++    // FIXME: use syntax::make & mutable AST apis instead
++    // `trait_text` and `code` can't be opaque blobs of text
 +    let mut buf = String::with_capacity(code.len());
++
++    // Copy any cfg attrs from the original adt
 +    buf.push_str("\n\n");
-         let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
-         let toc_params = generic_params.type_or_const_params().map(|toc_param| {
-             let type_param = match toc_param {
-                 ast::TypeOrConstParam::Type(x) => x,
-                 ast::TypeOrConstParam::Const(x) => return x.syntax().to_string(),
-             };
-             let mut buf = String::new();
-             if let Some(it) = type_param.name() {
-                 format_to!(buf, "{}", it.syntax());
-             }
-             if let Some(it) = type_param.colon_token() {
-                 format_to!(buf, "{} ", it);
-             }
-             if let Some(it) = type_param.type_bound_list() {
-                 format_to!(buf, "{}", it.syntax());
-             }
-             buf
-         });
-         let generics = lifetimes.chain(toc_params).format(", ");
-         format_to!(buf, "<{}>", generics);
++    let cfg_attrs = adt
++        .attrs()
++        .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false));
++    cfg_attrs.for_each(|attr| buf.push_str(&format!("{attr}\n")));
++
++    // `impl{generic_params} {trait_text} for {name}{generic_params.to_generic_args()}`
 +    buf.push_str("impl");
 +    if let Some(generic_params) = &generic_params {
-         let lifetime_params = generic_params
-             .lifetime_params()
-             .filter_map(|it| it.lifetime())
-             .map(|it| SmolStr::from(it.text()));
-         let toc_params = generic_params
-             .type_or_const_params()
-             .filter_map(|it| it.name())
-             .map(|it| SmolStr::from(it.text()));
-         format_to!(buf, "<{}>", lifetime_params.chain(toc_params).format(", "))
++        format_to!(buf, "{generic_params}");
 +    }
 +    buf.push(' ');
 +    if let Some(trait_text) = trait_text {
 +        buf.push_str(trait_text);
 +        buf.push_str(" for ");
 +    }
 +    buf.push_str(&adt.name().unwrap().text());
 +    if let Some(generic_params) = generic_params {
-             format_to!(buf, "\n{}\n{{\n{}\n}}", where_clause, code);
++        format_to!(buf, "{}", generic_params.to_generic_args());
 +    }
 +
 +    match adt.where_clause() {
 +        Some(where_clause) => {
-             format_to!(buf, " {{\n{}\n}}", code);
++            format_to!(buf, "\n{where_clause}\n{{\n{code}\n}}");
 +        }
 +        None => {
++            format_to!(buf, " {{\n{code}\n}}");
 +        }
 +    }
 +
 +    buf
 +}
 +
 +pub(crate) fn add_method_to_adt(
 +    builder: &mut SourceChangeBuilder,
 +    adt: &ast::Adt,
 +    impl_def: Option<ast::Impl>,
 +    method: &str,
 +) {
 +    let mut buf = String::with_capacity(method.len() + 2);
 +    if impl_def.is_some() {
 +        buf.push('\n');
 +    }
 +    buf.push_str(method);
 +
 +    let start_offset = impl_def
 +        .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf))
 +        .unwrap_or_else(|| {
 +            buf = generate_impl_text(adt, &buf);
 +            adt.syntax().text_range().end()
 +        });
 +
 +    builder.insert(start_offset, buf);
 +}
 +
 +#[derive(Debug)]
 +pub(crate) struct ReferenceConversion {
 +    conversion: ReferenceConversionType,
 +    ty: hir::Type,
 +}
 +
 +#[derive(Debug)]
 +enum ReferenceConversionType {
 +    // reference can be stripped if the type is Copy
 +    Copy,
 +    // &String -> &str
 +    AsRefStr,
 +    // &Vec<T> -> &[T]
 +    AsRefSlice,
 +    // &Box<T> -> &T
 +    Dereferenced,
 +    // &Option<T> -> Option<&T>
 +    Option,
 +    // &Result<T, E> -> Result<&T, &E>
 +    Result,
 +}
 +
 +impl ReferenceConversion {
 +    pub(crate) fn convert_type(&self, db: &dyn HirDatabase) -> String {
 +        match self.conversion {
 +            ReferenceConversionType::Copy => self.ty.display(db).to_string(),
 +            ReferenceConversionType::AsRefStr => "&str".to_string(),
 +            ReferenceConversionType::AsRefSlice => {
 +                let type_argument_name =
 +                    self.ty.type_arguments().next().unwrap().display(db).to_string();
 +                format!("&[{}]", type_argument_name)
 +            }
 +            ReferenceConversionType::Dereferenced => {
 +                let type_argument_name =
 +                    self.ty.type_arguments().next().unwrap().display(db).to_string();
 +                format!("&{}", type_argument_name)
 +            }
 +            ReferenceConversionType::Option => {
 +                let type_argument_name =
 +                    self.ty.type_arguments().next().unwrap().display(db).to_string();
 +                format!("Option<&{}>", type_argument_name)
 +            }
 +            ReferenceConversionType::Result => {
 +                let mut type_arguments = self.ty.type_arguments();
 +                let first_type_argument_name =
 +                    type_arguments.next().unwrap().display(db).to_string();
 +                let second_type_argument_name =
 +                    type_arguments.next().unwrap().display(db).to_string();
 +                format!("Result<&{}, &{}>", first_type_argument_name, second_type_argument_name)
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn getter(&self, field_name: String) -> String {
 +        match self.conversion {
 +            ReferenceConversionType::Copy => format!("self.{}", field_name),
 +            ReferenceConversionType::AsRefStr
 +            | ReferenceConversionType::AsRefSlice
 +            | ReferenceConversionType::Dereferenced
 +            | ReferenceConversionType::Option
 +            | ReferenceConversionType::Result => format!("self.{}.as_ref()", field_name),
 +        }
 +    }
 +}
 +
 +// FIXME: It should return a new hir::Type, but currently constructing new types is too cumbersome
 +//        and all users of this function operate on string type names, so they can do the conversion
 +//        itself themselves.
 +pub(crate) fn convert_reference_type(
 +    ty: hir::Type,
 +    db: &RootDatabase,
 +    famous_defs: &FamousDefs<'_, '_>,
 +) -> Option<ReferenceConversion> {
 +    handle_copy(&ty, db)
 +        .or_else(|| handle_as_ref_str(&ty, db, famous_defs))
 +        .or_else(|| handle_as_ref_slice(&ty, db, famous_defs))
 +        .or_else(|| handle_dereferenced(&ty, db, famous_defs))
 +        .or_else(|| handle_option_as_ref(&ty, db, famous_defs))
 +        .or_else(|| handle_result_as_ref(&ty, db, famous_defs))
 +        .map(|conversion| ReferenceConversion { ty, conversion })
 +}
 +
 +fn handle_copy(ty: &hir::Type, db: &dyn HirDatabase) -> Option<ReferenceConversionType> {
 +    ty.is_copy(db).then(|| ReferenceConversionType::Copy)
 +}
 +
 +fn handle_as_ref_str(
 +    ty: &hir::Type,
 +    db: &dyn HirDatabase,
 +    famous_defs: &FamousDefs<'_, '_>,
 +) -> Option<ReferenceConversionType> {
 +    let str_type = hir::BuiltinType::str().ty(db);
 +
 +    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[str_type])
 +        .then(|| ReferenceConversionType::AsRefStr)
 +}
 +
 +fn handle_as_ref_slice(
 +    ty: &hir::Type,
 +    db: &dyn HirDatabase,
 +    famous_defs: &FamousDefs<'_, '_>,
 +) -> Option<ReferenceConversionType> {
 +    let type_argument = ty.type_arguments().next()?;
 +    let slice_type = hir::Type::new_slice(type_argument);
 +
 +    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[slice_type])
 +        .then(|| ReferenceConversionType::AsRefSlice)
 +}
 +
 +fn handle_dereferenced(
 +    ty: &hir::Type,
 +    db: &dyn HirDatabase,
 +    famous_defs: &FamousDefs<'_, '_>,
 +) -> Option<ReferenceConversionType> {
 +    let type_argument = ty.type_arguments().next()?;
 +
 +    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[type_argument])
 +        .then(|| ReferenceConversionType::Dereferenced)
 +}
 +
 +fn handle_option_as_ref(
 +    ty: &hir::Type,
 +    db: &dyn HirDatabase,
 +    famous_defs: &FamousDefs<'_, '_>,
 +) -> Option<ReferenceConversionType> {
 +    if ty.as_adt() == famous_defs.core_option_Option()?.ty(db).as_adt() {
 +        Some(ReferenceConversionType::Option)
 +    } else {
 +        None
 +    }
 +}
 +
 +fn handle_result_as_ref(
 +    ty: &hir::Type,
 +    db: &dyn HirDatabase,
 +    famous_defs: &FamousDefs<'_, '_>,
 +) -> Option<ReferenceConversionType> {
 +    if ty.as_adt() == famous_defs.core_result_Result()?.ty(db).as_adt() {
 +        Some(ReferenceConversionType::Result)
 +    } else {
 +        None
 +    }
 +}
 +
 +pub(crate) fn get_methods(items: &ast::AssocItemList) -> Vec<ast::Fn> {
 +    items
 +        .assoc_items()
 +        .flat_map(|i| match i {
 +            ast::AssocItem::Fn(f) => Some(f),
 +            _ => None,
 +        })
 +        .filter(|f| f.name().is_some())
 +        .collect()
 +}
 +
 +/// Trim(remove leading and trailing whitespace) `initial_range` in `source_file`, return the trimmed range.
 +pub(crate) fn trimmed_text_range(source_file: &SourceFile, initial_range: TextRange) -> TextRange {
 +    let mut trimmed_range = initial_range;
 +    while source_file
 +        .syntax()
 +        .token_at_offset(trimmed_range.start())
 +        .find_map(Whitespace::cast)
 +        .is_some()
 +        && trimmed_range.start() < trimmed_range.end()
 +    {
 +        let start = trimmed_range.start() + TextSize::from(1);
 +        trimmed_range = TextRange::new(start, trimmed_range.end());
 +    }
 +    while source_file
 +        .syntax()
 +        .token_at_offset(trimmed_range.end())
 +        .find_map(Whitespace::cast)
 +        .is_some()
 +        && trimmed_range.start() < trimmed_range.end()
 +    {
 +        let end = trimmed_range.end() - TextSize::from(1);
 +        trimmed_range = TextRange::new(trimmed_range.start(), end);
 +    }
 +    trimmed_range
 +}
 +
 +/// Convert a list of function params to a list of arguments that can be passed
 +/// into a function call.
 +pub(crate) fn convert_param_list_to_arg_list(list: ast::ParamList) -> ast::ArgList {
 +    let mut args = vec![];
 +    for param in list.params() {
 +        if let Some(ast::Pat::IdentPat(pat)) = param.pat() {
 +            if let Some(name) = pat.name() {
 +                let name = name.to_string();
 +                let expr = make::expr_path(make::ext::ident_path(&name));
 +                args.push(expr);
 +            }
 +        }
 +    }
 +    make::arg_list(args)
 +}
index 8c9d6b228648e6bfec6e8c5414a269ebfce949e6,0000000000000000000000000000000000000000..75835bce95da19749e2b6abfc7416950d04aa6c0
mode 100644,000000..100644
--- /dev/null
@@@ -1,33 -1,0 +1,33 @@@
- itertools = "0.10.3"
 +[package]
 +name = "ide-completion"
 +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"
- once_cell = "1.12.0"
- smallvec = "1.9.0"
++itertools = "0.10.5"
 +
++once_cell = "1.15.0"
++smallvec = "1.10.0"
 +
 +stdx = { path = "../stdx", version = "0.0.0" }
 +syntax = { path = "../syntax", version = "0.0.0" }
 +text-edit = { path = "../text-edit", version = "0.0.0" }
 +base-db = { path = "../base-db", version = "0.0.0" }
 +ide-db = { path = "../ide-db", version = "0.0.0" }
 +profile = { path = "../profile", version = "0.0.0" }
 +
 +# completions crate should depend only on the top-level `hir` package. if you need
 +# something from some `hir-xxx` subpackage, reexport the API via `hir`.
 +hir = { path = "../hir", version = "0.0.0" }
 +
 +[dev-dependencies]
 +expect-test = "1.4.0"
 +
 +test-utils = { path = "../test-utils" }
index 97b90c62dd7775b1073181148bb6ae5ea27826c9,0000000000000000000000000000000000000000..296dfc14250f75013e748352511adcf8b26ff066
mode 100644,000000..100644
--- /dev/null
@@@ -1,694 -1,0 +1,695 @@@
 +//! This module defines an accumulator for completions which are going to be presented to user.
 +
 +pub(crate) mod attribute;
 +pub(crate) mod dot;
 +pub(crate) mod expr;
 +pub(crate) mod extern_abi;
 +pub(crate) mod field;
 +pub(crate) mod flyimport;
 +pub(crate) mod fn_param;
 +pub(crate) mod format_string;
 +pub(crate) mod item_list;
 +pub(crate) mod keyword;
 +pub(crate) mod lifetime;
 +pub(crate) mod mod_;
 +pub(crate) mod pattern;
 +pub(crate) mod postfix;
 +pub(crate) mod record;
 +pub(crate) mod snippet;
 +pub(crate) mod r#type;
 +pub(crate) mod use_;
 +pub(crate) mod vis;
++pub(crate) mod env_vars;
 +
 +use std::iter;
 +
 +use hir::{known, ScopeDef};
 +use ide_db::{imports::import_assets::LocatedImport, SymbolKind};
 +use syntax::ast;
 +
 +use crate::{
 +    context::{
 +        DotAccess, ItemListKind, NameContext, NameKind, NameRefContext, NameRefKind,
 +        PathCompletionCtx, PathKind, PatternContext, TypeLocation, Visible,
 +    },
 +    item::Builder,
 +    render::{
 +        const_::render_const,
 +        function::{render_fn, render_method},
 +        literal::{render_struct_literal, render_variant_lit},
 +        macro_::render_macro,
 +        pattern::{render_struct_pat, render_variant_pat},
 +        render_field, render_path_resolution, render_pattern_resolution, render_tuple_field,
 +        type_alias::{render_type_alias, render_type_alias_with_eq},
 +        union_literal::render_union_literal,
 +        RenderContext,
 +    },
 +    CompletionContext, CompletionItem, CompletionItemKind,
 +};
 +
 +/// Represents an in-progress set of completions being built.
 +#[derive(Debug, Default)]
 +pub struct Completions {
 +    buf: Vec<CompletionItem>,
 +}
 +
 +impl From<Completions> for Vec<CompletionItem> {
 +    fn from(val: Completions) -> Self {
 +        val.buf
 +    }
 +}
 +
 +impl Builder {
 +    /// Convenience method, which allows to add a freshly created completion into accumulator
 +    /// without binding it to the variable.
 +    pub(crate) fn add_to(self, acc: &mut Completions) {
 +        acc.add(self.build())
 +    }
 +}
 +
 +impl Completions {
 +    fn add(&mut self, item: CompletionItem) {
 +        self.buf.push(item)
 +    }
 +
 +    fn add_opt(&mut self, item: Option<CompletionItem>) {
 +        if let Some(item) = item {
 +            self.buf.push(item)
 +        }
 +    }
 +
 +    pub(crate) fn add_all<I>(&mut self, items: I)
 +    where
 +        I: IntoIterator,
 +        I::Item: Into<CompletionItem>,
 +    {
 +        items.into_iter().for_each(|item| self.add(item.into()))
 +    }
 +
 +    pub(crate) fn add_keyword(&mut self, ctx: &CompletionContext<'_>, keyword: &'static str) {
 +        let item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), keyword);
 +        item.add_to(self);
 +    }
 +
 +    pub(crate) fn add_nameref_keywords_with_colon(&mut self, ctx: &CompletionContext<'_>) {
 +        ["self::", "crate::"].into_iter().for_each(|kw| self.add_keyword(ctx, kw));
 +
 +        if ctx.depth_from_crate_root > 0 {
 +            self.add_keyword(ctx, "super::");
 +        }
 +    }
 +
 +    pub(crate) fn add_nameref_keywords(&mut self, ctx: &CompletionContext<'_>) {
 +        ["self", "crate"].into_iter().for_each(|kw| self.add_keyword(ctx, kw));
 +
 +        if ctx.depth_from_crate_root > 0 {
 +            self.add_keyword(ctx, "super");
 +        }
 +    }
 +
 +    pub(crate) fn add_super_keyword(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        super_chain_len: Option<usize>,
 +    ) {
 +        if let Some(len) = super_chain_len {
 +            if len > 0 && len < ctx.depth_from_crate_root {
 +                self.add_keyword(ctx, "super::");
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn add_keyword_snippet_expr(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        incomplete_let: bool,
 +        kw: &str,
 +        snippet: &str,
 +    ) {
 +        let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
 +
 +        match ctx.config.snippet_cap {
 +            Some(cap) => {
 +                if incomplete_let && snippet.ends_with('}') {
 +                    // complete block expression snippets with a trailing semicolon, if inside an incomplete let
 +                    cov_mark::hit!(let_semi);
 +                    item.insert_snippet(cap, format!("{};", snippet));
 +                } else {
 +                    item.insert_snippet(cap, snippet);
 +                }
 +            }
 +            None => {
 +                item.insert_text(if snippet.contains('$') { kw } else { snippet });
 +            }
 +        };
 +        item.add_to(self);
 +    }
 +
 +    pub(crate) fn add_keyword_snippet(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        kw: &str,
 +        snippet: &str,
 +    ) {
 +        let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
 +
 +        match ctx.config.snippet_cap {
 +            Some(cap) => item.insert_snippet(cap, snippet),
 +            None => item.insert_text(if snippet.contains('$') { kw } else { snippet }),
 +        };
 +        item.add_to(self);
 +    }
 +
 +    pub(crate) fn add_crate_roots(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +    ) {
 +        ctx.process_all_names(&mut |name, res| match res {
 +            ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => {
 +                self.add_module(ctx, path_ctx, m, name);
 +            }
 +            _ => (),
 +        });
 +    }
 +
 +    pub(crate) fn add_path_resolution(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        local_name: hir::Name,
 +        resolution: hir::ScopeDef,
 +    ) {
 +        let is_private_editable = match ctx.def_is_visible(&resolution) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add(
 +            render_path_resolution(
 +                RenderContext::new(ctx).private_editable(is_private_editable),
 +                path_ctx,
 +                local_name,
 +                resolution,
 +            )
 +            .build(),
 +        );
 +    }
 +
 +    pub(crate) fn add_pattern_resolution(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        pattern_ctx: &PatternContext,
 +        local_name: hir::Name,
 +        resolution: hir::ScopeDef,
 +    ) {
 +        let is_private_editable = match ctx.def_is_visible(&resolution) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add(
 +            render_pattern_resolution(
 +                RenderContext::new(ctx).private_editable(is_private_editable),
 +                pattern_ctx,
 +                local_name,
 +                resolution,
 +            )
 +            .build(),
 +        );
 +    }
 +
 +    pub(crate) fn add_enum_variants(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        e: hir::Enum,
 +    ) {
 +        e.variants(ctx.db)
 +            .into_iter()
 +            .for_each(|variant| self.add_enum_variant(ctx, path_ctx, variant, None));
 +    }
 +
 +    pub(crate) fn add_module(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        module: hir::Module,
 +        local_name: hir::Name,
 +    ) {
 +        self.add_path_resolution(
 +            ctx,
 +            path_ctx,
 +            local_name,
 +            hir::ScopeDef::ModuleDef(module.into()),
 +        );
 +    }
 +
 +    pub(crate) fn add_macro(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        mac: hir::Macro,
 +        local_name: hir::Name,
 +    ) {
 +        let is_private_editable = match ctx.is_visible(&mac) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add(
 +            render_macro(
 +                RenderContext::new(ctx).private_editable(is_private_editable),
 +                path_ctx,
 +                local_name,
 +                mac,
 +            )
 +            .build(),
 +        );
 +    }
 +
 +    pub(crate) fn add_function(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        func: hir::Function,
 +        local_name: Option<hir::Name>,
 +    ) {
 +        let is_private_editable = match ctx.is_visible(&func) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add(
 +            render_fn(
 +                RenderContext::new(ctx).private_editable(is_private_editable),
 +                path_ctx,
 +                local_name,
 +                func,
 +            )
 +            .build(),
 +        );
 +    }
 +
 +    pub(crate) fn add_method(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        dot_access: &DotAccess,
 +        func: hir::Function,
 +        receiver: Option<hir::Name>,
 +        local_name: Option<hir::Name>,
 +    ) {
 +        let is_private_editable = match ctx.is_visible(&func) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add(
 +            render_method(
 +                RenderContext::new(ctx).private_editable(is_private_editable),
 +                dot_access,
 +                receiver,
 +                local_name,
 +                func,
 +            )
 +            .build(),
 +        );
 +    }
 +
 +    pub(crate) fn add_method_with_import(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        dot_access: &DotAccess,
 +        func: hir::Function,
 +        import: LocatedImport,
 +    ) {
 +        let is_private_editable = match ctx.is_visible(&func) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add(
 +            render_method(
 +                RenderContext::new(ctx)
 +                    .private_editable(is_private_editable)
 +                    .import_to_add(Some(import)),
 +                dot_access,
 +                None,
 +                None,
 +                func,
 +            )
 +            .build(),
 +        );
 +    }
 +
 +    pub(crate) fn add_const(&mut self, ctx: &CompletionContext<'_>, konst: hir::Const) {
 +        let is_private_editable = match ctx.is_visible(&konst) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add_opt(render_const(
 +            RenderContext::new(ctx).private_editable(is_private_editable),
 +            konst,
 +        ));
 +    }
 +
 +    pub(crate) fn add_type_alias(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        type_alias: hir::TypeAlias,
 +    ) {
 +        let is_private_editable = match ctx.is_visible(&type_alias) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        self.add_opt(render_type_alias(
 +            RenderContext::new(ctx).private_editable(is_private_editable),
 +            type_alias,
 +        ));
 +    }
 +
 +    pub(crate) fn add_type_alias_with_eq(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        type_alias: hir::TypeAlias,
 +    ) {
 +        self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias));
 +    }
 +
 +    pub(crate) fn add_qualified_enum_variant(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        variant: hir::Variant,
 +        path: hir::ModPath,
 +    ) {
 +        if let Some(builder) =
 +            render_variant_lit(RenderContext::new(ctx), path_ctx, None, variant, Some(path))
 +        {
 +            self.add(builder.build());
 +        }
 +    }
 +
 +    pub(crate) fn add_enum_variant(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        variant: hir::Variant,
 +        local_name: Option<hir::Name>,
 +    ) {
 +        if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx {
 +            cov_mark::hit!(enum_variant_pattern_path);
 +            self.add_variant_pat(ctx, pat_ctx, Some(path_ctx), variant, local_name);
 +            return;
 +        }
 +
 +        if let Some(builder) =
 +            render_variant_lit(RenderContext::new(ctx), path_ctx, local_name, variant, None)
 +        {
 +            self.add(builder.build());
 +        }
 +    }
 +
 +    pub(crate) fn add_field(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        dot_access: &DotAccess,
 +        receiver: Option<hir::Name>,
 +        field: hir::Field,
 +        ty: &hir::Type,
 +    ) {
 +        let is_private_editable = match ctx.is_visible(&field) {
 +            Visible::Yes => false,
 +            Visible::Editable => true,
 +            Visible::No => return,
 +        };
 +        let item = render_field(
 +            RenderContext::new(ctx).private_editable(is_private_editable),
 +            dot_access,
 +            receiver,
 +            field,
 +            ty,
 +        );
 +        self.add(item);
 +    }
 +
 +    pub(crate) fn add_struct_literal(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        path_ctx: &PathCompletionCtx,
 +        strukt: hir::Struct,
 +        path: Option<hir::ModPath>,
 +        local_name: Option<hir::Name>,
 +    ) {
 +        if let Some(builder) =
 +            render_struct_literal(RenderContext::new(ctx), path_ctx, strukt, path, local_name)
 +        {
 +            self.add(builder.build());
 +        }
 +    }
 +
 +    pub(crate) fn add_union_literal(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        un: hir::Union,
 +        path: Option<hir::ModPath>,
 +        local_name: Option<hir::Name>,
 +    ) {
 +        let item = render_union_literal(RenderContext::new(ctx), un, path, local_name);
 +        self.add_opt(item);
 +    }
 +
 +    pub(crate) fn add_tuple_field(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        receiver: Option<hir::Name>,
 +        field: usize,
 +        ty: &hir::Type,
 +    ) {
 +        let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty);
 +        self.add(item);
 +    }
 +
 +    pub(crate) fn add_lifetime(&mut self, ctx: &CompletionContext<'_>, name: hir::Name) {
 +        CompletionItem::new(SymbolKind::LifetimeParam, ctx.source_range(), name.to_smol_str())
 +            .add_to(self)
 +    }
 +
 +    pub(crate) fn add_label(&mut self, ctx: &CompletionContext<'_>, name: hir::Name) {
 +        CompletionItem::new(SymbolKind::Label, ctx.source_range(), name.to_smol_str()).add_to(self)
 +    }
 +
 +    pub(crate) fn add_variant_pat(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        pattern_ctx: &PatternContext,
 +        path_ctx: Option<&PathCompletionCtx>,
 +        variant: hir::Variant,
 +        local_name: Option<hir::Name>,
 +    ) {
 +        self.add_opt(render_variant_pat(
 +            RenderContext::new(ctx),
 +            pattern_ctx,
 +            path_ctx,
 +            variant,
 +            local_name.clone(),
 +            None,
 +        ));
 +    }
 +
 +    pub(crate) fn add_qualified_variant_pat(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        pattern_ctx: &PatternContext,
 +        variant: hir::Variant,
 +        path: hir::ModPath,
 +    ) {
 +        let path = Some(&path);
 +        self.add_opt(render_variant_pat(
 +            RenderContext::new(ctx),
 +            pattern_ctx,
 +            None,
 +            variant,
 +            None,
 +            path,
 +        ));
 +    }
 +
 +    pub(crate) fn add_struct_pat(
 +        &mut self,
 +        ctx: &CompletionContext<'_>,
 +        pattern_ctx: &PatternContext,
 +        strukt: hir::Struct,
 +        local_name: Option<hir::Name>,
 +    ) {
 +        self.add_opt(render_struct_pat(RenderContext::new(ctx), pattern_ctx, strukt, local_name));
 +    }
 +}
 +
 +/// Calls the callback for each variant of the provided enum with the path to the variant.
 +/// Skips variants that are visible with single segment paths.
 +fn enum_variants_with_paths(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    enum_: hir::Enum,
 +    impl_: &Option<ast::Impl>,
 +    cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::Variant, hir::ModPath),
 +) {
 +    let variants = enum_.variants(ctx.db);
 +
 +    if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) {
 +        if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) {
 +            for &variant in &variants {
 +                let self_path = hir::ModPath::from_segments(
 +                    hir::PathKind::Plain,
 +                    iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))),
 +                );
 +                cb(acc, ctx, variant, self_path);
 +            }
 +        }
 +    }
 +
 +    for variant in variants {
 +        if let Some(path) = ctx.module.find_use_path(
 +            ctx.db,
 +            hir::ModuleDef::from(variant),
 +            ctx.config.prefer_no_std,
 +        ) {
 +            // Variants with trivial paths are already added by the existing completion logic,
 +            // so we should avoid adding these twice
 +            if path.segments().len() > 1 {
 +                cb(acc, ctx, variant, path);
 +            }
 +        }
 +    }
 +}
 +
 +pub(super) fn complete_name(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    NameContext { name, kind }: &NameContext,
 +) {
 +    match kind {
 +        NameKind::Const => {
 +            item_list::trait_impl::complete_trait_impl_const(acc, ctx, name);
 +        }
 +        NameKind::Function => {
 +            item_list::trait_impl::complete_trait_impl_fn(acc, ctx, name);
 +        }
 +        NameKind::IdentPat(pattern_ctx) => {
 +            if ctx.token.kind() != syntax::T![_] {
 +                complete_patterns(acc, ctx, pattern_ctx)
 +            }
 +        }
 +        NameKind::Module(mod_under_caret) => {
 +            mod_::complete_mod(acc, ctx, mod_under_caret);
 +        }
 +        NameKind::TypeAlias => {
 +            item_list::trait_impl::complete_trait_impl_type_alias(acc, ctx, name);
 +        }
 +        NameKind::RecordField => {
 +            field::complete_field_list_record_variant(acc, ctx);
 +        }
 +        NameKind::ConstParam
 +        | NameKind::Enum
 +        | NameKind::MacroDef
 +        | NameKind::MacroRules
 +        | NameKind::Rename
 +        | NameKind::SelfParam
 +        | NameKind::Static
 +        | NameKind::Struct
 +        | NameKind::Trait
 +        | NameKind::TypeParam
 +        | NameKind::Union
 +        | NameKind::Variant => (),
 +    }
 +}
 +
 +pub(super) fn complete_name_ref(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    NameRefContext { nameref, kind }: &NameRefContext,
 +) {
 +    match kind {
 +        NameRefKind::Path(path_ctx) => {
 +            flyimport::import_on_the_fly_path(acc, ctx, path_ctx);
 +
 +            match &path_ctx.kind {
 +                PathKind::Expr { expr_ctx } => {
 +                    expr::complete_expr_path(acc, ctx, path_ctx, expr_ctx);
 +
 +                    dot::complete_undotted_self(acc, ctx, path_ctx, expr_ctx);
 +                    item_list::complete_item_list_in_expr(acc, ctx, path_ctx, expr_ctx);
 +                    snippet::complete_expr_snippet(acc, ctx, path_ctx, expr_ctx);
 +                }
 +                PathKind::Type { location } => {
 +                    r#type::complete_type_path(acc, ctx, path_ctx, location);
 +
 +                    match location {
 +                        TypeLocation::TupleField => {
 +                            field::complete_field_list_tuple_variant(acc, ctx, path_ctx);
 +                        }
 +                        TypeLocation::TypeAscription(ascription) => {
 +                            r#type::complete_ascribed_type(acc, ctx, path_ctx, ascription);
 +                        }
 +                        TypeLocation::GenericArgList(_)
 +                        | TypeLocation::TypeBound
 +                        | TypeLocation::ImplTarget
 +                        | TypeLocation::ImplTrait
 +                        | TypeLocation::Other => (),
 +                    }
 +                }
 +                PathKind::Attr { attr_ctx } => {
 +                    attribute::complete_attribute_path(acc, ctx, path_ctx, attr_ctx);
 +                }
 +                PathKind::Derive { existing_derives } => {
 +                    attribute::complete_derive_path(acc, ctx, path_ctx, existing_derives);
 +                }
 +                PathKind::Item { kind } => {
 +                    item_list::complete_item_list(acc, ctx, path_ctx, kind);
 +
 +                    snippet::complete_item_snippet(acc, ctx, path_ctx, kind);
 +                    if let ItemListKind::TraitImpl(impl_) = kind {
 +                        item_list::trait_impl::complete_trait_impl_item_by_name(
 +                            acc, ctx, path_ctx, nameref, impl_,
 +                        );
 +                    }
 +                }
 +                PathKind::Pat { .. } => {
 +                    pattern::complete_pattern_path(acc, ctx, path_ctx);
 +                }
 +                PathKind::Vis { has_in_token } => {
 +                    vis::complete_vis_path(acc, ctx, path_ctx, has_in_token);
 +                }
 +                PathKind::Use => {
 +                    use_::complete_use_path(acc, ctx, path_ctx, nameref);
 +                }
 +            }
 +        }
 +        NameRefKind::DotAccess(dot_access) => {
 +            flyimport::import_on_the_fly_dot(acc, ctx, dot_access);
 +            dot::complete_dot(acc, ctx, dot_access);
 +            postfix::complete_postfix(acc, ctx, dot_access);
 +        }
 +        NameRefKind::Keyword(item) => {
 +            keyword::complete_for_and_where(acc, ctx, item);
 +        }
 +        NameRefKind::RecordExpr { dot_prefix, expr } => {
 +            record::complete_record_expr_fields(acc, ctx, expr, dot_prefix);
 +        }
 +        NameRefKind::Pattern(pattern_ctx) => complete_patterns(acc, ctx, pattern_ctx),
 +    }
 +}
 +
 +fn complete_patterns(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    pattern_ctx: &PatternContext,
 +) {
 +    flyimport::import_on_the_fly_pat(acc, ctx, pattern_ctx);
 +    fn_param::complete_fn_param(acc, ctx, pattern_ctx);
 +    pattern::complete_pattern(acc, ctx, pattern_ctx);
 +    record::complete_record_pattern_fields(acc, ctx, pattern_ctx);
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..09e95e53de63ce42f31791d8c092a2772b4e9501
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,150 @@@
++//! Completes environment variables defined by Cargo (https://doc.rust-lang.org/cargo/reference/environment-variables.html)
++use hir::Semantics;
++use ide_db::{syntax_helpers::node_ext::macro_call_for_string_token, RootDatabase};
++use syntax::ast::{self, IsString};
++
++use crate::{
++    completions::Completions, context::CompletionContext, CompletionItem, CompletionItemKind,
++};
++
++const CARGO_DEFINED_VARS: &[(&str, &str)] = &[
++    ("CARGO","Path to the cargo binary performing the build"),
++    ("CARGO_MANIFEST_DIR","The directory containing the manifest of your package"),
++    ("CARGO_PKG_VERSION","The full version of your package"),
++    ("CARGO_PKG_VERSION_MAJOR","The major version of your package"),
++    ("CARGO_PKG_VERSION_MINOR","The minor version of your package"),
++    ("CARGO_PKG_VERSION_PATCH","The patch version of your package"),
++    ("CARGO_PKG_VERSION_PRE","The pre-release version of your package"),
++    ("CARGO_PKG_AUTHORS","Colon separated list of authors from the manifest of your package"),
++    ("CARGO_PKG_NAME","The name of your package"),
++    ("CARGO_PKG_DESCRIPTION","The description from the manifest of your package"),
++    ("CARGO_PKG_HOMEPAGE","The home page from the manifest of your package"),
++    ("CARGO_PKG_REPOSITORY","The repository from the manifest of your package"),
++    ("CARGO_PKG_LICENSE","The license from the manifest of your package"),
++    ("CARGO_PKG_LICENSE_FILE","The license file from the manifest of your package"),
++    ("CARGO_PKG_RUST_VERSION","The Rust version from the manifest of your package. Note that this is the minimum Rust version supported by the package, not the current Rust version"),
++    ("CARGO_CRATE_NAME","The name of the crate that is currently being compiled"),
++    ("CARGO_BIN_NAME","The name of the binary that is currently being compiled (if it is a binary). This name does not include any file extension, such as .exe"),
++    ("CARGO_PRIMARY_PACKAGE","This environment variable will be set if the package being built is primary. Primary packages are the ones the user selected on the command-line, either with -p flags or the defaults based on the current directory and the default workspace members. This environment variable will not be set when building dependencies. This is only set when compiling the package (not when running binaries or tests)"),
++    ("CARGO_TARGET_TMPDIR","Only set when building integration test or benchmark code. This is a path to a directory inside the target directory where integration tests or benchmarks are free to put any data needed by the tests/benches. Cargo initially creates this directory but doesn't manage its content in any way, this is the responsibility of the test code")
++];
++
++pub(crate) fn complete_cargo_env_vars(
++    acc: &mut Completions,
++    ctx: &CompletionContext<'_>,
++    expanded: &ast::String,
++) -> Option<()> {
++    guard_env_macro(expanded, &ctx.sema)?;
++    let range = expanded.text_range_between_quotes()?;
++
++    CARGO_DEFINED_VARS.iter().for_each(|(var, detail)| {
++        let mut item = CompletionItem::new(CompletionItemKind::Keyword, range, var);
++        item.detail(*detail);
++        item.add_to(acc);
++    });
++
++    Some(())
++}
++
++fn guard_env_macro(string: &ast::String, semantics: &Semantics<'_, RootDatabase>) -> Option<()> {
++    let call = macro_call_for_string_token(string)?;
++    let name = call.path()?.segment()?.name_ref()?;
++    let makro = semantics.resolve_macro_call(&call)?;
++    let db = semantics.db;
++
++    match name.text().as_str() {
++        "env" | "option_env" if makro.kind(db) == hir::MacroKind::BuiltIn => Some(()),
++        _ => None,
++    }
++}
++
++#[cfg(test)]
++mod tests {
++    use crate::tests::{check_edit, completion_list};
++
++    fn check(macro_name: &str) {
++        check_edit(
++            "CARGO_BIN_NAME",
++            &format!(
++                r#"
++            #[rustc_builtin_macro]
++            macro_rules! {} {{
++                ($var:literal) => {{ 0 }}
++            }}
++
++            fn main() {{
++                let foo = {}!("CAR$0");
++            }}
++        "#,
++                macro_name, macro_name
++            ),
++            &format!(
++                r#"
++            #[rustc_builtin_macro]
++            macro_rules! {} {{
++                ($var:literal) => {{ 0 }}
++            }}
++
++            fn main() {{
++                let foo = {}!("CARGO_BIN_NAME");
++            }}
++        "#,
++                macro_name, macro_name
++            ),
++        );
++    }
++    #[test]
++    fn completes_env_variable_in_env() {
++        check("env")
++    }
++
++    #[test]
++    fn completes_env_variable_in_option_env() {
++        check("option_env");
++    }
++
++    #[test]
++    fn doesnt_complete_in_random_strings() {
++        let fixture = r#"
++            fn main() {
++                let foo = "CA$0";
++            }
++        "#;
++
++        let completions = completion_list(fixture);
++        assert!(completions.is_empty(), "Completions weren't empty: {}", completions);
++    }
++
++    #[test]
++    fn doesnt_complete_in_random_macro() {
++        let fixture = r#"
++            macro_rules! bar {
++                ($($arg:tt)*) => { 0 }
++            }
++
++            fn main() {
++                let foo = bar!("CA$0");
++
++            }
++        "#;
++
++        let completions = completion_list(fixture);
++        assert!(completions.is_empty(), "Completions weren't empty: {}", completions);
++    }
++
++    #[test]
++    fn doesnt_complete_for_shadowed_macro() {
++        let fixture = r#"
++            macro_rules! env {
++                ($var:literal) => { 0 }
++            }
++
++            fn main() {
++                let foo = env!("CA$0");
++            }
++        "#;
++
++        let completions = completion_list(fixture);
++        assert!(completions.is_empty(), "Completions weren't empty: {}", completions)
++    }
++}
index a5e854b74df9d268504f2b4e39684c6002e4c335,0000000000000000000000000000000000000000..9850813a0ce1c1b936f9671e67b838815cfa7f74
mode 100644,000000..100644
--- /dev/null
@@@ -1,643 -1,0 +1,652 @@@
- //! See `CompletionContext` structure.
++//! See [`CompletionContext`] structure.
 +
 +mod analysis;
 +#[cfg(test)]
 +mod tests;
 +
 +use std::iter;
 +
 +use base_db::SourceDatabaseExt;
 +use hir::{
 +    HasAttrs, Local, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, Type, TypeInfo,
 +};
 +use ide_db::{
 +    base_db::{FilePosition, SourceDatabase},
 +    famous_defs::FamousDefs,
 +    FxHashMap, FxHashSet, RootDatabase,
 +};
 +use syntax::{
 +    ast::{self, AttrKind, NameOrNameRef},
 +    AstNode,
 +    SyntaxKind::{self, *},
 +    SyntaxToken, TextRange, TextSize,
 +};
 +use text_edit::Indel;
 +
- use crate::CompletionConfig;
++use crate::{
++    context::analysis::{expand_and_analyze, AnalysisResult},
++    CompletionConfig,
++};
 +
 +const COMPLETION_MARKER: &str = "intellijRulezz";
 +
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +pub(crate) enum PatternRefutability {
 +    Refutable,
 +    Irrefutable,
 +}
 +
 +#[derive(Debug)]
 +pub(crate) enum Visible {
 +    Yes,
 +    Editable,
 +    No,
 +}
 +
 +/// Existing qualifiers for the thing we are currently completing.
 +#[derive(Debug, Default)]
 +pub(super) struct QualifierCtx {
 +    pub(super) unsafe_tok: Option<SyntaxToken>,
 +    pub(super) vis_node: Option<ast::Visibility>,
 +}
 +
 +impl QualifierCtx {
 +    pub(super) fn none(&self) -> bool {
 +        self.unsafe_tok.is_none() && self.vis_node.is_none()
 +    }
 +}
 +
 +/// The state of the path we are currently completing.
 +#[derive(Debug)]
 +pub(crate) struct PathCompletionCtx {
 +    /// If this is a call with () already there (or {} in case of record patterns)
 +    pub(super) has_call_parens: bool,
 +    /// If this has a macro call bang !
 +    pub(super) has_macro_bang: bool,
 +    /// The qualifier of the current path.
 +    pub(super) qualified: Qualified,
 +    /// The parent of the path we are completing.
 +    pub(super) parent: Option<ast::Path>,
 +    #[allow(dead_code)]
 +    /// The path of which we are completing the segment
 +    pub(super) path: ast::Path,
 +    /// The path of which we are completing the segment in the original file
 +    pub(crate) original_path: Option<ast::Path>,
 +    pub(super) kind: PathKind,
 +    /// Whether the path segment has type args or not.
 +    pub(super) has_type_args: bool,
 +    /// Whether the qualifier comes from a use tree parent or not
 +    pub(crate) use_tree_parent: bool,
 +}
 +
 +impl PathCompletionCtx {
 +    pub(super) fn is_trivial_path(&self) -> bool {
 +        matches!(
 +            self,
 +            PathCompletionCtx {
 +                has_call_parens: false,
 +                has_macro_bang: false,
 +                qualified: Qualified::No,
 +                parent: None,
 +                has_type_args: false,
 +                ..
 +            }
 +        )
 +    }
 +}
 +
 +/// The kind of path we are completing right now.
 +#[derive(Debug, PartialEq, Eq)]
 +pub(super) enum PathKind {
 +    Expr {
 +        expr_ctx: ExprCtx,
 +    },
 +    Type {
 +        location: TypeLocation,
 +    },
 +    Attr {
 +        attr_ctx: AttrCtx,
 +    },
 +    Derive {
 +        existing_derives: ExistingDerives,
 +    },
 +    /// Path in item position, that is inside an (Assoc)ItemList
 +    Item {
 +        kind: ItemListKind,
 +    },
 +    Pat {
 +        pat_ctx: PatternContext,
 +    },
 +    Vis {
 +        has_in_token: bool,
 +    },
 +    Use,
 +}
 +
 +pub(crate) type ExistingDerives = FxHashSet<hir::Macro>;
 +
 +#[derive(Debug, PartialEq, Eq)]
 +pub(crate) struct AttrCtx {
 +    pub(crate) kind: AttrKind,
 +    pub(crate) annotated_item_kind: Option<SyntaxKind>,
 +}
 +
 +#[derive(Debug, PartialEq, Eq)]
 +pub(crate) struct ExprCtx {
 +    pub(crate) in_block_expr: bool,
 +    pub(crate) in_loop_body: bool,
 +    pub(crate) after_if_expr: bool,
 +    /// Whether this expression is the direct condition of an if or while expression
 +    pub(crate) in_condition: bool,
 +    pub(crate) incomplete_let: bool,
 +    pub(crate) ref_expr_parent: Option<ast::RefExpr>,
 +    /// The surrounding RecordExpression we are completing a functional update
 +    pub(crate) is_func_update: Option<ast::RecordExpr>,
 +    pub(crate) self_param: Option<hir::SelfParam>,
 +    pub(crate) innermost_ret_ty: Option<hir::Type>,
 +    pub(crate) impl_: Option<ast::Impl>,
 +    /// Whether this expression occurs in match arm guard position: before the
 +    /// fat arrow token
 +    pub(crate) in_match_guard: bool,
 +}
 +
 +/// Original file ast nodes
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub(crate) enum TypeLocation {
 +    TupleField,
 +    TypeAscription(TypeAscriptionTarget),
 +    GenericArgList(Option<ast::GenericArgList>),
 +    TypeBound,
 +    ImplTarget,
 +    ImplTrait,
 +    Other,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub(crate) enum TypeAscriptionTarget {
 +    Let(Option<ast::Pat>),
 +    FnParam(Option<ast::Pat>),
 +    RetType(Option<ast::Expr>),
 +    Const(Option<ast::Expr>),
 +}
 +
 +/// The kind of item list a [`PathKind::Item`] belongs to.
 +#[derive(Debug, PartialEq, Eq)]
 +pub(super) enum ItemListKind {
 +    SourceFile,
 +    Module,
 +    Impl,
 +    TraitImpl(Option<ast::Impl>),
 +    Trait,
 +    ExternBlock,
 +}
 +
 +#[derive(Debug)]
 +pub(super) enum Qualified {
 +    No,
 +    With {
 +        path: ast::Path,
 +        resolution: Option<PathResolution>,
 +        /// How many `super` segments are present in the path
 +        ///
 +        /// This would be None, if path is not solely made of
 +        /// `super` segments, e.g.
 +        ///
 +        /// ```rust
 +        ///   use super::foo;
 +        /// ```
 +        ///
 +        /// Otherwise it should be Some(count of `super`)
 +        super_chain_len: Option<usize>,
 +    },
 +    /// <_>::
 +    TypeAnchor {
 +        ty: Option<hir::Type>,
 +        trait_: Option<hir::Trait>,
 +    },
 +    /// Whether the path is an absolute path
 +    Absolute,
 +}
 +
 +/// The state of the pattern we are completing.
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub(super) struct PatternContext {
 +    pub(super) refutability: PatternRefutability,
 +    pub(super) param_ctx: Option<ParamContext>,
 +    pub(super) has_type_ascription: bool,
 +    pub(super) parent_pat: Option<ast::Pat>,
 +    pub(super) ref_token: Option<SyntaxToken>,
 +    pub(super) mut_token: Option<SyntaxToken>,
 +    /// The record pattern this name or ref is a field of
 +    pub(super) record_pat: Option<ast::RecordPat>,
 +    pub(super) impl_: Option<ast::Impl>,
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub(super) struct ParamContext {
 +    pub(super) param_list: ast::ParamList,
 +    pub(super) param: ast::Param,
 +    pub(super) kind: ParamKind,
 +}
 +
 +/// The state of the lifetime we are completing.
 +#[derive(Debug)]
 +pub(super) struct LifetimeContext {
 +    pub(super) lifetime: Option<ast::Lifetime>,
 +    pub(super) kind: LifetimeKind,
 +}
 +
 +/// The kind of lifetime we are completing.
 +#[derive(Debug)]
 +pub(super) enum LifetimeKind {
 +    LifetimeParam { is_decl: bool, param: ast::LifetimeParam },
 +    Lifetime,
 +    LabelRef,
 +    LabelDef,
 +}
 +
 +/// The state of the name we are completing.
 +#[derive(Debug)]
 +pub(super) struct NameContext {
 +    #[allow(dead_code)]
 +    pub(super) name: Option<ast::Name>,
 +    pub(super) kind: NameKind,
 +}
 +
 +/// The kind of the name we are completing.
 +#[derive(Debug)]
 +#[allow(dead_code)]
 +pub(super) enum NameKind {
 +    Const,
 +    ConstParam,
 +    Enum,
 +    Function,
 +    IdentPat(PatternContext),
 +    MacroDef,
 +    MacroRules,
 +    /// Fake node
 +    Module(ast::Module),
 +    RecordField,
 +    Rename,
 +    SelfParam,
 +    Static,
 +    Struct,
 +    Trait,
 +    TypeAlias,
 +    TypeParam,
 +    Union,
 +    Variant,
 +}
 +
 +/// The state of the NameRef we are completing.
 +#[derive(Debug)]
 +pub(super) struct NameRefContext {
 +    /// NameRef syntax in the original file
 +    pub(super) nameref: Option<ast::NameRef>,
 +    pub(super) kind: NameRefKind,
 +}
 +
 +/// The kind of the NameRef we are completing.
 +#[derive(Debug)]
 +pub(super) enum NameRefKind {
 +    Path(PathCompletionCtx),
 +    DotAccess(DotAccess),
 +    /// Position where we are only interested in keyword completions
 +    Keyword(ast::Item),
 +    /// The record expression this nameref is a field of and whether a dot precedes the completion identifier.
 +    RecordExpr {
 +        dot_prefix: bool,
 +        expr: ast::RecordExpr,
 +    },
 +    Pattern(PatternContext),
 +}
 +
 +/// The identifier we are currently completing.
 +#[derive(Debug)]
 +pub(super) enum CompletionAnalysis {
 +    Name(NameContext),
 +    NameRef(NameRefContext),
 +    Lifetime(LifetimeContext),
 +    /// The string the cursor is currently inside
 +    String {
 +        /// original token
 +        original: ast::String,
 +        /// fake token
 +        expanded: Option<ast::String>,
 +    },
 +    /// Set if we are currently completing in an unexpanded attribute, this usually implies a builtin attribute like `allow($0)`
 +    UnexpandedAttrTT {
 +        colon_prefix: bool,
 +        fake_attribute_under_caret: Option<ast::Attr>,
 +    },
 +}
 +
 +/// Information about the field or method access we are completing.
 +#[derive(Debug)]
 +pub(super) struct DotAccess {
 +    pub(super) receiver: Option<ast::Expr>,
 +    pub(super) receiver_ty: Option<TypeInfo>,
 +    pub(super) kind: DotAccessKind,
 +}
 +
 +#[derive(Debug)]
 +pub(super) enum DotAccessKind {
 +    Field {
 +        /// True if the receiver is an integer and there is no ident in the original file after it yet
 +        /// like `0.$0`
 +        receiver_is_ambiguous_float_literal: bool,
 +    },
 +    Method {
 +        has_parens: bool,
 +    },
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub(crate) enum ParamKind {
 +    Function(ast::Fn),
 +    Closure(ast::ClosureExpr),
 +}
 +
 +/// `CompletionContext` is created early during completion to figure out, where
 +/// exactly is the cursor, syntax-wise.
 +#[derive(Debug)]
 +pub(crate) struct CompletionContext<'a> {
 +    pub(super) sema: Semantics<'a, RootDatabase>,
 +    pub(super) scope: SemanticsScope<'a>,
 +    pub(super) db: &'a RootDatabase,
 +    pub(super) config: &'a CompletionConfig,
 +    pub(super) position: FilePosition,
 +
 +    /// The token before the cursor, in the original file.
 +    pub(super) original_token: SyntaxToken,
 +    /// The token before the cursor, in the macro-expanded file.
 +    pub(super) token: SyntaxToken,
 +    /// The crate of the current file.
 +    pub(super) krate: hir::Crate,
 +    /// The module of the `scope`.
 +    pub(super) module: hir::Module,
 +
 +    /// The expected name of what we are completing.
 +    /// This is usually the parameter name of the function argument we are completing.
 +    pub(super) expected_name: Option<NameOrNameRef>,
 +    /// The expected type of what we are completing.
 +    pub(super) expected_type: Option<Type>,
 +
 +    pub(super) qualifier_ctx: QualifierCtx,
 +
 +    pub(super) locals: FxHashMap<Name, Local>,
 +
 +    /// The module depth of the current module of the cursor position.
 +    /// - crate-root
 +    ///  - mod foo
 +    ///   - mod bar
 +    /// Here depth will be 2
 +    pub(super) depth_from_crate_root: usize,
 +}
 +
 +impl<'a> CompletionContext<'a> {
 +    /// The range of the identifier that is being completed.
 +    pub(crate) fn source_range(&self) -> TextRange {
 +        // check kind of macro-expanded token, but use range of original token
 +        let kind = self.token.kind();
 +        match kind {
 +            CHAR => {
 +                // assume we are completing a lifetime but the user has only typed the '
 +                cov_mark::hit!(completes_if_lifetime_without_idents);
 +                TextRange::at(self.original_token.text_range().start(), TextSize::from(1))
 +            }
 +            IDENT | LIFETIME_IDENT | UNDERSCORE => self.original_token.text_range(),
 +            _ if kind.is_keyword() => self.original_token.text_range(),
 +            _ => TextRange::empty(self.position.offset),
 +        }
 +    }
 +
 +    pub(crate) fn famous_defs(&self) -> FamousDefs<'_, '_> {
 +        FamousDefs(&self.sema, self.krate)
 +    }
 +
 +    /// Checks if an item is visible and not `doc(hidden)` at the completion site.
 +    pub(crate) fn def_is_visible(&self, item: &ScopeDef) -> Visible {
 +        match item {
 +            ScopeDef::ModuleDef(def) => match def {
 +                hir::ModuleDef::Module(it) => self.is_visible(it),
 +                hir::ModuleDef::Function(it) => self.is_visible(it),
 +                hir::ModuleDef::Adt(it) => self.is_visible(it),
 +                hir::ModuleDef::Variant(it) => self.is_visible(it),
 +                hir::ModuleDef::Const(it) => self.is_visible(it),
 +                hir::ModuleDef::Static(it) => self.is_visible(it),
 +                hir::ModuleDef::Trait(it) => self.is_visible(it),
 +                hir::ModuleDef::TypeAlias(it) => self.is_visible(it),
 +                hir::ModuleDef::Macro(it) => self.is_visible(it),
 +                hir::ModuleDef::BuiltinType(_) => Visible::Yes,
 +            },
 +            ScopeDef::GenericParam(_)
 +            | ScopeDef::ImplSelfType(_)
 +            | ScopeDef::AdtSelfType(_)
 +            | ScopeDef::Local(_)
 +            | ScopeDef::Label(_)
 +            | ScopeDef::Unknown => Visible::Yes,
 +        }
 +    }
 +
 +    /// Checks if an item is visible and not `doc(hidden)` at the completion site.
 +    pub(crate) fn is_visible<I>(&self, item: &I) -> Visible
 +    where
 +        I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy,
 +    {
 +        let vis = item.visibility(self.db);
 +        let attrs = item.attrs(self.db);
 +        self.is_visible_impl(&vis, &attrs, item.krate(self.db))
 +    }
 +
 +    /// Check if an item is `#[doc(hidden)]`.
 +    pub(crate) fn is_item_hidden(&self, item: &hir::ItemInNs) -> bool {
 +        let attrs = item.attrs(self.db);
 +        let krate = item.krate(self.db);
 +        match (attrs, krate) {
 +            (Some(attrs), Some(krate)) => self.is_doc_hidden(&attrs, krate),
 +            _ => false,
 +        }
 +    }
 +
 +    /// Whether the given trait is an operator trait or not.
 +    pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
 +        match trait_.attrs(self.db).lang() {
 +            Some(lang) => OP_TRAIT_LANG_NAMES.contains(&lang.as_str()),
 +            None => false,
 +        }
 +    }
 +
 +    /// Returns the traits in scope, with the [`Drop`] trait removed.
 +    pub(crate) fn traits_in_scope(&self) -> hir::VisibleTraits {
 +        let mut traits_in_scope = self.scope.visible_traits();
 +        if let Some(drop) = self.famous_defs().core_ops_Drop() {
 +            traits_in_scope.0.remove(&drop.into());
 +        }
 +        traits_in_scope
 +    }
 +
 +    pub(crate) fn iterate_path_candidates(
 +        &self,
 +        ty: &hir::Type,
 +        mut cb: impl FnMut(hir::AssocItem),
 +    ) {
 +        let mut seen = FxHashSet::default();
 +        ty.iterate_path_candidates(
 +            self.db,
 +            &self.scope,
 +            &self.traits_in_scope(),
 +            Some(self.module),
 +            None,
 +            |item| {
 +                // We might iterate candidates of a trait multiple times here, so deduplicate
 +                // them.
 +                if seen.insert(item) {
 +                    cb(item)
 +                }
 +                None::<()>
 +            },
 +        );
 +    }
 +
 +    /// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items.
 +    pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
 +        let _p = profile::span("CompletionContext::process_all_names");
 +        self.scope.process_all_names(&mut |name, def| {
 +            if self.is_scope_def_hidden(def) {
 +                return;
 +            }
 +
 +            f(name, def);
 +        });
 +    }
 +
 +    pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
 +        let _p = profile::span("CompletionContext::process_all_names_raw");
 +        self.scope.process_all_names(&mut |name, def| f(name, def));
 +    }
 +
 +    fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool {
 +        if let (Some(attrs), Some(krate)) = (scope_def.attrs(self.db), scope_def.krate(self.db)) {
 +            return self.is_doc_hidden(&attrs, krate);
 +        }
 +
 +        false
 +    }
 +
 +    fn is_visible_impl(
 +        &self,
 +        vis: &hir::Visibility,
 +        attrs: &hir::Attrs,
 +        defining_crate: hir::Crate,
 +    ) -> Visible {
 +        if !vis.is_visible_from(self.db, self.module.into()) {
 +            if !self.config.enable_private_editable {
 +                return Visible::No;
 +            }
 +            // If the definition location is editable, also show private items
 +            let root_file = defining_crate.root_file(self.db);
 +            let source_root_id = self.db.file_source_root(root_file);
 +            let is_editable = !self.db.source_root(source_root_id).is_library;
 +            return if is_editable { Visible::Editable } else { Visible::No };
 +        }
 +
 +        if self.is_doc_hidden(attrs, defining_crate) {
 +            Visible::No
 +        } else {
 +            Visible::Yes
 +        }
 +    }
 +
 +    fn is_doc_hidden(&self, attrs: &hir::Attrs, defining_crate: hir::Crate) -> bool {
 +        // `doc(hidden)` items are only completed within the defining crate.
 +        self.krate != defining_crate && attrs.has_doc_hidden()
 +    }
 +}
 +
 +// CompletionContext construction
 +impl<'a> CompletionContext<'a> {
 +    pub(super) fn new(
 +        db: &'a RootDatabase,
 +        position @ FilePosition { file_id, offset }: FilePosition,
 +        config: &'a CompletionConfig,
 +    ) -> Option<(CompletionContext<'a>, CompletionAnalysis)> {
 +        let _p = profile::span("CompletionContext::new");
 +        let sema = Semantics::new(db);
 +
 +        let original_file = sema.parse(file_id);
 +
 +        // Insert a fake ident to get a valid parse tree. We will use this file
 +        // to determine context, though the original_file will be used for
 +        // actual completion.
 +        let file_with_fake_ident = {
 +            let parse = db.parse(file_id);
 +            let edit = Indel::insert(offset, COMPLETION_MARKER.to_string());
 +            parse.reparse(&edit).tree()
 +        };
-         let fake_ident_token =
-             file_with_fake_ident.syntax().token_at_offset(offset).right_biased()?;
 +
++        // always pick the token to the immediate left of the cursor, as that is what we are actually
++        // completing on
 +        let original_token = original_file.syntax().token_at_offset(offset).left_biased()?;
-         let token = sema.descend_into_macros_single(original_token.clone());
++
++        let AnalysisResult {
++            analysis,
++            expected: (expected_type, expected_name),
++            qualifier_ctx,
++            token,
++            offset,
++        } = expand_and_analyze(
++            &sema,
++            original_file.syntax().clone(),
++            file_with_fake_ident.syntax().clone(),
++            offset,
++            &original_token,
++        )?;
 +
 +        // adjust for macro input, this still fails if there is no token written yet
-         let scope_offset = if original_token == token { offset } else { token.text_range().end() };
-         let scope = sema.scope_at_offset(&token.parent()?, scope_offset)?;
++        let scope = sema.scope_at_offset(&token.parent()?, offset)?;
 +
 +        let krate = scope.krate();
 +        let module = scope.module();
 +
 +        let mut locals = FxHashMap::default();
 +        scope.process_all_names(&mut |name, scope| {
 +            if let ScopeDef::Local(local) = scope {
 +                locals.insert(name, local);
 +            }
 +        });
 +
 +        let depth_from_crate_root = iter::successors(module.parent(db), |m| m.parent(db)).count();
 +
-         let mut ctx = CompletionContext {
++        let ctx = CompletionContext {
 +            sema,
 +            scope,
 +            db,
 +            config,
 +            position,
 +            original_token,
 +            token,
 +            krate,
 +            module,
-             expected_name: None,
-             expected_type: None,
-             qualifier_ctx: Default::default(),
++            expected_name,
++            expected_type,
++            qualifier_ctx,
 +            locals,
 +            depth_from_crate_root,
 +        };
-         let ident_ctx = ctx.expand_and_analyze(
-             original_file.syntax().clone(),
-             file_with_fake_ident.syntax().clone(),
-             offset,
-             fake_ident_token,
-         )?;
-         Some((ctx, ident_ctx))
++        Some((ctx, analysis))
 +    }
 +}
 +
 +const OP_TRAIT_LANG_NAMES: &[&str] = &[
 +    "add_assign",
 +    "add",
 +    "bitand_assign",
 +    "bitand",
 +    "bitor_assign",
 +    "bitor",
 +    "bitxor_assign",
 +    "bitxor",
 +    "deref_mut",
 +    "deref",
 +    "div_assign",
 +    "div",
 +    "eq",
 +    "fn_mut",
 +    "fn_once",
 +    "fn",
 +    "index_mut",
 +    "index",
 +    "mul_assign",
 +    "mul",
 +    "neg",
 +    "not",
 +    "partial_ord",
 +    "rem_assign",
 +    "rem",
 +    "shl_assign",
 +    "shl",
 +    "shr_assign",
 +    "shr",
 +    "sub",
 +];
index 01dd9a234f553c354a47eb3487fc610a37b8df26,0000000000000000000000000000000000000000..04111ec7efaa68e4dad225e25a8a220861d6b490
mode 100644,000000..100644
--- /dev/null
@@@ -1,1296 -1,0 +1,1327 @@@
-     AttrCtx, CompletionAnalysis, CompletionContext, DotAccess, DotAccessKind, ExprCtx,
-     ItemListKind, LifetimeContext, LifetimeKind, NameContext, NameKind, NameRefContext,
-     NameRefKind, ParamContext, ParamKind, PathCompletionCtx, PathKind, PatternContext,
-     PatternRefutability, Qualified, QualifierCtx, TypeAscriptionTarget, TypeLocation,
-     COMPLETION_MARKER,
 +//! Module responsible for analyzing the code surrounding the cursor for completion.
 +use std::iter;
 +
 +use hir::{Semantics, Type, TypeInfo};
 +use ide_db::{active_parameter::ActiveParameter, RootDatabase};
 +use syntax::{
 +    algo::{find_node_at_offset, non_trivia_sibling},
 +    ast::{self, AttrKind, HasArgList, HasLoopBody, HasName, NameOrNameRef},
 +    match_ast, AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode,
 +    SyntaxToken, TextRange, TextSize, T,
 +};
 +
 +use crate::context::{
- impl<'a> CompletionContext<'a> {
-     /// Expand attributes and macro calls at the current cursor position for both the original file
-     /// and fake file repeatedly. As soon as one of the two expansions fail we stop so the original
-     /// and speculative states stay in sync.
-     pub(super) fn expand_and_analyze(
-         &mut self,
-         mut original_file: SyntaxNode,
-         mut speculative_file: SyntaxNode,
-         mut offset: TextSize,
-         mut fake_ident_token: SyntaxToken,
-     ) -> Option<CompletionAnalysis> {
-         let _p = profile::span("CompletionContext::expand_and_fill");
-         let mut derive_ctx = None;
++    AttrCtx, CompletionAnalysis, DotAccess, DotAccessKind, ExprCtx, ItemListKind, LifetimeContext,
++    LifetimeKind, NameContext, NameKind, NameRefContext, NameRefKind, ParamContext, ParamKind,
++    PathCompletionCtx, PathKind, PatternContext, PatternRefutability, Qualified, QualifierCtx,
++    TypeAscriptionTarget, TypeLocation, COMPLETION_MARKER,
 +};
 +
-         'expansion: loop {
-             let parent_item =
-                 |item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
-             let ancestor_items = iter::successors(
-                 Option::zip(
-                     find_node_at_offset::<ast::Item>(&original_file, offset),
-                     find_node_at_offset::<ast::Item>(&speculative_file, offset),
-                 ),
-                 |(a, b)| parent_item(a).zip(parent_item(b)),
-             );
++struct ExpansionResult {
++    original_file: SyntaxNode,
++    speculative_file: SyntaxNode,
++    offset: TextSize,
++    fake_ident_token: SyntaxToken,
++    derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>,
++}
 +
-             // first try to expand attributes as these are always the outermost macro calls
-             'ancestors: for (actual_item, item_with_fake_ident) in ancestor_items {
-                 match (
-                     self.sema.expand_attr_macro(&actual_item),
-                     self.sema.speculative_expand_attr_macro(
-                         &actual_item,
-                         &item_with_fake_ident,
-                         fake_ident_token.clone(),
-                     ),
-                 ) {
-                     // maybe parent items have attributes, so continue walking the ancestors
-                     (None, None) => continue 'ancestors,
-                     // successful expansions
-                     (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
-                         let new_offset = fake_mapped_token.text_range().start();
-                         if new_offset > actual_expansion.text_range().end() {
-                             // offset outside of bounds from the original expansion,
-                             // stop here to prevent problems from happening
-                             break 'expansion;
-                         }
-                         original_file = actual_expansion;
-                         speculative_file = fake_expansion;
-                         fake_ident_token = fake_mapped_token;
-                         offset = new_offset;
-                         continue 'expansion;
++pub(super) struct AnalysisResult {
++    pub(super) analysis: CompletionAnalysis,
++    pub(super) expected: (Option<Type>, Option<ast::NameOrNameRef>),
++    pub(super) qualifier_ctx: QualifierCtx,
++    pub(super) token: SyntaxToken,
++    pub(super) offset: TextSize,
++}
 +
-                     // exactly one expansion failed, inconsistent state so stop expanding completely
-                     _ => break 'expansion,
++pub(super) fn expand_and_analyze(
++    sema: &Semantics<'_, RootDatabase>,
++    original_file: SyntaxNode,
++    speculative_file: SyntaxNode,
++    offset: TextSize,
++    original_token: &SyntaxToken,
++) -> Option<AnalysisResult> {
++    // as we insert after the offset, right biased will *always* pick the identifier no matter
++    // if there is an ident already typed or not
++    let fake_ident_token = speculative_file.token_at_offset(offset).right_biased()?;
++    // the relative offset between the cursor and the *identifier* token we are completing on
++    let relative_offset = offset - fake_ident_token.text_range().start();
++    // make the offset point to the start of the original token, as that is what the
++    // intermediate offsets calculated in expansion always points to
++    let offset = offset - relative_offset;
++    let expansion = expand(sema, original_file, speculative_file, offset, fake_ident_token);
++    // add the relative offset back, so that left_biased finds the proper token
++    let offset = expansion.offset + relative_offset;
++    let token = expansion.original_file.token_at_offset(offset).left_biased()?;
++
++    analyze(sema, expansion, original_token, &token).map(|(analysis, expected, qualifier_ctx)| {
++        AnalysisResult { analysis, expected, qualifier_ctx, token, offset }
++    })
++}
++
++/// Expand attributes and macro calls at the current cursor position for both the original file
++/// and fake file repeatedly. As soon as one of the two expansions fail we stop so the original
++/// and speculative states stay in sync.
++fn expand(
++    sema: &Semantics<'_, RootDatabase>,
++    mut original_file: SyntaxNode,
++    mut speculative_file: SyntaxNode,
++    mut offset: TextSize,
++    mut fake_ident_token: SyntaxToken,
++) -> ExpansionResult {
++    let _p = profile::span("CompletionContext::expand");
++    let mut derive_ctx = None;
++
++    'expansion: loop {
++        let parent_item =
++            |item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
++        let ancestor_items = iter::successors(
++            Option::zip(
++                find_node_at_offset::<ast::Item>(&original_file, offset),
++                find_node_at_offset::<ast::Item>(&speculative_file, offset),
++            ),
++            |(a, b)| parent_item(a).zip(parent_item(b)),
++        );
++
++        // first try to expand attributes as these are always the outermost macro calls
++        'ancestors: for (actual_item, item_with_fake_ident) in ancestor_items {
++            match (
++                sema.expand_attr_macro(&actual_item),
++                sema.speculative_expand_attr_macro(
++                    &actual_item,
++                    &item_with_fake_ident,
++                    fake_ident_token.clone(),
++                ),
++            ) {
++                // maybe parent items have attributes, so continue walking the ancestors
++                (None, None) => continue 'ancestors,
++                // successful expansions
++                (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
++                    let new_offset = fake_mapped_token.text_range().start();
++                    if new_offset > actual_expansion.text_range().end() {
++                        // offset outside of bounds from the original expansion,
++                        // stop here to prevent problems from happening
++                        break 'expansion;
 +                    }
-             // No attributes have been expanded, so look for macro_call! token trees or derive token trees
-             let orig_tt = match find_node_at_offset::<ast::TokenTree>(&original_file, offset) {
-                 Some(it) => it,
-                 None => break 'expansion,
-             };
-             let spec_tt = match find_node_at_offset::<ast::TokenTree>(&speculative_file, offset) {
-                 Some(it) => it,
-                 None => break 'expansion,
-             };
++                    original_file = actual_expansion;
++                    speculative_file = fake_expansion;
++                    fake_ident_token = fake_mapped_token;
++                    offset = new_offset;
++                    continue 'expansion;
 +                }
++                // exactly one expansion failed, inconsistent state so stop expanding completely
++                _ => break 'expansion,
 +            }
++        }
 +
-             // Expand pseudo-derive expansion
-             if let (Some(orig_attr), Some(spec_attr)) = (
-                 orig_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
-                 spec_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
++        // No attributes have been expanded, so look for macro_call! token trees or derive token trees
++        let orig_tt = match find_node_at_offset::<ast::TokenTree>(&original_file, offset) {
++            Some(it) => it,
++            None => break 'expansion,
++        };
++        let spec_tt = match find_node_at_offset::<ast::TokenTree>(&speculative_file, offset) {
++            Some(it) => it,
++            None => break 'expansion,
++        };
 +
-                 if let (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) = (
-                     self.sema.expand_derive_as_pseudo_attr_macro(&orig_attr),
-                     self.sema.speculative_expand_derive_as_pseudo_attr_macro(
-                         &orig_attr,
-                         &spec_attr,
-                         fake_ident_token.clone(),
-                     ),
-                 ) {
-                     derive_ctx = Some((
-                         actual_expansion,
-                         fake_expansion,
-                         fake_mapped_token.text_range().start(),
-                         orig_attr,
-                     ));
-                 }
-                 // at this point we won't have any more successful expansions, so stop
-                 break 'expansion;
++        // Expand pseudo-derive expansion
++        if let (Some(orig_attr), Some(spec_attr)) = (
++            orig_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
++            spec_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
++        ) {
++            if let (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) = (
++                sema.expand_derive_as_pseudo_attr_macro(&orig_attr),
++                sema.speculative_expand_derive_as_pseudo_attr_macro(
++                    &orig_attr,
++                    &spec_attr,
++                    fake_ident_token.clone(),
++                ),
 +            ) {
-             // Expand fn-like macro calls
-             if let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = (
-                 orig_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
-                 spec_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
-             ) {
-                 let mac_call_path0 = actual_macro_call.path().as_ref().map(|s| s.syntax().text());
-                 let mac_call_path1 =
-                     macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text());
++                derive_ctx = Some((
++                    actual_expansion,
++                    fake_expansion,
++                    fake_mapped_token.text_range().start(),
++                    orig_attr,
++                ));
 +            }
++            // at this point we won't have any more successful expansions, so stop
++            break 'expansion;
++        }
 +
-                 // inconsistent state, stop expanding
-                 if mac_call_path0 != mac_call_path1 {
-                     break 'expansion;
-                 }
-                 let speculative_args = match macro_call_with_fake_ident.token_tree() {
-                     Some(tt) => tt,
-                     None => break 'expansion,
-                 };
++        // Expand fn-like macro calls
++        if let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = (
++            orig_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
++            spec_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
++        ) {
++            let mac_call_path0 = actual_macro_call.path().as_ref().map(|s| s.syntax().text());
++            let mac_call_path1 =
++                macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text());
 +
-                 match (
-                     self.sema.expand(&actual_macro_call),
-                     self.sema.speculative_expand(
-                         &actual_macro_call,
-                         &speculative_args,
-                         fake_ident_token.clone(),
-                     ),
-                 ) {
-                     // successful expansions
-                     (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
-                         let new_offset = fake_mapped_token.text_range().start();
-                         if new_offset > actual_expansion.text_range().end() {
-                             // offset outside of bounds from the original expansion,
-                             // stop here to prevent problems from happening
-                             break 'expansion;
-                         }
-                         original_file = actual_expansion;
-                         speculative_file = fake_expansion;
-                         fake_ident_token = fake_mapped_token;
-                         offset = new_offset;
-                         continue 'expansion;
++            // inconsistent state, stop expanding
++            if mac_call_path0 != mac_call_path1 {
++                break 'expansion;
++            }
++            let speculative_args = match macro_call_with_fake_ident.token_tree() {
++                Some(tt) => tt,
++                None => break 'expansion,
++            };
 +
-                     // at least on expansion failed, we won't have anything to expand from this point
-                     // onwards so break out
-                     _ => break 'expansion,
++            match (
++                sema.expand(&actual_macro_call),
++                sema.speculative_expand(
++                    &actual_macro_call,
++                    &speculative_args,
++                    fake_ident_token.clone(),
++                ),
++            ) {
++                // successful expansions
++                (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
++                    let new_offset = fake_mapped_token.text_range().start();
++                    if new_offset > actual_expansion.text_range().end() {
++                        // offset outside of bounds from the original expansion,
++                        // stop here to prevent problems from happening
++                        break 'expansion;
 +                    }
-             // none of our states have changed so stop the loop
-             break 'expansion;
++                    original_file = actual_expansion;
++                    speculative_file = fake_expansion;
++                    fake_ident_token = fake_mapped_token;
++                    offset = new_offset;
++                    continue 'expansion;
 +                }
++                // at least on expansion failed, we won't have anything to expand from this point
++                // onwards so break out
++                _ => break 'expansion,
 +            }
-         self.analyze(&original_file, speculative_file, offset, derive_ctx)
 +        }
 +
-     /// Calculate the expected type and name of the cursor position.
-     fn expected_type_and_name(
-         &self,
-         name_like: &ast::NameLike,
-     ) -> (Option<Type>, Option<NameOrNameRef>) {
-         let mut node = match self.token.parent() {
-             Some(it) => it,
-             None => return (None, None),
-         };
++        // none of our states have changed so stop the loop
++        break 'expansion;
 +    }
++    ExpansionResult { original_file, speculative_file, offset, fake_ident_token, derive_ctx }
++}
 +
-         let strip_refs = |mut ty: Type| match name_like {
-             ast::NameLike::NameRef(n) => {
-                 let p = match n.syntax().parent() {
-                     Some(it) => it,
-                     None => return ty,
-                 };
-                 let top_syn = match_ast! {
-                     match p {
-                         ast::FieldExpr(e) => e
-                             .syntax()
-                             .ancestors()
-                             .map_while(ast::FieldExpr::cast)
-                             .last()
-                             .map(|it| it.syntax().clone()),
-                         ast::PathSegment(e) => e
-                             .syntax()
-                             .ancestors()
-                             .skip(1)
-                             .take_while(|it| ast::Path::can_cast(it.kind()) || ast::PathExpr::can_cast(it.kind()))
-                             .find_map(ast::PathExpr::cast)
-                             .map(|it| it.syntax().clone()),
-                         _ => None
-                     }
-                 };
-                 let top_syn = match top_syn {
-                     Some(it) => it,
-                     None => return ty,
++/// Fill the completion context, this is what does semantic reasoning about the surrounding context
++/// of the completion location.
++fn analyze(
++    sema: &Semantics<'_, RootDatabase>,
++    expansion_result: ExpansionResult,
++    original_token: &SyntaxToken,
++    self_token: &SyntaxToken,
++) -> Option<(CompletionAnalysis, (Option<Type>, Option<ast::NameOrNameRef>), QualifierCtx)> {
++    let _p = profile::span("CompletionContext::analyze");
++    let ExpansionResult { original_file, speculative_file, offset, fake_ident_token, derive_ctx } =
++        expansion_result;
++    let syntax_element = NodeOrToken::Token(fake_ident_token);
++    if is_in_token_of_for_loop(syntax_element.clone()) {
++        // for pat $0
++        // there is nothing to complete here except `in` keyword
++        // don't bother populating the context
++        // FIXME: the completion calculations should end up good enough
++        // such that this special case becomes unnecessary
++        return None;
++    }
 +
-                 for _ in top_syn.ancestors().skip(1).map_while(ast::RefExpr::cast) {
-                     cov_mark::hit!(expected_type_fn_param_ref);
-                     ty = ty.strip_reference();
-                 }
-                 ty
++    // Overwrite the path kind for derives
++    if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx {
++        if let Some(ast::NameLike::NameRef(name_ref)) =
++            find_node_at_offset(&file_with_fake_ident, offset)
++        {
++            let parent = name_ref.syntax().parent()?;
++            let (mut nameref_ctx, _) = classify_name_ref(&sema, &original_file, name_ref, parent)?;
++            if let NameRefKind::Path(path_ctx) = &mut nameref_ctx.kind {
++                path_ctx.kind = PathKind::Derive {
++                    existing_derives: sema
++                        .resolve_derive_macro(&origin_attr)
++                        .into_iter()
++                        .flatten()
++                        .flatten()
++                        .collect(),
 +                };
-             _ => ty,
-         };
-         loop {
-             break match_ast! {
-                 match node {
-                     ast::LetStmt(it) => {
-                         cov_mark::hit!(expected_type_let_with_leading_char);
-                         cov_mark::hit!(expected_type_let_without_leading_char);
-                         let ty = it.pat()
-                             .and_then(|pat| self.sema.type_of_pat(&pat))
-                             .or_else(|| it.initializer().and_then(|it| self.sema.type_of_expr(&it)))
-                             .map(TypeInfo::original);
-                         let name = match it.pat() {
-                             Some(ast::Pat::IdentPat(ident)) => ident.name().map(NameOrNameRef::Name),
-                             Some(_) | None => None,
-                         };
-                         (ty, name)
-                     },
-                     ast::LetExpr(it) => {
-                         cov_mark::hit!(expected_type_if_let_without_leading_char);
-                         let ty = it.pat()
-                             .and_then(|pat| self.sema.type_of_pat(&pat))
-                             .or_else(|| it.expr().and_then(|it| self.sema.type_of_expr(&it)))
-                             .map(TypeInfo::original);
-                         (ty, None)
-                     },
-                     ast::ArgList(_) => {
-                         cov_mark::hit!(expected_type_fn_param);
-                         ActiveParameter::at_token(
-                             &self.sema,
-                             self.token.clone(),
-                         ).map(|ap| {
-                             let name = ap.ident().map(NameOrNameRef::Name);
-                             let ty = strip_refs(ap.ty);
-                             (Some(ty), name)
-                         })
-                         .unwrap_or((None, None))
-                     },
-                     ast::RecordExprFieldList(it) => {
-                         // wouldn't try {} be nice...
-                         (|| {
-                             if self.token.kind() == T![..]
-                                 || self.token.prev_token().map(|t| t.kind()) == Some(T![..])
-                             {
-                                 cov_mark::hit!(expected_type_struct_func_update);
-                                 let record_expr = it.syntax().parent().and_then(ast::RecordExpr::cast)?;
-                                 let ty = self.sema.type_of_expr(&record_expr.into())?;
-                                 Some((
-                                     Some(ty.original),
-                                     None
-                                 ))
-                             } else {
-                                 cov_mark::hit!(expected_type_struct_field_without_leading_char);
-                                 let expr_field = self.token.prev_sibling_or_token()?
-                                     .into_node()
-                                     .and_then(ast::RecordExprField::cast)?;
-                                 let (_, _, ty) = self.sema.resolve_record_field(&expr_field)?;
-                                 Some((
-                                     Some(ty),
-                                     expr_field.field_name().map(NameOrNameRef::NameRef),
-                                 ))
-                             }
-                         })().unwrap_or((None, None))
-                     },
-                     ast::RecordExprField(it) => {
-                         if let Some(expr) = it.expr() {
-                             cov_mark::hit!(expected_type_struct_field_with_leading_char);
-                             (
-                                 self.sema.type_of_expr(&expr).map(TypeInfo::original),
-                                 it.field_name().map(NameOrNameRef::NameRef),
-                             )
-                         } else {
-                             cov_mark::hit!(expected_type_struct_field_followed_by_comma);
-                             let ty = self.sema.resolve_record_field(&it)
-                                 .map(|(_, _, ty)| ty);
-                             (
-                                 ty,
-                                 it.field_name().map(NameOrNameRef::NameRef),
-                             )
-                         }
-                     },
-                     // match foo { $0 }
-                     // match foo { ..., pat => $0 }
-                     ast::MatchExpr(it) => {
-                         let on_arrow = previous_non_trivia_token(self.token.clone()).map_or(false, |it| T![=>] == it.kind());
 +            }
-                         let ty = if on_arrow {
-                             // match foo { ..., pat => $0 }
-                             cov_mark::hit!(expected_type_match_arm_body_without_leading_char);
-                             cov_mark::hit!(expected_type_match_arm_body_with_leading_char);
-                             self.sema.type_of_expr(&it.into())
-                         } else {
-                             // match foo { $0 }
-                             cov_mark::hit!(expected_type_match_arm_without_leading_char);
-                             it.expr().and_then(|e| self.sema.type_of_expr(&e))
-                         }.map(TypeInfo::original);
-                         (ty, None)
-                     },
-                     ast::IfExpr(it) => {
-                         let ty = it.condition()
-                             .and_then(|e| self.sema.type_of_expr(&e))
-                             .map(TypeInfo::original);
-                         (ty, None)
-                     },
-                     ast::IdentPat(it) => {
-                         cov_mark::hit!(expected_type_if_let_with_leading_char);
-                         cov_mark::hit!(expected_type_match_arm_with_leading_char);
-                         let ty = self.sema.type_of_pat(&ast::Pat::from(it)).map(TypeInfo::original);
-                         (ty, None)
-                     },
-                     ast::Fn(it) => {
-                         cov_mark::hit!(expected_type_fn_ret_with_leading_char);
-                         cov_mark::hit!(expected_type_fn_ret_without_leading_char);
-                         let def = self.sema.to_def(&it);
-                         (def.map(|def| def.ret_type(self.db)), None)
-                     },
-                     ast::ClosureExpr(it) => {
-                         let ty = self.sema.type_of_expr(&it.into());
-                         ty.and_then(|ty| ty.original.as_callable(self.db))
-                             .map(|c| (Some(c.return_type()), None))
-                             .unwrap_or((None, None))
-                     },
-                     ast::ParamList(_) => (None, None),
-                     ast::Stmt(_) => (None, None),
-                     ast::Item(_) => (None, None),
-                     _ => {
-                         match node.parent() {
-                             Some(n) => {
-                                 node = n;
-                                 continue;
-                             },
-                             None => (None, None),
-                         }
-                     },
++            return Some((
++                CompletionAnalysis::NameRef(nameref_ctx),
++                (None, None),
++                QualifierCtx::default(),
++            ));
++        }
++        return None;
++    }
 +
-     }
-     /// Fill the completion context, this is what does semantic reasoning about the surrounding context
-     /// of the completion location.
-     fn analyze(
-         &mut self,
-         original_file: &SyntaxNode,
-         file_with_fake_ident: SyntaxNode,
-         offset: TextSize,
-         derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>,
-     ) -> Option<CompletionAnalysis> {
-         let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased()?;
-         let syntax_element = NodeOrToken::Token(fake_ident_token);
-         if is_in_token_of_for_loop(syntax_element.clone()) {
-             // for pat $0
-             // there is nothing to complete here except `in` keyword
-             // don't bother populating the context
-             // FIXME: the completion calculations should end up good enough
-             // such that this special case becomes unnecessary
-             return None;
++    let name_like = match find_node_at_offset(&speculative_file, offset) {
++        Some(it) => it,
++        None => {
++            let analysis = if let Some(original) = ast::String::cast(original_token.clone()) {
++                CompletionAnalysis::String {
++                    original,
++                    expanded: ast::String::cast(self_token.clone()),
++                }
++            } else {
++                // Fix up trailing whitespace problem
++                // #[attr(foo = $0
++                let token = syntax::algo::skip_trivia_token(self_token.clone(), Direction::Prev)?;
++                let p = token.parent()?;
++                if p.kind() == SyntaxKind::TOKEN_TREE
++                    && p.ancestors().any(|it| it.kind() == SyntaxKind::META)
++                {
++                    let colon_prefix = previous_non_trivia_token(self_token.clone())
++                        .map_or(false, |it| T![:] == it.kind());
++                    CompletionAnalysis::UnexpandedAttrTT {
++                        fake_attribute_under_caret: syntax_element
++                            .ancestors()
++                            .find_map(ast::Attr::cast),
++                        colon_prefix,
++                    }
++                } else {
++                    return None;
 +                }
 +            };
++            return Some((analysis, (None, None), QualifierCtx::default()));
 +        }
-         // Overwrite the path kind for derives
-         if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx {
-             if let Some(ast::NameLike::NameRef(name_ref)) =
-                 find_node_at_offset(&file_with_fake_ident, offset)
-             {
-                 let parent = name_ref.syntax().parent()?;
-                 let (mut nameref_ctx, _) =
-                     Self::classify_name_ref(&self.sema, &original_file, name_ref, parent)?;
-                 if let NameRefKind::Path(path_ctx) = &mut nameref_ctx.kind {
-                     path_ctx.kind = PathKind::Derive {
-                         existing_derives: self
-                             .sema
-                             .resolve_derive_macro(&origin_attr)
-                             .into_iter()
-                             .flatten()
-                             .flatten()
-                             .collect(),
-                     };
++    };
++    let expected = expected_type_and_name(sema, &self_token, &name_like);
++    let mut qual_ctx = QualifierCtx::default();
++    let analysis = match name_like {
++        ast::NameLike::Lifetime(lifetime) => {
++            CompletionAnalysis::Lifetime(classify_lifetime(sema, &original_file, lifetime)?)
++        }
++        ast::NameLike::NameRef(name_ref) => {
++            let parent = name_ref.syntax().parent()?;
++            let (nameref_ctx, qualifier_ctx) =
++                classify_name_ref(sema, &original_file, name_ref, parent.clone())?;
++            qual_ctx = qualifier_ctx;
++            CompletionAnalysis::NameRef(nameref_ctx)
++        }
++        ast::NameLike::Name(name) => {
++            let name_ctx = classify_name(sema, &original_file, name)?;
++            CompletionAnalysis::Name(name_ctx)
 +        }
++    };
++    Some((analysis, expected, qual_ctx))
++}
 +
-                 return Some(CompletionAnalysis::NameRef(nameref_ctx));
++/// Calculate the expected type and name of the cursor position.
++fn expected_type_and_name(
++    sema: &Semantics<'_, RootDatabase>,
++    token: &SyntaxToken,
++    name_like: &ast::NameLike,
++) -> (Option<Type>, Option<NameOrNameRef>) {
++    let mut node = match token.parent() {
++        Some(it) => it,
++        None => return (None, None),
++    };
++
++    let strip_refs = |mut ty: Type| match name_like {
++        ast::NameLike::NameRef(n) => {
++            let p = match n.syntax().parent() {
++                Some(it) => it,
++                None => return ty,
++            };
++            let top_syn = match_ast! {
++                match p {
++                    ast::FieldExpr(e) => e
++                        .syntax()
++                        .ancestors()
++                        .map_while(ast::FieldExpr::cast)
++                        .last()
++                        .map(|it| it.syntax().clone()),
++                    ast::PathSegment(e) => e
++                        .syntax()
++                        .ancestors()
++                        .skip(1)
++                        .take_while(|it| ast::Path::can_cast(it.kind()) || ast::PathExpr::can_cast(it.kind()))
++                        .find_map(ast::PathExpr::cast)
++                        .map(|it| it.syntax().clone()),
++                    _ => None
 +                }
-             return None;
++            };
++            let top_syn = match top_syn {
++                Some(it) => it,
++                None => return ty,
++            };
++            for _ in top_syn.ancestors().skip(1).map_while(ast::RefExpr::cast) {
++                cov_mark::hit!(expected_type_fn_param_ref);
++                ty = ty.strip_reference();
 +            }
-         let name_like = match find_node_at_offset(&file_with_fake_ident, offset) {
-             Some(it) => it,
-             None => {
-                 let analysis =
-                     if let Some(original) = ast::String::cast(self.original_token.clone()) {
-                         CompletionAnalysis::String {
-                             original,
-                             expanded: ast::String::cast(self.token.clone()),
-                         }
-                     } else {
-                         // Fix up trailing whitespace problem
-                         // #[attr(foo = $0
-                         let token =
-                             syntax::algo::skip_trivia_token(self.token.clone(), Direction::Prev)?;
-                         let p = token.parent()?;
-                         if p.kind() == SyntaxKind::TOKEN_TREE
-                             && p.ancestors().any(|it| it.kind() == SyntaxKind::META)
++            ty
 +        }
++        _ => ty,
++    };
 +
-                             let colon_prefix = previous_non_trivia_token(self.token.clone())
-                                 .map_or(false, |it| T![:] == it.kind());
-                             CompletionAnalysis::UnexpandedAttrTT {
-                                 fake_attribute_under_caret: syntax_element
-                                     .ancestors()
-                                     .find_map(ast::Attr::cast),
-                                 colon_prefix,
-                             }
++    loop {
++        break match_ast! {
++            match node {
++                ast::LetStmt(it) => {
++                    cov_mark::hit!(expected_type_let_with_leading_char);
++                    cov_mark::hit!(expected_type_let_without_leading_char);
++                    let ty = it.pat()
++                        .and_then(|pat| sema.type_of_pat(&pat))
++                        .or_else(|| it.initializer().and_then(|it| sema.type_of_expr(&it)))
++                        .map(TypeInfo::original);
++                    let name = match it.pat() {
++                        Some(ast::Pat::IdentPat(ident)) => ident.name().map(NameOrNameRef::Name),
++                        Some(_) | None => None,
++                    };
++
++                    (ty, name)
++                },
++                ast::LetExpr(it) => {
++                    cov_mark::hit!(expected_type_if_let_without_leading_char);
++                    let ty = it.pat()
++                        .and_then(|pat| sema.type_of_pat(&pat))
++                        .or_else(|| it.expr().and_then(|it| sema.type_of_expr(&it)))
++                        .map(TypeInfo::original);
++                    (ty, None)
++                },
++                ast::ArgList(_) => {
++                    cov_mark::hit!(expected_type_fn_param);
++                    ActiveParameter::at_token(
++                        &sema,
++                       token.clone(),
++                    ).map(|ap| {
++                        let name = ap.ident().map(NameOrNameRef::Name);
++
++                        let ty = strip_refs(ap.ty);
++                        (Some(ty), name)
++                    })
++                    .unwrap_or((None, None))
++                },
++                ast::RecordExprFieldList(it) => {
++                    // wouldn't try {} be nice...
++                    (|| {
++                        if token.kind() == T![..]
++                            ||token.prev_token().map(|t| t.kind()) == Some(T![..])
 +                        {
-                             return None;
++                            cov_mark::hit!(expected_type_struct_func_update);
++                            let record_expr = it.syntax().parent().and_then(ast::RecordExpr::cast)?;
++                            let ty = sema.type_of_expr(&record_expr.into())?;
++                            Some((
++                                Some(ty.original),
++                                None
++                            ))
 +                        } else {
-                     };
-                 return Some(analysis);
-             }
-         };
-         (self.expected_type, self.expected_name) = self.expected_type_and_name(&name_like);
-         let analysis = match name_like {
-             ast::NameLike::Lifetime(lifetime) => CompletionAnalysis::Lifetime(
-                 Self::classify_lifetime(&self.sema, original_file, lifetime)?,
-             ),
-             ast::NameLike::NameRef(name_ref) => {
-                 let parent = name_ref.syntax().parent()?;
-                 let (nameref_ctx, qualifier_ctx) =
-                     Self::classify_name_ref(&self.sema, &original_file, name_ref, parent.clone())?;
++                            cov_mark::hit!(expected_type_struct_field_without_leading_char);
++                            let expr_field = token.prev_sibling_or_token()?
++                                .into_node()
++                                .and_then(ast::RecordExprField::cast)?;
++                            let (_, _, ty) = sema.resolve_record_field(&expr_field)?;
++                            Some((
++                                Some(ty),
++                                expr_field.field_name().map(NameOrNameRef::NameRef),
++                            ))
 +                        }
-                 self.qualifier_ctx = qualifier_ctx;
-                 CompletionAnalysis::NameRef(nameref_ctx)
-             }
-             ast::NameLike::Name(name) => {
-                 let name_ctx = Self::classify_name(&self.sema, original_file, name)?;
-                 CompletionAnalysis::Name(name_ctx)
++                    })().unwrap_or((None, None))
++                },
++                ast::RecordExprField(it) => {
++                    if let Some(expr) = it.expr() {
++                        cov_mark::hit!(expected_type_struct_field_with_leading_char);
++                        (
++                            sema.type_of_expr(&expr).map(TypeInfo::original),
++                            it.field_name().map(NameOrNameRef::NameRef),
++                        )
++                    } else {
++                        cov_mark::hit!(expected_type_struct_field_followed_by_comma);
++                        let ty = sema.resolve_record_field(&it)
++                            .map(|(_, _, ty)| ty);
++                        (
++                            ty,
++                            it.field_name().map(NameOrNameRef::NameRef),
++                        )
++                    }
++                },
++                // match foo { $0 }
++                // match foo { ..., pat => $0 }
++                ast::MatchExpr(it) => {
++                    let on_arrow = previous_non_trivia_token(token.clone()).map_or(false, |it| T![=>] == it.kind());
 +
-         Some(analysis)
++                    let ty = if on_arrow {
++                        // match foo { ..., pat => $0 }
++                        cov_mark::hit!(expected_type_match_arm_body_without_leading_char);
++                        cov_mark::hit!(expected_type_match_arm_body_with_leading_char);
++                        sema.type_of_expr(&it.into())
++                    } else {
++                        // match foo { $0 }
++                        cov_mark::hit!(expected_type_match_arm_without_leading_char);
++                        it.expr().and_then(|e| sema.type_of_expr(&e))
++                    }.map(TypeInfo::original);
++                    (ty, None)
++                },
++                ast::IfExpr(it) => {
++                    let ty = it.condition()
++                        .and_then(|e| sema.type_of_expr(&e))
++                        .map(TypeInfo::original);
++                    (ty, None)
++                },
++                ast::IdentPat(it) => {
++                    cov_mark::hit!(expected_type_if_let_with_leading_char);
++                    cov_mark::hit!(expected_type_match_arm_with_leading_char);
++                    let ty = sema.type_of_pat(&ast::Pat::from(it)).map(TypeInfo::original);
++                    (ty, None)
++                },
++                ast::Fn(it) => {
++                    cov_mark::hit!(expected_type_fn_ret_with_leading_char);
++                    cov_mark::hit!(expected_type_fn_ret_without_leading_char);
++                    let def = sema.to_def(&it);
++                    (def.map(|def| def.ret_type(sema.db)), None)
++                },
++                ast::ClosureExpr(it) => {
++                    let ty = sema.type_of_expr(&it.into());
++                    ty.and_then(|ty| ty.original.as_callable(sema.db))
++                        .map(|c| (Some(c.return_type()), None))
++                        .unwrap_or((None, None))
++                },
++                ast::ParamList(_) => (None, None),
++                ast::Stmt(_) => (None, None),
++                ast::Item(_) => (None, None),
++                _ => {
++                    match node.parent() {
++                        Some(n) => {
++                            node = n;
++                            continue;
++                        },
++                        None => (None, None),
++                    }
++                },
 +            }
 +        };
-     fn classify_lifetime(
-         _sema: &Semantics<'_, RootDatabase>,
-         original_file: &SyntaxNode,
-         lifetime: ast::Lifetime,
-     ) -> Option<LifetimeContext> {
-         let parent = lifetime.syntax().parent()?;
-         if parent.kind() == SyntaxKind::ERROR {
-             return None;
-         }
 +    }
++}
 +
-         let kind = match_ast! {
-             match parent {
-                 ast::LifetimeParam(param) => LifetimeKind::LifetimeParam {
-                     is_decl: param.lifetime().as_ref() == Some(&lifetime),
-                     param
-                 },
-                 ast::BreakExpr(_) => LifetimeKind::LabelRef,
-                 ast::ContinueExpr(_) => LifetimeKind::LabelRef,
-                 ast::Label(_) => LifetimeKind::LabelDef,
-                 _ => LifetimeKind::Lifetime,
-             }
-         };
-         let lifetime = find_node_at_offset(&original_file, lifetime.syntax().text_range().start());
++fn classify_lifetime(
++    _sema: &Semantics<'_, RootDatabase>,
++    original_file: &SyntaxNode,
++    lifetime: ast::Lifetime,
++) -> Option<LifetimeContext> {
++    let parent = lifetime.syntax().parent()?;
++    if parent.kind() == SyntaxKind::ERROR {
++        return None;
++    }
 +
-         Some(LifetimeContext { lifetime, kind })
-     }
++    let kind = match_ast! {
++        match parent {
++            ast::LifetimeParam(param) => LifetimeKind::LifetimeParam {
++                is_decl: param.lifetime().as_ref() == Some(&lifetime),
++                param
++            },
++            ast::BreakExpr(_) => LifetimeKind::LabelRef,
++            ast::ContinueExpr(_) => LifetimeKind::LabelRef,
++            ast::Label(_) => LifetimeKind::LabelDef,
++            _ => LifetimeKind::Lifetime,
++        }
++    };
++    let lifetime = find_node_at_offset(&original_file, lifetime.syntax().text_range().start());
 +
-     fn classify_name(
-         sema: &Semantics<'_, RootDatabase>,
-         original_file: &SyntaxNode,
-         name: ast::Name,
-     ) -> Option<NameContext> {
-         let parent = name.syntax().parent()?;
-         let kind = match_ast! {
-             match parent {
-                 ast::Const(_) => NameKind::Const,
-                 ast::ConstParam(_) => NameKind::ConstParam,
-                 ast::Enum(_) => NameKind::Enum,
-                 ast::Fn(_) => NameKind::Function,
-                 ast::IdentPat(bind_pat) => {
-                     let mut pat_ctx = pattern_context_for(sema, original_file, bind_pat.into());
-                     if let Some(record_field) = ast::RecordPatField::for_field_name(&name) {
-                         pat_ctx.record_pat = find_node_in_file_compensated(sema, original_file, &record_field.parent_record_pat());
-                     }
++    Some(LifetimeContext { lifetime, kind })
++}
 +
-                     NameKind::IdentPat(pat_ctx)
-                 },
-                 ast::MacroDef(_) => NameKind::MacroDef,
-                 ast::MacroRules(_) => NameKind::MacroRules,
-                 ast::Module(module) => NameKind::Module(module),
-                 ast::RecordField(_) => NameKind::RecordField,
-                 ast::Rename(_) => NameKind::Rename,
-                 ast::SelfParam(_) => NameKind::SelfParam,
-                 ast::Static(_) => NameKind::Static,
-                 ast::Struct(_) => NameKind::Struct,
-                 ast::Trait(_) => NameKind::Trait,
-                 ast::TypeAlias(_) => NameKind::TypeAlias,
-                 ast::TypeParam(_) => NameKind::TypeParam,
-                 ast::Union(_) => NameKind::Union,
-                 ast::Variant(_) => NameKind::Variant,
-                 _ => return None,
-             }
-         };
-         let name = find_node_at_offset(&original_file, name.syntax().text_range().start());
-         Some(NameContext { name, kind })
-     }
++fn classify_name(
++    sema: &Semantics<'_, RootDatabase>,
++    original_file: &SyntaxNode,
++    name: ast::Name,
++) -> Option<NameContext> {
++    let parent = name.syntax().parent()?;
++    let kind = match_ast! {
++        match parent {
++            ast::Const(_) => NameKind::Const,
++            ast::ConstParam(_) => NameKind::ConstParam,
++            ast::Enum(_) => NameKind::Enum,
++            ast::Fn(_) => NameKind::Function,
++            ast::IdentPat(bind_pat) => {
++                let mut pat_ctx = pattern_context_for(sema, original_file, bind_pat.into());
++                if let Some(record_field) = ast::RecordPatField::for_field_name(&name) {
++                    pat_ctx.record_pat = find_node_in_file_compensated(sema, original_file, &record_field.parent_record_pat());
++                }
 +
-     fn classify_name_ref(
-         sema: &Semantics<'_, RootDatabase>,
-         original_file: &SyntaxNode,
-         name_ref: ast::NameRef,
-         parent: SyntaxNode,
-     ) -> Option<(NameRefContext, QualifierCtx)> {
-         let nameref = find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
++                NameKind::IdentPat(pat_ctx)
++            },
++            ast::MacroDef(_) => NameKind::MacroDef,
++            ast::MacroRules(_) => NameKind::MacroRules,
++            ast::Module(module) => NameKind::Module(module),
++            ast::RecordField(_) => NameKind::RecordField,
++            ast::Rename(_) => NameKind::Rename,
++            ast::SelfParam(_) => NameKind::SelfParam,
++            ast::Static(_) => NameKind::Static,
++            ast::Struct(_) => NameKind::Struct,
++            ast::Trait(_) => NameKind::Trait,
++            ast::TypeAlias(_) => NameKind::TypeAlias,
++            ast::TypeParam(_) => NameKind::TypeParam,
++            ast::Union(_) => NameKind::Union,
++            ast::Variant(_) => NameKind::Variant,
++            _ => return None,
++        }
++    };
++    let name = find_node_at_offset(&original_file, name.syntax().text_range().start());
++    Some(NameContext { name, kind })
++}
 +
-         let make_res =
-             |kind| (NameRefContext { nameref: nameref.clone(), kind }, Default::default());
++fn classify_name_ref(
++    sema: &Semantics<'_, RootDatabase>,
++    original_file: &SyntaxNode,
++    name_ref: ast::NameRef,
++    parent: SyntaxNode,
++) -> Option<(NameRefContext, QualifierCtx)> {
++    let nameref = find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
 +
-         if let Some(record_field) = ast::RecordExprField::for_field_name(&name_ref) {
-             let dot_prefix = previous_non_trivia_token(name_ref.syntax().clone())
-                 .map_or(false, |it| T![.] == it.kind());
++    let make_res = |kind| (NameRefContext { nameref: nameref.clone(), kind }, Default::default());
 +
-             return find_node_in_file_compensated(
++    if let Some(record_field) = ast::RecordExprField::for_field_name(&name_ref) {
++        let dot_prefix = previous_non_trivia_token(name_ref.syntax().clone())
++            .map_or(false, |it| T![.] == it.kind());
 +
-                 &record_field.parent_record_lit(),
++        return find_node_in_file_compensated(
++            sema,
++            original_file,
++            &record_field.parent_record_lit(),
++        )
++        .map(|expr| NameRefKind::RecordExpr { expr, dot_prefix })
++        .map(make_res);
++    }
++    if let Some(record_field) = ast::RecordPatField::for_field_name_ref(&name_ref) {
++        let kind = NameRefKind::Pattern(PatternContext {
++            param_ctx: None,
++            has_type_ascription: false,
++            ref_token: None,
++            mut_token: None,
++            record_pat: find_node_in_file_compensated(
 +                sema,
 +                original_file,
-             .map(|expr| NameRefKind::RecordExpr { expr, dot_prefix })
-             .map(make_res);
++                &record_field.parent_record_pat(),
++            ),
++            ..pattern_context_for(
++                sema,
++                original_file,
++                record_field.parent_record_pat().clone().into(),
 +            )
-         if let Some(record_field) = ast::RecordPatField::for_field_name_ref(&name_ref) {
-             let kind = NameRefKind::Pattern(PatternContext {
-                 param_ctx: None,
-                 has_type_ascription: false,
-                 ref_token: None,
-                 mut_token: None,
-                 record_pat: find_node_in_file_compensated(
-                     sema,
-                     original_file,
-                     &record_field.parent_record_pat(),
-                 ),
-                 ..pattern_context_for(
-                     sema,
-                     original_file,
-                     record_field.parent_record_pat().clone().into(),
-                 )
-             });
-             return Some(make_res(kind));
++        });
++        return Some(make_res(kind));
++    }
++
++    let segment = match_ast! {
++        match parent {
++            ast::PathSegment(segment) => segment,
++            ast::FieldExpr(field) => {
++                let receiver = find_opt_node_in_file(original_file, field.expr());
++                let receiver_is_ambiguous_float_literal = match &receiver {
++                    Some(ast::Expr::Literal(l)) => matches! {
++                        l.kind(),
++                        ast::LiteralKind::FloatNumber { .. } if l.syntax().last_token().map_or(false, |it| it.text().ends_with('.'))
++                    },
++                    _ => false,
++                };
++                let kind = NameRefKind::DotAccess(DotAccess {
++                    receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
++                    kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal },
++                    receiver
++                });
++                return Some(make_res(kind));
++            },
++            ast::MethodCallExpr(method) => {
++                let receiver = find_opt_node_in_file(original_file, method.receiver());
++                let kind = NameRefKind::DotAccess(DotAccess {
++                    receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
++                    kind: DotAccessKind::Method { has_parens: method.arg_list().map_or(false, |it| it.l_paren_token().is_some()) },
++                    receiver
++                });
++                return Some(make_res(kind));
++            },
++            _ => return None,
 +        }
-         let segment = match_ast! {
++    };
++
++    let path = segment.parent_path();
++    let original_path = find_node_in_file_compensated(sema, original_file, &path);
++
++    let mut path_ctx = PathCompletionCtx {
++        has_call_parens: false,
++        has_macro_bang: false,
++        qualified: Qualified::No,
++        parent: None,
++        path: path.clone(),
++        original_path,
++        kind: PathKind::Item { kind: ItemListKind::SourceFile },
++        has_type_args: false,
++        use_tree_parent: false,
++    };
++
++    let is_in_block = |it: &SyntaxNode| {
++        it.parent()
++            .map(|node| {
++                ast::ExprStmt::can_cast(node.kind()) || ast::StmtList::can_cast(node.kind())
++            })
++            .unwrap_or(false)
++    };
++    let func_update_record = |syn: &SyntaxNode| {
++        if let Some(record_expr) = syn.ancestors().nth(2).and_then(ast::RecordExpr::cast) {
++            find_node_in_file_compensated(sema, original_file, &record_expr)
++        } else {
++            None
++        }
++    };
++    let after_if_expr = |node: SyntaxNode| {
++        let prev_expr = (|| {
++            let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?;
++            ast::ExprStmt::cast(prev_sibling)?.expr()
++        })();
++        matches!(prev_expr, Some(ast::Expr::IfExpr(_)))
++    };
++
++    // We do not want to generate path completions when we are sandwiched between an item decl signature and its body.
++    // ex. trait Foo $0 {}
++    // in these cases parser recovery usually kicks in for our inserted identifier, causing it
++    // to either be parsed as an ExprStmt or a MacroCall, depending on whether it is in a block
++    // expression or an item list.
++    // The following code checks if the body is missing, if it is we either cut off the body
++    // from the item or it was missing in the first place
++    let inbetween_body_and_decl_check = |node: SyntaxNode| {
++        if let Some(NodeOrToken::Node(n)) =
++            syntax::algo::non_trivia_sibling(node.into(), syntax::Direction::Prev)
++        {
++            if let Some(item) = ast::Item::cast(n) {
++                let is_inbetween = match &item {
++                    ast::Item::Const(it) => it.body().is_none(),
++                    ast::Item::Enum(it) => it.variant_list().is_none(),
++                    ast::Item::ExternBlock(it) => it.extern_item_list().is_none(),
++                    ast::Item::Fn(it) => it.body().is_none(),
++                    ast::Item::Impl(it) => it.assoc_item_list().is_none(),
++                    ast::Item::Module(it) => it.item_list().is_none(),
++                    ast::Item::Static(it) => it.body().is_none(),
++                    ast::Item::Struct(it) => it.field_list().is_none(),
++                    ast::Item::Trait(it) => it.assoc_item_list().is_none(),
++                    ast::Item::TypeAlias(it) => it.ty().is_none(),
++                    ast::Item::Union(it) => it.record_field_list().is_none(),
++                    _ => false,
++                };
++                if is_inbetween {
++                    return Some(item);
++                }
++            }
 +        }
++        None
++    };
 +
-                 ast::PathSegment(segment) => segment,
-                 ast::FieldExpr(field) => {
-                     let receiver = find_opt_node_in_file(original_file, field.expr());
-                     let receiver_is_ambiguous_float_literal = match &receiver {
-                         Some(ast::Expr::Literal(l)) => matches! {
-                             l.kind(),
-                             ast::LiteralKind::FloatNumber { .. } if l.syntax().last_token().map_or(false, |it| it.text().ends_with('.'))
-                         },
-                         _ => false,
++    let type_location = |node: &SyntaxNode| {
++        let parent = node.parent()?;
++        let res = match_ast! {
 +            match parent {
-                     let kind = NameRefKind::DotAccess(DotAccess {
-                         receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
-                         kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal },
-                         receiver
-                     });
-                     return Some(make_res(kind));
++                ast::Const(it) => {
++                    let name = find_opt_node_in_file(original_file, it.name())?;
++                    let original = ast::Const::cast(name.syntax().parent()?)?;
++                    TypeLocation::TypeAscription(TypeAscriptionTarget::Const(original.body()))
++                },
++                ast::RetType(it) => {
++                    if it.thin_arrow_token().is_none() {
++                        return None;
++                    }
++                    let parent = match ast::Fn::cast(parent.parent()?) {
++                        Some(x) => x.param_list(),
++                        None => ast::ClosureExpr::cast(parent.parent()?)?.param_list(),
 +                    };
-                 ast::MethodCallExpr(method) => {
-                     let receiver = find_opt_node_in_file(original_file, method.receiver());
-                     let kind = NameRefKind::DotAccess(DotAccess {
-                         receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
-                         kind: DotAccessKind::Method { has_parens: method.arg_list().map_or(false, |it| it.l_paren_token().is_some()) },
-                         receiver
-                     });
-                     return Some(make_res(kind));
++
++                    let parent = find_opt_node_in_file(original_file, parent)?.syntax().parent()?;
++                    TypeLocation::TypeAscription(TypeAscriptionTarget::RetType(match_ast! {
++                        match parent {
++                            ast::ClosureExpr(it) => {
++                                it.body()
++                            },
++                            ast::Fn(it) => {
++                                it.body().map(ast::Expr::BlockExpr)
++                            },
++                            _ => return None,
++                        }
++                    }))
++                },
++                ast::Param(it) => {
++                    if it.colon_token().is_none() {
++                        return None;
++                    }
++                    TypeLocation::TypeAscription(TypeAscriptionTarget::FnParam(find_opt_node_in_file(original_file, it.pat())))
 +                },
-         let path = segment.parent_path();
-         let original_path = find_node_in_file_compensated(sema, original_file, &path);
-         let mut path_ctx = PathCompletionCtx {
-             has_call_parens: false,
-             has_macro_bang: false,
-             qualified: Qualified::No,
-             parent: None,
-             path: path.clone(),
-             original_path,
-             kind: PathKind::Item { kind: ItemListKind::SourceFile },
-             has_type_args: false,
-             use_tree_parent: false,
-         };
-         let is_in_block = |it: &SyntaxNode| {
-             it.parent()
-                 .map(|node| {
-                     ast::ExprStmt::can_cast(node.kind()) || ast::StmtList::can_cast(node.kind())
-                 })
-                 .unwrap_or(false)
-         };
-         let func_update_record = |syn: &SyntaxNode| {
-             if let Some(record_expr) = syn.ancestors().nth(2).and_then(ast::RecordExpr::cast) {
-                 find_node_in_file_compensated(sema, original_file, &record_expr)
++                ast::LetStmt(it) => {
++                    if it.colon_token().is_none() {
++                        return None;
++                    }
++                    TypeLocation::TypeAscription(TypeAscriptionTarget::Let(find_opt_node_in_file(original_file, it.pat())))
++                },
++                ast::Impl(it) => {
++                    match it.trait_() {
++                        Some(t) if t.syntax() == node => TypeLocation::ImplTrait,
++                        _ => match it.self_ty() {
++                            Some(t) if t.syntax() == node => TypeLocation::ImplTarget,
++                            _ => return None,
++                        },
++                    }
 +                },
++                ast::TypeBound(_) => TypeLocation::TypeBound,
++                // is this case needed?
++                ast::TypeBoundList(_) => TypeLocation::TypeBound,
++                ast::GenericArg(it) => TypeLocation::GenericArgList(find_opt_node_in_file_compensated(sema, original_file, it.syntax().parent().and_then(ast::GenericArgList::cast))),
++                // is this case needed?
++                ast::GenericArgList(it) => TypeLocation::GenericArgList(find_opt_node_in_file_compensated(sema, original_file, Some(it))),
++                ast::TupleField(_) => TypeLocation::TupleField,
 +                _ => return None,
 +            }
 +        };
++        Some(res)
++    };
 +
-         };
-         let after_if_expr = |node: SyntaxNode| {
-             let prev_expr = (|| {
-                 let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?;
-                 ast::ExprStmt::cast(prev_sibling)?.expr()
-             })();
-             matches!(prev_expr, Some(ast::Expr::IfExpr(_)))
-         };
++    let is_in_condition = |it: &ast::Expr| {
++        (|| {
++            let parent = it.syntax().parent()?;
++            if let Some(expr) = ast::WhileExpr::cast(parent.clone()) {
++                Some(expr.condition()? == *it)
++            } else if let Some(expr) = ast::IfExpr::cast(parent) {
++                Some(expr.condition()? == *it)
 +            } else {
 +                None
 +            }
-         // We do not want to generate path completions when we are sandwiched between an item decl signature and its body.
-         // ex. trait Foo $0 {}
-         // in these cases parser recovery usually kicks in for our inserted identifier, causing it
-         // to either be parsed as an ExprStmt or a MacroCall, depending on whether it is in a block
-         // expression or an item list.
-         // The following code checks if the body is missing, if it is we either cut off the body
-         // from the item or it was missing in the first place
-         let inbetween_body_and_decl_check = |node: SyntaxNode| {
-             if let Some(NodeOrToken::Node(n)) =
-                 syntax::algo::non_trivia_sibling(node.into(), syntax::Direction::Prev)
-             {
-                 if let Some(item) = ast::Item::cast(n) {
-                     let is_inbetween = match &item {
-                         ast::Item::Const(it) => it.body().is_none(),
-                         ast::Item::Enum(it) => it.variant_list().is_none(),
-                         ast::Item::ExternBlock(it) => it.extern_item_list().is_none(),
-                         ast::Item::Fn(it) => it.body().is_none(),
-                         ast::Item::Impl(it) => it.assoc_item_list().is_none(),
-                         ast::Item::Module(it) => it.item_list().is_none(),
-                         ast::Item::Static(it) => it.body().is_none(),
-                         ast::Item::Struct(it) => it.field_list().is_none(),
-                         ast::Item::Trait(it) => it.assoc_item_list().is_none(),
-                         ast::Item::TypeAlias(it) => it.ty().is_none(),
-                         ast::Item::Union(it) => it.record_field_list().is_none(),
-                         _ => false,
-                     };
-                     if is_inbetween {
-                         return Some(item);
++        })()
++        .unwrap_or(false)
++    };
 +
-             None
++    let make_path_kind_expr = |expr: ast::Expr| {
++        let it = expr.syntax();
++        let in_block_expr = is_in_block(it);
++        let in_loop_body = is_in_loop_body(it);
++        let after_if_expr = after_if_expr(it.clone());
++        let ref_expr_parent =
++            path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast);
++        let (innermost_ret_ty, self_param) = {
++            let find_ret_ty = |it: SyntaxNode| {
++                if let Some(item) = ast::Item::cast(it.clone()) {
++                    match item {
++                        ast::Item::Fn(f) => Some(sema.to_def(&f).map(|it| it.ret_type(sema.db))),
++                        ast::Item::MacroCall(_) => None,
++                        _ => Some(None),
 +                    }
++                } else {
++                    let expr = ast::Expr::cast(it)?;
++                    let callable = match expr {
++                        // FIXME
++                        // ast::Expr::BlockExpr(b) if b.async_token().is_some() || b.try_token().is_some() => sema.type_of_expr(b),
++                        ast::Expr::ClosureExpr(_) => sema.type_of_expr(&expr),
++                        _ => return None,
++                    };
++                    Some(
++                        callable
++                            .and_then(|c| c.adjusted().as_callable(sema.db))
++                            .map(|it| it.return_type()),
++                    )
++                }
++            };
++            let find_fn_self_param = |it| match it {
++                ast::Item::Fn(fn_) => Some(sema.to_def(&fn_).and_then(|it| it.self_param(sema.db))),
++                ast::Item::MacroCall(_) => None,
++                _ => Some(None),
++            };
++
++            match find_node_in_file_compensated(sema, original_file, &expr) {
++                Some(it) => {
++                    let innermost_ret_ty = sema
++                        .ancestors_with_macros(it.syntax().clone())
++                        .find_map(find_ret_ty)
++                        .flatten();
++
++                    let self_param = sema
++                        .ancestors_with_macros(it.syntax().clone())
++                        .filter_map(ast::Item::cast)
++                        .find_map(find_fn_self_param)
++                        .flatten();
++                    (innermost_ret_ty, self_param)
 +                }
++                None => (None, None),
 +            }
-         let type_location = |node: &SyntaxNode| {
-             let parent = node.parent()?;
-             let res = match_ast! {
-                 match parent {
-                     ast::Const(it) => {
-                         let name = find_opt_node_in_file(original_file, it.name())?;
-                         let original = ast::Const::cast(name.syntax().parent()?)?;
-                         TypeLocation::TypeAscription(TypeAscriptionTarget::Const(original.body()))
-                     },
-                     ast::RetType(it) => {
-                         if it.thin_arrow_token().is_none() {
-                             return None;
-                         }
-                         let parent = match ast::Fn::cast(parent.parent()?) {
-                             Some(x) => x.param_list(),
-                             None => ast::ClosureExpr::cast(parent.parent()?)?.param_list(),
-                         };
 +        };
++        let is_func_update = func_update_record(it);
++        let in_condition = is_in_condition(&expr);
++        let incomplete_let = it
++            .parent()
++            .and_then(ast::LetStmt::cast)
++            .map_or(false, |it| it.semicolon_token().is_none());
++        let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax());
 +
-                         let parent = find_opt_node_in_file(original_file, parent)?.syntax().parent()?;
-                         TypeLocation::TypeAscription(TypeAscriptionTarget::RetType(match_ast! {
-                             match parent {
-                                 ast::ClosureExpr(it) => {
-                                     it.body()
-                                 },
-                                 ast::Fn(it) => {
-                                     it.body().map(ast::Expr::BlockExpr)
-                                 },
-                                 _ => return None,
-                             }
-                         }))
-                     },
-                     ast::Param(it) => {
-                         if it.colon_token().is_none() {
-                             return None;
-                         }
-                         TypeLocation::TypeAscription(TypeAscriptionTarget::FnParam(find_opt_node_in_file(original_file, it.pat())))
-                     },
-                     ast::LetStmt(it) => {
-                         if it.colon_token().is_none() {
-                             return None;
-                         }
-                         TypeLocation::TypeAscription(TypeAscriptionTarget::Let(find_opt_node_in_file(original_file, it.pat())))
-                     },
-                     ast::Impl(it) => {
-                         match it.trait_() {
-                             Some(t) if t.syntax() == node => TypeLocation::ImplTrait,
-                             _ => match it.self_ty() {
-                                 Some(t) if t.syntax() == node => TypeLocation::ImplTarget,
-                                 _ => return None,
++        let in_match_guard = match it.parent().and_then(ast::MatchArm::cast) {
++            Some(arm) => arm
++                .fat_arrow_token()
++                .map_or(true, |arrow| it.text_range().start() < arrow.text_range().start()),
++            None => false,
++        };
 +
-                     ast::TypeBound(_) => TypeLocation::TypeBound,
-                     // is this case needed?
-                     ast::TypeBoundList(_) => TypeLocation::TypeBound,
-                     ast::GenericArg(it) => TypeLocation::GenericArgList(find_opt_node_in_file_compensated(sema, original_file, it.syntax().parent().and_then(ast::GenericArgList::cast))),
-                     // is this case needed?
-                     ast::GenericArgList(it) => TypeLocation::GenericArgList(find_opt_node_in_file_compensated(sema, original_file, Some(it))),
-                     ast::TupleField(_) => TypeLocation::TupleField,
-                     _ => return None,
-                 }
-             };
-             Some(res)
-         };
-         let is_in_condition = |it: &ast::Expr| {
-             (|| {
-                 let parent = it.syntax().parent()?;
-                 if let Some(expr) = ast::WhileExpr::cast(parent.clone()) {
-                     Some(expr.condition()? == *it)
-                 } else if let Some(expr) = ast::IfExpr::cast(parent) {
-                     Some(expr.condition()? == *it)
-                 } else {
-                     None
-                 }
-             })()
-             .unwrap_or(false)
++        PathKind::Expr {
++            expr_ctx: ExprCtx {
++                in_block_expr,
++                in_loop_body,
++                after_if_expr,
++                in_condition,
++                ref_expr_parent,
++                is_func_update,
++                innermost_ret_ty,
++                self_param,
++                incomplete_let,
++                impl_,
++                in_match_guard,
++            },
++        }
++    };
++    let make_path_kind_type = |ty: ast::Type| {
++        let location = type_location(ty.syntax());
++        PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
++    };
++
++    let mut kind_macro_call = |it: ast::MacroCall| {
++        path_ctx.has_macro_bang = it.excl_token().is_some();
++        let parent = it.syntax().parent()?;
++        // Any path in an item list will be treated as a macro call by the parser
++        let kind = match_ast! {
++            match parent {
++                ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
++                ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
++                ast::MacroType(ty) => make_path_kind_type(ty.into()),
++                ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
++                ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
++                    Some(it) => match_ast! {
++                        match it {
++                            ast::Trait(_) => ItemListKind::Trait,
++                            ast::Impl(it) => if it.trait_().is_some() {
++                                ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
++                            } else {
++                                ItemListKind::Impl
 +                            },
++                            _ => return None
 +                        }
 +                    },
-         let make_path_kind_expr = |expr: ast::Expr| {
-             let it = expr.syntax();
-             let in_block_expr = is_in_block(it);
-             let in_loop_body = is_in_loop_body(it);
-             let after_if_expr = after_if_expr(it.clone());
-             let ref_expr_parent =
-                 path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast);
-             let (innermost_ret_ty, self_param) = {
-                 let find_ret_ty = |it: SyntaxNode| {
-                     if let Some(item) = ast::Item::cast(it.clone()) {
-                         match item {
-                             ast::Item::Fn(f) => {
-                                 Some(sema.to_def(&f).map(|it| it.ret_type(sema.db)))
-                             }
-                             ast::Item::MacroCall(_) => None,
-                             _ => Some(None),
++                    None => return None,
++                } },
++                ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
++                ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
++                _ => return None,
++            }
 +        };
++        Some(kind)
++    };
++    let make_path_kind_attr = |meta: ast::Meta| {
++        let attr = meta.parent_attr()?;
++        let kind = attr.kind();
++        let attached = attr.syntax().parent()?;
++        let is_trailing_outer_attr = kind != AttrKind::Inner
++            && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none();
++        let annotated_item_kind = if is_trailing_outer_attr { None } else { Some(attached.kind()) };
++        Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind } })
++    };
 +
-                     } else {
-                         let expr = ast::Expr::cast(it)?;
-                         let callable = match expr {
-                             // FIXME
-                             // ast::Expr::BlockExpr(b) if b.async_token().is_some() || b.try_token().is_some() => sema.type_of_expr(b),
-                             ast::Expr::ClosureExpr(_) => sema.type_of_expr(&expr),
-                             _ => return None,
-                         };
-                         Some(
-                             callable
-                                 .and_then(|c| c.adjusted().as_callable(sema.db))
-                                 .map(|it| it.return_type()),
-                         )
++    // Infer the path kind
++    let parent = path.syntax().parent()?;
++    let kind = match_ast! {
++        match parent {
++            ast::PathType(it) => make_path_kind_type(it.into()),
++            ast::PathExpr(it) => {
++                if let Some(p) = it.syntax().parent() {
++                    if ast::ExprStmt::can_cast(p.kind()) {
++                        if let Some(kind) = inbetween_body_and_decl_check(p) {
++                            return Some(make_res(NameRefKind::Keyword(kind)));
 +                        }
-                 };
-                 let find_fn_self_param = |it| match it {
-                     ast::Item::Fn(fn_) => {
-                         Some(sema.to_def(&fn_).and_then(|it| it.self_param(sema.db)))
-                     }
-                     ast::Item::MacroCall(_) => None,
-                     _ => Some(None),
-                 };
 +                    }
-                 match find_node_in_file_compensated(sema, original_file, &expr) {
-                     Some(it) => {
-                         let innermost_ret_ty = sema
-                             .ancestors_with_macros(it.syntax().clone())
-                             .find_map(find_ret_ty)
-                             .flatten();
++                }
 +
-                         let self_param = sema
-                             .ancestors_with_macros(it.syntax().clone())
-                             .filter_map(ast::Item::cast)
-                             .find_map(find_fn_self_param)
-                             .flatten();
-                         (innermost_ret_ty, self_param)
-                     }
-                     None => (None, None),
++                path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
 +
-             };
-             let is_func_update = func_update_record(it);
-             let in_condition = is_in_condition(&expr);
-             let incomplete_let = it
-                 .parent()
-                 .and_then(ast::LetStmt::cast)
-                 .map_or(false, |it| it.semicolon_token().is_none());
-             let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax());
-             let in_match_guard = match it.parent().and_then(ast::MatchArm::cast) {
-                 Some(arm) => arm
-                     .fat_arrow_token()
-                     .map_or(true, |arrow| it.text_range().start() < arrow.text_range().start()),
-                 None => false,
-             };
++                make_path_kind_expr(it.into())
++            },
++            ast::TupleStructPat(it) => {
++                path_ctx.has_call_parens = true;
++                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
++            },
++            ast::RecordPat(it) => {
++                path_ctx.has_call_parens = true;
++                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
++            },
++            ast::PathPat(it) => {
++                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
++            },
++            ast::MacroCall(it) => {
++                // A macro call in this position is usually a result of parsing recovery, so check that
++                if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
++                    return Some(make_res(NameRefKind::Keyword(kind)));
 +                }
-             PathKind::Expr {
-                 expr_ctx: ExprCtx {
-                     in_block_expr,
-                     in_loop_body,
-                     after_if_expr,
-                     in_condition,
-                     ref_expr_parent,
-                     is_func_update,
-                     innermost_ret_ty,
-                     self_param,
-                     incomplete_let,
-                     impl_,
-                     in_match_guard,
-                 },
-             }
-         };
-         let make_path_kind_type = |ty: ast::Type| {
-             let location = type_location(ty.syntax());
-             PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
-         };
 +
-         let mut kind_macro_call = |it: ast::MacroCall| {
-             path_ctx.has_macro_bang = it.excl_token().is_some();
-             let parent = it.syntax().parent()?;
-             // Any path in an item list will be treated as a macro call by the parser
-             let kind = match_ast! {
-                 match parent {
-                     ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
-                     ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
-                     ast::MacroType(ty) => make_path_kind_type(ty.into()),
-                     ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
-                     ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
-                         Some(it) => match_ast! {
-                             match it {
-                                 ast::Trait(_) => ItemListKind::Trait,
-                                 ast::Impl(it) => if it.trait_().is_some() {
-                                     ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
-                                 } else {
-                                     ItemListKind::Impl
-                                 },
-                                 _ => return None
-                             }
++                kind_macro_call(it)?
++            },
++            ast::Meta(meta) => make_path_kind_attr(meta)?,
++            ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
++            ast::UseTree(_) => PathKind::Use,
++            // completing inside a qualifier
++            ast::Path(parent) => {
++                path_ctx.parent = Some(parent.clone());
++                let parent = iter::successors(Some(parent), |it| it.parent_path()).last()?.syntax().parent()?;
++                match_ast! {
++                    match parent {
++                        ast::PathType(it) => make_path_kind_type(it.into()),
++                        ast::PathExpr(it) => {
++                            path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
 +
-                         None => return None,
-                     } },
-                     ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
-                     ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
-                     _ => return None,
-                 }
-             };
-             Some(kind)
-         };
-         let make_path_kind_attr = |meta: ast::Meta| {
-             let attr = meta.parent_attr()?;
-             let kind = attr.kind();
-             let attached = attr.syntax().parent()?;
-             let is_trailing_outer_attr = kind != AttrKind::Inner
-                 && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next)
-                     .is_none();
-             let annotated_item_kind =
-                 if is_trailing_outer_attr { None } else { Some(attached.kind()) };
-             Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind } })
-         };
-         // Infer the path kind
-         let parent = path.syntax().parent()?;
-         let kind = match_ast! {
-             match parent {
-                 ast::PathType(it) => make_path_kind_type(it.into()),
-                 ast::PathExpr(it) => {
-                     if let Some(p) = it.syntax().parent() {
-                         if ast::ExprStmt::can_cast(p.kind()) {
-                             if let Some(kind) = inbetween_body_and_decl_check(p) {
-                                 return Some(make_res(NameRefKind::Keyword(kind)));
-                             }
-                         }
++                            make_path_kind_expr(it.into())
 +                        },
-                     path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
++                        ast::TupleStructPat(it) => {
++                            path_ctx.has_call_parens = true;
++                            PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
++                        },
++                        ast::RecordPat(it) => {
++                            path_ctx.has_call_parens = true;
++                            PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
++                        },
++                        ast::PathPat(it) => {
++                            PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
++                        },
++                        ast::MacroCall(it) => {
++                            kind_macro_call(it)?
++                        },
++                        ast::Meta(meta) => make_path_kind_attr(meta)?,
++                        ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
++                        ast::UseTree(_) => PathKind::Use,
++                        ast::RecordExpr(it) => make_path_kind_expr(it.into()),
++                        _ => return None,
 +                    }
++                }
++            },
++            ast::RecordExpr(it) => make_path_kind_expr(it.into()),
++            _ => return None,
++        }
++    };
 +
-                     make_path_kind_expr(it.into())
-                 },
-                 ast::TupleStructPat(it) => {
-                     path_ctx.has_call_parens = true;
-                     PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
-                 },
-                 ast::RecordPat(it) => {
-                     path_ctx.has_call_parens = true;
-                     PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
-                 },
-                 ast::PathPat(it) => {
-                     PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
-                 },
-                 ast::MacroCall(it) => {
-                     // A macro call in this position is usually a result of parsing recovery, so check that
-                     if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
-                         return Some(make_res(NameRefKind::Keyword(kind)));
++    path_ctx.kind = kind;
++    path_ctx.has_type_args = segment.generic_arg_list().is_some();
 +
-                     kind_macro_call(it)?
-                 },
-                 ast::Meta(meta) => make_path_kind_attr(meta)?,
-                 ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
-                 ast::UseTree(_) => PathKind::Use,
-                 // completing inside a qualifier
-                 ast::Path(parent) => {
-                     path_ctx.parent = Some(parent.clone());
-                     let parent = iter::successors(Some(parent), |it| it.parent_path()).last()?.syntax().parent()?;
-                     match_ast! {
-                         match parent {
-                             ast::PathType(it) => make_path_kind_type(it.into()),
-                             ast::PathExpr(it) => {
-                                 path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
-                                 make_path_kind_expr(it.into())
-                             },
-                             ast::TupleStructPat(it) => {
-                                 path_ctx.has_call_parens = true;
-                                 PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
-                             },
-                             ast::RecordPat(it) => {
-                                 path_ctx.has_call_parens = true;
-                                 PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
-                             },
-                             ast::PathPat(it) => {
-                                 PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
-                             },
-                             ast::MacroCall(it) => {
-                                 kind_macro_call(it)?
-                             },
-                             ast::Meta(meta) => make_path_kind_attr(meta)?,
-                             ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
-                             ast::UseTree(_) => PathKind::Use,
-                             ast::RecordExpr(it) => make_path_kind_expr(it.into()),
-                             _ => return None,
-                         }
-                     }
-                 },
-                 ast::RecordExpr(it) => make_path_kind_expr(it.into()),
-                 _ => return None,
-             }
-         };
-         path_ctx.kind = kind;
-         path_ctx.has_type_args = segment.generic_arg_list().is_some();
-         // calculate the qualifier context
-         if let Some((qualifier, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
-             path_ctx.use_tree_parent = use_tree_parent;
-             if !use_tree_parent && segment.coloncolon_token().is_some() {
-                 path_ctx.qualified = Qualified::Absolute;
-             } else {
-                 let qualifier = qualifier
-                     .segment()
-                     .and_then(|it| find_node_in_file(original_file, &it))
-                     .map(|it| it.parent_path());
-                 if let Some(qualifier) = qualifier {
-                     let type_anchor = match qualifier.segment().and_then(|it| it.kind()) {
-                         Some(ast::PathSegmentKind::Type {
-                             type_ref: Some(type_ref),
-                             trait_ref,
-                         }) if qualifier.qualifier().is_none() => Some((type_ref, trait_ref)),
-                         _ => None,
++    // calculate the qualifier context
++    if let Some((qualifier, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
++        path_ctx.use_tree_parent = use_tree_parent;
++        if !use_tree_parent && segment.coloncolon_token().is_some() {
++            path_ctx.qualified = Qualified::Absolute;
++        } else {
++            let qualifier = qualifier
++                .segment()
++                .and_then(|it| find_node_in_file(original_file, &it))
++                .map(|it| it.parent_path());
++            if let Some(qualifier) = qualifier {
++                let type_anchor = match qualifier.segment().and_then(|it| it.kind()) {
++                    Some(ast::PathSegmentKind::Type { type_ref: Some(type_ref), trait_ref })
++                        if qualifier.qualifier().is_none() =>
++                    {
++                        Some((type_ref, trait_ref))
 +                    }
++                    _ => None,
++                };
 +
-                     path_ctx.qualified = if let Some((ty, trait_ref)) = type_anchor {
-                         let ty = match ty {
-                             ast::Type::InferType(_) => None,
-                             ty => sema.resolve_type(&ty),
-                         };
-                         let trait_ = trait_ref.and_then(|it| sema.resolve_trait(&it.path()?));
-                         Qualified::TypeAnchor { ty, trait_ }
-                     } else {
-                         let res = sema.resolve_path(&qualifier);
-                         // For understanding how and why super_chain_len is calculated the way it
-                         // is check the documentation at it's definition
-                         let mut segment_count = 0;
-                         let super_count =
-                             iter::successors(Some(qualifier.clone()), |p| p.qualifier())
-                                 .take_while(|p| {
-                                     p.segment()
-                                         .and_then(|s| {
-                                             segment_count += 1;
-                                             s.super_token()
-                                         })
-                                         .is_some()
++                path_ctx.qualified = if let Some((ty, trait_ref)) = type_anchor {
++                    let ty = match ty {
++                        ast::Type::InferType(_) => None,
++                        ty => sema.resolve_type(&ty),
 +                    };
++                    let trait_ = trait_ref.and_then(|it| sema.resolve_trait(&it.path()?));
++                    Qualified::TypeAnchor { ty, trait_ }
++                } else {
++                    let res = sema.resolve_path(&qualifier);
 +
-                                 .count();
++                    // For understanding how and why super_chain_len is calculated the way it
++                    // is check the documentation at it's definition
++                    let mut segment_count = 0;
++                    let super_count = iter::successors(Some(qualifier.clone()), |p| p.qualifier())
++                        .take_while(|p| {
++                            p.segment()
++                                .and_then(|s| {
++                                    segment_count += 1;
++                                    s.super_token()
 +                                })
-                         let super_chain_len =
-                             if segment_count > super_count { None } else { Some(super_count) };
++                                .is_some()
++                        })
++                        .count();
 +
-                         Qualified::With { path: qualifier, resolution: res, super_chain_len }
-                     }
-                 };
-             }
-         } else if let Some(segment) = path.segment() {
-             if segment.coloncolon_token().is_some() {
-                 path_ctx.qualified = Qualified::Absolute;
-             }
-         }
-         let mut qualifier_ctx = QualifierCtx::default();
-         if path_ctx.is_trivial_path() {
-             // fetch the full expression that may have qualifiers attached to it
-             let top_node = match path_ctx.kind {
-                 PathKind::Expr { expr_ctx: ExprCtx { in_block_expr: true, .. } } => {
-                     parent.ancestors().find(|it| ast::PathExpr::can_cast(it.kind())).and_then(|p| {
-                         let parent = p.parent()?;
-                         if ast::StmtList::can_cast(parent.kind()) {
-                             Some(p)
-                         } else if ast::ExprStmt::can_cast(parent.kind()) {
-                             Some(parent)
-                         } else {
-                             None
-                         }
-                     })
++                    let super_chain_len =
++                        if segment_count > super_count { None } else { Some(super_count) };
 +
-                 PathKind::Item { .. } => {
-                     parent.ancestors().find(|it| ast::MacroCall::can_cast(it.kind()))
-                 }
-                 _ => None,
++                    Qualified::With { path: qualifier, resolution: res, super_chain_len }
 +                }
-             if let Some(top) = top_node {
-                 if let Some(NodeOrToken::Node(error_node)) =
-                     syntax::algo::non_trivia_sibling(top.clone().into(), syntax::Direction::Prev)
-                 {
-                     if error_node.kind() == SyntaxKind::ERROR {
-                         qualifier_ctx.unsafe_tok = error_node
-                             .children_with_tokens()
-                             .filter_map(NodeOrToken::into_token)
-                             .find(|it| it.kind() == T![unsafe]);
-                         qualifier_ctx.vis_node =
-                             error_node.children().find_map(ast::Visibility::cast);
 +            };
-                 if let PathKind::Item { .. } = path_ctx.kind {
-                     if qualifier_ctx.none() {
-                         if let Some(t) = top.first_token() {
-                             if let Some(prev) = t
-                                 .prev_token()
-                                 .and_then(|t| syntax::algo::skip_trivia_token(t, Direction::Prev))
-                             {
-                                 if ![T![;], T!['}'], T!['{']].contains(&prev.kind()) {
-                                     // This was inferred to be an item position path, but it seems
-                                     // to be part of some other broken node which leaked into an item
-                                     // list
-                                     return None;
-                                 }
++        }
++    } else if let Some(segment) = path.segment() {
++        if segment.coloncolon_token().is_some() {
++            path_ctx.qualified = Qualified::Absolute;
++        }
++    }
++
++    let mut qualifier_ctx = QualifierCtx::default();
++    if path_ctx.is_trivial_path() {
++        // fetch the full expression that may have qualifiers attached to it
++        let top_node = match path_ctx.kind {
++            PathKind::Expr { expr_ctx: ExprCtx { in_block_expr: true, .. } } => {
++                parent.ancestors().find(|it| ast::PathExpr::can_cast(it.kind())).and_then(|p| {
++                    let parent = p.parent()?;
++                    if ast::StmtList::can_cast(parent.kind()) {
++                        Some(p)
++                    } else if ast::ExprStmt::can_cast(parent.kind()) {
++                        Some(parent)
++                    } else {
++                        None
 +                    }
++                })
++            }
++            PathKind::Item { .. } => {
++                parent.ancestors().find(|it| ast::MacroCall::can_cast(it.kind()))
++            }
++            _ => None,
++        };
++        if let Some(top) = top_node {
++            if let Some(NodeOrToken::Node(error_node)) =
++                syntax::algo::non_trivia_sibling(top.clone().into(), syntax::Direction::Prev)
++            {
++                if error_node.kind() == SyntaxKind::ERROR {
++                    qualifier_ctx.unsafe_tok = error_node
++                        .children_with_tokens()
++                        .filter_map(NodeOrToken::into_token)
++                        .find(|it| it.kind() == T![unsafe]);
++                    qualifier_ctx.vis_node = error_node.children().find_map(ast::Visibility::cast);
 +                }
++            }
 +
-         Some((NameRefContext { nameref, kind: NameRefKind::Path(path_ctx) }, qualifier_ctx))
++            if let PathKind::Item { .. } = path_ctx.kind {
++                if qualifier_ctx.none() {
++                    if let Some(t) = top.first_token() {
++                        if let Some(prev) = t
++                            .prev_token()
++                            .and_then(|t| syntax::algo::skip_trivia_token(t, Direction::Prev))
++                        {
++                            if ![T![;], T!['}'], T!['{']].contains(&prev.kind()) {
++                                // This was inferred to be an item position path, but it seems
++                                // to be part of some other broken node which leaked into an item
++                                // list
++                                return None;
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
++    Some((NameRefContext { nameref, kind: NameRefKind::Path(path_ctx) }, qualifier_ctx))
 +}
 +
 +fn pattern_context_for(
 +    sema: &Semantics<'_, RootDatabase>,
 +    original_file: &SyntaxNode,
 +    pat: ast::Pat,
 +) -> PatternContext {
 +    let mut param_ctx = None;
 +    let (refutability, has_type_ascription) =
 +    pat
 +        .syntax()
 +        .ancestors()
 +        .skip_while(|it| ast::Pat::can_cast(it.kind()))
 +        .next()
 +        .map_or((PatternRefutability::Irrefutable, false), |node| {
 +            let refutability = match_ast! {
 +                match node {
 +                    ast::LetStmt(let_) => return (PatternRefutability::Irrefutable, let_.ty().is_some()),
 +                    ast::Param(param) => {
 +                        let has_type_ascription = param.ty().is_some();
 +                        param_ctx = (|| {
 +                            let fake_param_list = param.syntax().parent().and_then(ast::ParamList::cast)?;
 +                            let param_list = find_node_in_file_compensated(sema, original_file, &fake_param_list)?;
 +                            let param_list_owner = param_list.syntax().parent()?;
 +                            let kind = match_ast! {
 +                                match param_list_owner {
 +                                    ast::ClosureExpr(closure) => ParamKind::Closure(closure),
 +                                    ast::Fn(fn_) => ParamKind::Function(fn_),
 +                                    _ => return None,
 +                                }
 +                            };
 +                            Some(ParamContext {
 +                                param_list, param, kind
 +                            })
 +                        })();
 +                        return (PatternRefutability::Irrefutable, has_type_ascription)
 +                    },
 +                    ast::MatchArm(_) => PatternRefutability::Refutable,
 +                    ast::LetExpr(_) => PatternRefutability::Refutable,
 +                    ast::ForExpr(_) => PatternRefutability::Irrefutable,
 +                    _ => PatternRefutability::Irrefutable,
 +                }
 +            };
 +            (refutability, false)
 +        });
 +    let (ref_token, mut_token) = match &pat {
 +        ast::Pat::IdentPat(it) => (it.ref_token(), it.mut_token()),
 +        _ => (None, None),
 +    };
 +
 +    PatternContext {
 +        refutability,
 +        param_ctx,
 +        has_type_ascription,
 +        parent_pat: pat.syntax().parent().and_then(ast::Pat::cast),
 +        mut_token,
 +        ref_token,
 +        record_pat: None,
 +        impl_: fetch_immediate_impl(sema, original_file, pat.syntax()),
 +    }
 +}
 +
 +fn fetch_immediate_impl(
 +    sema: &Semantics<'_, RootDatabase>,
 +    original_file: &SyntaxNode,
 +    node: &SyntaxNode,
 +) -> Option<ast::Impl> {
 +    let mut ancestors = ancestors_in_file_compensated(sema, original_file, node)?
 +        .filter_map(ast::Item::cast)
 +        .filter(|it| !matches!(it, ast::Item::MacroCall(_)));
 +
 +    match ancestors.next()? {
 +        ast::Item::Const(_) | ast::Item::Fn(_) | ast::Item::TypeAlias(_) => (),
 +        ast::Item::Impl(it) => return Some(it),
 +        _ => return None,
 +    }
 +    match ancestors.next()? {
 +        ast::Item::Impl(it) => Some(it),
 +        _ => None,
 +    }
 +}
 +
 +/// Attempts to find `node` inside `syntax` via `node`'s text range.
 +/// If the fake identifier has been inserted after this node or inside of this node use the `_compensated` version instead.
 +fn find_opt_node_in_file<N: AstNode>(syntax: &SyntaxNode, node: Option<N>) -> Option<N> {
 +    find_node_in_file(syntax, &node?)
 +}
 +
 +/// Attempts to find `node` inside `syntax` via `node`'s text range.
 +/// If the fake identifier has been inserted after this node or inside of this node use the `_compensated` version instead.
 +fn find_node_in_file<N: AstNode>(syntax: &SyntaxNode, node: &N) -> Option<N> {
 +    let syntax_range = syntax.text_range();
 +    let range = node.syntax().text_range();
 +    let intersection = range.intersect(syntax_range)?;
 +    syntax.covering_element(intersection).ancestors().find_map(N::cast)
 +}
 +
 +/// Attempts to find `node` inside `syntax` via `node`'s text range while compensating
 +/// for the offset introduced by the fake ident.
 +/// This is wrong if `node` comes before the insertion point! Use `find_node_in_file` instead.
 +fn find_node_in_file_compensated<N: AstNode>(
 +    sema: &Semantics<'_, RootDatabase>,
 +    in_file: &SyntaxNode,
 +    node: &N,
 +) -> Option<N> {
 +    ancestors_in_file_compensated(sema, in_file, node.syntax())?.find_map(N::cast)
 +}
 +
 +fn ancestors_in_file_compensated<'sema>(
 +    sema: &'sema Semantics<'_, RootDatabase>,
 +    in_file: &SyntaxNode,
 +    node: &SyntaxNode,
 +) -> Option<impl Iterator<Item = SyntaxNode> + 'sema> {
 +    let syntax_range = in_file.text_range();
 +    let range = node.text_range();
 +    let end = range.end().checked_sub(TextSize::try_from(COMPLETION_MARKER.len()).ok()?)?;
 +    if end < range.start() {
 +        return None;
 +    }
 +    let range = TextRange::new(range.start(), end);
 +    // our inserted ident could cause `range` to go outside of the original syntax, so cap it
 +    let intersection = range.intersect(syntax_range)?;
 +    let node = match in_file.covering_element(intersection) {
 +        NodeOrToken::Node(node) => node,
 +        NodeOrToken::Token(tok) => tok.parent()?,
 +    };
 +    Some(sema.ancestors_with_macros(node))
 +}
 +
 +/// Attempts to find `node` inside `syntax` via `node`'s text range while compensating
 +/// for the offset introduced by the fake ident..
 +/// This is wrong if `node` comes before the insertion point! Use `find_node_in_file` instead.
 +fn find_opt_node_in_file_compensated<N: AstNode>(
 +    sema: &Semantics<'_, RootDatabase>,
 +    syntax: &SyntaxNode,
 +    node: Option<N>,
 +) -> Option<N> {
 +    find_node_in_file_compensated(sema, syntax, &node?)
 +}
 +
 +fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> {
 +    if let Some(qual) = path.qualifier() {
 +        return Some((qual, false));
 +    }
 +    let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
 +    let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?;
 +    Some((use_tree.path()?, true))
 +}
 +
 +pub(crate) fn is_in_token_of_for_loop(element: SyntaxElement) -> bool {
 +    // oh my ...
 +    (|| {
 +        let syntax_token = element.into_token()?;
 +        let range = syntax_token.text_range();
 +        let for_expr = syntax_token.parent_ancestors().find_map(ast::ForExpr::cast)?;
 +
 +        // check if the current token is the `in` token of a for loop
 +        if let Some(token) = for_expr.in_token() {
 +            return Some(syntax_token == token);
 +        }
 +        let pat = for_expr.pat()?;
 +        if range.end() < pat.syntax().text_range().end() {
 +            // if we are inside or before the pattern we can't be at the `in` token position
 +            return None;
 +        }
 +        let next_sibl = next_non_trivia_sibling(pat.syntax().clone().into())?;
 +        Some(match next_sibl {
 +            // the loop body is some node, if our token is at the start we are at the `in` position,
 +            // otherwise we could be in a recovered expression, we don't wanna ruin completions there
 +            syntax::NodeOrToken::Node(n) => n.text_range().start() == range.start(),
 +            // the loop body consists of a single token, if we are this we are certainly at the `in` token position
 +            syntax::NodeOrToken::Token(t) => t == syntax_token,
 +        })
 +    })()
 +    .unwrap_or(false)
 +}
 +
 +#[test]
 +fn test_for_is_prev2() {
 +    crate::tests::check_pattern_is_applicable(r"fn __() { for i i$0 }", is_in_token_of_for_loop);
 +}
 +
 +pub(crate) fn is_in_loop_body(node: &SyntaxNode) -> bool {
 +    node.ancestors()
 +        .take_while(|it| it.kind() != SyntaxKind::FN && it.kind() != SyntaxKind::CLOSURE_EXPR)
 +        .find_map(|it| {
 +            let loop_body = match_ast! {
 +                match it {
 +                    ast::ForExpr(it) => it.loop_body(),
 +                    ast::WhileExpr(it) => it.loop_body(),
 +                    ast::LoopExpr(it) => it.loop_body(),
 +                    _ => None,
 +                }
 +            };
 +            loop_body.filter(|it| it.syntax().text_range().contains_range(node.text_range()))
 +        })
 +        .is_some()
 +}
 +
 +fn previous_non_trivia_token(e: impl Into<SyntaxElement>) -> Option<SyntaxToken> {
 +    let mut token = match e.into() {
 +        SyntaxElement::Node(n) => n.first_token()?,
 +        SyntaxElement::Token(t) => t,
 +    }
 +    .prev_token();
 +    while let Some(inner) = token {
 +        if !inner.kind().is_trivia() {
 +            return Some(inner);
 +        } else {
 +            token = inner.prev_token();
 +        }
 +    }
 +    None
 +}
 +
 +fn next_non_trivia_sibling(ele: SyntaxElement) -> Option<SyntaxElement> {
 +    let mut e = ele.next_sibling_or_token();
 +    while let Some(inner) = e {
 +        if !inner.kind().is_trivia() {
 +            return Some(inner);
 +        } else {
 +            e = inner.next_sibling_or_token();
 +        }
 +    }
 +    None
 +}
index 8d21f4fce0a2b324a3fc112c23ac2faef9560afa,0000000000000000000000000000000000000000..9d0044e55f598870413f74f7ce879d267342482c
mode 100644,000000..100644
--- /dev/null
@@@ -1,252 -1,0 +1,253 @@@
 +//! `completions` crate provides utilities for generating completions of user input.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +mod completions;
 +mod config;
 +mod context;
 +mod item;
 +mod render;
 +
 +#[cfg(test)]
 +mod tests;
 +mod snippet;
 +
 +use ide_db::{
 +    base_db::FilePosition,
 +    helpers::mod_path_to_ast,
 +    imports::{
 +        import_assets::NameToImport,
 +        insert_use::{self, ImportScope},
 +    },
 +    items_locator, RootDatabase,
 +};
 +use syntax::algo;
 +use text_edit::TextEdit;
 +
 +use crate::{
 +    completions::Completions,
 +    context::{
 +        CompletionAnalysis, CompletionContext, NameRefContext, NameRefKind, PathCompletionCtx,
 +        PathKind,
 +    },
 +};
 +
 +pub use crate::{
 +    config::{CallableSnippets, CompletionConfig},
 +    item::{
 +        CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch,
 +    },
 +    snippet::{Snippet, SnippetScope},
 +};
 +
 +//FIXME: split the following feature into fine-grained features.
 +
 +// Feature: Magic Completions
 +//
 +// In addition to usual reference completion, rust-analyzer provides some ✨magic✨
 +// completions as well:
 +//
 +// Keywords like `if`, `else` `while`, `loop` are completed with braces, and cursor
 +// is placed at the appropriate position. Even though `if` is easy to type, you
 +// still want to complete it, to get ` { }` for free! `return` is inserted with a
 +// space or `;` depending on the return type of the function.
 +//
 +// When completing a function call, `()` are automatically inserted. If a function
 +// takes arguments, the cursor is positioned inside the parenthesis.
 +//
 +// There are postfix completions, which can be triggered by typing something like
 +// `foo().if`. The word after `.` determines postfix completion. Possible variants are:
 +//
 +// - `expr.if` -> `if expr {}` or `if let ... {}` for `Option` or `Result`
 +// - `expr.match` -> `match expr {}`
 +// - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result`
 +// - `expr.ref` -> `&expr`
 +// - `expr.refm` -> `&mut expr`
 +// - `expr.let` -> `let $0 = expr;`
 +// - `expr.letm` -> `let mut $0 = expr;`
 +// - `expr.not` -> `!expr`
 +// - `expr.dbg` -> `dbg!(expr)`
 +// - `expr.dbgr` -> `dbg!(&expr)`
 +// - `expr.call` -> `(expr)`
 +//
 +// There also snippet completions:
 +//
 +// .Expressions
 +// - `pd` -> `eprintln!(" = {:?}", );`
 +// - `ppd` -> `eprintln!(" = {:#?}", );`
 +//
 +// .Items
 +// - `tfn` -> `#[test] fn feature(){}`
 +// - `tmod` ->
 +// ```rust
 +// #[cfg(test)]
 +// mod tests {
 +//     use super::*;
 +//
 +//     #[test]
 +//     fn test_name() {}
 +// }
 +// ```
 +//
 +// And the auto import completions, enabled with the `rust-analyzer.completion.autoimport.enable` setting and the corresponding LSP client capabilities.
 +// Those are the additional completion options with automatic `use` import and options from all project importable items,
 +// fuzzy matched against the completion input.
 +//
 +// image::https://user-images.githubusercontent.com/48062697/113020667-b72ab880-917a-11eb-8778-716cf26a0eb3.gif[]
 +
 +/// Main entry point for completion. We run completion as a two-phase process.
 +///
 +/// First, we look at the position and collect a so-called `CompletionContext.
 +/// This is a somewhat messy process, because, during completion, syntax tree is
 +/// incomplete and can look really weird.
 +///
 +/// Once the context is collected, we run a series of completion routines which
 +/// look at the context and produce completion items. One subtlety about this
 +/// phase is that completion engine should not filter by the substring which is
 +/// already present, it should give all possible variants for the identifier at
 +/// the caret. In other words, for
 +///
 +/// ```no_run
 +/// fn f() {
 +///     let foo = 92;
 +///     let _ = bar$0
 +/// }
 +/// ```
 +///
 +/// `foo` *should* be present among the completion variants. Filtering by
 +/// identifier prefix/fuzzy match should be done higher in the stack, together
 +/// with ordering of completions (currently this is done by the client).
 +///
 +/// # Speculative Completion Problem
 +///
 +/// There's a curious unsolved problem in the current implementation. Often, you
 +/// want to compute completions on a *slightly different* text document.
 +///
 +/// In the simplest case, when the code looks like `let x = `, you want to
 +/// insert a fake identifier to get a better syntax tree: `let x = complete_me`.
 +///
 +/// We do this in `CompletionContext`, and it works OK-enough for *syntax*
 +/// analysis. However, we might want to, eg, ask for the type of `complete_me`
 +/// variable, and that's where our current infrastructure breaks down. salsa
 +/// doesn't allow such "phantom" inputs.
 +///
 +/// Another case where this would be instrumental is macro expansion. We want to
 +/// insert a fake ident and re-expand code. There's `expand_speculative` as a
 +/// work-around for this.
 +///
 +/// A different use-case is completion of injection (examples and links in doc
 +/// comments). When computing completion for a path in a doc-comment, you want
 +/// to inject a fake path expression into the item being documented and complete
 +/// that.
 +///
 +/// IntelliJ has CodeFragment/Context infrastructure for that. You can create a
 +/// temporary PSI node, and say that the context ("parent") of this node is some
 +/// existing node. Asking for, eg, type of this `CodeFragment` node works
 +/// correctly, as the underlying infrastructure makes use of contexts to do
 +/// analysis.
 +pub fn completions(
 +    db: &RootDatabase,
 +    config: &CompletionConfig,
 +    position: FilePosition,
 +    trigger_character: Option<char>,
 +) -> Option<Vec<CompletionItem>> {
 +    let (ctx, analysis) = &CompletionContext::new(db, position, config)?;
 +    let mut completions = Completions::default();
 +
 +    // prevent `(` from triggering unwanted completion noise
 +    if trigger_character == Some('(') {
 +        if let CompletionAnalysis::NameRef(NameRefContext { kind, .. }) = &analysis {
 +            if let NameRefKind::Path(
 +                path_ctx @ PathCompletionCtx { kind: PathKind::Vis { has_in_token }, .. },
 +            ) = kind
 +            {
 +                completions::vis::complete_vis_path(&mut completions, ctx, path_ctx, has_in_token);
 +            }
 +        }
 +        // prevent `(` from triggering unwanted completion noise
 +        return Some(completions.into());
 +    }
 +
 +    {
 +        let acc = &mut completions;
 +
 +        match &analysis {
 +            CompletionAnalysis::Name(name_ctx) => completions::complete_name(acc, ctx, name_ctx),
 +            CompletionAnalysis::NameRef(name_ref_ctx) => {
 +                completions::complete_name_ref(acc, ctx, name_ref_ctx)
 +            }
 +            CompletionAnalysis::Lifetime(lifetime_ctx) => {
 +                completions::lifetime::complete_label(acc, ctx, lifetime_ctx);
 +                completions::lifetime::complete_lifetime(acc, ctx, lifetime_ctx);
 +            }
 +            CompletionAnalysis::String { original, expanded: Some(expanded) } => {
 +                completions::extern_abi::complete_extern_abi(acc, ctx, expanded);
 +                completions::format_string::format_string(acc, ctx, original, expanded);
++                completions::env_vars::complete_cargo_env_vars(acc, ctx, expanded);
 +            }
 +            CompletionAnalysis::UnexpandedAttrTT {
 +                colon_prefix,
 +                fake_attribute_under_caret: Some(attr),
 +            } => {
 +                completions::attribute::complete_known_attribute_input(
 +                    acc,
 +                    ctx,
 +                    colon_prefix,
 +                    attr,
 +                );
 +            }
 +            CompletionAnalysis::UnexpandedAttrTT { .. } | CompletionAnalysis::String { .. } => (),
 +        }
 +    }
 +
 +    Some(completions.into())
 +}
 +
 +/// Resolves additional completion data at the position given.
 +/// This is used for import insertion done via completions like flyimport and custom user snippets.
 +pub fn resolve_completion_edits(
 +    db: &RootDatabase,
 +    config: &CompletionConfig,
 +    FilePosition { file_id, offset }: FilePosition,
 +    imports: impl IntoIterator<Item = (String, String)>,
 +) -> Option<Vec<TextEdit>> {
 +    let _p = profile::span("resolve_completion_edits");
 +    let sema = hir::Semantics::new(db);
 +
 +    let original_file = sema.parse(file_id);
 +    let original_token =
 +        syntax::AstNode::syntax(&original_file).token_at_offset(offset).left_biased()?;
 +    let position_for_import = &original_token.parent()?;
 +    let scope = ImportScope::find_insert_use_container(position_for_import, &sema)?;
 +
 +    let current_module = sema.scope(position_for_import)?.module();
 +    let current_crate = current_module.krate();
 +    let new_ast = scope.clone_for_update();
 +    let mut import_insert = TextEdit::builder();
 +
 +    imports.into_iter().for_each(|(full_import_path, imported_name)| {
 +        let items_with_name = items_locator::items_with_name(
 +            &sema,
 +            current_crate,
 +            NameToImport::exact_case_sensitive(imported_name),
 +            items_locator::AssocItemSearch::Include,
 +            Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()),
 +        );
 +        let import = items_with_name
 +            .filter_map(|candidate| {
 +                current_module.find_use_path_prefixed(
 +                    db,
 +                    candidate,
 +                    config.insert_use.prefix_kind,
 +                    config.prefer_no_std,
 +                )
 +            })
 +            .find(|mod_path| mod_path.to_string() == full_import_path);
 +        if let Some(import_path) = import {
 +            insert_use::insert_use(&new_ast, mod_path_to_ast(&import_path), &config.insert_use);
 +        }
 +    });
 +
 +    algo::diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert);
 +    Some(vec![import_insert.finish()])
 +}
index 30272bc16f636754489c6838c64448ac48f8283a,0000000000000000000000000000000000000000..cf0bcd5c96b2a39e93fed07524c95246f3ff5735
mode 100644,000000..100644
--- /dev/null
@@@ -1,40 -1,0 +1,40 @@@
- once_cell = "1.12.0"
 +[package]
 +name = "ide-db"
 +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"
 +tracing = "0.1.35"
 +rayon = "1.5.3"
 +fst = { version = "0.4.7", default-features = false }
 +rustc-hash = "1.1.0"
- itertools = "0.10.3"
++once_cell = "1.15.0"
 +either = "1.7.0"
++itertools = "0.10.5"
 +arrayvec = "0.7.2"
 +indexmap = "1.9.1"
 +memchr = "2.5.0"
 +
 +stdx = { path = "../stdx", version = "0.0.0" }
 +parser = { path = "../parser", version = "0.0.0" }
 +syntax = { path = "../syntax", version = "0.0.0" }
 +text-edit = { path = "../text-edit", version = "0.0.0" }
 +base-db = { path = "../base-db", version = "0.0.0" }
 +profile = { path = "../profile", version = "0.0.0" }
 +# ide should depend only on the top-level `hir` package. if you need
 +# something from some `hir-xxx` subpackage, reexport the API via `hir`.
 +hir = { path = "../hir", version = "0.0.0" }
 +limit = { path = "../limit", version = "0.0.0" }
 +
 +[dev-dependencies]
 +test-utils = { path = "../test-utils" }
 +sourcegen = { path = "../sourcegen" }
 +xshell = "0.2.2"
 +expect-test = "1.4.0"
index f48a5700866560d7d919c33a100285ea4bf3617c,0000000000000000000000000000000000000000..2d6927cee9953c2fdd9a1a1e7cdc93d6ba2cbdfa
mode 100644,000000..100644
--- /dev/null
@@@ -1,308 -1,0 +1,308 @@@
-     AstNode, AstToken, TextRange, TextSize,
 +//! Tools to work with format string literals for the `format_args!` family of macros.
++use crate::syntax_helpers::node_ext::macro_call_for_string_token;
 +use syntax::{
 +    ast::{self, IsString},
-         let macro_call = string.syntax().parent_ancestors().find_map(ast::MacroCall::cast)?;
-         let name = macro_call.path()?.segment()?.name_ref()?;
++    TextRange, TextSize,
 +};
 +
 +pub fn is_format_string(string: &ast::String) -> bool {
 +    // Check if `string` is a format string argument of a macro invocation.
 +    // `string` is a string literal, mapped down into the innermost macro expansion.
 +    // Since `format_args!` etc. remove the format string when expanding, but place all arguments
 +    // in the expanded output, we know that the string token is (part of) the format string if it
 +    // appears in `format_args!` (otherwise it would have been mapped down further).
 +    //
 +    // This setup lets us correctly highlight the components of `concat!("{}", "bla")` format
 +    // strings. It still fails for `concat!("{", "}")`, but that is rare.
 +    (|| {
++        let name = macro_call_for_string_token(string)?.path()?.segment()?.name_ref()?;
 +
 +        if !matches!(
 +            name.text().as_str(),
 +            "format_args" | "format_args_nl" | "const_format_args" | "panic_2015" | "panic_2021"
 +        ) {
 +            return None;
 +        }
 +
 +        // NB: we match against `panic_2015`/`panic_2021` here because they have a special-cased arm for
 +        // `"{}"`, which otherwise wouldn't get highlighted.
 +
 +        Some(())
 +    })()
 +    .is_some()
 +}
 +
 +#[derive(Debug)]
 +pub enum FormatSpecifier {
 +    Open,
 +    Close,
 +    Integer,
 +    Identifier,
 +    Colon,
 +    Fill,
 +    Align,
 +    Sign,
 +    NumberSign,
 +    Zero,
 +    DollarSign,
 +    Dot,
 +    Asterisk,
 +    QuestionMark,
 +    Escape,
 +}
 +
 +pub fn lex_format_specifiers(
 +    string: &ast::String,
 +    mut callback: &mut dyn FnMut(TextRange, FormatSpecifier),
 +) {
 +    let mut char_ranges = Vec::new();
 +    string.escaped_char_ranges(&mut |range, res| char_ranges.push((range, res)));
 +    let mut chars = char_ranges
 +        .iter()
 +        .filter_map(|(range, res)| Some((*range, *res.as_ref().ok()?)))
 +        .peekable();
 +
 +    while let Some((range, first_char)) = chars.next() {
 +        if let '{' = first_char {
 +            // Format specifier, see syntax at https://doc.rust-lang.org/std/fmt/index.html#syntax
 +            if let Some((_, '{')) = chars.peek() {
 +                // Escaped format specifier, `{{`
 +                read_escaped_format_specifier(&mut chars, &mut callback);
 +                continue;
 +            }
 +
 +            callback(range, FormatSpecifier::Open);
 +
 +            // check for integer/identifier
 +            let (_, int_char) = chars.peek().copied().unwrap_or_default();
 +            match int_char {
 +                // integer
 +                '0'..='9' => read_integer(&mut chars, &mut callback),
 +                // identifier
 +                c if c == '_' || c.is_alphabetic() => read_identifier(&mut chars, &mut callback),
 +                _ => {}
 +            }
 +
 +            if let Some((_, ':')) = chars.peek() {
 +                skip_char_and_emit(&mut chars, FormatSpecifier::Colon, &mut callback);
 +
 +                // check for fill/align
 +                let mut cloned = chars.clone().take(2);
 +                let (_, first) = cloned.next().unwrap_or_default();
 +                let (_, second) = cloned.next().unwrap_or_default();
 +                match second {
 +                    '<' | '^' | '>' => {
 +                        // alignment specifier, first char specifies fillment
 +                        skip_char_and_emit(&mut chars, FormatSpecifier::Fill, &mut callback);
 +                        skip_char_and_emit(&mut chars, FormatSpecifier::Align, &mut callback);
 +                    }
 +                    _ => {
 +                        if let '<' | '^' | '>' = first {
 +                            skip_char_and_emit(&mut chars, FormatSpecifier::Align, &mut callback);
 +                        }
 +                    }
 +                }
 +
 +                // check for sign
 +                match chars.peek().copied().unwrap_or_default().1 {
 +                    '+' | '-' => {
 +                        skip_char_and_emit(&mut chars, FormatSpecifier::Sign, &mut callback);
 +                    }
 +                    _ => {}
 +                }
 +
 +                // check for `#`
 +                if let Some((_, '#')) = chars.peek() {
 +                    skip_char_and_emit(&mut chars, FormatSpecifier::NumberSign, &mut callback);
 +                }
 +
 +                // check for `0`
 +                let mut cloned = chars.clone().take(2);
 +                let first = cloned.next().map(|next| next.1);
 +                let second = cloned.next().map(|next| next.1);
 +
 +                if first == Some('0') && second != Some('$') {
 +                    skip_char_and_emit(&mut chars, FormatSpecifier::Zero, &mut callback);
 +                }
 +
 +                // width
 +                match chars.peek().copied().unwrap_or_default().1 {
 +                    '0'..='9' => {
 +                        read_integer(&mut chars, &mut callback);
 +                        if let Some((_, '$')) = chars.peek() {
 +                            skip_char_and_emit(
 +                                &mut chars,
 +                                FormatSpecifier::DollarSign,
 +                                &mut callback,
 +                            );
 +                        }
 +                    }
 +                    c if c == '_' || c.is_alphabetic() => {
 +                        read_identifier(&mut chars, &mut callback);
 +
 +                        if chars.peek().map(|&(_, c)| c) == Some('?') {
 +                            skip_char_and_emit(
 +                                &mut chars,
 +                                FormatSpecifier::QuestionMark,
 +                                &mut callback,
 +                            );
 +                        }
 +
 +                        // can be either width (indicated by dollar sign, or type in which case
 +                        // the next sign has to be `}`)
 +                        let next = chars.peek().map(|&(_, c)| c);
 +
 +                        match next {
 +                            Some('$') => skip_char_and_emit(
 +                                &mut chars,
 +                                FormatSpecifier::DollarSign,
 +                                &mut callback,
 +                            ),
 +                            Some('}') => {
 +                                skip_char_and_emit(
 +                                    &mut chars,
 +                                    FormatSpecifier::Close,
 +                                    &mut callback,
 +                                );
 +                                continue;
 +                            }
 +                            _ => continue,
 +                        };
 +                    }
 +                    _ => {}
 +                }
 +
 +                // precision
 +                if let Some((_, '.')) = chars.peek() {
 +                    skip_char_and_emit(&mut chars, FormatSpecifier::Dot, &mut callback);
 +
 +                    match chars.peek().copied().unwrap_or_default().1 {
 +                        '*' => {
 +                            skip_char_and_emit(
 +                                &mut chars,
 +                                FormatSpecifier::Asterisk,
 +                                &mut callback,
 +                            );
 +                        }
 +                        '0'..='9' => {
 +                            read_integer(&mut chars, &mut callback);
 +                            if let Some((_, '$')) = chars.peek() {
 +                                skip_char_and_emit(
 +                                    &mut chars,
 +                                    FormatSpecifier::DollarSign,
 +                                    &mut callback,
 +                                );
 +                            }
 +                        }
 +                        c if c == '_' || c.is_alphabetic() => {
 +                            read_identifier(&mut chars, &mut callback);
 +                            if chars.peek().map(|&(_, c)| c) != Some('$') {
 +                                continue;
 +                            }
 +                            skip_char_and_emit(
 +                                &mut chars,
 +                                FormatSpecifier::DollarSign,
 +                                &mut callback,
 +                            );
 +                        }
 +                        _ => {
 +                            continue;
 +                        }
 +                    }
 +                }
 +
 +                // type
 +                match chars.peek().copied().unwrap_or_default().1 {
 +                    '?' => {
 +                        skip_char_and_emit(
 +                            &mut chars,
 +                            FormatSpecifier::QuestionMark,
 +                            &mut callback,
 +                        );
 +                    }
 +                    c if c == '_' || c.is_alphabetic() => {
 +                        read_identifier(&mut chars, &mut callback);
 +
 +                        if chars.peek().map(|&(_, c)| c) == Some('?') {
 +                            skip_char_and_emit(
 +                                &mut chars,
 +                                FormatSpecifier::QuestionMark,
 +                                &mut callback,
 +                            );
 +                        }
 +                    }
 +                    _ => {}
 +                }
 +            }
 +
 +            if let Some((_, '}')) = chars.peek() {
 +                skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback);
 +            }
 +            continue;
 +        } else if let '}' = first_char {
 +            if let Some((_, '}')) = chars.peek() {
 +                // Escaped format specifier, `}}`
 +                read_escaped_format_specifier(&mut chars, &mut callback);
 +            }
 +        }
 +    }
 +
 +    fn skip_char_and_emit<I, F>(
 +        chars: &mut std::iter::Peekable<I>,
 +        emit: FormatSpecifier,
 +        callback: &mut F,
 +    ) where
 +        I: Iterator<Item = (TextRange, char)>,
 +        F: FnMut(TextRange, FormatSpecifier),
 +    {
 +        let (range, _) = chars.next().unwrap();
 +        callback(range, emit);
 +    }
 +
 +    fn read_integer<I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
 +    where
 +        I: Iterator<Item = (TextRange, char)>,
 +        F: FnMut(TextRange, FormatSpecifier),
 +    {
 +        let (mut range, c) = chars.next().unwrap();
 +        assert!(c.is_ascii_digit());
 +        while let Some(&(r, next_char)) = chars.peek() {
 +            if next_char.is_ascii_digit() {
 +                chars.next();
 +                range = range.cover(r);
 +            } else {
 +                break;
 +            }
 +        }
 +        callback(range, FormatSpecifier::Integer);
 +    }
 +
 +    fn read_identifier<I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
 +    where
 +        I: Iterator<Item = (TextRange, char)>,
 +        F: FnMut(TextRange, FormatSpecifier),
 +    {
 +        let (mut range, c) = chars.next().unwrap();
 +        assert!(c.is_alphabetic() || c == '_');
 +        while let Some(&(r, next_char)) = chars.peek() {
 +            if next_char == '_' || next_char.is_ascii_digit() || next_char.is_alphabetic() {
 +                chars.next();
 +                range = range.cover(r);
 +            } else {
 +                break;
 +            }
 +        }
 +        callback(range, FormatSpecifier::Identifier);
 +    }
 +
 +    fn read_escaped_format_specifier<I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
 +    where
 +        I: Iterator<Item = (TextRange, char)>,
 +        F: FnMut(TextRange, FormatSpecifier),
 +    {
 +        let (range, _) = chars.peek().unwrap();
 +        let offset = TextSize::from(1);
 +        callback(TextRange::new(range.start() - offset, range.end()), FormatSpecifier::Escape);
 +        chars.next();
 +    }
 +}
index b890e2b58df8f2688923c1262665e7361a747881,0000000000000000000000000000000000000000..39710b8f13eb5f7024b8fe2a385ead1badda3a21
mode 100644,000000..100644
--- /dev/null
@@@ -1,459 -1,0 +1,464 @@@
-     ast::{self, HasLoopBody, PathSegmentKind, VisibilityKind},
-     AstNode, Preorder, RustLanguage, WalkEvent,
 +//! Various helper functions to work with SyntaxNodes.
 +use itertools::Itertools;
 +use parser::T;
 +use syntax::{
++    ast::{self, HasLoopBody, MacroCall, PathSegmentKind, VisibilityKind},
++    AstNode, AstToken, Preorder, RustLanguage, WalkEvent,
 +};
 +
 +pub fn expr_as_name_ref(expr: &ast::Expr) -> Option<ast::NameRef> {
 +    if let ast::Expr::PathExpr(expr) = expr {
 +        let path = expr.path()?;
 +        path.as_single_name_ref()
 +    } else {
 +        None
 +    }
 +}
 +
 +pub fn full_path_of_name_ref(name_ref: &ast::NameRef) -> Option<ast::Path> {
 +    let mut ancestors = name_ref.syntax().ancestors();
 +    let _ = ancestors.next()?; // skip self
 +    let _ = ancestors.next().filter(|it| ast::PathSegment::can_cast(it.kind()))?; // skip self
 +    ancestors.take_while(|it| ast::Path::can_cast(it.kind())).last().and_then(ast::Path::cast)
 +}
 +
 +pub fn block_as_lone_tail(block: &ast::BlockExpr) -> Option<ast::Expr> {
 +    block.statements().next().is_none().then(|| block.tail_expr()).flatten()
 +}
 +
 +/// Preorder walk all the expression's child expressions.
 +pub fn walk_expr(expr: &ast::Expr, cb: &mut dyn FnMut(ast::Expr)) {
 +    preorder_expr(expr, &mut |ev| {
 +        if let WalkEvent::Enter(expr) = ev {
 +            cb(expr);
 +        }
 +        false
 +    })
 +}
 +
 +/// Preorder walk all the expression's child expressions preserving events.
 +/// If the callback returns true on an [`WalkEvent::Enter`], the subtree of the expression will be skipped.
 +/// Note that the subtree may already be skipped due to the context analysis this function does.
 +pub fn preorder_expr(start: &ast::Expr, cb: &mut dyn FnMut(WalkEvent<ast::Expr>) -> bool) {
 +    let mut preorder = start.syntax().preorder();
 +    while let Some(event) = preorder.next() {
 +        let node = match event {
 +            WalkEvent::Enter(node) => node,
 +            WalkEvent::Leave(node) => {
 +                if let Some(expr) = ast::Expr::cast(node) {
 +                    cb(WalkEvent::Leave(expr));
 +                }
 +                continue;
 +            }
 +        };
 +        if let Some(let_stmt) = node.parent().and_then(ast::LetStmt::cast) {
 +            if Some(node.clone()) != let_stmt.initializer().map(|it| it.syntax().clone()) {
 +                // skipping potential const pat expressions in  let statements
 +                preorder.skip_subtree();
 +                continue;
 +            }
 +        }
 +
 +        match ast::Stmt::cast(node.clone()) {
 +            // Don't skip subtree since we want to process the expression child next
 +            Some(ast::Stmt::ExprStmt(_)) | Some(ast::Stmt::LetStmt(_)) => (),
 +            // skip inner items which might have their own expressions
 +            Some(ast::Stmt::Item(_)) => preorder.skip_subtree(),
 +            None => {
 +                // skip const args, those expressions are a different context
 +                if ast::GenericArg::can_cast(node.kind()) {
 +                    preorder.skip_subtree();
 +                } else if let Some(expr) = ast::Expr::cast(node) {
 +                    let is_different_context = match &expr {
 +                        ast::Expr::BlockExpr(block_expr) => {
 +                            matches!(
 +                                block_expr.modifier(),
 +                                Some(
 +                                    ast::BlockModifier::Async(_)
 +                                        | ast::BlockModifier::Try(_)
 +                                        | ast::BlockModifier::Const(_)
 +                                )
 +                            )
 +                        }
 +                        ast::Expr::ClosureExpr(_) => true,
 +                        _ => false,
 +                    } && expr.syntax() != start.syntax();
 +                    let skip = cb(WalkEvent::Enter(expr));
 +                    if skip || is_different_context {
 +                        preorder.skip_subtree();
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +/// Preorder walk all the expression's child patterns.
 +pub fn walk_patterns_in_expr(start: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) {
 +    let mut preorder = start.syntax().preorder();
 +    while let Some(event) = preorder.next() {
 +        let node = match event {
 +            WalkEvent::Enter(node) => node,
 +            WalkEvent::Leave(_) => continue,
 +        };
 +        match ast::Stmt::cast(node.clone()) {
 +            Some(ast::Stmt::LetStmt(l)) => {
 +                if let Some(pat) = l.pat() {
 +                    walk_pat(&pat, cb);
 +                }
 +                if let Some(expr) = l.initializer() {
 +                    walk_patterns_in_expr(&expr, cb);
 +                }
 +                preorder.skip_subtree();
 +            }
 +            // Don't skip subtree since we want to process the expression child next
 +            Some(ast::Stmt::ExprStmt(_)) => (),
 +            // skip inner items which might have their own patterns
 +            Some(ast::Stmt::Item(_)) => preorder.skip_subtree(),
 +            None => {
 +                // skip const args, those are a different context
 +                if ast::GenericArg::can_cast(node.kind()) {
 +                    preorder.skip_subtree();
 +                } else if let Some(expr) = ast::Expr::cast(node.clone()) {
 +                    let is_different_context = match &expr {
 +                        ast::Expr::BlockExpr(block_expr) => {
 +                            matches!(
 +                                block_expr.modifier(),
 +                                Some(
 +                                    ast::BlockModifier::Async(_)
 +                                        | ast::BlockModifier::Try(_)
 +                                        | ast::BlockModifier::Const(_)
 +                                )
 +                            )
 +                        }
 +                        ast::Expr::ClosureExpr(_) => true,
 +                        _ => false,
 +                    } && expr.syntax() != start.syntax();
 +                    if is_different_context {
 +                        preorder.skip_subtree();
 +                    }
 +                } else if let Some(pat) = ast::Pat::cast(node) {
 +                    preorder.skip_subtree();
 +                    walk_pat(&pat, cb);
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +/// Preorder walk all the pattern's sub patterns.
 +pub fn walk_pat(pat: &ast::Pat, cb: &mut dyn FnMut(ast::Pat)) {
 +    let mut preorder = pat.syntax().preorder();
 +    while let Some(event) = preorder.next() {
 +        let node = match event {
 +            WalkEvent::Enter(node) => node,
 +            WalkEvent::Leave(_) => continue,
 +        };
 +        let kind = node.kind();
 +        match ast::Pat::cast(node) {
 +            Some(pat @ ast::Pat::ConstBlockPat(_)) => {
 +                preorder.skip_subtree();
 +                cb(pat);
 +            }
 +            Some(pat) => {
 +                cb(pat);
 +            }
 +            // skip const args
 +            None if ast::GenericArg::can_cast(kind) => {
 +                preorder.skip_subtree();
 +            }
 +            None => (),
 +        }
 +    }
 +}
 +
 +/// Preorder walk all the type's sub types.
 +pub fn walk_ty(ty: &ast::Type, cb: &mut dyn FnMut(ast::Type)) {
 +    let mut preorder = ty.syntax().preorder();
 +    while let Some(event) = preorder.next() {
 +        let node = match event {
 +            WalkEvent::Enter(node) => node,
 +            WalkEvent::Leave(_) => continue,
 +        };
 +        let kind = node.kind();
 +        match ast::Type::cast(node) {
 +            Some(ty @ ast::Type::MacroType(_)) => {
 +                preorder.skip_subtree();
 +                cb(ty)
 +            }
 +            Some(ty) => {
 +                cb(ty);
 +            }
 +            // skip const args
 +            None if ast::ConstArg::can_cast(kind) => {
 +                preorder.skip_subtree();
 +            }
 +            None => (),
 +        }
 +    }
 +}
 +
 +pub fn vis_eq(this: &ast::Visibility, other: &ast::Visibility) -> bool {
 +    match (this.kind(), other.kind()) {
 +        (VisibilityKind::In(this), VisibilityKind::In(other)) => {
 +            stdx::iter_eq_by(this.segments(), other.segments(), |lhs, rhs| {
 +                lhs.kind().zip(rhs.kind()).map_or(false, |it| match it {
 +                    (PathSegmentKind::CrateKw, PathSegmentKind::CrateKw)
 +                    | (PathSegmentKind::SelfKw, PathSegmentKind::SelfKw)
 +                    | (PathSegmentKind::SuperKw, PathSegmentKind::SuperKw) => true,
 +                    (PathSegmentKind::Name(lhs), PathSegmentKind::Name(rhs)) => {
 +                        lhs.text() == rhs.text()
 +                    }
 +                    _ => false,
 +                })
 +            })
 +        }
 +        (VisibilityKind::PubSelf, VisibilityKind::PubSelf)
 +        | (VisibilityKind::PubSuper, VisibilityKind::PubSuper)
 +        | (VisibilityKind::PubCrate, VisibilityKind::PubCrate)
 +        | (VisibilityKind::Pub, VisibilityKind::Pub) => true,
 +        _ => false,
 +    }
 +}
 +
 +/// Returns the `let` only if there is exactly one (that is, `let pat = expr`
 +/// or `((let pat = expr))`, but not `let pat = expr && expr` or `non_let_expr`).
 +pub fn single_let(expr: ast::Expr) -> Option<ast::LetExpr> {
 +    match expr {
 +        ast::Expr::ParenExpr(expr) => expr.expr().and_then(single_let),
 +        ast::Expr::LetExpr(expr) => Some(expr),
 +        _ => None,
 +    }
 +}
 +
 +pub fn is_pattern_cond(expr: ast::Expr) -> bool {
 +    match expr {
 +        ast::Expr::BinExpr(expr)
 +            if expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And)) =>
 +        {
 +            expr.lhs()
 +                .map(is_pattern_cond)
 +                .or_else(|| expr.rhs().map(is_pattern_cond))
 +                .unwrap_or(false)
 +        }
 +        ast::Expr::ParenExpr(expr) => expr.expr().map_or(false, is_pattern_cond),
 +        ast::Expr::LetExpr(_) => true,
 +        _ => false,
 +    }
 +}
 +
 +/// Calls `cb` on each expression inside `expr` that is at "tail position".
 +/// Does not walk into `break` or `return` expressions.
 +/// Note that modifying the tree while iterating it will cause undefined iteration which might
 +/// potentially results in an out of bounds panic.
 +pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
 +    match expr {
 +        ast::Expr::BlockExpr(b) => {
 +            match b.modifier() {
 +                Some(
 +                    ast::BlockModifier::Async(_)
 +                    | ast::BlockModifier::Try(_)
 +                    | ast::BlockModifier::Const(_),
 +                ) => return cb(expr),
 +
 +                Some(ast::BlockModifier::Label(label)) => {
 +                    for_each_break_expr(Some(label), b.stmt_list(), &mut |b| {
 +                        cb(&ast::Expr::BreakExpr(b))
 +                    });
 +                }
 +                Some(ast::BlockModifier::Unsafe(_)) => (),
 +                None => (),
 +            }
 +            if let Some(stmt_list) = b.stmt_list() {
 +                if let Some(e) = stmt_list.tail_expr() {
 +                    for_each_tail_expr(&e, cb);
 +                }
 +            }
 +        }
 +        ast::Expr::IfExpr(if_) => {
 +            let mut if_ = if_.clone();
 +            loop {
 +                if let Some(block) = if_.then_branch() {
 +                    for_each_tail_expr(&ast::Expr::BlockExpr(block), cb);
 +                }
 +                match if_.else_branch() {
 +                    Some(ast::ElseBranch::IfExpr(it)) => if_ = it,
 +                    Some(ast::ElseBranch::Block(block)) => {
 +                        for_each_tail_expr(&ast::Expr::BlockExpr(block), cb);
 +                        break;
 +                    }
 +                    None => break,
 +                }
 +            }
 +        }
 +        ast::Expr::LoopExpr(l) => {
 +            for_each_break_expr(l.label(), l.loop_body().and_then(|it| it.stmt_list()), &mut |b| {
 +                cb(&ast::Expr::BreakExpr(b))
 +            })
 +        }
 +        ast::Expr::MatchExpr(m) => {
 +            if let Some(arms) = m.match_arm_list() {
 +                arms.arms().filter_map(|arm| arm.expr()).for_each(|e| for_each_tail_expr(&e, cb));
 +            }
 +        }
 +        ast::Expr::ArrayExpr(_)
 +        | ast::Expr::AwaitExpr(_)
 +        | ast::Expr::BinExpr(_)
 +        | ast::Expr::BoxExpr(_)
 +        | ast::Expr::BreakExpr(_)
 +        | ast::Expr::CallExpr(_)
 +        | ast::Expr::CastExpr(_)
 +        | ast::Expr::ClosureExpr(_)
 +        | ast::Expr::ContinueExpr(_)
 +        | ast::Expr::FieldExpr(_)
 +        | ast::Expr::ForExpr(_)
 +        | ast::Expr::IndexExpr(_)
 +        | ast::Expr::Literal(_)
 +        | ast::Expr::MacroExpr(_)
 +        | ast::Expr::MethodCallExpr(_)
 +        | ast::Expr::ParenExpr(_)
 +        | ast::Expr::PathExpr(_)
 +        | ast::Expr::PrefixExpr(_)
 +        | ast::Expr::RangeExpr(_)
 +        | ast::Expr::RecordExpr(_)
 +        | ast::Expr::RefExpr(_)
 +        | ast::Expr::ReturnExpr(_)
 +        | ast::Expr::TryExpr(_)
 +        | ast::Expr::TupleExpr(_)
 +        | ast::Expr::WhileExpr(_)
 +        | ast::Expr::LetExpr(_)
 +        | ast::Expr::UnderscoreExpr(_)
 +        | ast::Expr::YieldExpr(_) => cb(expr),
 +    }
 +}
 +
 +pub fn for_each_break_and_continue_expr(
 +    label: Option<ast::Label>,
 +    body: Option<ast::StmtList>,
 +    cb: &mut dyn FnMut(ast::Expr),
 +) {
 +    let label = label.and_then(|lbl| lbl.lifetime());
 +    if let Some(b) = body {
 +        let tree_depth_iterator = TreeWithDepthIterator::new(b);
 +        for (expr, depth) in tree_depth_iterator {
 +            match expr {
 +                ast::Expr::BreakExpr(b)
 +                    if (depth == 0 && b.lifetime().is_none())
 +                        || eq_label_lt(&label, &b.lifetime()) =>
 +                {
 +                    cb(ast::Expr::BreakExpr(b));
 +                }
 +                ast::Expr::ContinueExpr(c)
 +                    if (depth == 0 && c.lifetime().is_none())
 +                        || eq_label_lt(&label, &c.lifetime()) =>
 +                {
 +                    cb(ast::Expr::ContinueExpr(c));
 +                }
 +                _ => (),
 +            }
 +        }
 +    }
 +}
 +
 +fn for_each_break_expr(
 +    label: Option<ast::Label>,
 +    body: Option<ast::StmtList>,
 +    cb: &mut dyn FnMut(ast::BreakExpr),
 +) {
 +    let label = label.and_then(|lbl| lbl.lifetime());
 +    if let Some(b) = body {
 +        let tree_depth_iterator = TreeWithDepthIterator::new(b);
 +        for (expr, depth) in tree_depth_iterator {
 +            match expr {
 +                ast::Expr::BreakExpr(b)
 +                    if (depth == 0 && b.lifetime().is_none())
 +                        || eq_label_lt(&label, &b.lifetime()) =>
 +                {
 +                    cb(b);
 +                }
 +                _ => (),
 +            }
 +        }
 +    }
 +}
 +
 +fn eq_label_lt(lt1: &Option<ast::Lifetime>, lt2: &Option<ast::Lifetime>) -> bool {
 +    lt1.as_ref().zip(lt2.as_ref()).map_or(false, |(lt, lbl)| lt.text() == lbl.text())
 +}
 +
 +struct TreeWithDepthIterator {
 +    preorder: Preorder<RustLanguage>,
 +    depth: u32,
 +}
 +
 +impl TreeWithDepthIterator {
 +    fn new(body: ast::StmtList) -> Self {
 +        let preorder = body.syntax().preorder();
 +        Self { preorder, depth: 0 }
 +    }
 +}
 +
 +impl Iterator for TreeWithDepthIterator {
 +    type Item = (ast::Expr, u32);
 +
 +    fn next(&mut self) -> Option<Self::Item> {
 +        while let Some(event) = self.preorder.find_map(|ev| match ev {
 +            WalkEvent::Enter(it) => ast::Expr::cast(it).map(WalkEvent::Enter),
 +            WalkEvent::Leave(it) => ast::Expr::cast(it).map(WalkEvent::Leave),
 +        }) {
 +            match event {
 +                WalkEvent::Enter(
 +                    ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_),
 +                ) => {
 +                    self.depth += 1;
 +                }
 +                WalkEvent::Leave(
 +                    ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_),
 +                ) => {
 +                    self.depth -= 1;
 +                }
 +                WalkEvent::Enter(ast::Expr::BlockExpr(e)) if e.label().is_some() => {
 +                    self.depth += 1;
 +                }
 +                WalkEvent::Leave(ast::Expr::BlockExpr(e)) if e.label().is_some() => {
 +                    self.depth -= 1;
 +                }
 +                WalkEvent::Enter(expr) => return Some((expr, self.depth)),
 +                _ => (),
 +            }
 +        }
 +        None
 +    }
 +}
 +
 +/// Parses the input token tree as comma separated plain paths.
 +pub fn parse_tt_as_comma_sep_paths(input: ast::TokenTree) -> Option<Vec<ast::Path>> {
 +    let r_paren = input.r_paren_token();
 +    let tokens =
 +        input.syntax().children_with_tokens().skip(1).map_while(|it| match it.into_token() {
 +            // seeing a keyword means the attribute is unclosed so stop parsing here
 +            Some(tok) if tok.kind().is_keyword() => None,
 +            // don't include the right token tree parenthesis if it exists
 +            tok @ Some(_) if tok == r_paren => None,
 +            // only nodes that we can find are other TokenTrees, those are unexpected in this parse though
 +            None => None,
 +            Some(tok) => Some(tok),
 +        });
 +    let input_expressions = tokens.group_by(|tok| tok.kind() == T![,]);
 +    let paths = input_expressions
 +        .into_iter()
 +        .filter_map(|(is_sep, group)| (!is_sep).then(|| group))
 +        .filter_map(|mut tokens| {
 +            syntax::hacks::parse_expr_from_str(&tokens.join("")).and_then(|expr| match expr {
 +                ast::Expr::PathExpr(it) => it.path(),
 +                _ => None,
 +            })
 +        })
 +        .collect();
 +    Some(paths)
 +}
++
++pub fn macro_call_for_string_token(string: &ast::String) -> Option<MacroCall> {
++    let macro_call = string.syntax().parent_ancestors().find_map(ast::MacroCall::cast)?;
++    Some(macro_call)
++}
index 9b9e21a4ddb592d3519a6e2778e9ac6da003e257,0000000000000000000000000000000000000000..e1d146f4ee561f368c7125ee3330d742394ed4e5
mode 100644,000000..100644
--- /dev/null
@@@ -1,35 -1,0 +1,33 @@@
- itertools = "0.10.3"
 +[package]
 +name = "ide-diagnostics"
 +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"
- serde_json = "1.0.82"
 +either = "1.7.0"
++itertools = "0.10.5"
++serde_json = "1.0.86"
 +
 +profile = { path = "../profile", version = "0.0.0" }
 +stdx = { path = "../stdx", version = "0.0.0" }
 +syntax = { path = "../syntax", version = "0.0.0" }
 +text-edit = { path = "../text-edit", version = "0.0.0" }
 +cfg = { path = "../cfg", version = "0.0.0" }
 +hir = { path = "../hir", version = "0.0.0" }
 +ide-db = { path = "../ide-db", version = "0.0.0" }
 +
 +[dev-dependencies]
 +expect-test = "1.4.0"
 +
 +test-utils = { path = "../test-utils" }
 +sourcegen = { path = "../sourcegen" }
 +
 +[features]
 +in-rust-tree = []
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..085d8d32598a1301acb9f96512d1f9d7e71a008b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,37 @@@
++use hir::InFile;
++
++use crate::{Diagnostic, DiagnosticsContext};
++
++// Diagnostic: incorrect-try-target
++//
++// This diagnostic is triggered if a question mark operator was used in a context where it is not applicable.
++pub(crate) fn incorrect_try_expr(
++    ctx: &DiagnosticsContext<'_>,
++    d: &hir::IncorrectTryExpr,
++) -> Diagnostic {
++    Diagnostic::new(
++        "incorrect-try-target",
++        format!("the return type of the containing function does not implement `FromResidual`"),
++        ctx.sema
++            .diagnostics_display_range(InFile::new(d.expr.file_id, d.expr.value.clone().into()))
++            .range,
++    )
++}
++
++#[cfg(test)]
++mod tests {
++    use crate::tests::check_diagnostics;
++
++    #[test]
++    fn try_ops_diag() {
++        check_diagnostics(
++            r#"
++//- minicore: try
++fn test() {
++    core::ops::ControlFlow::<u32, f32>::Continue(1.0)?;
++ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the return type of the containing function does not implement `FromResidual`
++}
++"#,
++        );
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3bf6a4232298c7884a69c2ccd072f3483ed554c5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,35 @@@
++use hir::{db::DefDatabase, HirDisplay};
++
++use crate::{Diagnostic, DiagnosticsContext};
++
++// Diagnostic: not-implemented
++//
++// This diagnostic is triggered if a type doesn't implement a necessary trait.
++pub(crate) fn not_implemented(ctx: &DiagnosticsContext<'_>, d: &hir::NotImplemented) -> Diagnostic {
++    Diagnostic::new(
++        "not-implemented",
++        format!(
++            "the trait `{}` is not implemented for `{}`",
++            ctx.sema.db.trait_data(d.trait_).name,
++            d.ty.display(ctx.sema.db)
++        ),
++        ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
++    )
++}
++
++#[cfg(test)]
++mod tests {
++    use crate::tests::check_diagnostics;
++
++    #[test]
++    fn missing_try_impl() {
++        check_diagnostics(
++            r#"
++//- minicore: try
++fn main() {
++    ()?;
++} //^^ error: the trait `Try` is not implemented for `()`
++"#,
++        )
++    }
++}
index ae299f0584148937c64b897e7cf658359a5c7069,0000000000000000000000000000000000000000..4577072149a72d7b6d3a0d64f391f1bc5ef6404d
mode 100644,000000..100644
--- /dev/null
@@@ -1,291 -1,0 +1,295 @@@
 +//! Diagnostics rendering and fixits.
 +//!
 +//! Most of the diagnostics originate from the dark depth of the compiler, and
 +//! are originally expressed in term of IR. When we emit the diagnostic, we are
 +//! usually not in the position to decide how to best "render" it in terms of
 +//! user-authored source code. We are especially not in the position to offer
 +//! fixits, as the compiler completely lacks the infrastructure to edit the
 +//! source code.
 +//!
 +//! Instead, we "bubble up" raw, structured diagnostics until the `hir` crate,
 +//! where we "cook" them so that each diagnostic is formulated in terms of `hir`
 +//! types. Well, at least that's the aspiration, the "cooking" is somewhat
 +//! ad-hoc at the moment. Anyways, we get a bunch of ide-friendly diagnostic
 +//! structs from hir, and we want to render them to unified serializable
 +//! representation (span, level, message) here. If we can, we also provide
 +//! fixits. By the way, that's why we want to keep diagnostics structured
 +//! internally -- so that we have all the info to make fixes.
 +//!
 +//! We have one "handler" module per diagnostic code. Such a module contains
 +//! rendering, optional fixes and tests. It's OK if some low-level compiler
 +//! functionality ends up being tested via a diagnostic.
 +//!
 +//! There are also a couple of ad-hoc diagnostics implemented directly here, we
 +//! don't yet have a great pattern for how to do them properly.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +mod handlers {
 +    pub(crate) mod break_outside_of_loop;
 +    pub(crate) mod inactive_code;
 +    pub(crate) mod incorrect_case;
++    pub(crate) mod incorrect_try_expr;
 +    pub(crate) mod invalid_derive_target;
 +    pub(crate) mod macro_error;
 +    pub(crate) mod malformed_derive;
 +    pub(crate) mod mismatched_arg_count;
 +    pub(crate) mod missing_fields;
 +    pub(crate) mod missing_match_arms;
 +    pub(crate) mod missing_unsafe;
++    pub(crate) mod not_implemented;
 +    pub(crate) mod no_such_field;
 +    pub(crate) mod replace_filter_map_next_with_find_map;
 +    pub(crate) mod type_mismatch;
 +    pub(crate) mod unimplemented_builtin_macro;
 +    pub(crate) mod unresolved_extern_crate;
 +    pub(crate) mod unresolved_import;
 +    pub(crate) mod unresolved_macro_call;
 +    pub(crate) mod unresolved_module;
 +    pub(crate) mod unresolved_proc_macro;
 +
 +    // The handlers below are unusual, the implement the diagnostics as well.
 +    pub(crate) mod field_shorthand;
 +    pub(crate) mod useless_braces;
 +    pub(crate) mod unlinked_file;
 +    pub(crate) mod json_is_not_rust;
 +}
 +
 +#[cfg(test)]
 +mod tests;
 +
 +use hir::{diagnostics::AnyDiagnostic, InFile, Semantics};
 +use ide_db::{
 +    assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
 +    base_db::{FileId, FileRange, SourceDatabase},
 +    imports::insert_use::InsertUseConfig,
 +    label::Label,
 +    source_change::SourceChange,
 +    FxHashSet, RootDatabase,
 +};
 +use syntax::{algo::find_node_at_range, ast::AstNode, SyntaxNodePtr, TextRange};
 +
 +#[derive(Copy, Clone, Debug, PartialEq)]
 +pub struct DiagnosticCode(pub &'static str);
 +
 +impl DiagnosticCode {
 +    pub fn as_str(&self) -> &str {
 +        self.0
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub struct Diagnostic {
 +    pub code: DiagnosticCode,
 +    pub message: String,
 +    pub range: TextRange,
 +    pub severity: Severity,
 +    pub unused: bool,
 +    pub experimental: bool,
 +    pub fixes: Option<Vec<Assist>>,
 +}
 +
 +impl Diagnostic {
 +    fn new(code: &'static str, message: impl Into<String>, range: TextRange) -> Diagnostic {
 +        let message = message.into();
 +        Diagnostic {
 +            code: DiagnosticCode(code),
 +            message,
 +            range,
 +            severity: Severity::Error,
 +            unused: false,
 +            experimental: false,
 +            fixes: None,
 +        }
 +    }
 +
 +    fn experimental(mut self) -> Diagnostic {
 +        self.experimental = true;
 +        self
 +    }
 +
 +    fn severity(mut self, severity: Severity) -> Diagnostic {
 +        self.severity = severity;
 +        self
 +    }
 +
 +    fn with_fixes(mut self, fixes: Option<Vec<Assist>>) -> Diagnostic {
 +        self.fixes = fixes;
 +        self
 +    }
 +
 +    fn with_unused(mut self, unused: bool) -> Diagnostic {
 +        self.unused = unused;
 +        self
 +    }
 +}
 +
 +#[derive(Debug, Copy, Clone)]
 +pub enum Severity {
 +    Error,
 +    // We don't actually emit this one yet, but we should at some point.
 +    // Warning,
 +    WeakWarning,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum ExprFillDefaultMode {
 +    Todo,
 +    Default,
 +}
 +impl Default for ExprFillDefaultMode {
 +    fn default() -> Self {
 +        Self::Todo
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +pub struct DiagnosticsConfig {
 +    pub proc_macros_enabled: bool,
 +    pub proc_attr_macros_enabled: bool,
 +    pub disable_experimental: bool,
 +    pub disabled: FxHashSet<String>,
 +    pub expr_fill_default: ExprFillDefaultMode,
 +    // FIXME: We may want to include a whole `AssistConfig` here
 +    pub insert_use: InsertUseConfig,
 +    pub prefer_no_std: bool,
 +}
 +
 +impl DiagnosticsConfig {
 +    pub fn test_sample() -> Self {
 +        use hir::PrefixKind;
 +        use ide_db::imports::insert_use::ImportGranularity;
 +
 +        Self {
 +            proc_macros_enabled: Default::default(),
 +            proc_attr_macros_enabled: Default::default(),
 +            disable_experimental: Default::default(),
 +            disabled: Default::default(),
 +            expr_fill_default: Default::default(),
 +            insert_use: InsertUseConfig {
 +                granularity: ImportGranularity::Preserve,
 +                enforce_granularity: false,
 +                prefix_kind: PrefixKind::Plain,
 +                group: false,
 +                skip_glob_imports: false,
 +            },
 +            prefer_no_std: false,
 +        }
 +    }
 +}
 +
 +struct DiagnosticsContext<'a> {
 +    config: &'a DiagnosticsConfig,
 +    sema: Semantics<'a, RootDatabase>,
 +    resolve: &'a AssistResolveStrategy,
 +}
 +
 +pub fn diagnostics(
 +    db: &RootDatabase,
 +    config: &DiagnosticsConfig,
 +    resolve: &AssistResolveStrategy,
 +    file_id: FileId,
 +) -> Vec<Diagnostic> {
 +    let _p = profile::span("diagnostics");
 +    let sema = Semantics::new(db);
 +    let parse = db.parse(file_id);
 +    let mut res = Vec::new();
 +
 +    // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
 +    res.extend(
 +        parse.errors().iter().take(128).map(|err| {
 +            Diagnostic::new("syntax-error", format!("Syntax Error: {}", err), err.range())
 +        }),
 +    );
 +
 +    let parse = sema.parse(file_id);
 +
 +    for node in parse.syntax().descendants() {
 +        handlers::useless_braces::useless_braces(&mut res, file_id, &node);
 +        handlers::field_shorthand::field_shorthand(&mut res, file_id, &node);
 +        handlers::json_is_not_rust::json_in_items(&sema, &mut res, file_id, &node, &config);
 +    }
 +
 +    let module = sema.to_module_def(file_id);
 +
 +    let ctx = DiagnosticsContext { config, sema, resolve };
 +    if module.is_none() {
 +        handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id);
 +    }
 +
 +    let mut diags = Vec::new();
 +    if let Some(m) = module {
 +        m.diagnostics(db, &mut diags)
 +    }
 +
 +    for diag in diags {
 +        #[rustfmt::skip]
 +        let d = match diag {
 +            AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
 +            AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d),
++            AnyDiagnostic::IncorrectTryExpr(d) => handlers::incorrect_try_expr::incorrect_try_expr(&ctx, &d),
 +            AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
 +            AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d),
 +            AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),
 +            AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d),
 +            AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d),
 +            AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d),
++            AnyDiagnostic::NotImplemented(d) => handlers::not_implemented::not_implemented(&ctx, &d),
 +            AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d),
 +            AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d),
 +            AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d),
 +            AnyDiagnostic::UnimplementedBuiltinMacro(d) => handlers::unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d),
 +            AnyDiagnostic::UnresolvedExternCrate(d) => handlers::unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
 +            AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d),
 +            AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d),
 +            AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d),
 +            AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d, config.proc_macros_enabled, config.proc_attr_macros_enabled),
 +            AnyDiagnostic::InvalidDeriveTarget(d) => handlers::invalid_derive_target::invalid_derive_target(&ctx, &d),
 +
 +            AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) {
 +                Some(it) => it,
 +                None => continue,
 +            }
 +        };
 +        res.push(d)
 +    }
 +
 +    res.retain(|d| {
 +        !ctx.config.disabled.contains(d.code.as_str())
 +            && !(ctx.config.disable_experimental && d.experimental)
 +    });
 +
 +    res
 +}
 +
 +fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist {
 +    let mut res = unresolved_fix(id, label, target);
 +    res.source_change = Some(source_change);
 +    res
 +}
 +
 +fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
 +    assert!(!id.contains(' '));
 +    Assist {
 +        id: AssistId(id, AssistKind::QuickFix),
 +        label: Label::new(label.to_string()),
 +        group: None,
 +        target,
 +        source_change: None,
 +        trigger_signature_help: false,
 +    }
 +}
 +
 +fn adjusted_display_range<N: AstNode>(
 +    ctx: &DiagnosticsContext<'_>,
 +    diag_ptr: InFile<SyntaxNodePtr>,
 +    adj: &dyn Fn(N) -> Option<TextRange>,
 +) -> TextRange {
 +    let FileRange { file_id, range } = ctx.sema.diagnostics_display_range(diag_ptr);
 +
 +    let source_file = ctx.sema.db.parse(file_id);
 +    find_node_at_range::<N>(&source_file.syntax_node(), range)
 +        .filter(|it| it.syntax().text_range() == range)
 +        .and_then(adj)
 +        .unwrap_or(range)
 +}
index 73314e0f330bc67a30b291e55bdb588ff30bdde7,0000000000000000000000000000000000000000..4baf786c455525acf462683ac82ab2515ea6bef3
mode 100644,000000..100644
--- /dev/null
@@@ -1,27 -1,0 +1,26 @@@
- itertools = "0.10.3"
 +[package]
 +name = "ide-ssr"
 +version = "0.0.0"
 +description = "Structural search and replace of Rust code"
 +license = "MIT OR Apache-2.0"
 +repository = "https://github.com/rust-lang/rust-analyzer"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
 +cov-mark = "2.0.0-pre.1"
++itertools = "0.10.5"
 +
 +text-edit = { path = "../text-edit", version = "0.0.0" }
 +parser = { path = "../parser", version = "0.0.0" }
 +syntax = { path = "../syntax", version = "0.0.0" }
 +ide-db = { path = "../ide-db", version = "0.0.0" }
 +hir = { path = "../hir", version = "0.0.0" }
 +stdx = { path = "../stdx", version = "0.0.0" }
 +
 +[dev-dependencies]
 +test-utils = { path = "../test-utils" }
 +expect-test = "1.4.0"
index 0e9771cd2ebafbc6f7df68c5cba6b3d5ad2d87b6,0000000000000000000000000000000000000000..712459a7ee9c688c3117f38f6546b7f47163b428
mode 100644,000000..100644
--- /dev/null
@@@ -1,47 -1,0 +1,47 @@@
- itertools = "0.10.3"
 +[package]
 +name = "ide"
 +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"
 +crossbeam-channel = "0.5.5"
 +either = "1.7.0"
- pulldown-cmark-to-cmark = "10.0.1"
++itertools = "0.10.5"
 +tracing = "0.1.35"
 +oorandom = "11.1.3"
- url = "2.2.2"
++pulldown-cmark-to-cmark = "10.0.4"
 +pulldown-cmark = { version = "0.9.1", default-features = false }
++url = "2.3.1"
 +dot = "0.1.4"
 +
 +stdx = { path = "../stdx", version = "0.0.0" }
 +syntax = { path = "../syntax", version = "0.0.0" }
 +text-edit = { path = "../text-edit", version = "0.0.0" }
 +ide-db = { path = "../ide-db", version = "0.0.0" }
 +cfg = { path = "../cfg", version = "0.0.0" }
 +profile = { path = "../profile", version = "0.0.0" }
 +ide-assists = { path = "../ide-assists", version = "0.0.0" }
 +ide-diagnostics = { path = "../ide-diagnostics", version = "0.0.0" }
 +ide-ssr = { path = "../ide-ssr", version = "0.0.0" }
 +ide-completion = { path = "../ide-completion", version = "0.0.0" }
 +
 +# ide should depend only on the top-level `hir` package. if you need
 +# something from some `hir-xxx` subpackage, reexport the API via `hir`.
 +hir = { path = "../hir", version = "0.0.0" }
 +
 +[target.'cfg(not(any(target_arch = "wasm32", target_os = "emscripten")))'.dependencies]
 +toolchain = { path = "../toolchain", version = "0.0.0" }
 +
 +[dev-dependencies]
 +test-utils = { path = "../test-utils" }
 +expect-test = "1.4.0"
 +
 +[features]
 +in-rust-tree = ["ide-assists/in-rust-tree", "ide-diagnostics/in-rust-tree"]
index f86ea61d1586febd45d96994b91eb179eddde5f9,0000000000000000000000000000000000000000..d0be1b3f4047942fd53ef846bea823316709059a
mode 100644,000000..100644
--- /dev/null
@@@ -1,1833 -1,0 +1,1837 @@@
-         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]))
-         });
 +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, _, link_range| {
++                let nav = def.try_to_nav(db)?;
++                Some(RangeInfo::new(link_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;
 +    }
 +
 +    // Ignore non-built-in macros to account for shadowing
 +    if let Some(it) = sema.resolve_macro_call(&macro_call) {
 +        if !matches!(it.kind(sema.db), hir::MacroKind::BuiltIn) {
 +            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;
 +
 +        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
 +
 +#[rustc_builtin_macro]
 +macro_rules! include_str {}
 +
 +fn main() {
 +    let str = include_str!("foo.txt$0");
 +}
 +//- /foo.txt
 +// empty
 +//^file
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_doc_include_str() {
 +        check(
 +            r#"
 +//- /main.rs
 +#[rustc_builtin_macro]
 +macro_rules! include_str {}
 +
 +#[doc = include_str!("docs.md$0")]
 +struct Item;
 +
 +//- /docs.md
 +// docs
 +//^file
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn goto_shadow_include() {
 +        check(
 +            r#"
 +//- /main.rs
 +macro_rules! include {
 +    ("included.rs") => {}
 +}
 +
 +include!("included.rs$0");
 +
 +//- /included.rs
 +// empty
 +"#,
 +        );
 +    }
 +
 +    #[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 eb997e6fef83022f726dec8a2ff0e5cbcd6fdc86,0000000000000000000000000000000000000000..5cab017a58dbdba582340ca11d9c682bfd58294c
mode 100644,000000..100644
--- /dev/null
@@@ -1,5309 -1,0 +1,5325 @@@
-                 ```rust
-                 <Option<i32> as Try>::Output
-                 ```"#]],
 +use expect_test::{expect, Expect};
 +use ide_db::base_db::{FileLoader, FileRange};
 +use syntax::TextRange;
 +
 +use crate::{fixture, hover::HoverDocFormat, HoverConfig};
 +
 +fn check_hover_no_result(ra_fixture: &str) {
 +    let (analysis, position) = fixture::position(ra_fixture);
 +    let hover = analysis
 +        .hover(
 +            &HoverConfig {
 +                links_in_hover: true,
 +                documentation: Some(HoverDocFormat::Markdown),
 +                keywords: true,
 +            },
 +            FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
 +        )
 +        .unwrap();
 +    assert!(hover.is_none(), "hover not expected but found: {:?}", hover.unwrap());
 +}
 +
 +#[track_caller]
 +fn check(ra_fixture: &str, expect: Expect) {
 +    let (analysis, position) = fixture::position(ra_fixture);
 +    let hover = analysis
 +        .hover(
 +            &HoverConfig {
 +                links_in_hover: true,
 +                documentation: Some(HoverDocFormat::Markdown),
 +                keywords: true,
 +            },
 +            FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
 +        )
 +        .unwrap()
 +        .unwrap();
 +
 +    let content = analysis.db.file_text(position.file_id);
 +    let hovered_element = &content[hover.range];
 +
 +    let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
 +    expect.assert_eq(&actual)
 +}
 +
 +fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
 +    let (analysis, position) = fixture::position(ra_fixture);
 +    let hover = analysis
 +        .hover(
 +            &HoverConfig {
 +                links_in_hover: false,
 +                documentation: Some(HoverDocFormat::Markdown),
 +                keywords: true,
 +            },
 +            FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
 +        )
 +        .unwrap()
 +        .unwrap();
 +
 +    let content = analysis.db.file_text(position.file_id);
 +    let hovered_element = &content[hover.range];
 +
 +    let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
 +    expect.assert_eq(&actual)
 +}
 +
 +fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) {
 +    let (analysis, position) = fixture::position(ra_fixture);
 +    let hover = analysis
 +        .hover(
 +            &HoverConfig {
 +                links_in_hover: true,
 +                documentation: Some(HoverDocFormat::PlainText),
 +                keywords: true,
 +            },
 +            FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
 +        )
 +        .unwrap()
 +        .unwrap();
 +
 +    let content = analysis.db.file_text(position.file_id);
 +    let hovered_element = &content[hover.range];
 +
 +    let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
 +    expect.assert_eq(&actual)
 +}
 +
 +fn check_actions(ra_fixture: &str, expect: Expect) {
 +    let (analysis, file_id, position) = fixture::range_or_position(ra_fixture);
 +    let hover = analysis
 +        .hover(
 +            &HoverConfig {
 +                links_in_hover: true,
 +                documentation: Some(HoverDocFormat::Markdown),
 +                keywords: true,
 +            },
 +            FileRange { file_id, range: position.range_or_empty() },
 +        )
 +        .unwrap()
 +        .unwrap();
 +    expect.assert_debug_eq(&hover.info.actions)
 +}
 +
 +fn check_hover_range(ra_fixture: &str, expect: Expect) {
 +    let (analysis, range) = fixture::range(ra_fixture);
 +    let hover = analysis
 +        .hover(
 +            &HoverConfig {
 +                links_in_hover: false,
 +                documentation: Some(HoverDocFormat::Markdown),
 +                keywords: true,
 +            },
 +            range,
 +        )
 +        .unwrap()
 +        .unwrap();
 +    expect.assert_eq(hover.info.markup.as_str())
 +}
 +
 +fn check_hover_range_no_results(ra_fixture: &str) {
 +    let (analysis, range) = fixture::range(ra_fixture);
 +    let hover = analysis
 +        .hover(
 +            &HoverConfig {
 +                links_in_hover: false,
 +                documentation: Some(HoverDocFormat::Markdown),
 +                keywords: true,
 +            },
 +            range,
 +        )
 +        .unwrap();
 +    assert!(hover.is_none());
 +}
 +
 +#[test]
 +fn hover_descend_macros_avoids_duplicates() {
 +    check(
 +        r#"
 +macro_rules! dupe_use {
 +    ($local:ident) => {
 +        {
 +            $local;
 +            $local;
 +        }
 +    }
 +}
 +fn foo() {
 +    let local = 0;
 +    dupe_use!(local$0);
 +}
 +"#,
 +        expect![[r#"
 +            *local*
 +
 +            ```rust
 +            let local: i32
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_all_macro_descends() {
 +    check(
 +        r#"
 +macro_rules! m {
 +    ($name:ident) => {
 +        /// Outer
 +        fn $name() {}
 +
 +        mod module {
 +            /// Inner
 +            fn $name() {}
 +        }
 +    };
 +}
 +
 +m!(ab$0c);
 +            "#,
 +        expect![[r#"
 +            *abc*
 +
 +            ```rust
 +            test::module
 +            ```
 +
 +            ```rust
 +            fn abc()
 +            ```
 +
 +            ---
 +
 +            Inner
 +            ---
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            fn abc()
 +            ```
 +
 +            ---
 +
 +            Outer
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_type_of_an_expression() {
 +    check(
 +        r#"
 +pub fn foo() -> u32 { 1 }
 +
 +fn main() {
 +    let foo_test = foo()$0;
 +}
 +"#,
 +        expect![[r#"
 +            *foo()*
 +            ```rust
 +            u32
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_remove_markdown_if_configured() {
 +    check_hover_no_markdown(
 +        r#"
 +pub fn foo() -> u32 { 1 }
 +
 +fn main() {
 +    let foo_test = foo()$0;
 +}
 +"#,
 +        expect![[r#"
 +            *foo()*
 +            u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_long_type_of_an_expression() {
 +    check(
 +        r#"
 +struct Scan<A, B, C> { a: A, b: B, c: C }
 +struct Iter<I> { inner: I }
 +enum Option<T> { Some(T), None }
 +
 +struct OtherStruct<T> { i: T }
 +
 +fn scan<A, B, C>(a: A, b: B, c: C) -> Iter<Scan<OtherStruct<A>, B, C>> {
 +    Iter { inner: Scan { a, b, c } }
 +}
 +
 +fn main() {
 +    let num: i32 = 55;
 +    let closure = |memo: &mut u32, value: &u32, _another: &mut u32| -> Option<u32> {
 +        Option::Some(*memo + value)
 +    };
 +    let number = 5u32;
 +    let mut iter$0 = scan(OtherStruct { i: num }, closure, number);
 +}
 +"#,
 +        expect![[r#"
 +                *iter*
 +
 +                ```rust
 +                let mut iter: Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>>
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_fn_signature() {
 +    // Single file with result
 +    check(
 +        r#"
 +pub fn foo() -> u32 { 1 }
 +
 +fn main() { let foo_test = fo$0o(); }
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub fn foo() -> u32
 +                ```
 +            "#]],
 +    );
 +
 +    // Multiple candidates but results are ambiguous.
 +    check(
 +        r#"
 +//- /a.rs
 +pub fn foo() -> u32 { 1 }
 +
 +//- /b.rs
 +pub fn foo() -> &str { "" }
 +
 +//- /c.rs
 +pub fn foo(a: u32, b: u32) {}
 +
 +//- /main.rs
 +mod a;
 +mod b;
 +mod c;
 +
 +fn main() { let foo_test = fo$0o(); }
 +        "#,
 +        expect![[r#"
 +                *foo*
 +                ```rust
 +                {unknown}
 +                ```
 +            "#]],
 +    );
 +
 +    // Use literal `crate` in path
 +    check(
 +        r#"
 +pub struct X;
 +
 +fn foo() -> crate::X { X }
 +
 +fn main() { f$0oo(); }
 +        "#,
 +        expect![[r#"
 +            *foo*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            fn foo() -> crate::X
 +            ```
 +        "#]],
 +    );
 +
 +    // Check `super` in path
 +    check(
 +        r#"
 +pub struct X;
 +
 +mod m { pub fn foo() -> super::X { super::X } }
 +
 +fn main() { m::f$0oo(); }
 +        "#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test::m
 +                ```
 +
 +                ```rust
 +                pub fn foo() -> super::X
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_omits_unnamed_where_preds() {
 +    check(
 +        r#"
 +pub fn foo(bar: impl T) { }
 +
 +fn main() { fo$0o(); }
 +        "#,
 +        expect![[r#"
 +            *foo*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            pub fn foo(bar: impl T)
 +            ```
 +        "#]],
 +    );
 +    check(
 +        r#"
 +pub fn foo<V: AsRef<str>>(bar: impl T, baz: V) { }
 +
 +fn main() { fo$0o(); }
 +        "#,
 +        expect![[r#"
 +            *foo*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            pub fn foo<V>(bar: impl T, baz: V)
 +            where
 +                V: AsRef<str>,
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_fn_signature_with_type_params() {
 +    check(
 +        r#"
 +pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { }
 +
 +fn main() { let foo_test = fo$0o(); }
 +        "#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub fn foo<'a, T>(b: &'a T) -> &'a str
 +                where
 +                    T: AsRef<str>,
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_fn_signature_on_fn_name() {
 +    check(
 +        r#"
 +pub fn foo$0(a: u32, b: u32) -> u32 {}
 +
 +fn main() { }
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub fn foo(a: u32, b: u32) -> u32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_fn_doc() {
 +    check(
 +        r#"
 +/// # Example
 +/// ```
 +/// # use std::path::Path;
 +/// #
 +/// foo(Path::new("hello, world!"))
 +/// ```
 +pub fn foo$0(_: &Path) {}
 +
 +fn main() { }
 +"#,
 +        expect![[r##"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub fn foo(_: &Path)
 +                ```
 +
 +                ---
 +
 +                # Example
 +
 +                ```
 +                # use std::path::Path;
 +                #
 +                foo(Path::new("hello, world!"))
 +                ```
 +            "##]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_fn_doc_attr_raw_string() {
 +    check(
 +        r##"
 +#[doc = r#"Raw string doc attr"#]
 +pub fn foo$0(_: &Path) {}
 +
 +fn main() { }
 +"##,
 +        expect![[r##"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub fn foo(_: &Path)
 +                ```
 +
 +                ---
 +
 +                Raw string doc attr
 +            "##]],
 +    );
 +}
 +
 +#[test]
 +fn hover_shows_struct_field_info() {
 +    // Hovering over the field when instantiating
 +    check(
 +        r#"
 +struct Foo { field_a: u32 }
 +
 +fn main() {
 +    let foo = Foo { field_a$0: 0, };
 +}
 +"#,
 +        expect![[r#"
 +                *field_a*
 +
 +                ```rust
 +                test::Foo
 +                ```
 +
 +                ```rust
 +                field_a: u32
 +                ```
 +            "#]],
 +    );
 +
 +    // Hovering over the field in the definition
 +    check(
 +        r#"
 +struct Foo { field_a$0: u32 }
 +
 +fn main() {
 +    let foo = Foo { field_a: 0 };
 +}
 +"#,
 +        expect![[r#"
 +                *field_a*
 +
 +                ```rust
 +                test::Foo
 +                ```
 +
 +                ```rust
 +                field_a: u32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_const_static() {
 +    check(
 +        r#"const foo$0: u32 = 123;"#,
 +        expect![[r#"
 +            *foo*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const foo: u32 = 123 (0x7B)
 +            ```
 +        "#]],
 +    );
 +    check(
 +        r#"
 +const foo$0: u32 = {
 +    let x = foo();
 +    x + 100
 +};"#,
 +        expect![[r#"
 +            *foo*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const foo: u32 = {
 +                let x = foo();
 +                x + 100
 +            }
 +            ```
 +        "#]],
 +    );
 +
 +    check(
 +        r#"static foo$0: u32 = 456;"#,
 +        expect![[r#"
 +            *foo*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            static foo: u32 = 456
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_default_generic_types() {
 +    check(
 +        r#"
 +struct Test<K, T = u8> { k: K, t: T }
 +
 +fn main() {
 +    let zz$0 = Test { t: 23u8, k: 33 };
 +}"#,
 +        expect![[r#"
 +                *zz*
 +
 +                ```rust
 +                let zz: Test<i32>
 +                ```
 +            "#]],
 +    );
 +    check_hover_range(
 +        r#"
 +struct Test<K, T = u8> { k: K, t: T }
 +
 +fn main() {
 +    let $0zz$0 = Test { t: 23u8, k: 33 };
 +}"#,
 +        expect![[r#"
 +            ```rust
 +            Test<i32, u8>
 +            ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_some() {
 +    check(
 +        r#"
 +enum Option<T> { Some(T) }
 +use Option::Some;
 +
 +fn main() { So$0me(12); }
 +"#,
 +        expect![[r#"
 +                *Some*
 +
 +                ```rust
 +                test::Option
 +                ```
 +
 +                ```rust
 +                Some(T)
 +                ```
 +            "#]],
 +    );
 +
 +    check(
 +        r#"
 +enum Option<T> { Some(T) }
 +use Option::Some;
 +
 +fn main() { let b$0ar = Some(12); }
 +"#,
 +        expect![[r#"
 +                *bar*
 +
 +                ```rust
 +                let bar: Option<i32>
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_enum_variant() {
 +    check(
 +        r#"
 +enum Option<T> {
 +    Some(T)
 +    /// The None variant
 +    Non$0e
 +}
 +"#,
 +        expect![[r#"
 +                *None*
 +
 +                ```rust
 +                test::Option
 +                ```
 +
 +                ```rust
 +                None
 +                ```
 +
 +                ---
 +
 +                The None variant
 +            "#]],
 +    );
 +
 +    check(
 +        r#"
 +enum Option<T> {
 +    /// The Some variant
 +    Some(T)
 +}
 +fn main() {
 +    let s = Option::Som$0e(12);
 +}
 +"#,
 +        expect![[r#"
 +                *Some*
 +
 +                ```rust
 +                test::Option
 +                ```
 +
 +                ```rust
 +                Some(T)
 +                ```
 +
 +                ---
 +
 +                The Some variant
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_for_local_variable() {
 +    check(
 +        r#"fn func(foo: i32) { fo$0o; }"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                foo: i32
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_for_local_variable_pat() {
 +    check(
 +        r#"fn func(fo$0o: i32) {}"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                foo: i32
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_local_var_edge() {
 +    check(
 +        r#"fn func(foo: i32) { if true { $0foo; }; }"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                foo: i32
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_for_param_edge() {
 +    check(
 +        r#"fn func($0foo: i32) {}"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                foo: i32
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_for_param_with_multiple_traits() {
 +    check(
 +        r#"
 +            //- minicore: sized
 +            trait Deref {
 +                type Target: ?Sized;
 +            }
 +            trait DerefMut {
 +                type Target: ?Sized;
 +            }
 +            fn f(_x$0: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#,
 +        expect![[r#"
 +                *_x*
 +
 +                ```rust
 +                _x: impl Deref<Target = u8> + DerefMut<Target = u8>
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_infer_associated_method_result() {
 +    check(
 +        r#"
 +struct Thing { x: u32 }
 +
 +impl Thing {
 +    fn new() -> Thing { Thing { x: 0 } }
 +}
 +
 +fn main() { let foo_$0test = Thing::new(); }
 +"#,
 +        expect![[r#"
 +                *foo_test*
 +
 +                ```rust
 +                let foo_test: Thing
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_infer_associated_method_exact() {
 +    check(
 +        r#"
 +mod wrapper {
 +    pub struct Thing { x: u32 }
 +
 +    impl Thing {
 +        pub fn new() -> Thing { Thing { x: 0 } }
 +    }
 +}
 +
 +fn main() { let foo_test = wrapper::Thing::new$0(); }
 +"#,
 +        expect![[r#"
 +                *new*
 +
 +                ```rust
 +                test::wrapper::Thing
 +                ```
 +
 +                ```rust
 +                pub fn new() -> Thing
 +                ```
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_infer_associated_const_in_pattern() {
 +    check(
 +        r#"
 +struct X;
 +impl X {
 +    const C: u32 = 1;
 +}
 +
 +fn main() {
 +    match 1 {
 +        X::C$0 => {},
 +        2 => {},
 +        _ => {}
 +    };
 +}
 +"#,
 +        expect![[r#"
 +            *C*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const C: u32 = 1
 +            ```
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_self() {
 +    check(
 +        r#"
 +struct Thing { x: u32 }
 +impl Thing {
 +    fn new() -> Self { Self$0 { x: 0 } }
 +}
 +"#,
 +        expect![[r#"
 +                *Self*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                struct Thing
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +struct Thing { x: u32 }
 +impl Thing {
 +    fn new() -> Self$0 { Self { x: 0 } }
 +}
 +"#,
 +        expect![[r#"
 +                *Self*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                struct Thing
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +enum Thing { A }
 +impl Thing {
 +    pub fn new() -> Self$0 { Thing::A }
 +}
 +"#,
 +        expect![[r#"
 +                *Self*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                enum Thing
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +        enum Thing { A }
 +        impl Thing {
 +            pub fn thing(a: Self$0) {}
 +        }
 +        "#,
 +        expect![[r#"
 +                *Self*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                enum Thing
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_shadowing_pat() {
 +    check(
 +        r#"
 +fn x() {}
 +
 +fn y() {
 +    let x = 0i32;
 +    x$0;
 +}
 +"#,
 +        expect![[r#"
 +                *x*
 +
 +                ```rust
 +                let x: i32
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_macro_invocation() {
 +    check(
 +        r#"
 +macro_rules! foo { () => {} }
 +
 +fn f() { fo$0o!(); }
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                macro_rules! foo
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_macro2_invocation() {
 +    check(
 +        r#"
 +/// foo bar
 +///
 +/// foo bar baz
 +macro foo() {}
 +
 +fn f() { fo$0o!(); }
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                macro foo
 +                ```
 +
 +                ---
 +
 +                foo bar
 +
 +                foo bar baz
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_tuple_field() {
 +    check(
 +        r#"struct TS(String, i32$0);"#,
 +        expect![[r#"
 +                *i32*
 +
 +                ```rust
 +                i32
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_through_macro() {
 +    check(
 +        r#"
 +macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
 +fn foo() {}
 +id! {
 +    fn bar() { fo$0o(); }
 +}
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                fn foo()
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_through_attr() {
 +    check(
 +        r#"
 +//- proc_macros: identity
 +#[proc_macros::identity]
 +fn foo$0() {}
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                fn foo()
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_through_expr_in_macro() {
 +    check(
 +        r#"
 +macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
 +fn foo(bar:u32) { let a = id!(ba$0r); }
 +"#,
 +        expect![[r#"
 +                *bar*
 +
 +                ```rust
 +                bar: u32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_through_expr_in_macro_recursive() {
 +    check(
 +        r#"
 +macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
 +macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
 +fn foo(bar:u32) { let a = id!(ba$0r); }
 +"#,
 +        expect![[r#"
 +                *bar*
 +
 +                ```rust
 +                bar: u32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_through_func_in_macro_recursive() {
 +    check(
 +        r#"
 +macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
 +macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
 +fn bar() -> u32 { 0 }
 +fn foo() { let a = id!([0u32, bar($0)] ); }
 +"#,
 +        expect![[r#"
 +                *bar()*
 +                ```rust
 +                u32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_through_literal_string_in_macro() {
 +    check(
 +        r#"
 +macro_rules! arr { ($($tt:tt)*) => { [$($tt)*] } }
 +fn foo() {
 +    let mastered_for_itunes = "";
 +    let _ = arr!("Tr$0acks", &mastered_for_itunes);
 +}
 +"#,
 +        expect![[r#"
 +                *"Tracks"*
 +                ```rust
 +                &str
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_through_assert_macro() {
 +    check(
 +        r#"
 +#[rustc_builtin_macro]
 +macro_rules! assert {}
 +
 +fn bar() -> bool { true }
 +fn foo() {
 +    assert!(ba$0r());
 +}
 +"#,
 +        expect![[r#"
 +                *bar*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                fn bar() -> bool
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_multiple_actions() {
 +    check_actions(
 +        r#"
 +struct Bar;
 +struct Foo { bar: Bar }
 +
 +fn foo(Foo { b$0ar }: &Foo) {}
 +        "#,
 +        expect![[r#"
 +            [
 +                GoToType(
 +                    [
 +                        HoverGotoTypeData {
 +                            mod_path: "test::Bar",
 +                            nav: NavigationTarget {
 +                                file_id: FileId(
 +                                    0,
 +                                ),
 +                                full_range: 0..11,
 +                                focus_range: 7..10,
 +                                name: "Bar",
 +                                kind: Struct,
 +                                description: "struct Bar",
 +                            },
 +                        },
 +                    ],
 +                ),
 +            ]
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn test_hover_through_literal_string_in_builtin_macro() {
 +    check_hover_no_result(
 +        r#"
 +            #[rustc_builtin_macro]
 +            macro_rules! format {}
 +
 +            fn foo() {
 +                format!("hel$0lo {}", 0);
 +            }
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn test_hover_non_ascii_space_doc() {
 +    check(
 +        "
 +/// <- `\u{3000}` here
 +fn foo() { }
 +
 +fn bar() { fo$0o(); }
 +",
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                fn foo()
 +                ```
 +
 +                ---
 +
 +                \<- ` ` here
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_function_show_qualifiers() {
 +    check(
 +        r#"async fn foo$0() {}"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                async fn foo()
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"pub const unsafe fn foo$0() {}"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub const unsafe fn foo()
 +                ```
 +            "#]],
 +    );
 +    // Top level `pub(crate)` will be displayed as no visibility.
 +    check(
 +        r#"mod m { pub(crate) async unsafe extern "C" fn foo$0() {} }"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test::m
 +                ```
 +
 +                ```rust
 +                pub(crate) async unsafe extern "C" fn foo()
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_function_show_types() {
 +    check(
 +        r#"fn foo$0(a: i32, b:i32) -> i32 { 0 }"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                fn foo(a: i32, b: i32) -> i32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_function_pointer_show_identifiers() {
 +    check(
 +        r#"type foo$0 = fn(a: i32, b: i32) -> i32;"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                type foo = fn(a: i32, b: i32) -> i32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_function_pointer_no_identifier() {
 +    check(
 +        r#"type foo$0 = fn(i32, _: i32) -> i32;"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                type foo = fn(i32, i32) -> i32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_trait_show_qualifiers() {
 +    check_actions(
 +        r"unsafe trait foo$0() {}",
 +        expect![[r#"
 +                [
 +                    Implementation(
 +                        FilePosition {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            offset: 13,
 +                        },
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_extern_crate() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:std
 +extern crate st$0d;
 +//- /std/lib.rs crate:std
 +//! Standard library for this test
 +//!
 +//! Printed?
 +//! abc123
 +"#,
 +        expect![[r#"
 +                *std*
 +
 +                ```rust
 +                extern crate std
 +                ```
 +
 +                ---
 +
 +                Standard library for this test
 +
 +                Printed?
 +                abc123
 +            "#]],
 +    );
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:std
 +extern crate std as ab$0c;
 +//- /std/lib.rs crate:std
 +//! Standard library for this test
 +//!
 +//! Printed?
 +//! abc123
 +"#,
 +        expect![[r#"
 +                *abc*
 +
 +                ```rust
 +                extern crate std
 +                ```
 +
 +                ---
 +
 +                Standard library for this test
 +
 +                Printed?
 +                abc123
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_mod_with_same_name_as_function() {
 +    check(
 +        r#"
 +use self::m$0y::Bar;
 +mod my { pub struct Bar; }
 +
 +fn my() {}
 +"#,
 +        expect![[r#"
 +                *my*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                mod my
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_struct_doc_comment() {
 +    check(
 +        r#"
 +/// This is an example
 +/// multiline doc
 +///
 +/// # Example
 +///
 +/// ```
 +/// let five = 5;
 +///
 +/// assert_eq!(6, my_crate::add_one(5));
 +/// ```
 +struct Bar;
 +
 +fn foo() { let bar = Ba$0r; }
 +"#,
 +        expect![[r##"
 +                *Bar*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                struct Bar
 +                ```
 +
 +                ---
 +
 +                This is an example
 +                multiline doc
 +
 +                # Example
 +
 +                ```
 +                let five = 5;
 +
 +                assert_eq!(6, my_crate::add_one(5));
 +                ```
 +            "##]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_struct_doc_attr() {
 +    check(
 +        r#"
 +#[doc = "bar docs"]
 +struct Bar;
 +
 +fn foo() { let bar = Ba$0r; }
 +"#,
 +        expect![[r#"
 +                *Bar*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                struct Bar
 +                ```
 +
 +                ---
 +
 +                bar docs
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_struct_doc_attr_multiple_and_mixed() {
 +    check(
 +        r#"
 +/// bar docs 0
 +#[doc = "bar docs 1"]
 +#[doc = "bar docs 2"]
 +struct Bar;
 +
 +fn foo() { let bar = Ba$0r; }
 +"#,
 +        expect![[r#"
 +                *Bar*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                struct Bar
 +                ```
 +
 +                ---
 +
 +                bar docs 0
 +                bar docs 1
 +                bar docs 2
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_external_url() {
 +    check(
 +        r#"
 +pub struct Foo;
 +/// [external](https://www.google.com)
 +pub struct B$0ar
 +"#,
 +        expect![[r#"
 +                *Bar*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub struct Bar
 +                ```
 +
 +                ---
 +
 +                [external](https://www.google.com)
 +            "#]],
 +    );
 +}
 +
 +// Check that we don't rewrite links which we can't identify
 +#[test]
 +fn test_hover_unknown_target() {
 +    check(
 +        r#"
 +pub struct Foo;
 +/// [baz](Baz)
 +pub struct B$0ar
 +"#,
 +        expect![[r#"
 +                *Bar*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub struct Bar
 +                ```
 +
 +                ---
 +
 +                [baz](Baz)
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_no_links() {
 +    check_hover_no_links(
 +        r#"
 +/// Test cases:
 +/// case 1.  bare URL: https://www.example.com/
 +/// case 2.  inline URL with title: [example](https://www.example.com/)
 +/// case 3.  code reference: [`Result`]
 +/// case 4.  code reference but miss footnote: [`String`]
 +/// case 5.  autolink: <http://www.example.com/>
 +/// case 6.  email address: <test@example.com>
 +/// case 7.  reference: [example][example]
 +/// case 8.  collapsed link: [example][]
 +/// case 9.  shortcut link: [example]
 +/// case 10. inline without URL: [example]()
 +/// case 11. reference: [foo][foo]
 +/// case 12. reference: [foo][bar]
 +/// case 13. collapsed link: [foo][]
 +/// case 14. shortcut link: [foo]
 +/// case 15. inline without URL: [foo]()
 +/// case 16. just escaped text: \[foo]
 +/// case 17. inline link: [Foo](foo::Foo)
 +///
 +/// [`Result`]: ../../std/result/enum.Result.html
 +/// [^example]: https://www.example.com/
 +pub fn fo$0o() {}
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                pub fn foo()
 +                ```
 +
 +                ---
 +
 +                Test cases:
 +                case 1.  bare URL: https://www.example.com/
 +                case 2.  inline URL with title: [example](https://www.example.com/)
 +                case 3.  code reference: `Result`
 +                case 4.  code reference but miss footnote: `String`
 +                case 5.  autolink: http://www.example.com/
 +                case 6.  email address: test@example.com
 +                case 7.  reference: example
 +                case 8.  collapsed link: example
 +                case 9.  shortcut link: example
 +                case 10. inline without URL: example
 +                case 11. reference: foo
 +                case 12. reference: foo
 +                case 13. collapsed link: foo
 +                case 14. shortcut link: foo
 +                case 15. inline without URL: foo
 +                case 16. just escaped text: \[foo\]
 +                case 17. inline link: Foo
 +
 +                [^example]: https://www.example.com/
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_macro_generated_struct_fn_doc_comment() {
 +    cov_mark::check!(hover_macro_generated_struct_fn_doc_comment);
 +
 +    check(
 +        r#"
 +macro_rules! bar {
 +    () => {
 +        struct Bar;
 +        impl Bar {
 +            /// Do the foo
 +            fn foo(&self) {}
 +        }
 +    }
 +}
 +
 +bar!();
 +
 +fn foo() { let bar = Bar; bar.fo$0o(); }
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test::Bar
 +                ```
 +
 +                ```rust
 +                fn foo(&self)
 +                ```
 +
 +                ---
 +
 +                Do the foo
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_macro_generated_struct_fn_doc_attr() {
 +    cov_mark::check!(hover_macro_generated_struct_fn_doc_attr);
 +
 +    check(
 +        r#"
 +macro_rules! bar {
 +    () => {
 +        struct Bar;
 +        impl Bar {
 +            #[doc = "Do the foo"]
 +            fn foo(&self) {}
 +        }
 +    }
 +}
 +
 +bar!();
 +
 +fn foo() { let bar = Bar; bar.fo$0o(); }
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test::Bar
 +                ```
 +
 +                ```rust
 +                fn foo(&self)
 +                ```
 +
 +                ---
 +
 +                Do the foo
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_variadic_function() {
 +    check(
 +        r#"
 +extern "C" {
 +    pub fn foo(bar: i32, ...) -> i32;
 +}
 +
 +fn main() { let foo_test = unsafe { fo$0o(1, 2, 3); } }
 +"#,
 +        expect![[r#"
 +            *foo*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            pub unsafe fn foo(bar: i32, ...) -> i32
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_trait_has_impl_action() {
 +    check_actions(
 +        r#"trait foo$0() {}"#,
 +        expect![[r#"
 +                [
 +                    Implementation(
 +                        FilePosition {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            offset: 6,
 +                        },
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_struct_has_impl_action() {
 +    check_actions(
 +        r"struct foo$0() {}",
 +        expect![[r#"
 +                [
 +                    Implementation(
 +                        FilePosition {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            offset: 7,
 +                        },
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_union_has_impl_action() {
 +    check_actions(
 +        r#"union foo$0() {}"#,
 +        expect![[r#"
 +                [
 +                    Implementation(
 +                        FilePosition {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            offset: 6,
 +                        },
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_enum_has_impl_action() {
 +    check_actions(
 +        r"enum foo$0() { A, B }",
 +        expect![[r#"
 +                [
 +                    Implementation(
 +                        FilePosition {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            offset: 5,
 +                        },
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_self_has_impl_action() {
 +    check_actions(
 +        r#"struct foo where Self$0:;"#,
 +        expect![[r#"
 +                [
 +                    Implementation(
 +                        FilePosition {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            offset: 7,
 +                        },
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_test_has_action() {
 +    check_actions(
 +        r#"
 +#[test]
 +fn foo_$0test() {}
 +"#,
 +        expect![[r#"
 +            [
 +                Reference(
 +                    FilePosition {
 +                        file_id: FileId(
 +                            0,
 +                        ),
 +                        offset: 11,
 +                    },
 +                ),
 +                Runnable(
 +                    Runnable {
 +                        use_name_in_title: false,
 +                        nav: NavigationTarget {
 +                            file_id: FileId(
 +                                0,
 +                            ),
 +                            full_range: 0..24,
 +                            focus_range: 11..19,
 +                            name: "foo_test",
 +                            kind: Function,
 +                        },
 +                        kind: Test {
 +                            test_id: Path(
 +                                "foo_test",
 +                            ),
 +                            attr: TestAttr {
 +                                ignore: false,
 +                            },
 +                        },
 +                        cfg: None,
 +                    },
 +                ),
 +            ]
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_test_mod_has_action() {
 +    check_actions(
 +        r#"
 +mod tests$0 {
 +    #[test]
 +    fn foo_test() {}
 +}
 +"#,
 +        expect![[r#"
 +                [
 +                    Runnable(
 +                        Runnable {
 +                            use_name_in_title: false,
 +                            nav: NavigationTarget {
 +                                file_id: FileId(
 +                                    0,
 +                                ),
 +                                full_range: 0..46,
 +                                focus_range: 4..9,
 +                                name: "tests",
 +                                kind: Module,
 +                                description: "mod tests",
 +                            },
 +                            kind: TestMod {
 +                                path: "tests",
 +                            },
 +                            cfg: None,
 +                        },
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_struct_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +struct S{ f1: u32 }
 +
 +fn main() { let s$0t = S{ f1:0 }; }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..19,
 +                                    focus_range: 7..8,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_generic_struct_has_goto_type_actions() {
 +    check_actions(
 +        r#"
 +struct Arg(u32);
 +struct S<T>{ f1: T }
 +
 +fn main() { let s$0t = S{ f1:Arg(0) }; }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 17..37,
 +                                    focus_range: 24..25,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Arg",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..16,
 +                                    focus_range: 7..10,
 +                                    name: "Arg",
 +                                    kind: Struct,
 +                                    description: "struct Arg",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_generic_struct_has_flattened_goto_type_actions() {
 +    check_actions(
 +        r#"
 +struct Arg(u32);
 +struct S<T>{ f1: T }
 +
 +fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 17..37,
 +                                    focus_range: 24..25,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Arg",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..16,
 +                                    focus_range: 7..10,
 +                                    name: "Arg",
 +                                    kind: Struct,
 +                                    description: "struct Arg",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_tuple_has_goto_type_actions() {
 +    check_actions(
 +        r#"
 +struct A(u32);
 +struct B(u32);
 +mod M {
 +    pub struct C(u32);
 +}
 +
 +fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::A",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..14,
 +                                    focus_range: 7..8,
 +                                    name: "A",
 +                                    kind: Struct,
 +                                    description: "struct A",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::B",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 15..29,
 +                                    focus_range: 22..23,
 +                                    name: "B",
 +                                    kind: Struct,
 +                                    description: "struct B",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::M::C",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 42..60,
 +                                    focus_range: 53..54,
 +                                    name: "C",
 +                                    kind: Struct,
 +                                    description: "pub struct C",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_return_impl_trait_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {}
 +fn foo() -> impl Foo {}
 +
 +fn main() { let s$0t = foo(); }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_generic_return_impl_trait_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo<T> {}
 +struct S;
 +fn foo() -> impl Foo<S> {}
 +
 +fn main() { let s$0t = foo(); }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..15,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 16..25,
 +                                    focus_range: 23..24,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_return_impl_traits_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {}
 +trait Bar {}
 +fn foo() -> impl Foo + Bar {}
 +
 +fn main() { let s$0t = foo(); }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Bar",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 13..25,
 +                                    focus_range: 19..22,
 +                                    name: "Bar",
 +                                    kind: Trait,
 +                                    description: "trait Bar",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_generic_return_impl_traits_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo<T> {}
 +trait Bar<T> {}
 +struct S1 {}
 +struct S2 {}
 +
 +fn foo() -> impl Foo<S1> + Bar<S2> {}
 +
 +fn main() { let s$0t = foo(); }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..15,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Bar",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 16..31,
 +                                    focus_range: 22..25,
 +                                    name: "Bar",
 +                                    kind: Trait,
 +                                    description: "trait Bar<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S1",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 32..44,
 +                                    focus_range: 39..41,
 +                                    name: "S1",
 +                                    kind: Struct,
 +                                    description: "struct S1",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S2",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 45..57,
 +                                    focus_range: 52..54,
 +                                    name: "S2",
 +                                    kind: Struct,
 +                                    description: "struct S2",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_arg_impl_trait_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {}
 +fn foo(ar$0g: &impl Foo) {}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_arg_impl_traits_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {}
 +trait Bar<T> {}
 +struct S{}
 +
 +fn foo(ar$0g: &impl Foo + Bar<S>) {}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Bar",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 13..28,
 +                                    focus_range: 19..22,
 +                                    name: "Bar",
 +                                    kind: Trait,
 +                                    description: "trait Bar<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 29..39,
 +                                    focus_range: 36..37,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_async_block_impl_trait_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +//- /main.rs crate:main deps:core
 +// we don't use minicore here so that this test doesn't randomly fail
 +// when someone edits minicore
 +struct S;
 +fn foo() {
 +    let fo$0o = async { S };
 +}
 +//- /core.rs crate:core
 +pub mod future {
 +    #[lang = "future_trait"]
 +    pub trait Future {}
 +}
 +"#,
 +        expect![[r#"
 +            [
 +                GoToType(
 +                    [
 +                        HoverGotoTypeData {
 +                            mod_path: "core::future::Future",
 +                            nav: NavigationTarget {
 +                                file_id: FileId(
 +                                    1,
 +                                ),
 +                                full_range: 21..69,
 +                                focus_range: 60..66,
 +                                name: "Future",
 +                                kind: Trait,
 +                                description: "pub trait Future",
 +                            },
 +                        },
 +                        HoverGotoTypeData {
 +                            mod_path: "main::S",
 +                            nav: NavigationTarget {
 +                                file_id: FileId(
 +                                    0,
 +                                ),
 +                                full_range: 0..110,
 +                                focus_range: 108..109,
 +                                name: "S",
 +                                kind: Struct,
 +                                description: "struct S",
 +                            },
 +                        },
 +                    ],
 +                ),
 +            ]
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo<T> {}
 +struct S {}
 +fn foo(ar$0g: &impl Foo<S>) {}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..15,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 16..27,
 +                                    focus_range: 23..24,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_dyn_return_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {}
 +struct S;
 +impl Foo for S {}
 +
 +struct B<T>{}
 +fn foo() -> B<dyn Foo> {}
 +
 +fn main() { let s$0t = foo(); }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::B",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 42..55,
 +                                    focus_range: 49..50,
 +                                    name: "B",
 +                                    kind: Struct,
 +                                    description: "struct B<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_dyn_arg_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {}
 +fn foo(ar$0g: &dyn Foo) {}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_generic_dyn_arg_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo<T> {}
 +struct S {}
 +fn foo(ar$0g: &dyn Foo<S>) {}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..15,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 16..27,
 +                                    focus_range: 23..24,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_goto_type_action_links_order() {
 +    check_actions(
 +        r#"
 +trait ImplTrait<T> {}
 +trait DynTrait<T> {}
 +struct B<T> {}
 +struct S {}
 +
 +fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::ImplTrait",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..21,
 +                                    focus_range: 6..15,
 +                                    name: "ImplTrait",
 +                                    kind: Trait,
 +                                    description: "trait ImplTrait<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::B",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 43..57,
 +                                    focus_range: 50..51,
 +                                    name: "B",
 +                                    kind: Struct,
 +                                    description: "struct B<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::DynTrait",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 22..42,
 +                                    focus_range: 28..36,
 +                                    name: "DynTrait",
 +                                    kind: Trait,
 +                                    description: "trait DynTrait<T>",
 +                                },
 +                            },
 +                            HoverGotoTypeData {
 +                                mod_path: "test::S",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 58..69,
 +                                    focus_range: 65..66,
 +                                    name: "S",
 +                                    kind: Struct,
 +                                    description: "struct S",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_associated_type_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {
 +    type Item;
 +    fn get(self) -> Self::Item {}
 +}
 +
 +struct Bar{}
 +struct S{}
 +
 +impl Foo for S { type Item = Bar; }
 +
 +fn test() -> impl Foo { S {} }
 +
 +fn main() { let s$0t = test().get(); }
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..62,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_const_param_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +struct Bar;
 +struct Foo<const BAR: Bar>;
 +
 +impl<const BAR: Bar> Foo<BAR$0> {}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Bar",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..11,
 +                                    focus_range: 7..10,
 +                                    name: "Bar",
 +                                    kind: Struct,
 +                                    description: "struct Bar",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_type_param_has_goto_type_action() {
 +    check_actions(
 +        r#"
 +trait Foo {}
 +
 +fn foo<T: Foo>(t: T$0){}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..12,
 +                                    focus_range: 6..9,
 +                                    name: "Foo",
 +                                    kind: Trait,
 +                                    description: "trait Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_self_has_go_to_type() {
 +    check_actions(
 +        r#"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self$0) {}
 +}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..11,
 +                                    focus_range: 7..10,
 +                                    name: "Foo",
 +                                    kind: Struct,
 +                                    description: "struct Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_displays_normalized_crate_names() {
 +    check(
 +        r#"
 +//- /lib.rs crate:name-with-dashes
 +pub mod wrapper {
 +    pub struct Thing { x: u32 }
 +
 +    impl Thing {
 +        pub fn new() -> Thing { Thing { x: 0 } }
 +    }
 +}
 +
 +//- /main.rs crate:main deps:name-with-dashes
 +fn main() { let foo_test = name_with_dashes::wrapper::Thing::new$0(); }
 +"#,
 +        expect![[r#"
 +            *new*
 +
 +            ```rust
 +            name_with_dashes::wrapper::Thing
 +            ```
 +
 +            ```rust
 +            pub fn new() -> Thing
 +            ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_field_pat_shorthand_ref_match_ergonomics() {
 +    check(
 +        r#"
 +struct S {
 +    f: i32,
 +}
 +
 +fn main() {
 +    let s = S { f: 0 };
 +    let S { f$0 } = &s;
 +}
 +"#,
 +        expect![[r#"
 +            *f*
 +
 +            ```rust
 +            f: &i32
 +            ```
 +            ---
 +
 +            ```rust
 +            test::S
 +            ```
 +
 +            ```rust
 +            f: i32
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn const_generic_order() {
 +    check(
 +        r#"
 +struct Foo;
 +struct S$0T<const C: usize = 1, T = Foo>(T);
 +"#,
 +        expect![[r#"
 +            *ST*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            struct ST<const C: usize, T = Foo>
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn const_generic_positive_i8_literal() {
 +    check(
 +        r#"
 +struct Const<const N: i8>;
 +
 +fn main() {
 +    let v$0alue = Const::<1>;
 +}
 +"#,
 +        expect![[r#"
 +            *value*
 +
 +            ```rust
 +            let value: Const<1>
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn const_generic_zero_i8_literal() {
 +    check(
 +        r#"
 +struct Const<const N: i8>;
 +
 +fn main() {
 +    let v$0alue = Const::<0>;
 +}
 +"#,
 +        expect![[r#"
 +            *value*
 +
 +            ```rust
 +            let value: Const<0>
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn const_generic_negative_i8_literal() {
 +    check(
 +        r#"
 +struct Const<const N: i8>;
 +
 +fn main() {
 +    let v$0alue = Const::<-1>;
 +}
 +"#,
 +        expect![[r#"
 +            *value*
 +
 +            ```rust
 +            let value: Const<-1>
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn const_generic_bool_literal() {
 +    check(
 +        r#"
 +struct Const<const F: bool>;
 +
 +fn main() {
 +    let v$0alue = Const::<true>;
 +}
 +"#,
 +        expect![[r#"
 +            *value*
 +
 +            ```rust
 +            let value: Const<true>
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn const_generic_char_literal() {
 +    check(
 +        r#"
 +struct Const<const C: char>;
 +
 +fn main() {
 +    let v$0alue = Const::<'🦀'>;
 +}
 +"#,
 +        expect![[r#"
 +            *value*
 +
 +            ```rust
 +            let value: Const<'🦀'>
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_self_param_shows_type() {
 +    check(
 +        r#"
 +struct Foo {}
 +impl Foo {
 +    fn bar(&sel$0f) {}
 +}
 +"#,
 +        expect![[r#"
 +                *self*
 +
 +                ```rust
 +                self: &Foo
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_self_param_shows_type_for_arbitrary_self_type() {
 +    check(
 +        r#"
 +struct Arc<T>(T);
 +struct Foo {}
 +impl Foo {
 +    fn bar(sel$0f: Arc<Foo>) {}
 +}
 +"#,
 +        expect![[r#"
 +                *self*
 +
 +                ```rust
 +                self: Arc<Foo>
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_doc_outer_inner() {
 +    check(
 +        r#"
 +/// Be quick;
 +mod Foo$0 {
 +    //! time is mana
 +
 +    /// This comment belongs to the function
 +    fn foo() {}
 +}
 +"#,
 +        expect![[r#"
 +                *Foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                mod Foo
 +                ```
 +
 +                ---
 +
 +                Be quick;
 +                time is mana
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_doc_outer_inner_attribue() {
 +    check(
 +        r#"
 +#[doc = "Be quick;"]
 +mod Foo$0 {
 +    #![doc = "time is mana"]
 +
 +    #[doc = "This comment belongs to the function"]
 +    fn foo() {}
 +}
 +"#,
 +        expect![[r#"
 +                *Foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                mod Foo
 +                ```
 +
 +                ---
 +
 +                Be quick;
 +                time is mana
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_doc_block_style_indentend() {
 +    check(
 +        r#"
 +/**
 +    foo
 +    ```rust
 +    let x = 3;
 +    ```
 +*/
 +fn foo$0() {}
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                fn foo()
 +                ```
 +
 +                ---
 +
 +                foo
 +
 +                ```rust
 +                let x = 3;
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_comments_dont_highlight_parent() {
 +    cov_mark::check!(no_highlight_on_comment_hover);
 +    check_hover_no_result(
 +        r#"
 +fn no_hover() {
 +    // no$0hover
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn hover_label() {
 +    check(
 +        r#"
 +fn foo() {
 +    'label$0: loop {}
 +}
 +"#,
 +        expect![[r#"
 +            *'label*
 +
 +            ```rust
 +            'label
 +            ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_lifetime() {
 +    check(
 +        r#"fn foo<'lifetime>(_: &'lifetime$0 ()) {}"#,
 +        expect![[r#"
 +            *'lifetime*
 +
 +            ```rust
 +            'lifetime
 +            ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_type_param() {
 +    check(
 +        r#"
 +//- minicore: sized
 +struct Foo<T>(T);
 +trait TraitA {}
 +trait TraitB {}
 +impl<T: TraitA + TraitB> Foo<T$0> where T: Sized {}
 +"#,
 +        expect![[r#"
 +                *T*
 +
 +                ```rust
 +                T: TraitA + TraitB
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +//- minicore: sized
 +struct Foo<T>(T);
 +impl<T> Foo<T$0> {}
 +"#,
 +        expect![[r#"
 +                *T*
 +
 +                ```rust
 +                T
 +                ```
 +                "#]],
 +    );
 +    // lifetimes bounds arent being tracked yet
 +    check(
 +        r#"
 +//- minicore: sized
 +struct Foo<T>(T);
 +impl<T: 'static> Foo<T$0> {}
 +"#,
 +        expect![[r#"
 +                *T*
 +
 +                ```rust
 +                T
 +                ```
 +                "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_type_param_sized_bounds() {
 +    // implicit `: Sized` bound
 +    check(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +struct Foo<T>(T);
 +impl<T: Trait> Foo<T$0> {}
 +"#,
 +        expect![[r#"
 +                *T*
 +
 +                ```rust
 +                T: Trait
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +struct Foo<T>(T);
 +impl<T: Trait + ?Sized> Foo<T$0> {}
 +"#,
 +        expect![[r#"
 +                *T*
 +
 +                ```rust
 +                T: Trait + ?Sized
 +                ```
 +            "#]],
 +    );
 +}
 +
 +mod type_param_sized_bounds {
 +    use super::*;
 +
 +    #[test]
 +    fn single_implicit() {
 +        check(
 +            r#"
 +//- minicore: sized
 +fn foo<T$0>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T
 +                    ```
 +                "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn single_explicit() {
 +        check(
 +            r#"
 +//- minicore: sized
 +fn foo<T$0: Sized>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T
 +                    ```
 +                "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn single_relaxed() {
 +        check(
 +            r#"
 +//- minicore: sized
 +fn foo<T$0: ?Sized>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T: ?Sized
 +                    ```
 +                "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn multiple_implicit() {
 +        check(
 +            r#"
 +//- minicore: sized
 +trait Trait {}
 +fn foo<T$0: Trait>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T: Trait
 +                    ```
 +                "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn multiple_explicit() {
 +        check(
 +            r#"
 +//- minicore: sized
 +trait Trait {}
 +fn foo<T$0: Trait + Sized>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T: Trait
 +                    ```
 +                "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn multiple_relaxed() {
 +        check(
 +            r#"
 +//- minicore: sized
 +trait Trait {}
 +fn foo<T$0: Trait + ?Sized>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T: Trait + ?Sized
 +                    ```
 +                "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn mixed() {
 +        check(
 +            r#"
 +//- minicore: sized
 +fn foo<T$0: ?Sized + Sized + Sized>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T
 +                    ```
 +                "#]],
 +        );
 +        check(
 +            r#"
 +//- minicore: sized
 +trait Trait {}
 +fn foo<T$0: Sized + ?Sized + Sized + Trait>() {}
 +"#,
 +            expect![[r#"
 +                    *T*
 +
 +                    ```rust
 +                    T: Trait
 +                    ```
 +                "#]],
 +        );
 +    }
 +}
 +
 +#[test]
 +fn hover_const_generic_type_alias() {
 +    check(
 +        r#"
 +struct Foo<const LEN: usize>;
 +type Fo$0o2 = Foo<2>;
 +"#,
 +        expect![[r#"
 +                *Foo2*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                type Foo2 = Foo<2>
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_const_param() {
 +    check(
 +        r#"
 +struct Foo<const LEN: usize>;
 +impl<const LEN: usize> Foo<LEN$0> {}
 +"#,
 +        expect![[r#"
 +                *LEN*
 +
 +                ```rust
 +                const LEN: usize
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_const_eval_variant() {
 +    // show hex for <10
 +    check(
 +        r#"
 +#[repr(u8)]
 +enum E {
 +    /// This is a doc
 +    A$0 = 1 << 3,
 +}
 +"#,
 +        expect![[r#"
 +            *A*
 +
 +            ```rust
 +            test::E
 +            ```
 +
 +            ```rust
 +            A = 8
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show hex for >10
 +    check(
 +        r#"
 +#[repr(u8)]
 +enum E {
 +    /// This is a doc
 +    A$0 = (1 << 3) + (1 << 2),
 +}
 +"#,
 +        expect![[r#"
 +            *A*
 +
 +            ```rust
 +            test::E
 +            ```
 +
 +            ```rust
 +            A = 12 (0xC)
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // enums in const eval
 +    check(
 +        r#"
 +#[repr(u8)]
 +enum E {
 +    A = 1,
 +    /// This is a doc
 +    B$0 = E::A as u8 + 1,
 +}
 +"#,
 +        expect![[r#"
 +            *B*
 +
 +            ```rust
 +            test::E
 +            ```
 +
 +            ```rust
 +            B = 2
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // unspecified variant should increment by one
 +    check(
 +        r#"
 +#[repr(u8)]
 +enum E {
 +    A = 4,
 +    /// This is a doc
 +    B$0,
 +}
 +"#,
 +        expect![[r#"
 +            *B*
 +
 +            ```rust
 +            test::E
 +            ```
 +
 +            ```rust
 +            B = 5
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_const_eval() {
 +    // show hex for <10
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: usize = 1 << 3;
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: usize = 8
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show hex for >10
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: usize = (1 << 3) + (1 << 2);
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: usize = 12 (0xC)
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show original body when const eval fails
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: usize = 2 - 3;
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: usize = 2 - 3
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // don't show hex for negatives
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: i32 = 2 - 3;
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: i32 = -1
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: &str = "bar";
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: &str = "bar"
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show char literal
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: char = 'a';
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: char = 'a'
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show escaped char literal
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: char = '\x61';
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: char = 'a'
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show byte literal
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: u8 = b'a';
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: u8 = 97 (0x61)
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show escaped byte literal
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: u8 = b'\x61';
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: u8 = 97 (0x61)
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    // show float literal
 +    check(
 +        r#"
 +    /// This is a doc
 +    const FOO$0: f64 = 1.0234;
 +    "#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: f64 = 1.0234
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    //show float typecasted from int
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: f32 = 1f32;
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: f32 = 1.0
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    //show f64 typecasted from float
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO$0: f64 = 1.0f64;
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: f64 = 1.0
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_const_pat() {
 +    check(
 +        r#"
 +/// This is a doc
 +const FOO: usize = 3;
 +fn foo() {
 +    match 5 {
 +        FOO$0 => (),
 +        _ => ()
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            *FOO*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            const FOO: usize = 3
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +    check(
 +        r#"
 +enum E {
 +    /// This is a doc
 +    A = 3,
 +}
 +fn foo(e: E) {
 +    match e {
 +        E::A$0 => (),
 +        _ => ()
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            *A*
 +
 +            ```rust
 +            test::E
 +            ```
 +
 +            ```rust
 +            A = 3
 +            ```
 +
 +            ---
 +
 +            This is a doc
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn array_repeat_exp() {
 +    check(
 +        r#"
 +fn main() {
 +    let til$0e4 = [0_u32; (4 * 8 * 8) / 32];
 +}
 +        "#,
 +        expect![[r#"
 +            *tile4*
 +
 +            ```rust
 +            let tile4: [u32; 8]
 +            ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_mod_def() {
 +    check(
 +        r#"
 +//- /main.rs
 +mod foo$0;
 +//- /foo.rs
 +//! For the horde!
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                mod foo
 +                ```
 +
 +                ---
 +
 +                For the horde!
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_self_in_use() {
 +    check(
 +        r#"
 +//! This should not appear
 +mod foo {
 +    /// But this should appear
 +    pub mod bar {}
 +}
 +use foo::bar::{self$0};
 +"#,
 +        expect![[r#"
 +                *self*
 +
 +                ```rust
 +                test::foo
 +                ```
 +
 +                ```rust
 +                mod bar
 +                ```
 +
 +                ---
 +
 +                But this should appear
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_keyword() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:std
 +fn f() { retur$0n; }
 +//- /libstd.rs crate:std
 +/// Docs for return_keyword
 +mod return_keyword {}
 +"#,
 +        expect![[r#"
 +                *return*
 +
 +                ```rust
 +                return
 +                ```
 +
 +                ---
 +
 +                Docs for return_keyword
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_keyword_doc() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:std
 +fn foo() {
 +    let bar = mov$0e || {};
 +}
 +//- /libstd.rs crate:std
 +#[doc(keyword = "move")]
 +/// [closure]
 +/// [closures][closure]
 +/// [threads]
 +/// <https://doc.rust-lang.org/nightly/book/ch13-01-closures.html>
 +///
 +/// [closure]: ../book/ch13-01-closures.html
 +/// [threads]: ../book/ch16-01-threads.html#using-move-closures-with-threads
 +mod move_keyword {}
 +"#,
 +        expect![[r##"
 +            *move*
 +
 +            ```rust
 +            move
 +            ```
 +
 +            ---
 +
 +            [closure](https://doc.rust-lang.org/nightly/book/ch13-01-closures.html)
 +            [closures](https://doc.rust-lang.org/nightly/book/ch13-01-closures.html)
 +            [threads](https://doc.rust-lang.org/nightly/book/ch16-01-threads.html#using-move-closures-with-threads)
 +            <https://doc.rust-lang.org/nightly/book/ch13-01-closures.html>
 +        "##]],
 +    );
 +}
 +
 +#[test]
 +fn hover_keyword_as_primitive() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:std
 +type F = f$0n(i32) -> i32;
 +//- /libstd.rs crate:std
 +/// Docs for prim_fn
 +mod prim_fn {}
 +"#,
 +        expect![[r#"
 +                *fn*
 +
 +                ```rust
 +                fn
 +                ```
 +
 +                ---
 +
 +                Docs for prim_fn
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_builtin() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:std
 +cosnt _: &str$0 = ""; }
 +
 +//- /libstd.rs crate:std
 +/// Docs for prim_str
 +/// [`foo`](../std/keyword.foo.html)
 +mod prim_str {}
 +"#,
 +        expect![[r#"
 +                *str*
 +
 +                ```rust
 +                str
 +                ```
 +
 +                ---
 +
 +                Docs for prim_str
 +                [`foo`](https://doc.rust-lang.org/nightly/std/keyword.foo.html)
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_macro_expanded_function() {
 +    check(
 +        r#"
 +struct S<'a, T>(&'a T);
 +trait Clone {}
 +macro_rules! foo {
 +    () => {
 +        fn bar<'t, T: Clone + 't>(s: &mut S<'t, T>, t: u32) -> *mut u32 where
 +            't: 't + 't,
 +            for<'a> T: Clone + 'a
 +        { 0 as _ }
 +    };
 +}
 +
 +foo!();
 +
 +fn main() {
 +    bar$0;
 +}
 +"#,
 +        expect![[r#"
 +                *bar*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32
 +                where
 +                    T: Clone + 't,
 +                    't: 't + 't,
 +                    for<'a> T: Clone + 'a,
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_intra_doc_links() {
 +    check(
 +        r#"
 +
 +pub mod theitem {
 +    /// This is the item. Cool!
 +    pub struct TheItem;
 +}
 +
 +/// Gives you a [`TheItem$0`].
 +///
 +/// [`TheItem`]: theitem::TheItem
 +pub fn gimme() -> theitem::TheItem {
 +    theitem::TheItem
 +}
 +"#,
 +        expect![[r#"
 +                *[`TheItem`]*
 +
 +                ```rust
 +                test::theitem
 +                ```
 +
 +                ```rust
 +                pub struct TheItem
 +                ```
 +
 +                ---
 +
 +                This is the item. Cool!
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn test_hover_trait_assoc_typealias() {
 +    check(
 +        r#"
 +        fn main() {}
 +
 +trait T1 {
 +    type Bar;
 +    type Baz;
 +}
 +
 +struct Foo;
 +
 +mod t2 {
 +    pub trait T2 {
 +        type Bar;
 +    }
 +}
 +
 +use t2::T2;
 +
 +impl T2 for Foo {
 +    type Bar = String;
 +}
 +
 +impl T1 for Foo {
 +    type Bar = <Foo as t2::T2>::Ba$0r;
 +    //                          ^^^ unresolvedReference
 +}
 +        "#,
 +        expect![[r#"
 +*Bar*
 +
 +```rust
 +test::t2
 +```
 +
 +```rust
 +pub type Bar
 +```
 +"#]],
 +    );
 +}
 +#[test]
 +fn hover_generic_assoc() {
 +    check(
 +        r#"
 +fn foo<T: A>() where T::Assoc$0: {}
 +
 +trait A {
 +    type Assoc;
 +}"#,
 +        expect![[r#"
 +                *Assoc*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                type Assoc
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +fn foo<T: A>() {
 +    let _: <T>::Assoc$0;
 +}
 +
 +trait A {
 +    type Assoc;
 +}"#,
 +        expect![[r#"
 +                *Assoc*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                type Assoc
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +trait A where
 +    Self::Assoc$0: ,
 +{
 +    type Assoc;
 +}"#,
 +        expect![[r#"
 +                *Assoc*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                type Assoc
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn string_shadowed_with_inner_items() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:alloc
 +
 +/// Custom `String` type.
 +struct String;
 +
 +fn f() {
 +    let _: String$0;
 +
 +    fn inner() {}
 +}
 +
 +//- /alloc.rs crate:alloc
 +#[prelude_import]
 +pub use string::*;
 +
 +mod string {
 +    /// This is `alloc::String`.
 +    pub struct String;
 +}
 +"#,
 +        expect![[r#"
 +                *String*
 +
 +                ```rust
 +                main
 +                ```
 +
 +                ```rust
 +                struct String
 +                ```
 +
 +                ---
 +
 +                Custom `String` type.
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn function_doesnt_shadow_crate_in_use_tree() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:foo
 +use foo$0::{foo};
 +
 +//- /foo.rs crate:foo
 +pub fn foo() {}
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                extern crate foo
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_feature() {
 +    check(
 +        r#"#![feature(box_syntax$0)]"#,
 +        expect![[r##"
 +                *box_syntax*
 +                ```
 +                box_syntax
 +                ```
 +                ___
 +
 +                # `box_syntax`
 +
 +                The tracking issue for this feature is: [#49733]
 +
 +                [#49733]: https://github.com/rust-lang/rust/issues/49733
 +
 +                See also [`box_patterns`](box-patterns.md)
 +
 +                ------------------------
 +
 +                Currently the only stable way to create a `Box` is via the `Box::new` method.
 +                Also it is not possible in stable Rust to destructure a `Box` in a match
 +                pattern. The unstable `box` keyword can be used to create a `Box`. An example
 +                usage would be:
 +
 +                ```rust
 +                #![feature(box_syntax)]
 +
 +                fn main() {
 +                    let b = box 5;
 +                }
 +                ```
 +
 +            "##]],
 +    )
 +}
 +
 +#[test]
 +fn hover_lint() {
 +    check(
 +        r#"#![allow(arithmetic_overflow$0)]"#,
 +        expect![[r#"
 +                *arithmetic_overflow*
 +                ```
 +                arithmetic_overflow
 +                ```
 +                ___
 +
 +                arithmetic operation overflows
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_clippy_lint() {
 +    check(
 +        r#"#![allow(clippy::almost_swapped$0)]"#,
 +        expect![[r#"
 +                *almost_swapped*
 +                ```
 +                clippy::almost_swapped
 +                ```
 +                ___
 +
 +                Checks for `foo = bar; bar = foo` sequences.
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_attr_path_qualifier() {
 +    check(
 +        r#"
 +//- /foo.rs crate:foo
 +
 +//- /lib.rs crate:main.rs deps:foo
 +#[fo$0o::bar()]
 +struct Foo;
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                extern crate foo
 +                ```
 +            "#]],
 +    )
 +}
 +
 +#[test]
 +fn hover_rename() {
 +    check(
 +        r#"
 +use self as foo$0;
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                extern crate test
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +mod bar {}
 +use bar::{self as foo$0};
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                test
 +                ```
 +
 +                ```rust
 +                mod bar
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +mod bar {
 +    use super as foo$0;
 +}
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                extern crate test
 +                ```
 +            "#]],
 +    );
 +    check(
 +        r#"
 +use crate as foo$0;
 +"#,
 +        expect![[r#"
 +                *foo*
 +
 +                ```rust
 +                extern crate test
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_attribute_in_macro() {
 +    check(
 +        r#"
 +//- minicore:derive
 +macro_rules! identity {
 +    ($struct:item) => {
 +        $struct
 +    };
 +}
 +#[rustc_builtin_macro]
 +pub macro Copy {}
 +identity!{
 +    #[derive(Copy$0)]
 +    struct Foo;
 +}
 +"#,
 +        expect![[r#"
 +            *Copy*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            macro Copy
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_derive_input() {
 +    check(
 +        r#"
 +//- minicore:derive
 +#[rustc_builtin_macro]
 +pub macro Copy {}
 +#[derive(Copy$0)]
 +struct Foo;
 +"#,
 +        expect![[r#"
 +            *Copy*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            macro Copy
 +            ```
 +        "#]],
 +    );
 +    check(
 +        r#"
 +//- minicore:derive
 +mod foo {
 +    #[rustc_builtin_macro]
 +    pub macro Copy {}
 +}
 +#[derive(foo::Copy$0)]
 +struct Foo;
 +"#,
 +        expect![[r#"
 +            *Copy*
 +
 +            ```rust
 +            test::foo
 +            ```
 +
 +            ```rust
 +            macro Copy
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_range_math() {
 +    check_hover_range(
 +        r#"
 +fn f() { let expr = $01 + 2 * 3$0 }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            i32
 +            ```"#]],
 +    );
 +
 +    check_hover_range(
 +        r#"
 +fn f() { let expr = 1 $0+ 2 * $03 }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            i32
 +            ```"#]],
 +    );
 +
 +    check_hover_range(
 +        r#"
 +fn f() { let expr = 1 + $02 * 3$0 }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            i32
 +            ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_range_arrays() {
 +    check_hover_range(
 +        r#"
 +fn f() { let expr = $0[1, 2, 3, 4]$0 }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            [i32; 4]
 +            ```"#]],
 +    );
 +
 +    check_hover_range(
 +        r#"
 +fn f() { let expr = [1, 2, $03, 4]$0 }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            [i32; 4]
 +            ```"#]],
 +    );
 +
 +    check_hover_range(
 +        r#"
 +fn f() { let expr = [1, 2, $03$0, 4] }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            i32
 +            ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_range_functions() {
 +    check_hover_range(
 +        r#"
 +fn f<T>(a: &[T]) { }
 +fn b() { $0f$0(&[1, 2, 3, 4, 5]); }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            fn f<i32>(&[i32])
 +            ```"#]],
 +    );
 +
 +    check_hover_range(
 +        r#"
 +fn f<T>(a: &[T]) { }
 +fn b() { f($0&[1, 2, 3, 4, 5]$0); }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            &[i32; 5]
 +            ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_range_shows_nothing_when_invalid() {
 +    check_hover_range_no_results(
 +        r#"
 +fn f<T>(a: &[T]) { }
 +fn b()$0 { f(&[1, 2, 3, 4, 5]); }$0
 +"#,
 +    );
 +
 +    check_hover_range_no_results(
 +        r#"
 +fn f<T>$0(a: &[T]) { }
 +fn b() { f(&[1, 2, 3,$0 4, 5]); }
 +"#,
 +    );
 +
 +    check_hover_range_no_results(
 +        r#"
 +fn $0f() { let expr = [1, 2, 3, 4]$0 }
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn hover_range_shows_unit_for_statements() {
 +    check_hover_range(
 +        r#"
 +fn f<T>(a: &[T]) { }
 +fn b() { $0f(&[1, 2, 3, 4, 5]); }$0
 +"#,
 +        expect![[r#"
 +            ```rust
 +            ()
 +            ```"#]],
 +    );
 +
 +    check_hover_range(
 +        r#"
 +fn f() { let expr$0 = $0[1, 2, 3, 4] }
 +"#,
 +        expect![[r#"
 +            ```rust
 +            ()
 +            ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_range_for_pat() {
 +    check_hover_range(
 +        r#"
 +fn foo() {
 +    let $0x$0 = 0;
 +}
 +"#,
 +        expect![[r#"
 +                ```rust
 +                i32
 +                ```"#]],
 +    );
 +
 +    check_hover_range(
 +        r#"
 +fn foo() {
 +    let $0x$0 = "";
 +}
 +"#,
 +        expect![[r#"
 +                ```rust
 +                &str
 +                ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_range_shows_coercions_if_applicable_expr() {
 +    check_hover_range(
 +        r#"
 +fn foo() {
 +    let x: &u32 = $0&&&&&0$0;
 +}
 +"#,
 +        expect![[r#"
 +                ```text
 +                Type:       &&&&&u32
 +                Coerced to:     &u32
 +                ```
 +            "#]],
 +    );
 +    check_hover_range(
 +        r#"
 +fn foo() {
 +    let x: *const u32 = $0&0$0;
 +}
 +"#,
 +        expect![[r#"
 +                ```text
 +                Type:             &u32
 +                Coerced to: *const u32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_range_shows_type_actions() {
 +    check_actions(
 +        r#"
 +struct Foo;
 +fn foo() {
 +    let x: &Foo = $0&&&&&Foo$0;
 +}
 +"#,
 +        expect![[r#"
 +                [
 +                    GoToType(
 +                        [
 +                            HoverGotoTypeData {
 +                                mod_path: "test::Foo",
 +                                nav: NavigationTarget {
 +                                    file_id: FileId(
 +                                        0,
 +                                    ),
 +                                    full_range: 0..11,
 +                                    focus_range: 7..10,
 +                                    name: "Foo",
 +                                    kind: Struct,
 +                                    description: "struct Foo",
 +                                },
 +                            },
 +                        ],
 +                    ),
 +                ]
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_try_expr_res() {
 +    check_hover_range(
 +        r#"
 +//- minicore:result
 +struct FooError;
 +
 +fn foo() -> Result<(), FooError> {
 +    Ok($0Result::<(), FooError>::Ok(())?$0)
 +}
 +"#,
 +        expect![[r#"
 +                ```rust
 +                ()
 +                ```"#]],
 +    );
 +    check_hover_range(
 +        r#"
 +//- minicore:result
 +struct FooError;
 +struct BarError;
 +
 +fn foo() -> Result<(), FooError> {
 +    Ok($0Result::<(), BarError>::Ok(())?$0)
 +}
 +"#,
 +        expect![[r#"
 +                ```text
 +                Try Error Type: BarError
 +                Propagated as:  FooError
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_try_expr() {
 +    check_hover_range(
 +        r#"
 +struct NotResult<T, U>(T, U);
 +struct Short;
 +struct Looooong;
 +
 +fn foo() -> NotResult<(), Looooong> {
 +    $0NotResult((), Short)?$0;
 +}
 +"#,
 +        expect![[r#"
 +                ```text
 +                Try Target Type:    NotResult<(), Short>
 +                Propagated as:   NotResult<(), Looooong>
 +                ```
 +            "#]],
 +    );
 +    check_hover_range(
 +        r#"
 +struct NotResult<T, U>(T, U);
 +struct Short;
 +struct Looooong;
 +
 +fn foo() -> NotResult<(), Short> {
 +    $0NotResult((), Looooong)?$0;
 +}
 +"#,
 +        expect![[r#"
 +                ```text
 +                Try Target Type: NotResult<(), Looooong>
 +                Propagated as:      NotResult<(), Short>
 +                ```
 +            "#]],
 +    );
++    check_hover_range(
++        r#"
++//- minicore: try
++use core::ops::ControlFlow;
++fn foo() -> ControlFlow<()> {
++    $0ControlFlow::Break(())?$0;
++    ControlFlow::Continue(())
++}
++"#,
++        expect![[r#"
++            ```text
++            Try Target Type: ControlFlow<(), {unknown}>
++            Propagated as:          ControlFlow<(), ()>
++            ```
++        "#]],
++    );
 +}
 +
 +#[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
++            i32
++            ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_deref_expr() {
 +    check_hover_range(
 +        r#"
 +//- minicore: deref
 +use core::ops::Deref;
 +
 +struct DerefExample<T> {
 +    value: T
 +}
 +
 +impl<T> Deref for DerefExample<T> {
 +    type Target = T;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.value
 +    }
 +}
 +
 +fn foo() {
 +    let x = DerefExample { value: 0 };
 +    let y: i32 = $0*x$0;
 +}
 +"#,
 +        expect![[r#"
 +                ```text
 +                Dereferenced from: DerefExample<i32>
 +                To type:                         i32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_deref_expr_with_coercion() {
 +    check_hover_range(
 +        r#"
 +//- minicore: deref
 +use core::ops::Deref;
 +
 +struct DerefExample<T> {
 +    value: T
 +}
 +
 +impl<T> Deref for DerefExample<T> {
 +    type Target = T;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.value
 +    }
 +}
 +
 +fn foo() {
 +    let x = DerefExample { value: &&&&&0 };
 +    let y: &i32 = $0*x$0;
 +}
 +"#,
 +        expect![[r#"
 +                ```text
 +                Dereferenced from: DerefExample<&&&&&i32>
 +                To type:                         &&&&&i32
 +                Coerced to:                          &i32
 +                ```
 +            "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_intra_in_macro() {
 +    check(
 +        r#"
 +macro_rules! foo_macro {
 +    ($(#[$attr:meta])* $name:ident) => {
 +        $(#[$attr])*
 +        pub struct $name;
 +    }
 +}
 +
 +foo_macro!(
 +    /// Doc comment for [`Foo$0`]
 +    Foo
 +);
 +"#,
 +        expect![[r#"
 +            *[`Foo`]*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            pub struct Foo
 +            ```
 +
 +            ---
 +
 +            Doc comment for [`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_intra_in_attr() {
 +    check(
 +        r#"
 +#[doc = "Doc comment for [`Foo$0`]"]
 +pub struct Foo;
 +"#,
 +        expect![[r#"
 +            *[`Foo`]*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            pub struct Foo
 +            ```
 +
 +            ---
 +
 +            Doc comment for [`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_inert_attr() {
 +    check(
 +        r#"
 +#[doc$0 = ""]
 +pub struct Foo;
 +"#,
 +        expect![[r##"
 +            *doc*
 +
 +            ```rust
 +            #[doc]
 +            ```
 +
 +            ---
 +
 +            Valid forms are:
 +
 +            * \#\[doc(hidden|inline|...)\]
 +            * \#\[doc = string\]
 +        "##]],
 +    );
 +    check(
 +        r#"
 +#[allow$0()]
 +pub struct Foo;
 +"#,
 +        expect![[r##"
 +            *allow*
 +
 +            ```rust
 +            #[allow]
 +            ```
 +
 +            ---
 +
 +            Valid forms are:
 +
 +            * \#\[allow(lint1, lint2, ..., /\*opt\*/ reason = "...")\]
 +        "##]],
 +    );
 +}
 +
 +#[test]
 +fn hover_dollar_crate() {
 +    // $crate should be resolved to the right crate name.
 +
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:dep
 +dep::m!(KONST$0);
 +//- /dep.rs crate:dep
 +#[macro_export]
 +macro_rules! m {
 +    ( $name:ident ) => { const $name: $crate::Type = $crate::Type; };
 +}
 +
 +pub struct Type;
 +"#,
 +        expect![[r#"
 +            *KONST*
 +
 +            ```rust
 +            main
 +            ```
 +
 +            ```rust
 +            const KONST: dep::Type = $crate::Type
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_record_variant() {
 +    check(
 +        r#"
 +enum Enum {
 +    RecordV$0 { field: u32 }
 +}
 +"#,
 +        expect![[r#"
 +            *RecordV*
 +
 +            ```rust
 +            test::Enum
 +            ```
 +
 +            ```rust
 +            RecordV { field: u32 }
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_trait_impl_assoc_item_def_doc_forwarding() {
 +    check(
 +        r#"
 +trait T {
 +    /// Trait docs
 +    fn func() {}
 +}
 +impl T for () {
 +    fn func$0() {}
 +}
 +"#,
 +        expect![[r#"
 +            *func*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            fn func()
 +            ```
 +
 +            ---
 +
 +            Trait docs
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_ranged_macro_call() {
 +    check_hover_range(
 +        r#"
 +macro_rules! __rust_force_expr {
 +    ($e:expr) => {
 +        $e
 +    };
 +}
 +macro_rules! vec {
 +    ($elem:expr) => {
 +        __rust_force_expr!($elem)
 +    };
 +}
 +
 +struct Struct;
 +impl Struct {
 +    fn foo(self) {}
 +}
 +
 +fn f() {
 +    $0vec![Struct]$0;
 +}
 +"#,
 +        expect![[r#"
 +            ```rust
 +            Struct
 +            ```"#]],
 +    );
 +}
 +
 +#[test]
 +fn hover_deref() {
 +    check(
 +        r#"
 +//- minicore: deref
 +
 +struct Struct(usize);
 +
 +impl core::ops::Deref for Struct {
 +    type Target = usize;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.0
 +    }
 +}
 +
 +fn f() {
 +    $0*Struct(0);
 +}
 +"#,
 +        expect![[r#"
 +            ***
 +
 +            ```rust
 +            test::Struct
 +            ```
 +
 +            ```rust
 +            fn deref(&self) -> &Self::Target
 +            ```
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn static_const_macro_expanded_body() {
 +    check(
 +        r#"
 +macro_rules! m {
 +    () => {
 +        pub const V: i8 = {
 +            let e = 123;
 +            f(e) // Prevent const eval from evaluating this constant, we want to print the body's code.
 +        };
 +    };
 +}
 +m!();
 +fn main() { $0V; }
 +"#,
 +        expect![[r#"
 +            *V*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            pub const V: i8 = {
 +              let e = 123;
 +              f(e)
 +            }
 +            ```
 +        "#]],
 +    );
 +    check(
 +        r#"
 +macro_rules! m {
 +    () => {
 +        pub static V: i8 = {
 +            let e = 123;
 +        };
 +    };
 +}
 +m!();
 +fn main() { $0V; }
 +"#,
 +        expect![[r#"
 +            *V*
 +
 +            ```rust
 +            test
 +            ```
 +
 +            ```rust
 +            pub static V: i8 = {
 +              let e = 123;
 +            }
 +            ```
 +        "#]],
 +    );
 +}
index 5ff3448a19ca788da78aff98bf718d9695933a38,0000000000000000000000000000000000000000..13cd8901031d526c91c7d9561a8e647e0d738242
mode 100644,000000..100644
--- /dev/null
@@@ -1,24 -1,0 +1,24 @@@
- smallvec = "1.9.0"
 +[package]
 +name = "mbe"
 +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"
 +rustc-hash = "1.1.0"
++smallvec = "1.10.0"
 +tracing = "0.1.35"
 +
 +syntax = { path = "../syntax", version = "0.0.0" }
 +parser = { path = "../parser", version = "0.0.0" }
 +tt = { path = "../tt", version = "0.0.0" }
 +stdx = { path = "../stdx", version = "0.0.0" }
 +
 +[dev-dependencies]
 +test-utils = { path = "../test-utils" }
index ac691578d88738bc6ee7e686603a5f88a715aa7d,0000000000000000000000000000000000000000..9c92bae6a1962d593219c3d869bb0c454967ec78
mode 100644,000000..100644
--- /dev/null
@@@ -1,222 -1,0 +1,222 @@@
-     parser::{Op, RepeatKind, Separator},
 +//! This module add real world mbe example for benchmark tests
 +
 +use rustc_hash::FxHashMap;
 +use syntax::{
 +    ast::{self, HasName},
 +    AstNode, SmolStr,
 +};
 +use test_utils::{bench, bench_fixture, skip_slow_tests};
 +
 +use crate::{
-             Op::Var { kind, .. } => match kind.as_ref().map(|it| it.as_str()) {
-                 Some("ident") => parent.token_trees.push(make_ident("foo")),
-                 Some("ty") => parent.token_trees.push(make_ident("Foo")),
-                 Some("tt") => parent.token_trees.push(make_ident("foo")),
-                 Some("vis") => parent.token_trees.push(make_ident("pub")),
-                 Some("pat") => parent.token_trees.push(make_ident("foo")),
-                 Some("path") => parent.token_trees.push(make_ident("foo")),
-                 Some("literal") => parent.token_trees.push(make_literal("1")),
-                 Some("expr") => parent.token_trees.push(make_ident("foo")),
-                 Some("lifetime") => {
++    parser::{MetaVarKind, Op, RepeatKind, Separator},
 +    syntax_node_to_token_tree, DeclarativeMacro,
 +};
 +
 +#[test]
 +fn benchmark_parse_macro_rules() {
 +    if skip_slow_tests() {
 +        return;
 +    }
 +    let rules = macro_rules_fixtures_tt();
 +    let hash: usize = {
 +        let _pt = bench("mbe parse macro rules");
 +        rules.values().map(|it| DeclarativeMacro::parse_macro_rules(it).unwrap().rules.len()).sum()
 +    };
 +    assert_eq!(hash, 1144);
 +}
 +
 +#[test]
 +fn benchmark_expand_macro_rules() {
 +    if skip_slow_tests() {
 +        return;
 +    }
 +    let rules = macro_rules_fixtures();
 +    let invocations = invocation_fixtures(&rules);
 +
 +    let hash: usize = {
 +        let _pt = bench("mbe expand macro rules");
 +        invocations
 +            .into_iter()
 +            .map(|(id, tt)| {
 +                let res = rules[&id].expand(&tt);
 +                assert!(res.err.is_none());
 +                res.value.token_trees.len()
 +            })
 +            .sum()
 +    };
 +    assert_eq!(hash, 69413);
 +}
 +
 +fn macro_rules_fixtures() -> FxHashMap<String, DeclarativeMacro> {
 +    macro_rules_fixtures_tt()
 +        .into_iter()
 +        .map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt).unwrap()))
 +        .collect()
 +}
 +
 +fn macro_rules_fixtures_tt() -> FxHashMap<String, tt::Subtree> {
 +    let fixture = bench_fixture::numerous_macro_rules();
 +    let source_file = ast::SourceFile::parse(&fixture).ok().unwrap();
 +
 +    source_file
 +        .syntax()
 +        .descendants()
 +        .filter_map(ast::MacroRules::cast)
 +        .map(|rule| {
 +            let id = rule.name().unwrap().to_string();
 +            let (def_tt, _) = syntax_node_to_token_tree(rule.token_tree().unwrap().syntax());
 +            (id, def_tt)
 +        })
 +        .collect()
 +}
 +
 +/// Generate random invocation fixtures from rules
 +fn invocation_fixtures(rules: &FxHashMap<String, DeclarativeMacro>) -> Vec<(String, tt::Subtree)> {
 +    let mut seed = 123456789;
 +    let mut res = Vec::new();
 +
 +    for (name, it) in rules {
 +        for rule in &it.rules {
 +            // Generate twice
 +            for _ in 0..2 {
 +                // The input are generated by filling the `Op` randomly.
 +                // However, there are some cases generated are ambiguous for expanding, for example:
 +                // ```rust
 +                // macro_rules! m {
 +                //    ($($t:ident),* as $ty:ident) => {}
 +                // }
 +                // m!(as u32);  // error: local ambiguity: multiple parsing options: built-in NTs ident ('t') or 1 other option.
 +                // ```
 +                //
 +                // So we just skip any error cases and try again
 +                let mut try_cnt = 0;
 +                loop {
 +                    let mut subtree = tt::Subtree::default();
 +                    for op in rule.lhs.iter() {
 +                        collect_from_op(op, &mut subtree, &mut seed);
 +                    }
 +                    if it.expand(&subtree).err.is_none() {
 +                        res.push((name.clone(), subtree));
 +                        break;
 +                    }
 +                    try_cnt += 1;
 +                    if try_cnt > 100 {
 +                        panic!("invocaton fixture {} cannot be generated.\n", name);
 +                    }
 +                }
 +            }
 +        }
 +    }
 +    return res;
 +
 +    fn collect_from_op(op: &Op, parent: &mut tt::Subtree, seed: &mut usize) {
 +        return match op {
-                 Some("block") => {
++            Op::Var { kind, .. } => match kind.as_ref() {
++                Some(MetaVarKind::Ident) => parent.token_trees.push(make_ident("foo")),
++                Some(MetaVarKind::Ty) => parent.token_trees.push(make_ident("Foo")),
++                Some(MetaVarKind::Tt) => parent.token_trees.push(make_ident("foo")),
++                Some(MetaVarKind::Vis) => parent.token_trees.push(make_ident("pub")),
++                Some(MetaVarKind::Pat) => parent.token_trees.push(make_ident("foo")),
++                Some(MetaVarKind::Path) => parent.token_trees.push(make_ident("foo")),
++                Some(MetaVarKind::Literal) => parent.token_trees.push(make_literal("1")),
++                Some(MetaVarKind::Expr) => parent.token_trees.push(make_ident("foo")),
++                Some(MetaVarKind::Lifetime) => {
 +                    parent.token_trees.push(make_punct('\''));
 +                    parent.token_trees.push(make_ident("a"));
 +                }
-                 Some("item") => {
++                Some(MetaVarKind::Block) => {
 +                    parent.token_trees.push(make_subtree(tt::DelimiterKind::Brace, None))
 +                }
-                 Some("meta") => {
++                Some(MetaVarKind::Item) => {
 +                    parent.token_trees.push(make_ident("fn"));
 +                    parent.token_trees.push(make_ident("foo"));
 +                    parent.token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
 +                    parent.token_trees.push(make_subtree(tt::DelimiterKind::Brace, None));
 +                }
-                 Some(kind) => panic!("Unhandled kind {}", kind),
++                Some(MetaVarKind::Meta) => {
 +                    parent.token_trees.push(make_ident("foo"));
 +                    parent.token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
 +                }
 +
 +                None => (),
++                Some(kind) => panic!("Unhandled kind {:?}", kind),
 +            },
 +            Op::Leaf(leaf) => parent.token_trees.push(leaf.clone().into()),
 +            Op::Repeat { tokens, kind, separator } => {
 +                let max = 10;
 +                let cnt = match kind {
 +                    RepeatKind::ZeroOrMore => rand(seed) % max,
 +                    RepeatKind::OneOrMore => 1 + rand(seed) % max,
 +                    RepeatKind::ZeroOrOne => rand(seed) % 2,
 +                };
 +                for i in 0..cnt {
 +                    for it in tokens.iter() {
 +                        collect_from_op(it, parent, seed);
 +                    }
 +                    if i + 1 != cnt {
 +                        if let Some(sep) = separator {
 +                            match sep {
 +                                Separator::Literal(it) => {
 +                                    parent.token_trees.push(tt::Leaf::Literal(it.clone()).into())
 +                                }
 +                                Separator::Ident(it) => {
 +                                    parent.token_trees.push(tt::Leaf::Ident(it.clone()).into())
 +                                }
 +                                Separator::Puncts(puncts) => {
 +                                    for it in puncts {
 +                                        parent.token_trees.push(tt::Leaf::Punct(*it).into())
 +                                    }
 +                                }
 +                            };
 +                        }
 +                    }
 +                }
 +            }
 +            Op::Subtree { tokens, delimiter } => {
 +                let mut subtree = tt::Subtree { delimiter: *delimiter, token_trees: Vec::new() };
 +                tokens.iter().for_each(|it| {
 +                    collect_from_op(it, &mut subtree, seed);
 +                });
 +                parent.token_trees.push(subtree.into());
 +            }
 +            Op::Ignore { .. } | Op::Index { .. } => {}
 +        };
 +
 +        // Simple linear congruential generator for determistic result
 +        fn rand(seed: &mut usize) -> usize {
 +            let a = 1664525;
 +            let c = 1013904223;
 +            *seed = usize::wrapping_add(usize::wrapping_mul(*seed, a), c);
 +            *seed
 +        }
 +        fn make_ident(ident: &str) -> tt::TokenTree {
 +            tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), text: SmolStr::new(ident) })
 +                .into()
 +        }
 +        fn make_punct(char: char) -> tt::TokenTree {
 +            tt::Leaf::Punct(tt::Punct {
 +                id: tt::TokenId::unspecified(),
 +                char,
 +                spacing: tt::Spacing::Alone,
 +            })
 +            .into()
 +        }
 +        fn make_literal(lit: &str) -> tt::TokenTree {
 +            tt::Leaf::Literal(tt::Literal {
 +                id: tt::TokenId::unspecified(),
 +                text: SmolStr::new(lit),
 +            })
 +            .into()
 +        }
 +        fn make_subtree(
 +            kind: tt::DelimiterKind,
 +            token_trees: Option<Vec<tt::TokenTree>>,
 +        ) -> tt::TokenTree {
 +            tt::Subtree {
 +                delimiter: Some(tt::Delimiter { id: tt::TokenId::unspecified(), kind }),
 +                token_trees: token_trees.unwrap_or_default(),
 +            }
 +            .into()
 +        }
 +    }
 +}
index 1e1bfa55055831a2fa2b8cb9affaa2c2f3e5a06e,0000000000000000000000000000000000000000..100ec6bfb93ac17e3cf0006c8c65ed78c5e7b646
mode 100644,000000..100644
--- /dev/null
@@@ -1,121 -1,0 +1,122 @@@
- use crate::{ExpandError, ExpandResult};
 +//! This module takes a (parsed) definition of `macro_rules` invocation, a
 +//! `tt::TokenTree` representing an argument of macro invocation, and produces a
 +//! `tt::TokenTree` for the result of the expansion.
 +
 +mod matcher;
 +mod transcriber;
 +
 +use rustc_hash::FxHashMap;
 +use syntax::SmolStr;
 +
++use crate::{parser::MetaVarKind, ExpandError, ExpandResult};
 +
 +pub(crate) fn expand_rules(
 +    rules: &[crate::Rule],
 +    input: &tt::Subtree,
 +) -> ExpandResult<tt::Subtree> {
 +    let mut match_: Option<(matcher::Match, &crate::Rule)> = None;
 +    for rule in rules {
 +        let new_match = matcher::match_(&rule.lhs, input);
 +
 +        if new_match.err.is_none() {
 +            // If we find a rule that applies without errors, we're done.
 +            // Unconditionally returning the transcription here makes the
 +            // `test_repeat_bad_var` test fail.
 +            let ExpandResult { value, err: transcribe_err } =
 +                transcriber::transcribe(&rule.rhs, &new_match.bindings);
 +            if transcribe_err.is_none() {
 +                return ExpandResult::ok(value);
 +            }
 +        }
 +        // Use the rule if we matched more tokens, or bound variables count
 +        if let Some((prev_match, _)) = &match_ {
 +            if (new_match.unmatched_tts, -(new_match.bound_count as i32))
 +                < (prev_match.unmatched_tts, -(prev_match.bound_count as i32))
 +            {
 +                match_ = Some((new_match, rule));
 +            }
 +        } else {
 +            match_ = Some((new_match, rule));
 +        }
 +    }
 +    if let Some((match_, rule)) = match_ {
 +        // if we got here, there was no match without errors
 +        let ExpandResult { value, err: transcribe_err } =
 +            transcriber::transcribe(&rule.rhs, &match_.bindings);
 +        ExpandResult { value, err: match_.err.or(transcribe_err) }
 +    } else {
 +        ExpandResult::only_err(ExpandError::NoMatchingRule)
 +    }
 +}
 +
 +/// The actual algorithm for expansion is not too hard, but is pretty tricky.
 +/// `Bindings` structure is the key to understanding what we are doing here.
 +///
 +/// On the high level, it stores mapping from meta variables to the bits of
 +/// syntax it should be substituted with. For example, if `$e:expr` is matched
 +/// with `1 + 1` by macro_rules, the `Binding` will store `$e -> 1 + 1`.
 +///
 +/// The tricky bit is dealing with repetitions (`$()*`). Consider this example:
 +///
 +/// ```not_rust
 +/// macro_rules! foo {
 +///     ($($ i:ident $($ e:expr),*);*) => {
 +///         $(fn $ i() { $($ e);*; })*
 +///     }
 +/// }
 +/// foo! { foo 1,2,3; bar 4,5,6 }
 +/// ```
 +///
 +/// Here, the `$i` meta variable is matched first with `foo` and then with
 +/// `bar`, and `$e` is matched in turn with `1`, `2`, `3`, `4`, `5`, `6`.
 +///
 +/// To represent such "multi-mappings", we use a recursive structures: we map
 +/// variables not to values, but to *lists* of values or other lists (that is,
 +/// to the trees).
 +///
 +/// For the above example, the bindings would store
 +///
 +/// ```not_rust
 +/// i -> [foo, bar]
 +/// e -> [[1, 2, 3], [4, 5, 6]]
 +/// ```
 +///
 +/// We construct `Bindings` in the `match_lhs`. The interesting case is
 +/// `TokenTree::Repeat`, where we use `push_nested` to create the desired
 +/// nesting structure.
 +///
 +/// The other side of the puzzle is `expand_subtree`, where we use the bindings
 +/// to substitute meta variables in the output template. When expanding, we
 +/// maintain a `nesting` stack of indices which tells us which occurrence from
 +/// the `Bindings` we should take. We push to the stack when we enter a
 +/// repetition.
 +///
 +/// In other words, `Bindings` is a *multi* mapping from `SmolStr` to
 +/// `tt::TokenTree`, where the index to select a particular `TokenTree` among
 +/// many is not a plain `usize`, but a `&[usize]`.
 +#[derive(Debug, Default, Clone, PartialEq, Eq)]
 +struct Bindings {
 +    inner: FxHashMap<SmolStr, Binding>,
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +enum Binding {
 +    Fragment(Fragment),
 +    Nested(Vec<Binding>),
 +    Empty,
++    Missing(MetaVarKind),
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +enum Fragment {
 +    /// token fragments are just copy-pasted into the output
 +    Tokens(tt::TokenTree),
 +    /// Expr ast fragments are surrounded with `()` on insertion to preserve
 +    /// precedence. Note that this impl is different from the one currently in
 +    /// `rustc` -- `rustc` doesn't translate fragments into token trees at all.
 +    ///
 +    /// At one point in time, we tried to to use "fake" delimiters here a-la
 +    /// proc-macro delimiter=none. As we later discovered, "none" delimiters are
 +    /// tricky to handle in the parser, and rustc doesn't handle those either.
 +    Expr(tt::TokenTree),
 +}
index 139a8cb8cbe589b9e586cdf6c8c0f94c36126e54,0000000000000000000000000000000000000000..3f656df25f7d4e04398ed1df21bc046dc0c35d2c
mode 100644,000000..100644
--- /dev/null
@@@ -1,905 -1,0 +1,921 @@@
-     parser::{Op, RepeatKind, Separator},
 +//! 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},
-                 if let Some(kind) = kind {
++    parser::{MetaVarKind, 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::Missing(_) => 1,
 +                Binding::Nested(it) => count(it.iter()),
 +            })
 +            .sum()
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +enum BindingKind {
 +    Empty(SmolStr),
 +    Optional(SmolStr),
 +    Fragment(SmolStr, Fragment),
++    Missing(SmolStr, MetaVarKind),
 +    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_missing(&mut self, idx: &mut BindingsIdx, var: &SmolStr, kind: MetaVarKind) {
++        self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Missing(var.clone(), kind))));
++    }
++
 +    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 {
 +        self.build_inner(&self.nodes[idx.0])
 +    }
 +
 +    fn build_inner(&self, link_nodes: &[LinkNode<Rc<BindingKind>>]) -> Bindings {
 +        let mut bindings = Bindings::default();
 +        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::Missing(name, kind) => {
++                    bindings.inner.insert(name.clone(), Binding::Missing(*kind));
++                }
 +                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());
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +
 +        bindings
 +    }
 +
 +    fn collect_nested_ref<'a>(
 +        &'a self,
 +        id: usize,
 +        len: usize,
 +        nested_refs: &mut Vec<&'a [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<&[_]> = 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.extend(nested_refs.into_iter().map(|iter| self.build_inner(iter)));
 +    }
 +
 +    fn collect_nodes_ref<'a>(&'a self, id: usize, len: usize, nodes: &mut Vec<&'a 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 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 let Some(up) = &item.up {
 +                    if item.sep_parsed.is_none() {
 +                        // Get the `up` matcher
 +                        let mut new_pos = (**up).clone();
 +                        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.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, .. }) => {
-                     let match_res = match_meta_var(kind.as_str(), &mut fork);
++                if let &Some(kind) = kind {
 +                    let mut fork = src.clone();
-                             if let Some(fragment) = match_res.value {
-                                 bindings_builder.push_fragment(&mut item.bindings, name, fragment);
++                    let match_res = match_meta_var(kind, &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);
- fn match_meta_var(kind: &str, input: &mut TtIter<'_>) -> ExpandResult<Option<Fragment>> {
++                            match match_res.value {
++                                Some(fragment) => bindings_builder.push_fragment(
++                                    &mut item.bindings,
++                                    name,
++                                    fragment,
++                                ),
++                                None => {
++                                    bindings_builder.push_missing(&mut item.bindings, name, kind)
++                                }
 +                            }
 +                            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),
 +    }
 +}
 +
-         "path" => parser::PrefixEntryPoint::Path,
-         "ty" => parser::PrefixEntryPoint::Ty,
++fn match_meta_var(kind: MetaVarKind, input: &mut TtIter<'_>) -> ExpandResult<Option<Fragment>> {
 +    let fragment = match kind {
-         "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" => {
++        MetaVarKind::Path => parser::PrefixEntryPoint::Path,
++        MetaVarKind::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
-                 "ident" => input
++        MetaVarKind::Pat | MetaVarKind::PatParam => parser::PrefixEntryPoint::Pat,
++        MetaVarKind::Stmt => parser::PrefixEntryPoint::Stmt,
++        MetaVarKind::Block => parser::PrefixEntryPoint::Block,
++        MetaVarKind::Meta => parser::PrefixEntryPoint::MetaItem,
++        MetaVarKind::Item => parser::PrefixEntryPoint::Item,
++        MetaVarKind::Vis => parser::PrefixEntryPoint::Vis,
++        MetaVarKind::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 {
-                 "tt" => input
++                MetaVarKind::Ident => input
 +                    .expect_ident()
 +                    .map(|ident| tt::Leaf::from(ident.clone()).into())
 +                    .map_err(|()| ExpandError::binding_error("expected ident")),
-                 "lifetime" => input
++                MetaVarKind::Tt => input
 +                    .expect_tt()
 +                    .map_err(|()| ExpandError::binding_error("expected token tree")),
-                 "literal" => {
++                MetaVarKind::Lifetime => input
 +                    .expect_lifetime()
 +                    .map_err(|()| ExpandError::binding_error("expected lifetime")),
++                MetaVarKind::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 7bcc84740f1869935c23fa710574c0f083da9f40,0000000000000000000000000000000000000000..cbb59ab8e67b5f5278a35c3f5c6c9a7368ad5e14
mode 100644,000000..100644
--- /dev/null
@@@ -1,272 -1,0 +1,321 @@@
-     parser::{Op, RepeatKind, Separator},
 +//! Transcriber takes a template, like `fn $ident() {}`, a set of bindings like
 +//! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}`
 +
 +use syntax::SmolStr;
 +use tt::{Delimiter, Subtree};
 +
 +use crate::{
 +    expander::{Binding, Bindings, Fragment},
-     fn get(&self, name: &str, nesting: &mut [NestingState]) -> Result<&Fragment, ExpandError> {
++    parser::{MetaVarKind, Op, RepeatKind, Separator},
 +    ExpandError, ExpandResult, MetaTemplate,
 +};
 +
 +impl Bindings {
 +    fn contains(&self, name: &str) -> bool {
 +        self.inner.contains_key(name)
 +    }
 +
-             Binding::Fragment(it) => Ok(it),
++    fn get(&self, name: &str, nesting: &mut [NestingState]) -> Result<Fragment, ExpandError> {
 +        macro_rules! binding_err {
 +            ($($arg:tt)*) => { ExpandError::binding_error(format!($($arg)*)) };
 +        }
 +
 +        let mut b: &Binding =
 +            self.inner.get(name).ok_or_else(|| binding_err!("could not find binding `{name}`"))?;
 +        for nesting_state in nesting.iter_mut() {
 +            nesting_state.hit = true;
 +            b = match b {
 +                Binding::Fragment(_) => break,
++                Binding::Missing(_) => break,
 +                Binding::Nested(bs) => bs.get(nesting_state.idx).ok_or_else(|| {
 +                    nesting_state.at_end = true;
 +                    binding_err!("could not find nested binding `{name}`")
 +                })?,
 +                Binding::Empty => {
 +                    nesting_state.at_end = true;
 +                    return Err(binding_err!("could not find empty binding `{name}`"));
 +                }
 +            };
 +        }
 +        match b {
-             |b| ExpandResult::ok(b.clone()),
++            Binding::Fragment(it) => Ok(it.clone()),
++            // emit some reasonable default expansion for missing bindings,
++            // this gives better recovery than emitting the `$fragment-name` verbatim
++            Binding::Missing(it) => Ok(match it {
++                MetaVarKind::Stmt => {
++                    Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
++                        id: tt::TokenId::unspecified(),
++                        char: ';',
++                        spacing: tt::Spacing::Alone,
++                    })))
++                }
++                MetaVarKind::Block => Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree {
++                    delimiter: Some(tt::Delimiter {
++                        id: tt::TokenId::unspecified(),
++                        kind: tt::DelimiterKind::Brace,
++                    }),
++                    token_trees: vec![],
++                })),
++                // FIXME: Meta and Item should get proper defaults
++                MetaVarKind::Meta | MetaVarKind::Item | MetaVarKind::Tt | MetaVarKind::Vis => {
++                    Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree {
++                        delimiter: None,
++                        token_trees: vec![],
++                    }))
++                }
++                MetaVarKind::Path
++                | MetaVarKind::Ty
++                | MetaVarKind::Pat
++                | MetaVarKind::PatParam
++                | MetaVarKind::Expr
++                | MetaVarKind::Ident => {
++                    Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
++                        text: SmolStr::new_inline("missing"),
++                        id: tt::TokenId::unspecified(),
++                    })))
++                }
++                MetaVarKind::Lifetime => {
++                    Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
++                        text: SmolStr::new_inline("'missing"),
++                        id: tt::TokenId::unspecified(),
++                    })))
++                }
++                MetaVarKind::Literal => {
++                    Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
++                        text: SmolStr::new_inline("\"missing\""),
++                        id: tt::TokenId::unspecified(),
++                    })))
++                }
++            }),
 +            Binding::Nested(_) => {
 +                Err(binding_err!("expected simple binding, found nested binding `{name}`"))
 +            }
 +            Binding::Empty => {
 +                Err(binding_err!("expected simple binding, found empty binding `{name}`"))
 +            }
 +        }
 +    }
 +}
 +
 +pub(super) fn transcribe(
 +    template: &MetaTemplate,
 +    bindings: &Bindings,
 +) -> ExpandResult<tt::Subtree> {
 +    let mut ctx = ExpandCtx { bindings, nesting: Vec::new() };
 +    let mut arena: Vec<tt::TokenTree> = Vec::new();
 +    expand_subtree(&mut ctx, template, None, &mut arena)
 +}
 +
 +#[derive(Debug)]
 +struct NestingState {
 +    idx: usize,
 +    /// `hit` is currently necessary to tell `expand_repeat` if it should stop
 +    /// because there is no variable in use by the current repetition
 +    hit: bool,
 +    /// `at_end` is currently necessary to tell `expand_repeat` if it should stop
 +    /// because there is no more value available for the current repetition
 +    at_end: bool,
 +}
 +
 +#[derive(Debug)]
 +struct ExpandCtx<'a> {
 +    bindings: &'a Bindings,
 +    nesting: Vec<NestingState>,
 +}
 +
 +fn expand_subtree(
 +    ctx: &mut ExpandCtx<'_>,
 +    template: &MetaTemplate,
 +    delimiter: Option<Delimiter>,
 +    arena: &mut Vec<tt::TokenTree>,
 +) -> ExpandResult<tt::Subtree> {
 +    // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation
 +    let start_elements = arena.len();
 +    let mut err = None;
 +    for op in template.iter() {
 +        match op {
 +            Op::Leaf(tt) => arena.push(tt.clone().into()),
 +            Op::Subtree { tokens, delimiter } => {
 +                let ExpandResult { value: tt, err: e } =
 +                    expand_subtree(ctx, tokens, *delimiter, arena);
 +                err = err.or(e);
 +                arena.push(tt.into());
 +            }
 +            Op::Var { name, id, .. } => {
 +                let ExpandResult { value: fragment, err: e } = expand_var(ctx, name, *id);
 +                err = err.or(e);
 +                push_fragment(arena, fragment);
 +            }
 +            Op::Repeat { tokens: subtree, kind, separator } => {
 +                let ExpandResult { value: fragment, err: e } =
 +                    expand_repeat(ctx, subtree, *kind, separator, arena);
 +                err = err.or(e);
 +                push_fragment(arena, fragment)
 +            }
 +            Op::Ignore { name, id } => {
 +                // Expand the variable, but ignore the result. This registers the repetition count.
 +                expand_var(ctx, name, *id);
 +            }
 +            Op::Index { depth } => {
 +                let index = ctx
 +                    .nesting
 +                    .get(ctx.nesting.len() - 1 - (*depth as usize))
 +                    .map_or(0, |nest| nest.idx);
 +                arena.push(
 +                    tt::Leaf::Literal(tt::Literal {
 +                        text: index.to_string().into(),
 +                        id: tt::TokenId::unspecified(),
 +                    })
 +                    .into(),
 +                );
 +            }
 +        }
 +    }
 +    // drain the elements added in this instance of expand_subtree
 +    let tts = arena.drain(start_elements..).collect();
 +    ExpandResult { value: tt::Subtree { delimiter, token_trees: tts }, err }
 +}
 +
 +fn expand_var(ctx: &mut ExpandCtx<'_>, v: &SmolStr, id: tt::TokenId) -> ExpandResult<Fragment> {
 +    // We already handle $crate case in mbe parser
 +    debug_assert!(v != "crate");
 +
 +    if !ctx.bindings.contains(v) {
 +        // Note that it is possible to have a `$var` inside a macro which is not bound.
 +        // For example:
 +        // ```
 +        // macro_rules! foo {
 +        //     ($a:ident, $b:ident, $c:tt) => {
 +        //         macro_rules! bar {
 +        //             ($bi:ident) => {
 +        //                 fn $bi() -> u8 {$c}
 +        //             }
 +        //         }
 +        //     }
 +        // ```
 +        // We just treat it a normal tokens
 +        let tt = tt::Subtree {
 +            delimiter: None,
 +            token_trees: vec![
 +                tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, id }).into(),
 +                tt::Leaf::from(tt::Ident { text: v.clone(), id }).into(),
 +            ],
 +        }
 +        .into();
 +        ExpandResult::ok(Fragment::Tokens(tt))
 +    } else {
 +        ctx.bindings.get(v, &mut ctx.nesting).map_or_else(
 +            |e| ExpandResult { value: Fragment::Tokens(tt::TokenTree::empty()), err: Some(e) },
++            |it| ExpandResult::ok(it),
 +        )
 +    }
 +}
 +
 +fn expand_repeat(
 +    ctx: &mut ExpandCtx<'_>,
 +    template: &MetaTemplate,
 +    kind: RepeatKind,
 +    separator: &Option<Separator>,
 +    arena: &mut Vec<tt::TokenTree>,
 +) -> ExpandResult<Fragment> {
 +    let mut buf: Vec<tt::TokenTree> = Vec::new();
 +    ctx.nesting.push(NestingState { idx: 0, at_end: false, hit: false });
 +    // Dirty hack to make macro-expansion terminate.
 +    // This should be replaced by a proper macro-by-example implementation
 +    let limit = 65536;
 +    let mut has_seps = 0;
 +    let mut counter = 0;
 +
 +    loop {
 +        let ExpandResult { value: mut t, err: e } = expand_subtree(ctx, template, None, arena);
 +        let nesting_state = ctx.nesting.last_mut().unwrap();
 +        if nesting_state.at_end || !nesting_state.hit {
 +            break;
 +        }
 +        nesting_state.idx += 1;
 +        nesting_state.hit = false;
 +
 +        counter += 1;
 +        if counter == limit {
 +            tracing::warn!(
 +                "expand_tt in repeat pattern exceed limit => {:#?}\n{:#?}",
 +                template,
 +                ctx
 +            );
 +            return ExpandResult {
 +                value: Fragment::Tokens(Subtree::default().into()),
 +                err: Some(ExpandError::LimitExceeded),
 +            };
 +        }
 +
 +        if e.is_some() {
 +            continue;
 +        }
 +
 +        t.delimiter = None;
 +        push_subtree(&mut buf, t);
 +
 +        if let Some(sep) = separator {
 +            has_seps = match sep {
 +                Separator::Ident(ident) => {
 +                    buf.push(tt::Leaf::from(ident.clone()).into());
 +                    1
 +                }
 +                Separator::Literal(lit) => {
 +                    buf.push(tt::Leaf::from(lit.clone()).into());
 +                    1
 +                }
 +                Separator::Puncts(puncts) => {
 +                    for &punct in puncts {
 +                        buf.push(tt::Leaf::from(punct).into());
 +                    }
 +                    puncts.len()
 +                }
 +            };
 +        }
 +
 +        if RepeatKind::ZeroOrOne == kind {
 +            break;
 +        }
 +    }
 +
 +    ctx.nesting.pop().unwrap();
 +    for _ in 0..has_seps {
 +        buf.pop();
 +    }
 +
 +    // Check if it is a single token subtree without any delimiter
 +    // e.g {Delimiter:None> ['>'] /Delimiter:None>}
 +    let tt = tt::Subtree { delimiter: None, token_trees: buf }.into();
 +
 +    if RepeatKind::OneOrMore == kind && counter == 0 {
 +        return ExpandResult {
 +            value: Fragment::Tokens(tt),
 +            err: Some(ExpandError::UnexpectedToken),
 +        };
 +    }
 +    ExpandResult::ok(Fragment::Tokens(tt))
 +}
 +
 +fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) {
 +    match fragment {
 +        Fragment::Tokens(tt::TokenTree::Subtree(tt)) => push_subtree(buf, tt),
 +        Fragment::Expr(tt::TokenTree::Subtree(mut tt)) => {
 +            if tt.delimiter.is_none() {
 +                tt.delimiter = Some(tt::Delimiter {
 +                    id: tt::TokenId::unspecified(),
 +                    kind: tt::DelimiterKind::Parenthesis,
 +                })
 +            }
 +            buf.push(tt.into())
 +        }
 +        Fragment::Tokens(tt) | Fragment::Expr(tt) => buf.push(tt),
 +    }
 +}
 +
 +fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) {
 +    match tt.delimiter {
 +        None => buf.extend(tt.token_trees),
 +        Some(_) => buf.push(tt.into()),
 +    }
 +}
index 79da84f4a022638c96a08d0b57842735a217545a,0000000000000000000000000000000000000000..c4f0fa20d6de03959f3600fd57bf6e52475c2eee
mode 100644,000000..100644
--- /dev/null
@@@ -1,352 -1,0 +1,352 @@@
-     parser::{MetaTemplate, Op},
 +//! `mbe` (short for Macro By Example) crate contains code for handling
 +//! `macro_rules` macros. It uses `TokenTree` (from `tt` package) as the
 +//! interface, although it contains some code to bridge `SyntaxNode`s and
 +//! `TokenTree`s as well!
 +//!
 +//! The tes for this functionality live in another crate:
 +//! `hir_def::macro_expansion_tests::mbe`.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +mod parser;
 +mod expander;
 +mod syntax_bridge;
 +mod tt_iter;
 +mod to_parser_input;
 +
 +#[cfg(test)]
 +mod benchmark;
 +mod token_map;
 +
 +use std::fmt;
 +
 +use crate::{
-                     match child_op {
++    parser::{MetaTemplate, MetaVarKind, Op},
 +    tt_iter::TtIter,
 +};
 +
 +// FIXME: we probably should re-think  `token_tree_to_syntax_node` interfaces
 +pub use ::parser::TopEntryPoint;
 +pub use tt::{Delimiter, DelimiterKind, Punct};
 +
 +pub use crate::{
 +    syntax_bridge::{
 +        parse_exprs_with_sep, parse_to_token_tree, syntax_node_to_token_tree,
 +        syntax_node_to_token_tree_with_modifications, token_tree_to_syntax_node, SyntheticToken,
 +        SyntheticTokenId,
 +    },
 +    token_map::TokenMap,
 +};
 +
 +#[derive(Debug, PartialEq, Eq, Clone)]
 +pub enum ParseError {
 +    UnexpectedToken(Box<str>),
 +    Expected(Box<str>),
 +    InvalidRepeat,
 +    RepetitionEmptyTokenTree,
 +}
 +
 +impl ParseError {
 +    fn expected(e: &str) -> ParseError {
 +        ParseError::Expected(e.into())
 +    }
 +
 +    fn unexpected(e: &str) -> ParseError {
 +        ParseError::UnexpectedToken(e.into())
 +    }
 +}
 +
 +impl fmt::Display for ParseError {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match self {
 +            ParseError::UnexpectedToken(it) => f.write_str(it),
 +            ParseError::Expected(it) => f.write_str(it),
 +            ParseError::InvalidRepeat => f.write_str("invalid repeat"),
 +            ParseError::RepetitionEmptyTokenTree => f.write_str("empty token tree in repetition"),
 +        }
 +    }
 +}
 +
 +#[derive(Debug, PartialEq, Eq, Clone)]
 +pub enum ExpandError {
 +    BindingError(Box<Box<str>>),
 +    LeftoverTokens,
 +    ConversionError,
 +    LimitExceeded,
 +    NoMatchingRule,
 +    UnexpectedToken,
 +}
 +
 +impl ExpandError {
 +    fn binding_error(e: impl Into<Box<str>>) -> ExpandError {
 +        ExpandError::BindingError(Box::new(e.into()))
 +    }
 +}
 +
 +impl fmt::Display for ExpandError {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match self {
 +            ExpandError::NoMatchingRule => f.write_str("no rule matches input tokens"),
 +            ExpandError::UnexpectedToken => f.write_str("unexpected token in input"),
 +            ExpandError::BindingError(e) => f.write_str(e),
 +            ExpandError::ConversionError => f.write_str("could not convert tokens"),
 +            ExpandError::LimitExceeded => f.write_str("Expand exceed limit"),
 +            ExpandError::LeftoverTokens => f.write_str("leftover tokens"),
 +        }
 +    }
 +}
 +
 +/// This struct contains AST for a single `macro_rules` definition. What might
 +/// be very confusing is that AST has almost exactly the same shape as
 +/// `tt::TokenTree`, but there's a crucial difference: in macro rules, `$ident`
 +/// and `$()*` have special meaning (see `Var` and `Repeat` data structures)
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub struct DeclarativeMacro {
 +    rules: Vec<Rule>,
 +    /// Highest id of the token we have in TokenMap
 +    shift: Shift,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +struct Rule {
 +    lhs: MetaTemplate,
 +    rhs: MetaTemplate,
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct Shift(u32);
 +
 +impl Shift {
 +    pub fn new(tt: &tt::Subtree) -> Shift {
 +        // Note that TokenId is started from zero,
 +        // We have to add 1 to prevent duplication.
 +        let value = max_id(tt).map_or(0, |it| it + 1);
 +        return Shift(value);
 +
 +        // Find the max token id inside a subtree
 +        fn max_id(subtree: &tt::Subtree) -> Option<u32> {
 +            let filter = |tt: &_| match tt {
 +                tt::TokenTree::Subtree(subtree) => {
 +                    let tree_id = max_id(subtree);
 +                    match subtree.delimiter {
 +                        Some(it) if it.id != tt::TokenId::unspecified() => {
 +                            Some(tree_id.map_or(it.id.0, |t| t.max(it.id.0)))
 +                        }
 +                        _ => tree_id,
 +                    }
 +                }
 +                tt::TokenTree::Leaf(leaf) => {
 +                    let &(tt::Leaf::Ident(tt::Ident { id, .. })
 +                    | tt::Leaf::Punct(tt::Punct { id, .. })
 +                    | tt::Leaf::Literal(tt::Literal { id, .. })) = leaf;
 +
 +                    (id != tt::TokenId::unspecified()).then(|| id.0)
 +                }
 +            };
 +            subtree.token_trees.iter().filter_map(filter).max()
 +        }
 +    }
 +
 +    /// Shift given TokenTree token id
 +    pub fn shift_all(self, tt: &mut tt::Subtree) {
 +        for t in &mut tt.token_trees {
 +            match t {
 +                tt::TokenTree::Leaf(
 +                    tt::Leaf::Ident(tt::Ident { id, .. })
 +                    | tt::Leaf::Punct(tt::Punct { id, .. })
 +                    | tt::Leaf::Literal(tt::Literal { id, .. }),
 +                ) => *id = self.shift(*id),
 +                tt::TokenTree::Subtree(tt) => {
 +                    if let Some(it) = tt.delimiter.as_mut() {
 +                        it.id = self.shift(it.id);
 +                    }
 +                    self.shift_all(tt)
 +                }
 +            }
 +        }
 +    }
 +
 +    pub fn shift(self, id: tt::TokenId) -> tt::TokenId {
 +        if id == tt::TokenId::unspecified() {
 +            id
 +        } else {
 +            tt::TokenId(id.0 + self.0)
 +        }
 +    }
 +
 +    pub fn unshift(self, id: tt::TokenId) -> Option<tt::TokenId> {
 +        id.0.checked_sub(self.0).map(tt::TokenId)
 +    }
 +}
 +
 +#[derive(Debug, Eq, PartialEq)]
 +pub enum Origin {
 +    Def,
 +    Call,
 +}
 +
 +impl DeclarativeMacro {
 +    /// The old, `macro_rules! m {}` flavor.
 +    pub fn parse_macro_rules(tt: &tt::Subtree) -> Result<DeclarativeMacro, ParseError> {
 +        // Note: this parsing can be implemented using mbe machinery itself, by
 +        // matching against `$($lhs:tt => $rhs:tt);*` pattern, but implementing
 +        // manually seems easier.
 +        let mut src = TtIter::new(tt);
 +        let mut rules = Vec::new();
 +        while src.len() > 0 {
 +            let rule = Rule::parse(&mut src, true)?;
 +            rules.push(rule);
 +            if let Err(()) = src.expect_char(';') {
 +                if src.len() > 0 {
 +                    return Err(ParseError::expected("expected `;`"));
 +                }
 +                break;
 +            }
 +        }
 +
 +        for Rule { lhs, .. } in &rules {
 +            validate(lhs)?;
 +        }
 +
 +        Ok(DeclarativeMacro { rules, shift: Shift::new(tt) })
 +    }
 +
 +    /// The new, unstable `macro m {}` flavor.
 +    pub fn parse_macro2(tt: &tt::Subtree) -> Result<DeclarativeMacro, ParseError> {
 +        let mut src = TtIter::new(tt);
 +        let mut rules = Vec::new();
 +
 +        if Some(tt::DelimiterKind::Brace) == tt.delimiter_kind() {
 +            cov_mark::hit!(parse_macro_def_rules);
 +            while src.len() > 0 {
 +                let rule = Rule::parse(&mut src, true)?;
 +                rules.push(rule);
 +                if let Err(()) = src.expect_any_char(&[';', ',']) {
 +                    if src.len() > 0 {
 +                        return Err(ParseError::expected("expected `;` or `,` to delimit rules"));
 +                    }
 +                    break;
 +                }
 +            }
 +        } else {
 +            cov_mark::hit!(parse_macro_def_simple);
 +            let rule = Rule::parse(&mut src, false)?;
 +            if src.len() != 0 {
 +                return Err(ParseError::expected("remaining tokens in macro def"));
 +            }
 +            rules.push(rule);
 +        }
 +
 +        for Rule { lhs, .. } in &rules {
 +            validate(lhs)?;
 +        }
 +
 +        Ok(DeclarativeMacro { rules, shift: Shift::new(tt) })
 +    }
 +
 +    pub fn expand(&self, tt: &tt::Subtree) -> ExpandResult<tt::Subtree> {
 +        // apply shift
 +        let mut tt = tt.clone();
 +        self.shift.shift_all(&mut tt);
 +        expander::expand_rules(&self.rules, &tt)
 +    }
 +
 +    pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
 +        self.shift.shift(id)
 +    }
 +
 +    pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, Origin) {
 +        match self.shift.unshift(id) {
 +            Some(id) => (id, Origin::Call),
 +            None => (id, Origin::Def),
 +        }
 +    }
 +
 +    pub fn shift(&self) -> Shift {
 +        self.shift
 +    }
 +}
 +
 +impl Rule {
 +    fn parse(src: &mut TtIter<'_>, expect_arrow: bool) -> Result<Self, ParseError> {
 +        let lhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?;
 +        if expect_arrow {
 +            src.expect_char('=').map_err(|()| ParseError::expected("expected `=`"))?;
 +            src.expect_char('>').map_err(|()| ParseError::expected("expected `>`"))?;
 +        }
 +        let rhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?;
 +
 +        let lhs = MetaTemplate::parse_pattern(lhs)?;
 +        let rhs = MetaTemplate::parse_template(rhs)?;
 +
 +        Ok(crate::Rule { lhs, rhs })
 +    }
 +}
 +
 +fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> {
 +    for op in pattern.iter() {
 +        match op {
 +            Op::Subtree { tokens, .. } => validate(tokens)?,
 +            Op::Repeat { tokens: subtree, separator, .. } => {
 +                // Checks that no repetition which could match an empty token
 +                // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558
 +                let lsh_is_empty_seq = separator.is_none() && subtree.iter().all(|child_op| {
-                         Op::Var { kind: Some(kind), .. } => kind == "vis",
++                    match *child_op {
 +                        // vis is optional
++                        Op::Var { kind: Some(kind), .. } => kind == MetaVarKind::Vis,
 +                        Op::Repeat {
 +                            kind: parser::RepeatKind::ZeroOrMore | parser::RepeatKind::ZeroOrOne,
 +                            ..
 +                        } => true,
 +                        _ => false,
 +                    }
 +                });
 +                if lsh_is_empty_seq {
 +                    return Err(ParseError::RepetitionEmptyTokenTree);
 +                }
 +                validate(subtree)?
 +            }
 +            _ => (),
 +        }
 +    }
 +    Ok(())
 +}
 +
 +pub type ExpandResult<T> = ValueResult<T, ExpandError>;
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct ValueResult<T, E> {
 +    pub value: T,
 +    pub err: Option<E>,
 +}
 +
 +impl<T, E> ValueResult<T, E> {
 +    pub fn ok(value: T) -> Self {
 +        Self { value, err: None }
 +    }
 +
 +    pub fn only_err(err: E) -> Self
 +    where
 +        T: Default,
 +    {
 +        Self { value: Default::default(), err: Some(err) }
 +    }
 +
 +    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> ValueResult<U, E> {
 +        ValueResult { value: f(self.value), err: self.err }
 +    }
 +
 +    pub fn map_err<E2>(self, f: impl FnOnce(E) -> E2) -> ValueResult<T, E2> {
 +        ValueResult { value: self.value, err: self.err.map(f) }
 +    }
 +
 +    pub fn result(self) -> Result<T, E> {
 +        self.err.map_or(Ok(self.value), Err)
 +    }
 +}
 +
 +impl<T: Default, E> From<Result<T, E>> for ValueResult<T, E> {
 +    fn from(result: Result<T, E>) -> Self {
 +        result.map_or_else(Self::only_err, Self::ok)
 +    }
 +}
index acb4be5846de1936a3ca2de080e17949321149bf,0000000000000000000000000000000000000000..351c359b73c87ea8352a0bb406f7dbb285360849
mode 100644,000000..100644
--- /dev/null
@@@ -1,261 -1,0 +1,296 @@@
-     Var { name: SmolStr, kind: Option<SmolStr>, id: tt::TokenId },
 +//! Parser recognizes special macro syntax, `$var` and `$(repeat)*`, in token
 +//! trees.
 +
 +use smallvec::SmallVec;
 +use syntax::SmolStr;
 +
 +use crate::{tt_iter::TtIter, ParseError};
 +
 +/// Consider
 +///
 +/// ```
 +/// macro_rules! an_macro {
 +///     ($x:expr + $y:expr) => ($y * $x)
 +/// }
 +/// ```
 +///
 +/// Stuff to the left of `=>` is a [`MetaTemplate`] pattern (which is matched
 +/// with input).
 +///
 +/// Stuff to the right is a [`MetaTemplate`] template which is used to produce
 +/// output.
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub(crate) struct MetaTemplate(pub(crate) Vec<Op>);
 +
 +impl MetaTemplate {
 +    pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Result<MetaTemplate, ParseError> {
 +        MetaTemplate::parse(pattern, Mode::Pattern)
 +    }
 +
 +    pub(crate) fn parse_template(template: &tt::Subtree) -> Result<MetaTemplate, ParseError> {
 +        MetaTemplate::parse(template, Mode::Template)
 +    }
 +
 +    pub(crate) fn iter(&self) -> impl Iterator<Item = &Op> {
 +        self.0.iter()
 +    }
 +
 +    fn parse(tt: &tt::Subtree, mode: Mode) -> Result<MetaTemplate, ParseError> {
 +        let mut src = TtIter::new(tt);
 +
 +        let mut res = Vec::new();
 +        while let Some(first) = src.next() {
 +            let op = next_op(first, &mut src, mode)?;
 +            res.push(op);
 +        }
 +
 +        Ok(MetaTemplate(res))
 +    }
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub(crate) enum Op {
- fn eat_fragment_kind(src: &mut TtIter<'_>, mode: Mode) -> Result<Option<SmolStr>, ParseError> {
++    Var { name: SmolStr, kind: Option<MetaVarKind>, id: tt::TokenId },
 +    Ignore { name: SmolStr, id: tt::TokenId },
 +    Index { depth: u32 },
 +    Repeat { tokens: MetaTemplate, kind: RepeatKind, separator: Option<Separator> },
 +    Leaf(tt::Leaf),
 +    Subtree { tokens: MetaTemplate, delimiter: Option<tt::Delimiter> },
 +}
 +
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +pub(crate) enum RepeatKind {
 +    ZeroOrMore,
 +    OneOrMore,
 +    ZeroOrOne,
 +}
 +
++#[derive(Copy, Clone, Debug, PartialEq, Eq)]
++pub(crate) enum MetaVarKind {
++    Path,
++    Ty,
++    Pat,
++    PatParam,
++    Stmt,
++    Block,
++    Meta,
++    Item,
++    Vis,
++    Expr,
++    Ident,
++    Tt,
++    Lifetime,
++    Literal,
++}
++
 +#[derive(Clone, Debug, Eq)]
 +pub(crate) enum Separator {
 +    Literal(tt::Literal),
 +    Ident(tt::Ident),
 +    Puncts(SmallVec<[tt::Punct; 3]>),
 +}
 +
 +// Note that when we compare a Separator, we just care about its textual value.
 +impl PartialEq for Separator {
 +    fn eq(&self, other: &Separator) -> bool {
 +        use Separator::*;
 +
 +        match (self, other) {
 +            (Ident(a), Ident(b)) => a.text == b.text,
 +            (Literal(a), Literal(b)) => a.text == b.text,
 +            (Puncts(a), Puncts(b)) if a.len() == b.len() => {
 +                let a_iter = a.iter().map(|a| a.char);
 +                let b_iter = b.iter().map(|b| b.char);
 +                a_iter.eq(b_iter)
 +            }
 +            _ => false,
 +        }
 +    }
 +}
 +
 +impl Separator {
 +    pub(crate) fn tt_count(&self) -> usize {
 +        match self {
 +            Separator::Literal(_) => 1,
 +            Separator::Ident(_) => 1,
 +            Separator::Puncts(it) => it.len(),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy)]
 +enum Mode {
 +    Pattern,
 +    Template,
 +}
 +
 +fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result<Op, ParseError> {
 +    let res = match first {
 +        tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => {
 +            // Note that the '$' itself is a valid token inside macro_rules.
 +            let second = match src.next() {
 +                None => return Ok(Op::Leaf(leaf.clone())),
 +                Some(it) => it,
 +            };
 +            match second {
 +                tt::TokenTree::Subtree(subtree) => match subtree.delimiter_kind() {
 +                    Some(tt::DelimiterKind::Parenthesis) => {
 +                        let (separator, kind) = parse_repeat(src)?;
 +                        let tokens = MetaTemplate::parse(subtree, mode)?;
 +                        Op::Repeat { tokens, separator, kind }
 +                    }
 +                    Some(tt::DelimiterKind::Brace) => match mode {
 +                        Mode::Template => {
 +                            parse_metavar_expr(&mut TtIter::new(subtree)).map_err(|()| {
 +                                ParseError::unexpected("invalid metavariable expression")
 +                            })?
 +                        }
 +                        Mode::Pattern => {
 +                            return Err(ParseError::unexpected(
 +                                "`${}` metavariable expressions are not allowed in matchers",
 +                            ))
 +                        }
 +                    },
 +                    _ => {
 +                        return Err(ParseError::expected(
 +                            "expected `$()` repetition or `${}` expression",
 +                        ))
 +                    }
 +                },
 +                tt::TokenTree::Leaf(leaf) => match leaf {
 +                    tt::Leaf::Ident(ident) if ident.text == "crate" => {
 +                        // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path.
 +                        Op::Leaf(tt::Leaf::from(tt::Ident { text: "$crate".into(), id: ident.id }))
 +                    }
 +                    tt::Leaf::Ident(ident) => {
 +                        let kind = eat_fragment_kind(src, mode)?;
 +                        let name = ident.text.clone();
 +                        let id = ident.id;
 +                        Op::Var { name, kind, id }
 +                    }
 +                    tt::Leaf::Literal(lit) if is_boolean_literal(lit) => {
 +                        let kind = eat_fragment_kind(src, mode)?;
 +                        let name = lit.text.clone();
 +                        let id = lit.id;
 +                        Op::Var { name, kind, id }
 +                    }
 +                    tt::Leaf::Punct(punct @ tt::Punct { char: '$', .. }) => match mode {
 +                        Mode::Pattern => {
 +                            return Err(ParseError::unexpected(
 +                                "`$$` is not allowed on the pattern side",
 +                            ))
 +                        }
 +                        Mode::Template => Op::Leaf(tt::Leaf::Punct(*punct)),
 +                    },
 +                    tt::Leaf::Punct(_) | tt::Leaf::Literal(_) => {
 +                        return Err(ParseError::expected("expected ident"))
 +                    }
 +                },
 +            }
 +        }
 +        tt::TokenTree::Leaf(tt) => Op::Leaf(tt.clone()),
 +        tt::TokenTree::Subtree(subtree) => {
 +            let tokens = MetaTemplate::parse(subtree, mode)?;
 +            Op::Subtree { tokens, delimiter: subtree.delimiter }
 +        }
 +    };
 +    Ok(res)
 +}
 +
-         return Ok(Some(ident.text.clone()));
++fn eat_fragment_kind(src: &mut TtIter<'_>, mode: Mode) -> Result<Option<MetaVarKind>, ParseError> {
 +    if let Mode::Pattern = mode {
 +        src.expect_char(':').map_err(|()| ParseError::unexpected("missing fragment specifier"))?;
 +        let ident = src
 +            .expect_ident()
 +            .map_err(|()| ParseError::unexpected("missing fragment specifier"))?;
++        let kind = match ident.text.as_str() {
++            "path" => MetaVarKind::Path,
++            "ty" => MetaVarKind::Ty,
++            "pat" => MetaVarKind::Pat,
++            "pat_param" => MetaVarKind::PatParam,
++            "stmt" => MetaVarKind::Stmt,
++            "block" => MetaVarKind::Block,
++            "meta" => MetaVarKind::Meta,
++            "item" => MetaVarKind::Item,
++            "vis" => MetaVarKind::Vis,
++            "expr" => MetaVarKind::Expr,
++            "ident" => MetaVarKind::Ident,
++            "tt" => MetaVarKind::Tt,
++            "lifetime" => MetaVarKind::Lifetime,
++            "literal" => MetaVarKind::Literal,
++            _ => return Ok(None),
++        };
++        return Ok(Some(kind));
 +    };
 +    Ok(None)
 +}
 +
 +fn is_boolean_literal(lit: &tt::Literal) -> bool {
 +    matches!(lit.text.as_str(), "true" | "false")
 +}
 +
 +fn parse_repeat(src: &mut TtIter<'_>) -> Result<(Option<Separator>, RepeatKind), ParseError> {
 +    let mut separator = Separator::Puncts(SmallVec::new());
 +    for tt in src {
 +        let tt = match tt {
 +            tt::TokenTree::Leaf(leaf) => leaf,
 +            tt::TokenTree::Subtree(_) => return Err(ParseError::InvalidRepeat),
 +        };
 +        let has_sep = match &separator {
 +            Separator::Puncts(puncts) => !puncts.is_empty(),
 +            _ => true,
 +        };
 +        match tt {
 +            tt::Leaf::Ident(_) | tt::Leaf::Literal(_) if has_sep => {
 +                return Err(ParseError::InvalidRepeat)
 +            }
 +            tt::Leaf::Ident(ident) => separator = Separator::Ident(ident.clone()),
 +            tt::Leaf::Literal(lit) => separator = Separator::Literal(lit.clone()),
 +            tt::Leaf::Punct(punct) => {
 +                let repeat_kind = match punct.char {
 +                    '*' => RepeatKind::ZeroOrMore,
 +                    '+' => RepeatKind::OneOrMore,
 +                    '?' => RepeatKind::ZeroOrOne,
 +                    _ => match &mut separator {
 +                        Separator::Puncts(puncts) if puncts.len() != 3 => {
 +                            puncts.push(*punct);
 +                            continue;
 +                        }
 +                        _ => return Err(ParseError::InvalidRepeat),
 +                    },
 +                };
 +                return Ok((has_sep.then(|| separator), repeat_kind));
 +            }
 +        }
 +    }
 +    Err(ParseError::InvalidRepeat)
 +}
 +
 +fn parse_metavar_expr(src: &mut TtIter<'_>) -> Result<Op, ()> {
 +    let func = src.expect_ident()?;
 +    let args = src.expect_subtree()?;
 +
 +    if args.delimiter_kind() != Some(tt::DelimiterKind::Parenthesis) {
 +        return Err(());
 +    }
 +
 +    let mut args = TtIter::new(args);
 +
 +    let op = match &*func.text {
 +        "ignore" => {
 +            let ident = args.expect_ident()?;
 +            Op::Ignore { name: ident.text.clone(), id: ident.id }
 +        }
 +        "index" => {
 +            let depth = if args.len() == 0 { 0 } else { args.expect_u32_literal()? };
 +            Op::Index { depth }
 +        }
 +        _ => return Err(()),
 +    };
 +
 +    if args.next().is_some() {
 +        return Err(());
 +    }
 +
 +    Ok(op)
 +}
index 85a1c13fe7d4490a128e03940ed42ef90a393a80,0000000000000000000000000000000000000000..54879c1870c050239ca2d8bb511a27fae6be54de
mode 100644,000000..100644
--- /dev/null
@@@ -1,31 -1,0 +1,31 @@@
- tracing = "0.1.35"
 +[package]
 +name = "proc-macro-api"
 +version = "0.0.0"
 +description = "TBD"
 +license = "MIT OR Apache-2.0"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
 +object = { version = "0.29.0", default-features = false, features = [
 +    "std",
 +    "read_core",
 +    "elf",
 +    "macho",
 +    "pe",
 +] }
 +serde = { version = "1.0.137", features = ["derive"] }
 +serde_json = { version = "1.0.81", features = ["unbounded_depth"] }
++tracing = "0.1.37"
 +memmap2 = "0.5.4"
 +snap = "1.0.5"
 +
 +paths = { path = "../paths", version = "0.0.0" }
 +tt = { path = "../tt", version = "0.0.0" }
 +stdx = { path = "../stdx", version = "0.0.0" }
 +profile = { path = "../profile", version = "0.0.0" }
 +# Intentionally *not* depend on anything salsa-related
 +# base-db = { path = "../base-db", version = "0.0.0" }
index 0b78a45a24b33c8fdff95ce353b01d665c33b4d9,0000000000000000000000000000000000000000..5697aea964f787a59bf8b0d5c49a4fc8aece848d
mode 100644,000000..100644
--- /dev/null
@@@ -1,31 -1,0 +1,31 @@@
- once_cell = "1.12.0"
 +[package]
 +name = "profile"
 +version = "0.0.0"
 +description = "TBD"
 +license = "MIT OR Apache-2.0"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
- libc = "0.2.126"
++once_cell = "1.15.0"
 +cfg-if = "1.0.0"
++libc = "0.2.135"
 +la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
 +countme = { version = "3.0.1", features = ["enable"] }
 +jemalloc-ctl = { version = "0.5.0", package = "tikv-jemalloc-ctl", optional = true }
 +
 +[target.'cfg(target_os = "linux")'.dependencies]
 +perf-event = "0.4.7"
 +
 +[target.'cfg(windows)'.dependencies]
 +winapi = { version = "0.3.9", features = ["processthreadsapi", "psapi"] }
 +
 +[features]
 +cpu_profiler = []
 +jemalloc = ["jemalloc-ctl"]
 +
 +# Uncomment to enable for the whole crate graph
 +# default = [ "cpu_profiler" ]
index bc75d6faa383f5cf6e56d350539ac72913a90373,0000000000000000000000000000000000000000..6fd7c3166f821a04b5ae83283a58334fe43ae3d3
mode 100644,000000..100644
--- /dev/null
@@@ -1,28 -1,0 +1,28 @@@
- semver = "1.0.10"
 +[package]
 +name = "project-model"
 +version = "0.0.0"
 +description = "TBD"
 +license = "MIT OR Apache-2.0"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
 +tracing = "0.1.35"
 +rustc-hash = "1.1.0"
 +cargo_metadata = "0.15.0"
- serde_json = "1.0.81"
- anyhow = "1.0.57"
++semver = "1.0.14"
 +serde = { version = "1.0.137", features = ["derive"] }
++serde_json = "1.0.86"
++anyhow = "1.0.62"
 +expect-test = "1.4.0"
 +la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
 +
 +cfg = { path = "../cfg", version = "0.0.0" }
 +base-db = { path = "../base-db", version = "0.0.0" }
 +toolchain = { path = "../toolchain", version = "0.0.0" }
 +paths = { path = "../paths", version = "0.0.0" }
 +stdx = { path = "../stdx", version = "0.0.0" }
 +profile = { path = "../profile", version = "0.0.0" }
index 32db42f1db75eabcebbd7be69d3dc9d155bfef98,0000000000000000000000000000000000000000..d9f09c0349566129a762c9f58d528dea9094fa38
mode 100644,000000..100644
--- /dev/null
@@@ -1,266 -1,0 +1,268 @@@
-                         progress(format!("metadata {}", message.target.name));
 +//! Workspace information we get from cargo consists of two pieces. The first is
 +//! the output of `cargo metadata`. The second is the output of running
 +//! `build.rs` files (`OUT_DIR` env var, extra cfg flags) and compiling proc
 +//! macro.
 +//!
 +//! This module implements this second part. We use "build script" terminology
 +//! here, but it covers procedural macros as well.
 +
 +use std::{cell::RefCell, io, path::PathBuf, process::Command};
 +
 +use cargo_metadata::{camino::Utf8Path, Message};
 +use la_arena::ArenaMap;
 +use paths::AbsPathBuf;
 +use rustc_hash::FxHashMap;
 +use semver::Version;
 +use serde::Deserialize;
 +
 +use crate::{cfg_flag::CfgFlag, CargoConfig, CargoFeatures, CargoWorkspace, Package};
 +
 +#[derive(Debug, Default, Clone, PartialEq, Eq)]
 +pub struct WorkspaceBuildScripts {
 +    outputs: ArenaMap<Package, Option<BuildScriptOutput>>,
 +    error: Option<String>,
 +}
 +
 +#[derive(Debug, Clone, Default, PartialEq, Eq)]
 +pub(crate) struct BuildScriptOutput {
 +    /// List of config flags defined by this package's build script.
 +    pub(crate) cfgs: Vec<CfgFlag>,
 +    /// List of cargo-related environment variables with their value.
 +    ///
 +    /// If the package has a build script which defines environment variables,
 +    /// they can also be found here.
 +    pub(crate) envs: Vec<(String, String)>,
 +    /// Directory where a build script might place its output.
 +    pub(crate) out_dir: Option<AbsPathBuf>,
 +    /// Path to the proc-macro library file if this package exposes proc-macros.
 +    pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>,
 +}
 +
 +impl WorkspaceBuildScripts {
 +    fn build_command(config: &CargoConfig) -> Command {
 +        if let Some([program, args @ ..]) = config.run_build_script_command.as_deref() {
 +            let mut cmd = Command::new(program);
 +            cmd.args(args);
 +            cmd.envs(&config.extra_env);
 +            return cmd;
 +        }
 +
 +        let mut cmd = Command::new(toolchain::cargo());
 +        cmd.envs(&config.extra_env);
 +        cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]);
 +
 +        // --all-targets includes tests, benches and examples in addition to the
 +        // default lib and bins. This is an independent concept from the --targets
 +        // flag below.
 +        cmd.arg("--all-targets");
 +
 +        if let Some(target) = &config.target {
 +            cmd.args(&["--target", target]);
 +        }
 +
 +        match &config.features {
 +            CargoFeatures::All => {
 +                cmd.arg("--all-features");
 +            }
 +            CargoFeatures::Selected { features, no_default_features } => {
 +                if *no_default_features {
 +                    cmd.arg("--no-default-features");
 +                }
 +                if !features.is_empty() {
 +                    cmd.arg("--features");
 +                    cmd.arg(features.join(" "));
 +                }
 +            }
 +        }
 +
 +        cmd
 +    }
 +
 +    pub(crate) fn run(
 +        config: &CargoConfig,
 +        workspace: &CargoWorkspace,
 +        progress: &dyn Fn(String),
 +        toolchain: &Option<Version>,
 +    ) -> io::Result<WorkspaceBuildScripts> {
 +        const RUST_1_62: Version = Version::new(1, 62, 0);
 +
 +        match Self::run_(Self::build_command(config), config, workspace, progress) {
 +            Ok(WorkspaceBuildScripts { error: Some(error), .. })
 +                if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) =>
 +            {
 +                // building build scripts failed, attempt to build with --keep-going so
 +                // that we potentially get more build data
 +                let mut cmd = Self::build_command(config);
 +                cmd.args(&["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
 +                let mut res = Self::run_(cmd, config, workspace, progress)?;
 +                res.error = Some(error);
 +                Ok(res)
 +            }
 +            res => res,
 +        }
 +    }
 +
 +    fn run_(
 +        mut cmd: Command,
 +        config: &CargoConfig,
 +        workspace: &CargoWorkspace,
 +        progress: &dyn Fn(String),
 +    ) -> io::Result<WorkspaceBuildScripts> {
 +        if config.wrap_rustc_in_build_scripts {
 +            // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
 +            // that to compile only proc macros and build scripts during the initial
 +            // `cargo check`.
 +            let myself = std::env::current_exe()?;
 +            cmd.env("RUSTC_WRAPPER", myself);
 +            cmd.env("RA_RUSTC_WRAPPER", "1");
 +        }
 +
 +        cmd.current_dir(workspace.workspace_root());
 +
 +        let mut res = WorkspaceBuildScripts::default();
 +        let outputs = &mut res.outputs;
 +        // NB: Cargo.toml could have been modified between `cargo metadata` and
 +        // `cargo check`. We shouldn't assume that package ids we see here are
 +        // exactly those from `config`.
 +        let mut by_id: FxHashMap<String, Package> = FxHashMap::default();
 +        for package in workspace.packages() {
 +            outputs.insert(package, None);
 +            by_id.insert(workspace[package].id.clone(), package);
 +        }
 +
 +        let errors = RefCell::new(String::new());
 +        let push_err = |err: &str| {
 +            let mut e = errors.borrow_mut();
 +            e.push_str(err);
 +            e.push('\n');
 +        };
 +
 +        tracing::info!("Running build scripts: {:?}", cmd);
 +        let output = stdx::process::spawn_with_streaming_output(
 +            cmd,
 +            &mut |line| {
 +                // Copy-pasted from existing cargo_metadata. It seems like we
 +                // should be using serde_stacker here?
 +                let mut deserializer = serde_json::Deserializer::from_str(line);
 +                deserializer.disable_recursion_limit();
 +                let message = Message::deserialize(&mut deserializer)
 +                    .unwrap_or_else(|_| Message::TextLine(line.to_string()));
 +
 +                match message {
 +                    Message::BuildScriptExecuted(message) => {
 +                        let package = match by_id.get(&message.package_id.repr) {
 +                            Some(&it) => it,
 +                            None => return,
 +                        };
++                        progress(format!("running build-script: {}", workspace[package].name));
++
 +                        let cfgs = {
 +                            let mut acc = Vec::new();
 +                            for cfg in message.cfgs {
 +                                match cfg.parse::<CfgFlag>() {
 +                                    Ok(it) => acc.push(it),
 +                                    Err(err) => {
 +                                        push_err(&format!(
 +                                            "invalid cfg from cargo-metadata: {}",
 +                                            err
 +                                        ));
 +                                        return;
 +                                    }
 +                                };
 +                            }
 +                            acc
 +                        };
 +                        // cargo_metadata crate returns default (empty) path for
 +                        // older cargos, which is not absolute, so work around that.
 +                        let out_dir = message.out_dir.into_os_string();
 +                        if !out_dir.is_empty() {
 +                            let data = outputs[package].get_or_insert_with(Default::default);
 +                            data.out_dir = Some(AbsPathBuf::assert(PathBuf::from(out_dir)));
 +                            data.cfgs = cfgs;
 +                        }
 +                        if !message.env.is_empty() {
 +                            outputs[package].get_or_insert_with(Default::default).envs =
 +                                message.env;
 +                        }
 +                    }
 +                    Message::CompilerArtifact(message) => {
 +                        let package = match by_id.get(&message.package_id.repr) {
 +                            Some(it) => *it,
 +                            None => return,
 +                        };
 +
++                        progress(format!("building proc-macros: {}", message.target.name));
 +
 +                        if message.target.kind.iter().any(|k| k == "proc-macro") {
 +                            // Skip rmeta file
 +                            if let Some(filename) =
 +                                message.filenames.iter().find(|name| is_dylib(name))
 +                            {
 +                                let filename = AbsPathBuf::assert(PathBuf::from(&filename));
 +                                outputs[package]
 +                                    .get_or_insert_with(Default::default)
 +                                    .proc_macro_dylib_path = Some(filename);
 +                            }
 +                        }
 +                    }
 +                    Message::CompilerMessage(message) => {
 +                        progress(message.target.name);
 +
 +                        if let Some(diag) = message.message.rendered.as_deref() {
 +                            push_err(diag);
 +                        }
 +                    }
 +                    Message::BuildFinished(_) => {}
 +                    Message::TextLine(_) => {}
 +                    _ => {}
 +                }
 +            },
 +            &mut |line| {
 +                push_err(line);
 +            },
 +        )?;
 +
 +        for package in workspace.packages() {
 +            if let Some(package_build_data) = &mut outputs[package] {
 +                tracing::info!(
 +                    "{}: {:?}",
 +                    workspace[package].manifest.parent().display(),
 +                    package_build_data,
 +                );
 +                // inject_cargo_env(package, package_build_data);
 +                if let Some(out_dir) = &package_build_data.out_dir {
 +                    // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
 +                    if let Some(out_dir) = out_dir.as_os_str().to_str().map(|s| s.to_owned()) {
 +                        package_build_data.envs.push(("OUT_DIR".to_string(), out_dir));
 +                    }
 +                }
 +            }
 +        }
 +
 +        let mut errors = errors.into_inner();
 +        if !output.status.success() {
 +            if errors.is_empty() {
 +                errors = "cargo check failed".to_string();
 +            }
 +            res.error = Some(errors);
 +        }
 +
 +        Ok(res)
 +    }
 +
 +    pub fn error(&self) -> Option<&str> {
 +        self.error.as_deref()
 +    }
 +
 +    pub(crate) fn get_output(&self, idx: Package) -> Option<&BuildScriptOutput> {
 +        self.outputs.get(idx)?.as_ref()
 +    }
 +}
 +
 +// FIXME: File a better way to know if it is a dylib.
 +fn is_dylib(path: &Utf8Path) -> bool {
 +    match path.extension().map(|e| e.to_string().to_lowercase()) {
 +        None => false,
 +        Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"),
 +    }
 +}
index a4e6550984ee8b577a8a581f96072b7867cb5d70,0000000000000000000000000000000000000000..5445028536cb54fcb6d2ac94da44ed6409223caf
mode 100644,000000..100644
--- /dev/null
@@@ -1,92 -1,0 +1,92 @@@
- anyhow = "1.0.57"
 +[package]
 +name = "rust-analyzer"
 +version = "0.0.0"
 +authors = ["rust-analyzer Team"]
 +homepage = "https://github.com/rust-analyzer/rust-analyzer"
 +description = "A language server for the Rust programming language"
 +documentation = "https://rust-analyzer.github.io/manual.html"
 +license = "MIT OR Apache-2.0"
 +autobins = false
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[[bin]]
 +name = "rust-analyzer"
 +path = "src/bin/main.rs"
 +
 +[dependencies]
- itertools = "0.10.3"
++anyhow = "1.0.62"
 +crossbeam-channel = "0.5.5"
 +dissimilar = "1.0.4"
- mimalloc = { version = "0.1.29", default-features = false, optional = true }
++itertools = "0.10.5"
 +scip = "0.1.1"
 +lsp-types = { version = "0.93.1", features = ["proposed"] }
 +parking_lot = "0.12.1"
 +xflags = "0.3.0"
 +oorandom = "11.1.3"
 +rustc-hash = "1.1.0"
 +serde = { version = "1.0.137", features = ["derive"] }
 +serde_json = { version = "1.0.81", features = ["preserve_order"] }
 +threadpool = "1.8.1"
 +rayon = "1.5.3"
 +num_cpus = "1.13.1"
- tracing-subscriber = { version = "0.3.14", default-features = false, features = [
++mimalloc = { version = "0.1.30", default-features = false, optional = true }
 +lsp-server = { version = "0.7.0", path = "../../lib/lsp-server" }
 +tracing = "0.1.35"
++tracing-subscriber = { version = "0.3.16", default-features = false, features = [
 +    "env-filter",
 +    "registry",
 +    "fmt",
 +    "tracing-log",
 +] }
 +tracing-log = "0.1.3"
 +tracing-tree = "0.2.1"
 +always-assert = "0.1.2"
 +
 +stdx = { path = "../stdx", version = "0.0.0" }
 +flycheck = { path = "../flycheck", version = "0.0.0" }
 +ide = { path = "../ide", version = "0.0.0" }
 +ide-db = { path = "../ide-db", version = "0.0.0" }
 +profile = { path = "../profile", version = "0.0.0" }
 +project-model = { path = "../project-model", version = "0.0.0" }
 +syntax = { path = "../syntax", version = "0.0.0" }
 +vfs = { path = "../vfs", version = "0.0.0" }
 +vfs-notify = { path = "../vfs-notify", version = "0.0.0" }
 +cfg = { path = "../cfg", version = "0.0.0" }
 +toolchain = { path = "../toolchain", version = "0.0.0" }
 +tt = { path = "../tt", version = "0.0.0" }
 +proc-macro-api = { path = "../proc-macro-api", version = "0.0.0" }
 +
 +# This should only be used in CLI
 +ide-ssr = { path = "../ide-ssr", version = "0.0.0" }
 +hir = { path = "../hir", version = "0.0.0" }
 +hir-def = { path = "../hir-def", version = "0.0.0" }
 +hir-ty = { path = "../hir-ty", version = "0.0.0" }
 +proc-macro-srv = { path = "../proc-macro-srv", version = "0.0.0" }
 +
 +[target.'cfg(windows)'.dependencies]
 +winapi = "0.3.9"
 +
 +[target.'cfg(not(target_env = "msvc"))'.dependencies]
 +jemallocator = { version = "0.5.0", package = "tikv-jemallocator", optional = true }
 +
 +[dev-dependencies]
 +expect-test = "1.4.0"
 +jod-thread = "0.1.2"
 +xshell = "0.2.2"
 +
 +test-utils = { path = "../test-utils" }
 +sourcegen = { path = "../sourcegen" }
 +mbe = { path = "../mbe" }
 +
 +[features]
 +jemalloc = ["jemallocator", "profile/jemalloc"]
 +force-always-assert = ["always-assert/force"]
 +in-rust-tree = [
 +    "proc-macro-srv/sysroot-abi",
 +    "ide/in-rust-tree",
 +    "syntax/in-rust-tree",
 +]
index 58099a58de053acb0506bfc61a77b264a987e6dd,0000000000000000000000000000000000000000..24e68eca676d7419ece4bb0125f479f652a617ef
mode 100644,000000..100644
--- /dev/null
@@@ -1,472 -1,0 +1,473 @@@
 +use std::{
 +    collections::HashSet,
 +    path::{Path, PathBuf},
 +};
 +
 +use xshell::Shell;
 +
 +#[cfg(not(feature = "in-rust-tree"))]
 +use xshell::cmd;
 +
 +#[cfg(not(feature = "in-rust-tree"))]
 +#[test]
 +fn check_code_formatting() {
 +    let sh = &Shell::new().unwrap();
 +    sh.change_dir(sourcegen::project_root());
 +
 +    let out = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap();
 +    if !out.contains("stable") {
 +        panic!(
 +            "Failed to run rustfmt from toolchain 'stable'. \
 +                 Please run `rustup component add rustfmt --toolchain stable` to install it.",
 +        )
 +    }
 +
 +    let res = cmd!(sh, "rustup run stable cargo fmt -- --check").run();
 +    if res.is_err() {
 +        let _ = cmd!(sh, "rustup run stable cargo fmt").run();
 +    }
 +    res.unwrap()
 +}
 +
 +#[test]
 +fn check_lsp_extensions_docs() {
 +    let sh = &Shell::new().unwrap();
 +
 +    let expected_hash = {
 +        let lsp_ext_rs = sh
 +            .read_file(sourcegen::project_root().join("crates/rust-analyzer/src/lsp_ext.rs"))
 +            .unwrap();
 +        stable_hash(lsp_ext_rs.as_str())
 +    };
 +
 +    let actual_hash = {
 +        let lsp_extensions_md =
 +            sh.read_file(sourcegen::project_root().join("docs/dev/lsp-extensions.md")).unwrap();
 +        let text = lsp_extensions_md
 +            .lines()
 +            .find_map(|line| line.strip_prefix("lsp_ext.rs hash:"))
 +            .unwrap()
 +            .trim();
 +        u64::from_str_radix(text, 16).unwrap()
 +    };
 +
 +    if actual_hash != expected_hash {
 +        panic!(
 +            "
 +lsp_ext.rs was changed without touching lsp-extensions.md.
 +
 +Expected hash: {:x}
 +Actual hash:   {:x}
 +
 +Please adjust docs/dev/lsp-extensions.md.
 +",
 +            expected_hash, actual_hash
 +        )
 +    }
 +}
 +
 +#[test]
 +fn files_are_tidy() {
 +    let sh = &Shell::new().unwrap();
 +
 +    let files = sourcegen::list_files(&sourcegen::project_root().join("crates"));
 +
 +    let mut tidy_docs = TidyDocs::default();
 +    let mut tidy_marks = TidyMarks::default();
 +    for path in files {
 +        let extension = path.extension().unwrap_or_default().to_str().unwrap_or_default();
 +        match extension {
 +            "rs" => {
 +                let text = sh.read_file(&path).unwrap();
 +                check_todo(&path, &text);
 +                check_dbg(&path, &text);
 +                check_test_attrs(&path, &text);
 +                check_trailing_ws(&path, &text);
 +                deny_clippy(&path, &text);
 +                tidy_docs.visit(&path, &text);
 +                tidy_marks.visit(&path, &text);
 +            }
 +            "toml" => {
 +                let text = sh.read_file(&path).unwrap();
 +                check_cargo_toml(&path, text);
 +            }
 +            _ => (),
 +        }
 +    }
 +
 +    tidy_docs.finish();
 +    tidy_marks.finish();
 +}
 +
 +fn check_cargo_toml(path: &Path, text: String) {
 +    let mut section = None;
 +    for (line_no, text) in text.lines().enumerate() {
 +        let text = text.trim();
 +        if text.starts_with('[') {
 +            if !text.ends_with(']') {
 +                panic!(
 +                    "\nplease don't add comments or trailing whitespace in section lines.\n\
 +                        {}:{}\n",
 +                    path.display(),
 +                    line_no + 1
 +                )
 +            }
 +            section = Some(text);
 +            continue;
 +        }
 +        let text: String = text.split_whitespace().collect();
 +        if !text.contains("path=") {
 +            continue;
 +        }
 +        match section {
 +            Some(s) if s.contains("dev-dependencies") => {
 +                if text.contains("version") {
 +                    panic!(
 +                        "\ncargo internal dev-dependencies should not have a version.\n\
 +                        {}:{}\n",
 +                        path.display(),
 +                        line_no + 1
 +                    );
 +                }
 +            }
 +            Some(s) if s.contains("dependencies") => {
 +                if !text.contains("version") {
 +                    panic!(
 +                        "\ncargo internal dependencies should have a version.\n\
 +                        {}:{}\n",
 +                        path.display(),
 +                        line_no + 1
 +                    );
 +                }
 +            }
 +            _ => {}
 +        }
 +    }
 +}
 +
 +fn deny_clippy(path: &Path, text: &str) {
 +    let ignore = &[
 +        // The documentation in string literals may contain anything for its own purposes
 +        "ide-db/src/generated/lints.rs",
 +        // The tests test clippy lint hovers
 +        "ide/src/hover/tests.rs",
 +        // The tests test clippy lint completions
 +        "ide-completion/src/tests/attribute.rs",
 +    ];
 +    if ignore.iter().any(|p| path.ends_with(p)) {
 +        return;
 +    }
 +
 +    if text.contains("\u{61}llow(clippy") {
 +        panic!(
 +            "\n\nallowing lints is forbidden: {}.
 +rust-analyzer intentionally doesn't check clippy on CI.
 +You can allow lint globally via `xtask clippy`.
 +See https://github.com/rust-lang/rust-clippy/issues/5537 for discussion.
 +
 +",
 +            path.display()
 +        )
 +    }
 +}
 +
 +#[cfg(not(feature = "in-rust-tree"))]
 +#[test]
 +fn check_licenses() {
 +    let sh = &Shell::new().unwrap();
 +
 +    let expected = "
++(MIT OR Apache-2.0) AND Unicode-DFS-2016
 +0BSD OR MIT OR Apache-2.0
 +Apache-2.0
 +Apache-2.0 OR BSL-1.0
 +Apache-2.0 OR MIT
 +Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT
 +Apache-2.0/MIT
 +BSD-3-Clause
 +BlueOak-1.0.0 OR MIT OR Apache-2.0
 +CC0-1.0 OR Artistic-2.0
 +ISC
 +MIT
 +MIT / Apache-2.0
 +MIT OR Apache-2.0
 +MIT OR Apache-2.0 OR Zlib
 +MIT OR Zlib OR Apache-2.0
 +MIT/Apache-2.0
 +Unlicense/MIT
 +Zlib OR Apache-2.0 OR MIT
 +"
 +    .lines()
 +    .filter(|it| !it.is_empty())
 +    .collect::<Vec<_>>();
 +
 +    let meta = cmd!(sh, "cargo metadata --format-version 1").read().unwrap();
 +    let mut licenses = meta
 +        .split(|c| c == ',' || c == '{' || c == '}')
 +        .filter(|it| it.contains(r#""license""#))
 +        .map(|it| it.trim())
 +        .map(|it| it[r#""license":"#.len()..].trim_matches('"'))
 +        .collect::<Vec<_>>();
 +    licenses.sort_unstable();
 +    licenses.dedup();
 +    if licenses != expected {
 +        let mut diff = String::new();
 +
 +        diff.push_str("New Licenses:\n");
 +        for &l in licenses.iter() {
 +            if !expected.contains(&l) {
 +                diff += &format!("  {}\n", l)
 +            }
 +        }
 +
 +        diff.push_str("\nMissing Licenses:\n");
 +        for &l in expected.iter() {
 +            if !licenses.contains(&l) {
 +                diff += &format!("  {}\n", l)
 +            }
 +        }
 +
 +        panic!("different set of licenses!\n{}", diff);
 +    }
 +    assert_eq!(licenses, expected);
 +}
 +
 +fn check_todo(path: &Path, text: &str) {
 +    let need_todo = &[
 +        // This file itself obviously needs to use todo (<- like this!).
 +        "tests/tidy.rs",
 +        // Some of our assists generate `todo!()`.
 +        "handlers/add_turbo_fish.rs",
 +        "handlers/generate_function.rs",
 +        "handlers/add_missing_match_arms.rs",
 +        "handlers/replace_derive_with_manual_impl.rs",
 +        // To support generating `todo!()` in assists, we have `expr_todo()` in
 +        // `ast::make`.
 +        "ast/make.rs",
 +        // The documentation in string literals may contain anything for its own purposes
 +        "ide-db/src/generated/lints.rs",
 +        "ide-assists/src/utils/gen_trait_fn_body.rs",
 +        "ide-assists/src/tests/generated.rs",
 +        // The tests for missing fields
 +        "ide-diagnostics/src/handlers/missing_fields.rs",
 +    ];
 +    if need_todo.iter().any(|p| path.ends_with(p)) {
 +        return;
 +    }
 +    if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") {
 +        // Generated by an assist
 +        if text.contains("${0:todo!()}") {
 +            return;
 +        }
 +
 +        panic!(
 +            "\nTODO markers or todo! macros should not be committed to the master branch,\n\
 +             use FIXME instead\n\
 +             {}\n",
 +            path.display(),
 +        )
 +    }
 +}
 +
 +fn check_dbg(path: &Path, text: &str) {
 +    let need_dbg = &[
 +        // This file itself obviously needs to use dbg.
 +        "slow-tests/tidy.rs",
 +        // Assists to remove `dbg!()`
 +        "handlers/remove_dbg.rs",
 +        // We have .dbg postfix
 +        "ide-completion/src/completions/postfix.rs",
 +        "ide-completion/src/completions/keyword.rs",
 +        "ide-completion/src/tests/proc_macros.rs",
 +        // The documentation in string literals may contain anything for its own purposes
 +        "ide-completion/src/lib.rs",
 +        "ide-db/src/generated/lints.rs",
 +        // test for doc test for remove_dbg
 +        "src/tests/generated.rs",
 +    ];
 +    if need_dbg.iter().any(|p| path.ends_with(p)) {
 +        return;
 +    }
 +    if text.contains("dbg!") {
 +        panic!(
 +            "\ndbg! macros should not be committed to the master branch,\n\
 +             {}\n",
 +            path.display(),
 +        )
 +    }
 +}
 +
 +fn check_test_attrs(path: &Path, text: &str) {
 +    let ignore_rule =
 +        "https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/style.md#ignore";
 +    let need_ignore: &[&str] = &[
 +        // This file.
 +        "slow-tests/tidy.rs",
 +        // Special case to run `#[ignore]` tests.
 +        "ide/src/runnables.rs",
 +        // A legit test which needs to be ignored, as it takes too long to run
 +        // :(
 +        "hir-def/src/nameres/collector.rs",
 +        // Long sourcegen test to generate lint completions.
 +        "ide-db/src/tests/sourcegen_lints.rs",
 +        // Obviously needs ignore.
 +        "ide-assists/src/handlers/toggle_ignore.rs",
 +        // See above.
 +        "ide-assists/src/tests/generated.rs",
 +    ];
 +    if text.contains("#[ignore") && !need_ignore.iter().any(|p| path.ends_with(p)) {
 +        panic!("\ndon't `#[ignore]` tests, see:\n\n    {}\n\n   {}\n", ignore_rule, path.display(),)
 +    }
 +
 +    let panic_rule =
 +        "https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/style.md#should_panic";
 +    let need_panic: &[&str] = &[
 +        // This file.
 +        "slow-tests/tidy.rs",
 +        "test-utils/src/fixture.rs",
 +    ];
 +    if text.contains("#[should_panic") && !need_panic.iter().any(|p| path.ends_with(p)) {
 +        panic!(
 +            "\ndon't add `#[should_panic]` tests, see:\n\n    {}\n\n   {}\n",
 +            panic_rule,
 +            path.display(),
 +        )
 +    }
 +}
 +
 +fn check_trailing_ws(path: &Path, text: &str) {
 +    if is_exclude_dir(path, &["test_data"]) {
 +        return;
 +    }
 +    for (line_number, line) in text.lines().enumerate() {
 +        if line.chars().last().map(char::is_whitespace) == Some(true) {
 +            panic!("Trailing whitespace in {} at line {}", path.display(), line_number + 1)
 +        }
 +    }
 +}
 +
 +#[derive(Default)]
 +struct TidyDocs {
 +    missing_docs: Vec<String>,
 +    contains_fixme: Vec<PathBuf>,
 +}
 +
 +impl TidyDocs {
 +    fn visit(&mut self, path: &Path, text: &str) {
 +        // Tests and diagnostic fixes don't need module level comments.
 +        if is_exclude_dir(path, &["tests", "test_data", "fixes", "grammar"]) {
 +            return;
 +        }
 +
 +        if is_exclude_file(path) {
 +            return;
 +        }
 +
 +        let first_line = match text.lines().next() {
 +            Some(it) => it,
 +            None => return,
 +        };
 +
 +        if first_line.starts_with("//!") {
 +            if first_line.contains("FIXME") {
 +                self.contains_fixme.push(path.to_path_buf());
 +            }
 +        } else {
 +            if text.contains("// Feature:")
 +                || text.contains("// Assist:")
 +                || text.contains("// Diagnostic:")
 +            {
 +                return;
 +            }
 +            self.missing_docs.push(path.display().to_string());
 +        }
 +
 +        fn is_exclude_file(d: &Path) -> bool {
 +            let file_names = ["tests.rs", "famous_defs_fixture.rs"];
 +
 +            d.file_name()
 +                .unwrap_or_default()
 +                .to_str()
 +                .map(|f_n| file_names.iter().any(|name| *name == f_n))
 +                .unwrap_or(false)
 +        }
 +    }
 +
 +    fn finish(self) {
 +        if !self.missing_docs.is_empty() {
 +            panic!(
 +                "\nMissing docs strings\n\n\
 +                 modules:\n{}\n\n",
 +                self.missing_docs.join("\n")
 +            )
 +        }
 +
 +        for path in self.contains_fixme {
 +            panic!("FIXME doc in a fully-documented crate: {}", path.display())
 +        }
 +    }
 +}
 +
 +fn is_exclude_dir(p: &Path, dirs_to_exclude: &[&str]) -> bool {
 +    p.strip_prefix(sourcegen::project_root())
 +        .unwrap()
 +        .components()
 +        .rev()
 +        .skip(1)
 +        .filter_map(|it| it.as_os_str().to_str())
 +        .any(|it| dirs_to_exclude.contains(&it))
 +}
 +
 +#[derive(Default)]
 +struct TidyMarks {
 +    hits: HashSet<String>,
 +    checks: HashSet<String>,
 +}
 +
 +impl TidyMarks {
 +    fn visit(&mut self, _path: &Path, text: &str) {
 +        find_marks(&mut self.hits, text, "hit");
 +        find_marks(&mut self.checks, text, "check");
 +        find_marks(&mut self.checks, text, "check_count");
 +    }
 +
 +    fn finish(self) {
 +        assert!(!self.hits.is_empty());
 +
 +        let diff: Vec<_> =
 +            self.hits.symmetric_difference(&self.checks).map(|it| it.as_str()).collect();
 +
 +        if !diff.is_empty() {
 +            panic!("unpaired marks: {:?}", diff)
 +        }
 +    }
 +}
 +
 +#[allow(deprecated)]
 +fn stable_hash(text: &str) -> u64 {
 +    use std::hash::{Hash, Hasher, SipHasher};
 +
 +    let text = text.replace('\r', "");
 +    let mut hasher = SipHasher::default();
 +    text.hash(&mut hasher);
 +    hasher.finish()
 +}
 +
 +fn find_marks(set: &mut HashSet<String>, text: &str, mark: &str) {
 +    let mut text = text;
 +    let mut prev_text = "";
 +    while text != prev_text {
 +        prev_text = text;
 +        if let Some(idx) = text.find(mark) {
 +            text = &text[idx + mark.len()..];
 +            if let Some(stripped_text) = text.strip_prefix("!(") {
 +                text = stripped_text.trim_start();
 +                if let Some(idx2) = text.find(|c: char| !(c.is_alphanumeric() || c == '_')) {
 +                    let mark_text = &text[..idx2];
 +                    set.insert(mark_text.to_string());
 +                    text = &text[idx2..];
 +                }
 +            }
 +        }
 +    }
 +}
index 092b99ae5152d7d54dd638c3f83359ebb95075c1,0000000000000000000000000000000000000000..e0657ab0f6d1c20fe439a74720da590b07cf8c3e
mode 100644,000000..100644
--- /dev/null
@@@ -1,24 -1,0 +1,24 @@@
- libc = "0.2.126"
 +[package]
 +name = "stdx"
 +version = "0.0.0"
 +description = "TBD"
 +license = "MIT OR Apache-2.0"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
++libc = "0.2.135"
 +backtrace = { version = "0.3.65", optional = true }
 +always-assert = { version = "0.1.2", features = ["log"] }
 +# Think twice before adding anything here
 +
 +[target.'cfg(windows)'.dependencies]
 +miow = "0.4.0"
 +winapi = { version = "0.3.9", features = ["winerror"] }
 +
 +[features]
 +# Uncomment to enable for the whole crate graph
 +# default = [ "backtrace" ]
index 0e2dec386ff77387392162db323a35fd5f11f8bf,0000000000000000000000000000000000000000..1ef903371cf896de2c31abf83b17d1b58af112d3
mode 100644,000000..100644
--- /dev/null
@@@ -1,39 -1,0 +1,39 @@@
- itertools = "0.10.3"
- rowan = "0.15.8"
 +[package]
 +name = "syntax"
 +version = "0.0.0"
 +description = "Comment and whitespace preserving parser for the Rust language"
 +license = "MIT OR Apache-2.0"
 +repository = "https://github.com/rust-lang/rust-analyzer"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
 +cov-mark = "2.0.0-pre.1"
- once_cell = "1.12.0"
++itertools = "0.10.5"
++rowan = "0.15.10"
 +rustc_lexer = { version = "725.0.0", package = "rustc-ap-rustc_lexer" }
 +rustc-hash = "1.1.0"
- proc-macro2 = "1.0.39"
++once_cell = "1.15.0"
 +indexmap = "1.9.1"
 +smol_str = "0.1.23"
 +
 +stdx = { path = "../stdx", version = "0.0.0" }
 +text-edit = { path = "../text-edit", version = "0.0.0" }
 +parser = { path = "../parser", version = "0.0.0" }
 +profile = { path = "../profile", version = "0.0.0" }
 +
 +[dev-dependencies]
 +rayon = "1.5.3"
 +expect-test = "1.4.0"
++proc-macro2 = "1.0.47"
 +quote = "1.0.20"
 +ungrammar = "1.16.1"
 +
 +test-utils = { path = "../test-utils" }
 +sourcegen = { path = "../sourcegen" }
 +
 +[features]
 +in-rust-tree = []
index eadebbe8a212bab90ff4a0857012ec762611865b,0000000000000000000000000000000000000000..229e7419b736febecf341b114dc86b121e6e006d
mode 100644,000000..100644
--- /dev/null
@@@ -1,840 -1,0 +1,894 @@@
-             let arg_list = make::generic_arg_list().clone_for_update();
 +//! Structural editing for ast.
 +
 +use std::iter::{empty, successors};
 +
 +use parser::{SyntaxKind, T};
 +use rowan::SyntaxElement;
 +
 +use crate::{
 +    algo::{self, neighbor},
 +    ast::{self, edit::IndentLevel, make, HasGenericParams},
 +    ted::{self, Position},
 +    AstNode, AstToken, Direction,
 +    SyntaxKind::{ATTR, COMMENT, WHITESPACE},
 +    SyntaxNode, SyntaxToken,
 +};
 +
 +use super::HasName;
 +
 +pub trait GenericParamsOwnerEdit: ast::HasGenericParams {
 +    fn get_or_create_generic_param_list(&self) -> ast::GenericParamList;
 +    fn get_or_create_where_clause(&self) -> ast::WhereClause;
 +}
 +
 +impl GenericParamsOwnerEdit for ast::Fn {
 +    fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
 +        match self.generic_param_list() {
 +            Some(it) => it,
 +            None => {
 +                let position = if let Some(name) = self.name() {
 +                    Position::after(name.syntax)
 +                } else if let Some(fn_token) = self.fn_token() {
 +                    Position::after(fn_token)
 +                } else if let Some(param_list) = self.param_list() {
 +                    Position::before(param_list.syntax)
 +                } else {
 +                    Position::last_child_of(self.syntax())
 +                };
 +                create_generic_param_list(position)
 +            }
 +        }
 +    }
 +
 +    fn get_or_create_where_clause(&self) -> ast::WhereClause {
 +        if self.where_clause().is_none() {
 +            let position = if let Some(ty) = self.ret_type() {
 +                Position::after(ty.syntax())
 +            } else if let Some(param_list) = self.param_list() {
 +                Position::after(param_list.syntax())
 +            } else {
 +                Position::last_child_of(self.syntax())
 +            };
 +            create_where_clause(position);
 +        }
 +        self.where_clause().unwrap()
 +    }
 +}
 +
 +impl GenericParamsOwnerEdit for ast::Impl {
 +    fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
 +        match self.generic_param_list() {
 +            Some(it) => it,
 +            None => {
 +                let position = match self.impl_token() {
 +                    Some(imp_token) => Position::after(imp_token),
 +                    None => Position::last_child_of(self.syntax()),
 +                };
 +                create_generic_param_list(position)
 +            }
 +        }
 +    }
 +
 +    fn get_or_create_where_clause(&self) -> ast::WhereClause {
 +        if self.where_clause().is_none() {
 +            let position = match self.assoc_item_list() {
 +                Some(items) => Position::before(items.syntax()),
 +                None => Position::last_child_of(self.syntax()),
 +            };
 +            create_where_clause(position);
 +        }
 +        self.where_clause().unwrap()
 +    }
 +}
 +
 +impl GenericParamsOwnerEdit for ast::Trait {
 +    fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
 +        match self.generic_param_list() {
 +            Some(it) => it,
 +            None => {
 +                let position = if let Some(name) = self.name() {
 +                    Position::after(name.syntax)
 +                } else if let Some(trait_token) = self.trait_token() {
 +                    Position::after(trait_token)
 +                } else {
 +                    Position::last_child_of(self.syntax())
 +                };
 +                create_generic_param_list(position)
 +            }
 +        }
 +    }
 +
 +    fn get_or_create_where_clause(&self) -> ast::WhereClause {
 +        if self.where_clause().is_none() {
 +            let position = match self.assoc_item_list() {
 +                Some(items) => Position::before(items.syntax()),
 +                None => Position::last_child_of(self.syntax()),
 +            };
 +            create_where_clause(position);
 +        }
 +        self.where_clause().unwrap()
 +    }
 +}
 +
 +impl GenericParamsOwnerEdit for ast::Struct {
 +    fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
 +        match self.generic_param_list() {
 +            Some(it) => it,
 +            None => {
 +                let position = if let Some(name) = self.name() {
 +                    Position::after(name.syntax)
 +                } else if let Some(struct_token) = self.struct_token() {
 +                    Position::after(struct_token)
 +                } else {
 +                    Position::last_child_of(self.syntax())
 +                };
 +                create_generic_param_list(position)
 +            }
 +        }
 +    }
 +
 +    fn get_or_create_where_clause(&self) -> ast::WhereClause {
 +        if self.where_clause().is_none() {
 +            let tfl = self.field_list().and_then(|fl| match fl {
 +                ast::FieldList::RecordFieldList(_) => None,
 +                ast::FieldList::TupleFieldList(it) => Some(it),
 +            });
 +            let position = if let Some(tfl) = tfl {
 +                Position::after(tfl.syntax())
 +            } else if let Some(gpl) = self.generic_param_list() {
 +                Position::after(gpl.syntax())
 +            } else if let Some(name) = self.name() {
 +                Position::after(name.syntax())
 +            } else {
 +                Position::last_child_of(self.syntax())
 +            };
 +            create_where_clause(position);
 +        }
 +        self.where_clause().unwrap()
 +    }
 +}
 +
 +impl GenericParamsOwnerEdit for ast::Enum {
 +    fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
 +        match self.generic_param_list() {
 +            Some(it) => it,
 +            None => {
 +                let position = if let Some(name) = self.name() {
 +                    Position::after(name.syntax)
 +                } else if let Some(enum_token) = self.enum_token() {
 +                    Position::after(enum_token)
 +                } else {
 +                    Position::last_child_of(self.syntax())
 +                };
 +                create_generic_param_list(position)
 +            }
 +        }
 +    }
 +
 +    fn get_or_create_where_clause(&self) -> ast::WhereClause {
 +        if self.where_clause().is_none() {
 +            let position = if let Some(gpl) = self.generic_param_list() {
 +                Position::after(gpl.syntax())
 +            } else if let Some(name) = self.name() {
 +                Position::after(name.syntax())
 +            } else {
 +                Position::last_child_of(self.syntax())
 +            };
 +            create_where_clause(position);
 +        }
 +        self.where_clause().unwrap()
 +    }
 +}
 +
 +fn create_where_clause(position: Position) {
 +    let where_clause = make::where_clause(empty()).clone_for_update();
 +    ted::insert(position, where_clause.syntax());
 +}
 +
 +fn create_generic_param_list(position: Position) -> ast::GenericParamList {
 +    let gpl = make::generic_param_list(empty()).clone_for_update();
 +    ted::insert_raw(position, gpl.syntax());
 +    gpl
 +}
 +
 +pub trait AttrsOwnerEdit: ast::HasAttrs {
 +    fn remove_attrs_and_docs(&self) {
 +        remove_attrs_and_docs(self.syntax());
 +
 +        fn remove_attrs_and_docs(node: &SyntaxNode) {
 +            let mut remove_next_ws = false;
 +            for child in node.children_with_tokens() {
 +                match child.kind() {
 +                    ATTR | COMMENT => {
 +                        remove_next_ws = true;
 +                        child.detach();
 +                        continue;
 +                    }
 +                    WHITESPACE if remove_next_ws => {
 +                        child.detach();
 +                    }
 +                    _ => (),
 +                }
 +                remove_next_ws = false;
 +            }
 +        }
 +    }
 +}
 +
 +impl<T: ast::HasAttrs> AttrsOwnerEdit for T {}
 +
 +impl ast::GenericParamList {
 +    pub fn add_generic_param(&self, generic_param: ast::GenericParam) {
 +        match self.generic_params().last() {
 +            Some(last_param) => {
 +                let position = Position::after(last_param.syntax());
 +                let elements = vec![
 +                    make::token(T![,]).into(),
 +                    make::tokens::single_space().into(),
 +                    generic_param.syntax().clone().into(),
 +                ];
 +                ted::insert_all(position, elements);
 +            }
 +            None => {
 +                let after_l_angle = Position::after(self.l_angle_token().unwrap());
 +                ted::insert(after_l_angle, generic_param.syntax());
 +            }
 +        }
 +    }
++
++    /// Constructs a matching [`ast::GenericArgList`]
++    pub fn to_generic_args(&self) -> ast::GenericArgList {
++        let args = self.generic_params().filter_map(|param| match param {
++            ast::GenericParam::LifetimeParam(it) => {
++                Some(ast::GenericArg::LifetimeArg(make::lifetime_arg(it.lifetime()?)))
++            }
++            ast::GenericParam::TypeParam(it) => {
++                Some(ast::GenericArg::TypeArg(make::type_arg(make::ext::ty_name(it.name()?))))
++            }
++            ast::GenericParam::ConstParam(it) => {
++                // Name-only const params get parsed as `TypeArg`s
++                Some(ast::GenericArg::TypeArg(make::type_arg(make::ext::ty_name(it.name()?))))
++            }
++        });
++
++        make::generic_arg_list(args)
++    }
 +}
 +
 +impl ast::WhereClause {
 +    pub fn add_predicate(&self, predicate: ast::WherePred) {
 +        if let Some(pred) = self.predicates().last() {
 +            if !pred.syntax().siblings_with_tokens(Direction::Next).any(|it| it.kind() == T![,]) {
 +                ted::append_child_raw(self.syntax(), make::token(T![,]));
 +            }
 +        }
 +        ted::append_child(self.syntax(), predicate.syntax());
 +    }
 +}
 +
++impl ast::TypeParam {
++    pub fn remove_default(&self) {
++        if let Some((eq, last)) = self
++            .syntax()
++            .children_with_tokens()
++            .find(|it| it.kind() == T![=])
++            .zip(self.syntax().last_child_or_token())
++        {
++            ted::remove_all(eq..=last);
++
++            // remove any trailing ws
++            if let Some(last) = self.syntax().last_token().filter(|it| it.kind() == WHITESPACE) {
++                last.detach();
++            }
++        }
++    }
++}
++
++impl ast::ConstParam {
++    pub fn remove_default(&self) {
++        if let Some((eq, last)) = self
++            .syntax()
++            .children_with_tokens()
++            .find(|it| it.kind() == T![=])
++            .zip(self.syntax().last_child_or_token())
++        {
++            ted::remove_all(eq..=last);
++
++            // remove any trailing ws
++            if let Some(last) = self.syntax().last_token().filter(|it| it.kind() == WHITESPACE) {
++                last.detach();
++            }
++        }
++    }
++}
++
 +pub trait Removable: AstNode {
 +    fn remove(&self);
 +}
 +
 +impl Removable for ast::TypeBoundList {
 +    fn remove(&self) {
 +        match self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) {
 +            Some(colon) => ted::remove_all(colon..=self.syntax().clone().into()),
 +            None => ted::remove(self.syntax()),
 +        }
 +    }
 +}
 +
 +impl ast::PathSegment {
 +    pub fn get_or_create_generic_arg_list(&self) -> ast::GenericArgList {
 +        if self.generic_arg_list().is_none() {
++            let arg_list = make::generic_arg_list(empty()).clone_for_update();
 +            ted::append_child(self.syntax(), arg_list.syntax());
 +        }
 +        self.generic_arg_list().unwrap()
 +    }
 +}
 +
 +impl Removable for ast::UseTree {
 +    fn remove(&self) {
 +        for dir in [Direction::Next, Direction::Prev] {
 +            if let Some(next_use_tree) = neighbor(self, dir) {
 +                let separators = self
 +                    .syntax()
 +                    .siblings_with_tokens(dir)
 +                    .skip(1)
 +                    .take_while(|it| it.as_node() != Some(next_use_tree.syntax()));
 +                ted::remove_all_iter(separators);
 +                break;
 +            }
 +        }
 +        ted::remove(self.syntax());
 +    }
 +}
 +
 +impl ast::UseTree {
 +    pub fn get_or_create_use_tree_list(&self) -> ast::UseTreeList {
 +        match self.use_tree_list() {
 +            Some(it) => it,
 +            None => {
 +                let position = Position::last_child_of(self.syntax());
 +                let use_tree_list = make::use_tree_list(empty()).clone_for_update();
 +                let mut elements = Vec::with_capacity(2);
 +                if self.coloncolon_token().is_none() {
 +                    elements.push(make::token(T![::]).into());
 +                }
 +                elements.push(use_tree_list.syntax().clone().into());
 +                ted::insert_all_raw(position, elements);
 +                use_tree_list
 +            }
 +        }
 +    }
 +
 +    /// Splits off the given prefix, making it the path component of the use tree,
 +    /// appending the rest of the path to all UseTreeList items.
 +    ///
 +    /// # Examples
 +    ///
 +    /// `prefix$0::suffix` -> `prefix::{suffix}`
 +    ///
 +    /// `prefix$0` -> `prefix::{self}`
 +    ///
 +    /// `prefix$0::*` -> `prefix::{*}`
 +    pub fn split_prefix(&self, prefix: &ast::Path) {
 +        debug_assert_eq!(self.path(), Some(prefix.top_path()));
 +        let path = self.path().unwrap();
 +        if &path == prefix && self.use_tree_list().is_none() {
 +            if self.star_token().is_some() {
 +                // path$0::* -> *
 +                self.coloncolon_token().map(ted::remove);
 +                ted::remove(prefix.syntax());
 +            } else {
 +                // path$0 -> self
 +                let self_suffix =
 +                    make::path_unqualified(make::path_segment_self()).clone_for_update();
 +                ted::replace(path.syntax(), self_suffix.syntax());
 +            }
 +        } else if split_path_prefix(prefix).is_none() {
 +            return;
 +        }
 +        // At this point, prefix path is detached; _self_ use tree has suffix path.
 +        // Next, transform 'suffix' use tree into 'prefix::{suffix}'
 +        let subtree = self.clone_subtree().clone_for_update();
 +        ted::remove_all_iter(self.syntax().children_with_tokens());
 +        ted::insert(Position::first_child_of(self.syntax()), prefix.syntax());
 +        self.get_or_create_use_tree_list().add_use_tree(subtree);
 +
 +        fn split_path_prefix(prefix: &ast::Path) -> Option<()> {
 +            let parent = prefix.parent_path()?;
 +            let segment = parent.segment()?;
 +            if algo::has_errors(segment.syntax()) {
 +                return None;
 +            }
 +            for p in successors(parent.parent_path(), |it| it.parent_path()) {
 +                p.segment()?;
 +            }
 +            prefix.parent_path().and_then(|p| p.coloncolon_token()).map(ted::remove);
 +            ted::remove(prefix.syntax());
 +            Some(())
 +        }
 +    }
 +}
 +
 +impl ast::UseTreeList {
 +    pub fn add_use_tree(&self, use_tree: ast::UseTree) {
 +        let (position, elements) = match self.use_trees().last() {
 +            Some(last_tree) => (
 +                Position::after(last_tree.syntax()),
 +                vec![
 +                    make::token(T![,]).into(),
 +                    make::tokens::single_space().into(),
 +                    use_tree.syntax.into(),
 +                ],
 +            ),
 +            None => {
 +                let position = match self.l_curly_token() {
 +                    Some(l_curly) => Position::after(l_curly),
 +                    None => Position::last_child_of(self.syntax()),
 +                };
 +                (position, vec![use_tree.syntax.into()])
 +            }
 +        };
 +        ted::insert_all_raw(position, elements);
 +    }
 +}
 +
 +impl Removable for ast::Use {
 +    fn remove(&self) {
 +        let next_ws = self
 +            .syntax()
 +            .next_sibling_or_token()
 +            .and_then(|it| it.into_token())
 +            .and_then(ast::Whitespace::cast);
 +        if let Some(next_ws) = next_ws {
 +            let ws_text = next_ws.syntax().text();
 +            if let Some(rest) = ws_text.strip_prefix('\n') {
 +                if rest.is_empty() {
 +                    ted::remove(next_ws.syntax());
 +                } else {
 +                    ted::replace(next_ws.syntax(), make::tokens::whitespace(rest));
 +                }
 +            }
 +        }
 +        ted::remove(self.syntax());
 +    }
 +}
 +
 +impl ast::Impl {
 +    pub fn get_or_create_assoc_item_list(&self) -> ast::AssocItemList {
 +        if self.assoc_item_list().is_none() {
 +            let assoc_item_list = make::assoc_item_list().clone_for_update();
 +            ted::append_child(self.syntax(), assoc_item_list.syntax());
 +        }
 +        self.assoc_item_list().unwrap()
 +    }
 +}
 +
 +impl ast::AssocItemList {
 +    pub fn add_item(&self, item: ast::AssocItem) {
 +        let (indent, position, whitespace) = match self.assoc_items().last() {
 +            Some(last_item) => (
 +                IndentLevel::from_node(last_item.syntax()),
 +                Position::after(last_item.syntax()),
 +                "\n\n",
 +            ),
 +            None => match self.l_curly_token() {
 +                Some(l_curly) => {
 +                    normalize_ws_between_braces(self.syntax());
 +                    (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly), "\n")
 +                }
 +                None => (IndentLevel::single(), Position::last_child_of(self.syntax()), "\n"),
 +            },
 +        };
 +        let elements: Vec<SyntaxElement<_>> = vec![
 +            make::tokens::whitespace(&format!("{}{}", whitespace, indent)).into(),
 +            item.syntax().clone().into(),
 +        ];
 +        ted::insert_all(position, elements);
 +    }
 +}
 +
 +impl ast::Fn {
 +    pub fn get_or_create_body(&self) -> ast::BlockExpr {
 +        if self.body().is_none() {
 +            let body = make::ext::empty_block_expr().clone_for_update();
 +            match self.semicolon_token() {
 +                Some(semi) => {
 +                    ted::replace(semi, body.syntax());
 +                    ted::insert(Position::before(body.syntax), make::tokens::single_space());
 +                }
 +                None => ted::append_child(self.syntax(), body.syntax()),
 +            }
 +        }
 +        self.body().unwrap()
 +    }
 +}
 +
 +impl Removable for ast::MatchArm {
 +    fn remove(&self) {
 +        if let Some(sibling) = self.syntax().prev_sibling_or_token() {
 +            if sibling.kind() == SyntaxKind::WHITESPACE {
 +                ted::remove(sibling);
 +            }
 +        }
 +        if let Some(sibling) = self.syntax().next_sibling_or_token() {
 +            if sibling.kind() == T![,] {
 +                ted::remove(sibling);
 +            }
 +        }
 +        ted::remove(self.syntax());
 +    }
 +}
 +
 +impl ast::MatchArmList {
 +    pub fn add_arm(&self, arm: ast::MatchArm) {
 +        normalize_ws_between_braces(self.syntax());
 +        let mut elements = Vec::new();
 +        let position = match self.arms().last() {
 +            Some(last_arm) => {
 +                if needs_comma(&last_arm) {
 +                    ted::append_child(last_arm.syntax(), make::token(SyntaxKind::COMMA));
 +                }
 +                Position::after(last_arm.syntax().clone())
 +            }
 +            None => match self.l_curly_token() {
 +                Some(it) => Position::after(it),
 +                None => Position::last_child_of(self.syntax()),
 +            },
 +        };
 +        let indent = IndentLevel::from_node(self.syntax()) + 1;
 +        elements.push(make::tokens::whitespace(&format!("\n{}", indent)).into());
 +        elements.push(arm.syntax().clone().into());
 +        if needs_comma(&arm) {
 +            ted::append_child(arm.syntax(), make::token(SyntaxKind::COMMA));
 +        }
 +        ted::insert_all(position, elements);
 +
 +        fn needs_comma(arm: &ast::MatchArm) -> bool {
 +            arm.expr().map_or(false, |e| !e.is_block_like()) && arm.comma_token().is_none()
 +        }
 +    }
 +}
 +
 +impl ast::RecordExprFieldList {
 +    pub fn add_field(&self, field: ast::RecordExprField) {
 +        let is_multiline = self.syntax().text().contains_char('\n');
 +        let whitespace = if is_multiline {
 +            let indent = IndentLevel::from_node(self.syntax()) + 1;
 +            make::tokens::whitespace(&format!("\n{}", indent))
 +        } else {
 +            make::tokens::single_space()
 +        };
 +
 +        if is_multiline {
 +            normalize_ws_between_braces(self.syntax());
 +        }
 +
 +        let position = match self.fields().last() {
 +            Some(last_field) => {
 +                let comma = get_or_insert_comma_after(last_field.syntax());
 +                Position::after(comma)
 +            }
 +            None => match self.l_curly_token() {
 +                Some(it) => Position::after(it),
 +                None => Position::last_child_of(self.syntax()),
 +            },
 +        };
 +
 +        ted::insert_all(position, vec![whitespace.into(), field.syntax().clone().into()]);
 +        if is_multiline {
 +            ted::insert(Position::after(field.syntax()), ast::make::token(T![,]));
 +        }
 +    }
 +}
 +
 +impl ast::RecordExprField {
 +    /// This will either replace the initializer, or in the case that this is a shorthand convert
 +    /// the initializer into the name ref and insert the expr as the new initializer.
 +    pub fn replace_expr(&self, expr: ast::Expr) {
 +        if self.name_ref().is_some() {
 +            match self.expr() {
 +                Some(prev) => ted::replace(prev.syntax(), expr.syntax()),
 +                None => ted::append_child(self.syntax(), expr.syntax()),
 +            }
 +            return;
 +        }
 +        // this is a shorthand
 +        if let Some(ast::Expr::PathExpr(path_expr)) = self.expr() {
 +            if let Some(path) = path_expr.path() {
 +                if let Some(name_ref) = path.as_single_name_ref() {
 +                    path_expr.syntax().detach();
 +                    let children = vec![
 +                        name_ref.syntax().clone().into(),
 +                        ast::make::token(T![:]).into(),
 +                        ast::make::tokens::single_space().into(),
 +                        expr.syntax().clone().into(),
 +                    ];
 +                    ted::insert_all_raw(Position::last_child_of(self.syntax()), children);
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +impl ast::RecordPatFieldList {
 +    pub fn add_field(&self, field: ast::RecordPatField) {
 +        let is_multiline = self.syntax().text().contains_char('\n');
 +        let whitespace = if is_multiline {
 +            let indent = IndentLevel::from_node(self.syntax()) + 1;
 +            make::tokens::whitespace(&format!("\n{}", indent))
 +        } else {
 +            make::tokens::single_space()
 +        };
 +
 +        if is_multiline {
 +            normalize_ws_between_braces(self.syntax());
 +        }
 +
 +        let position = match self.fields().last() {
 +            Some(last_field) => {
 +                let syntax = last_field.syntax();
 +                let comma = get_or_insert_comma_after(syntax);
 +                Position::after(comma)
 +            }
 +            None => match self.l_curly_token() {
 +                Some(it) => Position::after(it),
 +                None => Position::last_child_of(self.syntax()),
 +            },
 +        };
 +
 +        ted::insert_all(position, vec![whitespace.into(), field.syntax().clone().into()]);
 +        if is_multiline {
 +            ted::insert(Position::after(field.syntax()), ast::make::token(T![,]));
 +        }
 +    }
 +}
 +
 +fn get_or_insert_comma_after(syntax: &SyntaxNode) -> SyntaxToken {
 +    let comma = match syntax
 +        .siblings_with_tokens(Direction::Next)
 +        .filter_map(|it| it.into_token())
 +        .find(|it| it.kind() == T![,])
 +    {
 +        Some(it) => it,
 +        None => {
 +            let comma = ast::make::token(T![,]);
 +            ted::insert(Position::after(syntax), &comma);
 +            comma
 +        }
 +    };
 +    comma
 +}
 +
 +impl ast::StmtList {
 +    pub fn push_front(&self, statement: ast::Stmt) {
 +        ted::insert(Position::after(self.l_curly_token().unwrap()), statement.syntax());
 +    }
 +}
 +
 +impl ast::VariantList {
 +    pub fn add_variant(&self, variant: ast::Variant) {
 +        let (indent, position) = match self.variants().last() {
 +            Some(last_item) => (
 +                IndentLevel::from_node(last_item.syntax()),
 +                Position::after(get_or_insert_comma_after(last_item.syntax())),
 +            ),
 +            None => match self.l_curly_token() {
 +                Some(l_curly) => {
 +                    normalize_ws_between_braces(self.syntax());
 +                    (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly))
 +                }
 +                None => (IndentLevel::single(), Position::last_child_of(self.syntax())),
 +            },
 +        };
 +        let elements: Vec<SyntaxElement<_>> = vec![
 +            make::tokens::whitespace(&format!("{}{}", "\n", indent)).into(),
 +            variant.syntax().clone().into(),
 +            ast::make::token(T![,]).into(),
 +        ];
 +        ted::insert_all(position, elements);
 +    }
 +}
 +
 +fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> {
 +    let l = node
 +        .children_with_tokens()
 +        .filter_map(|it| it.into_token())
 +        .find(|it| it.kind() == T!['{'])?;
 +    let r = node
 +        .children_with_tokens()
 +        .filter_map(|it| it.into_token())
 +        .find(|it| it.kind() == T!['}'])?;
 +
 +    let indent = IndentLevel::from_node(node);
 +
 +    match l.next_sibling_or_token() {
 +        Some(ws) if ws.kind() == SyntaxKind::WHITESPACE => {
 +            if ws.next_sibling_or_token()?.into_token()? == r {
 +                ted::replace(ws, make::tokens::whitespace(&format!("\n{}", indent)));
 +            }
 +        }
 +        Some(ws) if ws.kind() == T!['}'] => {
 +            ted::insert(Position::after(l), make::tokens::whitespace(&format!("\n{}", indent)));
 +        }
 +        _ => (),
 +    }
 +    Some(())
 +}
 +
 +pub trait Indent: AstNode + Clone + Sized {
 +    fn indent_level(&self) -> IndentLevel {
 +        IndentLevel::from_node(self.syntax())
 +    }
 +    fn indent(&self, by: IndentLevel) {
 +        by.increase_indent(self.syntax());
 +    }
 +    fn dedent(&self, by: IndentLevel) {
 +        by.decrease_indent(self.syntax());
 +    }
 +    fn reindent_to(&self, target_level: IndentLevel) {
 +        let current_level = IndentLevel::from_node(self.syntax());
 +        self.dedent(current_level);
 +        self.indent(target_level);
 +    }
 +}
 +
 +impl<N: AstNode + Clone> Indent for N {}
 +
 +#[cfg(test)]
 +mod tests {
 +    use std::fmt;
 +
 +    use stdx::trim_indent;
 +    use test_utils::assert_eq_text;
 +
 +    use crate::SourceFile;
 +
 +    use super::*;
 +
 +    fn ast_mut_from_text<N: AstNode>(text: &str) -> N {
 +        let parse = SourceFile::parse(text);
 +        parse.tree().syntax().descendants().find_map(N::cast).unwrap().clone_for_update()
 +    }
 +
 +    #[test]
 +    fn test_create_generic_param_list() {
 +        fn check_create_gpl<N: GenericParamsOwnerEdit + fmt::Display>(before: &str, after: &str) {
 +            let gpl_owner = ast_mut_from_text::<N>(before);
 +            gpl_owner.get_or_create_generic_param_list();
 +            assert_eq!(gpl_owner.to_string(), after);
 +        }
 +
 +        check_create_gpl::<ast::Fn>("fn foo", "fn foo<>");
 +        check_create_gpl::<ast::Fn>("fn foo() {}", "fn foo<>() {}");
 +
 +        check_create_gpl::<ast::Impl>("impl", "impl<>");
 +        check_create_gpl::<ast::Impl>("impl Struct {}", "impl<> Struct {}");
 +        check_create_gpl::<ast::Impl>("impl Trait for Struct {}", "impl<> Trait for Struct {}");
 +
 +        check_create_gpl::<ast::Trait>("trait Trait<>", "trait Trait<>");
 +        check_create_gpl::<ast::Trait>("trait Trait<> {}", "trait Trait<> {}");
 +
 +        check_create_gpl::<ast::Struct>("struct A", "struct A<>");
 +        check_create_gpl::<ast::Struct>("struct A;", "struct A<>;");
 +        check_create_gpl::<ast::Struct>("struct A();", "struct A<>();");
 +        check_create_gpl::<ast::Struct>("struct A {}", "struct A<> {}");
 +
 +        check_create_gpl::<ast::Enum>("enum E", "enum E<>");
 +        check_create_gpl::<ast::Enum>("enum E {", "enum E<> {");
 +    }
 +
 +    #[test]
 +    fn test_increase_indent() {
 +        let arm_list = ast_mut_from_text::<ast::Fn>(
 +            "fn foo() {
 +    ;
 +    ;
 +}",
 +        );
 +        arm_list.indent(IndentLevel(2));
 +        assert_eq!(
 +            arm_list.to_string(),
 +            "fn foo() {
 +            ;
 +            ;
 +        }",
 +        );
 +    }
 +
 +    #[test]
 +    fn add_variant_to_empty_enum() {
 +        let variant = make::variant(make::name("Bar"), None).clone_for_update();
 +
 +        check_add_variant(
 +            r#"
 +enum Foo {}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar,
 +}
 +"#,
 +            variant,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_variant_to_non_empty_enum() {
 +        let variant = make::variant(make::name("Baz"), None).clone_for_update();
 +
 +        check_add_variant(
 +            r#"
 +enum Foo {
 +    Bar,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar,
 +    Baz,
 +}
 +"#,
 +            variant,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_variant_with_tuple_field_list() {
 +        let variant = make::variant(
 +            make::name("Baz"),
 +            Some(ast::FieldList::TupleFieldList(make::tuple_field_list(std::iter::once(
 +                make::tuple_field(None, make::ty("bool")),
 +            )))),
 +        )
 +        .clone_for_update();
 +
 +        check_add_variant(
 +            r#"
 +enum Foo {
 +    Bar,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar,
 +    Baz(bool),
 +}
 +"#,
 +            variant,
 +        );
 +    }
 +
 +    #[test]
 +    fn add_variant_with_record_field_list() {
 +        let variant = make::variant(
 +            make::name("Baz"),
 +            Some(ast::FieldList::RecordFieldList(make::record_field_list(std::iter::once(
 +                make::record_field(None, make::name("x"), make::ty("bool")),
 +            )))),
 +        )
 +        .clone_for_update();
 +
 +        check_add_variant(
 +            r#"
 +enum Foo {
 +    Bar,
 +}
 +"#,
 +            r#"
 +enum Foo {
 +    Bar,
 +    Baz { x: bool },
 +}
 +"#,
 +            variant,
 +        );
 +    }
 +
 +    fn check_add_variant(before: &str, expected: &str, variant: ast::Variant) {
 +        let enum_ = ast_mut_from_text::<ast::Enum>(before);
 +        enum_.variant_list().map(|it| it.add_variant(variant));
 +        let after = enum_.to_string();
 +        assert_eq_text!(&trim_indent(expected.trim()), &trim_indent(&after.trim()));
 +    }
 +}
index 83f8bbac5880bfd5fa542f03e90af2110039d169,0000000000000000000000000000000000000000..4057a75e7c1e693d053e987ac39bb588ec02b9fa
mode 100644,000000..100644
--- /dev/null
@@@ -1,905 -1,0 +1,920 @@@
- pub(crate) fn generic_arg_list() -> ast::GenericArgList {
-     ast_from_text("const S: T<> = ();")
- }
 +//! This module contains free-standing functions for creating AST fragments out
 +//! of smaller pieces.
 +//!
 +//! Note that all functions here intended to be stupid constructors, which just
 +//! assemble a finish node from immediate children. If you want to do something
 +//! smarter than that, it belongs to the `ext` submodule.
 +//!
 +//! Keep in mind that `from_text` functions should be kept private. The public
 +//! API should require to assemble every node piecewise. The trick of
 +//! `parse(format!())` we use internally is an implementation detail -- long
 +//! term, it will be replaced with direct tree manipulation.
 +use itertools::Itertools;
 +use stdx::{format_to, never};
 +
 +use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxToken};
 +
 +/// While the parent module defines basic atomic "constructors", the `ext`
 +/// module defines shortcuts for common things.
 +///
 +/// It's named `ext` rather than `shortcuts` just to keep it short.
 +pub mod ext {
 +    use super::*;
 +
 +    pub fn simple_ident_pat(name: ast::Name) -> ast::IdentPat {
 +        return from_text(&name.text());
 +
 +        fn from_text(text: &str) -> ast::IdentPat {
 +            ast_from_text(&format!("fn f({text}: ())"))
 +        }
 +    }
 +    pub fn ident_path(ident: &str) -> ast::Path {
 +        path_unqualified(path_segment(name_ref(ident)))
 +    }
 +
 +    pub fn path_from_idents<'a>(
 +        parts: impl std::iter::IntoIterator<Item = &'a str>,
 +    ) -> Option<ast::Path> {
 +        let mut iter = parts.into_iter();
 +        let base = ext::ident_path(iter.next()?);
 +        let path = iter.fold(base, |base, s| {
 +            let path = ext::ident_path(s);
 +            path_concat(base, path)
 +        });
 +        Some(path)
 +    }
 +
 +    pub fn field_from_idents<'a>(
 +        parts: impl std::iter::IntoIterator<Item = &'a str>,
 +    ) -> Option<ast::Expr> {
 +        let mut iter = parts.into_iter();
 +        let base = expr_path(ext::ident_path(iter.next()?));
 +        let expr = iter.fold(base, expr_field);
 +        Some(expr)
 +    }
 +
 +    pub fn expr_unreachable() -> ast::Expr {
 +        expr_from_text("unreachable!()")
 +    }
 +    pub fn expr_todo() -> ast::Expr {
 +        expr_from_text("todo!()")
 +    }
 +    pub fn expr_ty_default(ty: &ast::Type) -> ast::Expr {
 +        expr_from_text(&format!("{ty}::default()"))
 +    }
 +    pub fn expr_ty_new(ty: &ast::Type) -> ast::Expr {
 +        expr_from_text(&format!("{ty}::new()"))
 +    }
 +
 +    pub fn zero_number() -> ast::Expr {
 +        expr_from_text("0")
 +    }
 +    pub fn zero_float() -> ast::Expr {
 +        expr_from_text("0.0")
 +    }
 +    pub fn empty_str() -> ast::Expr {
 +        expr_from_text(r#""""#)
 +    }
 +    pub fn empty_char() -> ast::Expr {
 +        expr_from_text("'\x00'")
 +    }
 +    pub fn default_bool() -> ast::Expr {
 +        expr_from_text("false")
 +    }
 +    pub fn option_none() -> ast::Expr {
 +        expr_from_text("None")
 +    }
 +    pub fn empty_block_expr() -> ast::BlockExpr {
 +        block_expr(None, None)
 +    }
 +
++    pub fn ty_name(name: ast::Name) -> ast::Type {
++        ty_path(ident_path(&name.to_string()))
++    }
 +    pub fn ty_bool() -> ast::Type {
 +        ty_path(ident_path("bool"))
 +    }
 +    pub fn ty_option(t: ast::Type) -> ast::Type {
 +        ty_from_text(&format!("Option<{t}>"))
 +    }
 +    pub fn ty_result(t: ast::Type, e: ast::Type) -> ast::Type {
 +        ty_from_text(&format!("Result<{t}, {e}>"))
 +    }
 +}
 +
 +pub fn name(name: &str) -> ast::Name {
 +    let raw_escape = raw_ident_esc(name);
 +    ast_from_text(&format!("mod {raw_escape}{name};"))
 +}
 +pub fn name_ref(name_ref: &str) -> ast::NameRef {
 +    let raw_escape = raw_ident_esc(name_ref);
 +    ast_from_text(&format!("fn f() {{ {raw_escape}{name_ref}; }}"))
 +}
 +fn raw_ident_esc(ident: &str) -> &'static str {
 +    let is_keyword = parser::SyntaxKind::from_keyword(ident).is_some();
 +    if is_keyword && !matches!(ident, "self" | "crate" | "super" | "Self") {
 +        "r#"
 +    } else {
 +        ""
 +    }
 +}
 +
 +pub fn lifetime(text: &str) -> ast::Lifetime {
 +    let mut text = text;
 +    let tmp;
 +    if never!(!text.starts_with('\'')) {
 +        tmp = format!("'{text}");
 +        text = &tmp;
 +    }
 +    ast_from_text(&format!("fn f<{text}>() {{ }}"))
 +}
 +
 +// FIXME: replace stringly-typed constructor with a family of typed ctors, a-la
 +// `expr_xxx`.
 +pub fn ty(text: &str) -> ast::Type {
 +    ty_from_text(text)
 +}
 +pub fn ty_placeholder() -> ast::Type {
 +    ty_from_text("_")
 +}
 +pub fn ty_unit() -> ast::Type {
 +    ty_from_text("()")
 +}
 +pub fn ty_tuple(types: impl IntoIterator<Item = ast::Type>) -> ast::Type {
 +    let mut count: usize = 0;
 +    let mut contents = types.into_iter().inspect(|_| count += 1).join(", ");
 +    if count == 1 {
 +        contents.push(',');
 +    }
 +
 +    ty_from_text(&format!("({contents})"))
 +}
 +pub fn ty_ref(target: ast::Type, exclusive: bool) -> ast::Type {
 +    ty_from_text(&if exclusive { format!("&mut {target}") } else { format!("&{target}") })
 +}
 +pub fn ty_path(path: ast::Path) -> ast::Type {
 +    ty_from_text(&path.to_string())
 +}
 +fn ty_from_text(text: &str) -> ast::Type {
 +    ast_from_text(&format!("type _T = {text};"))
 +}
 +
 +pub fn assoc_item_list() -> ast::AssocItemList {
 +    ast_from_text("impl C for D {}")
 +}
 +
++// FIXME: `ty_params` should be `ast::GenericArgList`
 +pub fn impl_(
 +    ty: ast::Path,
 +    params: Option<ast::GenericParamList>,
 +    ty_params: Option<ast::GenericParamList>,
 +) -> ast::Impl {
 +    let params = match params {
 +        Some(params) => params.to_string(),
 +        None => String::new(),
 +    };
 +    let ty_params = match ty_params {
 +        Some(params) => params.to_string(),
 +        None => String::new(),
 +    };
 +    ast_from_text(&format!("impl{params} {ty}{ty_params} {{}}"))
 +}
 +
 +pub fn impl_trait(
 +    trait_: ast::Path,
 +    ty: ast::Path,
 +    ty_params: Option<ast::GenericParamList>,
 +) -> ast::Impl {
 +    let ty_params = ty_params.map_or_else(String::new, |params| params.to_string());
 +    ast_from_text(&format!("impl{ty_params} {trait_} for {ty}{ty_params} {{}}"))
 +}
 +
 +pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
 +    ast_from_text(&format!("type __ = {name_ref};"))
 +}
 +
 +pub fn path_segment_ty(type_ref: ast::Type, trait_ref: Option<ast::PathType>) -> ast::PathSegment {
 +    let text = match trait_ref {
 +        Some(trait_ref) => format!("fn f(x: <{type_ref} as {trait_ref}>) {{}}"),
 +        None => format!("fn f(x: <{type_ref}>) {{}}"),
 +    };
 +    ast_from_text(&text)
 +}
 +
 +pub fn path_segment_self() -> ast::PathSegment {
 +    ast_from_text("use self;")
 +}
 +
 +pub fn path_segment_super() -> ast::PathSegment {
 +    ast_from_text("use super;")
 +}
 +
 +pub fn path_segment_crate() -> ast::PathSegment {
 +    ast_from_text("use crate;")
 +}
 +
 +pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path {
 +    ast_from_text(&format!("type __ = {segment};"))
 +}
 +
 +pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path {
 +    ast_from_text(&format!("{qual}::{segment}"))
 +}
 +// FIXME: path concatenation operation doesn't make sense as AST op.
 +pub fn path_concat(first: ast::Path, second: ast::Path) -> ast::Path {
 +    ast_from_text(&format!("type __ = {first}::{second};"))
 +}
 +
 +pub fn path_from_segments(
 +    segments: impl IntoIterator<Item = ast::PathSegment>,
 +    is_abs: bool,
 +) -> ast::Path {
 +    let segments = segments.into_iter().map(|it| it.syntax().clone()).join("::");
 +    ast_from_text(&if is_abs {
 +        format!("fn f(x: ::{segments}) {{}}")
 +    } else {
 +        format!("fn f(x: {segments}) {{}}")
 +    })
 +}
 +
 +pub fn join_paths(paths: impl IntoIterator<Item = ast::Path>) -> ast::Path {
 +    let paths = paths.into_iter().map(|it| it.syntax().clone()).join("::");
 +    ast_from_text(&format!("type __ = {paths};"))
 +}
 +
 +// FIXME: should not be pub
 +pub fn path_from_text(text: &str) -> ast::Path {
 +    ast_from_text(&format!("fn main() {{ let test = {text}; }}"))
 +}
 +
 +pub fn use_tree_glob() -> ast::UseTree {
 +    ast_from_text("use *;")
 +}
 +pub fn use_tree(
 +    path: ast::Path,
 +    use_tree_list: Option<ast::UseTreeList>,
 +    alias: Option<ast::Rename>,
 +    add_star: bool,
 +) -> ast::UseTree {
 +    let mut buf = "use ".to_string();
 +    buf += &path.syntax().to_string();
 +    if let Some(use_tree_list) = use_tree_list {
 +        format_to!(buf, "::{use_tree_list}");
 +    }
 +    if add_star {
 +        buf += "::*";
 +    }
 +
 +    if let Some(alias) = alias {
 +        format_to!(buf, " {alias}");
 +    }
 +    ast_from_text(&buf)
 +}
 +
 +pub fn use_tree_list(use_trees: impl IntoIterator<Item = ast::UseTree>) -> ast::UseTreeList {
 +    let use_trees = use_trees.into_iter().map(|it| it.syntax().clone()).join(", ");
 +    ast_from_text(&format!("use {{{use_trees}}};"))
 +}
 +
 +pub fn use_(visibility: Option<ast::Visibility>, use_tree: ast::UseTree) -> ast::Use {
 +    let visibility = match visibility {
 +        None => String::new(),
 +        Some(it) => format!("{it} "),
 +    };
 +    ast_from_text(&format!("{visibility}use {use_tree};"))
 +}
 +
 +pub fn record_expr(path: ast::Path, fields: ast::RecordExprFieldList) -> ast::RecordExpr {
 +    ast_from_text(&format!("fn f() {{ {path} {fields} }}"))
 +}
 +
 +pub fn record_expr_field_list(
 +    fields: impl IntoIterator<Item = ast::RecordExprField>,
 +) -> ast::RecordExprFieldList {
 +    let fields = fields.into_iter().join(", ");
 +    ast_from_text(&format!("fn f() {{ S {{ {fields} }} }}"))
 +}
 +
 +pub fn record_expr_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordExprField {
 +    return match expr {
 +        Some(expr) => from_text(&format!("{name}: {expr}")),
 +        None => from_text(&name.to_string()),
 +    };
 +
 +    fn from_text(text: &str) -> ast::RecordExprField {
 +        ast_from_text(&format!("fn f() {{ S {{ {text}, }} }}"))
 +    }
 +}
 +
 +pub fn record_field(
 +    visibility: Option<ast::Visibility>,
 +    name: ast::Name,
 +    ty: ast::Type,
 +) -> ast::RecordField {
 +    let visibility = match visibility {
 +        None => String::new(),
 +        Some(it) => format!("{it} "),
 +    };
 +    ast_from_text(&format!("struct S {{ {visibility}{name}: {ty}, }}"))
 +}
 +
 +// TODO
 +pub fn block_expr(
 +    stmts: impl IntoIterator<Item = ast::Stmt>,
 +    tail_expr: Option<ast::Expr>,
 +) -> ast::BlockExpr {
 +    let mut buf = "{\n".to_string();
 +    for stmt in stmts.into_iter() {
 +        format_to!(buf, "    {stmt}\n");
 +    }
 +    if let Some(tail_expr) = tail_expr {
 +        format_to!(buf, "    {tail_expr}\n");
 +    }
 +    buf += "}";
 +    ast_from_text(&format!("fn f() {buf}"))
 +}
 +
 +/// Ideally this function wouldn't exist since it involves manual indenting.
 +/// It differs from `make::block_expr` by also supporting comments.
 +///
 +/// FIXME: replace usages of this with the mutable syntax tree API
 +pub fn hacky_block_expr_with_comments(
 +    elements: impl IntoIterator<Item = crate::SyntaxElement>,
 +    tail_expr: Option<ast::Expr>,
 +) -> ast::BlockExpr {
 +    let mut buf = "{\n".to_string();
 +    for node_or_token in elements.into_iter() {
 +        match node_or_token {
 +            rowan::NodeOrToken::Node(n) => format_to!(buf, "    {n}\n"),
 +            rowan::NodeOrToken::Token(t) if t.kind() == SyntaxKind::COMMENT => {
 +                format_to!(buf, "    {t}\n")
 +            }
 +            _ => (),
 +        }
 +    }
 +    if let Some(tail_expr) = tail_expr {
 +        format_to!(buf, "    {tail_expr}\n");
 +    }
 +    buf += "}";
 +    ast_from_text(&format!("fn f() {buf}"))
 +}
 +
 +pub fn expr_unit() -> ast::Expr {
 +    expr_from_text("()")
 +}
 +pub fn expr_literal(text: &str) -> ast::Literal {
 +    assert_eq!(text.trim(), text);
 +    ast_from_text(&format!("fn f() {{ let _ = {text}; }}"))
 +}
 +
 +pub fn expr_empty_block() -> ast::Expr {
 +    expr_from_text("{}")
 +}
 +pub fn expr_path(path: ast::Path) -> ast::Expr {
 +    expr_from_text(&path.to_string())
 +}
 +pub fn expr_continue(label: Option<ast::Lifetime>) -> ast::Expr {
 +    match label {
 +        Some(label) => expr_from_text(&format!("continue {label}")),
 +        None => expr_from_text("continue"),
 +    }
 +}
 +// Consider `op: SyntaxKind` instead for nicer syntax at the call-site?
 +pub fn expr_bin_op(lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::Expr {
 +    expr_from_text(&format!("{lhs} {op} {rhs}"))
 +}
 +pub fn expr_break(label: Option<ast::Lifetime>, expr: Option<ast::Expr>) -> ast::Expr {
 +    let mut s = String::from("break");
 +
 +    if let Some(label) = label {
 +        format_to!(s, " {label}");
 +    }
 +
 +    if let Some(expr) = expr {
 +        format_to!(s, " {expr}");
 +    }
 +
 +    expr_from_text(&s)
 +}
 +pub fn expr_return(expr: Option<ast::Expr>) -> ast::Expr {
 +    match expr {
 +        Some(expr) => expr_from_text(&format!("return {expr}")),
 +        None => expr_from_text("return"),
 +    }
 +}
 +pub fn expr_try(expr: ast::Expr) -> ast::Expr {
 +    expr_from_text(&format!("{expr}?"))
 +}
 +pub fn expr_await(expr: ast::Expr) -> ast::Expr {
 +    expr_from_text(&format!("{expr}.await"))
 +}
 +pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
 +    expr_from_text(&format!("match {expr} {match_arm_list}"))
 +}
 +pub fn expr_if(
 +    condition: ast::Expr,
 +    then_branch: ast::BlockExpr,
 +    else_branch: Option<ast::ElseBranch>,
 +) -> ast::Expr {
 +    let else_branch = match else_branch {
 +        Some(ast::ElseBranch::Block(block)) => format!("else {block}"),
 +        Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {if_expr}"),
 +        None => String::new(),
 +    };
 +    expr_from_text(&format!("if {condition} {then_branch} {else_branch}"))
 +}
 +pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::Expr {
 +    expr_from_text(&format!("for {pat} in {expr} {block}"))
 +}
 +
 +pub fn expr_loop(block: ast::BlockExpr) -> ast::Expr {
 +    expr_from_text(&format!("loop {block}"))
 +}
 +
 +pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr {
 +    let token = token(op);
 +    expr_from_text(&format!("{token}{expr}"))
 +}
 +pub fn expr_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr {
 +    expr_from_text(&format!("{f}{arg_list}"))
 +}
 +pub fn expr_method_call(
 +    receiver: ast::Expr,
 +    method: ast::NameRef,
 +    arg_list: ast::ArgList,
 +) -> ast::Expr {
 +    expr_from_text(&format!("{receiver}.{method}{arg_list}"))
 +}
 +pub fn expr_macro_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr {
 +    expr_from_text(&format!("{f}!{arg_list}"))
 +}
 +pub fn expr_ref(expr: ast::Expr, exclusive: bool) -> ast::Expr {
 +    expr_from_text(&if exclusive { format!("&mut {expr}") } else { format!("&{expr}") })
 +}
 +pub fn expr_closure(pats: impl IntoIterator<Item = ast::Param>, expr: ast::Expr) -> ast::Expr {
 +    let params = pats.into_iter().join(", ");
 +    expr_from_text(&format!("|{params}| {expr}"))
 +}
 +pub fn expr_field(receiver: ast::Expr, field: &str) -> ast::Expr {
 +    expr_from_text(&format!("{receiver}.{field}"))
 +}
 +pub fn expr_paren(expr: ast::Expr) -> ast::Expr {
 +    expr_from_text(&format!("({expr})"))
 +}
 +pub fn expr_tuple(elements: impl IntoIterator<Item = ast::Expr>) -> ast::Expr {
 +    let expr = elements.into_iter().format(", ");
 +    expr_from_text(&format!("({expr})"))
 +}
 +pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
 +    expr_from_text(&format!("{lhs} = {rhs}"))
 +}
 +fn expr_from_text(text: &str) -> ast::Expr {
 +    ast_from_text(&format!("const C: () = {text};"))
 +}
 +pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
 +    ast_from_text(&format!("const _: () = while let {pattern} = {expr} {{}};"))
 +}
 +
 +pub fn arg_list(args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList {
 +    let args = args.into_iter().format(", ");
 +    ast_from_text(&format!("fn main() {{ ()({args}) }}"))
 +}
 +
 +pub fn ident_pat(ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat {
 +    let mut s = String::from("fn f(");
 +    if ref_ {
 +        s.push_str("ref ");
 +    }
 +    if mut_ {
 +        s.push_str("mut ");
 +    }
 +    format_to!(s, "{name}");
 +    s.push_str(": ())");
 +    ast_from_text(&s)
 +}
 +
 +pub fn wildcard_pat() -> ast::WildcardPat {
 +    return from_text("_");
 +
 +    fn from_text(text: &str) -> ast::WildcardPat {
 +        ast_from_text(&format!("fn f({text}: ())"))
 +    }
 +}
 +
 +pub fn literal_pat(lit: &str) -> ast::LiteralPat {
 +    return from_text(lit);
 +
 +    fn from_text(text: &str) -> ast::LiteralPat {
 +        ast_from_text(&format!("fn f() {{ match x {{ {text} => {{}} }} }}"))
 +    }
 +}
 +
 +/// Creates a tuple of patterns from an iterator of patterns.
 +///
 +/// Invariant: `pats` must be length > 0
 +pub fn tuple_pat(pats: impl IntoIterator<Item = ast::Pat>) -> ast::TuplePat {
 +    let mut count: usize = 0;
 +    let mut pats_str = pats.into_iter().inspect(|_| count += 1).join(", ");
 +    if count == 1 {
 +        pats_str.push(',');
 +    }
 +    return from_text(&format!("({pats_str})"));
 +
 +    fn from_text(text: &str) -> ast::TuplePat {
 +        ast_from_text(&format!("fn f({text}: ())"))
 +    }
 +}
 +
 +pub fn tuple_struct_pat(
 +    path: ast::Path,
 +    pats: impl IntoIterator<Item = ast::Pat>,
 +) -> ast::TupleStructPat {
 +    let pats_str = pats.into_iter().join(", ");
 +    return from_text(&format!("{path}({pats_str})"));
 +
 +    fn from_text(text: &str) -> ast::TupleStructPat {
 +        ast_from_text(&format!("fn f({text}: ())"))
 +    }
 +}
 +
 +pub fn record_pat(path: ast::Path, pats: impl IntoIterator<Item = ast::Pat>) -> ast::RecordPat {
 +    let pats_str = pats.into_iter().join(", ");
 +    return from_text(&format!("{path} {{ {pats_str} }}"));
 +
 +    fn from_text(text: &str) -> ast::RecordPat {
 +        ast_from_text(&format!("fn f({text}: ())"))
 +    }
 +}
 +
 +pub fn record_pat_with_fields(path: ast::Path, fields: ast::RecordPatFieldList) -> ast::RecordPat {
 +    ast_from_text(&format!("fn f({path} {fields}: ()))"))
 +}
 +
 +pub fn record_pat_field_list(
 +    fields: impl IntoIterator<Item = ast::RecordPatField>,
 +) -> ast::RecordPatFieldList {
 +    let fields = fields.into_iter().join(", ");
 +    ast_from_text(&format!("fn f(S {{ {fields} }}: ()))"))
 +}
 +
 +pub fn record_pat_field(name_ref: ast::NameRef, pat: ast::Pat) -> ast::RecordPatField {
 +    ast_from_text(&format!("fn f(S {{ {name_ref}: {pat} }}: ()))"))
 +}
 +
 +pub fn record_pat_field_shorthand(name_ref: ast::NameRef) -> ast::RecordPatField {
 +    ast_from_text(&format!("fn f(S {{ {name_ref} }}: ()))"))
 +}
 +
 +/// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise.
 +pub fn path_pat(path: ast::Path) -> ast::Pat {
 +    return from_text(&path.to_string());
 +    fn from_text(text: &str) -> ast::Pat {
 +        ast_from_text(&format!("fn f({text}: ())"))
 +    }
 +}
 +
 +pub fn match_arm(
 +    pats: impl IntoIterator<Item = ast::Pat>,
 +    guard: Option<ast::Expr>,
 +    expr: ast::Expr,
 +) -> ast::MatchArm {
 +    let pats_str = pats.into_iter().join(" | ");
 +    return match guard {
 +        Some(guard) => from_text(&format!("{pats_str} if {guard} => {expr}")),
 +        None => from_text(&format!("{pats_str} => {expr}")),
 +    };
 +
 +    fn from_text(text: &str) -> ast::MatchArm {
 +        ast_from_text(&format!("fn f() {{ match () {{{text}}} }}"))
 +    }
 +}
 +
 +pub fn match_arm_with_guard(
 +    pats: impl IntoIterator<Item = ast::Pat>,
 +    guard: ast::Expr,
 +    expr: ast::Expr,
 +) -> ast::MatchArm {
 +    let pats_str = pats.into_iter().join(" | ");
 +    return from_text(&format!("{pats_str} if {guard} => {expr}"));
 +
 +    fn from_text(text: &str) -> ast::MatchArm {
 +        ast_from_text(&format!("fn f() {{ match () {{{text}}} }}"))
 +    }
 +}
 +
 +pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList {
 +    let arms_str = arms
 +        .into_iter()
 +        .map(|arm| {
 +            let needs_comma = arm.expr().map_or(true, |it| !it.is_block_like());
 +            let comma = if needs_comma { "," } else { "" };
 +            let arm = arm.syntax();
 +            format!("    {arm}{comma}\n")
 +        })
 +        .collect::<String>();
 +    return from_text(&arms_str);
 +
 +    fn from_text(text: &str) -> ast::MatchArmList {
 +        ast_from_text(&format!("fn f() {{ match () {{\n{text}}} }}"))
 +    }
 +}
 +
 +pub fn where_pred(
 +    path: ast::Path,
 +    bounds: impl IntoIterator<Item = ast::TypeBound>,
 +) -> ast::WherePred {
 +    let bounds = bounds.into_iter().join(" + ");
 +    return from_text(&format!("{path}: {bounds}"));
 +
 +    fn from_text(text: &str) -> ast::WherePred {
 +        ast_from_text(&format!("fn f() where {text} {{ }}"))
 +    }
 +}
 +
 +pub fn where_clause(preds: impl IntoIterator<Item = ast::WherePred>) -> ast::WhereClause {
 +    let preds = preds.into_iter().join(", ");
 +    return from_text(preds.as_str());
 +
 +    fn from_text(text: &str) -> ast::WhereClause {
 +        ast_from_text(&format!("fn f() where {text} {{ }}"))
 +    }
 +}
 +
 +pub fn let_stmt(
 +    pattern: ast::Pat,
 +    ty: Option<ast::Type>,
 +    initializer: Option<ast::Expr>,
 +) -> ast::LetStmt {
 +    let mut text = String::new();
 +    format_to!(text, "let {pattern}");
 +    if let Some(ty) = ty {
 +        format_to!(text, ": {ty}");
 +    }
 +    match initializer {
 +        Some(it) => format_to!(text, " = {it};"),
 +        None => format_to!(text, ";"),
 +    };
 +    ast_from_text(&format!("fn f() {{ {text} }}"))
 +}
 +pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt {
 +    let semi = if expr.is_block_like() { "" } else { ";" };
 +    ast_from_text(&format!("fn f() {{ {expr}{semi} (); }}"))
 +}
 +
 +pub fn item_const(
 +    visibility: Option<ast::Visibility>,
 +    name: ast::Name,
 +    ty: ast::Type,
 +    expr: ast::Expr,
 +) -> ast::Const {
 +    let visibility = match visibility {
 +        None => String::new(),
 +        Some(it) => format!("{it} "),
 +    };
 +    ast_from_text(&format!("{visibility} const {name}: {ty} = {expr};"))
 +}
 +
 +pub fn param(pat: ast::Pat, ty: ast::Type) -> ast::Param {
 +    ast_from_text(&format!("fn f({pat}: {ty}) {{ }}"))
 +}
 +
 +pub fn self_param() -> ast::SelfParam {
 +    ast_from_text("fn f(&self) { }")
 +}
 +
 +pub fn ret_type(ty: ast::Type) -> ast::RetType {
 +    ast_from_text(&format!("fn f() -> {ty} {{ }}"))
 +}
 +
 +pub fn param_list(
 +    self_param: Option<ast::SelfParam>,
 +    pats: impl IntoIterator<Item = ast::Param>,
 +) -> ast::ParamList {
 +    let args = pats.into_iter().join(", ");
 +    let list = match self_param {
 +        Some(self_param) if args.is_empty() => format!("fn f({self_param}) {{ }}"),
 +        Some(self_param) => format!("fn f({self_param}, {args}) {{ }}"),
 +        None => format!("fn f({args}) {{ }}"),
 +    };
 +    ast_from_text(&list)
 +}
 +
 +pub fn type_param(name: ast::Name, ty: Option<ast::TypeBoundList>) -> ast::TypeParam {
 +    let bound = match ty {
 +        Some(it) => format!(": {it}"),
 +        None => String::new(),
 +    };
 +    ast_from_text(&format!("fn f<{name}{bound}>() {{ }}"))
 +}
 +
 +pub fn lifetime_param(lifetime: ast::Lifetime) -> ast::LifetimeParam {
 +    ast_from_text(&format!("fn f<{lifetime}>() {{ }}"))
 +}
 +
 +pub fn generic_param_list(
 +    pats: impl IntoIterator<Item = ast::GenericParam>,
 +) -> ast::GenericParamList {
 +    let args = pats.into_iter().join(", ");
 +    ast_from_text(&format!("fn f<{args}>() {{ }}"))
 +}
 +
++pub fn type_arg(ty: ast::Type) -> ast::TypeArg {
++    ast_from_text(&format!("const S: T<{ty}> = ();"))
++}
++
++pub fn lifetime_arg(lifetime: ast::Lifetime) -> ast::LifetimeArg {
++    ast_from_text(&format!("const S: T<{lifetime}> = ();"))
++}
++
++pub(crate) fn generic_arg_list(
++    args: impl IntoIterator<Item = ast::GenericArg>,
++) -> ast::GenericArgList {
++    let args = args.into_iter().join(", ");
++    ast_from_text(&format!("const S: T<{args}> = ();"))
++}
++
 +pub fn visibility_pub_crate() -> ast::Visibility {
 +    ast_from_text("pub(crate) struct S")
 +}
 +
 +pub fn visibility_pub() -> ast::Visibility {
 +    ast_from_text("pub struct S")
 +}
 +
 +pub fn tuple_field_list(fields: impl IntoIterator<Item = ast::TupleField>) -> ast::TupleFieldList {
 +    let fields = fields.into_iter().join(", ");
 +    ast_from_text(&format!("struct f({fields});"))
 +}
 +
 +pub fn record_field_list(
 +    fields: impl IntoIterator<Item = ast::RecordField>,
 +) -> ast::RecordFieldList {
 +    let fields = fields.into_iter().join(", ");
 +    ast_from_text(&format!("struct f {{ {fields} }}"))
 +}
 +
 +pub fn tuple_field(visibility: Option<ast::Visibility>, ty: ast::Type) -> ast::TupleField {
 +    let visibility = match visibility {
 +        None => String::new(),
 +        Some(it) => format!("{it} "),
 +    };
 +    ast_from_text(&format!("struct f({visibility}{ty});"))
 +}
 +
 +pub fn variant(name: ast::Name, field_list: Option<ast::FieldList>) -> ast::Variant {
 +    let field_list = match field_list {
 +        None => String::new(),
 +        Some(it) => match it {
 +            ast::FieldList::RecordFieldList(record) => format!(" {record}"),
 +            ast::FieldList::TupleFieldList(tuple) => format!("{tuple}"),
 +        },
 +    };
 +    ast_from_text(&format!("enum f {{ {name}{field_list} }}"))
 +}
 +
 +pub fn fn_(
 +    visibility: Option<ast::Visibility>,
 +    fn_name: ast::Name,
 +    type_params: Option<ast::GenericParamList>,
 +    params: ast::ParamList,
 +    body: ast::BlockExpr,
 +    ret_type: Option<ast::RetType>,
 +    is_async: bool,
 +) -> ast::Fn {
 +    let type_params = match type_params {
 +        Some(type_params) => format!("{type_params}"),
 +        None => "".into(),
 +    };
 +    let ret_type = match ret_type {
 +        Some(ret_type) => format!("{ret_type} "),
 +        None => "".into(),
 +    };
 +    let visibility = match visibility {
 +        None => String::new(),
 +        Some(it) => format!("{it} "),
 +    };
 +
 +    let async_literal = if is_async { "async " } else { "" };
 +
 +    ast_from_text(&format!(
 +        "{visibility}{async_literal}fn {fn_name}{type_params}{params} {ret_type}{body}",
 +    ))
 +}
 +
 +pub fn struct_(
 +    visibility: Option<ast::Visibility>,
 +    strukt_name: ast::Name,
 +    generic_param_list: Option<ast::GenericParamList>,
 +    field_list: ast::FieldList,
 +) -> ast::Struct {
 +    let semicolon = if matches!(field_list, ast::FieldList::TupleFieldList(_)) { ";" } else { "" };
 +    let type_params = generic_param_list.map_or_else(String::new, |it| it.to_string());
 +    let visibility = match visibility {
 +        None => String::new(),
 +        Some(it) => format!("{it} "),
 +    };
 +
 +    ast_from_text(&format!("{visibility}struct {strukt_name}{type_params}{field_list}{semicolon}",))
 +}
 +
 +#[track_caller]
 +fn ast_from_text<N: AstNode>(text: &str) -> N {
 +    let parse = SourceFile::parse(text);
 +    let node = match parse.tree().syntax().descendants().find_map(N::cast) {
 +        Some(it) => it,
 +        None => {
 +            let node = std::any::type_name::<N>();
 +            panic!("Failed to make ast node `{node}` from text {text}")
 +        }
 +    };
 +    let node = node.clone_subtree();
 +    assert_eq!(node.syntax().text_range().start(), 0.into());
 +    node
 +}
 +
 +pub fn token(kind: SyntaxKind) -> SyntaxToken {
 +    tokens::SOURCE_FILE
 +        .tree()
 +        .syntax()
 +        .clone_for_update()
 +        .descendants_with_tokens()
 +        .filter_map(|it| it.into_token())
 +        .find(|it| it.kind() == kind)
 +        .unwrap_or_else(|| panic!("unhandled token: {kind:?}"))
 +}
 +
 +pub mod tokens {
 +    use once_cell::sync::Lazy;
 +
 +    use crate::{ast, AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken};
 +
 +    pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| {
 +        SourceFile::parse(
 +            "const C: <()>::Item = (1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p)\n;\n\n",
 +        )
 +    });
 +
 +    pub fn single_space() -> SyntaxToken {
 +        SOURCE_FILE
 +            .tree()
 +            .syntax()
 +            .clone_for_update()
 +            .descendants_with_tokens()
 +            .filter_map(|it| it.into_token())
 +            .find(|it| it.kind() == WHITESPACE && it.text() == " ")
 +            .unwrap()
 +    }
 +
 +    pub fn whitespace(text: &str) -> SyntaxToken {
 +        assert!(text.trim().is_empty());
 +        let sf = SourceFile::parse(text).ok().unwrap();
 +        sf.syntax().clone_for_update().first_child_or_token().unwrap().into_token().unwrap()
 +    }
 +
 +    pub fn doc_comment(text: &str) -> SyntaxToken {
 +        assert!(!text.trim().is_empty());
 +        let sf = SourceFile::parse(text).ok().unwrap();
 +        sf.syntax().first_child_or_token().unwrap().into_token().unwrap()
 +    }
 +
 +    pub fn literal(text: &str) -> SyntaxToken {
 +        assert_eq!(text.trim(), text);
 +        let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {text}; }}"));
 +        lit.syntax().first_child_or_token().unwrap().into_token().unwrap()
 +    }
 +
 +    pub fn single_newline() -> SyntaxToken {
 +        let res = SOURCE_FILE
 +            .tree()
 +            .syntax()
 +            .clone_for_update()
 +            .descendants_with_tokens()
 +            .filter_map(|it| it.into_token())
 +            .find(|it| it.kind() == WHITESPACE && it.text() == "\n")
 +            .unwrap();
 +        res.detach();
 +        res
 +    }
 +
 +    pub fn blank_line() -> SyntaxToken {
 +        SOURCE_FILE
 +            .tree()
 +            .syntax()
 +            .clone_for_update()
 +            .descendants_with_tokens()
 +            .filter_map(|it| it.into_token())
 +            .find(|it| it.kind() == WHITESPACE && it.text() == "\n\n")
 +            .unwrap()
 +    }
 +
 +    pub struct WsBuilder(SourceFile);
 +
 +    impl WsBuilder {
 +        pub fn new(text: &str) -> WsBuilder {
 +            WsBuilder(SourceFile::parse(text).ok().unwrap())
 +        }
 +        pub fn ws(&self) -> SyntaxToken {
 +            self.0.syntax().first_child_or_token().unwrap().into_token().unwrap()
 +        }
 +    }
 +}
index 8c806e7925b15b0eebe1275ade8a76220ede2960,0000000000000000000000000000000000000000..c824f5af7258485bb8aa97460ab23fc0f216a647
mode 100644,000000..100644
--- /dev/null
@@@ -1,409 -1,0 +1,410 @@@
-             res.activated_flags.push(entry.to_string());
 +//! Defines `Fixture` -- a convenient way to describe the initial state of
 +//! rust-analyzer database from a single string.
 +//!
 +//! Fixtures are strings containing rust source code with optional metadata.
 +//! A fixture without metadata is parsed into a single source file.
 +//! Use this to test functionality local to one file.
 +//!
 +//! Simple Example:
 +//! ```
 +//! r#"
 +//! fn main() {
 +//!     println!("Hello World")
 +//! }
 +//! "#
 +//! ```
 +//!
 +//! Metadata can be added to a fixture after a `//-` comment.
 +//! The basic form is specifying filenames,
 +//! which is also how to define multiple files in a single test fixture
 +//!
 +//! Example using two files in the same crate:
 +//! ```
 +//! "
 +//! //- /main.rs
 +//! mod foo;
 +//! fn main() {
 +//!     foo::bar();
 +//! }
 +//!
 +//! //- /foo.rs
 +//! pub fn bar() {}
 +//! "
 +//! ```
 +//!
 +//! Example using two crates with one file each, with one crate depending on the other:
 +//! ```
 +//! r#"
 +//! //- /main.rs crate:a deps:b
 +//! fn main() {
 +//!     b::foo();
 +//! }
 +//! //- /lib.rs crate:b
 +//! pub fn b() {
 +//!     println!("Hello World")
 +//! }
 +//! "#
 +//! ```
 +//!
 +//! Metadata allows specifying all settings and variables
 +//! that are available in a real rust project:
 +//! - crate names via `crate:cratename`
 +//! - dependencies via `deps:dep1,dep2`
 +//! - configuration settings via `cfg:dbg=false,opt_level=2`
 +//! - environment variables via `env:PATH=/bin,RUST_LOG=debug`
 +//!
 +//! Example using all available metadata:
 +//! ```
 +//! "
 +//! //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
 +//! fn insert_source_code_here() {}
 +//! "
 +//! ```
 +
++use std::iter;
++
 +use rustc_hash::FxHashMap;
 +use stdx::trim_indent;
 +
 +#[derive(Debug, Eq, PartialEq)]
 +pub struct Fixture {
 +    pub path: String,
 +    pub text: String,
 +    pub krate: Option<String>,
 +    pub deps: Vec<String>,
 +    pub extern_prelude: Option<Vec<String>>,
 +    pub cfg_atoms: Vec<String>,
 +    pub cfg_key_values: Vec<(String, String)>,
 +    pub edition: Option<String>,
 +    pub env: FxHashMap<String, String>,
 +    pub introduce_new_source_root: Option<String>,
 +}
 +
 +pub struct MiniCore {
 +    activated_flags: Vec<String>,
 +    valid_flags: Vec<String>,
 +}
 +
 +impl Fixture {
 +    /// Parses text which looks like this:
 +    ///
 +    ///  ```not_rust
 +    ///  //- some meta
 +    ///  line 1
 +    ///  line 2
 +    ///  //- other meta
 +    ///  ```
 +    ///
 +    /// Fixture can also start with a proc_macros and minicore declaration(in that order):
 +    ///
 +    /// ```
 +    /// //- proc_macros: identity
 +    /// //- minicore: sized
 +    /// ```
 +    ///
 +    /// That will include predefined proc macros and a subset of `libcore` into the fixture, see
 +    /// `minicore.rs` for what's available.
 +    pub fn parse(ra_fixture: &str) -> (Option<MiniCore>, Vec<String>, Vec<Fixture>) {
 +        let fixture = trim_indent(ra_fixture);
 +        let mut fixture = fixture.as_str();
 +        let mut mini_core = None;
 +        let mut res: Vec<Fixture> = Vec::new();
 +        let mut test_proc_macros = vec![];
 +
 +        if fixture.starts_with("//- proc_macros:") {
 +            let first_line = fixture.split_inclusive('\n').next().unwrap();
 +            test_proc_macros = first_line
 +                .strip_prefix("//- proc_macros:")
 +                .unwrap()
 +                .split(',')
 +                .map(|it| it.trim().to_string())
 +                .collect();
 +            fixture = &fixture[first_line.len()..];
 +        }
 +
 +        if fixture.starts_with("//- minicore:") {
 +            let first_line = fixture.split_inclusive('\n').next().unwrap();
 +            mini_core = Some(MiniCore::parse(first_line));
 +            fixture = &fixture[first_line.len()..];
 +        }
 +
 +        let default = if fixture.contains("//-") { None } else { Some("//- /main.rs") };
 +
 +        for (ix, line) in default.into_iter().chain(fixture.split_inclusive('\n')).enumerate() {
 +            if line.contains("//-") {
 +                assert!(
 +                    line.starts_with("//-"),
 +                    "Metadata line {} has invalid indentation. \
 +                     All metadata lines need to have the same indentation.\n\
 +                     The offending line: {:?}",
 +                    ix,
 +                    line
 +                );
 +            }
 +
 +            if line.starts_with("//-") {
 +                let meta = Fixture::parse_meta_line(line);
 +                res.push(meta);
 +            } else {
 +                if line.starts_with("// ")
 +                    && line.contains(':')
 +                    && !line.contains("::")
 +                    && !line.contains('.')
 +                    && line.chars().all(|it| !it.is_uppercase())
 +                {
 +                    panic!("looks like invalid metadata line: {:?}", line);
 +                }
 +
 +                if let Some(entry) = res.last_mut() {
 +                    entry.text.push_str(line);
 +                }
 +            }
 +        }
 +
 +        (mini_core, test_proc_macros, res)
 +    }
 +
 +    //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
 +    fn parse_meta_line(meta: &str) -> Fixture {
 +        assert!(meta.starts_with("//-"));
 +        let meta = meta["//-".len()..].trim();
 +        let components = meta.split_ascii_whitespace().collect::<Vec<_>>();
 +
 +        let path = components[0].to_string();
 +        assert!(path.starts_with('/'), "fixture path does not start with `/`: {:?}", path);
 +
 +        let mut krate = None;
 +        let mut deps = Vec::new();
 +        let mut extern_prelude = None;
 +        let mut edition = None;
 +        let mut cfg_atoms = Vec::new();
 +        let mut cfg_key_values = Vec::new();
 +        let mut env = FxHashMap::default();
 +        let mut introduce_new_source_root = None;
 +        for component in components[1..].iter() {
 +            let (key, value) = component
 +                .split_once(':')
 +                .unwrap_or_else(|| panic!("invalid meta line: {:?}", meta));
 +            match key {
 +                "crate" => krate = Some(value.to_string()),
 +                "deps" => deps = value.split(',').map(|it| it.to_string()).collect(),
 +                "extern-prelude" => {
 +                    if value.is_empty() {
 +                        extern_prelude = Some(Vec::new());
 +                    } else {
 +                        extern_prelude =
 +                            Some(value.split(',').map(|it| it.to_string()).collect::<Vec<_>>());
 +                    }
 +                }
 +                "edition" => edition = Some(value.to_string()),
 +                "cfg" => {
 +                    for entry in value.split(',') {
 +                        match entry.split_once('=') {
 +                            Some((k, v)) => cfg_key_values.push((k.to_string(), v.to_string())),
 +                            None => cfg_atoms.push(entry.to_string()),
 +                        }
 +                    }
 +                }
 +                "env" => {
 +                    for key in value.split(',') {
 +                        if let Some((k, v)) = key.split_once('=') {
 +                            env.insert(k.into(), v.into());
 +                        }
 +                    }
 +                }
 +                "new_source_root" => introduce_new_source_root = Some(value.to_string()),
 +                _ => panic!("bad component: {:?}", component),
 +            }
 +        }
 +
 +        for prelude_dep in extern_prelude.iter().flatten() {
 +            assert!(
 +                deps.contains(prelude_dep),
 +                "extern-prelude {:?} must be a subset of deps {:?}",
 +                extern_prelude,
 +                deps
 +            );
 +        }
 +
 +        Fixture {
 +            path,
 +            text: String::new(),
 +            krate,
 +            deps,
 +            extern_prelude,
 +            cfg_atoms,
 +            cfg_key_values,
 +            edition,
 +            env,
 +            introduce_new_source_root,
 +        }
 +    }
 +}
 +
 +impl MiniCore {
 +    fn has_flag(&self, flag: &str) -> bool {
 +        self.activated_flags.iter().any(|it| it == flag)
 +    }
 +
 +    #[track_caller]
 +    fn assert_valid_flag(&self, flag: &str) {
 +        if !self.valid_flags.iter().any(|it| it == flag) {
 +            panic!("invalid flag: {:?}, valid flags: {:?}", flag, self.valid_flags);
 +        }
 +    }
 +
 +    fn parse(line: &str) -> MiniCore {
 +        let mut res = MiniCore { activated_flags: Vec::new(), valid_flags: Vec::new() };
 +
 +        let line = line.strip_prefix("//- minicore:").unwrap().trim();
 +        for entry in line.split(", ") {
 +            if res.has_flag(entry) {
 +                panic!("duplicate minicore flag: {:?}", entry);
 +            }
-         let mut parsing_flags = false;
++            res.activated_flags.push(entry.to_owned());
 +        }
 +
 +        res
 +    }
 +
 +    /// Strips parts of minicore.rs which are flagged by inactive flags.
 +    ///
 +    /// This is probably over-engineered to support flags dependencies.
 +    pub fn source_code(mut self) -> String {
 +        let mut buf = String::new();
 +        let raw_mini_core = include_str!("./minicore.rs");
 +        let mut lines = raw_mini_core.split_inclusive('\n');
 +
-         for line in lines.by_ref() {
-             let line = match line.strip_prefix("//!") {
-                 Some(it) => it,
-                 None => {
-                     assert!(line.trim().is_empty());
-                     break;
-                 }
-             };
-             if parsing_flags {
-                 let (flag, deps) = line.split_once(':').unwrap();
-                 let flag = flag.trim();
-                 self.valid_flags.push(flag.to_string());
-                 for dep in deps.split(", ") {
-                     let dep = dep.trim();
-                     if !dep.is_empty() {
-                         self.assert_valid_flag(dep);
-                         implications.push((flag, dep));
-                     }
-                 }
 +        let mut implications = Vec::new();
 +
 +        // Parse `//!` preamble and extract flags and dependencies.
-             if line.contains("Available flags:") {
-                 parsing_flags = true;
-             }
++        let trim_doc: fn(&str) -> Option<&str> = |line| match line.strip_prefix("//!") {
++            Some(it) => Some(it),
++            None => {
++                assert!(line.trim().is_empty(), "expected empty line after minicore header");
++                None
 +            }
++        };
++        for line in lines
++            .by_ref()
++            .map_while(trim_doc)
++            .skip_while(|line| !line.contains("Available flags:"))
++            .skip(1)
++        {
++            let (flag, deps) = line.split_once(':').unwrap();
++            let flag = flag.trim();
++
++            self.valid_flags.push(flag.to_string());
++            implications.extend(
++                iter::repeat(flag)
++                    .zip(deps.split(", ").map(str::trim).filter(|dep| !dep.is_empty())),
++            );
++        }
 +
-                 assert_eq!(prev, region);
++        for (_, dep) in &implications {
++            self.assert_valid_flag(dep);
 +        }
 +
 +        for flag in &self.activated_flags {
 +            self.assert_valid_flag(flag);
 +        }
 +
 +        // Fixed point loop to compute transitive closure of flags.
 +        loop {
 +            let mut changed = false;
 +            for &(u, v) in &implications {
 +                if self.has_flag(u) && !self.has_flag(v) {
 +                    self.activated_flags.push(v.to_string());
 +                    changed = true;
 +                }
 +            }
 +            if !changed {
 +                break;
 +            }
 +        }
 +
 +        let mut active_regions = Vec::new();
 +        let mut seen_regions = Vec::new();
 +        for line in lines {
 +            let trimmed = line.trim();
 +            if let Some(region) = trimmed.strip_prefix("// region:") {
 +                active_regions.push(region);
 +                continue;
 +            }
 +            if let Some(region) = trimmed.strip_prefix("// endregion:") {
 +                let prev = active_regions.pop().unwrap();
++                assert_eq!(prev, region, "unbalanced region pairs");
 +                continue;
 +            }
 +
 +            let mut line_region = false;
 +            if let Some(idx) = trimmed.find("// :") {
 +                line_region = true;
 +                active_regions.push(&trimmed[idx + "// :".len()..]);
 +            }
 +
 +            let mut keep = true;
 +            for &region in &active_regions {
 +                assert!(
 +                    !region.starts_with(' '),
 +                    "region marker starts with a space: {:?}",
 +                    region
 +                );
 +                self.assert_valid_flag(region);
 +                seen_regions.push(region);
 +                keep &= self.has_flag(region);
 +            }
 +
 +            if keep {
 +                buf.push_str(line);
 +            }
 +            if line_region {
 +                active_regions.pop().unwrap();
 +            }
 +        }
 +
 +        for flag in &self.valid_flags {
 +            if !seen_regions.iter().any(|it| it == flag) {
 +                panic!("unused minicore flag: {:?}", flag);
 +            }
 +        }
 +        buf
 +    }
 +}
 +
 +#[test]
 +#[should_panic]
 +fn parse_fixture_checks_further_indented_metadata() {
 +    Fixture::parse(
 +        r"
 +        //- /lib.rs
 +          mod bar;
 +
 +          fn foo() {}
 +          //- /bar.rs
 +          pub fn baz() {}
 +          ",
 +    );
 +}
 +
 +#[test]
 +fn parse_fixture_gets_full_meta() {
 +    let (mini_core, proc_macros, parsed) = Fixture::parse(
 +        r#"
 +//- proc_macros: identity
 +//- minicore: coerce_unsized
 +//- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b,atom env:OUTDIR=path/to,OTHER=foo
 +mod m;
 +"#,
 +    );
 +    assert_eq!(proc_macros, vec!["identity".to_string()]);
 +    assert_eq!(mini_core.unwrap().activated_flags, vec!["coerce_unsized".to_string()]);
 +    assert_eq!(1, parsed.len());
 +
 +    let meta = &parsed[0];
 +    assert_eq!("mod m;\n", meta.text);
 +
 +    assert_eq!("foo", meta.krate.as_ref().unwrap());
 +    assert_eq!("/lib.rs", meta.path);
 +    assert_eq!(2, meta.env.len());
 +}
index 10386b5b7bcdd41e033144c705702b71d3dd27a5,0000000000000000000000000000000000000000..59b1c147d7f174e08339de3225c5e3541b2af1c9
mode 100644,000000..100644
--- /dev/null
@@@ -1,732 -1,0 +1,763 @@@
- //!     sized:
- //!     unsize: sized
 +//! 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:
- //!     slice:
- //!     range:
- //!     deref: sized
++//!     add:
++//!     as_ref: sized
++//!     bool_impl: option, fn
++//!     clone: sized
 +//!     coerce_unsized: unsize
- //!     index: sized
++//!     copy: clone
++//!     default: sized
 +//!     deref_mut: deref
- //!     try:
- //!     pin:
++//!     deref: sized
++//!     derive:
++//!     drop:
++//!     eq: sized
++//!     fmt: result
 +//!     fn:
- //!     option:
- //!     result:
++//!     from: sized
 +//!     future: pin
- //!     default: sized
- //!     hash:
- //!     clone: sized
- //!     copy: clone
- //!     from: sized
- //!     eq: sized
++//!     generator: pin
++//!     hash:
++//!     index: sized
++//!     infallible:
 +//!     iterator: option
 +//!     iterators: iterator, fn
- //!     derive:
- //!     fmt: result
- //!     bool_impl: option, fn
- //!     add:
- //!     as_ref: sized
- //!     drop:
- //!     generator: pin
++//!     option:
 +//!     ord: eq, option
-         pub trait FromResidual<R = Self::Residual> {
++//!     pin:
++//!     range:
++//!     result:
++//!     sized:
++//!     slice:
++//!     try: infallible
++//!     unsize: sized
 +
 +pub mod marker {
 +    // region:sized
 +    #[lang = "sized"]
 +    #[fundamental]
 +    #[rustc_specialization_trait]
 +    pub trait Sized {}
 +    // endregion:sized
 +
 +    // region:unsize
 +    #[lang = "unsize"]
 +    pub trait Unsize<T: ?Sized> {}
 +    // endregion:unsize
 +
 +    // region:copy
 +    #[lang = "copy"]
 +    pub trait Copy: Clone {}
 +    // region:derive
 +    #[rustc_builtin_macro]
 +    pub macro Copy($item:item) {}
 +    // endregion:derive
 +
 +    mod copy_impls {
 +        use super::Copy;
 +
 +        macro_rules! impl_copy {
 +            ($($t:ty)*) => {
 +                $(
 +                    impl Copy for $t {}
 +                )*
 +            }
 +        }
 +
 +        impl_copy! {
 +            usize u8 u16 u32 u64 u128
 +            isize i8 i16 i32 i64 i128
 +            f32 f64
 +            bool char
 +        }
 +
 +        impl<T: ?Sized> Copy for *const T {}
 +        impl<T: ?Sized> Copy for *mut T {}
 +        impl<T: ?Sized> Copy for &T {}
 +    }
 +    // endregion:copy
 +}
 +
 +// region:default
 +pub mod default {
 +    pub trait Default: Sized {
 +        fn default() -> Self;
 +    }
 +    // region:derive
 +    #[rustc_builtin_macro]
 +    pub macro Default($item:item) {}
 +    // endregion:derive
 +}
 +// endregion:default
 +
 +// region:hash
 +pub mod hash {
 +    pub trait Hasher {}
 +
 +    pub trait Hash {
 +        fn hash<H: Hasher>(&self, state: &mut H);
 +    }
 +}
 +// endregion:hash
 +
 +// region:clone
 +pub mod clone {
 +    #[lang = "clone"]
 +    pub trait Clone: Sized {
 +        fn clone(&self) -> Self;
 +    }
 +    // region:derive
 +    #[rustc_builtin_macro]
 +    pub macro Clone($item:item) {}
 +    // endregion:derive
 +}
 +// endregion:clone
 +
 +pub mod convert {
 +    // region:from
 +    pub trait From<T>: Sized {
 +        fn from(_: T) -> Self;
 +    }
 +    pub trait Into<T>: Sized {
 +        fn into(self) -> T;
 +    }
 +
 +    impl<T, U> Into<U> for T
 +    where
 +        U: From<T>,
 +    {
 +        fn into(self) -> U {
 +            U::from(self)
 +        }
 +    }
 +
 +    impl<T> From<T> for T {
 +        fn from(t: T) -> T {
 +            t
 +        }
 +    }
 +    // endregion:from
 +
 +    // region:as_ref
 +    pub trait AsRef<T: ?Sized> {
 +        fn as_ref(&self) -> &T;
 +    }
 +    // endregion:as_ref
++    // region:infallible
++    pub enum Infallible {}
++    // endregion:infallible
 +}
 +
 +pub mod ops {
 +    // region:coerce_unsized
 +    mod unsize {
 +        use crate::marker::Unsize;
 +
 +        #[lang = "coerce_unsized"]
 +        pub trait CoerceUnsized<T: ?Sized> {}
 +
 +        impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
 +        impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {}
 +        impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {}
 +        impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {}
 +
 +        impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
 +        impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {}
 +
 +        impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
 +        impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
 +        impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
 +    }
 +    pub use self::unsize::CoerceUnsized;
 +    // endregion:coerce_unsized
 +
 +    // region:deref
 +    mod deref {
 +        #[lang = "deref"]
 +        pub trait Deref {
 +            #[lang = "deref_target"]
 +            type Target: ?Sized;
 +            fn deref(&self) -> &Self::Target;
 +        }
 +
 +        impl<T: ?Sized> Deref for &T {
 +            type Target = T;
 +            fn deref(&self) -> &T {
 +                loop {}
 +            }
 +        }
 +        impl<T: ?Sized> Deref for &mut T {
 +            type Target = T;
 +            fn deref(&self) -> &T {
 +                loop {}
 +            }
 +        }
 +        // region:deref_mut
 +        #[lang = "deref_mut"]
 +        pub trait DerefMut: Deref {
 +            fn deref_mut(&mut self) -> &mut Self::Target;
 +        }
 +        // endregion:deref_mut
 +    }
 +    pub use self::deref::{
 +        Deref,
 +        DerefMut, // :deref_mut
 +    };
 +    // endregion:deref
 +
 +    // region:drop
 +    #[lang = "drop"]
 +    pub trait Drop {
 +        fn drop(&mut self);
 +    }
 +    // endregion:drop
 +
 +    // region:index
 +    mod index {
 +        #[lang = "index"]
 +        pub trait Index<Idx: ?Sized> {
 +            type Output: ?Sized;
 +            fn index(&self, index: Idx) -> &Self::Output;
 +        }
 +        #[lang = "index_mut"]
 +        pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
 +            fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
 +        }
 +
 +        // region:slice
 +        impl<T, I> Index<I> for [T]
 +        where
 +            I: SliceIndex<[T]>,
 +        {
 +            type Output = I::Output;
 +            fn index(&self, index: I) -> &I::Output {
 +                loop {}
 +            }
 +        }
 +        impl<T, I> IndexMut<I> for [T]
 +        where
 +            I: SliceIndex<[T]>,
 +        {
 +            fn index_mut(&mut self, index: I) -> &mut I::Output {
 +                loop {}
 +            }
 +        }
 +
 +        pub unsafe trait SliceIndex<T: ?Sized> {
 +            type Output: ?Sized;
 +        }
 +        unsafe impl<T> SliceIndex<[T]> for usize {
 +            type Output = T;
 +        }
 +        // endregion:slice
 +    }
 +    pub use self::index::{Index, IndexMut};
 +    // endregion:index
 +
 +    // region:drop
 +    pub mod mem {
 +        pub fn drop<T>(_x: T) {}
 +    }
 +    // endregion:drop
 +
 +    // region:range
 +    mod range {
 +        #[lang = "RangeFull"]
 +        pub struct RangeFull;
 +
 +        #[lang = "Range"]
 +        pub struct Range<Idx> {
 +            pub start: Idx,
 +            pub end: Idx,
 +        }
 +
 +        #[lang = "RangeFrom"]
 +        pub struct RangeFrom<Idx> {
 +            pub start: Idx,
 +        }
 +
 +        #[lang = "RangeTo"]
 +        pub struct RangeTo<Idx> {
 +            pub end: Idx,
 +        }
 +
 +        #[lang = "RangeInclusive"]
 +        pub struct RangeInclusive<Idx> {
 +            pub(crate) start: Idx,
 +            pub(crate) end: Idx,
 +            pub(crate) exhausted: bool,
 +        }
 +
 +        #[lang = "RangeToInclusive"]
 +        pub struct RangeToInclusive<Idx> {
 +            pub end: Idx,
 +        }
 +    }
 +    pub use self::range::{Range, RangeFrom, RangeFull, RangeTo};
 +    pub use self::range::{RangeInclusive, RangeToInclusive};
 +    // endregion:range
 +
 +    // region:fn
 +    mod function {
 +        #[lang = "fn"]
 +        #[fundamental]
 +        pub trait Fn<Args>: FnMut<Args> {}
 +
 +        #[lang = "fn_mut"]
 +        #[fundamental]
 +        pub trait FnMut<Args>: FnOnce<Args> {}
 +
 +        #[lang = "fn_once"]
 +        #[fundamental]
 +        pub trait FnOnce<Args> {
 +            #[lang = "fn_once_output"]
 +            type Output;
 +        }
 +    }
 +    pub use self::function::{Fn, FnMut, FnOnce};
 +    // endregion:fn
 +    // region:try
 +    mod try_ {
 +        pub enum ControlFlow<B, C = ()> {
 +            Continue(C),
 +            Break(B),
 +        }
-             type Residual = ControlFlow<B, convert::Infallible>;
++        pub trait FromResidual<R = <Self as Try>::Residual> {
 +            #[lang = "from_residual"]
 +            fn from_residual(residual: R) -> Self;
 +        }
 +        #[lang = "try"]
 +        pub trait Try: FromResidual<Self::Residual> {
 +            type Output;
 +            type Residual;
 +            #[lang = "from_output"]
 +            fn from_output(output: Self::Output) -> Self;
 +            #[lang = "branch"]
 +            fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
 +        }
 +
 +        impl<B, C> Try for ControlFlow<B, C> {
 +            type Output = C;
-             fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {}
++            type Residual = ControlFlow<B, crate::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> {
-     pub use self::adapters::{Take, FilterMap};
++            fn from_residual(residual: ControlFlow<B, crate::convert::Infallible>) -> Self {}
 +        }
 +    }
 +    pub use self::try_::{ControlFlow, FromResidual, Try};
 +    // endregion:try
 +
 +    // region:add
 +    #[lang = "add"]
 +    pub trait Add<Rhs = Self> {
 +        type Output;
 +        fn add(self, rhs: Rhs) -> Self::Output;
 +    }
 +    // endregion:add
 +
 +    // region:generator
 +    mod generator {
 +        use crate::pin::Pin;
 +
 +        #[lang = "generator"]
 +        pub trait Generator<R = ()> {
 +            type Yield;
 +            #[lang = "generator_return"]
 +            type Return;
 +            fn resume(self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return>;
 +        }
 +
 +        #[lang = "generator_state"]
 +        pub enum GeneratorState<Y, R> {
 +            Yielded(Y),
 +            Complete(R),
 +        }
 +    }
 +    pub use self::generator::{Generator, GeneratorState};
 +    // endregion:generator
 +}
 +
 +// region:eq
 +pub mod cmp {
 +    #[lang = "eq"]
 +    pub trait PartialEq<Rhs: ?Sized = Self> {
 +        fn eq(&self, other: &Rhs) -> bool;
 +        fn ne(&self, other: &Rhs) -> bool {
 +            !self.eq(other)
 +        }
 +    }
 +
 +    pub trait Eq: PartialEq<Self> {}
 +
 +    // region:derive
 +    #[rustc_builtin_macro]
 +    pub macro PartialEq($item:item) {}
 +    #[rustc_builtin_macro]
 +    pub macro Eq($item:item) {}
 +    // endregion:derive
 +
 +    // region:ord
 +    #[lang = "partial_ord"]
 +    pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
 +        fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;
 +    }
 +
 +    pub trait Ord: Eq + PartialOrd<Self> {
 +        fn cmp(&self, other: &Self) -> Ordering;
 +    }
 +
 +    pub enum Ordering {
 +        Less = -1,
 +        Equal = 0,
 +        Greater = 1,
 +    }
 +
 +    // region:derive
 +    #[rustc_builtin_macro]
 +    pub macro PartialOrd($item:item) {}
 +    #[rustc_builtin_macro]
 +    pub macro Ord($item:item) {}
 +    // endregion:derive
 +
 +    // endregion:ord
 +}
 +// endregion:eq
 +
 +// region:fmt
 +pub mod fmt {
 +    pub struct Error;
 +    pub type Result = Result<(), Error>;
 +    pub struct Formatter<'a>;
 +    pub trait Debug {
 +        fn fmt(&self, f: &mut Formatter<'_>) -> Result;
 +    }
 +}
 +// endregion:fmt
 +
 +// region:slice
 +pub mod slice {
 +    #[lang = "slice"]
 +    impl<T> [T] {
 +        pub fn len(&self) -> usize {
 +            loop {}
 +        }
 +    }
 +}
 +// endregion:slice
 +
 +// region:option
 +pub mod option {
 +    pub enum Option<T> {
 +        #[lang = "None"]
 +        None,
 +        #[lang = "Some"]
 +        Some(T),
 +    }
 +
 +    impl<T> Option<T> {
 +        pub const fn unwrap(self) -> T {
 +            match self {
 +                Some(val) => val,
 +                None => panic!("called `Option::unwrap()` on a `None` value"),
 +            }
 +        }
 +    }
++    // region:try
++    impl<T> crate::ops::Try for Option<T> {
++        type Output = T;
++        type Residual = Option<crate::convert::Infallible>;
++
++        #[inline]
++        fn from_output(output: Self::Output) -> Self {
++            Some(output)
++        }
++
++        #[inline]
++        fn branch(self) -> crate::ops::ControlFlow<Self::Residual, Self::Output> {
++            match self {
++                Some(v) => crate::ops::ControlFlow::Continue(v),
++                None => crate::ops::ControlFlow::Break(None),
++            }
++        }
++    }
++    impl<T> crate::ops::FromResidual for Option<T> {
++        #[inline]
++        fn from_residual(residual: Option<crate::convert::Infallible>) -> Self {
++            match residual {
++                None => None,
++            }
++        }
++    }
++    // endregion:try
 +}
 +// endregion:option
 +
 +// region:result
 +pub mod result {
 +    pub enum Result<T, E> {
 +        #[lang = "Ok"]
 +        Ok(T),
 +        #[lang = "Err"]
 +        Err(E),
 +    }
 +}
 +// endregion:result
 +
 +// region:pin
 +pub mod pin {
 +    #[lang = "pin"]
 +    #[fundamental]
 +    pub struct Pin<P> {
 +        pointer: P,
 +    }
 +    impl<P> Pin<P> {
 +        pub fn new(pointer: P) -> Pin<P> {
 +            loop {}
 +        }
 +    }
 +    // region:deref
 +    impl<P: crate::ops::Deref> crate::ops::Deref for Pin<P> {
 +        type Target = P::Target;
 +        fn deref(&self) -> &P::Target {
 +            loop {}
 +        }
 +    }
 +    // endregion:deref
 +}
 +// endregion:pin
 +
 +// region:future
 +pub mod future {
 +    use crate::{
 +        pin::Pin,
 +        task::{Context, Poll},
 +    };
 +
 +    #[lang = "future_trait"]
 +    pub trait Future {
 +        type Output;
 +        #[lang = "poll"]
 +        fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
 +    }
 +
 +    pub trait IntoFuture {
 +        type Output;
 +        type IntoFuture: Future<Output = Self::Output>;
 +        #[lang = "into_future"]
 +        fn into_future(self) -> Self::IntoFuture;
 +    }
 +
 +    impl<F: Future> IntoFuture for F {
 +        type Output = F::Output;
 +        type IntoFuture = F;
 +        fn into_future(self) -> F {
 +            self
 +        }
 +    }
 +}
 +pub mod task {
 +    pub enum Poll<T> {
 +        #[lang = "Ready"]
 +        Ready(T),
 +        #[lang = "Pending"]
 +        Pending,
 +    }
 +
 +    pub struct Context<'a> {
 +        waker: &'a (),
 +    }
 +}
 +// endregion:future
 +
 +// region:iterator
 +pub mod iter {
 +    // region:iterators
 +    mod adapters {
 +        pub struct Take<I> {
 +            iter: I,
 +            n: usize,
 +        }
 +        impl<I> Iterator for Take<I>
 +        where
 +            I: Iterator,
 +        {
 +            type Item = <I as Iterator>::Item;
 +
 +            fn next(&mut self) -> Option<<I as Iterator>::Item> {
 +                loop {}
 +            }
 +        }
 +
 +        pub struct FilterMap<I, F> {
 +            iter: I,
 +            f: F,
 +        }
 +        impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
 +        where
 +            F: FnMut(I::Item) -> Option<B>,
 +        {
 +            type Item = B;
 +
 +            #[inline]
 +            fn next(&mut self) -> Option<B> {
 +                loop {}
 +            }
 +        }
 +    }
++    pub use self::adapters::{FilterMap, Take};
 +
 +    mod sources {
 +        mod repeat {
 +            pub fn repeat<T>(elt: T) -> Repeat<T> {
 +                loop {}
 +            }
 +
 +            pub struct Repeat<A> {
 +                element: A,
 +            }
 +
 +            impl<A> Iterator for Repeat<A> {
 +                type Item = A;
 +
 +                fn next(&mut self) -> Option<A> {
 +                    loop {}
 +                }
 +            }
 +        }
 +        pub use self::repeat::{repeat, Repeat};
 +    }
 +    pub use self::sources::{repeat, Repeat};
 +    // endregion:iterators
 +
 +    mod traits {
 +        mod iterator {
 +            use super::super::Take;
 +
 +            pub trait Iterator {
 +                type Item;
 +                #[lang = "next"]
 +                fn next(&mut self) -> Option<Self::Item>;
 +                fn nth(&mut self, n: usize) -> Option<Self::Item> {
 +                    loop {}
 +                }
 +                fn by_ref(&mut self) -> &mut Self
 +                where
 +                    Self: Sized,
 +                {
 +                    self
 +                }
 +                // region:iterators
 +                fn take(self, n: usize) -> crate::iter::Take<Self> {
 +                    loop {}
 +                }
 +                fn filter_map<B, F>(self, f: F) -> crate::iter::FilterMap<Self, F>
 +                where
 +                    Self: Sized,
 +                    F: FnMut(Self::Item) -> Option<B>,
 +                {
 +                    loop {}
 +                }
 +                // endregion:iterators
 +            }
 +            impl<I: Iterator + ?Sized> Iterator for &mut I {
 +                type Item = I::Item;
 +                fn next(&mut self) -> Option<I::Item> {
 +                    (**self).next()
 +                }
 +            }
 +        }
 +        pub use self::iterator::Iterator;
 +
 +        mod collect {
 +            pub trait IntoIterator {
 +                type Item;
 +                type IntoIter: Iterator<Item = Self::Item>;
 +                #[lang = "into_iter"]
 +                fn into_iter(self) -> Self::IntoIter;
 +            }
 +            impl<I: Iterator> IntoIterator for I {
 +                type Item = I::Item;
 +                type IntoIter = I;
 +                fn into_iter(self) -> I {
 +                    self
 +                }
 +            }
 +        }
 +        pub use self::collect::IntoIterator;
 +    }
 +    pub use self::traits::{IntoIterator, Iterator};
 +}
 +// endregion:iterator
 +
 +// region:derive
 +mod macros {
 +    pub(crate) mod builtin {
 +        #[rustc_builtin_macro]
 +        pub macro derive($item:item) {
 +            /* compiler built-in */
 +        }
 +    }
 +}
 +// endregion:derive
 +
 +// region:bool_impl
 +#[lang = "bool"]
 +impl bool {
 +    pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
 +        if self {
 +            Some(f())
 +        } else {
 +            None
 +        }
 +    }
 +}
 +// endregion:bool_impl
 +
 +pub mod prelude {
 +    pub mod v1 {
 +        pub use crate::{
 +            clone::Clone,                       // :clone
 +            cmp::{Eq, PartialEq},               // :eq
 +            cmp::{Ord, PartialOrd},             // :ord
 +            convert::AsRef,                     // :as_ref
 +            convert::{From, Into},              // :from
 +            default::Default,                   // :default
 +            iter::{IntoIterator, Iterator},     // :iterator
 +            macros::builtin::derive,            // :derive
 +            marker::Copy,                       // :copy
 +            marker::Sized,                      // :sized
 +            mem::drop,                          // :drop
 +            ops::Drop,                          // :drop
 +            ops::{Fn, FnMut, FnOnce},           // :fn
 +            option::Option::{self, None, Some}, // :option
 +            result::Result::{self, Err, Ok},    // :result
 +        };
 +    }
 +
 +    pub mod rust_2015 {
 +        pub use super::v1::*;
 +    }
 +
 +    pub mod rust_2018 {
 +        pub use super::v1::*;
 +    }
 +
 +    pub mod rust_2021 {
 +        pub use super::v1::*;
 +    }
 +}
 +
 +#[prelude_import]
 +#[allow(unused)]
 +use prelude::v1::*;
index cf14bbd3c3e06c8ed4b4cdb30363f9664c3e84b4,0000000000000000000000000000000000000000..7a90d64a98ba9b01a55678f82ec00328724094ba
mode 100644,000000..100644
--- /dev/null
@@@ -1,14 -1,0 +1,14 @@@
- itertools = "0.10.3"
 +[package]
 +name = "text-edit"
 +version = "0.0.0"
 +description = "TBD"
 +license = "MIT OR Apache-2.0"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
++itertools = "0.10.5"
 +text-size = "1.1.0"
index 7d3b9e09ece773fa3babcb5669eaaea2d96d75b7,0000000000000000000000000000000000000000..3e0f31f19c507fc417fc413fd0039a5b9d124e8a
mode 100644,000000..100644
--- /dev/null
@@@ -1,13 -1,0 +1,13 @@@
- home = "0.5.3"
 +[package]
 +name = "toolchain"
 +version = "0.0.0"
 +description = "TBD"
 +license = "MIT OR Apache-2.0"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[lib]
 +doctest = false
 +
 +[dependencies]
++home = "0.5.4"
index fcc693a7ddac16908a14beaf99c946e9553462cf,0000000000000000000000000000000000000000..df5dc24e2cd12a15806ecef192798595a013e27b
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,20 @@@
- notify = "=5.0.0-pre.16"
 +[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"
 +
 +vfs = { path = "../vfs", version = "0.0.0" }
 +paths = { path = "../paths", version = "0.0.0" }
index c9ff0b6c29e379799461968dea5416af44eafcd1,0000000000000000000000000000000000000000..52a13da31c5d3ea3d25f963ec94e18b09fdbebd2
mode 100644,000000..100644
--- /dev/null
@@@ -1,573 -1,0 +1,572 @@@
- Procedural macros should become inputs as well, but currently they are not
- supported. Procedural macro will be a black box `Box<dyn Fn(TokenStream) -> TokenStream>`
- function, and will be inserted into the crate graph just like dependencies.
 +# Guide to rust-analyzer
 +
 +## About the guide
 +
 +This guide describes the current state of rust-analyzer as of 2019-01-20 (git
 +tag [guide-2019-01]). Its purpose is to document various problems and
 +architectural solutions related to the problem of building IDE-first compiler
 +for Rust. There is a video version of this guide as well:
 +https://youtu.be/ANKBNiSWyfc.
 +
 +[guide-2019-01]: https://github.com/rust-lang/rust-analyzer/tree/guide-2019-01
 +
 +## The big picture
 +
 +On the highest possible level, rust-analyzer is a stateful component. A client may
 +apply changes to the analyzer (new contents of `foo.rs` file is "fn main() {}")
 +and it may ask semantic questions about the current state (what is the
 +definition of the identifier with offset 92 in file `bar.rs`?). Two important
 +properties hold:
 +
 +* Analyzer does not do any I/O. It starts in an empty state and all input data is
 +  provided via `apply_change` API.
 +
 +* Only queries about the current state are supported. One can, of course,
 +  simulate undo and redo by keeping a log of changes and inverse changes respectively.
 +
 +## IDE API
 +
 +To see the bigger picture of how the IDE features work, let's take a look at the [`AnalysisHost`] and
 +[`Analysis`] pair of types. `AnalysisHost` has three methods:
 +
 +* `default()` for creating an empty analysis instance
 +* `apply_change(&mut self)` to make changes (this is how you get from an empty
 +  state to something interesting)
 +* `analysis(&self)` to get an instance of `Analysis`
 +
 +`Analysis` has a ton of methods for IDEs, like `goto_definition`, or
 +`completions`. Both inputs and outputs of `Analysis`' methods are formulated in
 +terms of files and offsets, and **not** in terms of Rust concepts like structs,
 +traits, etc. The "typed" API with Rust specific types is slightly lower in the
 +stack, we'll talk about it later.
 +
 +[`AnalysisHost`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L265-L284
 +[`Analysis`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L291-L478
 +
 +The reason for this separation of `Analysis` and `AnalysisHost` is that we want to apply
 +changes "uniquely", but we might also want to fork an `Analysis` and send it to
 +another thread for background processing. That is, there is only a single
 +`AnalysisHost`, but there may be several (equivalent) `Analysis`.
 +
 +Note that all of the `Analysis` API return `Cancellable<T>`. This is required to
 +be responsive in an IDE setting. Sometimes a long-running query is being computed
 +and the user types something in the editor and asks for completion. In this
 +case, we cancel the long-running computation (so it returns `Err(Cancelled)`),
 +apply the change and execute request for completion. We never use stale data to
 +answer requests. Under the cover, `AnalysisHost` "remembers" all outstanding
 +`Analysis` instances. The `AnalysisHost::apply_change` method cancels all
 +`Analysis`es, blocks until all of them are `Dropped` and then applies changes
 +in-place. This may be familiar to Rustaceans who use read-write locks for interior
 +mutability.
 +
 +Next, let's talk about what the inputs to the `Analysis` are, precisely.
 +
 +## Inputs
 +
 +rust-analyzer never does any I/O itself, all inputs get passed explicitly via
 +the `AnalysisHost::apply_change` method, which accepts a single argument, a
 +`Change`. [`Change`] is a builder for a single change
 +"transaction", so it suffices to study its methods to understand all of the
 +input data.
 +
 +[`Change`]: https://github.com/rust-lang/rust-analyzer/blob/master/crates/base_db/src/change.rs#L14-L89
 +
 +The `(add|change|remove)_file` methods control the set of the input files, where
 +each file has an integer id (`FileId`, picked by the client), text (`String`)
 +and a filesystem path. Paths are tricky; they'll be explained below, in source roots
 +section, together with the `add_root` method. The `add_library` method allows us to add a
 +group of files which are assumed to rarely change. It's mostly an optimization
 +and does not change the fundamental picture.
 +
 +The `set_crate_graph` method allows us to control how the input files are partitioned
 +into compilation units -- crates. It also controls (in theory, not implemented
 +yet) `cfg` flags. `CrateGraph` is a directed acyclic graph of crates. Each crate
 +has a root `FileId`, a set of active `cfg` flags and a set of dependencies. Each
 +dependency is a pair of a crate and a name. It is possible to have two crates
 +with the same root `FileId` but different `cfg`-flags/dependencies. This model
 +is lower than Cargo's model of packages: each Cargo package consists of several
 +targets, each of which is a separate crate (or several crates, if you try
 +different feature combinations).
 +
++Procedural macros are inputs as well, roughly modeled as a crate with a bunch of
++additional black box `dyn Fn(TokenStream) -> TokenStream` functions.
 +
 +Soon we'll talk how we build an LSP server on top of `Analysis`, but first,
 +let's deal with that paths issue.
 +
 +## Source roots (a.k.a. "Filesystems are horrible")
 +
 +This is a non-essential section, feel free to skip.
 +
 +The previous section said that the filesystem path is an attribute of a file,
 +but this is not the whole truth. Making it an absolute `PathBuf` will be bad for
 +several reasons. First, filesystems are full of (platform-dependent) edge cases:
 +
 +* It's hard (requires a syscall) to decide if two paths are equivalent.
 +* Some filesystems are case-sensitive (e.g. macOS).
 +* Paths are not necessarily UTF-8.
 +* Symlinks can form cycles.
 +
 +Second, this might hurt the reproducibility and hermeticity of builds. In theory,
 +moving a project from `/foo/bar/my-project` to `/spam/eggs/my-project` should
 +not change a bit in the output. However, if the absolute path is a part of the
 +input, it is at least in theory observable, and *could* affect the output.
 +
 +Yet another problem is that we really *really* want to avoid doing I/O, but with
 +Rust the set of "input" files is not necessarily known up-front. In theory, you
 +can have `#[path="/dev/random"] mod foo;`.
 +
 +To solve (or explicitly refuse to solve) these problems rust-analyzer uses the
 +concept of a "source root". Roughly speaking, source roots are the contents of a
 +directory on a file systems, like `/home/matklad/projects/rustraytracer/**.rs`.
 +
 +More precisely, all files (`FileId`s) are partitioned into disjoint
 +`SourceRoot`s. Each file has a relative UTF-8 path within the `SourceRoot`.
 +`SourceRoot` has an identity (integer ID). Crucially, the root path of the
 +source root itself is unknown to the analyzer: A client is supposed to maintain a
 +mapping between `SourceRoot` IDs (which are assigned by the client) and actual
 +`PathBuf`s. `SourceRoot`s give a sane tree model of the file system to the
 +analyzer.
 +
 +Note that `mod`, `#[path]` and `include!()` can only reference files from the
 +same source root. It is of course possible to explicitly add extra files to
 +the source root, even `/dev/random`.
 +
 +## Language Server Protocol
 +
 +Now let's see how the `Analysis` API is exposed via the JSON RPC based language server protocol. The
 +hard part here is managing changes (which can come either from the file system
 +or from the editor) and concurrency (we want to spawn background jobs for things
 +like syntax highlighting). We use the event loop pattern to manage the zoo, and
 +the loop is the [`main_loop_inner`] function. The [`main_loop`] does a one-time
 +initialization and tearing down of the resources.
 +
 +[`main_loop`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L51-L110
 +[`main_loop_inner`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L156-L258
 +
 +
 +Let's walk through a typical analyzer session!
 +
 +First, we need to figure out what to analyze. To do this, we run `cargo
 +metadata` to learn about Cargo packages for current workspace and dependencies,
 +and we run `rustc --print sysroot` and scan the "sysroot" (the directory containing the current Rust toolchain's files) to learn about crates like
 +`std`. Currently we load this configuration once at the start of the server, but
 +it should be possible to dynamically reconfigure it later without restart.
 +
 +[main_loop.rs#L62-L70](https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L62-L70)
 +
 +The [`ProjectModel`] we get after this step is very Cargo and sysroot specific,
 +it needs to be lowered to get the input in the form of `Change`. This
 +happens in [`ServerWorldState::new`] method. Specifically
 +
 +* Create a `SourceRoot` for each Cargo package and sysroot.
 +* Schedule a filesystem scan of the roots.
 +* Create an analyzer's `Crate` for each Cargo **target** and sysroot crate.
 +* Setup dependencies between the crates.
 +
 +[`ProjectModel`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/project_model.rs#L16-L20
 +[`ServerWorldState::new`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/server_world.rs#L38-L160
 +
 +The results of the scan (which may take a while) will be processed in the body
 +of the main loop, just like any other change. Here's where we handle:
 +
 +* [File system changes](https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L194)
 +* [Changes from the editor](https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L377)
 +
 +After a single loop's turn, we group the changes into one `Change` and
 +[apply] it. This always happens on the main thread and blocks the loop.
 +
 +[apply]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/server_world.rs#L216
 +
 +To handle requests, like ["goto definition"], we create an instance of the
 +`Analysis` and [`schedule`] the task (which consumes `Analysis`) on the
 +threadpool. [The task] calls the corresponding `Analysis` method, while
 +massaging the types into the LSP representation. Keep in mind that if we are
 +executing "goto definition" on the threadpool and a new change comes in, the
 +task will be canceled as soon as the main loop calls `apply_change` on the
 +`AnalysisHost`.
 +
 +["goto definition"]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/server_world.rs#L216
 +[`schedule`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L426-L455
 +[The task]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop/handlers.rs#L205-L223
 +
 +This concludes the overview of the analyzer's programing *interface*. Next, let's
 +dig into the implementation!
 +
 +## Salsa
 +
 +The most straightforward way to implement an "apply change, get analysis, repeat"
 +API would be to maintain the input state and to compute all possible analysis
 +information from scratch after every change. This works, but scales poorly with
 +the size of the project. To make this fast, we need to take advantage of the
 +fact that most of the changes are small, and that analysis results are unlikely
 +to change significantly between invocations.
 +
 +To do this we use [salsa]: a framework for incremental on-demand computation.
 +You can skip the rest of the section if you are familiar with `rustc`'s red-green
 +algorithm (which is used for incremental compilation).
 +
 +[salsa]: https://github.com/salsa-rs/salsa
 +
 +It's better to refer to salsa's docs to learn about it. Here's a small excerpt:
 +
 +The key idea of salsa is that you define your program as a set of queries. Every
 +query is used like a function `K -> V` that maps from some key of type `K` to a value
 +of type `V`. Queries come in two basic varieties:
 +
 +* **Inputs**: the base inputs to your system. You can change these whenever you
 +  like.
 +
 +* **Functions**: pure functions (no side effects) that transform your inputs
 +  into other values. The results of queries are memoized to avoid recomputing
 +  them a lot. When you make changes to the inputs, we'll figure out (fairly
 +  intelligently) when we can re-use these memoized values and when we have to
 +  recompute them.
 +
 +For further discussion, its important to understand one bit of "fairly
 +intelligently". Suppose we have two functions, `f1` and `f2`, and one input,
 +`z`. We call `f1(X)` which in turn calls `f2(Y)` which inspects `i(Z)`. `i(Z)`
 +returns some value `V1`, `f2` uses that and returns `R1`, `f1` uses that and
 +returns `O`. Now, let's change `i` at `Z` to `V2` from `V1` and try to compute
 +`f1(X)` again. Because `f1(X)` (transitively) depends on `i(Z)`, we can't just
 +reuse its value as is. However, if `f2(Y)` is *still* equal to `R1` (despite
 +`i`'s change), we, in fact, *can* reuse `O` as result of `f1(X)`. And that's how
 +salsa works: it recomputes results in *reverse* order, starting from inputs and
 +progressing towards outputs, stopping as soon as it sees an intermediate value
 +that hasn't changed. If this sounds confusing to you, don't worry: it is
 +confusing. This illustration by @killercup might help:
 +
 +<img alt="step 1" src="https://user-images.githubusercontent.com/1711539/51460907-c5484780-1d6d-11e9-9cd2-d6f62bd746e0.png" width="50%">
 +
 +<img alt="step 2" src="https://user-images.githubusercontent.com/1711539/51460915-c9746500-1d6d-11e9-9a77-27d33a0c51b5.png" width="50%">
 +
 +<img alt="step 3" src="https://user-images.githubusercontent.com/1711539/51460920-cda08280-1d6d-11e9-8d96-a782aa57a4d4.png" width="50%">
 +
 +<img alt="step 4" src="https://user-images.githubusercontent.com/1711539/51460927-d1340980-1d6d-11e9-851e-13c149d5c406.png" width="50%">
 +
 +## Salsa Input Queries
 +
 +All analyzer information is stored in a salsa database. `Analysis` and
 +`AnalysisHost` types are newtype wrappers for [`RootDatabase`] -- a salsa
 +database.
 +
 +[`RootDatabase`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/db.rs#L88-L134
 +
 +Salsa input queries are defined in [`FilesDatabase`] (which is a part of
 +`RootDatabase`). They closely mirror the familiar `Change` structure:
 +indeed, what `apply_change` does is it sets the values of input queries.
 +
 +[`FilesDatabase`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/base_db/src/input.rs#L150-L174
 +
 +## From text to semantic model
 +
 +The bulk of the rust-analyzer is transforming input text into a semantic model of
 +Rust code: a web of entities like modules, structs, functions and traits.
 +
 +An important fact to realize is that (unlike most other languages like C# or
 +Java) there is not a one-to-one mapping between the source code and the semantic model. A
 +single function definition in the source code might result in several semantic
 +functions: for example, the same source file might get included as a module in
 +several crates or a single crate might be present in the compilation DAG
 +several times, with different sets of `cfg`s enabled. The IDE-specific task of
 +mapping source code into a semantic model is inherently imprecise for
 +this reason and gets handled by the [`source_binder`].
 +
 +[`source_binder`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/source_binder.rs
 +
 +The semantic interface is declared in the [`code_model_api`] module. Each entity is
 +identified by an integer ID and has a bunch of methods which take a salsa database
 +as an argument and returns other entities (which are also IDs). Internally, these
 +methods invoke various queries on the database to build the model on demand.
 +Here's [the list of queries].
 +
 +[`code_model_api`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/code_model_api.rs
 +[the list of queries]: https://github.com/rust-lang/rust-analyzer/blob/7e84440e25e19529e4ff8a66e521d1b06349c6ec/crates/hir/src/db.rs#L20-L106
 +
 +The first step of building the model is parsing the source code.
 +
 +## Syntax trees
 +
 +An important property of the Rust language is that each file can be parsed in
 +isolation. Unlike, say, `C++`, an `include` can't change the meaning of the
 +syntax. For this reason, rust-analyzer can build a syntax tree for each "source
 +file", which could then be reused by several semantic models if this file
 +happens to be a part of several crates.
 +
 +The representation of syntax trees that rust-analyzer uses is similar to that of `Roslyn`
 +and Swift's new [libsyntax]. Swift's docs give an excellent overview of the
 +approach, so I skip this part here and instead outline the main characteristics
 +of the syntax trees:
 +
 +* Syntax trees are fully lossless. Converting **any** text to a syntax tree and
 +  back is a total identity function. All whitespace and comments are explicitly
 +  represented in the tree.
 +
 +* Syntax nodes have generic `(next|previous)_sibling`, `parent`,
 +  `(first|last)_child` functions. You can get from any one node to any other
 +  node in the file using only these functions.
 +
 +* Syntax nodes know their range (start offset and length) in the file.
 +
 +* Syntax nodes share the ownership of their syntax tree: if you keep a reference
 +  to a single function, the whole enclosing file is alive.
 +
 +* Syntax trees are immutable and the cost of replacing the subtree is
 +  proportional to the depth of the subtree. Read Swift's docs to learn how
 +  immutable + parent pointers + cheap modification is possible.
 +
 +* Syntax trees are build on best-effort basis. All accessor methods return
 +  `Option`s. The tree for `fn foo` will contain a function declaration with
 +  `None` for parameter list and body.
 +
 +* Syntax trees do not know the file they are built from, they only know about
 +  the text.
 +
 +The implementation is based on the generic [rowan] crate on top of which a
 +[rust-specific] AST is generated.
 +
 +[libsyntax]: https://github.com/apple/swift/tree/5e2c815edfd758f9b1309ce07bfc01c4bc20ec23/lib/Syntax
 +[rowan]: https://github.com/rust-analyzer/rowan/tree/100a36dc820eb393b74abe0d20ddf99077b61f88
 +[rust-specific]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_syntax/src/ast/generated.rs
 +
 +The next step in constructing the semantic model is ...
 +
 +## Building a Module Tree
 +
 +The algorithm for building a tree of modules is to start with a crate root
 +(remember, each `Crate` from a `CrateGraph` has a `FileId`), collect all `mod`
 +declarations and recursively process child modules. This is handled by the
 +[`module_tree_query`], with two slight variations.
 +
 +[`module_tree_query`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/module_tree.rs#L116-L123
 +
 +First, rust-analyzer builds a module tree for all crates in a source root
 +simultaneously. The main reason for this is historical (`module_tree` predates
 +`CrateGraph`), but this approach also enables accounting for files which are not
 +part of any crate. That is, if you create a file but do not include it as a
 +submodule anywhere, you still get semantic completion, and you get a warning
 +about a free-floating module (the actual warning is not implemented yet).
 +
 +The second difference is that `module_tree_query` does not *directly* depend on
 +the "parse" query (which is confusingly called `source_file`). Why would calling
 +the parse directly be bad? Suppose the user changes the file slightly, by adding
 +an insignificant whitespace. Adding whitespace changes the parse tree (because
 +it includes whitespace), and that means recomputing the whole module tree.
 +
 +We deal with this problem by introducing an intermediate [`submodules_query`].
 +This query processes the syntax tree and extracts a set of declared submodule
 +names. Now, changing the whitespace results in `submodules_query` being
 +re-executed for a *single* module, but because the result of this query stays
 +the same, we don't have to re-execute [`module_tree_query`]. In fact, we only
 +need to re-execute it when we add/remove new files or when we change mod
 +declarations.
 +
 +[`submodules_query`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/module_tree.rs#L41
 +
 +We store the resulting modules in a `Vec`-based indexed arena. The indices in
 +the arena becomes module IDs. And this brings us to the next topic:
 +assigning IDs in the general case.
 +
 +## Location Interner pattern
 +
 +One way to assign IDs is how we've dealt with modules: Collect all items into a
 +single array in some specific order and use the index in the array as an ID. The
 +main drawback of this approach is that these IDs are not stable: Adding a new item can
 +shift the IDs of all other items. This works for modules, because adding a module is
 +a comparatively rare operation, but would be less convenient for, for example,
 +functions.
 +
 +Another solution here is positional IDs: We can identify a function as "the
 +function with name `foo` in a ModuleId(92) module". Such locations are stable:
 +adding a new function to the module (unless it is also named `foo`) does not
 +change the location. However, such "ID" types ceases to be a `Copy`able integer and in
 +general can become pretty large if we account for nesting (for example: "third parameter of
 +the `foo` function of the `bar` `impl` in the `baz` module").
 +
 +[`LocationInterner`] allows us to combine the benefits of positional and numeric
 +IDs. It is a bidirectional append-only map between locations and consecutive
 +integers which can "intern" a location and return an integer ID back. The salsa
 +database we use includes a couple of [interners]. How to "garbage collect"
 +unused locations is an open question.
 +
 +[`LocationInterner`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/base_db/src/loc2id.rs#L65-L71
 +[interners]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/db.rs#L22-L23
 +
 +For example, we use `LocationInterner` to assign IDs to definitions of functions,
 +structs, enums, etc. The location, [`DefLoc`] contains two bits of information:
 +
 +* the ID of the module which contains the definition,
 +* the ID of the specific item in the modules source code.
 +
 +We "could" use a text offset for the location of a particular item, but that would play
 +badly with salsa: offsets change after edits. So, as a rule of thumb, we avoid
 +using offsets, text ranges or syntax trees as keys and values for queries. What
 +we do instead is we store "index" of the item among all of the items of a file
 +(so, a positional based ID, but localized to a single file).
 +
 +[`DefLoc`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/ids.rs#L127-L139
 +
 +One thing we've glossed over for the time being is support for macros. We have
 +only proof of concept handling of macros at the moment, but they are extremely
 +interesting from an "assigning IDs" perspective.
 +
 +## Macros and recursive locations
 +
 +The tricky bit about macros is that they effectively create new source files.
 +While we can use `FileId`s to refer to original files, we can't just assign them
 +willy-nilly to the pseudo files of macro expansion. Instead, we use a special
 +ID, [`HirFileId`] to refer to either a usual file or a macro-generated file:
 +
 +```rust
 +enum HirFileId {
 +    FileId(FileId),
 +    Macro(MacroCallId),
 +}
 +```
 +
 +`MacroCallId` is an interned ID that specifies a particular macro invocation.
 +Its `MacroCallLoc` contains:
 +
 +* `ModuleId` of the containing module
 +* `HirFileId` of the containing file or pseudo file
 +* an index of this particular macro invocation in this file (positional id
 +  again).
 +
 +Note how `HirFileId` is defined in terms of `MacroCallLoc` which is defined in
 +terms of `HirFileId`! This does not recur infinitely though: any chain of
 +`HirFileId`s bottoms out in `HirFileId::FileId`, that is, some source file
 +actually written by the user.
 +
 +[`HirFileId`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/ids.rs#L18-L125
 +
 +Now that we understand how to identify a definition, in a source or in a
 +macro-generated file, we can discuss name resolution a bit.
 +
 +## Name resolution
 +
 +Name resolution faces the same problem as the module tree: if we look at the
 +syntax tree directly, we'll have to recompute name resolution after every
 +modification. The solution to the problem is the same: We [lower] the source code of
 +each module into a position-independent representation which does not change if
 +we modify bodies of the items. After that we [loop] resolving all imports until
 +we've reached a fixed point.
 +
 +[lower]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L113-L117
 +[loop]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres.rs#L186-L196
 +
 +And, given all our preparation with IDs and a position-independent representation,
 +it is satisfying to [test] that typing inside function body does not invalidate
 +name resolution results.
 +
 +[test]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/tests.rs#L376
 +
 +An interesting fact about name resolution is that it "erases" all of the
 +intermediate paths from the imports: in the end, we know which items are defined
 +and which items are imported in each module, but, if the import was `use
 +foo::bar::baz`, we deliberately forget what modules `foo` and `bar` resolve to.
 +
 +To serve "goto definition" requests on intermediate segments we need this info
 +in the IDE, however. Luckily, we need it only for a tiny fraction of imports, so we just ask
 +the module explicitly, "What does the path `foo::bar` resolve to?". This is a
 +general pattern: we try to compute the minimal possible amount of information
 +during analysis while allowing IDE to ask for additional specific bits.
 +
 +Name resolution is also a good place to introduce another salsa pattern used
 +throughout the analyzer:
 +
 +## Source Map pattern
 +
 +Due to an obscure edge case in completion, IDE needs to know the syntax node of
 +a use statement which imported the given completion candidate. We can't just
 +store the syntax node as a part of name resolution: this will break
 +incrementality, due to the fact that syntax changes after every file
 +modification.
 +
 +We solve this problem during the lowering step of name resolution. The lowering
 +query actually produces a *pair* of outputs: `LoweredModule` and [`SourceMap`].
 +The `LoweredModule` module contains [imports], but in a position-independent form.
 +The `SourceMap` contains a mapping from position-independent imports to
 +(position-dependent) syntax nodes.
 +
 +The result of this basic lowering query changes after every modification. But
 +there's an intermediate [projection query] which returns only the first
 +position-independent part of the lowering. The result of this query is stable.
 +Naturally, name resolution [uses] this stable projection query.
 +
 +[imports]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L52-L59
 +[`SourceMap`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L52-L59
 +[projection query]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/nameres/lower.rs#L97-L103
 +[uses]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/query_definitions.rs#L49
 +
 +## Type inference
 +
 +First of all, implementation of type inference in rust-analyzer was spearheaded
 +by [@flodiebold]. [#327] was an awesome Christmas present, thank you, Florian!
 +
 +Type inference runs on per-function granularity and uses the patterns we've
 +discussed previously.
 +
 +First, we [lower the AST] of a function body into a position-independent
 +representation. In this representation, each expression is assigned a
 +[positional ID]. Alongside the lowered expression, [a source map] is produced,
 +which maps between expression ids and original syntax. This lowering step also
 +deals with "incomplete" source trees by replacing missing expressions by an
 +explicit `Missing` expression.
 +
 +Given the lowered body of the function, we can now run [type inference] and
 +construct a mapping from `ExprId`s to types.
 +
 +[@flodiebold]: https://github.com/flodiebold
 +[#327]: https://github.com/rust-lang/rust-analyzer/pull/327
 +[lower the AST]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/expr.rs
 +[positional ID]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/expr.rs#L13-L15
 +[a source map]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/expr.rs#L41-L44
 +[type inference]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/hir/src/ty.rs#L1208-L1223
 +
 +## Tying it all together: completion
 +
 +To conclude the overview of the rust-analyzer, let's trace the request for
 +(type-inference powered!) code completion!
 +
 +We start by [receiving a message] from the language client. We decode the
 +message as a request for completion and [schedule it on the threadpool]. This is
 +the place where we [catch] canceled errors if, immediately after completion, the
 +client sends some modification.
 +
 +In [the handler], we deserialize LSP requests into rust-analyzer specific data
 +types (by converting a file url into a numeric `FileId`), [ask analysis for
 +completion] and serialize results into the LSP.
 +
 +The [completion implementation] is finally the place where we start doing the actual
 +work. The first step is to collect the `CompletionContext` -- a struct which
 +describes the cursor position in terms of Rust syntax and semantics. For
 +example, `function_syntax: Option<&'a ast::FnDef>` stores a reference to
 +the enclosing function *syntax*, while `function: Option<hir::Function>` is the
 +`Def` for this function.
 +
 +To construct the context, we first do an ["IntelliJ Trick"]: we insert a dummy
 +identifier at the cursor's position and parse this modified file, to get a
 +reasonably looking syntax tree. Then we do a bunch of "classification" routines
 +to figure out the context. For example, we [find an ancestor `fn` node] and we get a
 +[semantic model] for it (using the lossy `source_binder` infrastructure).
 +
 +The second step is to run a [series of independent completion routines]. Let's
 +take a closer look at [`complete_dot`], which completes fields and methods in
 +`foo.bar|`. First we extract a semantic function and a syntactic receiver
 +expression out of the `Context`. Then we run type-inference for this single
 +function and map our syntactic expression to `ExprId`. Using the ID, we figure
 +out the type of the receiver expression. Then we add all fields & methods from
 +the type to completion.
 +
 +[receiving a message]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L203
 +[schedule it on the threadpool]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L428
 +[catch]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L436-L442
 +[the handler]: https://salsa.zulipchat.com/#narrow/stream/181542-rfcs.2Fsalsa-query-group/topic/design.20next.20steps
 +[ask analysis for completion]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/lib.rs#L439-L444
 +[completion implementation]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion.rs#L46-L62
 +[`CompletionContext`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L14-L37
 +["IntelliJ Trick"]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L72-L75
 +[find an ancestor `fn` node]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L116-L120
 +[semantic model]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/completion_context.rs#L123
 +[series of independent completion routines]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion.rs#L52-L59
 +[`complete_dot`]: https://github.com/rust-lang/rust-analyzer/blob/guide-2019-01/crates/ide_api/src/completion/complete_dot.rs#L6-L22
index 30e13701383a9a3f091daa20f35ee9bacaad8e56,0000000000000000000000000000000000000000..97e376787c828d9bb9ef5c9f391f3bbb637f7829
mode 100644,000000..100644
--- /dev/null
@@@ -1,534 -1,0 +1,534 @@@
- * [rowan](https://github.com/rust-analyzer/rowan/tree/v0.9.0) -- a generic library for rowan syntax trees.
- * [ra_syntax](https://github.com/rust-lang/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6/crates/ra_syntax) crate inside rust-analyzer which wraps `rowan` into rust-analyzer specific API.
 +# Syntax in rust-analyzer
 +
 +## About the guide
 +
 +This guide describes the current state of syntax trees and parsing in rust-analyzer as of 2020-01-09 ([link to commit](https://github.com/rust-lang/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6)).
 +
 +## Source Code
 +
 +The things described are implemented in three places
 +
- * [parser](https://github.com/rust-lang/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6/crates/parser) crate parses input tokens into an `ra_syntax` tree
++* [rowan](https://github.com/rust-analyzer/rowan/tree/v0.15.10) -- a generic library for rowan syntax trees.
++* [syntax](https://github.com/rust-lang/rust-analyzer/tree/36a70b7435c48837018c71576d7bb4e8f763f501/crates/syntax) crate inside rust-analyzer which wraps `rowan` into rust-analyzer specific API.
 +  Nothing in rust-analyzer except this crate knows about `rowan`.
++* [parser](https://github.com/rust-lang/rust-analyzer/tree/36a70b7435c48837018c71576d7bb4e8f763f501/crates/parser) crate parses input tokens into a `syntax` tree
 +
 +## Design Goals
 +
 +* Syntax trees are lossless, or full fidelity. All comments and whitespace get preserved.
 +* Syntax trees are semantic-less. They describe *strictly* the structure of a sequence of characters, they don't have hygiene, name resolution or type information attached.
 +* Syntax trees are simple value types. It is possible to create trees for a syntax without any external context.
 +* Syntax trees have intuitive traversal API (parent, children, siblings, etc).
 +* Parsing is lossless (even if the input is invalid, the tree produced by the parser represents it exactly).
 +* Parsing is resilient (even if the input is invalid, parser tries to see as much syntax tree fragments in the input as it can).
 +* Performance is important, it's OK to use `unsafe` if it means better memory/cpu usage.
 +* Keep the parser and the syntax tree isolated from each other, such that they can vary independently.
 +
 +## Trees
 +
 +### Overview
 +
 +The syntax tree consists of three layers:
 +
 +* GreenNodes
 +* SyntaxNodes (aka RedNode)
 +* AST
 +
 +Of these, only GreenNodes store the actual data, the other two layers are (non-trivial) views into green tree.
 +Red-green terminology comes from Roslyn ([link](https://ericlippert.com/2012/06/08/red-green-trees/)) and gives the name to the `rowan` library. Green and syntax nodes are defined in rowan, ast is defined in rust-analyzer.
 +
 +Syntax trees are a semi-transient data structure.
 +In general, frontend does not keep syntax trees for all files in memory.
 +Instead, it *lowers* syntax trees to more compact and rigid representation, which is not full-fidelity, but which can be mapped back to a syntax tree if so desired.
 +
 +
 +### GreenNode
 +
 +GreenNode is a purely-functional tree with arbitrary arity. Conceptually, it is equivalent to the following run of the mill struct:
 +
 +```rust
 +#[derive(PartialEq, Eq, Clone, Copy)]
 +struct SyntaxKind(u16);
 +
 +#[derive(PartialEq, Eq, Clone)]
 +struct Node {
 +    kind: SyntaxKind,
 +    text_len: usize,
 +    children: Vec<Arc<Either<Node, Token>>>,
 +}
 +
 +#[derive(PartialEq, Eq, Clone)]
 +struct Token {
 +    kind: SyntaxKind,
 +    text: String,
 +}
 +```
 +
 +All the difference between the above sketch and the real implementation are strictly due to optimizations.
 +
 +Points of note:
 +* The tree is untyped. Each node has a "type tag", `SyntaxKind`.
 +* Interior and leaf nodes are distinguished on the type level.
 +* Trivia and non-trivia tokens are not distinguished on the type level.
 +* Each token carries its full text.
 +* The original text can be recovered by concatenating the texts of all tokens in order.
 +* Accessing a child of particular type (for example, parameter list of a function) generally involves linearly traversing the children, looking for a specific `kind`.
 +* Modifying the tree is roughly `O(depth)`.
 +  We don't make special efforts to guarantee that the depth is not linear, but, in practice, syntax trees are branchy and shallow.
 +* If mandatory (grammar wise) node is missing from the input, it's just missing from the tree.
 +* If an extra erroneous input is present, it is wrapped into a node with `ERROR` kind, and treated just like any other node.
 +* Parser errors are not a part of syntax tree.
 +
 +An input like `fn f() { 90 + 2 }` might be parsed as
 +
 +```
 +FN@0..17
 +  FN_KW@0..2 "fn"
 +  WHITESPACE@2..3 " "
 +  NAME@3..4
 +    IDENT@3..4 "f"
 +  PARAM_LIST@4..6
 +    L_PAREN@4..5 "("
 +    R_PAREN@5..6 ")"
 +  WHITESPACE@6..7 " "
 +  BLOCK_EXPR@7..17
 +    L_CURLY@7..8 "{"
 +    WHITESPACE@8..9 " "
 +    BIN_EXPR@9..15
 +      LITERAL@9..11
 +        INT_NUMBER@9..11 "90"
 +      WHITESPACE@11..12 " "
 +      PLUS@12..13 "+"
 +      WHITESPACE@13..14 " "
 +      LITERAL@14..15
 +        INT_NUMBER@14..15 "2"
 +    WHITESPACE@15..16 " "
 +    R_CURLY@16..17 "}"
 +```
 +
 +#### Optimizations
 +
 +(significant amount of implementation work here was done by [CAD97](https://github.com/cad97)).
 +
 +To reduce the amount of allocations, the GreenNode is a [DST](https://doc.rust-lang.org/reference/dynamically-sized-types.html), which uses a single allocation for header and children. Thus, it is only usable behind a pointer.
 +
 +```
 +*-----------+------+----------+------------+--------+--------+-----+--------*
 +| ref_count | kind | text_len | n_children | child1 | child2 | ... | childn |
 +*-----------+------+----------+------------+--------+--------+-----+--------*
 +```
 +
 +To more compactly store the children, we box *both* interior nodes and tokens, and represent
 +`Either<Arc<Node>, Arc<Token>>` as a single pointer with a tag in the last bit.
 +
 +To avoid allocating EVERY SINGLE TOKEN on the heap, syntax trees use interning.
 +Because the tree is fully immutable, it's valid to structurally share subtrees.
 +For example, in `1 + 1`, there will be a *single* token for `1` with ref count 2; the same goes for the ` ` whitespace token.
 +Interior nodes are shared as well (for example in `(1 + 1) * (1 + 1)`).
 +
 +Note that, the result of the interning is an `Arc<Node>`.
 +That is, it's not an index into interning table, so you don't have to have the table around to do anything with the tree.
 +Each tree is fully self-contained (although different trees might share parts).
 +Currently, the interner is created per-file, but it will be easy to use a per-thread or per-some-contex one.
 +
 +We use a `TextSize`, a newtyped `u32`, to store the length of the text.
 +
 +We currently use `SmolStr`, a small object optimized string to store text.
 +This was mostly relevant *before* we implemented tree interning, to avoid allocating common keywords and identifiers. We should switch to storing text data alongside the interned tokens.
 +
 +#### Alternative designs
 +
 +##### Dealing with trivia
 +
 +In the above model, whitespace is not treated specially.
 +Another alternative (used by swift and roslyn) is to explicitly divide the set of tokens into trivia and non-trivia tokens, and represent non-trivia tokens as
 +
 +```rust
 +struct Token {
 +    kind: NonTriviaTokenKind,
 +    text: String,
 +    leading_trivia: Vec<TriviaToken>,
 +    trailing_trivia: Vec<TriviaToken>,
 +}
 +```
 +
 +The tree then contains only non-trivia tokens.
 +
 +Another approach (from Dart) is to, in addition to a syntax tree, link all the tokens into a bidirectional link list.
 +That way, the tree again contains only non-trivia tokens.
 +
 +Explicit trivia nodes, like in `rowan`, are used by IntelliJ.
 +
 +##### Accessing Children
 +
 +As noted before, accessing a specific child in the node requires a linear traversal of the children (though we can skip tokens, because the tag is encoded in the pointer itself).
 +It is possible to recover O(1) access with another representation.
 +We explicitly store optional and missing (required by the grammar, but not present) nodes.
 +That is, we use `Option<Node>` for children.
 +We also remove trivia tokens from the tree.
 +This way, each child kind generally occupies a fixed position in a parent, and we can use index access to fetch it.
 +The cost is that we now need to allocate space for all not-present optional nodes.
 +So, `fn foo() {}` will have slots for visibility, unsafeness, attributes, abi and return type.
 +
 +IntelliJ uses linear traversal.
 +Roslyn and Swift do `O(1)` access.
 +
 +##### Mutable Trees
 +
 +IntelliJ uses mutable trees.
 +Overall, it creates a lot of additional complexity.
 +However, the API for *editing* syntax trees is nice.
 +
 +For example the assist to move generic bounds to where clause has this code:
 +
 +```kotlin
 + for typeBound in typeBounds {
 +     typeBound.typeParamBounds?.delete()
 +}
 +```
 +
 +Modeling this with immutable trees is possible, but annoying.
 +
 +### Syntax Nodes
 +
 +A function green tree is not super-convenient to use.
 +The biggest problem is accessing parents (there are no parent pointers!).
 +But there are also "identify" issues.
 +Let's say you want to write a code which builds a list of expressions in a file: `fn collect_expressions(file: GreenNode) -> HashSet<GreenNode>`.
 +For the input like
 +
 +```rust
 +fn main() {
 +    let x = 90i8;
 +    let x = x + 2;
 +    let x = 90i64;
 +    let x = x + 2;
 +}
 +```
 +
 +both copies of the `x + 2` expression are representing by equal (and, with interning in mind, actually the same) green nodes.
 +Green trees just can't differentiate between the two.
 +
 +`SyntaxNode` adds parent pointers and identify semantics to green nodes.
 +They can be called cursors or [zippers](https://en.wikipedia.org/wiki/Zipper_(data_structure)) (fun fact: zipper is a derivative (as in ′) of a data structure).
 +
 +Conceptually, a `SyntaxNode` looks like this:
 +
 +```rust
 +type SyntaxNode = Arc<SyntaxData>;
 +
 +struct SyntaxData {
 +    offset: usize,
 +    parent: Option<SyntaxNode>,
 +    green: Arc<GreenNode>,
 +}
 +
 +impl SyntaxNode {
 +    fn new_root(root: Arc<GreenNode>) -> SyntaxNode {
 +        Arc::new(SyntaxData {
 +            offset: 0,
 +            parent: None,
 +            green: root,
 +        })
 +    }
 +    fn parent(&self) -> Option<SyntaxNode> {
 +        self.parent.clone()
 +    }
 +    fn children(&self) -> impl Iterator<Item = SyntaxNode> {
 +        let mut offset = self.offset;
 +        self.green.children().map(|green_child| {
 +            let child_offset = offset;
 +            offset += green_child.text_len;
 +            Arc::new(SyntaxData {
 +                offset: child_offset,
 +                parent: Some(Arc::clone(self)),
 +                green: Arc::clone(green_child),
 +            })
 +        })
 +    }
 +}
 +
 +impl PartialEq for SyntaxNode {
 +    fn eq(&self, other: &SyntaxNode) -> bool {
 +        self.offset == other.offset
 +            && Arc::ptr_eq(&self.green, &other.green)
 +    }
 +}
 +```
 +
 +Points of note:
 +
 +* SyntaxNode remembers its parent node (and, transitively, the path to the root of the tree)
 +* SyntaxNode knows its *absolute* text offset in the whole file
 +* Equality is based on identity. Comparing nodes from different trees does not make sense.
 +
 +#### Optimization
 +
 +The reality is different though :-)
 +Traversal of trees is a common operation, and it makes sense to optimize it.
 +In particular, the above code allocates and does atomic operations during a traversal.
 +
 +To get rid of atomics, `rowan` uses non thread-safe `Rc`.
 +This is OK because trees traversals mostly (always, in case of rust-analyzer) run on a single thread. If you need to send a `SyntaxNode` to another thread, you can send a pair of **root**`GreenNode` (which is thread safe) and a `Range<usize>`.
 +The other thread can restore the `SyntaxNode` by traversing from the root green node and looking for a node with specified range.
 +You can also use the similar trick to store a `SyntaxNode`.
 +That is, a data structure that holds a `(GreenNode, Range<usize>)` will be `Sync`.
 +However, rust-analyzer goes even further.
 +It treats trees as semi-transient and instead of storing a `GreenNode`, it generally stores just the id of the file from which the tree originated: `(FileId, Range<usize>)`.
 +The `SyntaxNode` is the restored by reparsing the file and traversing it from root.
 +With this trick, rust-analyzer holds only a small amount of trees in memory at the same time, which reduces memory usage.
 +
 +Additionally, only the root `SyntaxNode` owns an `Arc` to the (root) `GreenNode`.
 +All other `SyntaxNode`s point to corresponding `GreenNode`s with a raw pointer.
 +They also point to the parent (and, consequently, to the root) with an owning `Rc`, so this is sound.
 +In other words, one needs *one* arc bump when initiating a traversal.
 +
 +To get rid of allocations, `rowan` takes advantage of `SyntaxNode: !Sync` and uses a thread-local free list of `SyntaxNode`s.
 +In a typical traversal, you only directly hold a few `SyntaxNode`s at a time (and their ancestors indirectly), so a free list proportional to the depth of the tree removes all allocations in a typical case.
 +
 +So, while traversal is not exactly incrementing a pointer, it's still pretty cheap: TLS + rc bump!
 +
 +Traversal also yields (cheap) owned nodes, which improves ergonomics quite a bit.
 +
 +#### Alternative Designs
 +
 +##### Memoized RedNodes
 +
 +C# and Swift follow the design where the red nodes are memoized, which would look roughly like this in Rust:
 +
 +```rust
 +type SyntaxNode = Arc<SyntaxData>;
 +
 +struct SyntaxData {
 +    offset: usize,
 +    parent: Option<SyntaxNode>,
 +    green: Arc<GreenNode>,
 +    children: Vec<OnceCell<SyntaxNode>>,
 +}
 +```
 +
 +This allows using true pointer equality for comparison of identities of `SyntaxNodes`.
 +rust-analyzer used to have this design as well, but we've since switched to cursors.
 +The main problem with memoizing the red nodes is that it more than doubles the memory requirements for fully realized syntax trees.
 +In contrast, cursors generally retain only a path to the root.
 +C# combats increased memory usage by using weak references.
 +
 +### AST
 +
 +`GreenTree`s are untyped and homogeneous, because it makes accommodating error nodes, arbitrary whitespace and comments natural, and because it makes possible to write generic tree traversals.
 +However, when working with a specific node, like a function definition, one would want a strongly typed API.
 +
 +This is what is provided by the AST layer. AST nodes are transparent wrappers over untyped syntax nodes:
 +
 +```rust
 +pub trait AstNode {
 +    fn cast(syntax: SyntaxNode) -> Option<Self>
 +    where
 +        Self: Sized;
 +
 +    fn syntax(&self) -> &SyntaxNode;
 +}
 +```
 +
 +Concrete nodes are generated (there are 117 of them), and look roughly like this:
 +
 +```rust
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct FnDef {
 +    syntax: SyntaxNode,
 +}
 +
 +impl AstNode for FnDef {
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        match kind {
 +            FN => Some(FnDef { syntax }),
 +            _ => None,
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode {
 +        &self.syntax
 +    }
 +}
 +
 +impl FnDef {
 +    pub fn param_list(&self) -> Option<ParamList> {
 +        self.syntax.children().find_map(ParamList::cast)
 +    }
 +    pub fn ret_type(&self) -> Option<RetType> {
 +        self.syntax.children().find_map(RetType::cast)
 +    }
 +    pub fn body(&self) -> Option<BlockExpr> {
 +        self.syntax.children().find_map(BlockExpr::cast)
 +    }
 +    // ...
 +}
 +```
 +
 +Variants like expressions, patterns or items are modeled with `enum`s, which also implement `AstNode`:
 +
 +```rust
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum AssocItem {
 +    FnDef(FnDef),
 +    TypeAliasDef(TypeAliasDef),
 +    ConstDef(ConstDef),
 +}
 +
 +impl AstNode for AssocItem {
 +    ...
 +}
 +```
 +
 +Shared AST substructures are modeled via (object safe) traits:
 +
 +```rust
 +trait HasVisibility: AstNode {
 +    fn visibility(&self) -> Option<Visibility>;
 +}
 +
 +impl HasVisibility for FnDef {
 +    fn visibility(&self) -> Option<Visibility> {
 +        self.syntax.children().find_map(Visibility::cast)
 +    }
 +}
 +```
 +
 +Points of note:
 +
 +* Like `SyntaxNode`s, AST nodes are cheap to clone pointer-sized owned values.
 +* All "fields" are optional, to accommodate incomplete and/or erroneous source code.
 +* It's always possible to go from an ast node to an untyped `SyntaxNode`.
 +* It's possible to go in the opposite direction with a checked cast.
 +* `enum`s allow modeling of arbitrary intersecting subsets of AST types.
 +* Most of rust-analyzer works with the ast layer, with notable exceptions of:
 +  * macro expansion, which needs access to raw tokens and works with `SyntaxNode`s
 +  * some IDE-specific features like syntax highlighting are more conveniently implemented over a homogeneous `SyntaxNode` tree
 +
 +#### Alternative Designs
 +
 +##### Semantic Full AST
 +
 +In IntelliJ the AST layer (dubbed **P**rogram **S**tructure **I**nterface) can have semantics attached, and is usually backed by either syntax tree, indices, or metadata from compiled libraries.
 +The backend for PSI can change dynamically.
 +
 +### Syntax Tree Recap
 +
 +At its core, the syntax tree is a purely functional n-ary tree, which stores text at the leaf nodes and node "kinds" at all nodes.
 +A cursor layer is added on top, which gives owned, cheap to clone nodes with identity semantics, parent links and absolute offsets.
 +An AST layer is added on top, which reifies each node `Kind` as a separate Rust type with the corresponding API.
 +
 +## Parsing
 +
 +The (green) tree is constructed by a DFS "traversal" of the desired tree structure:
 +
 +```rust
 +pub struct GreenNodeBuilder { ... }
 +
 +impl GreenNodeBuilder {
 +    pub fn new() -> GreenNodeBuilder { ... }
 +
 +    pub fn token(&mut self, kind: SyntaxKind, text: &str) { ... }
 +
 +    pub fn start_node(&mut self, kind: SyntaxKind) { ... }
 +    pub fn finish_node(&mut self) { ... }
 +
 +    pub fn finish(self) -> GreenNode { ... }
 +}
 +```
 +
 +The parser, ultimately, needs to invoke the `GreenNodeBuilder`.
 +There are two principal sources of inputs for the parser:
 +  * source text, which contains trivia tokens (whitespace and comments)
 +  * token trees from macros, which lack trivia
 +
 +Additionally, input tokens do not correspond 1-to-1 with output tokens.
 +For example, two consecutive `>` tokens might be glued, by the parser, into a single `>>`.
 +
 +For these reasons, the parser crate defines a callback interfaces for both input tokens and output trees.
 +The explicit glue layer then bridges various gaps.
 +
 +The parser interface looks like this:
 +
 +```rust
 +pub struct Token {
 +    pub kind: SyntaxKind,
 +    pub is_joined_to_next: bool,
 +}
 +
 +pub trait TokenSource {
 +    fn current(&self) -> Token;
 +    fn lookahead_nth(&self, n: usize) -> Token;
 +    fn is_keyword(&self, kw: &str) -> bool;
 +
 +    fn bump(&mut self);
 +}
 +
 +pub trait TreeSink {
 +    fn token(&mut self, kind: SyntaxKind, n_tokens: u8);
 +
 +    fn start_node(&mut self, kind: SyntaxKind);
 +    fn finish_node(&mut self);
 +
 +    fn error(&mut self, error: ParseError);
 +}
 +
 +pub fn parse(
 +    token_source: &mut dyn TokenSource,
 +    tree_sink: &mut dyn TreeSink,
 +) { ... }
 +```
 +
 +Points of note:
 +
 +* The parser and the syntax tree are independent, they live in different crates neither of which depends on the other.
 +* The parser doesn't know anything about textual contents of the tokens, with an isolated hack for checking contextual keywords.
 +* For gluing tokens, the `TreeSink::token` might advance further than one atomic token ahead.
 +
 +### Reporting Syntax Errors
 +
 +Syntax errors are not stored directly in the tree.
 +The primary motivation for this is that syntax tree is not necessary produced by the parser, it may also be assembled manually from pieces (which happens all the time in refactorings).
 +Instead, parser reports errors to an error sink, which stores them in a `Vec`.
 +If possible, errors are not reported during parsing and are postponed for a separate validation step.
 +For example, parser accepts visibility modifiers on trait methods, but then a separate tree traversal flags all such visibilities as erroneous.
 +
 +### Macros
 +
 +The primary difficulty with macros is that individual tokens have identities, which need to be preserved in the syntax tree for hygiene purposes.
 +This is handled by the `TreeSink` layer.
 +Specifically, `TreeSink` constructs the tree in lockstep with draining the original token stream.
 +In the process, it records which tokens of the tree correspond to which tokens of the input, by using text ranges to identify syntax tokens.
 +The end result is that parsing an expanded code yields a syntax tree and a mapping of text-ranges of the tree to original tokens.
 +
 +To deal with precedence in cases like `$expr * 1`, we use special invisible parenthesis, which are explicitly handled by the parser
 +
 +### Whitespace & Comments
 +
 +Parser does not see whitespace nodes.
 +Instead, they are attached to the tree in the `TreeSink` layer.
 +
 +For example, in
 +
 +```rust
 +// non doc comment
 +fn foo() {}
 +```
 +
 +the comment will be (heuristically) made a child of function node.
 +
 +### Incremental Reparse
 +
 +Green trees are cheap to modify, so incremental reparse works by patching a previous tree, without maintaining any additional state.
 +The reparse is based on heuristic: we try to contain a change to a single `{}` block, and reparse only this block.
 +To do this, we maintain the invariant that, even for invalid code, curly braces are always paired correctly.
 +
 +In practice, incremental reparsing doesn't actually matter much for IDE use-cases, parsing from scratch seems to be fast enough.
 +
 +### Parsing Algorithm
 +
 +We use a boring hand-crafted recursive descent + pratt combination, with a special effort of continuing the parsing if an error is detected.
 +
 +### Parser Recap
 +
 +Parser itself defines traits for token sequence input and syntax tree output.
 +It doesn't care about where the tokens come from, and how the resulting syntax tree looks like.
index 9bd3b6a692b1a7514263ca06c4b39e97281f42df,0000000000000000000000000000000000000000..c30838e5f5e1e09b10ac34ce19c718d195f67a07
mode 100644,000000..100644
--- /dev/null
@@@ -1,874 -1,0 +1,885 @@@
- `rust-analyzer` is available in `rustup`, but only in the nightly toolchain:
 += User Manual
 +:toc: preamble
 +:sectanchors:
 +:page-layout: post
 +:icons: font
 +:source-highlighter: rouge
 +:experimental:
 +
 +////
 +IMPORTANT: the master copy of this document lives in the https://github.com/rust-lang/rust-analyzer repository
 +////
 +
 +At its core, rust-analyzer is a *library* for semantic analysis of Rust code as it changes over time.
 +This manual focuses on a specific usage of the library -- running it as part of a server that implements the
 +https://microsoft.github.io/language-server-protocol/[Language Server Protocol] (LSP).
 +The LSP allows various code editors, like VS Code, Emacs or Vim, to implement semantic features like completion or goto definition by talking to an external language server process.
 +
 +[TIP]
 +====
 +[.lead]
 +To improve this document, send a pull request: +
 +https://github.com/rust-lang/rust-analyzer/blob/master/docs/user/manual.adoc[https://github.com/rust-analyzer/.../manual.adoc]
 +
 +The manual is written in https://asciidoc.org[AsciiDoc] and includes some extra files which are generated from the source code. Run `cargo test` and `cargo test -p xtask` to create these and then `asciidoctor manual.adoc` to create an HTML copy.
 +====
 +
 +If you have questions about using rust-analyzer, please ask them in the https://users.rust-lang.org/c/ide/14["`IDEs and Editors`"] topic of Rust users forum.
 +
 +== Installation
 +
 +In theory, one should be able to just install the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>> and have it automatically work with any editor.
 +We are not there yet, so some editor specific setup is required.
 +
 +Additionally, rust-analyzer needs the sources of the standard library.
 +If the source code is not present, rust-analyzer will attempt to install it automatically.
 +
 +To add the sources manually, run the following command:
 +
 +```bash
 +$ rustup component add rust-src
 +```
 +
 +=== Toolchain
 +
 +Only the latest stable standard library source is officially supported for use with rust-analyzer.
 +If you are using an older toolchain or have an override set, rust-analyzer may fail to understand the Rust source.
 +You will either need to update your toolchain or use an older version of rust-analyzer that is compatible with your toolchain.
 +
 +If you are using an override in your project, you can still force rust-analyzer to use the stable toolchain via the environment variable `RUSTUP_TOOLCHAIN`.
 +For example, with VS Code or coc-rust-analyzer:
 +
 +[source,json]
 +----
 +{ "rust-analyzer.server.extraEnv": { "RUSTUP_TOOLCHAIN": "stable" } }
 +----
 +
 +=== VS Code
 +
 +This is the best supported editor at the moment.
 +The rust-analyzer plugin for VS Code is maintained
 +https://github.com/rust-lang/rust-analyzer/tree/master/editors/code[in tree].
 +
 +You can install the latest release of the plugin from
 +https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer[the marketplace].
 +
 +Note that the plugin may cause conflicts with the
 +https://marketplace.visualstudio.com/items?itemName=rust-lang.rust[official Rust plugin].
 +It is recommended to disable the Rust plugin when using the rust-analyzer extension.
 +
 +By default, the plugin will prompt you to download the matching version of the server as well:
 +
 +image::https://user-images.githubusercontent.com/9021944/75067008-17502500-54ba-11ea-835a-f92aac50e866.png[]
 +
 +[NOTE]
 +====
 +To disable this notification put the following to `settings.json`
 +
 +[source,json]
 +----
 +{ "rust-analyzer.updates.askBeforeDownload": false }
 +----
 +====
 +
 +The server binary is stored in the extension install directory, which starts with `rust-lang.rust-analyzer-` and is located under:
 +
 +* Linux: `~/.vscode/extensions`
 +* Linux (Remote, such as WSL): `~/.vscode-server/extensions`
 +* macOS: `~/.vscode/extensions`
 +* Windows: `%USERPROFILE%\.vscode\extensions`
 +
 +As an exception, on NixOS, the extension makes a copy of the server and stores it under `~/.config/Code/User/globalStorage/rust-lang.rust-analyzer`.
 +
 +Note that we only support the two most recent versions of VS Code.
 +
 +==== Updates
 +
 +The extension will be updated automatically as new versions become available.
 +It will ask your permission to download the matching language server version binary if needed.
 +
 +===== Nightly
 +
 +We ship nightly releases for VS Code.
 +To help us out by testing the newest code, you can enable pre-release versions in the Code extension page.
 +
 +==== Manual installation
 +
 +Alternatively, download a VSIX corresponding to your platform from the
 +https://github.com/rust-lang/rust-analyzer/releases[releases] page.
 +
 +Install the extension with the `Extensions: Install from VSIX` command within VS Code, or from the command line via:
 +[source]
 +----
 +$ code --install-extension /path/to/rust-analyzer.vsix
 +----
 +
 +If you are running an unsupported platform, you can install `rust-analyzer-no-server.vsix` and compile or obtain a server binary.
 +Copy the server anywhere, then add the path to your settings.json, for example:
 +[source,json]
 +----
 +{ "rust-analyzer.server.path": "~/.local/bin/rust-analyzer-linux" }
 +----
 +
 +==== Building From Source
 +
 +Both the server and the Code plugin can be installed from source:
 +
 +[source]
 +----
 +$ git clone https://github.com/rust-lang/rust-analyzer.git && cd rust-analyzer
 +$ cargo xtask install
 +----
 +
 +You'll need Cargo, nodejs (matching a supported version of VS Code) and npm for this.
 +
 +Note that installing via `xtask install` does not work for VS Code Remote, instead you'll need to install the `.vsix` manually.
 +
 +If you're not using Code, you can compile and install only the LSP server:
 +
 +[source]
 +----
 +$ cargo xtask install --server
 +----
 +
 +=== rust-analyzer Language Server Binary
 +
 +Other editors generally require the `rust-analyzer` binary to be in `$PATH`.
 +You can download pre-built binaries from the https://github.com/rust-lang/rust-analyzer/releases[releases] page.
 +You will need to uncompress and rename the binary for your platform, e.g. from `rust-analyzer-aarch64-apple-darwin.gz` on Mac OS to `rust-analyzer`, make it executable, then move it into a directory in your `$PATH`.
 +
 +On Linux to install the `rust-analyzer` binary into `~/.local/bin`, these commands should work:
 +
 +[source,bash]
 +----
 +$ mkdir -p ~/.local/bin
 +$ curl -L https://github.com/rust-lang/rust-analyzer/releases/latest/download/rust-analyzer-x86_64-unknown-linux-gnu.gz | gunzip -c - > ~/.local/bin/rust-analyzer
 +$ chmod +x ~/.local/bin/rust-analyzer
 +----
 +
 +Make sure that `~/.local/bin` is listed in the `$PATH` variable and use the appropriate URL if you're not on a `x86-64` system.
 +
 +You don't have to use `~/.local/bin`, any other path like `~/.cargo/bin` or `/usr/local/bin` will work just as well.
 +
 +Alternatively, you can install it from source using the command below.
 +You'll need the latest stable version of the Rust toolchain.
 +
 +[source,bash]
 +----
 +$ git clone https://github.com/rust-lang/rust-analyzer.git && cd rust-analyzer
 +$ cargo xtask install --server
 +----
 +
 +If your editor can't find the binary even though the binary is on your `$PATH`, the likely explanation is that it doesn't see the same `$PATH` as the shell, see https://github.com/rust-lang/rust-analyzer/issues/1811[this issue].
 +On Unix, running the editor from a shell or changing the `.desktop` file to set the environment should help.
 +
 +==== `rustup`
 +
- $ rustup +nightly component add rust-analyzer-preview
++`rust-analyzer` is available in `rustup`:
 +
 +[source,bash]
 +----
- However, in contrast to `component add clippy` or `component add rustfmt`, this does not actually place a `rust-analyzer` binary in `~/.cargo/bin`, see https://github.com/rust-lang/rustup/issues/2411[this issue].
++$ rustup component add rust-analyzer
 +----
 +
++However, in contrast to `component add clippy` or `component add rustfmt`, this does not actually place a `rust-analyzer` binary in `~/.cargo/bin`, see https://github.com/rust-lang/rustup/issues/2411[this issue]. You can find the path to the binary using:
++[source,bash]
++----
++$ rustup which --toolchain stable rust-analyzer
++----
++You can link to there from `~/.cargo/bin` or configure your editor to use the full path.
++
++Alternatively you might be able to configure your editor to start `rust-analyzer` using the command:
++[source,bash]
++----
++$ rustup run stable rust-analyzer
++----
 +
 +==== Arch Linux
 +
 +The `rust-analyzer` binary can be installed from the repos or AUR (Arch User Repository):
 +
 +- https://www.archlinux.org/packages/community/x86_64/rust-analyzer/[`rust-analyzer`] (built from latest tagged source)
 +- https://aur.archlinux.org/packages/rust-analyzer-git[`rust-analyzer-git`] (latest Git version)
 +
 +Install it with pacman, for example:
 +
 +[source,bash]
 +----
 +$ pacman -S rust-analyzer
 +----
 +
 +==== Gentoo Linux
 +
 +`rust-analyzer` is available in the GURU repository:
 +
 +- https://gitweb.gentoo.org/repo/proj/guru.git/tree/dev-util/rust-analyzer?id=9895cea62602cfe599bd48e0fb02127411ca6e81[`dev-util/rust-analyzer`] builds from source
 +- https://gitweb.gentoo.org/repo/proj/guru.git/tree/dev-util/rust-analyzer-bin?id=9895cea62602cfe599bd48e0fb02127411ca6e81[`dev-util/rust-analyzer-bin`] installs an official binary release
 +
 +If not already, GURU must be enabled (e.g. using `app-eselect/eselect-repository`) and sync'd before running `emerge`:
 +
 +[source,bash]
 +----
 +$ eselect repository enable guru && emaint sync -r guru
 +$ emerge rust-analyzer-bin
 +----
 +
 +==== macOS
 +
 +The `rust-analyzer` binary can be installed via https://brew.sh/[Homebrew].
 +
 +[source,bash]
 +----
 +$ brew install rust-analyzer
 +----
 +
 +=== Emacs
 +
 +Note this excellent https://robert.kra.hn/posts/2021-02-07_rust-with-emacs/[guide] from https://github.com/rksm[@rksm].
 +
 +Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>.
 +
 +Emacs support is maintained as part of the https://github.com/emacs-lsp/lsp-mode[Emacs-LSP] package in https://github.com/emacs-lsp/lsp-mode/blob/master/lsp-rust.el[lsp-rust.el].
 +
 +1. Install the most recent version of `emacs-lsp` package by following the https://github.com/emacs-lsp/lsp-mode[Emacs-LSP instructions].
 +2. Set `lsp-rust-server` to `'rust-analyzer`.
 +3. Run `lsp` in a Rust buffer.
 +4. (Optionally) bind commands like `lsp-rust-analyzer-join-lines`, `lsp-extend-selection` and `lsp-rust-analyzer-expand-macro` to keys.
 +
 +=== Vim/NeoVim
 +
 +Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>.
 +Not needed if the extension can install/update it on its own, coc-rust-analyzer is one example.
 +
 +There are several LSP client implementations for vim or neovim:
 +
 +==== coc-rust-analyzer
 +
 +1. Install coc.nvim by following the instructions at
 +   https://github.com/neoclide/coc.nvim[coc.nvim]
 +   (Node.js required)
 +2. Run `:CocInstall coc-rust-analyzer` to install
 +   https://github.com/fannheyward/coc-rust-analyzer[coc-rust-analyzer],
 +   this extension implements _most_ of the features supported in the VSCode extension:
 +   * automatically install and upgrade stable/nightly releases
 +   * same configurations as VSCode extension, `rust-analyzer.server.path`, `rust-analyzer.cargo.features` etc.
 +   * same commands too, `rust-analyzer.analyzerStatus`, `rust-analyzer.ssr` etc.
 +   * inlay hints for variables and method chaining, _Neovim Only_
 +
 +Note: for code actions, use `coc-codeaction-cursor` and `coc-codeaction-selected`; `coc-codeaction` and `coc-codeaction-line` are unlikely to be useful.
 +
 +==== LanguageClient-neovim
 +
 +1. Install LanguageClient-neovim by following the instructions
 +   https://github.com/autozimu/LanguageClient-neovim[here]
 +   * The GitHub project wiki has extra tips on configuration
 +
 +2. Configure by adding this to your vim/neovim config file (replacing the existing Rust-specific line if it exists):
 ++
 +[source,vim]
 +----
 +let g:LanguageClient_serverCommands = {
 +\ 'rust': ['rust-analyzer'],
 +\ }
 +----
 +
 +==== YouCompleteMe
 +
 +Install YouCompleteMe by following the instructions
 +  https://github.com/ycm-core/YouCompleteMe#installation[here].
 +
 +rust-analyzer is the default in ycm, it should work out of the box.
 +
 +==== ALE
 +
 +To use the LSP server in https://github.com/dense-analysis/ale[ale]:
 +
 +[source,vim]
 +----
 +let g:ale_linters = {'rust': ['analyzer']}
 +----
 +
 +==== nvim-lsp
 +
 +NeoVim 0.5 has built-in language server support.
 +For a quick start configuration of rust-analyzer, use https://github.com/neovim/nvim-lspconfig#rust_analyzer[neovim/nvim-lspconfig].
 +Once `neovim/nvim-lspconfig` is installed, use `+lua require'lspconfig'.rust_analyzer.setup({})+` in your `init.vim`.
 +
 +You can also pass LSP settings to the server:
 +
 +[source,vim]
 +----
 +lua << EOF
 +local nvim_lsp = require'lspconfig'
 +
 +local on_attach = function(client)
 +    require'completion'.on_attach(client)
 +end
 +
 +nvim_lsp.rust_analyzer.setup({
 +    on_attach=on_attach,
 +    settings = {
 +        ["rust-analyzer"] = {
 +            imports = {
 +                granularity = {
 +                    group = "module",
 +                },
 +                prefix = "self",
 +            },
 +            cargo = {
 +                buildScripts = {
 +                    enable = true,
 +                },
 +            },
 +            procMacro = {
 +                enable = true
 +            },
 +        }
 +    }
 +})
 +EOF
 +----
 +
 +See https://sharksforarms.dev/posts/neovim-rust/ for more tips on getting started.
 +
 +Check out https://github.com/simrat39/rust-tools.nvim for a batteries included rust-analyzer setup for neovim.
 +
 +==== vim-lsp
 +
 +vim-lsp is installed by following https://github.com/prabirshrestha/vim-lsp[the plugin instructions].
 +It can be as simple as adding this line to your `.vimrc`:
 +
 +[source,vim]
 +----
 +Plug 'prabirshrestha/vim-lsp'
 +----
 +
 +Next you need to register the `rust-analyzer` binary.
 +If it is available in `$PATH`, you may want to add this to your `.vimrc`:
 +
 +[source,vim]
 +----
 +if executable('rust-analyzer')
 +  au User lsp_setup call lsp#register_server({
 +        \   'name': 'Rust Language Server',
 +        \   'cmd': {server_info->['rust-analyzer']},
 +        \   'whitelist': ['rust'],
 +        \ })
 +endif
 +----
 +
 +There is no dedicated UI for the server configuration, so you would need to send any options as a value of the `initialization_options` field, as described in the <<_configuration,Configuration>> section.
 +Here is an example of how to enable the proc-macro support:
 +
 +[source,vim]
 +----
 +if executable('rust-analyzer')
 +  au User lsp_setup call lsp#register_server({
 +        \   'name': 'Rust Language Server',
 +        \   'cmd': {server_info->['rust-analyzer']},
 +        \   'whitelist': ['rust'],
 +        \   'initialization_options': {
 +        \     'cargo': {
 +        \       'buildScripts': {
 +        \         'enable': v:true,
 +        \       },
 +        \     },
 +        \     'procMacro': {
 +        \       'enable': v:true,
 +        \     },
 +        \   },
 +        \ })
 +endif
 +----
 +
 +=== Sublime Text
 +
 +==== Sublime Text 4:
 +* Follow the instructions in link:https://github.com/sublimelsp/LSP-rust-analyzer[LSP-rust-analyzer].
 +
 +NOTE: Install link:https://packagecontrol.io/packages/LSP-file-watcher-chokidar[LSP-file-watcher-chokidar] to enable file watching (`workspace/didChangeWatchedFiles`).
 +
 +==== Sublime Text 3:
 +* Install the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>.
 +* Install the link:https://packagecontrol.io/packages/LSP[LSP package].
 +* From the command palette, run `LSP: Enable Language Server Globally` and select `rust-analyzer`.
 +
 +If it worked, you should see "rust-analyzer, Line X, Column Y" on the left side of the status bar, and after waiting a bit, functionalities like tooltips on hovering over variables should become available.
 +
 +If you get an error saying `No such file or directory: 'rust-analyzer'`, see the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>> section on installing the language server binary.
 +
 +=== GNOME Builder
 +
 +GNOME Builder 3.37.1 and newer has native `rust-analyzer` support.
 +If the LSP binary is not available, GNOME Builder can install it when opening a Rust file.
 +
 +
 +=== Eclipse IDE
 +
 +Support for Rust development in the Eclipse IDE is provided by link:https://github.com/eclipse/corrosion[Eclipse Corrosion].
 +If available in PATH or in some standard location, `rust-analyzer` is detected and powers editing of Rust files without further configuration.
 +If `rust-analyzer` is not detected, Corrosion will prompt you for configuration of your Rust toolchain and language server with a link to the __Window > Preferences > Rust__ preference page; from here a button allows to download and configure `rust-analyzer`, but you can also reference another installation.
 +You'll need to close and reopen all .rs and Cargo files, or to restart the IDE, for this change to take effect.
 +
 +=== Kate Text Editor
 +
 +Support for the language server protocol is built into Kate through the LSP plugin, which is included by default.
 +It is preconfigured to use rust-analyzer for Rust sources since Kate 21.12.
 +
 +Earlier versions allow you to use rust-analyzer through a simple settings change.
 +In the LSP Client settings of Kate, copy the content of the third tab "default parameters" to the second tab "server configuration".
 +Then in the configuration replace:
 +[source,json]
 +----
 +        "rust": {
 +            "command": ["rls"],
 +            "rootIndicationFileNames": ["Cargo.lock", "Cargo.toml"],
 +            "url": "https://github.com/rust-lang/rls",
 +            "highlightingModeRegex": "^Rust$"
 +        },
 +----
 +With
 +[source,json]
 +----
 +        "rust": {
 +            "command": ["rust-analyzer"],
 +            "rootIndicationFileNames": ["Cargo.lock", "Cargo.toml"],
 +            "url": "https://github.com/rust-lang/rust-analyzer",
 +            "highlightingModeRegex": "^Rust$"
 +        },
 +----
 +Then click on apply, and restart the LSP server for your rust project.
 +
 +=== juCi++
 +
 +https://gitlab.com/cppit/jucipp[juCi++] has built-in support for the language server protocol, and since version 1.7.0 offers installation of both Rust and rust-analyzer when opening a Rust file.
 +
 +=== Kakoune
 +
 +https://kakoune.org/[Kakoune] supports LSP with the help of https://github.com/kak-lsp/kak-lsp[`kak-lsp`].
 +Follow the https://github.com/kak-lsp/kak-lsp#installation[instructions] to install `kak-lsp`.
 +To configure `kak-lsp`, refer to the https://github.com/kak-lsp/kak-lsp#configuring-kak-lsp[configuration section] which is basically about copying the https://github.com/kak-lsp/kak-lsp/blob/master/kak-lsp.toml[configuration file] in the right place (latest versions should use `rust-analyzer` by default).
 +
 +Finally, you need to configure Kakoune to talk to `kak-lsp` (see https://github.com/kak-lsp/kak-lsp#usage[Usage section]).
 +A basic configuration will only get you LSP but you can also activate inlay diagnostics and auto-formatting on save.
 +The following might help you get all of this.
 +
 +[source,txt]
 +----
 +eval %sh{kak-lsp --kakoune -s $kak_session}  # Not needed if you load it with plug.kak.
 +hook global WinSetOption filetype=rust %{
 +    # Enable LSP
 +    lsp-enable-window
 +
 +    # Auto-formatting on save
 +    hook window BufWritePre .* lsp-formatting-sync
 +
 +    # Configure inlay hints (only on save)
 +    hook window -group rust-inlay-hints BufWritePost .* rust-analyzer-inlay-hints
 +    hook -once -always window WinSetOption filetype=.* %{
 +        remove-hooks window rust-inlay-hints
 +    }
 +}
 +----
 +
 +=== Helix
 +
 +https://docs.helix-editor.com/[Helix] supports LSP by default.
 +However, it won't install `rust-analyzer` automatically.
 +You can follow instructions for installing <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>.
 +
 +== Troubleshooting
 +
 +Start with looking at the rust-analyzer version.
 +Try **rust-analyzer: Show RA Version** in VS Code (using **Command Palette** feature typically activated by Ctrl+Shift+P) or `rust-analyzer --version` in the command line.
 +If the date is more than a week ago, it's better to update rust-analyzer version.
 +
 +The next thing to check would be panic messages in rust-analyzer's log.
 +Log messages are printed to stderr, in VS Code you can see then in the `Output > Rust Analyzer Language Server` tab of the panel.
 +To see more logs, set the `RA_LOG=info` environment variable, this can be done either by setting the environment variable manually or by using `rust-analyzer.server.extraEnv`, note that both of these approaches require the server to be restarted.
 +
 +To fully capture LSP messages between the editor and the server, set `"rust-analyzer.trace.server": "verbose"` config and check
 +`Output > Rust Analyzer Language Server Trace`.
 +
 +The root cause for many "`nothing works`" problems is that rust-analyzer fails to understand the project structure.
 +To debug that, first note the `rust-analyzer` section in the status bar.
 +If it has an error icon and red, that's the problem (hover will have somewhat helpful error message).
 +**rust-analyzer: Status** prints dependency information for the current file.
 +Finally, `RA_LOG=project_model=debug` enables verbose logs during project loading.
 +
 +If rust-analyzer outright crashes, try running `rust-analyzer analysis-stats /path/to/project/directory/` on the command line.
 +This command type checks the whole project in batch mode bypassing LSP machinery.
 +
 +When filing issues, it is useful (but not necessary) to try to minimize examples.
 +An ideal bug reproduction looks like this:
 +
 +```bash
 +$ git clone https://github.com/username/repo.git && cd repo && git switch --detach commit-hash
 +$ rust-analyzer --version
 +rust-analyzer dd12184e4 2021-05-08 dev
 +$ rust-analyzer analysis-stats .
 +💀 💀 💀
 +```
 +
 +It is especially useful when the `repo` doesn't use external crates or the standard library.
 +
 +If you want to go as far as to modify the source code to debug the problem, be sure to take a look at the
 +https://github.com/rust-lang/rust-analyzer/tree/master/docs/dev[dev docs]!
 +
 +== Configuration
 +
 +**Source:** https://github.com/rust-lang/rust-analyzer/blob/master/crates/rust-analyzer/src/config.rs[config.rs]
 +
 +The <<_installation,Installation>> section contains details on configuration for some of the editors.
 +In general `rust-analyzer` is configured via LSP messages, which means that it's up to the editor to decide on the exact format and location of configuration files.
 +
 +Some clients, such as <<vs-code,VS Code>> or <<coc-rust-analyzer,COC plugin in Vim>> provide `rust-analyzer` specific configuration UIs. Others may require you to know a bit more about the interaction with `rust-analyzer`.
 +
 +For the later category, it might help to know that the initial configuration is specified as a value of the `initializationOptions` field of the https://microsoft.github.io/language-server-protocol/specifications/specification-current/#initialize[`InitializeParams` message, in the LSP protocol].
 +The spec says that the field type is `any?`, but `rust-analyzer` is looking for a JSON object that is constructed using settings from the list below.
 +Name of the setting, ignoring the `rust-analyzer.` prefix, is used as a path, and value of the setting becomes the JSON property value.
 +
 +For example, a very common configuration is to enable proc-macro support, can be achieved by sending this JSON:
 +
 +[source,json]
 +----
 +{
 +  "cargo": {
 +    "buildScripts": {
 +      "enable": true,
 +    },
 +  },
 +  "procMacro": {
 +    "enable": true,
 +  }
 +}
 +----
 +
 +Please consult your editor's documentation to learn more about how to configure https://microsoft.github.io/language-server-protocol/[LSP servers].
 +
 +To verify which configuration is actually used by `rust-analyzer`, set `RA_LOG` environment variable to `rust_analyzer=info` and look for config-related messages.
 +Logs should show both the JSON that `rust-analyzer` sees as well as the updated config.
 +
 +This is the list of config options `rust-analyzer` supports:
 +
 +include::./generated_config.adoc[]
 +
 +== Non-Cargo Based Projects
 +
 +rust-analyzer does not require Cargo.
 +However, if you use some other build system, you'll have to describe the structure of your project for rust-analyzer in the `rust-project.json` format:
 +
 +[source,TypeScript]
 +----
 +interface JsonProject {
 +    /// Path to the directory with *source code* of
 +    /// sysroot crates.
 +    ///
 +    /// It should point to the directory where std,
 +    /// core, and friends can be found:
 +    ///
 +    /// https://github.com/rust-lang/rust/tree/master/library.
 +    ///
 +    /// If provided, rust-analyzer automatically adds
 +    /// dependencies on sysroot crates. Conversely,
 +    /// if you omit this path, you can specify sysroot
 +    /// dependencies yourself and, for example, have
 +    /// several different "sysroots" in one graph of
 +    /// crates.
 +    sysroot_src?: string;
 +    /// The set of crates comprising the current
 +    /// project. Must include all transitive
 +    /// dependencies as well as sysroot crate (libstd,
 +    /// libcore and such).
 +    crates: Crate[];
 +}
 +
 +interface Crate {
 +    /// Optional crate name used for display purposes,
 +    /// without affecting semantics. See the `deps`
 +    /// key for semantically-significant crate names.
 +    display_name?: string;
 +    /// Path to the root module of the crate.
 +    root_module: string;
 +    /// Edition of the crate.
 +    edition: "2015" | "2018" | "2021";
 +    /// Dependencies
 +    deps: Dep[];
 +    /// Should this crate be treated as a member of
 +    /// current "workspace".
 +    ///
 +    /// By default, inferred from the `root_module`
 +    /// (members are the crates which reside inside
 +    /// the directory opened in the editor).
 +    ///
 +    /// Set this to `false` for things like standard
 +    /// library and 3rd party crates to enable
 +    /// performance optimizations (rust-analyzer
 +    /// assumes that non-member crates don't change).
 +    is_workspace_member?: boolean;
 +    /// Optionally specify the (super)set of `.rs`
 +    /// files comprising this crate.
 +    ///
 +    /// By default, rust-analyzer assumes that only
 +    /// files under `root_module.parent` can belong
 +    /// to a crate. `include_dirs` are included
 +    /// recursively, unless a subdirectory is in
 +    /// `exclude_dirs`.
 +    ///
 +    /// Different crates can share the same `source`.
 +    ///
 +    /// If two crates share an `.rs` file in common,
 +    /// they *must* have the same `source`.
 +    /// rust-analyzer assumes that files from one
 +    /// source can't refer to files in another source.
 +    source?: {
 +        include_dirs: string[],
 +        exclude_dirs: string[],
 +    },
 +    /// The set of cfgs activated for a given crate, like
 +    /// `["unix", "feature=\"foo\"", "feature=\"bar\""]`.
 +    cfg: string[];
 +    /// Target triple for this Crate.
 +    ///
 +    /// Used when running `rustc --print cfg`
 +    /// to get target-specific cfgs.
 +    target?: string;
 +    /// Environment variables, used for
 +    /// the `env!` macro
 +    env: { [key: string]: string; },
 +
 +    /// Whether the crate is a proc-macro crate.
 +    is_proc_macro: boolean;
 +    /// For proc-macro crates, path to compiled
 +    /// proc-macro (.so file).
 +    proc_macro_dylib_path?: string;
 +}
 +
 +interface Dep {
 +    /// Index of a crate in the `crates` array.
 +    crate: number,
 +    /// Name as should appear in the (implicit)
 +    /// `extern crate name` declaration.
 +    name: string,
 +}
 +----
 +
 +This format is provisional and subject to change.
 +Specifically, the `roots` setup will be different eventually.
 +
 +There are three ways to feed `rust-project.json` to rust-analyzer:
 +
 +* Place `rust-project.json` file at the root of the project, and rust-analyzer will discover it.
 +* Specify `"rust-analyzer.linkedProjects": [ "path/to/rust-project.json" ]` in the settings (and make sure that your LSP client sends settings as a part of initialize request).
 +* Specify `"rust-analyzer.linkedProjects": [ { "roots": [...], "crates": [...] }]` inline.
 +
 +Relative paths are interpreted relative to `rust-project.json` file location or (for inline JSON) relative to `rootUri`.
 +
 +See https://github.com/rust-analyzer/rust-project.json-example for a small example.
 +
 +You can set the `RA_LOG` environment variable to `rust_analyzer=info` to inspect how rust-analyzer handles config and project loading.
 +
 +Note that calls to `cargo check` are disabled when using `rust-project.json` by default, so compilation errors and warnings will no longer be sent to your LSP client. To enable these compilation errors you will need to specify explicitly what command rust-analyzer should run to perform the checks using the `checkOnSave.overrideCommand` configuration. As an example, the following configuration explicitly sets `cargo check` as the `checkOnSave` command.
 +
 +[source,json]
 +----
 +{ "rust-analyzer.checkOnSave.overrideCommand": ["cargo", "check", "--message-format=json"] }
 +----
 +
 +The `checkOnSave.overrideCommand` requires the command specified to output json error messages for rust-analyzer to consume. The `--message-format=json` flag does this for `cargo check` so whichever command you use must also output errors in this format. See the <<Configuration>> section for more information.
 +
 +== Security
 +
 +At the moment, rust-analyzer assumes that all code is trusted.
 +Here is a **non-exhaustive** list of ways to make rust-analyzer execute arbitrary code:
 +
 +* proc macros and build scripts are executed by default
 +* `.cargo/config` can override `rustc` with an arbitrary executable
 +* `rust-toolchain.toml` can override `rustc` with an arbitrary executable
 +* VS Code plugin reads configuration from project directory, and that can be used to override paths to various executables, like `rustfmt` or `rust-analyzer` itself.
 +* rust-analyzer's syntax trees library uses a lot of `unsafe` and hasn't been properly audited for memory safety.
 +
 +== Privacy
 +
 +The LSP server performs no network access in itself, but runs `cargo metadata` which will update or download the crate registry and the source code of the project dependencies.
 +If enabled (the default), build scripts and procedural macros can do anything.
 +
 +The Code extension does not access the network.
 +
 +Any other editor plugins are not under the control of the `rust-analyzer` developers. For any privacy concerns, you should check with their respective developers.
 +
 +For `rust-analyzer` developers, `cargo xtask release` uses the GitHub API to put together the release notes.
 +
 +== Features
 +
 +include::./generated_features.adoc[]
 +
 +== Assists (Code Actions)
 +
 +Assists, or code actions, are small local refactorings, available in a particular context.
 +They are usually triggered by a shortcut or by clicking a light bulb icon in the editor.
 +Cursor position or selection is signified by `┃` character.
 +
 +include::./generated_assists.adoc[]
 +
 +== Diagnostics
 +
 +While most errors and warnings provided by rust-analyzer come from the `cargo check` integration, there's a growing number of diagnostics implemented using rust-analyzer's own analysis.
 +Some of these diagnostics don't respect `\#[allow]` or `\#[deny]` attributes yet, but can be turned off using the `rust-analyzer.diagnostics.enable`, `rust-analyzer.diagnostics.experimental.enable` or `rust-analyzer.diagnostics.disabled` settings.
 +
 +include::./generated_diagnostic.adoc[]
 +
 +== Editor Features
 +=== VS Code
 +
 +==== Color configurations
 +
 +It is possible to change the foreground/background color and font family/size of inlay hints.
 +Just add this to your `settings.json`:
 +
 +[source,jsonc]
 +----
 +{
 +  "editor.inlayHints.fontFamily": "Courier New",
 +  "editor.inlayHints.fontSize": 11,
 +
 +  "workbench.colorCustomizations": {
 +    // Name of the theme you are currently using
 +    "[Default Dark+]": {
 +      "editorInlayHint.foreground": "#868686f0",
 +      "editorInlayHint.background": "#3d3d3d48",
 +
 +      // Overrides for specific kinds of inlay hints
 +      "editorInlayHint.typeForeground": "#fdb6fdf0",
 +      "editorInlayHint.parameterForeground": "#fdb6fdf0",
 +    }
 +  }
 +}
 +----
 +
 +==== Semantic style customizations
 +
 +You can customize the look of different semantic elements in the source code.
 +For example, mutable bindings are underlined by default and you can override this behavior by adding the following section to your `settings.json`:
 +
 +[source,jsonc]
 +----
 +{
 +  "editor.semanticTokenColorCustomizations": {
 +    "rules": {
 +      "*.mutable": {
 +        "fontStyle": "", // underline is the default
 +      },
 +    }
 +  },
 +}
 +----
 +
 +Most themes doesn't support styling unsafe operations differently yet. You can fix this by adding overrides for the rules `operator.unsafe`, `function.unsafe`, and `method.unsafe`:
 +
 +[source,jsonc]
 +----
 +{
 +   "editor.semanticTokenColorCustomizations": {
 +         "rules": {
 +             "operator.unsafe": "#ff6600",
 +             "function.unsafe": "#ff6600",
 +             "method.unsafe": "#ff6600"
 +         }
 +    },
 +}
 +----
 +
 +In addition to the top-level rules you can specify overrides for specific themes. For example, if you wanted to use a darker text color on a specific light theme, you might write:
 +
 +[source,jsonc]
 +----
 +{
 +   "editor.semanticTokenColorCustomizations": {
 +         "rules": {
 +             "operator.unsafe": "#ff6600"
 +         },
 +         "[Ayu Light]": {
 +            "rules": {
 +               "operator.unsafe": "#572300"
 +            }
 +         }
 +    },
 +}
 +----
 +
 +Make sure you include the brackets around the theme name. For example, use `"[Ayu Light]"` to customize the theme Ayu Light.
 +
 +==== Special `when` clause context for keybindings.
 +You may use `inRustProject` context to configure keybindings for rust projects only.
 +For example:
 +
 +[source,json]
 +----
 +{
 +  "key": "ctrl+alt+d",
 +  "command": "rust-analyzer.openDocs",
 +  "when": "inRustProject"
 +}
 +----
 +More about `when` clause contexts https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts[here].
 +
 +==== Setting runnable environment variables
 +You can use "rust-analyzer.runnableEnv" setting to define runnable environment-specific substitution variables.
 +The simplest way for all runnables in a bunch:
 +```jsonc
 +"rust-analyzer.runnableEnv": {
 +    "RUN_SLOW_TESTS": "1"
 +}
 +```
 +
 +Or it is possible to specify vars more granularly:
 +```jsonc
 +"rust-analyzer.runnableEnv": [
 +    {
 +        // "mask": null, // null mask means that this rule will be applied for all runnables
 +        env: {
 +             "APP_ID": "1",
 +             "APP_DATA": "asdf"
 +        }
 +    },
 +    {
 +        "mask": "test_name",
 +        "env": {
 +             "APP_ID": "2", // overwrites only APP_ID
 +        }
 +    }
 +]
 +```
 +
 +You can use any valid regular expression as a mask.
 +Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively.
 +
 +==== Compiler feedback from external commands
 +
 +Instead of relying on the built-in `cargo check`, you can configure Code to run a command in the background and use the `$rustc-watch` problem matcher to generate inline error markers from its output.
 +
 +To do this you need to create a new https://code.visualstudio.com/docs/editor/tasks[VS Code Task] and set `rust-analyzer.checkOnSave.enable: false` in preferences.
 +
 +For example, if you want to run https://crates.io/crates/cargo-watch[`cargo watch`] instead, you might add the following to `.vscode/tasks.json`:
 +
 +```json
 +{
 +    "label": "Watch",
 +    "group": "build",
 +    "type": "shell",
 +    "command": "cargo watch",
 +    "problemMatcher": "$rustc-watch",
 +    "isBackground": true
 +}
 +```
 +
 +==== Live Share
 +
 +VS Code Live Share has partial support for rust-analyzer.
 +
 +Live Share _requires_ the official Microsoft build of VS Code, OSS builds will not work correctly.
 +
 +The host's rust-analyzer instance will be shared with all guests joining the session.
 +The guests do not have to have the rust-analyzer extension installed for this to work.
 +
 +If you are joining a Live Share session and _do_ have rust-analyzer installed locally, commands from the command palette will not work correctly since they will attempt to communicate with the local server.
index a9c0f079b3da9350eeb3624fbed5247b465da7d9,0000000000000000000000000000000000000000..15846a5e8645e67fd6d2888a81b4b1ca862efefc
mode 100644,000000..100644
--- /dev/null
@@@ -1,300 -1,0 +1,314 @@@
-         return this.get<RunnableEnvCfg>("runnableEnv");
 +import path = require("path");
 +import * as vscode from "vscode";
 +import { Env } from "./client";
 +import { log } from "./util";
 +
 +export type RunnableEnvCfg =
 +    | undefined
 +    | Record<string, string>
 +    | { mask?: string; env: Record<string, string> }[];
 +
 +export class Config {
 +    readonly extensionId = "rust-lang.rust-analyzer";
 +
 +    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() {
++        const item = this.get<any>("runnableEnv");
++        if (!item) return item;
++        const fixRecord = (r: Record<string, any>) => {
++            for (const key in r) {
++                if (typeof r[key] !== "string") {
++                    r[key] = String(r[key]);
++                }
++            }
++        };
++        if (item instanceof Array) {
++            item.forEach((x) => fixRecord(x.env));
++        } else {
++            fixRecord(item);
++        }
++        return item;
 +    }
 +
 +    get restartServerOnConfigChange() {
 +        return this.get<boolean>("restartServerOnConfigChange");
 +    }
 +
 +    get typingContinueCommentsOnNewline() {
 +        return this.get<boolean>("typing.continueCommentsOnNewline");
 +    }
 +
 +    get debug() {
 +        let sourceFileMap = this.get<Record<string, string> | "auto">("debug.sourceFileMap");
 +        if (sourceFileMap !== "auto") {
 +            // "/rustc/<id>" used by suggestions only.
 +            const { ["/rustc/<id>"]: _, ...trimmed } =
 +                this.get<Record<string, string>>("debug.sourceFileMap");
 +            sourceFileMap = trimmed;
 +        }
 +
 +        return {
 +            engine: this.get<string>("debug.engine"),
 +            engineSettings: this.get<object>("debug.engineSettings"),
 +            openDebugPane: this.get<boolean>("debug.openDebugPane"),
 +            sourceFileMap: sourceFileMap,
 +        };
 +    }
 +
 +    get hoverActions() {
 +        return {
 +            enable: this.get<boolean>("hover.actions.enable"),
 +            implementations: this.get<boolean>("hover.actions.implementations.enable"),
 +            references: this.get<boolean>("hover.actions.references.enable"),
 +            run: this.get<boolean>("hover.actions.run.enable"),
 +            debug: this.get<boolean>("hover.actions.debug.enable"),
 +            gotoTypeDef: this.get<boolean>("hover.actions.gotoTypeDef.enable"),
 +        };
 +    }
 +}
 +
 +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 b236b156cf99a505fec68c9302328211480b1e78,0000000000000000000000000000000000000000..5922bbfdb483d6d2f679475d9d8c04875c50b558
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,16 @@@
- serde_json = "1.0.85"
 +[package]
 +name = "lsp-server"
 +version = "0.7.0"
 +description = "Generic LSP server scaffold."
 +license = "MIT OR Apache-2.0"
 +repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/lsp-server"
 +edition = "2021"
 +
 +[dependencies]
 +log = "0.4.17"
++serde_json = "1.0.86"
 +serde = { version = "1.0.144", features = ["derive"] }
 +crossbeam-channel = "0.5.6"
 +
 +[dev-dependencies]
 +lsp-types = "0.93.1"
index 14816912b720d369a7cb75178bd5557f9d81a18f,0000000000000000000000000000000000000000..0be0bf920de9dd661d4851c4c03fb5527d97b63d
mode 100644,000000..100644
--- /dev/null
@@@ -1,15 -1,0 +1,15 @@@
- anyhow = "1.0.57"
 +[package]
 +name = "xtask"
 +version = "0.1.0"
 +publish = false
 +license = "MIT OR Apache-2.0"
 +edition = "2021"
 +rust-version = "1.57"
 +
 +[dependencies]
++anyhow = "1.0.62"
 +flate2 = "1.0.24"
 +write-json = "0.1.2"
 +xshell = "0.2.2"
 +xflags = "0.3.0"
 +# Avoid adding more dependencies to this crate