]> git.lizzy.rs Git - rust.git/commitdiff
:arrow_up: rust-analyzer
authorLaurențiu Nicola <lnicola@dend.ro>
Tue, 6 Sep 2022 18:20:49 +0000 (21:20 +0300)
committerLaurențiu Nicola <lnicola@dend.ro>
Tue, 6 Sep 2022 18:20:49 +0000 (21:20 +0300)
56 files changed:
1  2 
src/tools/rust-analyzer/.github/workflows/ci.yaml
src/tools/rust-analyzer/.github/workflows/release.yaml
src/tools/rust-analyzer/crates/hir-def/src/body.rs
src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
src/tools/rust-analyzer/crates/hir-def/src/expr.rs
src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
src/tools/rust-analyzer/crates/hir-expand/src/name.rs
src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/usefulness.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/inhabitedness.rs
src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
src/tools/rust-analyzer/crates/hir/src/lib.rs
src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.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/replace_or_with_or_else.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs
src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast
src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
src/tools/rust-analyzer/crates/syntax/rust.ungram
src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
src/tools/rust-analyzer/lib/la-arena/src/lib.rs

index a70252fa65a5d41dc9a26355ca5849c32a59474b,0000000000000000000000000000000000000000..1563ee0b143851435a28597c8c088621e5c4a59b
mode 100644,000000..100644
--- /dev/null
@@@ -1,156 -1,0 +1,156 @@@
-     - auto
-     - try
 +# 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:
-   RUSTFLAGS: "-D warnings -W unreachable-pub -W rust-2021-compatibility"
++      - auto
++      - try
 +
 +env:
 +  CARGO_INCREMENTAL: 0
 +  CARGO_NET_RETRY: 10
 +  CI: 1
 +  RUST_BACKTRACE: short
-     - name: Checkout repository
-       uses: actions/checkout@v3
-       with:
-         ref: ${{ github.event.pull_request.head.sha }}
-         fetch-depth: 20
++  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: Install Rust toolchain
-       run: |
-         rustup update --no-self-update stable
-         rustup component add rustfmt rust-src
++      - name: Checkout repository
++        uses: actions/checkout@v3
++        with:
++          ref: ${{ github.event.pull_request.head.sha }}
++          fetch-depth: 20
 +
-     - name: Cache Dependencies
-       uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
++      - name: Install Rust toolchain
++        run: |
++          rustup update --no-self-update stable
++          rustup component add rustfmt rust-src
 +
-     - name: Compile
-       run: cargo test --no-run --locked
++      - name: Cache Dependencies
++        uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
 +
-     - name: Test
-       run: cargo test -- --nocapture --quiet
++      - name: Compile
++        run: cargo test --no-run --locked
 +
-     - name: Checkout repository
-       uses: actions/checkout@v3
-     - name: Install Rust toolchain
-       run: |
-         rustup update --no-self-update stable
-         rustup target add ${{ env.targets }} ${{ env.targets_ide }}
-     - name: Cache Dependencies
-       uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
-     - name: Check
-       run: |
-         for target in ${{ env.targets }}; do
-           cargo check --target=$target --all-targets
-         done
-         for target in ${{ env.targets_ide }}; do
-           cargo check -p ide --target=$target --all-targets
-         done
++      - name: Test
++        run: cargo test -- --nocapture --quiet
 +
 +  # Weird targets to catch non-portable code
 +  rust-cross:
 +    if: github.repository == 'rust-lang/rust-analyzer'
 +    name: Rust Cross
 +    runs-on: ubuntu-latest
 +
 +    env:
 +      targets: "powerpc-unknown-linux-gnu x86_64-unknown-linux-musl"
 +      # The rust-analyzer binary is not expected to compile on WASM, but the IDE
 +      # crate should
 +      targets_ide: "wasm32-unknown-unknown"
 +
 +    steps:
-     - name: Checkout repository
-       uses: actions/checkout@v3
-     - name: Install Nodejs
-       uses: actions/setup-node@v1
-       with:
-         node-version: 16.x
-     - name: Install xvfb
-       if: matrix.os == 'ubuntu-latest'
-       run: sudo apt-get install -y xvfb
-     - run: npm ci
-       working-directory: ./editors/code
- #    - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; }
- #      if: runner.os == 'Linux'
- #      working-directory: ./editors/code
-     - run: npm run lint
-       working-directory: ./editors/code
-     - name: Run VS Code tests (Linux)
-       if: matrix.os == 'ubuntu-latest'
-       env:
-         VSCODE_CLI: 1
-       run: xvfb-run npm test
-       working-directory: ./editors/code
-     - name: Run VS Code tests (Windows)
-       if: matrix.os == 'windows-latest'
-       env:
-         VSCODE_CLI: 1
-       run: npm test
-       working-directory: ./editors/code
-     - run: npm run pretest
-       working-directory: ./editors/code
-     - run: npm run package --scripts-prepend-node-path
-       working-directory: ./editors/code
++      - name: Checkout repository
++        uses: actions/checkout@v3
++
++      - name: Install Rust toolchain
++        run: |
++          rustup update --no-self-update stable
++          rustup target add ${{ env.targets }} ${{ env.targets_ide }}
++
++      - name: Cache Dependencies
++        uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
++
++      - name: Check
++        run: |
++          for target in ${{ env.targets }}; do
++            cargo check --target=$target --all-targets
++          done
++          for target in ${{ env.targets_ide }}; do
++            cargo check -p ide --target=$target --all-targets
++          done
 +
 +  typescript:
 +    if: github.repository == 'rust-lang/rust-analyzer'
 +    name: TypeScript
 +    strategy:
 +      fail-fast: false
 +      matrix:
 +        os: [ubuntu-latest, windows-latest]
 +
 +    runs-on: ${{ matrix.os }}
 +
 +    steps:
++      - name: Checkout repository
++        uses: actions/checkout@v3
++
++      - name: Install Nodejs
++        uses: actions/setup-node@v1
++        with:
++          node-version: 16.x
++
++      - name: Install xvfb
++        if: matrix.os == 'ubuntu-latest'
++        run: sudo apt-get install -y xvfb
++
++      - run: npm ci
++        working-directory: ./editors/code
++
++      #    - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; }
++      #      if: runner.os == 'Linux'
++      #      working-directory: ./editors/code
++
++      - run: npm run lint
++        working-directory: ./editors/code
++
++      - name: Run VS Code tests (Linux)
++        if: matrix.os == 'ubuntu-latest'
++        env:
++          VSCODE_CLI: 1
++        run: xvfb-run npm test
++        working-directory: ./editors/code
++
++      - name: Run VS Code tests (Windows)
++        if: matrix.os == 'windows-latest'
++        env:
++          VSCODE_CLI: 1
++        run: npm test
++        working-directory: ./editors/code
++
++      - run: npm run pretest
++        working-directory: ./editors/code
++
++      - run: npm run package --scripts-prepend-node-path
++        working-directory: ./editors/code
 +
 +  end-success:
 +    name: bors build finished
 +    if: github.event.pusher.name == 'bors' && success()
 +    runs-on: ubuntu-latest
 +    needs: [rust, rust-cross, typescript]
 +    steps:
 +      - name: Mark the job as successful
 +        run: exit 0
 +
 +  end-failure:
 +    name: bors build finished
 +    if: github.event.pusher.name == 'bors' && (failure() || cancelled())
 +    runs-on: ubuntu-latest
 +    needs: [rust, rust-cross, typescript]
 +    steps:
 +      - name: Mark the job as a failure
 +        run: exit 1
index b2e5db6f689b518e5b6cfdfbe11a7b79294bdbb1,0000000000000000000000000000000000000000..303a10615bb7b7e33e5beb616a27059321cfff58
mode 100644,000000..100644
--- /dev/null
@@@ -1,261 -1,0 +1,261 @@@
-         run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
 +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
 +          - os: ubuntu-20.04
 +            target: aarch64-unknown-linux-gnu
 +            code-target: linux-arm64
 +          - os: ubuntu-20.04
 +            target: arm-unknown-linux-gnueabihf
 +            code-target: linux-armhf
 +          - os: macos-11
 +            target: x86_64-apple-darwin
 +            code-target: darwin-x64
 +          - os: macos-11
 +            target: aarch64-apple-darwin
 +            code-target: darwin-arm64
 +
 +    name: dist (${{ matrix.target }})
 +    runs-on: ${{ matrix.os }}
 +
 +    env:
 +      RA_TARGET: ${{ matrix.target }}
 +
 +    steps:
 +      - name: Checkout repository
 +        uses: actions/checkout@v3
 +        with:
 +          fetch-depth: ${{ env.FETCH_DEPTH }}
 +
 +      - name: Install Rust toolchain
 +        run: |
 +          rustup update --no-self-update stable
 +          rustup target add ${{ matrix.target }}
 +          rustup component add rust-src
 +
 +      - name: Install Node.js
 +        uses: actions/setup-node@v1
 +        with:
 +          node-version: 16.x
 +
 +      - name: Update apt repositories
 +        if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf'
 +        run: sudo apt-get update
 +
 +      - name: Install AArch64 target toolchain
 +        if: matrix.target == 'aarch64-unknown-linux-gnu'
 +        run: sudo apt-get install gcc-aarch64-linux-gnu
 +
 +      - name: Install ARM target toolchain
 +        if: matrix.target == 'arm-unknown-linux-gnueabihf'
 +        run: sudo apt-get install gcc-arm-linux-gnueabihf
 +
 +      - name: Dist
 +        run: cargo xtask dist --client-patch-version ${{ github.run_number }}
 +
 +      - run: npm ci
 +        working-directory: editors/code
 +
 +      - name: Package Extension (release)
 +        if: github.ref == 'refs/heads/release'
 +        run: npx vsce package -o "../../dist/rust-analyzer-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }}
 +        working-directory: editors/code
 +
 +      - name: Package Extension (nightly)
 +        if: github.ref != 'refs/heads/release'
 +        run: npx vsce package -o "../../dist/rust-analyzer-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} --pre-release
 +        working-directory: editors/code
 +
 +      - if: matrix.target == 'x86_64-unknown-linux-gnu'
 +        run: rm -rf editors/code/server
 +
 +      - if: matrix.target == 'x86_64-unknown-linux-gnu' && github.ref == 'refs/heads/release'
 +        run: npx vsce package -o ../../dist/rust-analyzer-no-server.vsix
 +        working-directory: editors/code
 +
 +      - if: matrix.target == 'x86_64-unknown-linux-gnu' && github.ref != 'refs/heads/release'
 +        run: npx vsce package -o ../../dist/rust-analyzer-no-server.vsix --pre-release
 +        working-directory: editors/code
 +
 +      - name: Run analysis-stats on rust-analyzer
 +        if: matrix.target == 'x86_64-unknown-linux-gnu'
 +        run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats .
 +
 +      - name: Run analysis-stats on rust std library
 +        if: matrix.target == 'x86_64-unknown-linux-gnu'
 +        run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std
 +
 +      - name: Upload artifacts
 +        uses: actions/upload-artifact@v1
 +        with:
 +          name: dist-${{ matrix.target }}
 +          path: ./dist
 +
 +  dist-x86_64-unknown-linux-musl:
 +    name: dist (x86_64-unknown-linux-musl)
 +    runs-on: ubuntu-latest
 +    env:
 +      RA_TARGET: x86_64-unknown-linux-musl
 +      # For some reason `-crt-static` is not working for clang without lld
 +      RUSTFLAGS: "-C link-arg=-fuse-ld=lld -C target-feature=-crt-static"
 +    container:
 +      image: rust:alpine
 +      volumes:
 +        - /usr/local/cargo/registry:/usr/local/cargo/registry
 +
 +    steps:
 +      - name: Install dependencies
 +        run: apk add --no-cache git clang lld musl-dev nodejs npm
 +
 +      - name: Checkout repository
 +        uses: actions/checkout@v3
 +        with:
 +          fetch-depth: ${{ env.FETCH_DEPTH }}
 +
 +      - name: Dist
 +        run: cargo xtask dist --client-patch-version ${{ github.run_number }}
 +
 +      - run: npm ci
 +        working-directory: editors/code
 +
 +      - name: Package Extension (release)
 +        if: github.ref == 'refs/heads/release'
 +        run: npx vsce package -o "../../dist/rust-analyzer-alpine-x64.vsix" --target alpine-x64
 +        working-directory: editors/code
 +
 +      - name: Package Extension (nightly)
 +        if: github.ref != 'refs/heads/release'
 +        run: npx vsce package -o "../../dist/rust-analyzer-alpine-x64.vsix" --target alpine-x64 --pre-release
 +        working-directory: editors/code
 +
 +      - run: rm -rf editors/code/server
 +
 +      - name: Upload artifacts
 +        uses: actions/upload-artifact@v1
 +        with:
 +          name: dist-x86_64-unknown-linux-musl
 +          path: ./dist
 +
 +  publish:
 +    name: publish
 +    runs-on: ubuntu-latest
 +    needs: ["dist", "dist-x86_64-unknown-linux-musl"]
 +    steps:
 +      - name: Install Nodejs
 +        uses: actions/setup-node@v1
 +        with:
 +          node-version: 16.x
 +
 +      - run: echo "TAG=$(date --iso -u)" >> $GITHUB_ENV
 +        if: github.ref == 'refs/heads/release'
 +      - run: echo "TAG=nightly" >> $GITHUB_ENV
 +        if: github.ref != 'refs/heads/release'
 +      - run: 'echo "TAG: $TAG"'
 +
 +      - name: Checkout repository
 +        uses: actions/checkout@v3
 +        with:
 +          fetch-depth: ${{ env.FETCH_DEPTH }}
 +
 +      - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
 +      - run: 'echo "HEAD_SHA: $HEAD_SHA"'
 +
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-aarch64-apple-darwin
 +          path: dist
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-x86_64-apple-darwin
 +          path: dist
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-x86_64-unknown-linux-gnu
 +          path: dist
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-x86_64-unknown-linux-musl
 +          path: dist
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-aarch64-unknown-linux-gnu
 +          path: dist
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-arm-unknown-linux-gnueabihf
 +          path: dist
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-x86_64-pc-windows-msvc
 +          path: dist
 +      - uses: actions/download-artifact@v1
 +        with:
 +          name: dist-aarch64-pc-windows-msvc
 +          path: dist
 +      - run: ls -al ./dist
 +
 +      - name: Publish Release
 +        uses: ./.github/actions/github-release
 +        with:
 +          files: "dist/*"
 +          name: ${{ env.TAG }}
 +          token: ${{ secrets.GITHUB_TOKEN }}
 +
 +      - run: rm dist/rust-analyzer-no-server.vsix
 +
 +      - run: npm ci
 +        working-directory: ./editors/code
 +
 +      - name: Publish Extension (Code Marketplace, release)
 +        if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
 +        working-directory: ./editors/code
 +        # token from https://dev.azure.com/rust-analyzer/
 +        run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
 +
 +      - name: Publish Extension (OpenVSX, release)
 +        if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
 +        working-directory: ./editors/code
 +        # token from https://dev.azure.com/rust-analyzer/
-         run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
++        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
 +
 +      - 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
index 1d818d96267c177223985d6588e138556227e9c2,0000000000000000000000000000000000000000..22f5fb9926638e0f7ea9413563fbcec4a372483f
mode 100644,000000..100644
--- /dev/null
@@@ -1,476 -1,0 +1,481 @@@
-     expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
 +//! Defines `Body`: a lowered representation of bodies of functions, statics and
 +//! consts.
 +mod lower;
 +#[cfg(test)]
 +mod tests;
 +pub mod scope;
 +mod pretty;
 +
 +use std::{ops::Index, sync::Arc};
 +
 +use base_db::CrateId;
 +use cfg::{CfgExpr, CfgOptions};
 +use drop_bomb::DropBomb;
 +use either::Either;
 +use hir_expand::{hygiene::Hygiene, ExpandError, ExpandResult, HirFileId, InFile, MacroCallId};
 +use la_arena::{Arena, ArenaMap};
 +use limit::Limit;
 +use profile::Count;
 +use rustc_hash::FxHashMap;
 +use syntax::{ast, AstPtr, SyntaxNodePtr};
 +
 +use crate::{
 +    attr::{Attrs, RawAttrs},
 +    db::DefDatabase,
 +    expr::{dummy_expr_id, Expr, ExprId, Label, LabelId, Pat, PatId},
 +    item_scope::BuiltinShadowMode,
 +    macro_id_to_def_id,
 +    nameres::DefMap,
 +    path::{ModPath, Path},
 +    src::HasSource,
 +    AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, ModuleId,
 +    UnresolvedMacro,
 +};
 +
 +pub use lower::LowerCtx;
 +
 +/// A subset of Expander that only deals with cfg attributes. We only need it to
 +/// avoid cyclic queries in crate def map during enum processing.
 +#[derive(Debug)]
 +pub(crate) struct CfgExpander {
 +    cfg_options: CfgOptions,
 +    hygiene: Hygiene,
 +    krate: CrateId,
 +}
 +
 +#[derive(Debug)]
 +pub struct Expander {
 +    cfg_expander: CfgExpander,
 +    def_map: Arc<DefMap>,
 +    current_file_id: HirFileId,
 +    module: LocalModuleId,
 +    recursion_limit: usize,
 +}
 +
 +impl CfgExpander {
 +    pub(crate) fn new(
 +        db: &dyn DefDatabase,
 +        current_file_id: HirFileId,
 +        krate: CrateId,
 +    ) -> CfgExpander {
 +        let hygiene = Hygiene::new(db.upcast(), current_file_id);
 +        let cfg_options = db.crate_graph()[krate].cfg_options.clone();
 +        CfgExpander { cfg_options, hygiene, krate }
 +    }
 +
 +    pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs {
 +        RawAttrs::new(db, owner, &self.hygiene).filter(db, self.krate)
 +    }
 +
 +    pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> bool {
 +        let attrs = self.parse_attrs(db, owner);
 +        attrs.is_cfg_enabled(&self.cfg_options)
 +    }
 +}
 +
 +impl Expander {
 +    pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
 +        let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
 +        let def_map = module.def_map(db);
 +        Expander {
 +            cfg_expander,
 +            def_map,
 +            current_file_id,
 +            module: module.local_id,
 +            recursion_limit: 0,
 +        }
 +    }
 +
 +    pub fn enter_expand<T: ast::AstNode>(
 +        &mut self,
 +        db: &dyn DefDatabase,
 +        macro_call: ast::MacroCall,
 +    ) -> Result<ExpandResult<Option<(Mark, T)>>, UnresolvedMacro> {
 +        if self.recursion_limit(db).check(self.recursion_limit + 1).is_err() {
 +            cov_mark::hit!(your_stack_belongs_to_me);
 +            return Ok(ExpandResult::only_err(ExpandError::Other(
 +                "reached recursion limit during macro expansion".into(),
 +            )));
 +        }
 +
 +        let macro_call = InFile::new(self.current_file_id, &macro_call);
 +
 +        let resolver =
 +            |path| self.resolve_path_as_macro(db, &path).map(|it| macro_id_to_def_id(db, it));
 +
 +        let mut err = None;
 +        let call_id =
 +            macro_call.as_call_id_with_errors(db, self.def_map.krate(), resolver, &mut |e| {
 +                err.get_or_insert(e);
 +            })?;
 +        let call_id = match call_id {
 +            Ok(it) => it,
 +            Err(_) => {
 +                return Ok(ExpandResult { value: None, err });
 +            }
 +        };
 +
 +        Ok(self.enter_expand_inner(db, call_id, err))
 +    }
 +
 +    pub fn enter_expand_id<T: ast::AstNode>(
 +        &mut self,
 +        db: &dyn DefDatabase,
 +        call_id: MacroCallId,
 +    ) -> ExpandResult<Option<(Mark, T)>> {
 +        self.enter_expand_inner(db, call_id, None)
 +    }
 +
 +    fn enter_expand_inner<T: ast::AstNode>(
 +        &mut self,
 +        db: &dyn DefDatabase,
 +        call_id: MacroCallId,
 +        mut err: Option<ExpandError>,
 +    ) -> ExpandResult<Option<(Mark, T)>> {
 +        if err.is_none() {
 +            err = db.macro_expand_error(call_id);
 +        }
 +
 +        let file_id = call_id.as_file();
 +
 +        let raw_node = match db.parse_or_expand(file_id) {
 +            Some(it) => it,
 +            None => {
 +                // Only `None` if the macro expansion produced no usable AST.
 +                if err.is_none() {
 +                    tracing::warn!("no error despite `parse_or_expand` failing");
 +                }
 +
 +                return ExpandResult::only_err(err.unwrap_or_else(|| {
 +                    ExpandError::Other("failed to parse macro invocation".into())
 +                }));
 +            }
 +        };
 +
 +        let node = match T::cast(raw_node) {
 +            Some(it) => it,
 +            None => {
 +                // This can happen without being an error, so only forward previous errors.
 +                return ExpandResult { value: None, err };
 +            }
 +        };
 +
 +        tracing::debug!("macro expansion {:#?}", node.syntax());
 +
 +        self.recursion_limit += 1;
 +        let mark =
 +            Mark { file_id: self.current_file_id, bomb: DropBomb::new("expansion mark dropped") };
 +        self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
 +        self.current_file_id = file_id;
 +
 +        ExpandResult { value: Some((mark, node)), err }
 +    }
 +
 +    pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
 +        self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
 +        self.current_file_id = mark.file_id;
 +        self.recursion_limit -= 1;
 +        mark.bomb.defuse();
 +    }
 +
 +    pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> {
 +        InFile { file_id: self.current_file_id, value }
 +    }
 +
 +    pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs {
 +        self.cfg_expander.parse_attrs(db, owner)
 +    }
 +
 +    pub(crate) fn cfg_options(&self) -> &CfgOptions {
 +        &self.cfg_expander.cfg_options
 +    }
 +
 +    pub fn current_file_id(&self) -> HirFileId {
 +        self.current_file_id
 +    }
 +
 +    fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> {
 +        let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene);
 +        Path::from_src(path, &ctx)
 +    }
 +
 +    fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroId> {
 +        self.def_map.resolve_path(db, self.module, path, BuiltinShadowMode::Other).0.take_macros()
 +    }
 +
 +    fn recursion_limit(&self, db: &dyn DefDatabase) -> Limit {
 +        let limit = db.crate_limits(self.cfg_expander.krate).recursion_limit as _;
 +
 +        #[cfg(not(test))]
 +        return Limit::new(limit);
 +
 +        // Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug
 +        #[cfg(test)]
 +        return Limit::new(std::cmp::min(32, limit));
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub struct Mark {
 +    file_id: HirFileId,
 +    bomb: DropBomb,
 +}
 +
 +/// The body of an item (function, const etc.).
 +#[derive(Debug, Eq, PartialEq)]
 +pub struct Body {
 +    pub exprs: Arena<Expr>,
 +    pub pats: Arena<Pat>,
 +    pub or_pats: FxHashMap<PatId, Arc<[PatId]>>,
 +    pub labels: Arena<Label>,
 +    /// The patterns for the function's parameters. While the parameter types are
 +    /// part of the function signature, the patterns are not (they don't change
 +    /// the external type of the function).
 +    ///
 +    /// If this `Body` is for the body of a constant, this will just be
 +    /// empty.
 +    pub params: Vec<PatId>,
 +    /// The `ExprId` of the actual body expression.
 +    pub body_expr: ExprId,
 +    /// Block expressions in this body that may contain inner items.
 +    block_scopes: Vec<BlockId>,
 +    _c: Count<Self>,
 +}
 +
 +pub type ExprPtr = AstPtr<ast::Expr>;
 +pub type ExprSource = InFile<ExprPtr>;
 +
 +pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
 +pub type PatSource = InFile<PatPtr>;
 +
 +pub type LabelPtr = AstPtr<ast::Label>;
 +pub type LabelSource = InFile<LabelPtr>;
++
++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>,
-     pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>,
++    expr_map_back: ArenaMap<ExprId, ExprSource>,
 +
 +    pat_map: FxHashMap<PatSource, PatId>,
-     field_map: FxHashMap<InFile<AstPtr<ast::RecordExprField>>, ExprId>,
-     field_map_back: FxHashMap<ExprId, InFile<AstPtr<ast::RecordExprField>>>,
++    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.
-         self.expr_map_back[expr].clone()
++    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 = src.value.param_list();
 +                (src.file_id, f.module(db), src.value.body().map(ast::Expr::from))
 +            }
 +            DefWithBodyId::ConstId(c) => {
 +                let c = c.lookup(db);
 +                let src = c.source(db);
 +                (src.file_id, c.module(db), src.value.body())
 +            }
 +            DefWithBodyId::StaticId(s) => {
 +                let s = s.lookup(db);
 +                let src = s.source(db);
 +                (src.file_id, s.module(db), src.value.body())
 +            }
 +        };
 +        let expander = Expander::new(db, file_id, module);
 +        let (mut body, source_map) = Body::new(db, expander, params, body);
 +        body.shrink_to_fit();
 +        (Arc::new(body), Arc::new(source_map))
 +    }
 +
 +    pub(crate) fn body_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<Body> {
 +        db.body_with_source_map(def).0
 +    }
 +
 +    /// Returns an iterator over all block expressions in this body that define inner items.
 +    pub fn blocks<'a>(
 +        &'a self,
 +        db: &'a dyn DefDatabase,
 +    ) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + '_ {
 +        self.block_scopes
 +            .iter()
 +            .map(move |&block| (block, db.block_def_map(block).expect("block ID without DefMap")))
 +    }
 +
 +    pub fn pattern_representative(&self, pat: PatId) -> PatId {
 +        self.or_pats.get(&pat).and_then(|pats| pats.first().copied()).unwrap_or(pat)
 +    }
 +
 +    /// Retrieves all ident patterns this pattern shares the ident with.
 +    pub fn ident_patterns_for<'slf>(&'slf self, pat: &'slf PatId) -> &'slf [PatId] {
 +        match self.or_pats.get(pat) {
 +            Some(pats) => &**pats,
 +            None => std::slice::from_ref(pat),
 +        }
 +    }
 +
 +    pub fn pretty_print(&self, db: &dyn DefDatabase, owner: DefWithBodyId) -> String {
 +        pretty::print_body_hir(db, self, owner)
 +    }
 +
 +    fn new(
 +        db: &dyn DefDatabase,
 +        expander: Expander,
 +        params: Option<ast::ParamList>,
 +        body: Option<ast::Expr>,
 +    ) -> (Body, BodySourceMap) {
 +        lower::lower(db, expander, params, body)
 +    }
 +
 +    fn shrink_to_fit(&mut self) {
 +        let Self { _c: _, body_expr: _, block_scopes, or_pats, exprs, labels, params, pats } = self;
 +        block_scopes.shrink_to_fit();
 +        or_pats.shrink_to_fit();
 +        exprs.shrink_to_fit();
 +        labels.shrink_to_fit();
 +        params.shrink_to_fit();
 +        pats.shrink_to_fit();
 +    }
 +}
 +
 +impl Default for Body {
 +    fn default() -> Self {
 +        Self {
 +            body_expr: dummy_expr_id(),
 +            exprs: Default::default(),
 +            pats: Default::default(),
 +            or_pats: Default::default(),
 +            labels: Default::default(),
 +            params: Default::default(),
 +            block_scopes: Default::default(),
 +            _c: Default::default(),
 +        }
 +    }
 +}
 +
 +impl Index<ExprId> for Body {
 +    type Output = Expr;
 +
 +    fn index(&self, expr: ExprId) -> &Expr {
 +        &self.exprs[expr]
 +    }
 +}
 +
 +impl Index<PatId> for Body {
 +    type Output = Pat;
 +
 +    fn index(&self, pat: PatId) -> &Pat {
 +        &self.pats[pat]
 +    }
 +}
 +
 +impl Index<LabelId> for Body {
 +    type Output = Label;
 +
 +    fn index(&self, label: LabelId) -> &Label {
 +        &self.labels[label]
 +    }
 +}
 +
 +// FIXME: Change `node_` prefix to something more reasonable.
 +// Perhaps `expr_syntax` and `expr_id`?
 +impl BodySourceMap {
 +    pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
-         self.pat_map_back[pat].clone()
++        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> {
-     pub fn field_syntax(&self, expr: ExprId) -> InFile<AstPtr<ast::RecordExprField>> {
++        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 f6ec8bf7e9e0b4475302dfb6ed17b3c0e8c44d88,0000000000000000000000000000000000000000..3b3297f7811c07628ba30e2382531672f2c89c39
mode 100644,000000..100644
--- /dev/null
@@@ -1,1031 -1,0 +1,1020 @@@
-     body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
 +//! 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,
-     fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
++    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, Expr, ExprId, FloatTypeWrapper, Label, LabelId,
 +        Literal, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
 +    },
 +    intern::Interned,
 +    item_scope::BuiltinShadowMode,
 +    path::{GenericArgs, Path},
 +    type_ref::{Mutability, Rawness, TypeRef},
 +    AdtId, BlockLoc, ModuleDefId, UnresolvedMacro,
 +};
 +
 +pub struct LowerCtx<'a> {
 +    pub db: &'a dyn DefDatabase,
 +    hygiene: Hygiene,
 +    ast_id_map: Option<(HirFileId, OnceCell<Arc<AstIdMap>>)>,
 +}
 +
 +impl<'a> LowerCtx<'a> {
 +    pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
 +        LowerCtx {
 +            db,
 +            hygiene: Hygiene::new(db.upcast(), file_id),
 +            ast_id_map: Some((file_id, OnceCell::new())),
 +        }
 +    }
 +
 +    pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self {
 +        LowerCtx { db, hygiene: hygiene.clone(), ast_id_map: None }
 +    }
 +
 +    pub(crate) fn hygiene(&self) -> &Hygiene {
 +        &self.hygiene
 +    }
 +
 +    pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> {
 +        Path::from_src(ast, self)
 +    }
 +
 +    pub(crate) fn ast_id<N: AstNode>(&self, db: &dyn DefDatabase, item: &N) -> Option<AstId<N>> {
 +        let &(file_id, ref ast_id_map) = self.ast_id_map.as_ref()?;
 +        let ast_id_map = ast_id_map.get_or_init(|| db.ast_id_map(file_id));
 +        Some(InFile::new(file_id, ast_id_map.ast_id(item)))
 +    }
 +}
 +
 +pub(super) fn lower(
 +    db: &dyn DefDatabase,
 +    expander: Expander,
 +    params: Option<ast::ParamList>,
 +    body: Option<ast::Expr>,
 +) -> (Body, BodySourceMap) {
 +    ExprCollector {
 +        db,
 +        source_map: BodySourceMap::default(),
 +        ast_id_map: db.ast_id_map(expander.current_file_id),
 +        body: Body {
 +            exprs: Arena::default(),
 +            pats: Arena::default(),
 +            labels: Arena::default(),
 +            params: Vec::new(),
 +            body_expr: dummy_expr_id(),
 +            block_scopes: Vec::new(),
 +            _c: Count::new(),
 +            or_pats: Default::default(),
 +        },
 +        expander,
 +        name_to_pat_grouping: Default::default(),
 +        is_lowering_inside_or_pat: false,
 +        is_lowering_assignee_expr: false,
 +    }
 +    .collect(params, body)
 +}
 +
 +struct ExprCollector<'a> {
 +    db: &'a dyn DefDatabase,
 +    expander: Expander,
 +    ast_id_map: Arc<AstIdMap>,
 +    body: Body,
 +    source_map: BodySourceMap,
 +    // a poor-mans union-find?
 +    name_to_pat_grouping: FxHashMap<Name, Vec<PatId>>,
 +    is_lowering_inside_or_pat: bool,
 +    is_lowering_assignee_expr: bool,
 +}
 +
 +impl ExprCollector<'_> {
 +    fn collect(
 +        mut self,
 +        param_list: Option<ast::ParamList>,
 +        body: Option<ast::Expr>,
 +    ) -> (Body, BodySourceMap) {
 +        if let Some(param_list) = param_list {
 +            if let Some(self_param) = param_list.self_param() {
 +                let ptr = AstPtr::new(&self_param);
 +                let param_pat = self.alloc_pat(
 +                    Pat::Bind {
 +                        name: name![self],
 +                        mode: BindingAnnotation::new(
 +                            self_param.mut_token().is_some() && self_param.amp_token().is_none(),
 +                            false,
 +                        ),
 +                        subpat: None,
 +                    },
 +                    Either::Right(ptr),
 +                );
 +                self.body.params.push(param_pat);
 +            }
 +
 +            for pat in param_list.params().filter_map(|param| param.pat()) {
 +                let param_pat = self.collect_pat(pat);
 +                self.body.params.push(param_pat);
 +            }
 +        };
 +
 +        self.body.body_expr = self.collect_expr_opt(body);
 +        (self.body, self.source_map)
 +    }
 +
 +    fn ctx(&self) -> LowerCtx<'_> {
 +        LowerCtx::new(self.db, self.expander.current_file_id)
 +    }
 +
-         let id = self.make_expr(expr, Ok(src.clone()));
++    fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
 +        let src = self.expander.to_source(ptr);
-         self.make_expr(expr, Err(SyntheticSyntax))
++        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 {
-     fn make_expr(&mut self, expr: Expr, src: Result<ExprSource, SyntheticSyntax>) -> ExprId {
++        self.body.exprs.alloc(expr)
 +    }
 +    fn missing_expr(&mut self) -> ExprId {
 +        self.alloc_expr_desugared(Expr::Missing)
 +    }
-         let id = self.make_pat(pat, Ok(src.clone()));
++    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);
-         self.make_pat(Pat::Missing, Err(SyntheticSyntax))
++        let id = self.make_pat(pat, src.clone());
 +        self.source_map.pat_map.insert(src, id);
 +        id
 +    }
 +    fn missing_pat(&mut self) -> PatId {
-     fn make_pat(&mut self, pat: Pat, src: Result<PatSource, SyntheticSyntax>) -> PatId {
++        self.body.pats.alloc(Pat::Missing)
 +    }
-     fn alloc_label(&mut self, label: Label, ptr: AstPtr<ast::Label>) -> LabelId {
++    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
 +    }
 +
-             ast::Expr::MacroStmts(e) => {
-                 let statements: Box<[_]> =
-                     e.statements().filter_map(|s| self.collect_stmt(s)).collect();
-                 let tail = e.expr().map(|e| self.collect_expr(e));
-                 if e.syntax().children().next().is_none() {
-                     // HACK: make sure that macros that expand to nothing aren't treated as a `()`
-                     // expression when used in block tail position.
-                     cov_mark::hit!(empty_macro_in_trailing_position_is_removed);
-                     return None;
-                 }
-                 self.alloc_expr(Expr::MacroStmts { tail, statements }, syntax_ptr)
-             }
++    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) => {
 +                let expr = e.expr().map(|e| self.collect_expr(e));
 +                self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
 +            }
 +            ast::Expr::RecordExpr(e) => {
 +                let path =
 +                    e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
 +                let is_assignee_expr = self.is_lowering_assignee_expr;
 +                let record_lit = if let Some(nfl) = e.record_expr_field_list() {
 +                    let fields = nfl
 +                        .fields()
 +                        .filter_map(|field| {
 +                            self.check_cfg(&field)?;
 +
 +                            let name = field.field_name()?.as_name();
 +
 +                            let expr = match field.expr() {
 +                                Some(e) => self.collect_expr(e),
 +                                None => self.missing_expr(),
 +                            };
 +                            let src = self.expander.to_source(AstPtr::new(&field));
 +                            self.source_map.field_map.insert(src.clone(), expr);
 +                            self.source_map.field_map_back.insert(expr, src);
 +                            Some(RecordLitField { name, expr })
 +                        })
 +                        .collect();
 +                    let spread = nfl.spread().map(|s| self.collect_expr(s));
 +                    let ellipsis = nfl.dotdot_token().is_some();
 +                    Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr }
 +                } else {
 +                    Expr::RecordLit {
 +                        path,
 +                        fields: Box::default(),
 +                        spread: None,
 +                        ellipsis: false,
 +                        is_assignee_expr,
 +                    }
 +                };
 +
 +                self.alloc_expr(record_lit, syntax_ptr)
 +            }
 +            ast::Expr::FieldExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                let name = match e.field_access() {
 +                    Some(kind) => kind.as_name(),
 +                    _ => Name::missing(),
 +                };
 +                self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
 +            }
 +            ast::Expr::AwaitExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                self.alloc_expr(Expr::Await { expr }, syntax_ptr)
 +            }
 +            ast::Expr::TryExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                self.alloc_expr(Expr::Try { expr }, syntax_ptr)
 +            }
 +            ast::Expr::CastExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
 +                self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
 +            }
 +            ast::Expr::RefExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                let raw_tok = e.raw_token().is_some();
 +                let mutability = if raw_tok {
 +                    if e.mut_token().is_some() {
 +                        Mutability::Mut
 +                    } else if e.const_token().is_some() {
 +                        Mutability::Shared
 +                    } else {
 +                        unreachable!("parser only remaps to raw_token() if matching mutability token follows")
 +                    }
 +                } else {
 +                    Mutability::from_mutable(e.mut_token().is_some())
 +                };
 +                let rawness = Rawness::from_raw(raw_tok);
 +                self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)
 +            }
 +            ast::Expr::PrefixExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                match e.op_kind() {
 +                    Some(op) => self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr),
 +                    None => self.alloc_expr(Expr::Missing, syntax_ptr),
 +                }
 +            }
 +            ast::Expr::ClosureExpr(e) => {
 +                let mut args = Vec::new();
 +                let mut arg_types = Vec::new();
 +                if let Some(pl) = e.param_list() {
 +                    for param in pl.params() {
 +                        let pat = self.collect_pat_opt(param.pat());
 +                        let type_ref =
 +                            param.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
 +                        args.push(pat);
 +                        arg_types.push(type_ref);
 +                    }
 +                }
 +                let ret_type = e
 +                    .ret_type()
 +                    .and_then(|r| r.ty())
 +                    .map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
 +                let body = self.collect_expr_opt(e.body());
 +                self.alloc_expr(
 +                    Expr::Closure {
 +                        args: args.into(),
 +                        arg_types: arg_types.into(),
 +                        ret_type,
 +                        body,
 +                    },
 +                    syntax_ptr,
 +                )
 +            }
 +            ast::Expr::BinExpr(e) => {
 +                let op = e.op_kind();
 +                if let Some(ast::BinaryOp::Assignment { op: None }) = op {
 +                    self.is_lowering_assignee_expr = true;
 +                }
 +                let lhs = self.collect_expr_opt(e.lhs());
 +                self.is_lowering_assignee_expr = false;
 +                let rhs = self.collect_expr_opt(e.rhs());
 +                self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
 +            }
 +            ast::Expr::TupleExpr(e) => {
 +                let exprs = e.fields().map(|expr| self.collect_expr(expr)).collect();
 +                self.alloc_expr(
 +                    Expr::Tuple { exprs, is_assignee_expr: self.is_lowering_assignee_expr },
 +                    syntax_ptr,
 +                )
 +            }
 +            ast::Expr::BoxExpr(e) => {
 +                let expr = self.collect_expr_opt(e.expr());
 +                self.alloc_expr(Expr::Box { expr }, syntax_ptr)
 +            }
 +
 +            ast::Expr::ArrayExpr(e) => {
 +                let kind = e.kind();
 +
 +                match kind {
 +                    ArrayExprKind::ElementList(e) => {
 +                        let elements = e.map(|expr| self.collect_expr(expr)).collect();
 +                        self.alloc_expr(
 +                            Expr::Array(Array::ElementList {
 +                                elements,
 +                                is_assignee_expr: self.is_lowering_assignee_expr,
 +                            }),
 +                            syntax_ptr,
 +                        )
 +                    }
 +                    ArrayExprKind::Repeat { initializer, repeat } => {
 +                        let initializer = self.collect_expr_opt(initializer);
 +                        let repeat = self.collect_expr_opt(repeat);
 +                        self.alloc_expr(
 +                            Expr::Array(Array::Repeat { initializer, repeat }),
 +                            syntax_ptr,
 +                        )
 +                    }
 +                }
 +            }
 +
 +            ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr),
 +            ast::Expr::IndexExpr(e) => {
 +                let base = self.collect_expr_opt(e.base());
 +                let index = self.collect_expr_opt(e.index());
 +                self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
 +            }
 +            ast::Expr::RangeExpr(e) => {
 +                let lhs = e.start().map(|lhs| self.collect_expr(lhs));
 +                let rhs = e.end().map(|rhs| self.collect_expr(rhs));
 +                match e.op_kind() {
 +                    Some(range_type) => {
 +                        self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)
 +                    }
 +                    None => self.alloc_expr(Expr::Missing, syntax_ptr),
 +                }
 +            }
 +            ast::Expr::MacroExpr(e) => {
 +                let e = e.macro_call()?;
 +                let macro_ptr = AstPtr::new(&e);
 +                let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
 +                    expansion.map(|it| this.collect_expr(it))
 +                });
 +                match id {
 +                    Some(id) => {
 +                        // Make the macro-call point to its expanded expression so we can query
 +                        // semantics on syntax pointers to the macro
 +                        let src = self.expander.to_source(syntax_ptr);
 +                        self.source_map.expr_map.insert(src, id);
 +                        id
 +                    }
 +                    None => self.alloc_expr(Expr::Missing, syntax_ptr),
 +                }
 +            }
-     fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Statement> {
 +            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(),
 +        }
 +    }
 +
-                     return None;
++    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() {
-                 Some(Statement::Let { pat, type_ref, initializer, else_branch })
++                    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));
-                 if let Some(expr) = &expr {
-                     if self.check_cfg(expr).is_none() {
-                         return None;
-                     }
++                statements.push(Statement::Let { pat, type_ref, initializer, else_branch });
 +            }
 +            ast::Stmt::ExprStmt(stmt) => {
 +                let expr = stmt.expr();
-                 if let Some(expr @ ast::Expr::MacroExpr(mac)) = &expr {
-                     let mac_call = mac.macro_call()?;
-                     let syntax_ptr = AstPtr::new(expr);
-                     let macro_ptr = AstPtr::new(&mac_call);
-                     let stmt = self.collect_macro_call(
-                         mac_call,
-                         macro_ptr,
-                         false,
-                         |this, expansion: Option<ast::MacroStmts>| match expansion {
-                             Some(expansion) => {
-                                 let statements = expansion
-                                     .statements()
-                                     .filter_map(|stmt| this.collect_stmt(stmt))
-                                     .collect();
-                                 let tail = expansion.expr().map(|expr| this.collect_expr(expr));
-                                 let mac_stmts = this.alloc_expr(
-                                     Expr::MacroStmts { tail, statements },
-                                     AstPtr::new(&ast::Expr::MacroStmts(expansion)),
-                                 );
-                                 Some(mac_stmts)
-                             }
-                             None => None,
-                         },
-                     );
-                     let expr = match stmt {
-                         Some(expr) => {
-                             // Make the macro-call point to its expanded expression so we can query
-                             // semantics on syntax pointers to the macro
-                             let src = self.expander.to_source(syntax_ptr);
-                             self.source_map.expr_map.insert(src, expr);
-                             expr
-                         }
-                         None => self.alloc_expr(Expr::Missing, syntax_ptr),
-                     };
-                     Some(Statement::Expr { expr, has_semi })
++                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
-                     Some(Statement::Expr { expr, has_semi })
++                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);
-             ast::Stmt::Item(_item) => None,
++                    statements.push(Statement::Expr { expr, has_semi });
 +                }
 +            }
-         let mut statements: Vec<_> =
-             block.statements().filter_map(|s| self.collect_stmt(s)).collect();
-         let tail = block.tail_expr().and_then(|e| self.maybe_collect_expr(e));
++            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 ddd476efe5c4d764dabd4ff597e732d902fb3dec,0000000000000000000000000000000000000000..f2fed954444e2ca80b04a41a7bafa488f87905e4
mode 100644,000000..100644
--- /dev/null
@@@ -1,621 -1,0 +1,608 @@@
-             Expr::MacroStmts { statements, tail } => {
-                 w!(self, "{{ // macro statements");
-                 self.indented(|p| {
-                     for stmt in statements.iter() {
-                         p.print_stmt(stmt);
-                     }
-                     if let Some(tail) = tail {
-                         p.print_expr(*tail);
-                     }
-                 });
-                 self.newline();
-                 w!(self, "}}");
-             }
 +//! A pretty-printer for HIR.
 +
 +use std::fmt::{self, Write};
 +
 +use crate::{
 +    expr::{Array, BindingAnnotation, Literal, Statement},
 +    pretty::{print_generic_args, print_path, print_type_ref},
 +    type_ref::TypeRef,
 +};
 +
 +use super::*;
 +
 +pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String {
 +    let needs_semi;
 +    let header = match owner {
 +        DefWithBodyId::FunctionId(it) => {
 +            needs_semi = false;
 +            let item_tree_id = it.lookup(db).id;
 +            format!("fn {}(…) ", item_tree_id.item_tree(db)[item_tree_id.value].name)
 +        }
 +        DefWithBodyId::StaticId(it) => {
 +            needs_semi = true;
 +            let item_tree_id = it.lookup(db).id;
 +            format!("static {} = ", item_tree_id.item_tree(db)[item_tree_id.value].name)
 +        }
 +        DefWithBodyId::ConstId(it) => {
 +            needs_semi = true;
 +            let item_tree_id = it.lookup(db).id;
 +            let name = match &item_tree_id.item_tree(db)[item_tree_id.value].name {
 +                Some(name) => name.to_string(),
 +                None => "_".to_string(),
 +            };
 +            format!("const {} = ", name)
 +        }
 +    };
 +
 +    let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false };
 +    p.print_expr(body.body_expr);
 +    if needs_semi {
 +        p.buf.push(';');
 +    }
 +    p.buf
 +}
 +
 +macro_rules! w {
 +    ($dst:expr, $($arg:tt)*) => {
 +        { let _ = write!($dst, $($arg)*); }
 +    };
 +}
 +
 +macro_rules! wln {
 +    ($dst:expr) => {
 +        { let _ = writeln!($dst); }
 +    };
 +    ($dst:expr, $($arg:tt)*) => {
 +        { let _ = writeln!($dst, $($arg)*); }
 +    };
 +}
 +
 +struct Printer<'a> {
 +    body: &'a Body,
 +    buf: String,
 +    indent_level: usize,
 +    needs_indent: bool,
 +}
 +
 +impl<'a> Write for Printer<'a> {
 +    fn write_str(&mut self, s: &str) -> fmt::Result {
 +        for line in s.split_inclusive('\n') {
 +            if self.needs_indent {
 +                match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() {
 +                    Some('\n') | None => {}
 +                    _ => self.buf.push('\n'),
 +                }
 +                self.buf.push_str(&"    ".repeat(self.indent_level));
 +                self.needs_indent = false;
 +            }
 +
 +            self.buf.push_str(line);
 +            self.needs_indent = line.ends_with('\n');
 +        }
 +
 +        Ok(())
 +    }
 +}
 +
 +impl<'a> Printer<'a> {
 +    fn indented(&mut self, f: impl FnOnce(&mut Self)) {
 +        self.indent_level += 1;
 +        wln!(self);
 +        f(self);
 +        self.indent_level -= 1;
 +        self.buf = self.buf.trim_end_matches('\n').to_string();
 +    }
 +
 +    fn whitespace(&mut self) {
 +        match self.buf.chars().next_back() {
 +            None | Some('\n' | ' ') => {}
 +            _ => self.buf.push(' '),
 +        }
 +    }
 +
 +    fn newline(&mut self) {
 +        match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() {
 +            Some('\n') | None => {}
 +            _ => writeln!(self).unwrap(),
 +        }
 +    }
 +
 +    fn print_expr(&mut self, expr: ExprId) {
 +        let expr = &self.body[expr];
 +
 +        match expr {
 +            Expr::Missing => w!(self, "�"),
 +            Expr::Underscore => w!(self, "_"),
 +            Expr::Path(path) => self.print_path(path),
 +            Expr::If { condition, then_branch, else_branch } => {
 +                w!(self, "if ");
 +                self.print_expr(*condition);
 +                w!(self, " ");
 +                self.print_expr(*then_branch);
 +                if let Some(els) = *else_branch {
 +                    w!(self, " else ");
 +                    self.print_expr(els);
 +                }
 +            }
 +            Expr::Let { pat, expr } => {
 +                w!(self, "let ");
 +                self.print_pat(*pat);
 +                w!(self, " = ");
 +                self.print_expr(*expr);
 +            }
 +            Expr::Loop { body, label } => {
 +                if let Some(lbl) = label {
 +                    w!(self, "{}: ", self.body[*lbl].name);
 +                }
 +                w!(self, "loop ");
 +                self.print_expr(*body);
 +            }
 +            Expr::While { condition, body, label } => {
 +                if let Some(lbl) = label {
 +                    w!(self, "{}: ", self.body[*lbl].name);
 +                }
 +                w!(self, "while ");
 +                self.print_expr(*condition);
 +                self.print_expr(*body);
 +            }
 +            Expr::For { iterable, pat, body, label } => {
 +                if let Some(lbl) = label {
 +                    w!(self, "{}: ", self.body[*lbl].name);
 +                }
 +                w!(self, "for ");
 +                self.print_pat(*pat);
 +                w!(self, " in ");
 +                self.print_expr(*iterable);
 +                self.print_expr(*body);
 +            }
 +            Expr::Call { callee, args, is_assignee_expr: _ } => {
 +                self.print_expr(*callee);
 +                w!(self, "(");
 +                if !args.is_empty() {
 +                    self.indented(|p| {
 +                        for arg in &**args {
 +                            p.print_expr(*arg);
 +                            wln!(p, ",");
 +                        }
 +                    });
 +                }
 +                w!(self, ")");
 +            }
 +            Expr::MethodCall { receiver, method_name, args, generic_args } => {
 +                self.print_expr(*receiver);
 +                w!(self, ".{}", method_name);
 +                if let Some(args) = generic_args {
 +                    w!(self, "::<");
 +                    print_generic_args(args, self).unwrap();
 +                    w!(self, ">");
 +                }
 +                w!(self, "(");
 +                if !args.is_empty() {
 +                    self.indented(|p| {
 +                        for arg in &**args {
 +                            p.print_expr(*arg);
 +                            wln!(p, ",");
 +                        }
 +                    });
 +                }
 +                w!(self, ")");
 +            }
 +            Expr::Match { expr, arms } => {
 +                w!(self, "match ");
 +                self.print_expr(*expr);
 +                w!(self, " {{");
 +                self.indented(|p| {
 +                    for arm in &**arms {
 +                        p.print_pat(arm.pat);
 +                        if let Some(guard) = arm.guard {
 +                            w!(p, " if ");
 +                            p.print_expr(guard);
 +                        }
 +                        w!(p, " => ");
 +                        p.print_expr(arm.expr);
 +                        wln!(p, ",");
 +                    }
 +                });
 +                wln!(self, "}}");
 +            }
 +            Expr::Continue { label } => {
 +                w!(self, "continue");
 +                if let Some(label) = label {
 +                    w!(self, " {}", label);
 +                }
 +            }
 +            Expr::Break { expr, label } => {
 +                w!(self, "break");
 +                if let Some(label) = label {
 +                    w!(self, " {}", label);
 +                }
 +                if let Some(expr) = expr {
 +                    self.whitespace();
 +                    self.print_expr(*expr);
 +                }
 +            }
 +            Expr::Return { expr } => {
 +                w!(self, "return");
 +                if let Some(expr) = expr {
 +                    self.whitespace();
 +                    self.print_expr(*expr);
 +                }
 +            }
 +            Expr::Yield { expr } => {
 +                w!(self, "yield");
 +                if let Some(expr) = expr {
 +                    self.whitespace();
 +                    self.print_expr(*expr);
 +                }
 +            }
 +            Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => {
 +                match path {
 +                    Some(path) => self.print_path(path),
 +                    None => w!(self, "�"),
 +                }
 +
 +                w!(self, "{{");
 +                self.indented(|p| {
 +                    for field in &**fields {
 +                        w!(p, "{}: ", field.name);
 +                        p.print_expr(field.expr);
 +                        wln!(p, ",");
 +                    }
 +                    if let Some(spread) = spread {
 +                        w!(p, "..");
 +                        p.print_expr(*spread);
 +                        wln!(p);
 +                    }
 +                    if *ellipsis {
 +                        wln!(p, "..");
 +                    }
 +                });
 +                w!(self, "}}");
 +            }
 +            Expr::Field { expr, name } => {
 +                self.print_expr(*expr);
 +                w!(self, ".{}", name);
 +            }
 +            Expr::Await { expr } => {
 +                self.print_expr(*expr);
 +                w!(self, ".await");
 +            }
 +            Expr::Try { expr } => {
 +                self.print_expr(*expr);
 +                w!(self, "?");
 +            }
 +            Expr::TryBlock { body } => {
 +                w!(self, "try ");
 +                self.print_expr(*body);
 +            }
 +            Expr::Async { body } => {
 +                w!(self, "async ");
 +                self.print_expr(*body);
 +            }
 +            Expr::Const { body } => {
 +                w!(self, "const ");
 +                self.print_expr(*body);
 +            }
 +            Expr::Cast { expr, type_ref } => {
 +                self.print_expr(*expr);
 +                w!(self, " as ");
 +                self.print_type_ref(type_ref);
 +            }
 +            Expr::Ref { expr, rawness, mutability } => {
 +                w!(self, "&");
 +                if rawness.is_raw() {
 +                    w!(self, "raw ");
 +                }
 +                if mutability.is_mut() {
 +                    w!(self, "mut ");
 +                }
 +                self.print_expr(*expr);
 +            }
 +            Expr::Box { expr } => {
 +                w!(self, "box ");
 +                self.print_expr(*expr);
 +            }
 +            Expr::UnaryOp { expr, op } => {
 +                let op = match op {
 +                    ast::UnaryOp::Deref => "*",
 +                    ast::UnaryOp::Not => "!",
 +                    ast::UnaryOp::Neg => "-",
 +                };
 +                w!(self, "{}", op);
 +                self.print_expr(*expr);
 +            }
 +            Expr::BinaryOp { lhs, rhs, op } => {
 +                let (bra, ket) = match op {
 +                    None | Some(ast::BinaryOp::Assignment { .. }) => ("", ""),
 +                    _ => ("(", ")"),
 +                };
 +                w!(self, "{}", bra);
 +                self.print_expr(*lhs);
 +                w!(self, "{} ", ket);
 +                match op {
 +                    Some(op) => w!(self, "{}", op),
 +                    None => w!(self, "�"), // :)
 +                }
 +                w!(self, " {}", bra);
 +                self.print_expr(*rhs);
 +                w!(self, "{}", ket);
 +            }
 +            Expr::Range { lhs, rhs, range_type } => {
 +                if let Some(lhs) = lhs {
 +                    w!(self, "(");
 +                    self.print_expr(*lhs);
 +                    w!(self, ") ");
 +                }
 +                let range = match range_type {
 +                    ast::RangeOp::Exclusive => "..",
 +                    ast::RangeOp::Inclusive => "..=",
 +                };
 +                w!(self, "{}", range);
 +                if let Some(rhs) = rhs {
 +                    w!(self, "(");
 +                    self.print_expr(*rhs);
 +                    w!(self, ") ");
 +                }
 +            }
 +            Expr::Index { base, index } => {
 +                self.print_expr(*base);
 +                w!(self, "[");
 +                self.print_expr(*index);
 +                w!(self, "]");
 +            }
 +            Expr::Closure { args, arg_types, ret_type, body } => {
 +                w!(self, "|");
 +                for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
 +                    if i != 0 {
 +                        w!(self, ", ");
 +                    }
 +                    self.print_pat(*pat);
 +                    if let Some(ty) = ty {
 +                        w!(self, ": ");
 +                        self.print_type_ref(ty);
 +                    }
 +                }
 +                w!(self, "|");
 +                if let Some(ret_ty) = ret_type {
 +                    w!(self, " -> ");
 +                    self.print_type_ref(ret_ty);
 +                }
 +                self.whitespace();
 +                self.print_expr(*body);
 +            }
 +            Expr::Tuple { exprs, is_assignee_expr: _ } => {
 +                w!(self, "(");
 +                for expr in exprs.iter() {
 +                    self.print_expr(*expr);
 +                    w!(self, ", ");
 +                }
 +                w!(self, ")");
 +            }
 +            Expr::Unsafe { body } => {
 +                w!(self, "unsafe ");
 +                self.print_expr(*body);
 +            }
 +            Expr::Array(arr) => {
 +                w!(self, "[");
 +                if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) {
 +                    self.indented(|p| match arr {
 +                        Array::ElementList { elements, is_assignee_expr: _ } => {
 +                            for elem in elements.iter() {
 +                                p.print_expr(*elem);
 +                                w!(p, ", ");
 +                            }
 +                        }
 +                        Array::Repeat { initializer, repeat } => {
 +                            p.print_expr(*initializer);
 +                            w!(p, "; ");
 +                            p.print_expr(*repeat);
 +                        }
 +                    });
 +                    self.newline();
 +                }
 +                w!(self, "]");
 +            }
 +            Expr::Literal(lit) => self.print_literal(lit),
 +            Expr::Block { id: _, statements, tail, label } => {
 +                self.whitespace();
 +                if let Some(lbl) = label {
 +                    w!(self, "{}: ", self.body[*lbl].name);
 +                }
 +                w!(self, "{{");
 +                if !statements.is_empty() || tail.is_some() {
 +                    self.indented(|p| {
 +                        for stmt in &**statements {
 +                            p.print_stmt(stmt);
 +                        }
 +                        if let Some(tail) = tail {
 +                            p.print_expr(*tail);
 +                        }
 +                        p.newline();
 +                    });
 +                }
 +                w!(self, "}}");
 +            }
 +        }
 +    }
 +
 +    fn print_pat(&mut self, pat: PatId) {
 +        let pat = &self.body[pat];
 +
 +        match pat {
 +            Pat::Missing => w!(self, "�"),
 +            Pat::Wild => w!(self, "_"),
 +            Pat::Tuple { args, ellipsis } => {
 +                w!(self, "(");
 +                for (i, pat) in args.iter().enumerate() {
 +                    if i != 0 {
 +                        w!(self, ", ");
 +                    }
 +                    if *ellipsis == Some(i) {
 +                        w!(self, ".., ");
 +                    }
 +                    self.print_pat(*pat);
 +                }
 +                w!(self, ")");
 +            }
 +            Pat::Or(pats) => {
 +                for (i, pat) in pats.iter().enumerate() {
 +                    if i != 0 {
 +                        w!(self, " | ");
 +                    }
 +                    self.print_pat(*pat);
 +                }
 +            }
 +            Pat::Record { path, args, ellipsis } => {
 +                match path {
 +                    Some(path) => self.print_path(path),
 +                    None => w!(self, "�"),
 +                }
 +
 +                w!(self, " {{");
 +                self.indented(|p| {
 +                    for arg in args.iter() {
 +                        w!(p, "{}: ", arg.name);
 +                        p.print_pat(arg.pat);
 +                        wln!(p, ",");
 +                    }
 +                    if *ellipsis {
 +                        wln!(p, "..");
 +                    }
 +                });
 +                w!(self, "}}");
 +            }
 +            Pat::Range { start, end } => {
 +                self.print_expr(*start);
 +                w!(self, "...");
 +                self.print_expr(*end);
 +            }
 +            Pat::Slice { prefix, slice, suffix } => {
 +                w!(self, "[");
 +                for pat in prefix.iter() {
 +                    self.print_pat(*pat);
 +                    w!(self, ", ");
 +                }
 +                if let Some(pat) = slice {
 +                    self.print_pat(*pat);
 +                    w!(self, ", ");
 +                }
 +                for pat in suffix.iter() {
 +                    self.print_pat(*pat);
 +                    w!(self, ", ");
 +                }
 +                w!(self, "]");
 +            }
 +            Pat::Path(path) => self.print_path(path),
 +            Pat::Lit(expr) => self.print_expr(*expr),
 +            Pat::Bind { mode, name, subpat } => {
 +                let mode = match mode {
 +                    BindingAnnotation::Unannotated => "",
 +                    BindingAnnotation::Mutable => "mut ",
 +                    BindingAnnotation::Ref => "ref ",
 +                    BindingAnnotation::RefMut => "ref mut ",
 +                };
 +                w!(self, "{}{}", mode, name);
 +                if let Some(pat) = subpat {
 +                    self.whitespace();
 +                    self.print_pat(*pat);
 +                }
 +            }
 +            Pat::TupleStruct { path, args, ellipsis } => {
 +                match path {
 +                    Some(path) => self.print_path(path),
 +                    None => w!(self, "�"),
 +                }
 +                w!(self, "(");
 +                for (i, arg) in args.iter().enumerate() {
 +                    if i != 0 {
 +                        w!(self, ", ");
 +                    }
 +                    if *ellipsis == Some(i) {
 +                        w!(self, ", ..");
 +                    }
 +                    self.print_pat(*arg);
 +                }
 +                w!(self, ")");
 +            }
 +            Pat::Ref { pat, mutability } => {
 +                w!(self, "&");
 +                if mutability.is_mut() {
 +                    w!(self, "mut ");
 +                }
 +                self.print_pat(*pat);
 +            }
 +            Pat::Box { inner } => {
 +                w!(self, "box ");
 +                self.print_pat(*inner);
 +            }
 +            Pat::ConstBlock(c) => {
 +                w!(self, "const ");
 +                self.print_expr(*c);
 +            }
 +        }
 +    }
 +
 +    fn print_stmt(&mut self, stmt: &Statement) {
 +        match stmt {
 +            Statement::Let { pat, type_ref, initializer, else_branch } => {
 +                w!(self, "let ");
 +                self.print_pat(*pat);
 +                if let Some(ty) = type_ref {
 +                    w!(self, ": ");
 +                    self.print_type_ref(ty);
 +                }
 +                if let Some(init) = initializer {
 +                    w!(self, " = ");
 +                    self.print_expr(*init);
 +                }
 +                if let Some(els) = else_branch {
 +                    w!(self, " else ");
 +                    self.print_expr(*els);
 +                }
 +                wln!(self, ";");
 +            }
 +            Statement::Expr { expr, has_semi } => {
 +                self.print_expr(*expr);
 +                if *has_semi {
 +                    w!(self, ";");
 +                }
 +                wln!(self);
 +            }
 +        }
 +    }
 +
 +    fn print_literal(&mut self, literal: &Literal) {
 +        match literal {
 +            Literal::String(it) => w!(self, "{:?}", it),
 +            Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()),
 +            Literal::Char(it) => w!(self, "'{}'", it.escape_debug()),
 +            Literal::Bool(it) => w!(self, "{}", it),
 +            Literal::Int(i, suffix) => {
 +                w!(self, "{}", i);
 +                if let Some(suffix) = suffix {
 +                    w!(self, "{}", suffix);
 +                }
 +            }
 +            Literal::Uint(i, suffix) => {
 +                w!(self, "{}", i);
 +                if let Some(suffix) = suffix {
 +                    w!(self, "{}", suffix);
 +                }
 +            }
 +            Literal::Float(f, suffix) => {
 +                w!(self, "{}", f);
 +                if let Some(suffix) = suffix {
 +                    w!(self, "{}", suffix);
 +                }
 +            }
 +        }
 +    }
 +
 +    fn print_type_ref(&mut self, ty: &TypeRef) {
 +        print_type_ref(ty, self).unwrap();
 +    }
 +
 +    fn print_path(&mut self, path: &Path) {
 +        print_path(path, self).unwrap();
 +    }
 +}
index f4c390dce26e0520168594430508281406137c3f,0000000000000000000000000000000000000000..45f64ebb06007b7c5cf1a414d02930d5a12b203a
mode 100644,000000..100644
--- /dev/null
@@@ -1,571 -1,0 +1,579 @@@
-         Arc::new(ExprScopes::new(&*body))
-     }
-     fn new(body: &Body) -> ExprScopes {
-         let mut scopes =
-             ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() };
-         let mut root = scopes.root_scope();
-         scopes.add_params_bindings(body, root, &body.params);
-         compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
-         scopes
 +//! Name resolution for expressions.
 +use std::sync::Arc;
 +
 +use hir_expand::name::Name;
 +use la_arena::{Arena, Idx};
 +use rustc_hash::FxHashMap;
 +
 +use crate::{
 +    body::Body,
 +    db::DefDatabase,
 +    expr::{Expr, ExprId, LabelId, Pat, PatId, Statement},
 +    BlockId, DefWithBodyId,
 +};
 +
 +pub type ScopeId = Idx<ScopeData>;
 +
 +#[derive(Debug, PartialEq, Eq)]
 +pub struct ExprScopes {
 +    scopes: Arena<ScopeData>,
 +    scope_by_expr: FxHashMap<ExprId, ScopeId>,
 +}
 +
 +#[derive(Debug, PartialEq, Eq)]
 +pub struct ScopeEntry {
 +    name: Name,
 +    pat: PatId,
 +}
 +
 +impl ScopeEntry {
 +    pub fn name(&self) -> &Name {
 +        &self.name
 +    }
 +
 +    pub fn pat(&self) -> PatId {
 +        self.pat
 +    }
 +}
 +
 +#[derive(Debug, PartialEq, Eq)]
 +pub struct ScopeData {
 +    parent: Option<ScopeId>,
 +    block: Option<BlockId>,
 +    label: Option<(LabelId, Name)>,
 +    entries: Vec<ScopeEntry>,
 +}
 +
 +impl ExprScopes {
 +    pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> {
 +        let body = db.body(def);
-         Expr::MacroStmts { statements, tail } => {
-             compute_block_scopes(statements, *tail, body, scopes, scope);
-         }
++        let mut scopes = ExprScopes::new(&*body);
++        scopes.shrink_to_fit();
++        Arc::new(scopes)
 +    }
 +
 +    pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
 +        &self.scopes[scope].entries
 +    }
 +
 +    /// If `scope` refers to a block expression scope, returns the corresponding `BlockId`.
 +    pub fn block(&self, scope: ScopeId) -> Option<BlockId> {
 +        self.scopes[scope].block
 +    }
 +
 +    /// If `scope` refers to a labeled expression scope, returns the corresponding `Label`.
 +    pub fn label(&self, scope: ScopeId) -> Option<(LabelId, Name)> {
 +        self.scopes[scope].label.clone()
 +    }
 +
 +    pub fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ {
 +        std::iter::successors(scope, move |&scope| self.scopes[scope].parent)
 +    }
 +
 +    pub fn resolve_name_in_scope(&self, scope: ScopeId, name: &Name) -> Option<&ScopeEntry> {
 +        self.scope_chain(Some(scope))
 +            .find_map(|scope| self.entries(scope).iter().find(|it| it.name == *name))
 +    }
 +
 +    pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> {
 +        self.scope_by_expr.get(&expr).copied()
 +    }
 +
 +    pub fn scope_by_expr(&self) -> &FxHashMap<ExprId, ScopeId> {
 +        &self.scope_by_expr
 +    }
++}
++
++impl ExprScopes {
++    fn new(body: &Body) -> ExprScopes {
++        let mut scopes =
++            ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() };
++        let mut root = scopes.root_scope();
++        scopes.add_params_bindings(body, root, &body.params);
++        compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
++        scopes
++    }
 +
 +    fn root_scope(&mut self) -> ScopeId {
 +        self.scopes.alloc(ScopeData { parent: None, block: None, label: None, entries: vec![] })
 +    }
 +
 +    fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
 +        self.scopes.alloc(ScopeData {
 +            parent: Some(parent),
 +            block: None,
 +            label: None,
 +            entries: vec![],
 +        })
 +    }
 +
 +    fn new_labeled_scope(&mut self, parent: ScopeId, label: Option<(LabelId, Name)>) -> ScopeId {
 +        self.scopes.alloc(ScopeData { parent: Some(parent), block: None, label, entries: vec![] })
 +    }
 +
 +    fn new_block_scope(
 +        &mut self,
 +        parent: ScopeId,
 +        block: BlockId,
 +        label: Option<(LabelId, Name)>,
 +    ) -> ScopeId {
 +        self.scopes.alloc(ScopeData {
 +            parent: Some(parent),
 +            block: Some(block),
 +            label,
 +            entries: vec![],
 +        })
 +    }
 +
 +    fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
 +        let pattern = &body[pat];
 +        if let Pat::Bind { name, .. } = pattern {
 +            let entry = ScopeEntry { name: name.clone(), pat };
 +            self.scopes[scope].entries.push(entry);
 +        }
 +
 +        pattern.walk_child_pats(|pat| self.add_bindings(body, scope, pat));
 +    }
 +
 +    fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) {
 +        params.iter().for_each(|pat| self.add_bindings(body, scope, *pat));
 +    }
 +
 +    fn set_scope(&mut self, node: ExprId, scope: ScopeId) {
 +        self.scope_by_expr.insert(node, scope);
 +    }
++
++    fn shrink_to_fit(&mut self) {
++        let ExprScopes { scopes, scope_by_expr } = self;
++        scopes.shrink_to_fit();
++        scopes.values_mut().for_each(|it| it.entries.shrink_to_fit());
++        scope_by_expr.shrink_to_fit();
++    }
 +}
 +
 +fn compute_block_scopes(
 +    statements: &[Statement],
 +    tail: Option<ExprId>,
 +    body: &Body,
 +    scopes: &mut ExprScopes,
 +    scope: &mut ScopeId,
 +) {
 +    for stmt in statements {
 +        match stmt {
 +            Statement::Let { pat, initializer, else_branch, .. } => {
 +                if let Some(expr) = initializer {
 +                    compute_expr_scopes(*expr, body, scopes, scope);
 +                }
 +                if let Some(expr) = else_branch {
 +                    compute_expr_scopes(*expr, body, scopes, scope);
 +                }
 +
 +                *scope = scopes.new_scope(*scope);
 +                scopes.add_bindings(body, *scope, *pat);
 +            }
 +            Statement::Expr { expr, .. } => {
 +                compute_expr_scopes(*expr, body, scopes, scope);
 +            }
 +        }
 +    }
 +    if let Some(expr) = tail {
 +        compute_expr_scopes(expr, body, scopes, scope);
 +    }
 +}
 +
 +fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: &mut ScopeId) {
 +    let make_label =
 +        |label: &Option<LabelId>| label.map(|label| (label, body.labels[label].name.clone()));
 +
 +    scopes.set_scope(expr, *scope);
 +    match &body[expr] {
 +        Expr::Block { statements, tail, id, label } => {
 +            let mut scope = scopes.new_block_scope(*scope, *id, make_label(label));
 +            // Overwrite the old scope for the block expr, so that every block scope can be found
 +            // via the block itself (important for blocks that only contain items, no expressions).
 +            scopes.set_scope(expr, scope);
 +            compute_block_scopes(statements, *tail, body, scopes, &mut scope);
 +        }
 +        Expr::For { iterable, pat, body: body_expr, label } => {
 +            compute_expr_scopes(*iterable, body, scopes, scope);
 +            let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
 +            scopes.add_bindings(body, scope, *pat);
 +            compute_expr_scopes(*body_expr, body, scopes, &mut scope);
 +        }
 +        Expr::While { condition, body: body_expr, label } => {
 +            let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
 +            compute_expr_scopes(*condition, body, scopes, &mut scope);
 +            compute_expr_scopes(*body_expr, body, scopes, &mut scope);
 +        }
 +        Expr::Loop { body: body_expr, label } => {
 +            let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
 +            compute_expr_scopes(*body_expr, body, scopes, &mut scope);
 +        }
 +        Expr::Closure { args, body: body_expr, .. } => {
 +            let mut scope = scopes.new_scope(*scope);
 +            scopes.add_params_bindings(body, scope, args);
 +            compute_expr_scopes(*body_expr, body, scopes, &mut scope);
 +        }
 +        Expr::Match { expr, arms } => {
 +            compute_expr_scopes(*expr, body, scopes, scope);
 +            for arm in arms.iter() {
 +                let mut scope = scopes.new_scope(*scope);
 +                scopes.add_bindings(body, scope, arm.pat);
 +                if let Some(guard) = arm.guard {
 +                    scope = scopes.new_scope(scope);
 +                    compute_expr_scopes(guard, body, scopes, &mut scope);
 +                }
 +                compute_expr_scopes(arm.expr, body, scopes, &mut scope);
 +            }
 +        }
 +        &Expr::If { condition, then_branch, else_branch } => {
 +            let mut then_branch_scope = scopes.new_scope(*scope);
 +            compute_expr_scopes(condition, body, scopes, &mut then_branch_scope);
 +            compute_expr_scopes(then_branch, body, scopes, &mut then_branch_scope);
 +            if let Some(else_branch) = else_branch {
 +                compute_expr_scopes(else_branch, body, scopes, scope);
 +            }
 +        }
 +        &Expr::Let { pat, expr } => {
 +            compute_expr_scopes(expr, body, scopes, scope);
 +            *scope = scopes.new_scope(*scope);
 +            scopes.add_bindings(body, *scope, pat);
 +        }
 +        e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)),
 +    };
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use base_db::{fixture::WithFixture, FileId, SourceDatabase};
 +    use hir_expand::{name::AsName, InFile};
 +    use syntax::{algo::find_node_at_offset, ast, AstNode};
 +    use test_utils::{assert_eq_text, extract_offset};
 +
 +    use crate::{db::DefDatabase, test_db::TestDB, FunctionId, ModuleDefId};
 +
 +    fn find_function(db: &TestDB, file_id: FileId) -> FunctionId {
 +        let krate = db.test_crate();
 +        let crate_def_map = db.crate_def_map(krate);
 +
 +        let module = crate_def_map.modules_for_file(file_id).next().unwrap();
 +        let (_, def) = crate_def_map[module].scope.entries().next().unwrap();
 +        match def.take_values().unwrap() {
 +            ModuleDefId::FunctionId(it) => it,
 +            _ => panic!(),
 +        }
 +    }
 +
 +    fn do_check(ra_fixture: &str, expected: &[&str]) {
 +        let (offset, code) = extract_offset(ra_fixture);
 +        let code = {
 +            let mut buf = String::new();
 +            let off: usize = offset.into();
 +            buf.push_str(&code[..off]);
 +            buf.push_str("$0marker");
 +            buf.push_str(&code[off..]);
 +            buf
 +        };
 +
 +        let (db, position) = TestDB::with_position(&code);
 +        let file_id = position.file_id;
 +        let offset = position.offset;
 +
 +        let file_syntax = db.parse(file_id).syntax_node();
 +        let marker: ast::PathExpr = find_node_at_offset(&file_syntax, offset).unwrap();
 +        let function = find_function(&db, file_id);
 +
 +        let scopes = db.expr_scopes(function.into());
 +        let (_body, source_map) = db.body_with_source_map(function.into());
 +
 +        let expr_id = source_map
 +            .node_expr(InFile { file_id: file_id.into(), value: &marker.into() })
 +            .unwrap();
 +        let scope = scopes.scope_for(expr_id);
 +
 +        let actual = scopes
 +            .scope_chain(scope)
 +            .flat_map(|scope| scopes.entries(scope))
 +            .map(|it| it.name().to_smol_str())
 +            .collect::<Vec<_>>()
 +            .join("\n");
 +        let expected = expected.join("\n");
 +        assert_eq_text!(&expected, &actual);
 +    }
 +
 +    #[test]
 +    fn test_lambda_scope() {
 +        do_check(
 +            r"
 +            fn quux(foo: i32) {
 +                let f = |bar, baz: i32| {
 +                    $0
 +                };
 +            }",
 +            &["bar", "baz", "foo"],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_call_scope() {
 +        do_check(
 +            r"
 +            fn quux() {
 +                f(|x| $0 );
 +            }",
 +            &["x"],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_method_call_scope() {
 +        do_check(
 +            r"
 +            fn quux() {
 +                z.f(|x| $0 );
 +            }",
 +            &["x"],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_loop_scope() {
 +        do_check(
 +            r"
 +            fn quux() {
 +                loop {
 +                    let x = ();
 +                    $0
 +                };
 +            }",
 +            &["x"],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_match() {
 +        do_check(
 +            r"
 +            fn quux() {
 +                match () {
 +                    Some(x) => {
 +                        $0
 +                    }
 +                };
 +            }",
 +            &["x"],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_shadow_variable() {
 +        do_check(
 +            r"
 +            fn foo(x: String) {
 +                let x : &str = &x$0;
 +            }",
 +            &["x"],
 +        );
 +    }
 +
 +    #[test]
 +    fn test_bindings_after_at() {
 +        do_check(
 +            r"
 +fn foo() {
 +    match Some(()) {
 +        opt @ Some(unit) => {
 +            $0
 +        }
 +        _ => {}
 +    }
 +}
 +",
 +            &["opt", "unit"],
 +        );
 +    }
 +
 +    #[test]
 +    fn macro_inner_item() {
 +        do_check(
 +            r"
 +            macro_rules! mac {
 +                () => {{
 +                    fn inner() {}
 +                    inner();
 +                }};
 +            }
 +
 +            fn foo() {
 +                mac!();
 +                $0
 +            }
 +        ",
 +            &[],
 +        );
 +    }
 +
 +    #[test]
 +    fn broken_inner_item() {
 +        do_check(
 +            r"
 +            fn foo() {
 +                trait {}
 +                $0
 +            }
 +        ",
 +            &[],
 +        );
 +    }
 +
 +    fn do_check_local_name(ra_fixture: &str, expected_offset: u32) {
 +        let (db, position) = TestDB::with_position(ra_fixture);
 +        let file_id = position.file_id;
 +        let offset = position.offset;
 +
 +        let file = db.parse(file_id).ok().unwrap();
 +        let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into())
 +            .expect("failed to find a name at the target offset");
 +        let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), offset).unwrap();
 +
 +        let function = find_function(&db, file_id);
 +
 +        let scopes = db.expr_scopes(function.into());
 +        let (_body, source_map) = db.body_with_source_map(function.into());
 +
 +        let expr_scope = {
 +            let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap();
 +            let expr_id =
 +                source_map.node_expr(InFile { file_id: file_id.into(), value: &expr_ast }).unwrap();
 +            scopes.scope_for(expr_id).unwrap()
 +        };
 +
 +        let resolved = scopes.resolve_name_in_scope(expr_scope, &name_ref.as_name()).unwrap();
 +        let pat_src = source_map.pat_syntax(resolved.pat()).unwrap();
 +
 +        let local_name = pat_src.value.either(
 +            |it| it.syntax_node_ptr().to_node(file.syntax()),
 +            |it| it.syntax_node_ptr().to_node(file.syntax()),
 +        );
 +        assert_eq!(local_name.text_range(), expected_name.syntax().text_range());
 +    }
 +
 +    #[test]
 +    fn test_resolve_local_name() {
 +        do_check_local_name(
 +            r#"
 +fn foo(x: i32, y: u32) {
 +    {
 +        let z = x * 2;
 +    }
 +    {
 +        let t = x$0 * 3;
 +    }
 +}
 +"#,
 +            7,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_resolve_local_name_declaration() {
 +        do_check_local_name(
 +            r#"
 +fn foo(x: String) {
 +    let x : &str = &x$0;
 +}
 +"#,
 +            7,
 +        );
 +    }
 +
 +    #[test]
 +    fn test_resolve_local_name_shadow() {
 +        do_check_local_name(
 +            r"
 +fn foo(x: String) {
 +    let x : &str = &x;
 +    x$0
 +}
 +",
 +            28,
 +        );
 +    }
 +
 +    #[test]
 +    fn ref_patterns_contribute_bindings() {
 +        do_check_local_name(
 +            r"
 +fn foo() {
 +    if let Some(&from) = bar() {
 +        from$0;
 +    }
 +}
 +",
 +            28,
 +        );
 +    }
 +
 +    #[test]
 +    fn while_let_adds_binding() {
 +        do_check_local_name(
 +            r#"
 +fn test() {
 +    let foo: Option<f32> = None;
 +    while let Option::Some(spam) = foo {
 +        spam$0
 +    }
 +}
 +"#,
 +            75,
 +        );
 +        do_check_local_name(
 +            r#"
 +fn test() {
 +    let foo: Option<f32> = None;
 +    while (((let Option::Some(_) = foo))) && let Option::Some(spam) = foo {
 +        spam$0
 +    }
 +}
 +"#,
 +            107,
 +        );
 +    }
 +
 +    #[test]
 +    fn match_guard_if_let() {
 +        do_check_local_name(
 +            r#"
 +fn test() {
 +    let foo: Option<f32> = None;
 +    match foo {
 +        _ if let Option::Some(spam) = foo => spam$0,
 +    }
 +}
 +"#,
 +            93,
 +        );
 +    }
 +
 +    #[test]
 +    fn let_chains_can_reference_previous_lets() {
 +        do_check_local_name(
 +            r#"
 +fn test() {
 +    let foo: Option<i32> = None;
 +    if let Some(spam) = foo && spa$0m > 1 && let Some(spam) = foo && spam > 1 {}
 +}
 +"#,
 +            61,
 +        );
 +        do_check_local_name(
 +            r#"
 +fn test() {
 +    let foo: Option<i32> = None;
 +    if let Some(spam) = foo && spam > 1 && let Some(spam) = foo && sp$0am > 1 {}
 +}
 +"#,
 +            100,
 +        );
 +    }
 +}
index 4381b43c258bfe90a9387e10f7608981090105f8,0000000000000000000000000000000000000000..419d3feec3b6c2240c8be326edb0ad24a402c9eb
mode 100644,000000..100644
--- /dev/null
@@@ -1,446 -1,0 +1,442 @@@
-     MacroStmts {
-         statements: Box<[Statement]>,
-         tail: Option<ExprId>,
-     },
 +//! This module describes hir-level representation of expressions.
 +//!
 +//! This representation is:
 +//!
 +//! 1. Identity-based. Each expression has an `id`, so we can distinguish
 +//!    between different `1` in `1 + 1`.
 +//! 2. Independent of syntax. Though syntactic provenance information can be
 +//!    attached separately via id-based side map.
 +//! 3. Unresolved. Paths are stored as sequences of names, and not as defs the
 +//!    names refer to.
 +//! 4. Desugared. There's no `if let`.
 +//!
 +//! See also a neighboring `body` module.
 +
 +use std::fmt;
 +
 +use hir_expand::name::Name;
 +use la_arena::{Idx, RawIdx};
 +
 +use crate::{
 +    builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
 +    intern::Interned,
 +    path::{GenericArgs, Path},
 +    type_ref::{Mutability, Rawness, TypeRef},
 +    BlockId,
 +};
 +
 +pub use syntax::ast::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp};
 +
 +pub type ExprId = Idx<Expr>;
 +
 +/// FIXME: this is a hacky function which should be removed
 +pub(crate) fn dummy_expr_id() -> ExprId {
 +    ExprId::from_raw(RawIdx::from(u32::MAX))
 +}
 +
 +pub type PatId = Idx<Pat>;
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct Label {
 +    pub name: Name,
 +}
 +pub type LabelId = Idx<Label>;
 +
 +// We convert float values into bits and that's how we don't need to deal with f32 and f64.
 +// For PartialEq, bits comparison should work, as ordering is not important
 +// https://github.com/rust-lang/rust-analyzer/issues/12380#issuecomment-1137284360
 +#[derive(Default, Debug, Clone, Eq, PartialEq)]
 +pub struct FloatTypeWrapper(u64);
 +
 +impl FloatTypeWrapper {
 +    pub fn new(value: f64) -> Self {
 +        Self(value.to_bits())
 +    }
 +}
 +
 +impl fmt::Display for FloatTypeWrapper {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        write!(f, "{:?}", f64::from_bits(self.0))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum Literal {
 +    String(Box<str>),
 +    ByteString(Box<[u8]>),
 +    Char(char),
 +    Bool(bool),
 +    Int(i128, Option<BuiltinInt>),
 +    Uint(u128, Option<BuiltinUint>),
 +    // Here we are using a wrapper around float because f32 and f64 do not implement Eq, so they
 +    // could not be used directly here, to understand how the wrapper works go to definition of
 +    // FloatTypeWrapper
 +    Float(FloatTypeWrapper, Option<BuiltinFloat>),
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum Expr {
 +    /// This is produced if the syntax tree does not have a required expression piece.
 +    Missing,
 +    Path(Path),
 +    If {
 +        condition: ExprId,
 +        then_branch: ExprId,
 +        else_branch: Option<ExprId>,
 +    },
 +    Let {
 +        pat: PatId,
 +        expr: ExprId,
 +    },
 +    Block {
 +        id: BlockId,
 +        statements: Box<[Statement]>,
 +        tail: Option<ExprId>,
 +        label: Option<LabelId>,
 +    },
 +    Loop {
 +        body: ExprId,
 +        label: Option<LabelId>,
 +    },
 +    While {
 +        condition: ExprId,
 +        body: ExprId,
 +        label: Option<LabelId>,
 +    },
 +    For {
 +        iterable: ExprId,
 +        pat: PatId,
 +        body: ExprId,
 +        label: Option<LabelId>,
 +    },
 +    Call {
 +        callee: ExprId,
 +        args: Box<[ExprId]>,
 +        is_assignee_expr: bool,
 +    },
 +    MethodCall {
 +        receiver: ExprId,
 +        method_name: Name,
 +        args: Box<[ExprId]>,
 +        generic_args: Option<Box<GenericArgs>>,
 +    },
 +    Match {
 +        expr: ExprId,
 +        arms: Box<[MatchArm]>,
 +    },
 +    Continue {
 +        label: Option<Name>,
 +    },
 +    Break {
 +        expr: Option<ExprId>,
 +        label: Option<Name>,
 +    },
 +    Return {
 +        expr: Option<ExprId>,
 +    },
 +    Yield {
 +        expr: Option<ExprId>,
 +    },
 +    RecordLit {
 +        path: Option<Box<Path>>,
 +        fields: Box<[RecordLitField]>,
 +        spread: Option<ExprId>,
 +        ellipsis: bool,
 +        is_assignee_expr: bool,
 +    },
 +    Field {
 +        expr: ExprId,
 +        name: Name,
 +    },
 +    Await {
 +        expr: ExprId,
 +    },
 +    Try {
 +        expr: ExprId,
 +    },
 +    TryBlock {
 +        body: ExprId,
 +    },
 +    Async {
 +        body: ExprId,
 +    },
 +    Const {
 +        body: ExprId,
 +    },
 +    Cast {
 +        expr: ExprId,
 +        type_ref: Interned<TypeRef>,
 +    },
 +    Ref {
 +        expr: ExprId,
 +        rawness: Rawness,
 +        mutability: Mutability,
 +    },
 +    Box {
 +        expr: ExprId,
 +    },
 +    UnaryOp {
 +        expr: ExprId,
 +        op: UnaryOp,
 +    },
 +    BinaryOp {
 +        lhs: ExprId,
 +        rhs: ExprId,
 +        op: Option<BinaryOp>,
 +    },
 +    Range {
 +        lhs: Option<ExprId>,
 +        rhs: Option<ExprId>,
 +        range_type: RangeOp,
 +    },
 +    Index {
 +        base: ExprId,
 +        index: ExprId,
 +    },
 +    Closure {
 +        args: Box<[PatId]>,
 +        arg_types: Box<[Option<Interned<TypeRef>>]>,
 +        ret_type: Option<Interned<TypeRef>>,
 +        body: ExprId,
 +    },
 +    Tuple {
 +        exprs: Box<[ExprId]>,
 +        is_assignee_expr: bool,
 +    },
 +    Unsafe {
 +        body: ExprId,
 +    },
-             Expr::MacroStmts { tail, statements } | Expr::Block { statements, tail, .. } => {
 +    Array(Array),
 +    Literal(Literal),
 +    Underscore,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum Array {
 +    ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
 +    Repeat { initializer: ExprId, repeat: ExprId },
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct MatchArm {
 +    pub pat: PatId,
 +    pub guard: Option<ExprId>,
 +    pub expr: ExprId,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct RecordLitField {
 +    pub name: Name,
 +    pub expr: ExprId,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum Statement {
 +    Let {
 +        pat: PatId,
 +        type_ref: Option<Interned<TypeRef>>,
 +        initializer: Option<ExprId>,
 +        else_branch: Option<ExprId>,
 +    },
 +    Expr {
 +        expr: ExprId,
 +        has_semi: bool,
 +    },
 +}
 +
 +impl Expr {
 +    pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
 +        match self {
 +            Expr::Missing => {}
 +            Expr::Path(_) => {}
 +            Expr::If { condition, then_branch, else_branch } => {
 +                f(*condition);
 +                f(*then_branch);
 +                if let &Some(else_branch) = else_branch {
 +                    f(else_branch);
 +                }
 +            }
 +            Expr::Let { expr, .. } => {
 +                f(*expr);
 +            }
++            Expr::Block { statements, tail, .. } => {
 +                for stmt in statements.iter() {
 +                    match stmt {
 +                        Statement::Let { initializer, .. } => {
 +                            if let &Some(expr) = initializer {
 +                                f(expr);
 +                            }
 +                        }
 +                        Statement::Expr { expr: expression, .. } => f(*expression),
 +                    }
 +                }
 +                if let &Some(expr) = tail {
 +                    f(expr);
 +                }
 +            }
 +            Expr::TryBlock { body }
 +            | Expr::Unsafe { body }
 +            | Expr::Async { body }
 +            | Expr::Const { body } => f(*body),
 +            Expr::Loop { body, .. } => f(*body),
 +            Expr::While { condition, body, .. } => {
 +                f(*condition);
 +                f(*body);
 +            }
 +            Expr::For { iterable, body, .. } => {
 +                f(*iterable);
 +                f(*body);
 +            }
 +            Expr::Call { callee, args, .. } => {
 +                f(*callee);
 +                args.iter().copied().for_each(f);
 +            }
 +            Expr::MethodCall { receiver, args, .. } => {
 +                f(*receiver);
 +                args.iter().copied().for_each(f);
 +            }
 +            Expr::Match { expr, arms } => {
 +                f(*expr);
 +                arms.iter().map(|arm| arm.expr).for_each(f);
 +            }
 +            Expr::Continue { .. } => {}
 +            Expr::Break { expr, .. } | Expr::Return { expr } | Expr::Yield { expr } => {
 +                if let &Some(expr) = expr {
 +                    f(expr);
 +                }
 +            }
 +            Expr::RecordLit { fields, spread, .. } => {
 +                for field in fields.iter() {
 +                    f(field.expr);
 +                }
 +                if let &Some(expr) = spread {
 +                    f(expr);
 +                }
 +            }
 +            Expr::Closure { body, .. } => {
 +                f(*body);
 +            }
 +            Expr::BinaryOp { lhs, rhs, .. } => {
 +                f(*lhs);
 +                f(*rhs);
 +            }
 +            Expr::Range { lhs, rhs, .. } => {
 +                if let &Some(lhs) = rhs {
 +                    f(lhs);
 +                }
 +                if let &Some(rhs) = lhs {
 +                    f(rhs);
 +                }
 +            }
 +            Expr::Index { base, index } => {
 +                f(*base);
 +                f(*index);
 +            }
 +            Expr::Field { expr, .. }
 +            | Expr::Await { expr }
 +            | Expr::Try { expr }
 +            | Expr::Cast { expr, .. }
 +            | Expr::Ref { expr, .. }
 +            | Expr::UnaryOp { expr, .. }
 +            | Expr::Box { expr } => {
 +                f(*expr);
 +            }
 +            Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
 +            Expr::Array(a) => match a {
 +                Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
 +                Array::Repeat { initializer, repeat } => {
 +                    f(*initializer);
 +                    f(*repeat)
 +                }
 +            },
 +            Expr::Literal(_) => {}
 +            Expr::Underscore => {}
 +        }
 +    }
 +}
 +
 +/// Explicit binding annotations given in the HIR for a binding. Note
 +/// that this is not the final binding *mode* that we infer after type
 +/// inference.
 +#[derive(Clone, PartialEq, Eq, Debug, Copy)]
 +pub enum BindingAnnotation {
 +    /// No binding annotation given: this means that the final binding mode
 +    /// will depend on whether we have skipped through a `&` reference
 +    /// when matching. For example, the `x` in `Some(x)` will have binding
 +    /// mode `None`; if you do `let Some(x) = &Some(22)`, it will
 +    /// ultimately be inferred to be by-reference.
 +    Unannotated,
 +
 +    /// Annotated with `mut x` -- could be either ref or not, similar to `None`.
 +    Mutable,
 +
 +    /// Annotated as `ref`, like `ref x`
 +    Ref,
 +
 +    /// Annotated as `ref mut x`.
 +    RefMut,
 +}
 +
 +impl BindingAnnotation {
 +    pub fn new(is_mutable: bool, is_ref: bool) -> Self {
 +        match (is_mutable, is_ref) {
 +            (true, true) => BindingAnnotation::RefMut,
 +            (false, true) => BindingAnnotation::Ref,
 +            (true, false) => BindingAnnotation::Mutable,
 +            (false, false) => BindingAnnotation::Unannotated,
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct RecordFieldPat {
 +    pub name: Name,
 +    pub pat: PatId,
 +}
 +
 +/// Close relative to rustc's hir::PatKind
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub enum Pat {
 +    Missing,
 +    Wild,
 +    Tuple { args: Box<[PatId]>, ellipsis: Option<usize> },
 +    Or(Box<[PatId]>),
 +    Record { path: Option<Box<Path>>, args: Box<[RecordFieldPat]>, ellipsis: bool },
 +    Range { start: ExprId, end: ExprId },
 +    Slice { prefix: Box<[PatId]>, slice: Option<PatId>, suffix: Box<[PatId]> },
 +    Path(Box<Path>),
 +    Lit(ExprId),
 +    Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> },
 +    TupleStruct { path: Option<Box<Path>>, args: Box<[PatId]>, ellipsis: Option<usize> },
 +    Ref { pat: PatId, mutability: Mutability },
 +    Box { inner: PatId },
 +    ConstBlock(ExprId),
 +}
 +
 +impl Pat {
 +    pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) {
 +        match self {
 +            Pat::Range { .. }
 +            | Pat::Lit(..)
 +            | Pat::Path(..)
 +            | Pat::ConstBlock(..)
 +            | Pat::Wild
 +            | Pat::Missing => {}
 +            Pat::Bind { subpat, .. } => {
 +                subpat.iter().copied().for_each(f);
 +            }
 +            Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => {
 +                args.iter().copied().for_each(f);
 +            }
 +            Pat::Ref { pat, .. } => f(*pat),
 +            Pat::Slice { prefix, slice, suffix } => {
 +                let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
 +                total_iter.copied().for_each(f);
 +            }
 +            Pat::Record { args, .. } => {
 +                args.iter().map(|f| f.pat).for_each(f);
 +            }
 +            Pat::Box { inner } => f(*inner),
 +        }
 +    }
 +}
index 6eb530ecc54209d5e2f37ea98a8012c09ac3e87a,0000000000000000000000000000000000000000..9b4ce9f97c86ff4b708e8c124ac71f07b385463e
mode 100644,000000..100644
--- /dev/null
@@@ -1,545 -1,0 +1,558 @@@
- use rustc_hash::FxHashMap;
 +//! This module implements import-resolution/macro expansion algorithm.
 +//!
 +//! The result of this module is `DefMap`: a data structure which contains:
 +//!
 +//!   * a tree of modules for the crate
 +//!   * for each module, a set of items visible in the module (directly declared
 +//!     or imported)
 +//!
 +//! Note that `DefMap` contains fully macro expanded code.
 +//!
 +//! Computing `DefMap` can be partitioned into several logically
 +//! independent "phases". The phases are mutually recursive though, there's no
 +//! strict ordering.
 +//!
 +//! ## Collecting RawItems
 +//!
 +//! This happens in the `raw` module, which parses a single source file into a
 +//! set of top-level items. Nested imports are desugared to flat imports in this
 +//! phase. Macro calls are represented as a triple of (Path, Option<Name>,
 +//! TokenTree).
 +//!
 +//! ## Collecting Modules
 +//!
 +//! This happens in the `collector` module. In this phase, we recursively walk
 +//! tree of modules, collect raw items from submodules, populate module scopes
 +//! with defined items (so, we assign item ids in this phase) and record the set
 +//! of unresolved imports and macros.
 +//!
 +//! While we walk tree of modules, we also record macro_rules definitions and
 +//! expand calls to macro_rules defined macros.
 +//!
 +//! ## Resolving Imports
 +//!
 +//! We maintain a list of currently unresolved imports. On every iteration, we
 +//! try to resolve some imports from this list. If the import is resolved, we
 +//! record it, by adding an item to current module scope and, if necessary, by
 +//! recursively populating glob imports.
 +//!
 +//! ## Resolving Macros
 +//!
 +//! macro_rules from the same crate use a global mutable namespace. We expand
 +//! them immediately, when we collect modules.
 +//!
 +//! Macros from other crates (including proc-macros) can be used with
 +//! `foo::bar!` syntax. We handle them similarly to imports. There's a list of
 +//! unexpanded macros. On every iteration, we try to resolve each macro call
 +//! path and, upon success, we run macro expansion and "collect module" phase on
 +//! the result
 +
 +pub mod attr_resolution;
 +pub mod proc_macro;
 +pub mod diagnostics;
 +mod collector;
 +mod mod_resolution;
 +mod path_resolution;
 +
 +#[cfg(test)]
 +mod tests;
 +
 +use std::{cmp::Ord, ops::Deref, sync::Arc};
 +
 +use base_db::{CrateId, Edition, FileId};
 +use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId};
 +use itertools::Itertools;
 +use la_arena::Arena;
 +use profile::Count;
++use rustc_hash::{FxHashMap, FxHashSet};
 +use stdx::format_to;
 +use syntax::{ast, SmolStr};
 +
 +use crate::{
 +    db::DefDatabase,
 +    item_scope::{BuiltinShadowMode, ItemScope},
 +    item_tree::{ItemTreeId, Mod, TreeId},
 +    nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
 +    path::ModPath,
 +    per_ns::PerNs,
 +    visibility::Visibility,
 +    AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, MacroId, ModuleId, ProcMacroId,
 +};
 +
 +/// Contains the results of (early) name resolution.
 +///
 +/// A `DefMap` stores the module tree and the definitions that are in scope in every module after
 +/// item-level macros have been expanded.
 +///
 +/// Every crate has a primary `DefMap` whose root is the crate's main file (`main.rs`/`lib.rs`),
 +/// computed by the `crate_def_map` query. Additionally, every block expression introduces the
 +/// opportunity to write arbitrary item and module hierarchies, and thus gets its own `DefMap` that
 +/// is computed by the `block_def_map` query.
 +#[derive(Debug, PartialEq, Eq)]
 +pub struct DefMap {
 +    _c: Count<Self>,
 +    block: Option<BlockInfo>,
 +    root: LocalModuleId,
 +    modules: Arena<ModuleData>,
 +    krate: CrateId,
 +    /// The prelude module for this crate. This either comes from an import
 +    /// marked with the `prelude_import` attribute, or (in the normal case) from
 +    /// a dependency (`std` or `core`).
++    /// The prelude is empty for non-block DefMaps (unless `#[prelude_import]` was used,
++    /// but that attribute is nightly and when used in a block, it affects resolution globally
++    /// so we aren't handling this correctly anyways).
 +    prelude: Option<ModuleId>,
++    /// The extern prelude is only populated for non-block DefMaps
 +    extern_prelude: FxHashMap<Name, ModuleId>,
 +
 +    /// Side table for resolving derive helpers.
 +    exported_derives: FxHashMap<MacroDefId, Box<[Name]>>,
 +    fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>,
 +    /// The error that occurred when failing to load the proc-macro dll.
 +    proc_macro_loading_error: Option<Box<str>>,
 +    /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
 +    /// attributes.
 +    derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>,
 +
 +    /// Custom attributes registered with `#![register_attr]`.
 +    registered_attrs: Vec<SmolStr>,
 +    /// Custom tool modules registered with `#![register_tool]`.
 +    registered_tools: Vec<SmolStr>,
++    /// Unstable features of Rust enabled with `#![feature(A, B)]`.
++    unstable_features: FxHashSet<SmolStr>,
 +
 +    edition: Edition,
 +    recursion_limit: Option<u32>,
 +    diagnostics: Vec<DefDiagnostic>,
 +}
 +
 +/// For `DefMap`s computed for a block expression, this stores its location in the parent map.
 +#[derive(Debug, PartialEq, Eq, Clone, Copy)]
 +struct BlockInfo {
 +    /// The `BlockId` this `DefMap` was created from.
 +    block: BlockId,
 +    /// The containing module.
 +    parent: ModuleId,
 +}
 +
 +impl std::ops::Index<LocalModuleId> for DefMap {
 +    type Output = ModuleData;
 +    fn index(&self, id: LocalModuleId) -> &ModuleData {
 +        &self.modules[id]
 +    }
 +}
 +
 +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
 +pub enum ModuleOrigin {
 +    CrateRoot {
 +        definition: FileId,
 +    },
 +    /// Note that non-inline modules, by definition, live inside non-macro file.
 +    File {
 +        is_mod_rs: bool,
 +        declaration: AstId<ast::Module>,
 +        declaration_tree_id: ItemTreeId<Mod>,
 +        definition: FileId,
 +    },
 +    Inline {
 +        definition_tree_id: ItemTreeId<Mod>,
 +        definition: AstId<ast::Module>,
 +    },
 +    /// Pseudo-module introduced by a block scope (contains only inner items).
 +    BlockExpr {
 +        block: AstId<ast::BlockExpr>,
 +    },
 +}
 +
 +impl ModuleOrigin {
 +    pub fn declaration(&self) -> Option<AstId<ast::Module>> {
 +        match self {
 +            ModuleOrigin::File { declaration: module, .. }
 +            | ModuleOrigin::Inline { definition: module, .. } => Some(*module),
 +            ModuleOrigin::CrateRoot { .. } | ModuleOrigin::BlockExpr { .. } => None,
 +        }
 +    }
 +
 +    pub fn file_id(&self) -> Option<FileId> {
 +        match self {
 +            ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
 +                Some(*definition)
 +            }
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn is_inline(&self) -> bool {
 +        match self {
 +            ModuleOrigin::Inline { .. } | ModuleOrigin::BlockExpr { .. } => true,
 +            ModuleOrigin::CrateRoot { .. } | ModuleOrigin::File { .. } => false,
 +        }
 +    }
 +
 +    /// Returns a node which defines this module.
 +    /// That is, a file or a `mod foo {}` with items.
 +    fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> {
 +        match self {
 +            ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
 +                let file_id = *definition;
 +                let sf = db.parse(file_id).tree();
 +                InFile::new(file_id.into(), ModuleSource::SourceFile(sf))
 +            }
 +            ModuleOrigin::Inline { definition, .. } => InFile::new(
 +                definition.file_id,
 +                ModuleSource::Module(definition.to_node(db.upcast())),
 +            ),
 +            ModuleOrigin::BlockExpr { block } => {
 +                InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db.upcast())))
 +            }
 +        }
 +    }
 +}
 +
 +#[derive(Debug, PartialEq, Eq)]
 +pub struct ModuleData {
 +    /// Where does this module come from?
 +    pub origin: ModuleOrigin,
 +    /// Declared visibility of this module.
 +    pub visibility: Visibility,
 +
 +    pub parent: Option<LocalModuleId>,
 +    pub children: FxHashMap<Name, LocalModuleId>,
 +    pub scope: ItemScope,
 +}
 +
 +impl DefMap {
 +    pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> {
 +        let _p = profile::span("crate_def_map_query").detail(|| {
 +            db.crate_graph()[krate].display_name.as_deref().unwrap_or_default().to_string()
 +        });
 +
 +        let crate_graph = db.crate_graph();
 +
 +        let edition = crate_graph[krate].edition;
 +        let origin = ModuleOrigin::CrateRoot { definition: crate_graph[krate].root_file_id };
 +        let def_map = DefMap::empty(krate, edition, ModuleData::new(origin, Visibility::Public));
 +        let def_map = collector::collect_defs(
 +            db,
 +            def_map,
 +            TreeId::new(crate_graph[krate].root_file_id.into(), None),
 +        );
 +
 +        Arc::new(def_map)
 +    }
 +
 +    pub(crate) fn block_def_map_query(
 +        db: &dyn DefDatabase,
 +        block_id: BlockId,
 +    ) -> Option<Arc<DefMap>> {
 +        let block: BlockLoc = db.lookup_intern_block(block_id);
 +
 +        let tree_id = TreeId::new(block.ast_id.file_id, Some(block_id));
 +        let item_tree = tree_id.item_tree(db);
 +        if item_tree.top_level_items().is_empty() {
 +            return None;
 +        }
 +
 +        let parent_map = block.module.def_map(db);
 +        let krate = block.module.krate;
 +        let local_id = LocalModuleId::from_raw(la_arena::RawIdx::from(0));
 +        // NB: we use `None` as block here, which would be wrong for implicit
 +        // modules declared by blocks with items. At the moment, we don't use
 +        // this visibility for anything outside IDE, so that's probably OK.
 +        let visibility = Visibility::Module(ModuleId { krate, local_id, block: None });
 +        let module_data =
 +            ModuleData::new(ModuleOrigin::BlockExpr { block: block.ast_id }, visibility);
 +
 +        let mut def_map = DefMap::empty(krate, parent_map.edition, module_data);
 +        def_map.block = Some(BlockInfo { block: block_id, parent: block.module });
 +
 +        let def_map = collector::collect_defs(db, def_map, tree_id);
 +        Some(Arc::new(def_map))
 +    }
 +
 +    fn empty(krate: CrateId, edition: Edition, module_data: ModuleData) -> DefMap {
 +        let mut modules: Arena<ModuleData> = Arena::default();
 +        let root = modules.alloc(module_data);
 +
 +        DefMap {
 +            _c: Count::new(),
 +            block: None,
 +            krate,
 +            edition,
 +            recursion_limit: None,
 +            extern_prelude: FxHashMap::default(),
 +            exported_derives: FxHashMap::default(),
 +            fn_proc_macro_mapping: FxHashMap::default(),
 +            proc_macro_loading_error: None,
 +            derive_helpers_in_scope: FxHashMap::default(),
 +            prelude: None,
 +            root,
 +            modules,
 +            registered_attrs: Vec::new(),
 +            registered_tools: Vec::new(),
++            unstable_features: FxHashSet::default(),
 +            diagnostics: Vec::new(),
 +        }
 +    }
 +
 +    pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ {
 +        self.modules
 +            .iter()
 +            .filter(move |(_id, data)| data.origin.file_id() == Some(file_id))
 +            .map(|(id, _data)| id)
 +    }
 +
 +    pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ {
 +        self.modules.iter()
 +    }
 +
 +    pub fn derive_helpers_in_scope(
 +        &self,
 +        id: AstId<ast::Adt>,
 +    ) -> Option<&[(Name, MacroId, MacroCallId)]> {
 +        self.derive_helpers_in_scope.get(&id.map(|it| it.upcast())).map(Deref::deref)
 +    }
 +
 +    pub fn registered_tools(&self) -> &[SmolStr] {
 +        &self.registered_tools
 +    }
 +
 +    pub fn registered_attrs(&self) -> &[SmolStr] {
 +        &self.registered_attrs
 +    }
 +
++    pub fn is_unstable_feature_enabled(&self, feature: &str) -> bool {
++        self.unstable_features.contains(feature)
++    }
++
 +    pub fn root(&self) -> LocalModuleId {
 +        self.root
 +    }
 +
 +    pub fn fn_as_proc_macro(&self, id: FunctionId) -> Option<ProcMacroId> {
 +        self.fn_proc_macro_mapping.get(&id).copied()
 +    }
 +
 +    pub fn proc_macro_loading_error(&self) -> Option<&str> {
 +        self.proc_macro_loading_error.as_deref()
 +    }
 +
 +    pub(crate) fn krate(&self) -> CrateId {
 +        self.krate
 +    }
 +
 +    pub(crate) fn block_id(&self) -> Option<BlockId> {
 +        self.block.as_ref().map(|block| block.block)
 +    }
 +
 +    pub(crate) fn prelude(&self) -> Option<ModuleId> {
 +        self.prelude
 +    }
 +
 +    pub(crate) fn extern_prelude(&self) -> impl Iterator<Item = (&Name, &ModuleId)> + '_ {
 +        self.extern_prelude.iter()
 +    }
 +
 +    pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId {
 +        let block = self.block.as_ref().map(|b| b.block);
 +        ModuleId { krate: self.krate, local_id, block }
 +    }
 +
 +    pub(crate) fn crate_root(&self, db: &dyn DefDatabase) -> ModuleId {
 +        self.with_ancestor_maps(db, self.root, &mut |def_map, _module| {
 +            if def_map.block.is_none() { Some(def_map.module_id(def_map.root)) } else { None }
 +        })
 +        .expect("DefMap chain without root")
 +    }
 +
 +    pub(crate) fn resolve_path(
 +        &self,
 +        db: &dyn DefDatabase,
 +        original_module: LocalModuleId,
 +        path: &ModPath,
 +        shadow: BuiltinShadowMode,
 +    ) -> (PerNs, Option<usize>) {
 +        let res =
 +            self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow);
 +        (res.resolved_def, res.segment_index)
 +    }
 +
 +    pub(crate) fn resolve_path_locally(
 +        &self,
 +        db: &dyn DefDatabase,
 +        original_module: LocalModuleId,
 +        path: &ModPath,
 +        shadow: BuiltinShadowMode,
 +    ) -> (PerNs, Option<usize>) {
 +        let res = self.resolve_path_fp_with_macro_single(
 +            db,
 +            ResolveMode::Other,
 +            original_module,
 +            path,
 +            shadow,
 +        );
 +        (res.resolved_def, res.segment_index)
 +    }
 +
 +    /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module.
 +    ///
 +    /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns
 +    /// `None`, iteration continues.
 +    pub fn with_ancestor_maps<T>(
 +        &self,
 +        db: &dyn DefDatabase,
 +        local_mod: LocalModuleId,
 +        f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option<T>,
 +    ) -> Option<T> {
 +        if let Some(it) = f(self, local_mod) {
 +            return Some(it);
 +        }
 +        let mut block = self.block;
 +        while let Some(block_info) = block {
 +            let parent = block_info.parent.def_map(db);
 +            if let Some(it) = f(&parent, block_info.parent.local_id) {
 +                return Some(it);
 +            }
 +            block = parent.block;
 +        }
 +
 +        None
 +    }
 +
 +    /// If this `DefMap` is for a block expression, returns the module containing the block (which
 +    /// might again be a block, or a module inside a block).
 +    pub fn parent(&self) -> Option<ModuleId> {
 +        Some(self.block?.parent)
 +    }
 +
 +    /// Returns the module containing `local_mod`, either the parent `mod`, or the module containing
 +    /// the block, if `self` corresponds to a block expression.
 +    pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> {
 +        match &self[local_mod].parent {
 +            Some(parent) => Some(self.module_id(*parent)),
 +            None => self.block.as_ref().map(|block| block.parent),
 +        }
 +    }
 +
 +    // FIXME: this can use some more human-readable format (ideally, an IR
 +    // even), as this should be a great debugging aid.
 +    pub fn dump(&self, db: &dyn DefDatabase) -> String {
 +        let mut buf = String::new();
 +        let mut arc;
 +        let mut current_map = self;
 +        while let Some(block) = &current_map.block {
 +            go(&mut buf, current_map, "block scope", current_map.root);
 +            buf.push('\n');
 +            arc = block.parent.def_map(db);
 +            current_map = &*arc;
 +        }
 +        go(&mut buf, current_map, "crate", current_map.root);
 +        return buf;
 +
 +        fn go(buf: &mut String, map: &DefMap, path: &str, module: LocalModuleId) {
 +            format_to!(buf, "{}\n", path);
 +
 +            map.modules[module].scope.dump(buf);
 +
 +            for (name, child) in
 +                map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
 +            {
 +                let path = format!("{}::{}", path, name);
 +                buf.push('\n');
 +                go(buf, map, &path, *child);
 +            }
 +        }
 +    }
 +
 +    pub fn dump_block_scopes(&self, db: &dyn DefDatabase) -> String {
 +        let mut buf = String::new();
 +        let mut arc;
 +        let mut current_map = self;
 +        while let Some(block) = &current_map.block {
 +            format_to!(buf, "{:?} in {:?}\n", block.block, block.parent);
 +            arc = block.parent.def_map(db);
 +            current_map = &*arc;
 +        }
 +
 +        format_to!(buf, "crate scope\n");
 +        buf
 +    }
 +
 +    fn shrink_to_fit(&mut self) {
 +        // Exhaustive match to require handling new fields.
 +        let Self {
 +            _c: _,
 +            exported_derives,
 +            extern_prelude,
 +            diagnostics,
 +            modules,
 +            registered_attrs,
 +            registered_tools,
 +            fn_proc_macro_mapping,
 +            derive_helpers_in_scope,
++            unstable_features,
 +            proc_macro_loading_error: _,
 +            block: _,
 +            edition: _,
 +            recursion_limit: _,
 +            krate: _,
 +            prelude: _,
 +            root: _,
 +        } = self;
 +
 +        extern_prelude.shrink_to_fit();
 +        exported_derives.shrink_to_fit();
 +        diagnostics.shrink_to_fit();
 +        modules.shrink_to_fit();
 +        registered_attrs.shrink_to_fit();
 +        registered_tools.shrink_to_fit();
 +        fn_proc_macro_mapping.shrink_to_fit();
 +        derive_helpers_in_scope.shrink_to_fit();
++        unstable_features.shrink_to_fit();
 +        for (_, module) in modules.iter_mut() {
 +            module.children.shrink_to_fit();
 +            module.scope.shrink_to_fit();
 +        }
 +    }
 +
 +    /// Get a reference to the def map's diagnostics.
 +    pub fn diagnostics(&self) -> &[DefDiagnostic] {
 +        self.diagnostics.as_slice()
 +    }
 +
 +    pub fn recursion_limit(&self) -> Option<u32> {
 +        self.recursion_limit
 +    }
 +}
 +
 +impl ModuleData {
 +    pub(crate) fn new(origin: ModuleOrigin, visibility: Visibility) -> Self {
 +        ModuleData {
 +            origin,
 +            visibility,
 +            parent: None,
 +            children: FxHashMap::default(),
 +            scope: ItemScope::default(),
 +        }
 +    }
 +
 +    /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
 +    pub fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> {
 +        self.origin.definition_source(db)
 +    }
 +
 +    /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
 +    /// `None` for the crate root or block.
 +    pub fn declaration_source(&self, db: &dyn DefDatabase) -> Option<InFile<ast::Module>> {
 +        let decl = self.origin.declaration()?;
 +        let value = decl.to_node(db.upcast());
 +        Some(InFile { file_id: decl.file_id, value })
 +    }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub enum ModuleSource {
 +    SourceFile(ast::SourceFile),
 +    Module(ast::Module),
 +    BlockExpr(ast::BlockExpr),
 +}
index 8a6bb929c3df7bd660e2fcd5995b8e38b61bcfc0,0000000000000000000000000000000000000000..495bbe4579f00780774fc970110130f7fdd0ddb3
mode 100644,000000..100644
--- /dev/null
@@@ -1,2202 -1,0 +1,2214 @@@
-         let path_kind = if self.def_map.edition == Edition::Edition2015 {
-             PathKind::Plain
-         } else {
-             PathKind::Abs
 +//! The core of the module-level name resolution algorithm.
 +//!
 +//! `DefCollector::collect` contains the fixed-point iteration loop which
 +//! resolves imports and expands macros.
 +
 +use std::{iter, mem};
 +
 +use base_db::{CrateId, Edition, FileId};
 +use cfg::{CfgExpr, CfgOptions};
 +use either::Either;
 +use hir_expand::{
 +    ast_id_map::FileAstId,
 +    builtin_attr_macro::find_builtin_attr,
 +    builtin_derive_macro::find_builtin_derive,
 +    builtin_fn_macro::find_builtin_macro,
 +    name::{name, AsName, Name},
 +    proc_macro::ProcMacroExpander,
 +    ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId,
 +    MacroDefKind,
 +};
 +use itertools::{izip, Itertools};
 +use la_arena::Idx;
 +use limit::Limit;
 +use rustc_hash::{FxHashMap, FxHashSet};
 +use stdx::always;
 +use syntax::{ast, SmolStr};
 +
 +use crate::{
 +    attr::{Attr, AttrId, Attrs},
 +    attr_macro_as_call_id,
 +    db::DefDatabase,
 +    derive_macro_as_call_id,
 +    item_scope::{ImportType, PerNsGlobImports},
 +    item_tree::{
 +        self, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode, MacroCall,
 +        MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId,
 +    },
 +    macro_call_as_call_id, macro_id_to_def_id,
 +    nameres::{
 +        diagnostics::DefDiagnostic,
 +        mod_resolution::ModDir,
 +        path_resolution::ReachedFixedPoint,
 +        proc_macro::{ProcMacroDef, ProcMacroKind},
 +        BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode,
 +    },
 +    path::{ImportAlias, ModPath, PathKind},
 +    per_ns::PerNs,
 +    visibility::{RawVisibility, Visibility},
 +    AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionId,
 +    FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc,
 +    MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId,
 +    ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro,
 +};
 +
 +static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
 +static EXPANSION_DEPTH_LIMIT: Limit = Limit::new(128);
 +static FIXED_POINT_LIMIT: Limit = Limit::new(8192);
 +
 +pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: TreeId) -> DefMap {
 +    let crate_graph = db.crate_graph();
 +
 +    let mut deps = FxHashMap::default();
 +    // populate external prelude and dependency list
 +    let krate = &crate_graph[def_map.krate];
 +    for dep in &krate.dependencies {
 +        tracing::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
 +        let dep_def_map = db.crate_def_map(dep.crate_id);
 +        let dep_root = dep_def_map.module_id(dep_def_map.root);
 +
 +        deps.insert(dep.as_name(), dep_root.into());
 +
 +        if dep.is_prelude() && !tree_id.is_block() {
 +            def_map.extern_prelude.insert(dep.as_name(), dep_root);
 +        }
 +    }
 +
 +    let cfg_options = &krate.cfg_options;
 +    let proc_macros = match &krate.proc_macro {
 +        Ok(proc_macros) => {
 +            proc_macros
 +                .iter()
 +                .enumerate()
 +                .map(|(idx, it)| {
 +                    // FIXME: a hacky way to create a Name from string.
 +                    let name = tt::Ident { text: it.name.clone(), id: tt::TokenId::unspecified() };
 +                    (
 +                        name.as_name(),
 +                        ProcMacroExpander::new(def_map.krate, base_db::ProcMacroId(idx as u32)),
 +                    )
 +                })
 +                .collect()
 +        }
 +        Err(e) => {
 +            def_map.proc_macro_loading_error = Some(e.clone().into_boxed_str());
 +            Vec::new()
 +        }
 +    };
 +    let is_proc_macro = krate.is_proc_macro;
 +
 +    let mut collector = DefCollector {
 +        db,
 +        def_map,
 +        deps,
 +        glob_imports: FxHashMap::default(),
 +        unresolved_imports: Vec::new(),
 +        indeterminate_imports: Vec::new(),
 +        unresolved_macros: Vec::new(),
 +        mod_dirs: FxHashMap::default(),
 +        cfg_options,
 +        proc_macros,
 +        from_glob_import: Default::default(),
 +        skip_attrs: Default::default(),
 +        is_proc_macro,
 +    };
 +    if tree_id.is_block() {
 +        collector.seed_with_inner(tree_id);
 +    } else {
 +        collector.seed_with_top_level();
 +    }
 +    collector.collect();
 +    let mut def_map = collector.finish();
 +    def_map.shrink_to_fit();
 +    def_map
 +}
 +
 +#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 +enum PartialResolvedImport {
 +    /// None of any namespaces is resolved
 +    Unresolved,
 +    /// One of namespaces is resolved
 +    Indeterminate(PerNs),
 +    /// All namespaces are resolved, OR it comes from other crate
 +    Resolved(PerNs),
 +}
 +
 +impl PartialResolvedImport {
 +    fn namespaces(self) -> PerNs {
 +        match self {
 +            PartialResolvedImport::Unresolved => PerNs::none(),
 +            PartialResolvedImport::Indeterminate(ns) | PartialResolvedImport::Resolved(ns) => ns,
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Debug, Eq, PartialEq)]
 +enum ImportSource {
 +    Import { id: ItemTreeId<item_tree::Import>, use_tree: Idx<ast::UseTree> },
 +    ExternCrate(ItemTreeId<item_tree::ExternCrate>),
 +}
 +
 +#[derive(Debug, Eq, PartialEq)]
 +struct Import {
 +    path: ModPath,
 +    alias: Option<ImportAlias>,
 +    visibility: RawVisibility,
 +    kind: ImportKind,
 +    is_prelude: bool,
 +    is_extern_crate: bool,
 +    is_macro_use: bool,
 +    source: ImportSource,
 +}
 +
 +impl Import {
 +    fn from_use(
 +        db: &dyn DefDatabase,
 +        krate: CrateId,
 +        tree: &ItemTree,
 +        id: ItemTreeId<item_tree::Import>,
 +    ) -> Vec<Self> {
 +        let it = &tree[id.value];
 +        let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
 +        let visibility = &tree[it.visibility];
 +        let is_prelude = attrs.by_key("prelude_import").exists();
 +
 +        let mut res = Vec::new();
 +        it.use_tree.expand(|idx, path, kind, alias| {
 +            res.push(Self {
 +                path,
 +                alias,
 +                visibility: visibility.clone(),
 +                kind,
 +                is_prelude,
 +                is_extern_crate: false,
 +                is_macro_use: false,
 +                source: ImportSource::Import { id, use_tree: idx },
 +            });
 +        });
 +        res
 +    }
 +
 +    fn from_extern_crate(
 +        db: &dyn DefDatabase,
 +        krate: CrateId,
 +        tree: &ItemTree,
 +        id: ItemTreeId<item_tree::ExternCrate>,
 +    ) -> Self {
 +        let it = &tree[id.value];
 +        let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
 +        let visibility = &tree[it.visibility];
 +        Self {
 +            path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())),
 +            alias: it.alias.clone(),
 +            visibility: visibility.clone(),
 +            kind: ImportKind::Plain,
 +            is_prelude: false,
 +            is_extern_crate: true,
 +            is_macro_use: attrs.by_key("macro_use").exists(),
 +            source: ImportSource::ExternCrate(id),
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Eq, PartialEq)]
 +struct ImportDirective {
 +    module_id: LocalModuleId,
 +    import: Import,
 +    status: PartialResolvedImport,
 +}
 +
 +#[derive(Clone, Debug, Eq, PartialEq)]
 +struct MacroDirective {
 +    module_id: LocalModuleId,
 +    depth: usize,
 +    kind: MacroDirectiveKind,
 +    container: ItemContainerId,
 +}
 +
 +#[derive(Clone, Debug, Eq, PartialEq)]
 +enum MacroDirectiveKind {
 +    FnLike { ast_id: AstIdWithPath<ast::MacroCall>, expand_to: ExpandTo },
 +    Derive { ast_id: AstIdWithPath<ast::Adt>, derive_attr: AttrId, derive_pos: usize },
 +    Attr { ast_id: AstIdWithPath<ast::Item>, attr: Attr, mod_item: ModItem, tree: TreeId },
 +}
 +
 +/// Walks the tree of module recursively
 +struct DefCollector<'a> {
 +    db: &'a dyn DefDatabase,
 +    def_map: DefMap,
 +    deps: FxHashMap<Name, ModuleId>,
 +    glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>,
 +    unresolved_imports: Vec<ImportDirective>,
 +    indeterminate_imports: Vec<ImportDirective>,
 +    unresolved_macros: Vec<MacroDirective>,
 +    mod_dirs: FxHashMap<LocalModuleId, ModDir>,
 +    cfg_options: &'a CfgOptions,
 +    /// List of procedural macros defined by this crate. This is read from the dynamic library
 +    /// built by the build system, and is the list of proc. macros we can actually expand. It is
 +    /// empty when proc. macro support is disabled (in which case we still do name resolution for
 +    /// them).
 +    proc_macros: Vec<(Name, ProcMacroExpander)>,
 +    is_proc_macro: bool,
 +    from_glob_import: PerNsGlobImports,
 +    /// If we fail to resolve an attribute on a `ModItem`, we fall back to ignoring the attribute.
 +    /// This map is used to skip all attributes up to and including the one that failed to resolve,
 +    /// in order to not expand them twice.
 +    ///
 +    /// This also stores the attributes to skip when we resolve derive helpers and non-macro
 +    /// non-builtin attributes in general.
 +    skip_attrs: FxHashMap<InFile<ModItem>, AttrId>,
 +}
 +
 +impl DefCollector<'_> {
 +    fn seed_with_top_level(&mut self) {
 +        let _p = profile::span("seed_with_top_level");
 +
 +        let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id;
 +        let item_tree = self.db.file_item_tree(file_id.into());
 +        let module_id = self.def_map.root;
 +
 +        let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
 +        if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) {
 +            self.inject_prelude(&attrs);
 +
 +            // Process other crate-level attributes.
 +            for attr in &*attrs {
 +                let attr_name = match attr.path.as_ident() {
 +                    Some(name) => name,
 +                    None => continue,
 +                };
 +
 +                if *attr_name == hir_expand::name![recursion_limit] {
 +                    if let Some(limit) = attr.string_value() {
 +                        if let Ok(limit) = limit.parse() {
 +                            self.def_map.recursion_limit = Some(limit);
 +                        }
 +                    }
 +                    continue;
 +                }
 +
 +                if *attr_name == hir_expand::name![crate_type] {
 +                    if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) {
 +                        self.is_proc_macro = true;
 +                    }
 +                    continue;
 +                }
 +
++                if *attr_name == hir_expand::name![feature] {
++                    let features =
++                        attr.parse_path_comma_token_tree().into_iter().flatten().filter_map(
++                            |feat| match feat.segments() {
++                                [name] => Some(name.to_smol_str()),
++                                _ => None,
++                            },
++                        );
++                    self.def_map.unstable_features.extend(features);
++                }
++
 +                let attr_is_register_like = *attr_name == hir_expand::name![register_attr]
 +                    || *attr_name == hir_expand::name![register_tool];
 +                if !attr_is_register_like {
 +                    continue;
 +                }
 +
 +                let registered_name = match attr.single_ident_value() {
 +                    Some(ident) => ident.as_name(),
 +                    _ => continue,
 +                };
 +
 +                if *attr_name == hir_expand::name![register_attr] {
 +                    self.def_map.registered_attrs.push(registered_name.to_smol_str());
 +                    cov_mark::hit!(register_attr);
 +                } else {
 +                    self.def_map.registered_tools.push(registered_name.to_smol_str());
 +                    cov_mark::hit!(register_tool);
 +                }
 +            }
 +
 +            ModCollector {
 +                def_collector: self,
 +                macro_depth: 0,
 +                module_id,
 +                tree_id: TreeId::new(file_id.into(), None),
 +                item_tree: &item_tree,
 +                mod_dir: ModDir::root(),
 +            }
 +            .collect_in_top_module(item_tree.top_level_items());
 +        }
 +    }
 +
 +    fn seed_with_inner(&mut self, tree_id: TreeId) {
 +        let item_tree = tree_id.item_tree(self.db);
 +        let module_id = self.def_map.root;
 +
 +        let is_cfg_enabled = item_tree
 +            .top_level_attrs(self.db, self.def_map.krate)
 +            .cfg()
 +            .map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false));
 +        if is_cfg_enabled {
 +            ModCollector {
 +                def_collector: self,
 +                macro_depth: 0,
 +                module_id,
 +                tree_id,
 +                item_tree: &item_tree,
 +                mod_dir: ModDir::root(),
 +            }
 +            .collect_in_top_module(item_tree.top_level_items());
 +        }
 +    }
 +
 +    fn resolution_loop(&mut self) {
 +        let _p = profile::span("DefCollector::resolution_loop");
 +
 +        // main name resolution fixed-point loop.
 +        let mut i = 0;
 +        'resolve_attr: loop {
 +            'resolve_macros: loop {
 +                self.db.unwind_if_cancelled();
 +
 +                {
 +                    let _p = profile::span("resolve_imports loop");
 +
 +                    'resolve_imports: loop {
 +                        if self.resolve_imports() == ReachedFixedPoint::Yes {
 +                            break 'resolve_imports;
 +                        }
 +                    }
 +                }
 +                if self.resolve_macros() == ReachedFixedPoint::Yes {
 +                    break 'resolve_macros;
 +                }
 +
 +                i += 1;
 +                if FIXED_POINT_LIMIT.check(i).is_err() {
 +                    tracing::error!("name resolution is stuck");
 +                    break 'resolve_attr;
 +                }
 +            }
 +
 +            if self.reseed_with_unresolved_attribute() == ReachedFixedPoint::Yes {
 +                break 'resolve_attr;
 +            }
 +        }
 +    }
 +
 +    fn collect(&mut self) {
 +        let _p = profile::span("DefCollector::collect");
 +
 +        self.resolution_loop();
 +
 +        // Resolve all indeterminate resolved imports again
 +        // As some of the macros will expand newly import shadowing partial resolved imports
 +        // FIXME: We maybe could skip this, if we handle the indeterminate imports in `resolve_imports`
 +        // correctly
 +        let partial_resolved = self.indeterminate_imports.drain(..).map(|directive| {
 +            ImportDirective { status: PartialResolvedImport::Unresolved, ..directive }
 +        });
 +        self.unresolved_imports.extend(partial_resolved);
 +        self.resolve_imports();
 +
 +        let unresolved_imports = mem::take(&mut self.unresolved_imports);
 +        // show unresolved imports in completion, etc
 +        for directive in &unresolved_imports {
 +            self.record_resolved_import(directive);
 +        }
 +        self.unresolved_imports = unresolved_imports;
 +
 +        if self.is_proc_macro {
 +            // A crate exporting procedural macros is not allowed to export anything else.
 +            //
 +            // Additionally, while the proc macro entry points must be `pub`, they are not publicly
 +            // exported in type/value namespace. This function reduces the visibility of all items
 +            // in the crate root that aren't proc macros.
 +            let root = self.def_map.root;
 +            let module_id = self.def_map.module_id(root);
 +            let root = &mut self.def_map.modules[root];
 +            root.scope.censor_non_proc_macros(module_id);
 +        }
 +    }
 +
 +    /// When the fixed-point loop reaches a stable state, we might still have
 +    /// some unresolved attributes left over. This takes one of them, and feeds
 +    /// the item it's applied to back into name resolution.
 +    ///
 +    /// This effectively ignores the fact that the macro is there and just treats the items as
 +    /// normal code.
 +    ///
 +    /// This improves UX for unresolved attributes, and replicates the
 +    /// behavior before we supported proc. attribute macros.
 +    fn reseed_with_unresolved_attribute(&mut self) -> ReachedFixedPoint {
 +        cov_mark::hit!(unresolved_attribute_fallback);
 +
 +        let unresolved_attr =
 +            self.unresolved_macros.iter().enumerate().find_map(|(idx, directive)| match &directive
 +                .kind
 +            {
 +                MacroDirectiveKind::Attr { ast_id, mod_item, attr, tree } => {
 +                    self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
 +                        directive.module_id,
 +                        MacroCallKind::Attr {
 +                            ast_id: ast_id.ast_id,
 +                            attr_args: Default::default(),
 +                            invoc_attr_index: attr.id.ast_index,
 +                            is_derive: false,
 +                        },
 +                        attr.path().clone(),
 +                    ));
 +
 +                    self.skip_attrs.insert(ast_id.ast_id.with_value(*mod_item), attr.id);
 +
 +                    Some((idx, directive, *mod_item, *tree))
 +                }
 +                _ => None,
 +            });
 +
 +        match unresolved_attr {
 +            Some((pos, &MacroDirective { module_id, depth, container, .. }, mod_item, tree_id)) => {
 +                let item_tree = &tree_id.item_tree(self.db);
 +                let mod_dir = self.mod_dirs[&module_id].clone();
 +                ModCollector {
 +                    def_collector: self,
 +                    macro_depth: depth,
 +                    module_id,
 +                    tree_id,
 +                    item_tree,
 +                    mod_dir,
 +                }
 +                .collect(&[mod_item], container);
 +
 +                self.unresolved_macros.swap_remove(pos);
 +                // Continue name resolution with the new data.
 +                ReachedFixedPoint::No
 +            }
 +            None => ReachedFixedPoint::Yes,
 +        }
 +    }
 +
 +    fn inject_prelude(&mut self, crate_attrs: &Attrs) {
 +        // See compiler/rustc_builtin_macros/src/standard_library_imports.rs
 +
 +        if crate_attrs.by_key("no_core").exists() {
 +            // libcore does not get a prelude.
 +            return;
 +        }
 +
 +        let krate = if crate_attrs.by_key("no_std").exists() {
 +            name![core]
 +        } else {
 +            let std = name![std];
 +            if self.def_map.extern_prelude().any(|(name, _)| *name == std) {
 +                std
 +            } else {
 +                // If `std` does not exist for some reason, fall back to core. This mostly helps
 +                // keep r-a's own tests minimal.
 +                name![core]
 +            }
 +        };
 +
 +        let edition = match self.def_map.edition {
 +            Edition::Edition2015 => name![rust_2015],
 +            Edition::Edition2018 => name![rust_2018],
 +            Edition::Edition2021 => name![rust_2021],
 +        };
 +
-                     return;
++        let path_kind = match self.def_map.edition {
++            Edition::Edition2015 => PathKind::Plain,
++            _ => PathKind::Abs,
 +        };
 +        let path =
 +            ModPath::from_segments(path_kind, [krate.clone(), name![prelude], edition].into_iter());
 +        // Fall back to the older `std::prelude::v1` for compatibility with Rust <1.52.0
 +        // FIXME remove this fallback
 +        let fallback_path =
 +            ModPath::from_segments(path_kind, [krate, name![prelude], name![v1]].into_iter());
 +
 +        for path in &[path, fallback_path] {
 +            let (per_ns, _) = self.def_map.resolve_path(
 +                self.db,
 +                self.def_map.root,
 +                path,
 +                BuiltinShadowMode::Other,
 +            );
 +
 +            match per_ns.types {
 +                Some((ModuleDefId::ModuleId(m), _)) => {
 +                    self.def_map.prelude = Some(m);
-                 if import.is_extern_crate && module_id == self.def_map.root {
 +                }
 +                types => {
 +                    tracing::debug!(
 +                        "could not resolve prelude path `{}` to module (resolved to {:?})",
 +                        path,
 +                        types
 +                    );
 +                }
 +            }
 +        }
 +    }
 +
 +    /// Adds a definition of procedural macro `name` to the root module.
 +    ///
 +    /// # Notes on procedural macro resolution
 +    ///
 +    /// Procedural macro functionality is provided by the build system: It has to build the proc
 +    /// macro and pass the resulting dynamic library to rust-analyzer.
 +    ///
 +    /// When procedural macro support is enabled, the list of proc macros exported by a crate is
 +    /// known before we resolve names in the crate. This list is stored in `self.proc_macros` and is
 +    /// derived from the dynamic library.
 +    ///
 +    /// However, we *also* would like to be able to at least *resolve* macros on our own, without
 +    /// help by the build system. So, when the macro isn't found in `self.proc_macros`, we instead
 +    /// use a dummy expander that always errors. This comes with the drawback of macros potentially
 +    /// going out of sync with what the build system sees (since we resolve using VFS state, but
 +    /// Cargo builds only on-disk files). We could and probably should add diagnostics for that.
 +    fn export_proc_macro(
 +        &mut self,
 +        def: ProcMacroDef,
 +        id: ItemTreeId<item_tree::Function>,
 +        fn_id: FunctionId,
 +        module_id: ModuleId,
 +    ) {
 +        let kind = def.kind.to_basedb_kind();
 +        let (expander, kind) = match self.proc_macros.iter().find(|(n, _)| n == &def.name) {
 +            Some(&(_, expander)) => (expander, kind),
 +            None => (ProcMacroExpander::dummy(self.def_map.krate), kind),
 +        };
 +
 +        let proc_macro_id =
 +            ProcMacroLoc { container: module_id, id, expander, kind }.intern(self.db);
 +        self.define_proc_macro(def.name.clone(), proc_macro_id);
 +        if let ProcMacroKind::CustomDerive { helpers } = def.kind {
 +            self.def_map
 +                .exported_derives
 +                .insert(macro_id_to_def_id(self.db, proc_macro_id.into()), helpers);
 +        }
 +        self.def_map.fn_proc_macro_mapping.insert(fn_id, proc_macro_id);
 +    }
 +
 +    /// Define a macro with `macro_rules`.
 +    ///
 +    /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`,
 +    /// then it is also defined in the root module scope.
 +    /// You can `use` or invoke it by `crate::macro_name` anywhere, before or after the definition.
 +    ///
 +    /// It is surprising that the macro will never be in the current module scope.
 +    /// These code fails with "unresolved import/macro",
 +    /// ```rust,compile_fail
 +    /// mod m { macro_rules! foo { () => {} } }
 +    /// use m::foo as bar;
 +    /// ```
 +    ///
 +    /// ```rust,compile_fail
 +    /// macro_rules! foo { () => {} }
 +    /// self::foo!();
 +    /// crate::foo!();
 +    /// ```
 +    ///
 +    /// Well, this code compiles, because the plain path `foo` in `use` is searched
 +    /// in the legacy textual scope only.
 +    /// ```rust
 +    /// macro_rules! foo { () => {} }
 +    /// use foo as bar;
 +    /// ```
 +    fn define_macro_rules(
 +        &mut self,
 +        module_id: LocalModuleId,
 +        name: Name,
 +        macro_: MacroRulesId,
 +        export: bool,
 +    ) {
 +        // Textual scoping
 +        self.define_legacy_macro(module_id, name.clone(), macro_.into());
 +
 +        // Module scoping
 +        // In Rust, `#[macro_export]` macros are unconditionally visible at the
 +        // crate root, even if the parent modules is **not** visible.
 +        if export {
 +            let module_id = self.def_map.root;
 +            self.def_map.modules[module_id].scope.declare(macro_.into());
 +            self.update(
 +                module_id,
 +                &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
 +                Visibility::Public,
 +                ImportType::Named,
 +            );
 +        }
 +    }
 +
 +    /// Define a legacy textual scoped macro in module
 +    ///
 +    /// We use a map `legacy_macros` to store all legacy textual scoped macros visible per module.
 +    /// It will clone all macros from parent legacy scope, whose definition is prior to
 +    /// the definition of current module.
 +    /// And also, `macro_use` on a module will import all legacy macros visible inside to
 +    /// current legacy scope, with possible shadowing.
 +    fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroId) {
 +        // Always shadowing
 +        self.def_map.modules[module_id].scope.define_legacy_macro(name, mac);
 +    }
 +
 +    /// Define a macro 2.0 macro
 +    ///
 +    /// The scoped of macro 2.0 macro is equal to normal function
 +    fn define_macro_def(
 +        &mut self,
 +        module_id: LocalModuleId,
 +        name: Name,
 +        macro_: Macro2Id,
 +        vis: &RawVisibility,
 +    ) {
 +        let vis =
 +            self.def_map.resolve_visibility(self.db, module_id, vis).unwrap_or(Visibility::Public);
 +        self.def_map.modules[module_id].scope.declare(macro_.into());
 +        self.update(
 +            module_id,
 +            &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
 +            vis,
 +            ImportType::Named,
 +        );
 +    }
 +
 +    /// Define a proc macro
 +    ///
 +    /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped.
 +    /// And unconditionally exported.
 +    fn define_proc_macro(&mut self, name: Name, macro_: ProcMacroId) {
 +        let module_id = self.def_map.root;
 +        self.def_map.modules[module_id].scope.declare(macro_.into());
 +        self.update(
 +            module_id,
 +            &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
 +            Visibility::Public,
 +            ImportType::Named,
 +        );
 +    }
 +
 +    /// Import macros from `#[macro_use] extern crate`.
 +    fn import_macros_from_extern_crate(
 +        &mut self,
 +        current_module_id: LocalModuleId,
 +        extern_crate: &item_tree::ExternCrate,
 +    ) {
 +        tracing::debug!(
 +            "importing macros from extern crate: {:?} ({:?})",
 +            extern_crate,
 +            self.def_map.edition,
 +        );
 +
 +        if let Some(m) = self.resolve_extern_crate(&extern_crate.name) {
 +            if m == self.def_map.module_id(current_module_id) {
 +                cov_mark::hit!(ignore_macro_use_extern_crate_self);
 +                return;
 +            }
 +
 +            cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
 +            self.import_all_macros_exported(current_module_id, m.krate);
 +        }
 +    }
 +
 +    /// Import all exported macros from another crate
 +    ///
 +    /// Exported macros are just all macros in the root module scope.
 +    /// Note that it contains not only all `#[macro_export]` macros, but also all aliases
 +    /// created by `use` in the root module, ignoring the visibility of `use`.
 +    fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) {
 +        let def_map = self.db.crate_def_map(krate);
 +        for (name, def) in def_map[def_map.root].scope.macros() {
 +            // `#[macro_use]` brings macros into legacy scope. Yes, even non-`macro_rules!` macros.
 +            self.define_legacy_macro(current_module_id, name.clone(), def);
 +        }
 +    }
 +
 +    /// Tries to resolve every currently unresolved import.
 +    fn resolve_imports(&mut self) -> ReachedFixedPoint {
 +        let mut res = ReachedFixedPoint::Yes;
 +        let imports = mem::take(&mut self.unresolved_imports);
 +
 +        self.unresolved_imports = imports
 +            .into_iter()
 +            .filter_map(|mut directive| {
 +                directive.status = self.resolve_import(directive.module_id, &directive.import);
 +                match directive.status {
 +                    PartialResolvedImport::Indeterminate(_) => {
 +                        self.record_resolved_import(&directive);
 +                        self.indeterminate_imports.push(directive);
 +                        res = ReachedFixedPoint::No;
 +                        None
 +                    }
 +                    PartialResolvedImport::Resolved(_) => {
 +                        self.record_resolved_import(&directive);
 +                        res = ReachedFixedPoint::No;
 +                        None
 +                    }
 +                    PartialResolvedImport::Unresolved => Some(directive),
 +                }
 +            })
 +            .collect();
 +        res
 +    }
 +
 +    fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport {
 +        let _p = profile::span("resolve_import").detail(|| format!("{}", import.path));
 +        tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
 +        if import.is_extern_crate {
 +            let name = import
 +                .path
 +                .as_ident()
 +                .expect("extern crate should have been desugared to one-element path");
 +
 +            let res = self.resolve_extern_crate(name);
 +
 +            match res {
 +                Some(res) => {
 +                    PartialResolvedImport::Resolved(PerNs::types(res.into(), Visibility::Public))
 +                }
 +                None => PartialResolvedImport::Unresolved,
 +            }
 +        } else {
 +            let res = self.def_map.resolve_path_fp_with_macro(
 +                self.db,
 +                ResolveMode::Import,
 +                module_id,
 +                &import.path,
 +                BuiltinShadowMode::Module,
 +            );
 +
 +            let def = res.resolved_def;
 +            if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() {
 +                return PartialResolvedImport::Unresolved;
 +            }
 +
 +            if let Some(krate) = res.krate {
 +                if krate != self.def_map.krate {
 +                    return PartialResolvedImport::Resolved(
 +                        def.filter_visibility(|v| matches!(v, Visibility::Public)),
 +                    );
 +                }
 +            }
 +
 +            // Check whether all namespace is resolved
 +            if def.take_types().is_some()
 +                && def.take_values().is_some()
 +                && def.take_macros().is_some()
 +            {
 +                PartialResolvedImport::Resolved(def)
 +            } else {
 +                PartialResolvedImport::Indeterminate(def)
 +            }
 +        }
 +    }
 +
 +    fn resolve_extern_crate(&self, name: &Name) -> Option<ModuleId> {
 +        if *name == name!(self) {
 +            cov_mark::hit!(extern_crate_self_as);
 +            let root = match self.def_map.block {
 +                Some(_) => {
 +                    let def_map = self.def_map.crate_root(self.db).def_map(self.db);
 +                    def_map.module_id(def_map.root())
 +                }
 +                None => self.def_map.module_id(self.def_map.root()),
 +            };
 +            Some(root)
 +        } else {
 +            self.deps.get(name).copied()
 +        }
 +    }
 +
 +    fn record_resolved_import(&mut self, directive: &ImportDirective) {
 +        let _p = profile::span("record_resolved_import");
 +
 +        let module_id = directive.module_id;
 +        let import = &directive.import;
 +        let mut def = directive.status.namespaces();
 +        let vis = self
 +            .def_map
 +            .resolve_visibility(self.db, module_id, &directive.import.visibility)
 +            .unwrap_or(Visibility::Public);
 +
 +        match import.kind {
 +            ImportKind::Plain | ImportKind::TypeOnly => {
 +                let name = match &import.alias {
 +                    Some(ImportAlias::Alias(name)) => Some(name),
 +                    Some(ImportAlias::Underscore) => None,
 +                    None => match import.path.segments().last() {
 +                        Some(last_segment) => Some(last_segment),
 +                        None => {
 +                            cov_mark::hit!(bogus_paths);
 +                            return;
 +                        }
 +                    },
 +                };
 +
 +                if import.kind == ImportKind::TypeOnly {
 +                    def.values = None;
 +                    def.macros = None;
 +                }
 +
 +                tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
 +
 +                // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
++                if import.is_extern_crate
++                    && self.def_map.block.is_none()
++                    && module_id == self.def_map.root
++                {
 +                    if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name)
 +                    {
 +                        self.def_map.extern_prelude.insert(name.clone(), def);
 +                    }
 +                }
 +
 +                self.update(module_id, &[(name.cloned(), def)], vis, ImportType::Named);
 +            }
 +            ImportKind::Glob => {
 +                tracing::debug!("glob import: {:?}", import);
 +                match def.take_types() {
 +                    Some(ModuleDefId::ModuleId(m)) => {
 +                        if import.is_prelude {
 +                            // Note: This dodgily overrides the injected prelude. The rustc
 +                            // implementation seems to work the same though.
 +                            cov_mark::hit!(std_prelude);
 +                            self.def_map.prelude = Some(m);
 +                        } else if m.krate != self.def_map.krate {
 +                            cov_mark::hit!(glob_across_crates);
 +                            // glob import from other crate => we can just import everything once
 +                            let item_map = m.def_map(self.db);
 +                            let scope = &item_map[m.local_id].scope;
 +
 +                            // Module scoped macros is included
 +                            let items = scope
 +                                .resolutions()
 +                                // only keep visible names...
 +                                .map(|(n, res)| {
 +                                    (n, res.filter_visibility(|v| v.is_visible_from_other_crate()))
 +                                })
 +                                .filter(|(_, res)| !res.is_none())
 +                                .collect::<Vec<_>>();
 +
 +                            self.update(module_id, &items, vis, ImportType::Glob);
 +                        } else {
 +                            // glob import from same crate => we do an initial
 +                            // import, and then need to propagate any further
 +                            // additions
 +                            let def_map;
 +                            let scope = if m.block == self.def_map.block_id() {
 +                                &self.def_map[m.local_id].scope
 +                            } else {
 +                                def_map = m.def_map(self.db);
 +                                &def_map[m.local_id].scope
 +                            };
 +
 +                            // Module scoped macros is included
 +                            let items = scope
 +                                .resolutions()
 +                                // only keep visible names...
 +                                .map(|(n, res)| {
 +                                    (
 +                                        n,
 +                                        res.filter_visibility(|v| {
 +                                            v.is_visible_from_def_map(
 +                                                self.db,
 +                                                &self.def_map,
 +                                                module_id,
 +                                            )
 +                                        }),
 +                                    )
 +                                })
 +                                .filter(|(_, res)| !res.is_none())
 +                                .collect::<Vec<_>>();
 +
 +                            self.update(module_id, &items, vis, ImportType::Glob);
 +                            // record the glob import in case we add further items
 +                            let glob = self.glob_imports.entry(m.local_id).or_default();
 +                            if !glob.iter().any(|(mid, _)| *mid == module_id) {
 +                                glob.push((module_id, vis));
 +                            }
 +                        }
 +                    }
 +                    Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
 +                        cov_mark::hit!(glob_enum);
 +                        // glob import from enum => just import all the variants
 +
 +                        // XXX: urgh, so this works by accident! Here, we look at
 +                        // the enum data, and, in theory, this might require us to
 +                        // look back at the crate_def_map, creating a cycle. For
 +                        // example, `enum E { crate::some_macro!(); }`. Luckily, the
 +                        // only kind of macro that is allowed inside enum is a
 +                        // `cfg_macro`, and we don't need to run name resolution for
 +                        // it, but this is sheer luck!
 +                        let enum_data = self.db.enum_data(e);
 +                        let resolutions = enum_data
 +                            .variants
 +                            .iter()
 +                            .map(|(local_id, variant_data)| {
 +                                let name = variant_data.name.clone();
 +                                let variant = EnumVariantId { parent: e, local_id };
 +                                let res = PerNs::both(variant.into(), variant.into(), vis);
 +                                (Some(name), res)
 +                            })
 +                            .collect::<Vec<_>>();
 +                        self.update(module_id, &resolutions, vis, ImportType::Glob);
 +                    }
 +                    Some(d) => {
 +                        tracing::debug!("glob import {:?} from non-module/enum {:?}", import, d);
 +                    }
 +                    None => {
 +                        tracing::debug!("glob import {:?} didn't resolve as type", import);
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn update(
 +        &mut self,
 +        module_id: LocalModuleId,
 +        resolutions: &[(Option<Name>, PerNs)],
 +        vis: Visibility,
 +        import_type: ImportType,
 +    ) {
 +        self.db.unwind_if_cancelled();
 +        self.update_recursive(module_id, resolutions, vis, import_type, 0)
 +    }
 +
 +    fn update_recursive(
 +        &mut self,
 +        module_id: LocalModuleId,
 +        resolutions: &[(Option<Name>, PerNs)],
 +        // All resolutions are imported with this visibility; the visibilities in
 +        // the `PerNs` values are ignored and overwritten
 +        vis: Visibility,
 +        import_type: ImportType,
 +        depth: usize,
 +    ) {
 +        if GLOB_RECURSION_LIMIT.check(depth).is_err() {
 +            // prevent stack overflows (but this shouldn't be possible)
 +            panic!("infinite recursion in glob imports!");
 +        }
 +        let mut changed = false;
 +
 +        for (name, res) in resolutions {
 +            match name {
 +                Some(name) => {
 +                    let scope = &mut self.def_map.modules[module_id].scope;
 +                    changed |= scope.push_res_with_import(
 +                        &mut self.from_glob_import,
 +                        (module_id, name.clone()),
 +                        res.with_visibility(vis),
 +                        import_type,
 +                    );
 +                }
 +                None => {
 +                    let tr = match res.take_types() {
 +                        Some(ModuleDefId::TraitId(tr)) => tr,
 +                        Some(other) => {
 +                            tracing::debug!("non-trait `_` import of {:?}", other);
 +                            continue;
 +                        }
 +                        None => continue,
 +                    };
 +                    let old_vis = self.def_map.modules[module_id].scope.unnamed_trait_vis(tr);
 +                    let should_update = match old_vis {
 +                        None => true,
 +                        Some(old_vis) => {
 +                            let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| {
 +                                panic!("`Tr as _` imports with unrelated visibilities {:?} and {:?} (trait {:?})", old_vis, vis, tr);
 +                            });
 +
 +                            if max_vis == old_vis {
 +                                false
 +                            } else {
 +                                cov_mark::hit!(upgrade_underscore_visibility);
 +                                true
 +                            }
 +                        }
 +                    };
 +
 +                    if should_update {
 +                        changed = true;
 +                        self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis);
 +                    }
 +                }
 +            }
 +        }
 +
 +        if !changed {
 +            return;
 +        }
 +        let glob_imports = self
 +            .glob_imports
 +            .get(&module_id)
 +            .into_iter()
 +            .flatten()
 +            .filter(|(glob_importing_module, _)| {
 +                // we know all resolutions have the same visibility (`vis`), so we
 +                // just need to check that once
 +                vis.is_visible_from_def_map(self.db, &self.def_map, *glob_importing_module)
 +            })
 +            .cloned()
 +            .collect::<Vec<_>>();
 +
 +        for (glob_importing_module, glob_import_vis) in glob_imports {
 +            self.update_recursive(
 +                glob_importing_module,
 +                resolutions,
 +                glob_import_vis,
 +                ImportType::Glob,
 +                depth + 1,
 +            );
 +        }
 +    }
 +
 +    fn resolve_macros(&mut self) -> ReachedFixedPoint {
 +        let mut macros = mem::take(&mut self.unresolved_macros);
 +        let mut resolved = Vec::new();
 +        let mut push_resolved = |directive: &MacroDirective, call_id| {
 +            resolved.push((directive.module_id, directive.depth, directive.container, call_id));
 +        };
 +        let mut res = ReachedFixedPoint::Yes;
 +        macros.retain(|directive| {
 +            let resolver = |path| {
 +                let resolved_res = self.def_map.resolve_path_fp_with_macro(
 +                    self.db,
 +                    ResolveMode::Other,
 +                    directive.module_id,
 +                    &path,
 +                    BuiltinShadowMode::Module,
 +                );
 +                resolved_res
 +                    .resolved_def
 +                    .take_macros()
 +                    .map(|it| (it, macro_id_to_def_id(self.db, it)))
 +            };
 +            let resolver_def_id = |path| resolver(path).map(|(_, it)| it);
 +
 +            match &directive.kind {
 +                MacroDirectiveKind::FnLike { ast_id, expand_to } => {
 +                    let call_id = macro_call_as_call_id(
 +                        self.db,
 +                        ast_id,
 +                        *expand_to,
 +                        self.def_map.krate,
 +                        &resolver_def_id,
 +                        &mut |_err| (),
 +                    );
 +                    if let Ok(Ok(call_id)) = call_id {
 +                        push_resolved(directive, call_id);
 +                        res = ReachedFixedPoint::No;
 +                        return false;
 +                    }
 +                }
 +                MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos } => {
 +                    let id = derive_macro_as_call_id(
 +                        self.db,
 +                        ast_id,
 +                        *derive_attr,
 +                        *derive_pos as u32,
 +                        self.def_map.krate,
 +                        &resolver,
 +                    );
 +
 +                    if let Ok((macro_id, def_id, call_id)) = id {
 +                        self.def_map.modules[directive.module_id].scope.set_derive_macro_invoc(
 +                            ast_id.ast_id,
 +                            call_id,
 +                            *derive_attr,
 +                            *derive_pos,
 +                        );
 +                        // Record its helper attributes.
 +                        if def_id.krate != self.def_map.krate {
 +                            let def_map = self.db.crate_def_map(def_id.krate);
 +                            if let Some(helpers) = def_map.exported_derives.get(&def_id) {
 +                                self.def_map
 +                                    .derive_helpers_in_scope
 +                                    .entry(ast_id.ast_id.map(|it| it.upcast()))
 +                                    .or_default()
 +                                    .extend(izip!(
 +                                        helpers.iter().cloned(),
 +                                        iter::repeat(macro_id),
 +                                        iter::repeat(call_id),
 +                                    ));
 +                            }
 +                        }
 +
 +                        push_resolved(directive, call_id);
 +                        res = ReachedFixedPoint::No;
 +                        return false;
 +                    }
 +                }
 +                MacroDirectiveKind::Attr { ast_id: file_ast_id, mod_item, attr, tree } => {
 +                    let &AstIdWithPath { ast_id, ref path } = file_ast_id;
 +                    let file_id = ast_id.file_id;
 +
 +                    let mut recollect_without = |collector: &mut Self| {
 +                        // Remove the original directive since we resolved it.
 +                        let mod_dir = collector.mod_dirs[&directive.module_id].clone();
 +                        collector.skip_attrs.insert(InFile::new(file_id, *mod_item), attr.id);
 +
 +                        let item_tree = tree.item_tree(self.db);
 +                        ModCollector {
 +                            def_collector: collector,
 +                            macro_depth: directive.depth,
 +                            module_id: directive.module_id,
 +                            tree_id: *tree,
 +                            item_tree: &item_tree,
 +                            mod_dir,
 +                        }
 +                        .collect(&[*mod_item], directive.container);
 +                        res = ReachedFixedPoint::No;
 +                        false
 +                    };
 +
 +                    if let Some(ident) = path.as_ident() {
 +                        if let Some(helpers) = self.def_map.derive_helpers_in_scope.get(&ast_id) {
 +                            if helpers.iter().any(|(it, ..)| it == ident) {
 +                                cov_mark::hit!(resolved_derive_helper);
 +                                // Resolved to derive helper. Collect the item's attributes again,
 +                                // starting after the derive helper.
 +                                return recollect_without(self);
 +                            }
 +                        }
 +                    }
 +
 +                    let def = match resolver_def_id(path.clone()) {
 +                        Some(def) if def.is_attribute() => def,
 +                        _ => return true,
 +                    };
 +                    if matches!(
 +                        def,
 +                        MacroDefId { kind:MacroDefKind::BuiltInAttr(expander, _),.. }
 +                        if expander.is_derive()
 +                    ) {
 +                        // Resolved to `#[derive]`
 +
 +                        let item_tree = tree.item_tree(self.db);
 +                        let ast_adt_id: FileAstId<ast::Adt> = match *mod_item {
 +                            ModItem::Struct(strukt) => item_tree[strukt].ast_id().upcast(),
 +                            ModItem::Union(union) => item_tree[union].ast_id().upcast(),
 +                            ModItem::Enum(enum_) => item_tree[enum_].ast_id().upcast(),
 +                            _ => {
 +                                let diag = DefDiagnostic::invalid_derive_target(
 +                                    directive.module_id,
 +                                    ast_id,
 +                                    attr.id,
 +                                );
 +                                self.def_map.diagnostics.push(diag);
 +                                return recollect_without(self);
 +                            }
 +                        };
 +                        let ast_id = ast_id.with_value(ast_adt_id);
 +
 +                        match attr.parse_path_comma_token_tree() {
 +                            Some(derive_macros) => {
 +                                let mut len = 0;
 +                                for (idx, path) in derive_macros.enumerate() {
 +                                    let ast_id = AstIdWithPath::new(file_id, ast_id.value, path);
 +                                    self.unresolved_macros.push(MacroDirective {
 +                                        module_id: directive.module_id,
 +                                        depth: directive.depth + 1,
 +                                        kind: MacroDirectiveKind::Derive {
 +                                            ast_id,
 +                                            derive_attr: attr.id,
 +                                            derive_pos: idx,
 +                                        },
 +                                        container: directive.container,
 +                                    });
 +                                    len = idx;
 +                                }
 +
 +                                // We treat the #[derive] macro as an attribute call, but we do not resolve it for nameres collection.
 +                                // This is just a trick to be able to resolve the input to derives as proper paths.
 +                                // Check the comment in [`builtin_attr_macro`].
 +                                let call_id = attr_macro_as_call_id(
 +                                    self.db,
 +                                    file_ast_id,
 +                                    attr,
 +                                    self.def_map.krate,
 +                                    def,
 +                                    true,
 +                                );
 +                                self.def_map.modules[directive.module_id]
 +                                    .scope
 +                                    .init_derive_attribute(ast_id, attr.id, call_id, len + 1);
 +                            }
 +                            None => {
 +                                let diag = DefDiagnostic::malformed_derive(
 +                                    directive.module_id,
 +                                    ast_id,
 +                                    attr.id,
 +                                );
 +                                self.def_map.diagnostics.push(diag);
 +                            }
 +                        }
 +
 +                        return recollect_without(self);
 +                    }
 +
 +                    // Not resolved to a derive helper or the derive attribute, so try to treat as a normal attribute.
 +                    let call_id = attr_macro_as_call_id(
 +                        self.db,
 +                        file_ast_id,
 +                        attr,
 +                        self.def_map.krate,
 +                        def,
 +                        false,
 +                    );
 +                    let loc: MacroCallLoc = self.db.lookup_intern_macro_call(call_id);
 +
 +                    // If proc attribute macro expansion is disabled, skip expanding it here
 +                    if !self.db.enable_proc_attr_macros() {
 +                        self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
 +                            directive.module_id,
 +                            loc.kind,
 +                            loc.def.krate,
 +                        ));
 +                        return recollect_without(self);
 +                    }
 +
 +                    // Skip #[test]/#[bench] expansion, which would merely result in more memory usage
 +                    // due to duplicating functions into macro expansions
 +                    if matches!(
 +                        loc.def.kind,
 +                        MacroDefKind::BuiltInAttr(expander, _)
 +                        if expander.is_test() || expander.is_bench()
 +                    ) {
 +                        return recollect_without(self);
 +                    }
 +
 +                    if let MacroDefKind::ProcMacro(exp, ..) = loc.def.kind {
 +                        if exp.is_dummy() {
 +                            // If there's no expander for the proc macro (e.g.
 +                            // because proc macros are disabled, or building the
 +                            // proc macro crate failed), report this and skip
 +                            // expansion like we would if it was disabled
 +                            self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
 +                                directive.module_id,
 +                                loc.kind,
 +                                loc.def.krate,
 +                            ));
 +
 +                            return recollect_without(self);
 +                        }
 +                    }
 +
 +                    self.def_map.modules[directive.module_id]
 +                        .scope
 +                        .add_attr_macro_invoc(ast_id, call_id);
 +
 +                    push_resolved(directive, call_id);
 +                    res = ReachedFixedPoint::No;
 +                    return false;
 +                }
 +            }
 +
 +            true
 +        });
 +        // Attribute resolution can add unresolved macro invocations, so concatenate the lists.
 +        macros.extend(mem::take(&mut self.unresolved_macros));
 +        self.unresolved_macros = macros;
 +
 +        for (module_id, depth, container, macro_call_id) in resolved {
 +            self.collect_macro_expansion(module_id, macro_call_id, depth, container);
 +        }
 +
 +        res
 +    }
 +
 +    fn collect_macro_expansion(
 +        &mut self,
 +        module_id: LocalModuleId,
 +        macro_call_id: MacroCallId,
 +        depth: usize,
 +        container: ItemContainerId,
 +    ) {
 +        if EXPANSION_DEPTH_LIMIT.check(depth).is_err() {
 +            cov_mark::hit!(macro_expansion_overflow);
 +            tracing::warn!("macro expansion is too deep");
 +            return;
 +        }
 +        let file_id = macro_call_id.as_file();
 +
 +        // First, fetch the raw expansion result for purposes of error reporting. This goes through
 +        // `macro_expand_error` to avoid depending on the full expansion result (to improve
 +        // incrementality).
 +        let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
 +        let err = self.db.macro_expand_error(macro_call_id);
 +        if let Some(err) = err {
 +            let diag = match err {
 +                hir_expand::ExpandError::UnresolvedProcMacro(krate) => {
 +                    always!(krate == loc.def.krate);
 +                    // Missing proc macros are non-fatal, so they are handled specially.
 +                    DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone(), loc.def.krate)
 +                }
 +                _ => DefDiagnostic::macro_error(module_id, loc.kind.clone(), err.to_string()),
 +            };
 +
 +            self.def_map.diagnostics.push(diag);
 +        }
 +
 +        // Then, fetch and process the item tree. This will reuse the expansion result from above.
 +        let item_tree = self.db.file_item_tree(file_id);
 +        let mod_dir = self.mod_dirs[&module_id].clone();
 +        ModCollector {
 +            def_collector: &mut *self,
 +            macro_depth: depth,
 +            tree_id: TreeId::new(file_id, None),
 +            module_id,
 +            item_tree: &item_tree,
 +            mod_dir,
 +        }
 +        .collect(item_tree.top_level_items(), container);
 +    }
 +
 +    fn finish(mut self) -> DefMap {
 +        // Emit diagnostics for all remaining unexpanded macros.
 +
 +        let _p = profile::span("DefCollector::finish");
 +
 +        for directive in &self.unresolved_macros {
 +            match &directive.kind {
 +                MacroDirectiveKind::FnLike { ast_id, expand_to } => {
 +                    let macro_call_as_call_id = macro_call_as_call_id(
 +                        self.db,
 +                        ast_id,
 +                        *expand_to,
 +                        self.def_map.krate,
 +                        |path| {
 +                            let resolved_res = self.def_map.resolve_path_fp_with_macro(
 +                                self.db,
 +                                ResolveMode::Other,
 +                                directive.module_id,
 +                                &path,
 +                                BuiltinShadowMode::Module,
 +                            );
 +                            resolved_res
 +                                .resolved_def
 +                                .take_macros()
 +                                .map(|it| macro_id_to_def_id(self.db, it))
 +                        },
 +                        &mut |_| (),
 +                    );
 +                    if let Err(UnresolvedMacro { path }) = macro_call_as_call_id {
 +                        self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
 +                            directive.module_id,
 +                            MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: *expand_to },
 +                            path,
 +                        ));
 +                    }
 +                }
 +                MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos } => {
 +                    self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
 +                        directive.module_id,
 +                        MacroCallKind::Derive {
 +                            ast_id: ast_id.ast_id,
 +                            derive_attr_index: derive_attr.ast_index,
 +                            derive_index: *derive_pos as u32,
 +                        },
 +                        ast_id.path.clone(),
 +                    ));
 +                }
 +                // These are diagnosed by `reseed_with_unresolved_attribute`, as that function consumes them
 +                MacroDirectiveKind::Attr { .. } => {}
 +            }
 +        }
 +
 +        // Emit diagnostics for all remaining unresolved imports.
 +
 +        // We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't
 +        // resolve. We first emit diagnostics for unresolved extern crates and collect the missing
 +        // crate names. Then we emit diagnostics for unresolved imports, but only if the import
 +        // doesn't start with an unresolved crate's name. Due to renaming and reexports, this is a
 +        // heuristic, but it works in practice.
 +        let mut diagnosed_extern_crates = FxHashSet::default();
 +        for directive in &self.unresolved_imports {
 +            if let ImportSource::ExternCrate(krate) = directive.import.source {
 +                let item_tree = krate.item_tree(self.db);
 +                let extern_crate = &item_tree[krate.value];
 +
 +                diagnosed_extern_crates.insert(extern_crate.name.clone());
 +
 +                self.def_map.diagnostics.push(DefDiagnostic::unresolved_extern_crate(
 +                    directive.module_id,
 +                    InFile::new(krate.file_id(), extern_crate.ast_id),
 +                ));
 +            }
 +        }
 +
 +        for directive in &self.unresolved_imports {
 +            if let ImportSource::Import { id: import, use_tree } = directive.import.source {
 +                if matches!(
 +                    (directive.import.path.segments().first(), &directive.import.path.kind),
 +                    (Some(krate), PathKind::Plain | PathKind::Abs) if diagnosed_extern_crates.contains(krate)
 +                ) {
 +                    continue;
 +                }
 +
 +                self.def_map.diagnostics.push(DefDiagnostic::unresolved_import(
 +                    directive.module_id,
 +                    import,
 +                    use_tree,
 +                ));
 +            }
 +        }
 +
 +        self.def_map
 +    }
 +}
 +
 +/// Walks a single module, populating defs, imports and macros
 +struct ModCollector<'a, 'b> {
 +    def_collector: &'a mut DefCollector<'b>,
 +    macro_depth: usize,
 +    module_id: LocalModuleId,
 +    tree_id: TreeId,
 +    item_tree: &'a ItemTree,
 +    mod_dir: ModDir,
 +}
 +
 +impl ModCollector<'_, '_> {
 +    fn collect_in_top_module(&mut self, items: &[ModItem]) {
 +        let module = self.def_collector.def_map.module_id(self.module_id);
 +        self.collect(items, module.into())
 +    }
 +
 +    fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
 +        let krate = self.def_collector.def_map.krate;
 +
 +        // Note: don't assert that inserted value is fresh: it's simply not true
 +        // for macros.
 +        self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
 +
 +        // Prelude module is always considered to be `#[macro_use]`.
 +        if let Some(prelude_module) = self.def_collector.def_map.prelude {
 +            if prelude_module.krate != krate {
 +                cov_mark::hit!(prelude_is_macro_use);
 +                self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
 +            }
 +        }
 +
 +        // This should be processed eagerly instead of deferred to resolving.
 +        // `#[macro_use] extern crate` is hoisted to imports macros before collecting
 +        // any other items.
 +        for &item in items {
 +            let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
 +            if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) {
 +                if let ModItem::ExternCrate(id) = item {
 +                    let import = &self.item_tree[id];
 +                    let attrs = self.item_tree.attrs(
 +                        self.def_collector.db,
 +                        krate,
 +                        ModItem::from(id).into(),
 +                    );
 +                    if attrs.by_key("macro_use").exists() {
 +                        self.def_collector.import_macros_from_extern_crate(self.module_id, import);
 +                    }
 +                }
 +            }
 +        }
 +
 +        for &item in items {
 +            let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
 +            if let Some(cfg) = attrs.cfg() {
 +                if !self.is_cfg_enabled(&cfg) {
 +                    self.emit_unconfigured_diagnostic(item, &cfg);
 +                    continue;
 +                }
 +            }
 +
 +            if let Err(()) = self.resolve_attributes(&attrs, item, container) {
 +                // Do not process the item. It has at least one non-builtin attribute, so the
 +                // fixed-point algorithm is required to resolve the rest of them.
 +                continue;
 +            }
 +
 +            let db = self.def_collector.db;
 +            let module = self.def_collector.def_map.module_id(self.module_id);
 +            let def_map = &mut self.def_collector.def_map;
 +            let update_def =
 +                |def_collector: &mut DefCollector<'_>, id, name: &Name, vis, has_constructor| {
 +                    def_collector.def_map.modules[self.module_id].scope.declare(id);
 +                    def_collector.update(
 +                        self.module_id,
 +                        &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
 +                        vis,
 +                        ImportType::Named,
 +                    )
 +                };
 +            let resolve_vis = |def_map: &DefMap, visibility| {
 +                def_map
 +                    .resolve_visibility(db, self.module_id, visibility)
 +                    .unwrap_or(Visibility::Public)
 +            };
 +
 +            match item {
 +                ModItem::Mod(m) => self.collect_module(m, &attrs),
 +                ModItem::Import(import_id) => {
 +                    let imports = Import::from_use(
 +                        db,
 +                        krate,
 +                        self.item_tree,
 +                        ItemTreeId::new(self.tree_id, import_id),
 +                    );
 +                    self.def_collector.unresolved_imports.extend(imports.into_iter().map(
 +                        |import| ImportDirective {
 +                            module_id: self.module_id,
 +                            import,
 +                            status: PartialResolvedImport::Unresolved,
 +                        },
 +                    ));
 +                }
 +                ModItem::ExternCrate(import_id) => {
 +                    self.def_collector.unresolved_imports.push(ImportDirective {
 +                        module_id: self.module_id,
 +                        import: Import::from_extern_crate(
 +                            db,
 +                            krate,
 +                            self.item_tree,
 +                            ItemTreeId::new(self.tree_id, import_id),
 +                        ),
 +                        status: PartialResolvedImport::Unresolved,
 +                    })
 +                }
 +                ModItem::ExternBlock(block) => self.collect(
 +                    &self.item_tree[block].children,
 +                    ItemContainerId::ExternBlockId(
 +                        ExternBlockLoc {
 +                            container: module,
 +                            id: ItemTreeId::new(self.tree_id, block),
 +                        }
 +                        .intern(db),
 +                    ),
 +                ),
 +                ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac], container),
 +                ModItem::MacroRules(id) => self.collect_macro_rules(id, module),
 +                ModItem::MacroDef(id) => self.collect_macro_def(id, module),
 +                ModItem::Impl(imp) => {
 +                    let impl_id =
 +                        ImplLoc { container: module, id: ItemTreeId::new(self.tree_id, imp) }
 +                            .intern(db);
 +                    self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id)
 +                }
 +                ModItem::Function(id) => {
 +                    let it = &self.item_tree[id];
 +                    let fn_id =
 +                        FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
 +
 +                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                    if self.def_collector.is_proc_macro {
 +                        if self.module_id == def_map.root {
 +                            if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
 +                                let crate_root = def_map.module_id(def_map.root);
 +                                self.def_collector.export_proc_macro(
 +                                    proc_macro,
 +                                    ItemTreeId::new(self.tree_id, id),
 +                                    fn_id,
 +                                    crate_root,
 +                                );
 +                            }
 +                        }
 +                    }
 +
 +                    update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
 +                }
 +                ModItem::Struct(id) => {
 +                    let it = &self.item_tree[id];
 +
 +                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                    update_def(
 +                        self.def_collector,
 +                        StructLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
 +                            .intern(db)
 +                            .into(),
 +                        &it.name,
 +                        vis,
 +                        !matches!(it.fields, Fields::Record(_)),
 +                    );
 +                }
 +                ModItem::Union(id) => {
 +                    let it = &self.item_tree[id];
 +
 +                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                    update_def(
 +                        self.def_collector,
 +                        UnionLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
 +                            .intern(db)
 +                            .into(),
 +                        &it.name,
 +                        vis,
 +                        false,
 +                    );
 +                }
 +                ModItem::Enum(id) => {
 +                    let it = &self.item_tree[id];
 +
 +                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                    update_def(
 +                        self.def_collector,
 +                        EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
 +                            .intern(db)
 +                            .into(),
 +                        &it.name,
 +                        vis,
 +                        false,
 +                    );
 +                }
 +                ModItem::Const(id) => {
 +                    let it = &self.item_tree[id];
 +                    let const_id =
 +                        ConstLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
 +
 +                    match &it.name {
 +                        Some(name) => {
 +                            let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                            update_def(self.def_collector, const_id.into(), name, vis, false);
 +                        }
 +                        None => {
 +                            // const _: T = ...;
 +                            self.def_collector.def_map.modules[self.module_id]
 +                                .scope
 +                                .define_unnamed_const(const_id);
 +                        }
 +                    }
 +                }
 +                ModItem::Static(id) => {
 +                    let it = &self.item_tree[id];
 +
 +                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                    update_def(
 +                        self.def_collector,
 +                        StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) }
 +                            .intern(db)
 +                            .into(),
 +                        &it.name,
 +                        vis,
 +                        false,
 +                    );
 +                }
 +                ModItem::Trait(id) => {
 +                    let it = &self.item_tree[id];
 +
 +                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                    update_def(
 +                        self.def_collector,
 +                        TraitLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
 +                            .intern(db)
 +                            .into(),
 +                        &it.name,
 +                        vis,
 +                        false,
 +                    );
 +                }
 +                ModItem::TypeAlias(id) => {
 +                    let it = &self.item_tree[id];
 +
 +                    let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
 +                    update_def(
 +                        self.def_collector,
 +                        TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) }
 +                            .intern(db)
 +                            .into(),
 +                        &it.name,
 +                        vis,
 +                        false,
 +                    );
 +                }
 +            }
 +        }
 +    }
 +
 +    fn collect_module(&mut self, module_id: FileItemTreeId<Mod>, attrs: &Attrs) {
 +        let path_attr = attrs.by_key("path").string_value();
 +        let is_macro_use = attrs.by_key("macro_use").exists();
 +        let module = &self.item_tree[module_id];
 +        match &module.kind {
 +            // inline module, just recurse
 +            ModKind::Inline { items } => {
 +                let module_id = self.push_child_module(
 +                    module.name.clone(),
 +                    AstId::new(self.file_id(), module.ast_id),
 +                    None,
 +                    &self.item_tree[module.visibility],
 +                    module_id,
 +                );
 +
 +                if let Some(mod_dir) = self.mod_dir.descend_into_definition(&module.name, path_attr)
 +                {
 +                    ModCollector {
 +                        def_collector: &mut *self.def_collector,
 +                        macro_depth: self.macro_depth,
 +                        module_id,
 +                        tree_id: self.tree_id,
 +                        item_tree: self.item_tree,
 +                        mod_dir,
 +                    }
 +                    .collect_in_top_module(&*items);
 +                    if is_macro_use {
 +                        self.import_all_legacy_macros(module_id);
 +                    }
 +                }
 +            }
 +            // out of line module, resolve, parse and recurse
 +            ModKind::Outline => {
 +                let ast_id = AstId::new(self.tree_id.file_id(), module.ast_id);
 +                let db = self.def_collector.db;
 +                match self.mod_dir.resolve_declaration(db, self.file_id(), &module.name, path_attr)
 +                {
 +                    Ok((file_id, is_mod_rs, mod_dir)) => {
 +                        let item_tree = db.file_item_tree(file_id.into());
 +                        let krate = self.def_collector.def_map.krate;
 +                        let is_enabled = item_tree
 +                            .top_level_attrs(db, krate)
 +                            .cfg()
 +                            .map_or(true, |cfg| self.is_cfg_enabled(&cfg));
 +                        if is_enabled {
 +                            let module_id = self.push_child_module(
 +                                module.name.clone(),
 +                                ast_id,
 +                                Some((file_id, is_mod_rs)),
 +                                &self.item_tree[module.visibility],
 +                                module_id,
 +                            );
 +                            ModCollector {
 +                                def_collector: self.def_collector,
 +                                macro_depth: self.macro_depth,
 +                                module_id,
 +                                tree_id: TreeId::new(file_id.into(), None),
 +                                item_tree: &item_tree,
 +                                mod_dir,
 +                            }
 +                            .collect_in_top_module(item_tree.top_level_items());
 +                            let is_macro_use = is_macro_use
 +                                || item_tree
 +                                    .top_level_attrs(db, krate)
 +                                    .by_key("macro_use")
 +                                    .exists();
 +                            if is_macro_use {
 +                                self.import_all_legacy_macros(module_id);
 +                            }
 +                        }
 +                    }
 +                    Err(candidates) => {
 +                        self.push_child_module(
 +                            module.name.clone(),
 +                            ast_id,
 +                            None,
 +                            &self.item_tree[module.visibility],
 +                            module_id,
 +                        );
 +                        self.def_collector.def_map.diagnostics.push(
 +                            DefDiagnostic::unresolved_module(self.module_id, ast_id, candidates),
 +                        );
 +                    }
 +                };
 +            }
 +        }
 +    }
 +
 +    fn push_child_module(
 +        &mut self,
 +        name: Name,
 +        declaration: AstId<ast::Module>,
 +        definition: Option<(FileId, bool)>,
 +        visibility: &crate::visibility::RawVisibility,
 +        mod_tree_id: FileItemTreeId<Mod>,
 +    ) -> LocalModuleId {
 +        let def_map = &mut self.def_collector.def_map;
 +        let vis = def_map
 +            .resolve_visibility(self.def_collector.db, self.module_id, visibility)
 +            .unwrap_or(Visibility::Public);
 +        let modules = &mut def_map.modules;
 +        let origin = match definition {
 +            None => ModuleOrigin::Inline {
 +                definition: declaration,
 +                definition_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id),
 +            },
 +            Some((definition, is_mod_rs)) => ModuleOrigin::File {
 +                declaration,
 +                definition,
 +                is_mod_rs,
 +                declaration_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id),
 +            },
 +        };
 +
 +        let res = modules.alloc(ModuleData::new(origin, vis));
 +        modules[res].parent = Some(self.module_id);
 +        for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() {
 +            for &mac in &mac {
 +                modules[res].scope.define_legacy_macro(name.clone(), mac);
 +            }
 +        }
 +        modules[self.module_id].children.insert(name.clone(), res);
 +
 +        let module = def_map.module_id(res);
 +        let def = ModuleDefId::from(module);
 +
 +        def_map.modules[self.module_id].scope.declare(def);
 +        self.def_collector.update(
 +            self.module_id,
 +            &[(Some(name), PerNs::from_def(def, vis, false))],
 +            vis,
 +            ImportType::Named,
 +        );
 +        res
 +    }
 +
 +    /// Resolves attributes on an item.
 +    ///
 +    /// Returns `Err` when some attributes could not be resolved to builtins and have been
 +    /// registered as unresolved.
 +    ///
 +    /// If `ignore_up_to` is `Some`, attributes preceding and including that attribute will be
 +    /// assumed to be resolved already.
 +    fn resolve_attributes(
 +        &mut self,
 +        attrs: &Attrs,
 +        mod_item: ModItem,
 +        container: ItemContainerId,
 +    ) -> Result<(), ()> {
 +        let mut ignore_up_to =
 +            self.def_collector.skip_attrs.get(&InFile::new(self.file_id(), mod_item)).copied();
 +        let iter = attrs
 +            .iter()
 +            .dedup_by(|a, b| {
 +                // FIXME: this should not be required, all attributes on an item should have a
 +                // unique ID!
 +                // Still, this occurs because `#[cfg_attr]` can "expand" to multiple attributes:
 +                //     #[cfg_attr(not(off), unresolved, unresolved)]
 +                //     struct S;
 +                // We should come up with a different way to ID attributes.
 +                a.id == b.id
 +            })
 +            .skip_while(|attr| match ignore_up_to {
 +                Some(id) if attr.id == id => {
 +                    ignore_up_to = None;
 +                    true
 +                }
 +                Some(_) => true,
 +                None => false,
 +            });
 +
 +        for attr in iter {
 +            if self.def_collector.def_map.is_builtin_or_registered_attr(&attr.path) {
 +                continue;
 +            }
 +            tracing::debug!("non-builtin attribute {}", attr.path);
 +
 +            let ast_id = AstIdWithPath::new(
 +                self.file_id(),
 +                mod_item.ast_id(self.item_tree),
 +                attr.path.as_ref().clone(),
 +            );
 +            self.def_collector.unresolved_macros.push(MacroDirective {
 +                module_id: self.module_id,
 +                depth: self.macro_depth + 1,
 +                kind: MacroDirectiveKind::Attr {
 +                    ast_id,
 +                    attr: attr.clone(),
 +                    mod_item,
 +                    tree: self.tree_id,
 +                },
 +                container,
 +            });
 +
 +            return Err(());
 +        }
 +
 +        Ok(())
 +    }
 +
 +    fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>, module: ModuleId) {
 +        let krate = self.def_collector.def_map.krate;
 +        let mac = &self.item_tree[id];
 +        let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
 +        let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast());
 +
 +        let export_attr = attrs.by_key("macro_export");
 +
 +        let is_export = export_attr.exists();
 +        let local_inner = if is_export {
 +            export_attr.tt_values().flat_map(|it| &it.token_trees).any(|it| match it {
 +                tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
 +                    ident.text.contains("local_inner_macros")
 +                }
 +                _ => false,
 +            })
 +        } else {
 +            false
 +        };
 +
 +        // Case 1: builtin macros
 +        let expander = if attrs.by_key("rustc_builtin_macro").exists() {
 +            // `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name.
 +            let name;
 +            let name = match attrs.by_key("rustc_builtin_macro").string_value() {
 +                Some(it) => {
 +                    // FIXME: a hacky way to create a Name from string.
 +                    name = tt::Ident { text: it.clone(), id: tt::TokenId::unspecified() }.as_name();
 +                    &name
 +                }
 +                None => {
 +                    let explicit_name =
 +                        attrs.by_key("rustc_builtin_macro").tt_values().next().and_then(|tt| {
 +                            match tt.token_trees.first() {
 +                                Some(tt::TokenTree::Leaf(tt::Leaf::Ident(name))) => Some(name),
 +                                _ => None,
 +                            }
 +                        });
 +                    match explicit_name {
 +                        Some(ident) => {
 +                            name = ident.as_name();
 +                            &name
 +                        }
 +                        None => &mac.name,
 +                    }
 +                }
 +            };
 +            match find_builtin_macro(name) {
 +                Some(Either::Left(it)) => MacroExpander::BuiltIn(it),
 +                Some(Either::Right(it)) => MacroExpander::BuiltInEager(it),
 +                None => {
 +                    self.def_collector
 +                        .def_map
 +                        .diagnostics
 +                        .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
 +                    return;
 +                }
 +            }
 +        } else {
 +            // Case 2: normal `macro_rules!` macro
 +            MacroExpander::Declarative
 +        };
 +
 +        let macro_id = MacroRulesLoc {
 +            container: module,
 +            id: ItemTreeId::new(self.tree_id, id),
 +            local_inner,
 +            expander,
 +        }
 +        .intern(self.def_collector.db);
 +        self.def_collector.define_macro_rules(
 +            self.module_id,
 +            mac.name.clone(),
 +            macro_id,
 +            is_export,
 +        );
 +    }
 +
 +    fn collect_macro_def(&mut self, id: FileItemTreeId<MacroDef>, module: ModuleId) {
 +        let krate = self.def_collector.def_map.krate;
 +        let mac = &self.item_tree[id];
 +        let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast());
 +
 +        // Case 1: builtin macros
 +        let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
 +        let expander = if attrs.by_key("rustc_builtin_macro").exists() {
 +            if let Some(expander) = find_builtin_macro(&mac.name) {
 +                match expander {
 +                    Either::Left(it) => MacroExpander::BuiltIn(it),
 +                    Either::Right(it) => MacroExpander::BuiltInEager(it),
 +                }
 +            } else if let Some(expander) = find_builtin_derive(&mac.name) {
 +                MacroExpander::BuiltInDerive(expander)
 +            } else if let Some(expander) = find_builtin_attr(&mac.name) {
 +                MacroExpander::BuiltInAttr(expander)
 +            } else {
 +                self.def_collector
 +                    .def_map
 +                    .diagnostics
 +                    .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
 +                return;
 +            }
 +        } else {
 +            // Case 2: normal `macro`
 +            MacroExpander::Declarative
 +        };
 +
 +        let macro_id =
 +            Macro2Loc { container: module, id: ItemTreeId::new(self.tree_id, id), expander }
 +                .intern(self.def_collector.db);
 +        self.def_collector.define_macro_def(
 +            self.module_id,
 +            mac.name.clone(),
 +            macro_id,
 +            &self.item_tree[mac.visibility],
 +        );
 +    }
 +
 +    fn collect_macro_call(&mut self, mac: &MacroCall, container: ItemContainerId) {
 +        let ast_id = AstIdWithPath::new(self.file_id(), mac.ast_id, ModPath::clone(&mac.path));
 +
 +        // Case 1: try to resolve in legacy scope and expand macro_rules
 +        let mut error = None;
 +        match macro_call_as_call_id(
 +            self.def_collector.db,
 +            &ast_id,
 +            mac.expand_to,
 +            self.def_collector.def_map.krate,
 +            |path| {
 +                path.as_ident().and_then(|name| {
 +                    self.def_collector.def_map.with_ancestor_maps(
 +                        self.def_collector.db,
 +                        self.module_id,
 +                        &mut |map, module| {
 +                            map[module]
 +                                .scope
 +                                .get_legacy_macro(name)
 +                                .and_then(|it| it.last())
 +                                .map(|&it| macro_id_to_def_id(self.def_collector.db, it.into()))
 +                        },
 +                    )
 +                })
 +            },
 +            &mut |err| {
 +                error.get_or_insert(err);
 +            },
 +        ) {
 +            Ok(Ok(macro_call_id)) => {
 +                // Legacy macros need to be expanded immediately, so that any macros they produce
 +                // are in scope.
 +                self.def_collector.collect_macro_expansion(
 +                    self.module_id,
 +                    macro_call_id,
 +                    self.macro_depth + 1,
 +                    container,
 +                );
 +
 +                if let Some(err) = error {
 +                    self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
 +                        self.module_id,
 +                        MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: mac.expand_to },
 +                        err.to_string(),
 +                    ));
 +                }
 +
 +                return;
 +            }
 +            Ok(Err(_)) => {
 +                // Built-in macro failed eager expansion.
 +
 +                self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
 +                    self.module_id,
 +                    MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: mac.expand_to },
 +                    error.unwrap().to_string(),
 +                ));
 +                return;
 +            }
 +            Err(UnresolvedMacro { .. }) => (),
 +        }
 +
 +        // Case 2: resolve in module scope, expand during name resolution.
 +        self.def_collector.unresolved_macros.push(MacroDirective {
 +            module_id: self.module_id,
 +            depth: self.macro_depth + 1,
 +            kind: MacroDirectiveKind::FnLike { ast_id, expand_to: mac.expand_to },
 +            container,
 +        });
 +    }
 +
 +    fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) {
 +        let macros = self.def_collector.def_map[module_id].scope.collect_legacy_macros();
 +        for (name, macs) in macros {
 +            macs.last().map(|&mac| {
 +                self.def_collector.define_legacy_macro(self.module_id, name.clone(), mac)
 +            });
 +        }
 +    }
 +
 +    fn is_cfg_enabled(&self, cfg: &CfgExpr) -> bool {
 +        self.def_collector.cfg_options.check(cfg) != Some(false)
 +    }
 +
 +    fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) {
 +        let ast_id = item.ast_id(self.item_tree);
 +
 +        let ast_id = InFile::new(self.file_id(), ast_id);
 +        self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
 +            self.module_id,
 +            ast_id,
 +            cfg.clone(),
 +            self.def_collector.cfg_options.clone(),
 +        ));
 +    }
 +
 +    fn file_id(&self) -> HirFileId {
 +        self.tree_id.file_id()
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::{db::DefDatabase, test_db::TestDB};
 +    use base_db::{fixture::WithFixture, SourceDatabase};
 +
 +    use super::*;
 +
 +    fn do_collect_defs(db: &dyn DefDatabase, def_map: DefMap) -> DefMap {
 +        let mut collector = DefCollector {
 +            db,
 +            def_map,
 +            deps: FxHashMap::default(),
 +            glob_imports: FxHashMap::default(),
 +            unresolved_imports: Vec::new(),
 +            indeterminate_imports: Vec::new(),
 +            unresolved_macros: Vec::new(),
 +            mod_dirs: FxHashMap::default(),
 +            cfg_options: &CfgOptions::default(),
 +            proc_macros: Default::default(),
 +            from_glob_import: Default::default(),
 +            skip_attrs: Default::default(),
 +            is_proc_macro: false,
 +        };
 +        collector.seed_with_top_level();
 +        collector.collect();
 +        collector.def_map
 +    }
 +
 +    fn do_resolve(not_ra_fixture: &str) -> DefMap {
 +        let (db, file_id) = TestDB::with_single_file(not_ra_fixture);
 +        let krate = db.test_crate();
 +
 +        let edition = db.crate_graph()[krate].edition;
 +        let module_origin = ModuleOrigin::CrateRoot { definition: file_id };
 +        let def_map =
 +            DefMap::empty(krate, edition, ModuleData::new(module_origin, Visibility::Public));
 +        do_collect_defs(&db, def_map)
 +    }
 +
 +    #[test]
 +    fn test_macro_expand_will_stop_1() {
 +        do_resolve(
 +            r#"
 +macro_rules! foo {
 +    ($($ty:ty)*) => { foo!($($ty)*); }
 +}
 +foo!(KABOOM);
 +"#,
 +        );
 +        do_resolve(
 +            r#"
 +macro_rules! foo {
 +    ($($ty:ty)*) => { foo!(() $($ty)*); }
 +}
 +foo!(KABOOM);
 +"#,
 +        );
 +    }
 +
 +    #[ignore]
 +    #[test]
 +    fn test_macro_expand_will_stop_2() {
 +        // FIXME: this test does succeed, but takes quite a while: 90 seconds in
 +        // the release mode. That's why the argument is not an ra_fixture --
 +        // otherwise injection highlighting gets stuck.
 +        //
 +        // We need to find a way to fail this faster.
 +        do_resolve(
 +            r#"
 +macro_rules! foo {
 +    ($($ty:ty)*) => { foo!($($ty)* $($ty)*); }
 +}
 +foo!(KABOOM);
 +"#,
 +        );
 +    }
 +}
index 99f7f1b549e2c91f0c09e3af97a6be772f0c1b61,0000000000000000000000000000000000000000..ca7bcc814e8f8e41e4ced5c765e48f22af51a505
mode 100644,000000..100644
--- /dev/null
@@@ -1,163 -1,0 +1,162 @@@
-                 let name = name.unescaped();
 +//! This module resolves `mod foo;` declaration to file.
 +use arrayvec::ArrayVec;
 +use base_db::{AnchoredPath, FileId};
 +use hir_expand::name::Name;
 +use limit::Limit;
 +use syntax::SmolStr;
 +
 +use crate::{db::DefDatabase, HirFileId};
 +
 +const MOD_DEPTH_LIMIT: Limit = Limit::new(32);
 +
 +#[derive(Clone, Debug)]
 +pub(super) struct ModDir {
 +    /// `` for `mod.rs`, `lib.rs`
 +    /// `foo/` for `foo.rs`
 +    /// `foo/bar/` for `mod bar { mod x; }` nested in `foo.rs`
 +    /// Invariant: path.is_empty() || path.ends_with('/')
 +    dir_path: DirPath,
 +    /// inside `./foo.rs`, mods with `#[path]` should *not* be relative to `./foo/`
 +    root_non_dir_owner: bool,
 +    depth: u32,
 +}
 +
 +impl ModDir {
 +    pub(super) fn root() -> ModDir {
 +        ModDir { dir_path: DirPath::empty(), root_non_dir_owner: false, depth: 0 }
 +    }
 +
 +    pub(super) fn descend_into_definition(
 +        &self,
 +        name: &Name,
 +        attr_path: Option<&SmolStr>,
 +    ) -> Option<ModDir> {
 +        let path = match attr_path.map(SmolStr::as_str) {
 +            None => {
 +                let mut path = self.dir_path.clone();
 +                path.push(&name.to_smol_str());
 +                path
 +            }
 +            Some(attr_path) => {
 +                let mut path = self.dir_path.join_attr(attr_path, self.root_non_dir_owner);
 +                if !(path.is_empty() || path.ends_with('/')) {
 +                    path.push('/')
 +                }
 +                DirPath::new(path)
 +            }
 +        };
 +        self.child(path, false)
 +    }
 +
 +    fn child(&self, dir_path: DirPath, root_non_dir_owner: bool) -> Option<ModDir> {
 +        let depth = self.depth + 1;
 +        if MOD_DEPTH_LIMIT.check(depth as usize).is_err() {
 +            tracing::error!("MOD_DEPTH_LIMIT exceeded");
 +            cov_mark::hit!(circular_mods);
 +            return None;
 +        }
 +        Some(ModDir { dir_path, root_non_dir_owner, depth })
 +    }
 +
 +    pub(super) fn resolve_declaration(
 +        &self,
 +        db: &dyn DefDatabase,
 +        file_id: HirFileId,
 +        name: &Name,
 +        attr_path: Option<&SmolStr>,
 +    ) -> Result<(FileId, bool, ModDir), Box<[String]>> {
++        let name = name.unescaped();
 +        let orig_file_id = file_id.original_file(db.upcast());
 +
 +        let mut candidate_files = ArrayVec::<_, 2>::new();
 +        match attr_path {
 +            Some(attr_path) => {
 +                candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner))
 +            }
 +            None if file_id.is_include_macro(db.upcast()) => {
-                 let name = name.unescaped();
 +                candidate_files.push(format!("{}.rs", name));
 +                candidate_files.push(format!("{}/mod.rs", name));
 +            }
 +            None => {
 +                candidate_files.push(format!("{}{}.rs", self.dir_path.0, name));
 +                candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name));
 +            }
 +        };
 +
 +        for candidate in candidate_files.iter() {
 +            let path = AnchoredPath { anchor: orig_file_id, path: candidate.as_str() };
 +            if let Some(file_id) = db.resolve_path(path) {
 +                let is_mod_rs = candidate.ends_with("/mod.rs");
 +
 +                let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() {
 +                    (DirPath::empty(), false)
 +                } else {
 +                    (DirPath::new(format!("{}/", name)), true)
 +                };
 +                if let Some(mod_dir) = self.child(dir_path, root_non_dir_owner) {
 +                    return Ok((file_id, is_mod_rs, mod_dir));
 +                }
 +            }
 +        }
 +        Err(candidate_files.into_iter().collect())
 +    }
 +}
 +
 +#[derive(Clone, Debug)]
 +struct DirPath(String);
 +
 +impl DirPath {
 +    fn assert_invariant(&self) {
 +        assert!(self.0.is_empty() || self.0.ends_with('/'));
 +    }
 +    fn new(repr: String) -> DirPath {
 +        let res = DirPath(repr);
 +        res.assert_invariant();
 +        res
 +    }
 +    fn empty() -> DirPath {
 +        DirPath::new(String::new())
 +    }
 +    fn push(&mut self, name: &str) {
 +        self.0.push_str(name);
 +        self.0.push('/');
 +        self.assert_invariant();
 +    }
 +    fn parent(&self) -> Option<&str> {
 +        if self.0.is_empty() {
 +            return None;
 +        };
 +        let idx =
 +            self.0[..self.0.len() - '/'.len_utf8()].rfind('/').map_or(0, |it| it + '/'.len_utf8());
 +        Some(&self.0[..idx])
 +    }
 +    /// So this is the case which doesn't really work I think if we try to be
 +    /// 100% platform agnostic:
 +    ///
 +    /// ```
 +    /// mod a {
 +    ///     #[path="C://sad/face"]
 +    ///     mod b { mod c; }
 +    /// }
 +    /// ```
 +    ///
 +    /// Here, we need to join logical dir path to a string path from an
 +    /// attribute. Ideally, we should somehow losslessly communicate the whole
 +    /// construction to `FileLoader`.
 +    fn join_attr(&self, mut attr: &str, relative_to_parent: bool) -> String {
 +        let base = if relative_to_parent { self.parent().unwrap() } else { &self.0 };
 +
 +        if attr.starts_with("./") {
 +            attr = &attr["./".len()..];
 +        }
 +        let tmp;
 +        let attr = if attr.contains('\\') {
 +            tmp = attr.replace('\\', "/");
 +            &tmp
 +        } else {
 +            attr
 +        };
 +        let res = format!("{}{}", base, attr);
 +        res
 +    }
 +}
index 3fa585574deec5076c4ca53f0afd3be52747310e,0000000000000000000000000000000000000000..ba3bf8b5a5cfa54075da94a07765c26f98fb2a7b
mode 100644,000000..100644
--- /dev/null
@@@ -1,843 -1,0 +1,859 @@@
 +use super::*;
 +
 +#[test]
 +fn name_res_works_for_broken_modules() {
 +    cov_mark::check!(name_res_works_for_broken_modules);
 +    check(
 +        r"
 +//- /lib.rs
 +mod foo // no `;`, no body
 +use self::foo::Baz;
 +
 +//- /foo/mod.rs
 +pub mod bar;
 +pub use self::bar::Baz;
 +
 +//- /foo/bar.rs
 +pub struct Baz;
 +",
 +        expect![[r#"
 +            crate
 +            Baz: _
 +            foo: t
 +
 +            crate::foo
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn nested_module_resolution() {
 +    check(
 +        r#"
 +//- /lib.rs
 +mod n1;
 +
 +//- /n1.rs
 +mod n2;
 +
 +//- /n1/n2.rs
 +struct X;
 +"#,
 +        expect![[r#"
 +            crate
 +            n1: t
 +
 +            crate::n1
 +            n2: t
 +
 +            crate::n1::n2
 +            X: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn nested_module_resolution_2() {
 +    check(
 +        r#"
 +//- /lib.rs
 +mod prelude;
 +mod iter;
 +
 +//- /prelude.rs
 +pub use crate::iter::Iterator;
 +
 +//- /iter.rs
 +pub use self::traits::Iterator;
 +mod traits;
 +
 +//- /iter/traits.rs
 +pub use self::iterator::Iterator;
 +mod iterator;
 +
 +//- /iter/traits/iterator.rs
 +pub trait Iterator;
 +"#,
 +        expect![[r#"
 +            crate
 +            iter: t
 +            prelude: t
 +
 +            crate::iter
 +            Iterator: t
 +            traits: t
 +
 +            crate::iter::traits
 +            Iterator: t
 +            iterator: t
 +
 +            crate::iter::traits::iterator
 +            Iterator: t
 +
 +            crate::prelude
 +            Iterator: t
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_works_for_non_standard_filenames() {
 +    check(
 +        r#"
 +//- /my_library.rs crate:my_library
 +mod foo;
 +use self::foo::Bar;
 +
 +//- /foo/mod.rs
 +pub struct Bar;
 +"#,
 +        expect![[r#"
 +            crate
 +            Bar: t v
 +            foo: t
 +
 +            crate::foo
 +            Bar: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_works_for_raw_modules() {
 +    check(
 +        r#"
 +//- /lib.rs
 +mod r#async;
 +use self::r#async::Bar;
 +
 +//- /async.rs
++mod foo;
++mod r#async;
 +pub struct Bar;
++
++//- /async/foo.rs
++pub struct Foo;
++
++//- /async/async.rs
++pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            Bar: t v
 +            r#async: t
 +
 +            crate::r#async
 +            Bar: t v
++            foo: t
++            r#async: t
++
++            crate::r#async::foo
++            Foo: t v
++
++            crate::r#async::r#async
++            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_decl_path() {
 +    check(
 +        r#"
 +//- /lib.rs
 +#[path = "bar/baz/foo.rs"]
 +mod foo;
 +use self::foo::Bar;
 +
 +//- /bar/baz/foo.rs
 +pub struct Bar;
 +"#,
 +        expect![[r#"
 +            crate
 +            Bar: t v
 +            foo: t
 +
 +            crate::foo
 +            Bar: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_module_with_path_in_mod_rs() {
 +    check(
 +        r#"
 +//- /main.rs
 +mod foo;
 +
 +//- /foo/mod.rs
 +#[path = "baz.rs"]
 +pub mod bar;
 +use self::bar::Baz;
 +
 +//- /foo/baz.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            Baz: t v
 +            bar: t
 +
 +            crate::foo::bar
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_module_with_path_non_crate_root() {
 +    check(
 +        r#"
 +//- /main.rs
 +mod foo;
 +
 +//- /foo.rs
 +#[path = "baz.rs"]
 +pub mod bar;
 +use self::bar::Baz;
 +
 +//- /baz.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            Baz: t v
 +            bar: t
 +
 +            crate::foo::bar
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_module_decl_path_super() {
 +    check(
 +        r#"
 +//- /main.rs
 +#[path = "bar/baz/module.rs"]
 +mod foo;
 +pub struct Baz;
 +
 +//- /bar/baz/module.rs
 +use super::Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            Baz: t v
 +            foo: t
 +
 +            crate::foo
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_explicit_path_mod_rs() {
 +    check(
 +        r#"
 +//- /main.rs
 +#[path = "module/mod.rs"]
 +mod foo;
 +
 +//- /module/mod.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_relative_path() {
 +    check(
 +        r#"
 +//- /main.rs
 +mod foo;
 +
 +//- /foo.rs
 +#[path = "./sub.rs"]
 +pub mod foo_bar;
 +
 +//- /sub.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            foo_bar: t
 +
 +            crate::foo::foo_bar
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_relative_path_2() {
 +    check(
 +        r#"
 +//- /main.rs
 +mod foo;
 +
 +//- /foo/mod.rs
 +#[path="../sub.rs"]
 +pub mod foo_bar;
 +
 +//- /sub.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            foo_bar: t
 +
 +            crate::foo::foo_bar
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_relative_path_outside_root() {
 +    check(
 +        r#"
 +//- /a/b/c/d/e/main.rs crate:main
 +#[path="../../../../../outside.rs"]
 +mod foo;
 +
 +//- /outside.rs
 +mod bar;
 +
 +//- /bar.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            bar: t
 +
 +            crate::foo::bar
 +            Baz: t v
 +"#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_explicit_path_mod_rs_2() {
 +    check(
 +        r#"
 +//- /main.rs
 +#[path = "module/bar/mod.rs"]
 +mod foo;
 +
 +//- /module/bar/mod.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_explicit_path_mod_rs_with_win_separator() {
 +    check(
 +        r#"
 +//- /main.rs
 +#[path = r"module\bar\mod.rs"]
 +mod foo;
 +
 +//- /module/bar/mod.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_decl_inside_inline_module_with_path_attribute() {
 +    check(
 +        r#"
 +//- /main.rs
 +#[path = "models"]
 +mod foo { mod bar; }
 +
 +//- /models/bar.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            bar: t
 +
 +            crate::foo::bar
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_decl_inside_inline_module() {
 +    check(
 +        r#"
 +//- /main.rs
 +mod foo { mod bar; }
 +
 +//- /foo/bar.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            bar: t
 +
 +            crate::foo::bar
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_decl_inside_inline_module_2_with_path_attribute() {
 +    check(
 +        r#"
 +//- /main.rs
 +#[path = "models/db"]
 +mod foo { mod bar; }
 +
 +//- /models/db/bar.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            bar: t
 +
 +            crate::foo::bar
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_decl_inside_inline_module_3() {
 +    check(
 +        r#"
 +//- /main.rs
 +#[path = "models/db"]
 +mod foo {
 +    #[path = "users.rs"]
 +    mod bar;
 +}
 +
 +//- /models/db/users.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            bar: t
 +
 +            crate::foo::bar
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_decl_inside_inline_module_empty_path() {
 +    check(
 +        r#"
 +//- /main.rs
 +#[path = ""]
 +mod foo {
 +    #[path = "users.rs"]
 +    mod bar;
 +}
 +
 +//- /users.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            bar: t
 +
 +            crate::foo::bar
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_decl_empty_path() {
 +    check(
 +        r#"
 +//- /main.rs
 +#[path = ""] // Should try to read `/` (a directory)
 +mod foo;
 +
 +//- /foo.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_decl_inside_inline_module_relative_path() {
 +    check(
 +        r#"
 +//- /main.rs
 +#[path = "./models"]
 +mod foo { mod bar; }
 +
 +//- /models/bar.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            bar: t
 +
 +            crate::foo::bar
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_decl_inside_inline_module_in_crate_root() {
 +    check(
 +        r#"
 +//- /main.rs
 +mod foo {
 +    #[path = "baz.rs"]
 +    mod bar;
 +}
 +use self::foo::bar::Baz;
 +
 +//- /foo/baz.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            Baz: t v
 +            foo: t
 +
 +            crate::foo
 +            bar: t
 +
 +            crate::foo::bar
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_decl_inside_inline_module_in_mod_rs() {
 +    check(
 +        r#"
 +//- /main.rs
 +mod foo;
 +
 +//- /foo/mod.rs
 +mod bar {
 +    #[path = "qwe.rs"]
 +    pub mod baz;
 +}
 +use self::bar::baz::Baz;
 +
 +//- /foo/bar/qwe.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            Baz: t v
 +            bar: t
 +
 +            crate::foo::bar
 +            baz: t
 +
 +            crate::foo::bar::baz
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_decl_inside_inline_module_in_non_crate_root() {
 +    check(
 +        r#"
 +//- /main.rs
 +mod foo;
 +
 +//- /foo.rs
 +mod bar {
 +    #[path = "qwe.rs"]
 +    pub mod baz;
 +}
 +use self::bar::baz::Baz;
 +
 +//- /foo/bar/qwe.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            Baz: t v
 +            bar: t
 +
 +            crate::foo::bar
 +            baz: t
 +
 +            crate::foo::bar::baz
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() {
 +    check(
 +        r#"
 +//- /main.rs
 +mod foo;
 +
 +//- /foo.rs
 +#[path = "bar"]
 +mod bar {
 +    pub mod baz;
 +}
 +use self::bar::baz::Baz;
 +
 +//- /bar/baz.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            foo: t
 +
 +            crate::foo
 +            Baz: t v
 +            bar: t
 +
 +            crate::foo::bar
 +            baz: t
 +
 +            crate::foo::bar::baz
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn module_resolution_decl_inside_module_in_non_crate_root_2() {
 +    check(
 +        r#"
 +//- /main.rs
 +#[path="module/m2.rs"]
 +mod module;
 +
 +//- /module/m2.rs
 +pub mod submod;
 +
 +//- /module/submod.rs
 +pub struct Baz;
 +"#,
 +        expect![[r#"
 +            crate
 +            module: t
 +
 +            crate::module
 +            submod: t
 +
 +            crate::module::submod
 +            Baz: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn nested_out_of_line_module() {
 +    check(
 +        r#"
 +//- /lib.rs
 +mod a {
 +    mod b {
 +        mod c;
 +    }
 +}
 +
 +//- /a/b/c.rs
 +struct X;
 +"#,
 +        expect![[r#"
 +            crate
 +            a: t
 +
 +            crate::a
 +            b: t
 +
 +            crate::a::b
 +            c: t
 +
 +            crate::a::b::c
 +            X: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn nested_out_of_line_module_with_path() {
 +    check(
 +        r#"
 +//- /lib.rs
 +mod a {
 +    #[path = "d/e"]
 +    mod b {
 +        mod c;
 +    }
 +}
 +
 +//- /a/d/e/c.rs
 +struct X;
 +"#,
 +        expect![[r#"
 +            crate
 +            a: t
 +
 +            crate::a
 +            b: t
 +
 +            crate::a::b
 +            c: t
 +
 +            crate::a::b::c
 +            X: t v
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn circular_mods() {
 +    cov_mark::check!(circular_mods);
 +    compute_crate_def_map(
 +        r#"
 +//- /lib.rs
 +mod foo;
 +//- /foo.rs
 +#[path = "./foo.rs"]
 +mod foo;
 +"#,
 +    );
 +
 +    compute_crate_def_map(
 +        r#"
 +//- /lib.rs
 +mod foo;
 +//- /foo.rs
 +#[path = "./bar.rs"]
 +mod bar;
 +//- /bar.rs
 +#[path = "./foo.rs"]
 +mod foo;
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn abs_path_ignores_local() {
 +    check(
 +        r#"
 +//- /main.rs crate:main deps:core
 +pub use ::core::hash::Hash;
 +pub mod core {}
 +
 +//- /lib.rs crate:core
 +pub mod hash { pub trait Hash {} }
 +"#,
 +        expect![[r#"
 +            crate
 +            Hash: t
 +            core: t
 +
 +            crate::core
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn cfg_in_module_file() {
 +    // Inner `#![cfg]` in a module file makes the whole module disappear.
 +    check(
 +        r#"
 +//- /main.rs
 +mod module;
 +
 +//- /module.rs
 +#![cfg(NEVER)]
 +
 +struct AlsoShoulntAppear;
 +        "#,
 +        expect![[r#"
 +            crate
 +        "#]],
 +    )
 +}
index 3163fa0f93fa573c0e2215f2ccaf5f1627340b38,0000000000000000000000000000000000000000..8aa5973cac57baae18937f13d92a45f2d83242f2
mode 100644,000000..100644
--- /dev/null
@@@ -1,912 -1,0 +1,907 @@@
-     ///
-     /// Invariant: There exists at least one Scope::ModuleScope at the start of the vec.
 +//! Name resolution façade.
 +use std::{hash::BuildHasherDefault, sync::Arc};
 +
 +use base_db::CrateId;
 +use hir_expand::name::{name, Name};
 +use indexmap::IndexMap;
 +use rustc_hash::FxHashSet;
 +use smallvec::{smallvec, SmallVec};
 +
 +use crate::{
 +    body::scope::{ExprScopes, ScopeId},
 +    builtin_type::BuiltinType,
 +    db::DefDatabase,
 +    expr::{ExprId, LabelId, PatId},
 +    generics::{GenericParams, TypeOrConstParamData},
 +    intern::Interned,
 +    item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
 +    nameres::DefMap,
 +    path::{ModPath, PathKind},
 +    per_ns::PerNs,
 +    visibility::{RawVisibility, Visibility},
 +    AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId,
 +    FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
 +    LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId,
 +    StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, VariantId,
 +};
 +
 +#[derive(Debug, Clone)]
 +pub struct Resolver {
 +    /// The stack of scopes, where the inner-most scope is the last item.
 +    ///
 +    /// When using, you generally want to process the scopes in reverse order,
 +    /// there's `scopes` *method* for that.
- // FIXME how to store these best
 +    scopes: Vec<Scope>,
++    module_scope: ModuleItemMap,
 +}
 +
-     ModuleScope(ModuleItemMap),
 +#[derive(Debug, Clone)]
 +struct ModuleItemMap {
 +    def_map: Arc<DefMap>,
 +    module_id: LocalModuleId,
 +}
 +
 +#[derive(Debug, Clone)]
 +struct ExprScope {
 +    owner: DefWithBodyId,
 +    expr_scopes: Arc<ExprScopes>,
 +    scope_id: ScopeId,
 +}
 +
 +#[derive(Debug, Clone)]
 +enum Scope {
 +    /// All the items and imported names of a module
-     fn scopes(&self) -> impl Iterator<Item = &Scope> {
-         self.scopes.iter().rev()
-     }
-     fn resolve_module_path(
-         &self,
-         db: &dyn DefDatabase,
-         path: &ModPath,
-         shadow: BuiltinShadowMode,
-     ) -> PerNs {
-         let (item_map, module) = self.module_scope();
-         let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
-         if segment_index.is_some() {
-             return PerNs::none();
-         }
-         module_res
-     }
++    BlockScope(ModuleItemMap),
 +    /// Brings the generic parameters of an item into scope
 +    GenericParams { def: GenericDefId, params: Interned<GenericParams> },
 +    /// Brings `Self` in `impl` block into scope
 +    ImplDefScope(ImplId),
 +    /// Brings `Self` in enum, struct and union definitions into scope
 +    AdtScope(AdtId),
 +    /// Local bindings
 +    ExprScope(ExprScope),
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum TypeNs {
 +    SelfType(ImplId),
 +    GenericParam(TypeParamId),
 +    AdtId(AdtId),
 +    AdtSelfType(AdtId),
 +    // Yup, enum variants are added to the types ns, but any usage of variant as
 +    // type is an error.
 +    EnumVariantId(EnumVariantId),
 +    TypeAliasId(TypeAliasId),
 +    BuiltinType(BuiltinType),
 +    TraitId(TraitId),
 +    // Module belong to type ns, but the resolver is used when all module paths
 +    // are fully resolved.
 +    // ModuleId(ModuleId)
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum ResolveValueResult {
 +    ValueNs(ValueNs),
 +    Partial(TypeNs, usize),
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum ValueNs {
 +    ImplSelf(ImplId),
 +    LocalBinding(PatId),
 +    FunctionId(FunctionId),
 +    ConstId(ConstId),
 +    StaticId(StaticId),
 +    StructId(StructId),
 +    EnumVariantId(EnumVariantId),
 +    GenericParam(ConstParamId),
 +}
 +
 +impl Resolver {
 +    /// Resolve known trait from std, like `std::futures::Future`
 +    pub fn resolve_known_trait(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<TraitId> {
 +        let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
 +        match res {
 +            ModuleDefId::TraitId(it) => Some(it),
 +            _ => None,
 +        }
 +    }
 +
 +    /// Resolve known struct from std, like `std::boxed::Box`
 +    pub fn resolve_known_struct(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<StructId> {
 +        let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
 +        match res {
 +            ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it),
 +            _ => None,
 +        }
 +    }
 +
 +    /// Resolve known enum from std, like `std::result::Result`
 +    pub fn resolve_known_enum(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<EnumId> {
 +        let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
 +        match res {
 +            ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it),
 +            _ => None,
 +        }
 +    }
 +
-         let (item_map, module) = self.module_scope();
 +    pub fn resolve_module_path_in_items(&self, db: &dyn DefDatabase, path: &ModPath) -> PerNs {
 +        self.resolve_module_path(db, path, BuiltinShadowMode::Module)
 +    }
 +
 +    // FIXME: This shouldn't exist
 +    pub fn resolve_module_path_in_trait_assoc_items(
 +        &self,
 +        db: &dyn DefDatabase,
 +        path: &ModPath,
 +    ) -> Option<PerNs> {
-                 Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue,
++        let (item_map, module) = self.item_scope();
 +        let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module);
 +        match module_res.take_types()? {
 +            ModuleDefId::TraitId(it) => {
 +                let idx = idx?;
 +                let unresolved = &path.segments()[idx..];
 +                let assoc = match unresolved {
 +                    [it] => it,
 +                    _ => return None,
 +                };
 +                let &(_, assoc) = db.trait_data(it).items.iter().find(|(n, _)| n == assoc)?;
 +                Some(match assoc {
 +                    AssocItemId::FunctionId(it) => PerNs::values(it.into(), Visibility::Public),
 +                    AssocItemId::ConstId(it) => PerNs::values(it.into(), Visibility::Public),
 +                    AssocItemId::TypeAliasId(it) => PerNs::types(it.into(), Visibility::Public),
 +                })
 +            }
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn resolve_path_in_type_ns(
 +        &self,
 +        db: &dyn DefDatabase,
 +        path: &ModPath,
 +    ) -> Option<(TypeNs, Option<usize>)> {
 +        let first_name = path.segments().first()?;
 +        let skip_to_mod = path.kind != PathKind::Plain;
++        if skip_to_mod {
++            return self.module_scope.resolve_path_in_type_ns(db, path);
++        }
++
++        let remaining_idx = || if path.segments().len() == 1 { None } else { Some(1) };
++
 +        for scope in self.scopes() {
 +            match scope {
 +                Scope::ExprScope(_) => continue,
-                         let idx = if path.segments().len() == 1 { None } else { Some(1) };
-                         return Some((TypeNs::GenericParam(id), idx));
 +                Scope::GenericParams { params, def } => {
 +                    if let Some(id) = params.find_type_by_name(first_name, *def) {
-                 Scope::ImplDefScope(impl_) => {
++                        return Some((TypeNs::GenericParam(id), remaining_idx()));
 +                    }
 +                }
-                         let idx = if path.segments().len() == 1 { None } else { Some(1) };
-                         return Some((TypeNs::SelfType(*impl_), idx));
++                &Scope::ImplDefScope(impl_) => {
 +                    if first_name == &name![Self] {
-                 Scope::AdtScope(adt) => {
++                        return Some((TypeNs::SelfType(impl_), remaining_idx()));
 +                    }
 +                }
-                         let idx = if path.segments().len() == 1 { None } else { Some(1) };
-                         return Some((TypeNs::AdtSelfType(*adt), idx));
++                &Scope::AdtScope(adt) => {
 +                    if first_name == &name![Self] {
-                 Scope::ModuleScope(m) => {
++                        return Some((TypeNs::AdtSelfType(adt), remaining_idx()));
 +                    }
 +                }
-         None
++                Scope::BlockScope(m) => {
 +                    if let Some(res) = m.resolve_path_in_type_ns(db, path) {
 +                        return Some(res);
 +                    }
 +                }
 +            }
 +        }
-                 let (item_map, module) = self.module_scope();
++        self.module_scope.resolve_path_in_type_ns(db, path)
 +    }
 +
 +    pub fn resolve_path_in_type_ns_fully(
 +        &self,
 +        db: &dyn DefDatabase,
 +        path: &ModPath,
 +    ) -> Option<TypeNs> {
 +        let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?;
 +        if unresolved.is_some() {
 +            return None;
 +        }
 +        Some(res)
 +    }
 +
 +    pub fn resolve_visibility(
 +        &self,
 +        db: &dyn DefDatabase,
 +        visibility: &RawVisibility,
 +    ) -> Option<Visibility> {
 +        match visibility {
 +            RawVisibility::Module(_) => {
-                 Scope::AdtScope(_)
-                 | Scope::ExprScope(_)
-                 | Scope::GenericParams { .. }
-                 | Scope::ImplDefScope(_)
-                     if skip_to_mod =>
-                 {
-                     continue
-                 }
-                 Scope::ExprScope(scope) if n_segments <= 1 => {
++                let (item_map, module) = self.item_scope();
 +                item_map.resolve_visibility(db, module, visibility)
 +            }
 +            RawVisibility::Public => Some(Visibility::Public),
 +        }
 +    }
 +
 +    pub fn resolve_path_in_value_ns(
 +        &self,
 +        db: &dyn DefDatabase,
 +        path: &ModPath,
 +    ) -> Option<ResolveValueResult> {
 +        let n_segments = path.segments().len();
 +        let tmp = name![self];
 +        let first_name = if path.is_self() { &tmp } else { path.segments().first()? };
 +        let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
++        if skip_to_mod {
++            return self.module_scope.resolve_path_in_value_ns(db, path);
++        }
++
 +        for scope in self.scopes() {
 +            match scope {
-                 Scope::ExprScope(_) => continue,
++                Scope::ExprScope(_) if n_segments > 1 => continue,
++                Scope::ExprScope(scope) => {
 +                    let entry = scope
 +                        .expr_scopes
 +                        .entries(scope.scope_id)
 +                        .iter()
 +                        .find(|entry| entry.name() == first_name);
 +
 +                    if let Some(e) = entry {
 +                        return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat())));
 +                    }
 +                }
-                 Scope::GenericParams { params, def } if n_segments == 1 => {
 +                Scope::GenericParams { params, def } if n_segments > 1 => {
 +                    if let Some(id) = params.find_type_by_name(first_name, *def) {
 +                        let ty = TypeNs::GenericParam(id);
 +                        return Some(ResolveValueResult::Partial(ty, 1));
 +                    }
 +                }
-                 Scope::GenericParams { .. } => continue,
++                Scope::GenericParams { .. } if n_segments != 1 => continue,
++                Scope::GenericParams { params, def } => {
 +                    if let Some(id) = params.find_const_by_name(first_name, *def) {
 +                        let val = ValueNs::GenericParam(id);
 +                        return Some(ResolveValueResult::ValueNs(val));
 +                    }
 +                }
-                 Scope::ImplDefScope(impl_) => {
 +
-                         if n_segments > 1 {
-                             let ty = TypeNs::SelfType(*impl_);
-                             return Some(ResolveValueResult::Partial(ty, 1));
++                &Scope::ImplDefScope(impl_) => {
 +                    if first_name == &name![Self] {
-                             return Some(ResolveValueResult::ValueNs(ValueNs::ImplSelf(*impl_)));
-                         }
++                        return Some(if n_segments > 1 {
++                            ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1)
 +                        } else {
-                     if n_segments == 1 {
-                         // bare `Self` doesn't work in the value namespace in a struct/enum definition
-                         continue;
-                     }
++                            ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_))
++                        });
 +                    }
 +                }
++                // bare `Self` doesn't work in the value namespace in a struct/enum definition
++                Scope::AdtScope(_) if n_segments == 1 => continue,
 +                Scope::AdtScope(adt) => {
-                 Scope::ModuleScope(m) => {
 +                    if first_name == &name![Self] {
 +                        let ty = TypeNs::AdtSelfType(*adt);
 +                        return Some(ResolveValueResult::Partial(ty, 1));
 +                    }
 +                }
 +
-             match BuiltinType::by_name(&path.segments()[0]) {
-                 Some(builtin) => {
-                     return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1));
-                 }
-                 None => {}
++                Scope::BlockScope(m) => {
 +                    if let Some(def) = m.resolve_path_in_value_ns(db, path) {
 +                        return Some(def);
 +                    }
 +                }
 +            }
 +        }
 +
++        if let res @ Some(_) = self.module_scope.resolve_path_in_value_ns(db, path) {
++            return res;
++        }
++
 +        // If a path of the shape `u16::from_le_bytes` failed to resolve at all, then we fall back
 +        // to resolving to the primitive type, to allow this to still work in the presence of
 +        // `use core::u16;`.
 +        if path.kind == PathKind::Plain && path.segments().len() > 1 {
-         let (item_map, module) = self.module_scope();
++            if let Some(builtin) = BuiltinType::by_name(&path.segments()[0]) {
++                return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1));
 +            }
 +        }
 +
 +        None
 +    }
 +
 +    pub fn resolve_path_in_value_ns_fully(
 +        &self,
 +        db: &dyn DefDatabase,
 +        path: &ModPath,
 +    ) -> Option<ValueNs> {
 +        match self.resolve_path_in_value_ns(db, path)? {
 +            ResolveValueResult::ValueNs(it) => Some(it),
 +            ResolveValueResult::Partial(..) => None,
 +        }
 +    }
 +
 +    pub fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroId> {
-                 Scope::ModuleScope(m) => {
-                     if let Some(prelude) = m.def_map.prelude() {
-                         let prelude_def_map = prelude.def_map(db);
-                         traits.extend(prelude_def_map[prelude.local_id].scope.traits());
-                     }
-                     traits.extend(m.def_map[m.module_id].scope.traits());
-                     // Add all traits that are in scope because of the containing DefMaps
-                     m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| {
-                         if let Some(prelude) = def_map.prelude() {
-                             let prelude_def_map = prelude.def_map(db);
-                             traits.extend(prelude_def_map[prelude.local_id].scope.traits());
-                         }
-                         traits.extend(def_map[module].scope.traits());
-                         None::<()>
-                     });
-                 }
++        let (item_map, module) = self.item_scope();
 +        item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros()
 +    }
 +
 +    /// Returns a set of names available in the current scope.
 +    ///
 +    /// Note that this is a somewhat fuzzy concept -- internally, the compiler
 +    /// doesn't necessary follow a strict scoping discipline. Rather, it just
 +    /// tells for each ident what it resolves to.
 +    ///
 +    /// A good example is something like `str::from_utf8`. From scopes point of
 +    /// view, this code is erroneous -- both `str` module and `str` type occupy
 +    /// the same type namespace.
 +    ///
 +    /// We don't try to model that super-correctly -- this functionality is
 +    /// primarily exposed for completions.
 +    ///
 +    /// Note that in Rust one name can be bound to several items:
 +    ///
 +    /// ```
 +    /// macro_rules! t { () => (()) }
 +    /// type t = t!();
 +    /// const t: t = t!()
 +    /// ```
 +    ///
 +    /// That's why we return a multimap.
 +    ///
 +    /// The shadowing is accounted for: in
 +    ///
 +    /// ```
 +    /// let x = 92;
 +    /// {
 +    ///     let x = 92;
 +    ///     $0
 +    /// }
 +    /// ```
 +    ///
 +    /// there will be only one entry for `x` in the result.
 +    ///
 +    /// The result is ordered *roughly* from the innermost scope to the
 +    /// outermost: when the name is introduced in two namespaces in two scopes,
 +    /// we use the position of the first scope.
 +    pub fn names_in_scope(
 +        &self,
 +        db: &dyn DefDatabase,
 +    ) -> FxIndexMap<Name, SmallVec<[ScopeDef; 1]>> {
 +        let mut res = ScopeNames::default();
 +        for scope in self.scopes() {
 +            scope.process_names(&mut res, db);
 +        }
++        let ModuleItemMap { ref def_map, module_id } = self.module_scope;
++        // FIXME: should we provide `self` here?
++        // f(
++        //     Name::self_param(),
++        //     PerNs::types(Resolution::Def {
++        //         def: m.module.into(),
++        //     }),
++        // );
++        def_map[module_id].scope.entries().for_each(|(name, def)| {
++            res.add_per_ns(name, def);
++        });
++        def_map[module_id].scope.legacy_macros().for_each(|(name, macs)| {
++            macs.iter().for_each(|&mac| {
++                res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac))));
++            })
++        });
++        def_map.extern_prelude().for_each(|(name, &def)| {
++            res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def)));
++        });
++        BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
++            res.add_per_ns(name, def);
++        });
++        if let Some(prelude) = def_map.prelude() {
++            let prelude_def_map = prelude.def_map(db);
++            for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
++                res.add_per_ns(name, def)
++            }
++        }
 +        res.map
 +    }
 +
 +    pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> {
 +        let mut traits = FxHashSet::default();
++
 +        for scope in self.scopes() {
 +            match scope {
-         traits
-     }
++                Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()),
 +                &Scope::ImplDefScope(impl_) => {
 +                    if let Some(target_trait) = &db.impl_data(impl_).target_trait {
 +                        if let Some(TypeNs::TraitId(trait_)) =
 +                            self.resolve_path_in_type_ns_fully(db, target_trait.path.mod_path())
 +                        {
 +                            traits.insert(trait_);
 +                        }
 +                    }
 +                }
 +                _ => (),
 +            }
 +        }
-     fn module_scope(&self) -> (&DefMap, LocalModuleId) {
-         self.scopes()
-             .find_map(|scope| match scope {
-                 Scope::ModuleScope(m) => Some((&*m.def_map, m.module_id)),
-                 _ => None,
-             })
-             .expect("module scope invariant violated")
 +
-         let (def_map, local_id) = self.module_scope();
++        // Fill in the prelude traits
++        if let Some(prelude) = self.module_scope.def_map.prelude() {
++            let prelude_def_map = prelude.def_map(db);
++            traits.extend(prelude_def_map[prelude.local_id].scope.traits());
++        }
++        // Fill in module visible traits
++        traits.extend(self.module_scope.def_map[self.module_scope.module_id].scope.traits());
++        traits
 +    }
 +
 +    pub fn module(&self) -> ModuleId {
-         self.def_map().krate()
++        let (def_map, local_id) = self.item_scope();
 +        def_map.module_id(local_id)
 +    }
 +
 +    pub fn krate(&self) -> CrateId {
-         self.scopes
-             .get(0)
-             .and_then(|scope| match scope {
-                 Scope::ModuleScope(m) => Some(&m.def_map),
-                 _ => None,
-             })
-             .expect("module scope invariant violated")
++        self.module_scope.def_map.krate()
 +    }
 +
 +    pub fn def_map(&self) -> &DefMap {
-             Scope::ModuleScope(m) => {
-                 // FIXME: should we provide `self` here?
-                 // f(
-                 //     Name::self_param(),
-                 //     PerNs::types(Resolution::Def {
-                 //         def: m.module.into(),
-                 //     }),
-                 // );
++        self.item_scope().0
 +    }
 +
 +    pub fn where_predicates_in_scope(
 +        &self,
 +    ) -> impl Iterator<Item = &crate::generics::WherePredicate> {
 +        self.scopes()
 +            .filter_map(|scope| match scope {
 +                Scope::GenericParams { params, .. } => Some(params),
 +                _ => None,
 +            })
 +            .flat_map(|params| params.where_predicates.iter())
 +    }
 +
 +    pub fn generic_def(&self) -> Option<GenericDefId> {
 +        self.scopes().find_map(|scope| match scope {
 +            Scope::GenericParams { def, .. } => Some(*def),
 +            _ => None,
 +        })
 +    }
 +
 +    pub fn body_owner(&self) -> Option<DefWithBodyId> {
 +        self.scopes().find_map(|scope| match scope {
 +            Scope::ExprScope(it) => Some(it.owner),
 +            _ => None,
 +        })
 +    }
 +}
 +
++impl Resolver {
++    fn scopes(&self) -> impl Iterator<Item = &Scope> {
++        self.scopes.iter().rev()
++    }
++
++    fn resolve_module_path(
++        &self,
++        db: &dyn DefDatabase,
++        path: &ModPath,
++        shadow: BuiltinShadowMode,
++    ) -> PerNs {
++        let (item_map, module) = self.item_scope();
++        let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
++        if segment_index.is_some() {
++            return PerNs::none();
++        }
++        module_res
++    }
++
++    /// The innermost block scope that contains items or the module scope that contains this resolver.
++    fn item_scope(&self) -> (&DefMap, LocalModuleId) {
++        self.scopes()
++            .find_map(|scope| match scope {
++                Scope::BlockScope(m) => Some((&*m.def_map, m.module_id)),
++                _ => None,
++            })
++            .unwrap_or((&self.module_scope.def_map, self.module_scope.module_id))
++    }
++}
++
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +pub enum ScopeDef {
 +    ModuleDef(ModuleDefId),
 +    Unknown,
 +    ImplSelfType(ImplId),
 +    AdtSelfType(AdtId),
 +    GenericParam(GenericParamId),
 +    Local(PatId),
 +    Label(LabelId),
 +}
 +
 +impl Scope {
 +    fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) {
 +        match self {
-                 m.def_map.extern_prelude().for_each(|(name, &def)| {
-                     acc.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def)));
-                 });
-                 BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
-                     acc.add_per_ns(name, def);
-                 });
-                 if let Some(prelude) = m.def_map.prelude() {
-                     let prelude_def_map = prelude.def_map(db);
-                     for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
-                         acc.add_per_ns(name, def)
-                     }
-                 }
++            Scope::BlockScope(m) => {
 +                m.def_map[m.module_id].scope.entries().for_each(|(name, def)| {
 +                    acc.add_per_ns(name, def);
 +                });
 +                m.def_map[m.module_id].scope.legacy_macros().for_each(|(name, macs)| {
 +                    macs.iter().for_each(|&mac| {
 +                        acc.add(
 +                            name,
 +                            ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac))),
 +                        );
 +                    })
 +                });
-                 r = r.push_module_scope(def_map, root);
 +            }
 +            Scope::GenericParams { params, def: parent } => {
 +                let parent = *parent;
 +                for (local_id, param) in params.type_or_consts.iter() {
 +                    if let Some(name) = &param.name() {
 +                        let id = TypeOrConstParamId { parent, local_id };
 +                        let data = &db.generic_params(parent).type_or_consts[local_id];
 +                        acc.add(
 +                            name,
 +                            ScopeDef::GenericParam(match data {
 +                                TypeOrConstParamData::TypeParamData(_) => {
 +                                    GenericParamId::TypeParamId(TypeParamId::from_unchecked(id))
 +                                }
 +                                TypeOrConstParamData::ConstParamData(_) => {
 +                                    GenericParamId::ConstParamId(ConstParamId::from_unchecked(id))
 +                                }
 +                            }),
 +                        );
 +                    }
 +                }
 +                for (local_id, param) in params.lifetimes.iter() {
 +                    let id = LifetimeParamId { parent, local_id };
 +                    acc.add(&param.name, ScopeDef::GenericParam(id.into()))
 +                }
 +            }
 +            Scope::ImplDefScope(i) => {
 +                acc.add(&name![Self], ScopeDef::ImplSelfType(*i));
 +            }
 +            Scope::AdtScope(i) => {
 +                acc.add(&name![Self], ScopeDef::AdtSelfType(*i));
 +            }
 +            Scope::ExprScope(scope) => {
 +                if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) {
 +                    acc.add(&name, ScopeDef::Label(label))
 +                }
 +                scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| {
 +                    acc.add_local(e.name(), e.pat());
 +                });
 +            }
 +        }
 +    }
 +}
 +
 +// needs arbitrary_self_types to be a method... or maybe move to the def?
 +pub fn resolver_for_expr(db: &dyn DefDatabase, owner: DefWithBodyId, expr_id: ExprId) -> Resolver {
 +    let scopes = db.expr_scopes(owner);
 +    resolver_for_scope(db, owner, scopes.scope_for(expr_id))
 +}
 +
 +pub fn resolver_for_scope(
 +    db: &dyn DefDatabase,
 +    owner: DefWithBodyId,
 +    scope_id: Option<ScopeId>,
 +) -> Resolver {
 +    let mut r = owner.resolver(db);
 +    let scopes = db.expr_scopes(owner);
 +    let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
 +    r.scopes.reserve(scope_chain.len());
 +
 +    for scope in scope_chain.into_iter().rev() {
 +        if let Some(block) = scopes.block(scope) {
 +            if let Some(def_map) = db.block_def_map(block) {
 +                let root = def_map.root();
-     fn push_module_scope(self, def_map: Arc<DefMap>, module_id: LocalModuleId) -> Resolver {
-         self.push_scope(Scope::ModuleScope(ModuleItemMap { def_map, module_id }))
++                r = r.push_block_scope(def_map, root);
 +                // FIXME: This adds as many module scopes as there are blocks, but resolving in each
 +                // already traverses all parents, so this is O(n²). I think we could only store the
 +                // innermost module scope instead?
 +            }
 +        }
 +
 +        r = r.push_expr_scope(owner, Arc::clone(&scopes), scope);
 +    }
 +    r
 +}
 +
 +impl Resolver {
 +    fn push_scope(mut self, scope: Scope) -> Resolver {
 +        self.scopes.push(scope);
 +        self
 +    }
 +
 +    fn push_generic_params_scope(self, db: &dyn DefDatabase, def: GenericDefId) -> Resolver {
 +        let params = db.generic_params(def);
 +        self.push_scope(Scope::GenericParams { def, params })
 +    }
 +
 +    fn push_impl_def_scope(self, impl_def: ImplId) -> Resolver {
 +        self.push_scope(Scope::ImplDefScope(impl_def))
 +    }
 +
-         let mut modules: SmallVec<[_; 2]> = smallvec![(def_map.clone(), self.local_id)];
++    fn push_block_scope(self, def_map: Arc<DefMap>, module_id: LocalModuleId) -> Resolver {
++        self.push_scope(Scope::BlockScope(ModuleItemMap { def_map, module_id }))
 +    }
 +
 +    fn push_expr_scope(
 +        self,
 +        owner: DefWithBodyId,
 +        expr_scopes: Arc<ExprScopes>,
 +        scope_id: ScopeId,
 +    ) -> Resolver {
 +        self.push_scope(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id }))
 +    }
 +}
 +
 +impl ModuleItemMap {
 +    fn resolve_path_in_value_ns(
 +        &self,
 +        db: &dyn DefDatabase,
 +        path: &ModPath,
 +    ) -> Option<ResolveValueResult> {
 +        let (module_def, idx) =
 +            self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
 +        match idx {
 +            None => {
 +                let value = to_value_ns(module_def)?;
 +                Some(ResolveValueResult::ValueNs(value))
 +            }
 +            Some(idx) => {
 +                let ty = match module_def.take_types()? {
 +                    ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
 +                    ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
 +                    ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it),
 +                    ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
 +
 +                    ModuleDefId::ModuleId(_)
 +                    | ModuleDefId::FunctionId(_)
 +                    | ModuleDefId::EnumVariantId(_)
 +                    | ModuleDefId::ConstId(_)
 +                    | ModuleDefId::MacroId(_)
 +                    | ModuleDefId::StaticId(_) => return None,
 +                };
 +                Some(ResolveValueResult::Partial(ty, idx))
 +            }
 +        }
 +    }
 +
 +    fn resolve_path_in_type_ns(
 +        &self,
 +        db: &dyn DefDatabase,
 +        path: &ModPath,
 +    ) -> Option<(TypeNs, Option<usize>)> {
 +        let (module_def, idx) =
 +            self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
 +        let res = to_type_ns(module_def)?;
 +        Some((res, idx))
 +    }
 +}
 +
 +fn to_value_ns(per_ns: PerNs) -> Option<ValueNs> {
 +    let res = match per_ns.take_values()? {
 +        ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
 +        ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
 +        ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it),
 +        ModuleDefId::ConstId(it) => ValueNs::ConstId(it),
 +        ModuleDefId::StaticId(it) => ValueNs::StaticId(it),
 +
 +        ModuleDefId::AdtId(AdtId::EnumId(_) | AdtId::UnionId(_))
 +        | ModuleDefId::TraitId(_)
 +        | ModuleDefId::TypeAliasId(_)
 +        | ModuleDefId::BuiltinType(_)
 +        | ModuleDefId::MacroId(_)
 +        | ModuleDefId::ModuleId(_) => return None,
 +    };
 +    Some(res)
 +}
 +
 +fn to_type_ns(per_ns: PerNs) -> Option<TypeNs> {
 +    let res = match per_ns.take_types()? {
 +        ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
 +        ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it),
 +
 +        ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it),
 +        ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
 +
 +        ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
 +
 +        ModuleDefId::FunctionId(_)
 +        | ModuleDefId::ConstId(_)
 +        | ModuleDefId::MacroId(_)
 +        | ModuleDefId::StaticId(_)
 +        | ModuleDefId::ModuleId(_) => return None,
 +    };
 +    Some(res)
 +}
 +
 +type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<rustc_hash::FxHasher>>;
 +#[derive(Default)]
 +struct ScopeNames {
 +    map: FxIndexMap<Name, SmallVec<[ScopeDef; 1]>>,
 +}
 +
 +impl ScopeNames {
 +    fn add(&mut self, name: &Name, def: ScopeDef) {
 +        let set = self.map.entry(name.clone()).or_default();
 +        if !set.contains(&def) {
 +            set.push(def)
 +        }
 +    }
 +    fn add_per_ns(&mut self, name: &Name, def: PerNs) {
 +        if let &Some((ty, _)) = &def.types {
 +            self.add(name, ScopeDef::ModuleDef(ty))
 +        }
 +        if let &Some((def, _)) = &def.values {
 +            self.add(name, ScopeDef::ModuleDef(def))
 +        }
 +        if let &Some((mac, _)) = &def.macros {
 +            self.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac)))
 +        }
 +        if def.is_none() {
 +            self.add(name, ScopeDef::Unknown)
 +        }
 +    }
 +    fn add_local(&mut self, name: &Name, pat: PatId) {
 +        let set = self.map.entry(name.clone()).or_default();
 +        // XXX: hack, account for local (and only local) shadowing.
 +        //
 +        // This should be somewhat more principled and take namespaces into
 +        // accounts, but, alas, scoping rules are a hoax. `str` type and `str`
 +        // module can be both available in the same scope.
 +        if set.iter().any(|it| matches!(it, &ScopeDef::Local(_))) {
 +            cov_mark::hit!(shadowing_shows_single_completion);
 +            return;
 +        }
 +        set.push(ScopeDef::Local(pat))
 +    }
 +}
 +
 +pub trait HasResolver: Copy {
 +    /// Builds a resolver for type references inside this def.
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver;
 +}
 +
 +impl HasResolver for ModuleId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        let mut def_map = self.def_map(db);
-             modules.push((def_map.clone(), parent.local_id));
++        let mut modules: SmallVec<[_; 1]> = smallvec![];
++        let mut module_id = self.local_id;
 +        while let Some(parent) = def_map.parent() {
++            modules.push((def_map, module_id));
 +            def_map = parent.def_map(db);
-         let mut resolver = Resolver { scopes: Vec::with_capacity(modules.len()) };
++            module_id = parent.local_id;
 +        }
-             resolver = resolver.push_module_scope(def_map, module);
++        let mut resolver = Resolver {
++            scopes: Vec::with_capacity(modules.len()),
++            module_scope: ModuleItemMap { def_map, module_id },
++        };
 +        for (def_map, module) in modules.into_iter().rev() {
++            resolver = resolver.push_block_scope(def_map, module);
 +        }
 +        resolver
 +    }
 +}
 +
 +impl HasResolver for TraitId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
 +    }
 +}
 +
 +impl<T: Into<AdtId> + Copy> HasResolver for T {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        let def = self.into();
 +        def.module(db)
 +            .resolver(db)
 +            .push_generic_params_scope(db, def.into())
 +            .push_scope(Scope::AdtScope(def))
 +    }
 +}
 +
 +impl HasResolver for FunctionId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
 +    }
 +}
 +
 +impl HasResolver for ConstId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db)
 +    }
 +}
 +
 +impl HasResolver for StaticId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db)
 +    }
 +}
 +
 +impl HasResolver for TypeAliasId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
 +    }
 +}
 +
 +impl HasResolver for ImplId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db)
 +            .container
 +            .resolver(db)
 +            .push_generic_params_scope(db, self.into())
 +            .push_impl_def_scope(self)
 +    }
 +}
 +
 +impl HasResolver for ExternBlockId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        // Same as parent's
 +        self.lookup(db).container.resolver(db)
 +    }
 +}
 +
 +impl HasResolver for DefWithBodyId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        match self {
 +            DefWithBodyId::ConstId(c) => c.resolver(db),
 +            DefWithBodyId::FunctionId(f) => f.resolver(db),
 +            DefWithBodyId::StaticId(s) => s.resolver(db),
 +        }
 +    }
 +}
 +
 +impl HasResolver for ItemContainerId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        match self {
 +            ItemContainerId::ModuleId(it) => it.resolver(db),
 +            ItemContainerId::TraitId(it) => it.resolver(db),
 +            ItemContainerId::ImplId(it) => it.resolver(db),
 +            ItemContainerId::ExternBlockId(it) => it.resolver(db),
 +        }
 +    }
 +}
 +
 +impl HasResolver for GenericDefId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        match self {
 +            GenericDefId::FunctionId(inner) => inner.resolver(db),
 +            GenericDefId::AdtId(adt) => adt.resolver(db),
 +            GenericDefId::TraitId(inner) => inner.resolver(db),
 +            GenericDefId::TypeAliasId(inner) => inner.resolver(db),
 +            GenericDefId::ImplId(inner) => inner.resolver(db),
 +            GenericDefId::EnumVariantId(inner) => inner.parent.resolver(db),
 +            GenericDefId::ConstId(inner) => inner.resolver(db),
 +        }
 +    }
 +}
 +
 +impl HasResolver for VariantId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        match self {
 +            VariantId::EnumVariantId(it) => it.parent.resolver(db),
 +            VariantId::StructId(it) => it.resolver(db),
 +            VariantId::UnionId(it) => it.resolver(db),
 +        }
 +    }
 +}
 +
 +impl HasResolver for MacroId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        match self {
 +            MacroId::Macro2Id(it) => it.resolver(db),
 +            MacroId::MacroRulesId(it) => it.resolver(db),
 +            MacroId::ProcMacroId(it) => it.resolver(db),
 +        }
 +    }
 +}
 +
 +impl HasResolver for Macro2Id {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db)
 +    }
 +}
 +
 +impl HasResolver for ProcMacroId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db)
 +    }
 +}
 +
 +impl HasResolver for MacroRulesId {
 +    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
 +        self.lookup(db).container.resolver(db)
 +    }
 +}
index d753d88470c442cb3c372494c2fc38720eb91573,0000000000000000000000000000000000000000..fc128102f225a18cc066193e649e843dd2147906
mode 100644,000000..100644
--- /dev/null
@@@ -1,999 -1,0 +1,999 @@@
-                 .map_or(true, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS))
 +//! `hir_expand` deals with macro expansion.
 +//!
 +//! Specifically, it implements a concept of `MacroFile` -- a file whose syntax
 +//! tree originates not from the text of some `FileId`, but from some macro
 +//! expansion.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +pub mod db;
 +pub mod ast_id_map;
 +pub mod name;
 +pub mod hygiene;
 +pub mod builtin_attr_macro;
 +pub mod builtin_derive_macro;
 +pub mod builtin_fn_macro;
 +pub mod proc_macro;
 +pub mod quote;
 +pub mod eager;
 +pub mod mod_path;
 +mod fixup;
 +
 +pub use mbe::{Origin, ValueResult};
 +
 +use std::{fmt, hash::Hash, iter, sync::Arc};
 +
 +use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange, ProcMacroKind};
 +use either::Either;
 +use syntax::{
 +    algo::{self, skip_trivia_token},
 +    ast::{self, AstNode, HasDocComments},
 +    Direction, SyntaxNode, SyntaxToken,
 +};
 +
 +use crate::{
 +    ast_id_map::FileAstId,
 +    builtin_attr_macro::BuiltinAttrExpander,
 +    builtin_derive_macro::BuiltinDeriveExpander,
 +    builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
 +    db::TokenExpander,
 +    mod_path::ModPath,
 +    proc_macro::ProcMacroExpander,
 +};
 +
 +pub type ExpandResult<T> = ValueResult<T, ExpandError>;
 +
 +#[derive(Debug, PartialEq, Eq, Clone)]
 +pub enum ExpandError {
 +    UnresolvedProcMacro(CrateId),
 +    Mbe(mbe::ExpandError),
 +    Other(Box<str>),
 +}
 +
 +impl From<mbe::ExpandError> for ExpandError {
 +    fn from(mbe: mbe::ExpandError) -> Self {
 +        Self::Mbe(mbe)
 +    }
 +}
 +
 +impl fmt::Display for ExpandError {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match self {
 +            ExpandError::UnresolvedProcMacro(_) => f.write_str("unresolved proc-macro"),
 +            ExpandError::Mbe(it) => it.fmt(f),
 +            ExpandError::Other(it) => f.write_str(it),
 +        }
 +    }
 +}
 +
 +/// Input to the analyzer is a set of files, where each file is identified by
 +/// `FileId` and contains source code. However, another source of source code in
 +/// Rust are macros: each macro can be thought of as producing a "temporary
 +/// file". To assign an id to such a file, we use the id of the macro call that
 +/// produced the file. So, a `HirFileId` is either a `FileId` (source code
 +/// written by user), or a `MacroCallId` (source code produced by macro).
 +///
 +/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
 +/// containing the call plus the offset of the macro call in the file. Note that
 +/// this is a recursive definition! However, the size_of of `HirFileId` is
 +/// finite (because everything bottoms out at the real `FileId`) and small
 +/// (`MacroCallId` uses the location interning. You can check details here:
 +/// <https://en.wikipedia.org/wiki/String_interning>).
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct HirFileId(HirFileIdRepr);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +enum HirFileIdRepr {
 +    FileId(FileId),
 +    MacroFile(MacroFile),
 +}
 +
 +impl From<FileId> for HirFileId {
 +    fn from(id: FileId) -> Self {
 +        HirFileId(HirFileIdRepr::FileId(id))
 +    }
 +}
 +
 +impl From<MacroFile> for HirFileId {
 +    fn from(id: MacroFile) -> Self {
 +        HirFileId(HirFileIdRepr::MacroFile(id))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct MacroFile {
 +    pub macro_call_id: MacroCallId,
 +}
 +
 +/// `MacroCallId` identifies a particular macro invocation, like
 +/// `println!("Hello, {}", world)`.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct MacroCallId(salsa::InternId);
 +impl_intern_key!(MacroCallId);
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct MacroCallLoc {
 +    pub def: MacroDefId,
 +    pub(crate) krate: CrateId,
 +    eager: Option<EagerCallInfo>,
 +    pub kind: MacroCallKind,
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct MacroDefId {
 +    pub krate: CrateId,
 +    pub kind: MacroDefKind,
 +    pub local_inner: bool,
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum MacroDefKind {
 +    Declarative(AstId<ast::Macro>),
 +    BuiltIn(BuiltinFnLikeExpander, AstId<ast::Macro>),
 +    BuiltInAttr(BuiltinAttrExpander, AstId<ast::Macro>),
 +    BuiltInDerive(BuiltinDeriveExpander, AstId<ast::Macro>),
 +    BuiltInEager(EagerExpander, AstId<ast::Macro>),
 +    ProcMacro(ProcMacroExpander, ProcMacroKind, AstId<ast::Fn>),
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +struct EagerCallInfo {
 +    /// NOTE: This can be *either* the expansion result, *or* the argument to the eager macro!
 +    arg_or_expansion: Arc<tt::Subtree>,
 +    included_file: Option<FileId>,
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum MacroCallKind {
 +    FnLike {
 +        ast_id: AstId<ast::MacroCall>,
 +        expand_to: ExpandTo,
 +    },
 +    Derive {
 +        ast_id: AstId<ast::Adt>,
 +        /// Syntactical index of the invoking `#[derive]` attribute.
 +        ///
 +        /// Outer attributes are counted first, then inner attributes. This does not support
 +        /// out-of-line modules, which may have attributes spread across 2 files!
 +        derive_attr_index: u32,
 +        /// Index of the derive macro in the derive attribute
 +        derive_index: u32,
 +    },
 +    Attr {
 +        ast_id: AstId<ast::Item>,
 +        attr_args: Arc<(tt::Subtree, mbe::TokenMap)>,
 +        /// Syntactical index of the invoking `#[attribute]`.
 +        ///
 +        /// Outer attributes are counted first, then inner attributes. This does not support
 +        /// out-of-line modules, which may have attributes spread across 2 files!
 +        invoc_attr_index: u32,
 +        /// Whether this attribute is the `#[derive]` attribute.
 +        is_derive: bool,
 +    },
 +}
 +
 +impl HirFileId {
 +    /// For macro-expansion files, returns the file original source file the
 +    /// expansion originated from.
 +    pub fn original_file(self, db: &dyn db::AstDatabase) -> FileId {
 +        let mut file_id = self;
 +        loop {
 +            match file_id.0 {
 +                HirFileIdRepr::FileId(id) => break id,
 +                HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => {
 +                    let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_call_id);
 +                    file_id = match loc.eager {
 +                        Some(EagerCallInfo { included_file: Some(file), .. }) => file.into(),
 +                        _ => loc.kind.file_id(),
 +                    };
 +                }
 +            }
 +        }
 +    }
 +
 +    pub fn expansion_level(self, db: &dyn db::AstDatabase) -> u32 {
 +        let mut level = 0;
 +        let mut curr = self;
 +        while let HirFileIdRepr::MacroFile(macro_file) = curr.0 {
 +            let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +
 +            level += 1;
 +            curr = loc.kind.file_id();
 +        }
 +        level
 +    }
 +
 +    /// If this is a macro call, returns the syntax node of the call.
 +    pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
 +        match self.0 {
 +            HirFileIdRepr::FileId(_) => None,
 +            HirFileIdRepr::MacroFile(macro_file) => {
 +                let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +                Some(loc.kind.to_node(db))
 +            }
 +        }
 +    }
 +
 +    /// If this is a macro call, returns the syntax node of the very first macro call this file resides in.
 +    pub fn original_call_node(self, db: &dyn db::AstDatabase) -> Option<(FileId, SyntaxNode)> {
 +        let mut call = match self.0 {
 +            HirFileIdRepr::FileId(_) => return None,
 +            HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => {
 +                db.lookup_intern_macro_call(macro_call_id).kind.to_node(db)
 +            }
 +        };
 +        loop {
 +            match call.file_id.0 {
 +                HirFileIdRepr::FileId(file_id) => break Some((file_id, call.value)),
 +                HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => {
 +                    call = db.lookup_intern_macro_call(macro_call_id).kind.to_node(db);
 +                }
 +            }
 +        }
 +    }
 +
 +    /// Return expansion information if it is a macro-expansion file
 +    pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> {
 +        match self.0 {
 +            HirFileIdRepr::FileId(_) => None,
 +            HirFileIdRepr::MacroFile(macro_file) => {
 +                let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +
 +                let arg_tt = loc.kind.arg(db)?;
 +
 +                let macro_def = db.macro_def(loc.def).ok()?;
 +                let (parse, exp_map) = db.parse_macro_expansion(macro_file).value?;
 +                let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
 +
 +                let def = loc.def.ast_id().left().and_then(|id| {
 +                    let def_tt = match id.to_node(db) {
 +                        ast::Macro::MacroRules(mac) => mac.token_tree()?,
 +                        ast::Macro::MacroDef(_)
 +                            if matches!(*macro_def, TokenExpander::BuiltinAttr(_)) =>
 +                        {
 +                            return None
 +                        }
 +                        ast::Macro::MacroDef(mac) => mac.body()?,
 +                    };
 +                    Some(InFile::new(id.file_id, def_tt))
 +                });
 +                let attr_input_or_mac_def = def.or_else(|| match loc.kind {
 +                    MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
 +                        let tt = ast_id
 +                            .to_node(db)
 +                            .doc_comments_and_attrs()
 +                            .nth(invoc_attr_index as usize)
 +                            .and_then(Either::left)?
 +                            .token_tree()?;
 +                        Some(InFile::new(ast_id.file_id, tt))
 +                    }
 +                    _ => None,
 +                });
 +
 +                Some(ExpansionInfo {
 +                    expanded: InFile::new(self, parse.syntax_node()),
 +                    arg: InFile::new(loc.kind.file_id(), arg_tt),
 +                    attr_input_or_mac_def,
 +                    macro_arg_shift: mbe::Shift::new(&macro_arg.0),
 +                    macro_arg,
 +                    macro_def,
 +                    exp_map,
 +                })
 +            }
 +        }
 +    }
 +
 +    /// Indicate it is macro file generated for builtin derive
 +    pub fn is_builtin_derive(&self, db: &dyn db::AstDatabase) -> Option<InFile<ast::Attr>> {
 +        match self.0 {
 +            HirFileIdRepr::FileId(_) => None,
 +            HirFileIdRepr::MacroFile(macro_file) => {
 +                let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +                let attr = match loc.def.kind {
 +                    MacroDefKind::BuiltInDerive(..) => loc.kind.to_node(db),
 +                    _ => return None,
 +                };
 +                Some(attr.with_value(ast::Attr::cast(attr.value.clone())?))
 +            }
 +        }
 +    }
 +
 +    pub fn is_custom_derive(&self, db: &dyn db::AstDatabase) -> bool {
 +        match self.0 {
 +            HirFileIdRepr::FileId(_) => false,
 +            HirFileIdRepr::MacroFile(macro_file) => {
 +                let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +                matches!(loc.def.kind, MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _))
 +            }
 +        }
 +    }
 +
 +    /// Return whether this file is an include macro
 +    pub fn is_include_macro(&self, db: &dyn db::AstDatabase) -> bool {
 +        match self.0 {
 +            HirFileIdRepr::MacroFile(macro_file) => {
 +                let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +                matches!(loc.eager, Some(EagerCallInfo { included_file: Some(_), .. }))
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    /// Return whether this file is an attr macro
 +    pub fn is_attr_macro(&self, db: &dyn db::AstDatabase) -> bool {
 +        match self.0 {
 +            HirFileIdRepr::MacroFile(macro_file) => {
 +                let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +                matches!(loc.kind, MacroCallKind::Attr { .. })
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    /// Return whether this file is the pseudo expansion of the derive attribute.
 +    /// See [`crate::builtin_attr_macro::derive_attr_expand`].
 +    pub fn is_derive_attr_pseudo_expansion(&self, db: &dyn db::AstDatabase) -> bool {
 +        match self.0 {
 +            HirFileIdRepr::MacroFile(macro_file) => {
 +                let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
 +                matches!(loc.kind, MacroCallKind::Attr { is_derive: true, .. })
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    pub fn is_macro(self) -> bool {
 +        matches!(self.0, HirFileIdRepr::MacroFile(_))
 +    }
 +
 +    pub fn macro_file(self) -> Option<MacroFile> {
 +        match self.0 {
 +            HirFileIdRepr::FileId(_) => None,
 +            HirFileIdRepr::MacroFile(m) => Some(m),
 +        }
 +    }
 +}
 +
 +impl MacroDefId {
 +    pub fn as_lazy_macro(
 +        self,
 +        db: &dyn db::AstDatabase,
 +        krate: CrateId,
 +        kind: MacroCallKind,
 +    ) -> MacroCallId {
 +        db.intern_macro_call(MacroCallLoc { def: self, krate, eager: None, kind })
 +    }
 +
 +    pub fn ast_id(&self) -> Either<AstId<ast::Macro>, AstId<ast::Fn>> {
 +        let id = match self.kind {
 +            MacroDefKind::ProcMacro(.., id) => return Either::Right(id),
 +            MacroDefKind::Declarative(id)
 +            | MacroDefKind::BuiltIn(_, id)
 +            | MacroDefKind::BuiltInAttr(_, id)
 +            | MacroDefKind::BuiltInDerive(_, id)
 +            | MacroDefKind::BuiltInEager(_, id) => id,
 +        };
 +        Either::Left(id)
 +    }
 +
 +    pub fn is_proc_macro(&self) -> bool {
 +        matches!(self.kind, MacroDefKind::ProcMacro(..))
 +    }
 +
 +    pub fn is_attribute(&self) -> bool {
 +        matches!(
 +            self.kind,
 +            MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, ProcMacroKind::Attr, _)
 +        )
 +    }
 +}
 +
 +// FIXME: attribute indices do not account for `cfg_attr`, which means that we'll strip the whole
 +// `cfg_attr` instead of just one of the attributes it expands to
 +
 +impl MacroCallKind {
 +    /// Returns the file containing the macro invocation.
 +    fn file_id(&self) -> HirFileId {
 +        match *self {
 +            MacroCallKind::FnLike { ast_id: InFile { file_id, .. }, .. }
 +            | MacroCallKind::Derive { ast_id: InFile { file_id, .. }, .. }
 +            | MacroCallKind::Attr { ast_id: InFile { file_id, .. }, .. } => file_id,
 +        }
 +    }
 +
 +    pub fn to_node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> {
 +        match self {
 +            MacroCallKind::FnLike { ast_id, .. } => {
 +                ast_id.with_value(ast_id.to_node(db).syntax().clone())
 +            }
 +            MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
 +                // FIXME: handle `cfg_attr`
 +                ast_id.with_value(ast_id.to_node(db)).map(|it| {
 +                    it.doc_comments_and_attrs()
 +                        .nth(*derive_attr_index as usize)
 +                        .and_then(|it| match it {
 +                            Either::Left(attr) => Some(attr.syntax().clone()),
 +                            Either::Right(_) => None,
 +                        })
 +                        .unwrap_or_else(|| it.syntax().clone())
 +                })
 +            }
 +            MacroCallKind::Attr { ast_id, is_derive: true, invoc_attr_index, .. } => {
 +                // FIXME: handle `cfg_attr`
 +                ast_id.with_value(ast_id.to_node(db)).map(|it| {
 +                    it.doc_comments_and_attrs()
 +                        .nth(*invoc_attr_index as usize)
 +                        .and_then(|it| match it {
 +                            Either::Left(attr) => Some(attr.syntax().clone()),
 +                            Either::Right(_) => None,
 +                        })
 +                        .unwrap_or_else(|| it.syntax().clone())
 +                })
 +            }
 +            MacroCallKind::Attr { ast_id, .. } => {
 +                ast_id.with_value(ast_id.to_node(db).syntax().clone())
 +            }
 +        }
 +    }
 +
 +    /// Returns the original file range that best describes the location of this macro call.
 +    ///
 +    /// Unlike `MacroCallKind::original_call_range`, this also spans the item of attributes and derives.
 +    pub fn original_call_range_with_body(self, db: &dyn db::AstDatabase) -> FileRange {
 +        let mut kind = self;
 +        let file_id = loop {
 +            match kind.file_id().0 {
 +                HirFileIdRepr::MacroFile(file) => {
 +                    kind = db.lookup_intern_macro_call(file.macro_call_id).kind;
 +                }
 +                HirFileIdRepr::FileId(file_id) => break file_id,
 +            }
 +        };
 +
 +        let range = match kind {
 +            MacroCallKind::FnLike { ast_id, .. } => ast_id.to_node(db).syntax().text_range(),
 +            MacroCallKind::Derive { ast_id, .. } => ast_id.to_node(db).syntax().text_range(),
 +            MacroCallKind::Attr { ast_id, .. } => ast_id.to_node(db).syntax().text_range(),
 +        };
 +
 +        FileRange { range, file_id }
 +    }
 +
 +    /// Returns the original file range that best describes the location of this macro call.
 +    ///
 +    /// Here we try to roughly match what rustc does to improve diagnostics: fn-like macros
 +    /// get the whole `ast::MacroCall`, attribute macros get the attribute's range, and derives
 +    /// get only the specific derive that is being referred to.
 +    pub fn original_call_range(self, db: &dyn db::AstDatabase) -> FileRange {
 +        let mut kind = self;
 +        let file_id = loop {
 +            match kind.file_id().0 {
 +                HirFileIdRepr::MacroFile(file) => {
 +                    kind = db.lookup_intern_macro_call(file.macro_call_id).kind;
 +                }
 +                HirFileIdRepr::FileId(file_id) => break file_id,
 +            }
 +        };
 +
 +        let range = match kind {
 +            MacroCallKind::FnLike { ast_id, .. } => ast_id.to_node(db).syntax().text_range(),
 +            MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
 +                // FIXME: should be the range of the macro name, not the whole derive
 +                ast_id
 +                    .to_node(db)
 +                    .doc_comments_and_attrs()
 +                    .nth(derive_attr_index as usize)
 +                    .expect("missing derive")
 +                    .expect_left("derive is a doc comment?")
 +                    .syntax()
 +                    .text_range()
 +            }
 +            MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => ast_id
 +                .to_node(db)
 +                .doc_comments_and_attrs()
 +                .nth(invoc_attr_index as usize)
 +                .expect("missing attribute")
 +                .expect_left("attribute macro is a doc comment?")
 +                .syntax()
 +                .text_range(),
 +        };
 +
 +        FileRange { range, file_id }
 +    }
 +
 +    fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> {
 +        match self {
 +            MacroCallKind::FnLike { ast_id, .. } => {
 +                Some(ast_id.to_node(db).token_tree()?.syntax().clone())
 +            }
 +            MacroCallKind::Derive { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()),
 +            MacroCallKind::Attr { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()),
 +        }
 +    }
 +
 +    fn expand_to(&self) -> ExpandTo {
 +        match self {
 +            MacroCallKind::FnLike { expand_to, .. } => *expand_to,
 +            MacroCallKind::Derive { .. } => ExpandTo::Items,
 +            MacroCallKind::Attr { is_derive: true, .. } => ExpandTo::Statements,
 +            MacroCallKind::Attr { .. } => ExpandTo::Items, // is this always correct?
 +        }
 +    }
 +}
 +
 +impl MacroCallId {
 +    pub fn as_file(self) -> HirFileId {
 +        MacroFile { macro_call_id: self }.into()
 +    }
 +}
 +
 +/// ExpansionInfo mainly describes how to map text range between src and expanded macro
 +#[derive(Debug, Clone, PartialEq, Eq)]
 +pub struct ExpansionInfo {
 +    expanded: InFile<SyntaxNode>,
 +    /// The argument TokenTree or item for attributes
 +    arg: InFile<SyntaxNode>,
 +    /// The `macro_rules!` or attribute input.
 +    attr_input_or_mac_def: Option<InFile<ast::TokenTree>>,
 +
 +    macro_def: Arc<TokenExpander>,
 +    macro_arg: Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>,
 +    /// A shift built from `macro_arg`'s subtree, relevant for attributes as the item is the macro arg
 +    /// and as such we need to shift tokens if they are part of an attributes input instead of their item.
 +    macro_arg_shift: mbe::Shift,
 +    exp_map: Arc<mbe::TokenMap>,
 +}
 +
 +impl ExpansionInfo {
 +    pub fn expanded(&self) -> InFile<SyntaxNode> {
 +        self.expanded.clone()
 +    }
 +
 +    pub fn call_node(&self) -> Option<InFile<SyntaxNode>> {
 +        Some(self.arg.with_value(self.arg.value.parent()?))
 +    }
 +
 +    /// Map a token down from macro input into the macro expansion.
 +    ///
 +    /// The inner workings of this function differ slightly depending on the type of macro we are dealing with:
 +    /// - declarative:
 +    ///     For declarative macros, we need to accommodate for the macro definition site(which acts as a second unchanging input)
 +    ///     , as tokens can mapped in and out of it.
 +    ///     To do this we shift all ids in the expansion by the maximum id of the definition site giving us an easy
 +    ///     way to map all the tokens.
 +    /// - attribute:
 +    ///     Attributes have two different inputs, the input tokentree in the attribute node and the item
 +    ///     the attribute is annotating. Similarly as for declarative macros we need to do a shift here
 +    ///     as well. Currently this is done by shifting the attribute input by the maximum id of the item.
 +    /// - function-like and derives:
 +    ///     Both of these only have one simple call site input so no special handling is required here.
 +    pub fn map_token_down(
 +        &self,
 +        db: &dyn db::AstDatabase,
 +        item: Option<ast::Item>,
 +        token: InFile<&SyntaxToken>,
 +    ) -> Option<impl Iterator<Item = InFile<SyntaxToken>> + '_> {
 +        assert_eq!(token.file_id, self.arg.file_id);
 +        let token_id_in_attr_input = if let Some(item) = item {
 +            // check if we are mapping down in an attribute input
 +            // this is a special case as attributes can have two inputs
 +            let call_id = self.expanded.file_id.macro_file()?.macro_call_id;
 +            let loc = db.lookup_intern_macro_call(call_id);
 +
 +            let token_range = token.value.text_range();
 +            match &loc.kind {
 +                MacroCallKind::Attr { attr_args, invoc_attr_index, is_derive, .. } => {
 +                    let attr = item
 +                        .doc_comments_and_attrs()
 +                        .nth(*invoc_attr_index as usize)
 +                        .and_then(Either::left)?;
 +                    match attr.token_tree() {
 +                        Some(token_tree)
 +                            if token_tree.syntax().text_range().contains_range(token_range) =>
 +                        {
 +                            let attr_input_start =
 +                                token_tree.left_delimiter_token()?.text_range().start();
 +                            let relative_range =
 +                                token.value.text_range().checked_sub(attr_input_start)?;
 +                            // shift by the item's tree's max id
 +                            let token_id = attr_args.1.token_by_range(relative_range)?;
 +                            let token_id = if *is_derive {
 +                                // we do not shift for `#[derive]`, as we only need to downmap the derive attribute tokens
 +                                token_id
 +                            } else {
 +                                self.macro_arg_shift.shift(token_id)
 +                            };
 +                            Some(token_id)
 +                        }
 +                        _ => None,
 +                    }
 +                }
 +                _ => None,
 +            }
 +        } else {
 +            None
 +        };
 +
 +        let token_id = match token_id_in_attr_input {
 +            Some(token_id) => token_id,
 +            // the token is not inside an attribute's input so do the lookup in the macro_arg as usual
 +            None => {
 +                let relative_range =
 +                    token.value.text_range().checked_sub(self.arg.value.text_range().start())?;
 +                let token_id = self.macro_arg.1.token_by_range(relative_range)?;
 +                // conditionally shift the id by a declaratives macro definition
 +                self.macro_def.map_id_down(token_id)
 +            }
 +        };
 +
 +        let tokens = self
 +            .exp_map
 +            .ranges_by_token(token_id, token.value.kind())
 +            .flat_map(move |range| self.expanded.value.covering_element(range).into_token());
 +
 +        Some(tokens.map(move |token| self.expanded.with_value(token)))
 +    }
 +
 +    /// Map a token up out of the expansion it resides in into the arguments of the macro call of the expansion.
 +    pub fn map_token_up(
 +        &self,
 +        db: &dyn db::AstDatabase,
 +        token: InFile<&SyntaxToken>,
 +    ) -> Option<(InFile<SyntaxToken>, Origin)> {
 +        // Fetch the id through its text range,
 +        let token_id = self.exp_map.token_by_range(token.value.text_range())?;
 +        // conditionally unshifting the id to accommodate for macro-rules def site
 +        let (mut token_id, origin) = self.macro_def.map_id_up(token_id);
 +
 +        let call_id = self.expanded.file_id.macro_file()?.macro_call_id;
 +        let loc = db.lookup_intern_macro_call(call_id);
 +
 +        // Attributes are a bit special for us, they have two inputs, the input tokentree and the annotated item.
 +        let (token_map, tt) = match &loc.kind {
 +            MacroCallKind::Attr { attr_args, is_derive: true, .. } => {
 +                (&attr_args.1, self.attr_input_or_mac_def.clone()?.syntax().cloned())
 +            }
 +            MacroCallKind::Attr { attr_args, .. } => {
 +                // try unshifting the the token id, if unshifting fails, the token resides in the non-item attribute input
 +                // note that the `TokenExpander::map_id_up` earlier only unshifts for declarative macros, so we don't double unshift with this
 +                match self.macro_arg_shift.unshift(token_id) {
 +                    Some(unshifted) => {
 +                        token_id = unshifted;
 +                        (&attr_args.1, self.attr_input_or_mac_def.clone()?.syntax().cloned())
 +                    }
 +                    None => (&self.macro_arg.1, self.arg.clone()),
 +                }
 +            }
 +            _ => match origin {
 +                mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()),
 +                mbe::Origin::Def => match (&*self.macro_def, &self.attr_input_or_mac_def) {
 +                    (TokenExpander::DeclarativeMacro { def_site_token_map, .. }, Some(tt)) => {
 +                        (def_site_token_map, tt.syntax().cloned())
 +                    }
 +                    _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"),
 +                },
 +            },
 +        };
 +
 +        let range = token_map.first_range_by_token(token_id, token.value.kind())?;
 +        let token =
 +            tt.value.covering_element(range + tt.value.text_range().start()).into_token()?;
 +        Some((tt.with_value(token), origin))
 +    }
 +}
 +
 +/// `AstId` points to an AST node in any file.
 +///
 +/// It is stable across reparses, and can be used as salsa key/value.
 +pub type AstId<N> = InFile<FileAstId<N>>;
 +
 +impl<N: AstNode> AstId<N> {
 +    pub fn to_node(&self, db: &dyn db::AstDatabase) -> N {
 +        let root = db.parse_or_expand(self.file_id).unwrap();
 +        db.ast_id_map(self.file_id).get(self.value).to_node(&root)
 +    }
 +}
 +
 +/// `InFile<T>` stores a value of `T` inside a particular file/syntax tree.
 +///
 +/// Typical usages are:
 +///
 +/// * `InFile<SyntaxNode>` -- syntax node in a file
 +/// * `InFile<ast::FnDef>` -- ast node in a file
 +/// * `InFile<TextSize>` -- offset in a file
 +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
 +pub struct InFile<T> {
 +    pub file_id: HirFileId,
 +    pub value: T,
 +}
 +
 +impl<T> InFile<T> {
 +    pub fn new(file_id: HirFileId, value: T) -> InFile<T> {
 +        InFile { file_id, value }
 +    }
 +
 +    pub fn with_value<U>(&self, value: U) -> InFile<U> {
 +        InFile::new(self.file_id, value)
 +    }
 +
 +    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> InFile<U> {
 +        InFile::new(self.file_id, f(self.value))
 +    }
 +
 +    pub fn as_ref(&self) -> InFile<&T> {
 +        self.with_value(&self.value)
 +    }
 +
 +    pub fn file_syntax(&self, db: &dyn db::AstDatabase) -> SyntaxNode {
 +        db.parse_or_expand(self.file_id).expect("source created from invalid file")
 +    }
 +}
 +
 +impl<T: Clone> InFile<&T> {
 +    pub fn cloned(&self) -> InFile<T> {
 +        self.with_value(self.value.clone())
 +    }
 +}
 +
 +impl<T> InFile<Option<T>> {
 +    pub fn transpose(self) -> Option<InFile<T>> {
 +        let value = self.value?;
 +        Some(InFile::new(self.file_id, value))
 +    }
 +}
 +
 +impl<'a> InFile<&'a SyntaxNode> {
 +    pub fn ancestors_with_macros(
 +        self,
 +        db: &dyn db::AstDatabase,
 +    ) -> impl Iterator<Item = InFile<SyntaxNode>> + Clone + '_ {
 +        iter::successors(Some(self.cloned()), move |node| match node.value.parent() {
 +            Some(parent) => Some(node.with_value(parent)),
 +            None => node.file_id.call_node(db),
 +        })
 +    }
 +
 +    /// Skips the attributed item that caused the macro invocation we are climbing up
 +    pub fn ancestors_with_macros_skip_attr_item(
 +        self,
 +        db: &dyn db::AstDatabase,
 +    ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
 +        let succ = move |node: &InFile<SyntaxNode>| match node.value.parent() {
 +            Some(parent) => Some(node.with_value(parent)),
 +            None => {
 +                let parent_node = node.file_id.call_node(db)?;
 +                if node.file_id.is_attr_macro(db) {
 +                    // macro call was an attributed item, skip it
 +                    // FIXME: does this fail if this is a direct expansion of another macro?
 +                    parent_node.map(|node| node.parent()).transpose()
 +                } else {
 +                    Some(parent_node)
 +                }
 +            }
 +        };
 +        iter::successors(succ(&self.cloned()), succ)
 +    }
 +
 +    /// Falls back to the macro call range if the node cannot be mapped up fully.
 +    ///
 +    /// For attributes and derives, this will point back to the attribute only.
 +    /// For the entire item `InFile::use original_file_range_full`.
 +    pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange {
 +        match self.file_id.0 {
 +            HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
 +            HirFileIdRepr::MacroFile(mac_file) => {
 +                if let Some(res) = self.original_file_range_opt(db) {
 +                    return res;
 +                }
 +                // Fall back to whole macro call.
 +                let loc = db.lookup_intern_macro_call(mac_file.macro_call_id);
 +                loc.kind.original_call_range(db)
 +            }
 +        }
 +    }
 +
 +    /// Attempts to map the syntax node back up its macro calls.
 +    pub fn original_file_range_opt(self, db: &dyn db::AstDatabase) -> Option<FileRange> {
 +        match ascend_node_border_tokens(db, self) {
 +            Some(InFile { file_id, value: (first, last) }) => {
 +                let original_file = file_id.original_file(db);
 +                let range = first.text_range().cover(last.text_range());
 +                if file_id != original_file.into() {
 +                    tracing::error!("Failed mapping up more for {:?}", range);
 +                    return None;
 +                }
 +                Some(FileRange { file_id: original_file, range })
 +            }
 +            _ if !self.file_id.is_macro() => Some(FileRange {
 +                file_id: self.file_id.original_file(db),
 +                range: self.value.text_range(),
 +            }),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +impl InFile<SyntaxToken> {
 +    pub fn upmap(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxToken>> {
 +        let expansion = self.file_id.expansion_info(db)?;
 +        expansion.map_token_up(db, self.as_ref()).map(|(it, _)| it)
 +    }
 +
 +    /// Falls back to the macro call range if the node cannot be mapped up fully.
 +    pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange {
 +        match self.file_id.0 {
 +            HirFileIdRepr::FileId(file_id) => FileRange { file_id, range: self.value.text_range() },
 +            HirFileIdRepr::MacroFile(mac_file) => {
 +                if let Some(res) = self.original_file_range_opt(db) {
 +                    return res;
 +                }
 +                // Fall back to whole macro call.
 +                let loc = db.lookup_intern_macro_call(mac_file.macro_call_id);
 +                loc.kind.original_call_range(db)
 +            }
 +        }
 +    }
 +
 +    /// Attempts to map the syntax node back up its macro calls.
 +    pub fn original_file_range_opt(self, db: &dyn db::AstDatabase) -> Option<FileRange> {
 +        match self.file_id.0 {
 +            HirFileIdRepr::FileId(file_id) => {
 +                Some(FileRange { file_id, range: self.value.text_range() })
 +            }
 +            HirFileIdRepr::MacroFile(_) => {
 +                let expansion = self.file_id.expansion_info(db)?;
 +                let InFile { file_id, value } = ascend_call_token(db, &expansion, self)?;
 +                let original_file = file_id.original_file(db);
 +                if file_id != original_file.into() {
 +                    return None;
 +                }
 +                Some(FileRange { file_id: original_file, range: value.text_range() })
 +            }
 +        }
 +    }
 +
 +    pub fn ancestors_with_macros(
 +        self,
 +        db: &dyn db::AstDatabase,
 +    ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
 +        self.value.parent().into_iter().flat_map({
 +            let file_id = self.file_id;
 +            move |parent| InFile::new(file_id, &parent).ancestors_with_macros(db)
 +        })
 +    }
 +}
 +
 +fn ascend_node_border_tokens(
 +    db: &dyn db::AstDatabase,
 +    InFile { file_id, value: node }: InFile<&SyntaxNode>,
 +) -> Option<InFile<(SyntaxToken, SyntaxToken)>> {
 +    let expansion = file_id.expansion_info(db)?;
 +
 +    let first_token = |node: &SyntaxNode| skip_trivia_token(node.first_token()?, Direction::Next);
 +    let last_token = |node: &SyntaxNode| skip_trivia_token(node.last_token()?, Direction::Prev);
 +
 +    let first = first_token(node)?;
 +    let last = last_token(node)?;
 +    let first = ascend_call_token(db, &expansion, InFile::new(file_id, first))?;
 +    let last = ascend_call_token(db, &expansion, InFile::new(file_id, last))?;
 +    (first.file_id == last.file_id).then(|| InFile::new(first.file_id, (first.value, last.value)))
 +}
 +
 +fn ascend_call_token(
 +    db: &dyn db::AstDatabase,
 +    expansion: &ExpansionInfo,
 +    token: InFile<SyntaxToken>,
 +) -> Option<InFile<SyntaxToken>> {
 +    let mut mapping = expansion.map_token_up(db, token.as_ref())?;
 +    while let (mapped, Origin::Call) = mapping {
 +        match mapped.file_id.expansion_info(db) {
 +            Some(info) => mapping = info.map_token_up(db, mapped.as_ref())?,
 +            None => return Some(mapped),
 +        }
 +    }
 +    None
 +}
 +
 +impl<N: AstNode> InFile<N> {
 +    pub fn descendants<T: AstNode>(self) -> impl Iterator<Item = InFile<T>> {
 +        self.value.syntax().descendants().filter_map(T::cast).map(move |n| self.with_value(n))
 +    }
 +
 +    pub fn original_ast_node(self, db: &dyn db::AstDatabase) -> Option<InFile<N>> {
 +        // This kind of upmapping can only be achieved in attribute expanded files,
 +        // as we don't have node inputs otherwise and  therefor can't find an `N` node in the input
 +        if !self.file_id.is_macro() {
 +            return Some(self);
 +        } else if !self.file_id.is_attr_macro(db) {
 +            return None;
 +        }
 +
 +        if let Some(InFile { file_id, value: (first, last) }) =
 +            ascend_node_border_tokens(db, self.syntax())
 +        {
 +            if file_id.is_macro() {
 +                let range = first.text_range().cover(last.text_range());
 +                tracing::error!("Failed mapping out of macro file for {:?}", range);
 +                return None;
 +            }
 +            // FIXME: This heuristic is brittle and with the right macro may select completely unrelated nodes
 +            let anc = algo::least_common_ancestor(&first.parent()?, &last.parent()?)?;
 +            let value = anc.ancestors().find_map(N::cast)?;
 +            return Some(InFile::new(file_id, value));
 +        }
 +        None
 +    }
 +
 +    pub fn syntax(&self) -> InFile<&SyntaxNode> {
 +        self.with_value(self.value.syntax())
 +    }
 +}
 +
 +/// In Rust, macros expand token trees to token trees. When we want to turn a
 +/// token tree into an AST node, we need to figure out what kind of AST node we
 +/// want: something like `foo` can be a type, an expression, or a pattern.
 +///
 +/// Naively, one would think that "what this expands to" is a property of a
 +/// particular macro: macro `m1` returns an item, while macro `m2` returns an
 +/// expression, etc. That's not the case -- macros are polymorphic in the
 +/// result, and can expand to any type of the AST node.
 +///
 +/// What defines the actual AST node is the syntactic context of the macro
 +/// invocation. As a contrived example, in `let T![*] = T![*];` the first `T`
 +/// expands to a pattern, while the second one expands to an expression.
 +///
 +/// `ExpandTo` captures this bit of information about a particular macro call
 +/// site.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum ExpandTo {
 +    Statements,
 +    Items,
 +    Pattern,
 +    Type,
 +    Expr,
 +}
 +
 +impl ExpandTo {
 +    pub fn from_call_site(call: &ast::MacroCall) -> ExpandTo {
 +        use syntax::SyntaxKind::*;
 +
 +        let syn = call.syntax();
 +
 +        let parent = match syn.parent() {
 +            Some(it) => it,
 +            None => return ExpandTo::Statements,
 +        };
 +
 +        // FIXME: macros in statement position are treated as expression statements, they should
 +        // probably be their own statement kind. The *grand*parent indicates what's valid.
 +        if parent.kind() == MACRO_EXPR
 +            && parent
 +                .parent()
++                .map_or(false, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS))
 +        {
 +            return ExpandTo::Statements;
 +        }
 +
 +        match parent.kind() {
 +            MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => ExpandTo::Items,
 +            MACRO_STMTS | EXPR_STMT | STMT_LIST => ExpandTo::Statements,
 +            MACRO_PAT => ExpandTo::Pattern,
 +            MACRO_TYPE => ExpandTo::Type,
 +
 +            ARG_LIST | ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BREAK_EXPR | CALL_EXPR | CAST_EXPR
 +            | CLOSURE_EXPR | FIELD_EXPR | FOR_EXPR | IF_EXPR | INDEX_EXPR | LET_EXPR
 +            | MATCH_ARM | MATCH_EXPR | MATCH_GUARD | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR
 +            | PREFIX_EXPR | RANGE_EXPR | RECORD_EXPR_FIELD | REF_EXPR | RETURN_EXPR | TRY_EXPR
 +            | TUPLE_EXPR | WHILE_EXPR | MACRO_EXPR => ExpandTo::Expr,
 +            _ => {
 +                // Unknown , Just guess it is `Items`
 +                ExpandTo::Items
 +            }
 +        }
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub struct UnresolvedMacro {
 +    pub path: ModPath,
 +}
index 2b859f775095beb0e005fb1657e59d001e933408,0000000000000000000000000000000000000000..4ce21a57967c72048f59b5db4517c544d075b528
mode 100644,000000..100644
--- /dev/null
@@@ -1,445 -1,0 +1,446 @@@
 +//! See [`Name`].
 +
 +use std::fmt;
 +
 +use syntax::{ast, SmolStr, SyntaxKind};
 +
 +/// `Name` is a wrapper around string, which is used in hir for both references
 +/// and declarations. In theory, names should also carry hygiene info, but we are
 +/// not there yet!
 +///
 +/// Note that `Name` holds and prints escaped name i.e. prefixed with "r#" when it
 +/// is a raw identifier. Use [`unescaped()`][Name::unescaped] when you need the
 +/// name without "r#".
 +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub struct Name(Repr);
 +
 +/// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
 +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +pub struct UnescapedName<'a>(&'a Name);
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
 +enum Repr {
 +    Text(SmolStr),
 +    TupleField(usize),
 +}
 +
 +impl fmt::Display for Name {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match &self.0 {
 +            Repr::Text(text) => fmt::Display::fmt(&text, f),
 +            Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
 +        }
 +    }
 +}
 +
 +fn is_raw_identifier(name: &str) -> bool {
 +    let is_keyword = SyntaxKind::from_keyword(name).is_some();
 +    is_keyword && !matches!(name, "self" | "crate" | "super" | "Self")
 +}
 +
 +impl<'a> fmt::Display for UnescapedName<'a> {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match &self.0 .0 {
 +            Repr::Text(text) => {
 +                let text = text.strip_prefix("r#").unwrap_or(text);
 +                fmt::Display::fmt(&text, f)
 +            }
 +            Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
 +        }
 +    }
 +}
 +
 +impl<'a> UnescapedName<'a> {
 +    /// Returns the textual representation of this name as a [`SmolStr`]. Prefer using this over
 +    /// [`ToString::to_string`] if possible as this conversion is cheaper in the general case.
 +    pub fn to_smol_str(&self) -> SmolStr {
 +        match &self.0 .0 {
 +            Repr::Text(it) => {
 +                if let Some(stripped) = it.strip_prefix("r#") {
 +                    SmolStr::new(stripped)
 +                } else {
 +                    it.clone()
 +                }
 +            }
 +            Repr::TupleField(it) => SmolStr::new(&it.to_string()),
 +        }
 +    }
 +}
 +
 +impl Name {
 +    /// Note: this is private to make creating name from random string hard.
 +    /// Hopefully, this should allow us to integrate hygiene cleaner in the
 +    /// future, and to switch to interned representation of names.
 +    const fn new_text(text: SmolStr) -> Name {
 +        Name(Repr::Text(text))
 +    }
 +
 +    pub fn new_tuple_field(idx: usize) -> Name {
 +        Name(Repr::TupleField(idx))
 +    }
 +
 +    pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
 +        Self::new_text(lt.text().into())
 +    }
 +
 +    /// Shortcut to create inline plain text name
 +    const fn new_inline(text: &str) -> Name {
 +        Name::new_text(SmolStr::new_inline(text))
 +    }
 +
 +    /// Resolve a name from the text of token.
 +    fn resolve(raw_text: &str) -> Name {
 +        match raw_text.strip_prefix("r#") {
 +            // When `raw_text` starts with "r#" but the name does not coincide with any
 +            // keyword, we never need the prefix so we strip it.
 +            Some(text) if !is_raw_identifier(text) => Name::new_text(SmolStr::new(text)),
 +            // Keywords (in the current edition) *can* be used as a name in earlier editions of
 +            // Rust, e.g. "try" in Rust 2015. Even in such cases, we keep track of them in their
 +            // escaped form.
 +            None if is_raw_identifier(raw_text) => {
 +                Name::new_text(SmolStr::from_iter(["r#", raw_text]))
 +            }
 +            _ => Name::new_text(raw_text.into()),
 +        }
 +    }
 +
 +    /// A fake name for things missing in the source code.
 +    ///
 +    /// For example, `impl Foo for {}` should be treated as a trait impl for a
 +    /// type with a missing name. Similarly, `struct S { : u32 }` should have a
 +    /// single field with a missing name.
 +    ///
 +    /// Ideally, we want a `gensym` semantics for missing names -- each missing
 +    /// name is equal only to itself. It's not clear how to implement this in
 +    /// salsa though, so we punt on that bit for a moment.
 +    pub const fn missing() -> Name {
 +        Name::new_inline("[missing name]")
 +    }
 +
 +    /// Returns the tuple index this name represents if it is a tuple field.
 +    pub fn as_tuple_index(&self) -> Option<usize> {
 +        match self.0 {
 +            Repr::TupleField(idx) => Some(idx),
 +            _ => None,
 +        }
 +    }
 +
 +    /// Returns the text this name represents if it isn't a tuple field.
 +    pub fn as_text(&self) -> Option<SmolStr> {
 +        match &self.0 {
 +            Repr::Text(it) => Some(it.clone()),
 +            _ => None,
 +        }
 +    }
 +
 +    /// Returns the textual representation of this name as a [`SmolStr`].
 +    /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in
 +    /// the general case.
 +    pub fn to_smol_str(&self) -> SmolStr {
 +        match &self.0 {
 +            Repr::Text(it) => it.clone(),
 +            Repr::TupleField(it) => SmolStr::new(&it.to_string()),
 +        }
 +    }
 +
 +    pub fn unescaped(&self) -> UnescapedName<'_> {
 +        UnescapedName(self)
 +    }
 +
 +    pub fn is_escaped(&self) -> bool {
 +        match &self.0 {
 +            Repr::Text(it) => it.starts_with("r#"),
 +            Repr::TupleField(_) => false,
 +        }
 +    }
 +}
 +
 +pub trait AsName {
 +    fn as_name(&self) -> Name;
 +}
 +
 +impl AsName for ast::NameRef {
 +    fn as_name(&self) -> Name {
 +        match self.as_tuple_field() {
 +            Some(idx) => Name::new_tuple_field(idx),
 +            None => Name::resolve(&self.text()),
 +        }
 +    }
 +}
 +
 +impl AsName for ast::Name {
 +    fn as_name(&self) -> Name {
 +        Name::resolve(&self.text())
 +    }
 +}
 +
 +impl AsName for ast::NameOrNameRef {
 +    fn as_name(&self) -> Name {
 +        match self {
 +            ast::NameOrNameRef::Name(it) => it.as_name(),
 +            ast::NameOrNameRef::NameRef(it) => it.as_name(),
 +        }
 +    }
 +}
 +
 +impl AsName for tt::Ident {
 +    fn as_name(&self) -> Name {
 +        Name::resolve(&self.text)
 +    }
 +}
 +
 +impl AsName for ast::FieldKind {
 +    fn as_name(&self) -> Name {
 +        match self {
 +            ast::FieldKind::Name(nr) => nr.as_name(),
 +            ast::FieldKind::Index(idx) => {
 +                let idx = idx.text().parse::<usize>().unwrap_or(0);
 +                Name::new_tuple_field(idx)
 +            }
 +        }
 +    }
 +}
 +
 +impl AsName for base_db::Dependency {
 +    fn as_name(&self) -> Name {
 +        Name::new_text(SmolStr::new(&*self.name))
 +    }
 +}
 +
 +pub mod known {
 +    macro_rules! known_names {
 +        ($($ident:ident),* $(,)?) => {
 +            $(
 +                #[allow(bad_style)]
 +                pub const $ident: super::Name =
 +                    super::Name::new_inline(stringify!($ident));
 +            )*
 +        };
 +    }
 +
 +    known_names!(
 +        // Primitives
 +        isize,
 +        i8,
 +        i16,
 +        i32,
 +        i64,
 +        i128,
 +        usize,
 +        u8,
 +        u16,
 +        u32,
 +        u64,
 +        u128,
 +        f32,
 +        f64,
 +        bool,
 +        char,
 +        str,
 +        // Special names
 +        macro_rules,
 +        doc,
 +        cfg,
 +        cfg_attr,
 +        register_attr,
 +        register_tool,
 +        // Components of known path (value or mod name)
 +        std,
 +        core,
 +        alloc,
 +        iter,
 +        ops,
 +        future,
 +        result,
 +        boxed,
 +        option,
 +        prelude,
 +        rust_2015,
 +        rust_2018,
 +        rust_2021,
 +        v1,
 +        // Components of known path (type name)
 +        Iterator,
 +        IntoIterator,
 +        Item,
 +        Try,
 +        Ok,
 +        Future,
 +        IntoFuture,
 +        Result,
 +        Option,
 +        Output,
 +        Target,
 +        Box,
 +        RangeFrom,
 +        RangeFull,
 +        RangeInclusive,
 +        RangeToInclusive,
 +        RangeTo,
 +        Range,
 +        Neg,
 +        Not,
 +        None,
 +        Index,
 +        // Components of known path (function name)
 +        filter_map,
 +        next,
 +        iter_mut,
 +        len,
 +        is_empty,
 +        new,
 +        // Builtin macros
 +        asm,
 +        assert,
 +        column,
 +        compile_error,
 +        concat_idents,
 +        concat_bytes,
 +        concat,
 +        const_format_args,
 +        core_panic,
 +        env,
 +        file,
 +        format_args_nl,
 +        format_args,
 +        global_asm,
 +        include_bytes,
 +        include_str,
 +        include,
 +        line,
 +        llvm_asm,
 +        log_syntax,
 +        module_path,
 +        option_env,
 +        std_panic,
 +        stringify,
 +        trace_macros,
 +        unreachable,
 +        // Builtin derives
 +        Copy,
 +        Clone,
 +        Default,
 +        Debug,
 +        Hash,
 +        Ord,
 +        PartialOrd,
 +        Eq,
 +        PartialEq,
 +        // Builtin attributes
 +        bench,
 +        cfg_accessible,
 +        cfg_eval,
 +        crate_type,
 +        derive,
 +        global_allocator,
 +        test,
 +        test_case,
 +        recursion_limit,
++        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 b6f226dbfd20d238ff19338a20d07eab5a3b7008,0000000000000000000000000000000000000000..344036dd8139d28d433c745b6121ab8c85e9865f
mode 100644,000000..100644
--- /dev/null
@@@ -1,145 -1,0 +1,144 @@@
-         TyKind::Ref(.., ty) => Some(ty),
-         TyKind::Raw(.., ty) => Some(ty),
 +//! In certain situations, rust automatically inserts derefs as necessary: for
 +//! example, field accesses `foo.bar` still work when `foo` is actually a
 +//! reference to a type with the field `bar`. This is an approximation of the
 +//! logic in rustc (which lives in librustc_typeck/check/autoderef.rs).
 +
 +use std::sync::Arc;
 +
 +use chalk_ir::cast::Cast;
 +use hir_expand::name::name;
 +use limit::Limit;
 +use syntax::SmolStr;
 +
 +use crate::{
 +    db::HirDatabase, infer::unify::InferenceTable, Canonical, Goal, Interner, ProjectionTyExt,
 +    TraitEnvironment, Ty, TyBuilder, TyKind,
 +};
 +
 +static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10);
 +
 +pub(crate) enum AutoderefKind {
 +    Builtin,
 +    Overloaded,
 +}
 +
 +pub(crate) struct Autoderef<'a, 'db> {
 +    pub(crate) table: &'a mut InferenceTable<'db>,
 +    ty: Ty,
 +    at_start: bool,
 +    steps: Vec<(AutoderefKind, Ty)>,
 +}
 +
 +impl<'a, 'db> Autoderef<'a, 'db> {
 +    pub(crate) fn new(table: &'a mut InferenceTable<'db>, ty: Ty) -> Self {
 +        let ty = table.resolve_ty_shallow(&ty);
 +        Autoderef { table, ty, at_start: true, steps: Vec::new() }
 +    }
 +
 +    pub(crate) fn step_count(&self) -> usize {
 +        self.steps.len()
 +    }
 +
 +    pub(crate) fn steps(&self) -> &[(AutoderefKind, Ty)] {
 +        &self.steps
 +    }
 +
 +    pub(crate) fn final_ty(&self) -> Ty {
 +        self.ty.clone()
 +    }
 +}
 +
 +impl Iterator for Autoderef<'_, '_> {
 +    type Item = (Ty, usize);
 +
 +    fn next(&mut self) -> Option<Self::Item> {
 +        if self.at_start {
 +            self.at_start = false;
 +            return Some((self.ty.clone(), 0));
 +        }
 +
 +        if AUTODEREF_RECURSION_LIMIT.check(self.steps.len() + 1).is_err() {
 +            return None;
 +        }
 +
 +        let (kind, new_ty) = autoderef_step(self.table, self.ty.clone())?;
 +
 +        self.steps.push((kind, self.ty.clone()));
 +        self.ty = new_ty;
 +
 +        Some((self.ty.clone(), self.step_count()))
 +    }
 +}
 +
 +pub(crate) fn autoderef_step(
 +    table: &mut InferenceTable<'_>,
 +    ty: Ty,
 +) -> Option<(AutoderefKind, Ty)> {
 +    if let Some(derefed) = builtin_deref(&ty) {
 +        Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed)))
 +    } else {
 +        Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?))
 +    }
 +}
 +
 +// FIXME: replace uses of this with Autoderef above
 +pub fn autoderef<'a>(
 +    db: &'a dyn HirDatabase,
 +    env: Arc<TraitEnvironment>,
 +    ty: Canonical<Ty>,
 +) -> impl Iterator<Item = Canonical<Ty>> + 'a {
 +    let mut table = InferenceTable::new(db, env);
 +    let ty = table.instantiate_canonical(ty);
 +    let mut autoderef = Autoderef::new(&mut table, ty);
 +    let mut v = Vec::new();
 +    while let Some((ty, _steps)) = autoderef.next() {
 +        v.push(autoderef.table.canonicalize(ty).value);
 +    }
 +    v.into_iter()
 +}
 +
 +pub(crate) fn deref(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
 +    let _p = profile::span("deref");
 +    autoderef_step(table, ty).map(|(_, ty)| ty)
 +}
 +
 +fn builtin_deref(ty: &Ty) -> Option<&Ty> {
 +    match ty.kind(Interner) {
++        TyKind::Ref(.., ty) | TyKind::Raw(.., ty) => Some(ty),
 +        _ => None,
 +    }
 +}
 +
 +fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
 +    let _p = profile::span("deref_by_trait");
 +    if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() {
 +        // don't try to deref unknown variables
 +        return None;
 +    }
 +
 +    let db = table.db;
 +    let deref_trait = db
 +        .lang_item(table.trait_env.krate, SmolStr::new_inline("deref"))
 +        .and_then(|l| l.as_trait())?;
 +    let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
 +
 +    let projection = {
 +        let b = TyBuilder::assoc_type_projection(db, target);
 +        if b.remaining() != 1 {
 +            // the Target type + Deref trait should only have one generic parameter,
 +            // namely Deref's Self type
 +            return None;
 +        }
 +        b.push(ty).build()
 +    };
 +
 +    // Check that the type implements Deref at all
 +    let trait_ref = projection.trait_ref(db);
 +    let implements_goal: Goal = trait_ref.cast(Interner);
 +    table.try_obligation(implements_goal.clone())?;
 +
 +    table.register_obligation(implements_goal);
 +
 +    let result = table.normalize_projection_ty(projection);
 +    Some(table.resolve_ty_shallow(&result))
 +}
index 642e03edd230636ca3911a0e0eee44dc8989a41e,0000000000000000000000000000000000000000..c8df4c796efca045f974d21e3b21a8a67e23bf28
mode 100644,000000..100644
--- /dev/null
@@@ -1,416 -1,0 +1,411 @@@
-         let cx = MatchCheckCtx {
-             module: self.owner.module(db.upcast()),
-             body: self.owner,
-             db,
-             pattern_arena: &pattern_arena,
-         };
 +//! Various diagnostics for expressions that are collected together in one pass
 +//! through the body using inference results: mismatched arg counts, missing
 +//! fields, etc.
 +
 +use std::fmt;
 +use std::sync::Arc;
 +
 +use hir_def::{path::path, resolver::HasResolver, AdtId, AssocItemId, DefWithBodyId, HasModule};
 +use hir_expand::name;
 +use itertools::Either;
 +use itertools::Itertools;
 +use rustc_hash::FxHashSet;
 +use typed_arena::Arena;
 +
 +use crate::{
 +    db::HirDatabase,
 +    diagnostics::match_check::{
 +        self,
 +        deconstruct_pat::DeconstructedPat,
 +        usefulness::{compute_match_usefulness, MatchCheckCtx},
 +    },
 +    display::HirDisplay,
 +    InferenceResult, Ty, TyExt,
 +};
 +
 +pub(crate) use hir_def::{
 +    body::Body,
 +    expr::{Expr, ExprId, MatchArm, Pat, PatId},
 +    LocalFieldId, VariantId,
 +};
 +
 +pub enum BodyValidationDiagnostic {
 +    RecordMissingFields {
 +        record: Either<ExprId, PatId>,
 +        variant: VariantId,
 +        missed_fields: Vec<LocalFieldId>,
 +    },
 +    ReplaceFilterMapNextWithFindMap {
 +        method_call_expr: ExprId,
 +    },
 +    MissingMatchArms {
 +        match_expr: ExprId,
 +        uncovered_patterns: String,
 +    },
 +}
 +
 +impl BodyValidationDiagnostic {
 +    pub fn collect(db: &dyn HirDatabase, owner: DefWithBodyId) -> Vec<BodyValidationDiagnostic> {
 +        let _p = profile::span("BodyValidationDiagnostic::collect");
 +        let infer = db.infer(owner);
 +        let mut validator = ExprValidator::new(owner, infer);
 +        validator.validate_body(db);
 +        validator.diagnostics
 +    }
 +}
 +
 +struct ExprValidator {
 +    owner: DefWithBodyId,
 +    infer: Arc<InferenceResult>,
 +    pub(super) diagnostics: Vec<BodyValidationDiagnostic>,
 +}
 +
 +impl ExprValidator {
 +    fn new(owner: DefWithBodyId, infer: Arc<InferenceResult>) -> ExprValidator {
 +        ExprValidator { owner, infer, diagnostics: Vec::new() }
 +    }
 +
 +    fn validate_body(&mut self, db: &dyn HirDatabase) {
 +        let body = db.body(self.owner);
 +        let mut filter_map_next_checker = None;
 +
 +        for (id, expr) in body.exprs.iter() {
 +            if let Some((variant, missed_fields, true)) =
 +                record_literal_missing_fields(db, &self.infer, id, expr)
 +            {
 +                self.diagnostics.push(BodyValidationDiagnostic::RecordMissingFields {
 +                    record: Either::Left(id),
 +                    variant,
 +                    missed_fields,
 +                });
 +            }
 +
 +            match expr {
 +                Expr::Match { expr, arms } => {
 +                    self.validate_match(id, *expr, arms, db, self.infer.clone());
 +                }
 +                Expr::Call { .. } | Expr::MethodCall { .. } => {
 +                    self.validate_call(db, id, expr, &mut filter_map_next_checker);
 +                }
 +                _ => {}
 +            }
 +        }
 +        for (id, pat) in body.pats.iter() {
 +            if let Some((variant, missed_fields, true)) =
 +                record_pattern_missing_fields(db, &self.infer, id, pat)
 +            {
 +                self.diagnostics.push(BodyValidationDiagnostic::RecordMissingFields {
 +                    record: Either::Right(id),
 +                    variant,
 +                    missed_fields,
 +                });
 +            }
 +        }
 +    }
 +
 +    fn validate_call(
 +        &mut self,
 +        db: &dyn HirDatabase,
 +        call_id: ExprId,
 +        expr: &Expr,
 +        filter_map_next_checker: &mut Option<FilterMapNextChecker>,
 +    ) {
 +        // Check that the number of arguments matches the number of parameters.
 +
 +        // FIXME: Due to shortcomings in the current type system implementation, only emit this
 +        // diagnostic if there are no type mismatches in the containing function.
 +        if self.infer.expr_type_mismatches().next().is_some() {
 +            return;
 +        }
 +
 +        match expr {
 +            Expr::MethodCall { receiver, .. } => {
 +                let (callee, _) = match self.infer.method_resolution(call_id) {
 +                    Some(it) => it,
 +                    None => return,
 +                };
 +
 +                if filter_map_next_checker
 +                    .get_or_insert_with(|| {
 +                        FilterMapNextChecker::new(&self.owner.resolver(db.upcast()), db)
 +                    })
 +                    .check(call_id, receiver, &callee)
 +                    .is_some()
 +                {
 +                    self.diagnostics.push(
 +                        BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap {
 +                            method_call_expr: call_id,
 +                        },
 +                    );
 +                }
 +            }
 +            _ => return,
 +        };
 +    }
 +
 +    fn validate_match(
 +        &mut self,
 +        id: ExprId,
 +        match_expr: ExprId,
 +        arms: &[MatchArm],
 +        db: &dyn HirDatabase,
 +        infer: Arc<InferenceResult>,
 +    ) {
 +        let body = db.body(self.owner);
 +
 +        let match_expr_ty = &infer[match_expr];
 +        if match_expr_ty.is_unknown() {
 +            return;
 +        }
 +
 +        let pattern_arena = Arena::new();
++        let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db, &pattern_arena);
 +
 +        let mut m_arms = Vec::with_capacity(arms.len());
 +        let mut has_lowering_errors = false;
 +        for arm in arms {
 +            if let Some(pat_ty) = infer.type_of_pat.get(arm.pat) {
 +                // We only include patterns whose type matches the type
 +                // of the match expression. If we had an InvalidMatchArmPattern
 +                // diagnostic or similar we could raise that in an else
 +                // block here.
 +                //
 +                // When comparing the types, we also have to consider that rustc
 +                // will automatically de-reference the match expression type if
 +                // necessary.
 +                //
 +                // FIXME we should use the type checker for this.
 +                if (pat_ty == match_expr_ty
 +                    || match_expr_ty
 +                        .as_reference()
 +                        .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
 +                        .unwrap_or(false))
 +                    && types_of_subpatterns_do_match(arm.pat, &body, &infer)
 +                {
 +                    // If we had a NotUsefulMatchArm diagnostic, we could
 +                    // check the usefulness of each pattern as we added it
 +                    // to the matrix here.
 +                    let m_arm = match_check::MatchArm {
 +                        pat: self.lower_pattern(&cx, arm.pat, db, &body, &mut has_lowering_errors),
 +                        has_guard: arm.guard.is_some(),
 +                    };
 +                    m_arms.push(m_arm);
 +                    if !has_lowering_errors {
 +                        continue;
 +                    }
 +                }
 +            }
 +
 +            // If we can't resolve the type of a pattern, or the pattern type doesn't
 +            // fit the match expression, we skip this diagnostic. Skipping the entire
 +            // diagnostic rather than just not including this match arm is preferred
 +            // to avoid the chance of false positives.
 +            cov_mark::hit!(validate_match_bailed_out);
 +            return;
 +        }
 +
 +        let report = compute_match_usefulness(&cx, &m_arms, match_expr_ty);
 +
 +        // FIXME Report unreacheble arms
 +        // https://github.com/rust-lang/rust/blob/f31622a50/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200
 +
 +        let witnesses = report.non_exhaustiveness_witnesses;
 +        if !witnesses.is_empty() {
 +            self.diagnostics.push(BodyValidationDiagnostic::MissingMatchArms {
 +                match_expr: id,
 +                uncovered_patterns: missing_match_arms(&cx, match_expr_ty, witnesses, arms),
 +            });
 +        }
 +    }
 +
 +    fn lower_pattern<'p>(
 +        &self,
 +        cx: &MatchCheckCtx<'_, 'p>,
 +        pat: PatId,
 +        db: &dyn HirDatabase,
 +        body: &Body,
 +        have_errors: &mut bool,
 +    ) -> &'p DeconstructedPat<'p> {
 +        let mut patcx = match_check::PatCtxt::new(db, &self.infer, body);
 +        let pattern = patcx.lower_pattern(pat);
 +        let pattern = cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern));
 +        if !patcx.errors.is_empty() {
 +            *have_errors = true;
 +        }
 +        pattern
 +    }
 +}
 +
 +struct FilterMapNextChecker {
 +    filter_map_function_id: Option<hir_def::FunctionId>,
 +    next_function_id: Option<hir_def::FunctionId>,
 +    prev_filter_map_expr_id: Option<ExprId>,
 +}
 +
 +impl FilterMapNextChecker {
 +    fn new(resolver: &hir_def::resolver::Resolver, db: &dyn HirDatabase) -> Self {
 +        // Find and store the FunctionIds for Iterator::filter_map and Iterator::next
 +        let iterator_path = path![core::iter::Iterator];
 +        let mut filter_map_function_id = None;
 +        let mut next_function_id = None;
 +
 +        if let Some(iterator_trait_id) = resolver.resolve_known_trait(db.upcast(), &iterator_path) {
 +            let iterator_trait_items = &db.trait_data(iterator_trait_id).items;
 +            for item in iterator_trait_items.iter() {
 +                if let (name, AssocItemId::FunctionId(id)) = item {
 +                    if *name == name![filter_map] {
 +                        filter_map_function_id = Some(*id);
 +                    }
 +                    if *name == name![next] {
 +                        next_function_id = Some(*id);
 +                    }
 +                }
 +                if filter_map_function_id.is_some() && next_function_id.is_some() {
 +                    break;
 +                }
 +            }
 +        }
 +        Self { filter_map_function_id, next_function_id, prev_filter_map_expr_id: None }
 +    }
 +
 +    // check for instances of .filter_map(..).next()
 +    fn check(
 +        &mut self,
 +        current_expr_id: ExprId,
 +        receiver_expr_id: &ExprId,
 +        function_id: &hir_def::FunctionId,
 +    ) -> Option<()> {
 +        if *function_id == self.filter_map_function_id? {
 +            self.prev_filter_map_expr_id = Some(current_expr_id);
 +            return None;
 +        }
 +
 +        if *function_id == self.next_function_id? {
 +            if let Some(prev_filter_map_expr_id) = self.prev_filter_map_expr_id {
 +                if *receiver_expr_id == prev_filter_map_expr_id {
 +                    return Some(());
 +                }
 +            }
 +        }
 +
 +        self.prev_filter_map_expr_id = None;
 +        None
 +    }
 +}
 +
 +pub fn record_literal_missing_fields(
 +    db: &dyn HirDatabase,
 +    infer: &InferenceResult,
 +    id: ExprId,
 +    expr: &Expr,
 +) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> {
 +    let (fields, exhaustive) = match expr {
 +        Expr::RecordLit { fields, spread, ellipsis, is_assignee_expr, .. } => {
 +            let exhaustive = if *is_assignee_expr { !*ellipsis } else { spread.is_none() };
 +            (fields, exhaustive)
 +        }
 +        _ => return None,
 +    };
 +
 +    let variant_def = infer.variant_resolution_for_expr(id)?;
 +    if let VariantId::UnionId(_) = variant_def {
 +        return None;
 +    }
 +
 +    let variant_data = variant_def.variant_data(db.upcast());
 +
 +    let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
 +    let missed_fields: Vec<LocalFieldId> = variant_data
 +        .fields()
 +        .iter()
 +        .filter_map(|(f, d)| if specified_fields.contains(&d.name) { None } else { Some(f) })
 +        .collect();
 +    if missed_fields.is_empty() {
 +        return None;
 +    }
 +    Some((variant_def, missed_fields, exhaustive))
 +}
 +
 +pub fn record_pattern_missing_fields(
 +    db: &dyn HirDatabase,
 +    infer: &InferenceResult,
 +    id: PatId,
 +    pat: &Pat,
 +) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> {
 +    let (fields, exhaustive) = match pat {
 +        Pat::Record { path: _, args, ellipsis } => (args, !ellipsis),
 +        _ => return None,
 +    };
 +
 +    let variant_def = infer.variant_resolution_for_pat(id)?;
 +    if let VariantId::UnionId(_) = variant_def {
 +        return None;
 +    }
 +
 +    let variant_data = variant_def.variant_data(db.upcast());
 +
 +    let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
 +    let missed_fields: Vec<LocalFieldId> = variant_data
 +        .fields()
 +        .iter()
 +        .filter_map(|(f, d)| if specified_fields.contains(&d.name) { None } else { Some(f) })
 +        .collect();
 +    if missed_fields.is_empty() {
 +        return None;
 +    }
 +    Some((variant_def, missed_fields, exhaustive))
 +}
 +
 +fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResult) -> bool {
 +    fn walk(pat: PatId, body: &Body, infer: &InferenceResult, has_type_mismatches: &mut bool) {
 +        match infer.type_mismatch_for_pat(pat) {
 +            Some(_) => *has_type_mismatches = true,
 +            None => {
 +                body[pat].walk_child_pats(|subpat| walk(subpat, body, infer, has_type_mismatches))
 +            }
 +        }
 +    }
 +
 +    let mut has_type_mismatches = false;
 +    walk(pat, body, infer, &mut has_type_mismatches);
 +    !has_type_mismatches
 +}
 +
 +fn missing_match_arms<'p>(
 +    cx: &MatchCheckCtx<'_, 'p>,
 +    scrut_ty: &Ty,
 +    witnesses: Vec<DeconstructedPat<'p>>,
 +    arms: &[MatchArm],
 +) -> String {
 +    struct DisplayWitness<'a, 'p>(&'a DeconstructedPat<'p>, &'a MatchCheckCtx<'a, 'p>);
 +    impl<'a, 'p> fmt::Display for DisplayWitness<'a, 'p> {
 +        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +            let DisplayWitness(witness, cx) = *self;
 +            let pat = witness.to_pat(cx);
 +            write!(f, "{}", pat.display(cx.db))
 +        }
 +    }
 +
 +    let non_empty_enum = match scrut_ty.as_adt() {
 +        Some((AdtId::EnumId(e), _)) => !cx.db.enum_data(e).variants.is_empty(),
 +        _ => false,
 +    };
 +    if arms.is_empty() && !non_empty_enum {
 +        format!("type `{}` is non-empty", scrut_ty.display(cx.db))
 +    } else {
 +        let pat_display = |witness| DisplayWitness(witness, cx);
 +        const LIMIT: usize = 3;
 +        match &*witnesses {
 +            [witness] => format!("`{}` not covered", pat_display(witness)),
 +            [head @ .., tail] if head.len() < LIMIT => {
 +                let head = head.iter().map(pat_display);
 +                format!("`{}` and `{}` not covered", head.format("`, `"), pat_display(tail))
 +            }
 +            _ => {
 +                let (head, tail) = witnesses.split_at(LIMIT);
 +                let head = head.iter().map(pat_display);
 +                format!("`{}` and {} more not covered", head.format("`, `"), tail.len())
 +            }
 +        }
 +    }
 +}
index bbbe539c13fbe2c94b1bb05c5c5ed3e9928398da,0000000000000000000000000000000000000000..47d60fc41e700bc2962665e48ab04f6720b3884d
mode 100644,000000..100644
--- /dev/null
@@@ -1,1094 -1,0 +1,1098 @@@
- use crate::{infer::normalize, AdtId, Interner, Scalar, Ty, TyExt, TyKind};
 +//! [`super::usefulness`] explains most of what is happening in this file. As explained there,
 +//! values and patterns are made from constructors applied to fields. This file defines a
 +//! `Constructor` enum, a `Fields` struct, and various operations to manipulate them and convert
 +//! them from/to patterns.
 +//!
 +//! There's one idea that is not detailed in [`super::usefulness`] because the details are not
 +//! needed there: _constructor splitting_.
 +//!
 +//! # Constructor splitting
 +//!
 +//! The idea is as follows: given a constructor `c` and a matrix, we want to specialize in turn
 +//! with all the value constructors that are covered by `c`, and compute usefulness for each.
 +//! Instead of listing all those constructors (which is intractable), we group those value
 +//! constructors together as much as possible. Example:
 +//!
 +//! ```
 +//! match (0, false) {
 +//!     (0 ..=100, true) => {} // `p_1`
 +//!     (50..=150, false) => {} // `p_2`
 +//!     (0 ..=200, _) => {} // `q`
 +//! }
 +//! ```
 +//!
 +//! The naive approach would try all numbers in the range `0..=200`. But we can be a lot more
 +//! clever: `0` and `1` for example will match the exact same rows, and return equivalent
 +//! witnesses. In fact all of `0..50` would. We can thus restrict our exploration to 4
 +//! constructors: `0..50`, `50..=100`, `101..=150` and `151..=200`. That is enough and infinitely
 +//! more tractable.
 +//!
 +//! We capture this idea in a function `split(p_1 ... p_n, c)` which returns a list of constructors
 +//! `c'` covered by `c`. Given such a `c'`, we require that all value ctors `c''` covered by `c'`
 +//! return an equivalent set of witnesses after specializing and computing usefulness.
 +//! In the example above, witnesses for specializing by `c''` covered by `0..50` will only differ
 +//! in their first element.
 +//!
 +//! We usually also ask that the `c'` together cover all of the original `c`. However we allow
 +//! skipping some constructors as long as it doesn't change whether the resulting list of witnesses
 +//! is empty of not. We use this in the wildcard `_` case.
 +//!
 +//! Splitting is implemented in the [`Constructor::split`] function. We don't do splitting for
 +//! or-patterns; instead we just try the alternatives one-by-one. For details on splitting
 +//! wildcards, see [`SplitWildcard`]; for integer ranges, see [`SplitIntRange`].
 +
 +use std::{
 +    cell::Cell,
 +    cmp::{max, min},
 +    iter::once,
 +    ops::RangeInclusive,
 +};
 +
 +use hir_def::{EnumVariantId, HasModule, LocalFieldId, VariantId};
 +use smallvec::{smallvec, SmallVec};
 +use stdx::never;
 +
-             &TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ..) => {
-                 let enum_data = cx.db.enum_data(enum_id);
++use crate::{
++    infer::normalize, inhabitedness::is_enum_variant_uninhabited_from, AdtId, Interner, Scalar, Ty,
++    TyExt, TyKind,
++};
 +
 +use super::{
 +    is_box,
 +    usefulness::{helper::Captures, MatchCheckCtx, PatCtxt},
 +    FieldPat, Pat, PatKind,
 +};
 +
 +use self::Constructor::*;
 +
 +/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
 +fn expand_or_pat(pat: &Pat) -> Vec<&Pat> {
 +    fn expand<'p>(pat: &'p Pat, vec: &mut Vec<&'p Pat>) {
 +        if let PatKind::Or { pats } = pat.kind.as_ref() {
 +            for pat in pats {
 +                expand(pat, vec);
 +            }
 +        } else {
 +            vec.push(pat)
 +        }
 +    }
 +
 +    let mut pats = Vec::new();
 +    expand(pat, &mut pats);
 +    pats
 +}
 +
 +/// [Constructor] uses this in umimplemented variants.
 +/// It allows porting match expressions from upstream algorithm without losing semantics.
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +pub(super) enum Void {}
 +
 +/// An inclusive interval, used for precise integer exhaustiveness checking.
 +/// `IntRange`s always store a contiguous range. This means that values are
 +/// encoded such that `0` encodes the minimum value for the integer,
 +/// regardless of the signedness.
 +/// For example, the pattern `-128..=127i8` is encoded as `0..=255`.
 +/// This makes comparisons and arithmetic on interval endpoints much more
 +/// straightforward. See `signed_bias` for details.
 +///
 +/// `IntRange` is never used to encode an empty range or a "range" that wraps
 +/// around the (offset) space: i.e., `range.lo <= range.hi`.
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub(super) struct IntRange {
 +    range: RangeInclusive<u128>,
 +}
 +
 +impl IntRange {
 +    #[inline]
 +    fn is_integral(ty: &Ty) -> bool {
 +        matches!(
 +            ty.kind(Interner),
 +            TyKind::Scalar(Scalar::Char | Scalar::Int(_) | Scalar::Uint(_) | Scalar::Bool)
 +        )
 +    }
 +
 +    fn is_singleton(&self) -> bool {
 +        self.range.start() == self.range.end()
 +    }
 +
 +    fn boundaries(&self) -> (u128, u128) {
 +        (*self.range.start(), *self.range.end())
 +    }
 +
 +    #[inline]
 +    fn from_bool(value: bool) -> IntRange {
 +        let val = value as u128;
 +        IntRange { range: val..=val }
 +    }
 +
 +    #[inline]
 +    fn from_range(lo: u128, hi: u128, scalar_ty: Scalar) -> IntRange {
 +        match scalar_ty {
 +            Scalar::Bool => IntRange { range: lo..=hi },
 +            _ => unimplemented!(),
 +        }
 +    }
 +
 +    fn is_subrange(&self, other: &Self) -> bool {
 +        other.range.start() <= self.range.start() && self.range.end() <= other.range.end()
 +    }
 +
 +    fn intersection(&self, other: &Self) -> Option<Self> {
 +        let (lo, hi) = self.boundaries();
 +        let (other_lo, other_hi) = other.boundaries();
 +        if lo <= other_hi && other_lo <= hi {
 +            Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi) })
 +        } else {
 +            None
 +        }
 +    }
 +
 +    fn to_pat(&self, _cx: &MatchCheckCtx<'_, '_>, ty: Ty) -> Pat {
 +        match ty.kind(Interner) {
 +            TyKind::Scalar(Scalar::Bool) => {
 +                let kind = match self.boundaries() {
 +                    (0, 0) => PatKind::LiteralBool { value: false },
 +                    (1, 1) => PatKind::LiteralBool { value: true },
 +                    (0, 1) => PatKind::Wild,
 +                    (lo, hi) => {
 +                        never!("bad range for bool pattern: {}..={}", lo, hi);
 +                        PatKind::Wild
 +                    }
 +                };
 +                Pat { ty, kind: kind.into() }
 +            }
 +            _ => unimplemented!(),
 +        }
 +    }
 +
 +    /// See `Constructor::is_covered_by`
 +    fn is_covered_by(&self, other: &Self) -> bool {
 +        if self.intersection(other).is_some() {
 +            // Constructor splitting should ensure that all intersections we encounter are actually
 +            // inclusions.
 +            assert!(self.is_subrange(other));
 +            true
 +        } else {
 +            false
 +        }
 +    }
 +}
 +
 +/// Represents a border between 2 integers. Because the intervals spanning borders must be able to
 +/// cover every integer, we need to be able to represent 2^128 + 1 such borders.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 +enum IntBorder {
 +    JustBefore(u128),
 +    AfterMax,
 +}
 +
 +/// A range of integers that is partitioned into disjoint subranges. This does constructor
 +/// splitting for integer ranges as explained at the top of the file.
 +///
 +/// This is fed multiple ranges, and returns an output that covers the input, but is split so that
 +/// the only intersections between an output range and a seen range are inclusions. No output range
 +/// straddles the boundary of one of the inputs.
 +///
 +/// The following input:
 +/// ```
 +///   |-------------------------| // `self`
 +/// |------|  |----------|   |----|
 +///    |-------| |-------|
 +/// ```
 +/// would be iterated over as follows:
 +/// ```
 +///   ||---|--||-|---|---|---|--|
 +/// ```
 +#[derive(Debug, Clone)]
 +struct SplitIntRange {
 +    /// The range we are splitting
 +    range: IntRange,
 +    /// The borders of ranges we have seen. They are all contained within `range`. This is kept
 +    /// sorted.
 +    borders: Vec<IntBorder>,
 +}
 +
 +impl SplitIntRange {
 +    fn new(range: IntRange) -> Self {
 +        SplitIntRange { range, borders: Vec::new() }
 +    }
 +
 +    /// Internal use
 +    fn to_borders(r: IntRange) -> [IntBorder; 2] {
 +        use IntBorder::*;
 +        let (lo, hi) = r.boundaries();
 +        let lo = JustBefore(lo);
 +        let hi = match hi.checked_add(1) {
 +            Some(m) => JustBefore(m),
 +            None => AfterMax,
 +        };
 +        [lo, hi]
 +    }
 +
 +    /// Add ranges relative to which we split.
 +    fn split(&mut self, ranges: impl Iterator<Item = IntRange>) {
 +        let this_range = &self.range;
 +        let included_ranges = ranges.filter_map(|r| this_range.intersection(&r));
 +        let included_borders = included_ranges.flat_map(|r| {
 +            let borders = Self::to_borders(r);
 +            once(borders[0]).chain(once(borders[1]))
 +        });
 +        self.borders.extend(included_borders);
 +        self.borders.sort_unstable();
 +    }
 +
 +    /// Iterate over the contained ranges.
 +    fn iter(&self) -> impl Iterator<Item = IntRange> + '_ {
 +        use IntBorder::*;
 +
 +        let self_range = Self::to_borders(self.range.clone());
 +        // Start with the start of the range.
 +        let mut prev_border = self_range[0];
 +        self.borders
 +            .iter()
 +            .copied()
 +            // End with the end of the range.
 +            .chain(once(self_range[1]))
 +            // List pairs of adjacent borders.
 +            .map(move |border| {
 +                let ret = (prev_border, border);
 +                prev_border = border;
 +                ret
 +            })
 +            // Skip duplicates.
 +            .filter(|(prev_border, border)| prev_border != border)
 +            // Finally, convert to ranges.
 +            .map(|(prev_border, border)| {
 +                let range = match (prev_border, border) {
 +                    (JustBefore(n), JustBefore(m)) if n < m => n..=(m - 1),
 +                    (JustBefore(n), AfterMax) => n..=u128::MAX,
 +                    _ => unreachable!(), // Ruled out by the sorting and filtering we did
 +                };
 +                IntRange { range }
 +            })
 +    }
 +}
 +
 +/// A constructor for array and slice patterns.
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +pub(super) struct Slice {
 +    _unimplemented: Void,
 +}
 +
 +impl Slice {
 +    fn arity(self) -> usize {
 +        match self._unimplemented {}
 +    }
 +
 +    /// See `Constructor::is_covered_by`
 +    fn is_covered_by(self, _other: Self) -> bool {
 +        match self._unimplemented {}
 +    }
 +}
 +
 +/// A value can be decomposed into a constructor applied to some fields. This struct represents
 +/// the constructor. See also `Fields`.
 +///
 +/// `pat_constructor` retrieves the constructor corresponding to a pattern.
 +/// `specialize_constructor` returns the list of fields corresponding to a pattern, given a
 +/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and
 +/// `Fields`.
 +#[allow(dead_code)]
 +#[derive(Clone, Debug, PartialEq)]
 +pub(super) enum Constructor {
 +    /// The constructor for patterns that have a single constructor, like tuples, struct patterns
 +    /// and fixed-length arrays.
 +    Single,
 +    /// Enum variants.
 +    Variant(EnumVariantId),
 +    /// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
 +    IntRange(IntRange),
 +    /// Ranges of floating-point literal values (`2.0..=5.2`).
 +    FloatRange(Void),
 +    /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
 +    Str(Void),
 +    /// Array and slice patterns.
 +    Slice(Slice),
 +    /// Constants that must not be matched structurally. They are treated as black
 +    /// boxes for the purposes of exhaustiveness: we must not inspect them, and they
 +    /// don't count towards making a match exhaustive.
 +    Opaque,
 +    /// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used
 +    /// for those types for which we cannot list constructors explicitly, like `f64` and `str`.
 +    NonExhaustive,
 +    /// Stands for constructors that are not seen in the matrix, as explained in the documentation
 +    /// for [`SplitWildcard`]. The carried `bool` is used for the `non_exhaustive_omitted_patterns`
 +    /// lint.
 +    Missing { nonexhaustive_enum_missing_real_variants: bool },
 +    /// Wildcard pattern.
 +    Wildcard,
 +    /// Or-pattern.
 +    Or,
 +}
 +
 +impl Constructor {
 +    pub(super) fn is_wildcard(&self) -> bool {
 +        matches!(self, Wildcard)
 +    }
 +
 +    pub(super) fn is_non_exhaustive(&self) -> bool {
 +        matches!(self, NonExhaustive)
 +    }
 +
 +    fn as_int_range(&self) -> Option<&IntRange> {
 +        match self {
 +            IntRange(range) => Some(range),
 +            _ => None,
 +        }
 +    }
 +
 +    fn as_slice(&self) -> Option<Slice> {
 +        match self {
 +            Slice(slice) => Some(*slice),
 +            _ => None,
 +        }
 +    }
 +
 +    pub(super) fn is_unstable_variant(&self, _pcx: PatCtxt<'_, '_>) -> bool {
 +        false //FIXME: implement this
 +    }
 +
 +    pub(super) fn is_doc_hidden_variant(&self, _pcx: PatCtxt<'_, '_>) -> bool {
 +        false //FIXME: implement this
 +    }
 +
 +    fn variant_id_for_adt(&self, adt: hir_def::AdtId) -> VariantId {
 +        match *self {
 +            Variant(id) => id.into(),
 +            Single => {
 +                assert!(!matches!(adt, hir_def::AdtId::EnumId(_)));
 +                match adt {
 +                    hir_def::AdtId::EnumId(_) => unreachable!(),
 +                    hir_def::AdtId::StructId(id) => id.into(),
 +                    hir_def::AdtId::UnionId(id) => id.into(),
 +                }
 +            }
 +            _ => panic!("bad constructor {:?} for adt {:?}", self, adt),
 +        }
 +    }
 +
 +    /// The number of fields for this constructor. This must be kept in sync with
 +    /// `Fields::wildcards`.
 +    pub(super) fn arity(&self, pcx: PatCtxt<'_, '_>) -> usize {
 +        match self {
 +            Single | Variant(_) => match *pcx.ty.kind(Interner) {
 +                TyKind::Tuple(arity, ..) => arity,
 +                TyKind::Ref(..) => 1,
 +                TyKind::Adt(adt, ..) => {
 +                    if is_box(adt.0, pcx.cx.db) {
 +                        // The only legal patterns of type `Box` (outside `std`) are `_` and box
 +                        // patterns. If we're here we can assume this is a box pattern.
 +                        1
 +                    } else {
 +                        let variant = self.variant_id_for_adt(adt.0);
 +                        Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant).count()
 +                    }
 +                }
 +                _ => {
 +                    never!("Unexpected type for `Single` constructor: {:?}", pcx.ty);
 +                    0
 +                }
 +            },
 +            Slice(slice) => slice.arity(),
 +            Str(..)
 +            | FloatRange(..)
 +            | IntRange(..)
 +            | NonExhaustive
 +            | Opaque
 +            | Missing { .. }
 +            | Wildcard => 0,
 +            Or => {
 +                never!("The `Or` constructor doesn't have a fixed arity");
 +                0
 +            }
 +        }
 +    }
 +
 +    /// Some constructors (namely `Wildcard`, `IntRange` and `Slice`) actually stand for a set of actual
 +    /// constructors (like variants, integers or fixed-sized slices). When specializing for these
 +    /// constructors, we want to be specialising for the actual underlying constructors.
 +    /// Naively, we would simply return the list of constructors they correspond to. We instead are
 +    /// more clever: if there are constructors that we know will behave the same wrt the current
 +    /// matrix, we keep them grouped. For example, all slices of a sufficiently large length
 +    /// will either be all useful or all non-useful with a given matrix.
 +    ///
 +    /// See the branches for details on how the splitting is done.
 +    ///
 +    /// This function may discard some irrelevant constructors if this preserves behavior and
 +    /// diagnostics. Eg. for the `_` case, we ignore the constructors already present in the
 +    /// matrix, unless all of them are.
 +    pub(super) fn split<'a>(
 +        &self,
 +        pcx: PatCtxt<'_, '_>,
 +        ctors: impl Iterator<Item = &'a Constructor> + Clone,
 +    ) -> SmallVec<[Self; 1]> {
 +        match self {
 +            Wildcard => {
 +                let mut split_wildcard = SplitWildcard::new(pcx);
 +                split_wildcard.split(pcx, ctors);
 +                split_wildcard.into_ctors(pcx)
 +            }
 +            // Fast-track if the range is trivial. In particular, we don't do the overlapping
 +            // ranges check.
 +            IntRange(ctor_range) if !ctor_range.is_singleton() => {
 +                let mut split_range = SplitIntRange::new(ctor_range.clone());
 +                let int_ranges = ctors.filter_map(|ctor| ctor.as_int_range());
 +                split_range.split(int_ranges.cloned());
 +                split_range.iter().map(IntRange).collect()
 +            }
 +            Slice(slice) => match slice._unimplemented {},
 +            // Any other constructor can be used unchanged.
 +            _ => smallvec![self.clone()],
 +        }
 +    }
 +
 +    /// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`.
 +    /// For the simple cases, this is simply checking for equality. For the "grouped" constructors,
 +    /// this checks for inclusion.
 +    // We inline because this has a single call site in `Matrix::specialize_constructor`.
 +    #[inline]
 +    pub(super) fn is_covered_by(&self, _pcx: PatCtxt<'_, '_>, other: &Self) -> bool {
 +        // This must be kept in sync with `is_covered_by_any`.
 +        match (self, other) {
 +            // Wildcards cover anything
 +            (_, Wildcard) => true,
 +            // The missing ctors are not covered by anything in the matrix except wildcards.
 +            (Missing { .. } | Wildcard, _) => false,
 +
 +            (Single, Single) => true,
 +            (Variant(self_id), Variant(other_id)) => self_id == other_id,
 +
 +            (IntRange(self_range), IntRange(other_range)) => self_range.is_covered_by(other_range),
 +            (FloatRange(void), FloatRange(..)) => match *void {},
 +            (Str(void), Str(..)) => match *void {},
 +            (Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice),
 +
 +            // We are trying to inspect an opaque constant. Thus we skip the row.
 +            (Opaque, _) | (_, Opaque) => false,
 +            // Only a wildcard pattern can match the special extra constructor.
 +            (NonExhaustive, _) => false,
 +
 +            _ => {
 +                never!("trying to compare incompatible constructors {:?} and {:?}", self, other);
 +                // Continue with 'whatever is covered' supposed to result in false no-error diagnostic.
 +                true
 +            }
 +        }
 +    }
 +
 +    /// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is
 +    /// assumed to be built from `matrix.head_ctors()` with wildcards filtered out, and `self` is
 +    /// assumed to have been split from a wildcard.
 +    fn is_covered_by_any(&self, _pcx: PatCtxt<'_, '_>, used_ctors: &[Constructor]) -> bool {
 +        if used_ctors.is_empty() {
 +            return false;
 +        }
 +
 +        // This must be kept in sync with `is_covered_by`.
 +        match self {
 +            // If `self` is `Single`, `used_ctors` cannot contain anything else than `Single`s.
 +            Single => !used_ctors.is_empty(),
 +            Variant(_) => used_ctors.iter().any(|c| c == self),
 +            IntRange(range) => used_ctors
 +                .iter()
 +                .filter_map(|c| c.as_int_range())
 +                .any(|other| range.is_covered_by(other)),
 +            Slice(slice) => used_ctors
 +                .iter()
 +                .filter_map(|c| c.as_slice())
 +                .any(|other| slice.is_covered_by(other)),
 +            // This constructor is never covered by anything else
 +            NonExhaustive => false,
 +            Str(..) | FloatRange(..) | Opaque | Missing { .. } | Wildcard | Or => {
 +                never!("found unexpected ctor in all_ctors: {:?}", self);
 +                true
 +            }
 +        }
 +    }
 +}
 +
 +/// A wildcard constructor that we split relative to the constructors in the matrix, as explained
 +/// at the top of the file.
 +///
 +/// A constructor that is not present in the matrix rows will only be covered by the rows that have
 +/// wildcards. Thus we can group all of those constructors together; we call them "missing
 +/// constructors". Splitting a wildcard would therefore list all present constructors individually
 +/// (or grouped if they are integers or slices), and then all missing constructors together as a
 +/// group.
 +///
 +/// However we can go further: since any constructor will match the wildcard rows, and having more
 +/// rows can only reduce the amount of usefulness witnesses, we can skip the present constructors
 +/// and only try the missing ones.
 +/// This will not preserve the whole list of witnesses, but will preserve whether the list is empty
 +/// or not. In fact this is quite natural from the point of view of diagnostics too. This is done
 +/// in `to_ctors`: in some cases we only return `Missing`.
 +#[derive(Debug)]
 +pub(super) struct SplitWildcard {
 +    /// Constructors seen in the matrix.
 +    matrix_ctors: Vec<Constructor>,
 +    /// All the constructors for this type
 +    all_ctors: SmallVec<[Constructor; 1]>,
 +}
 +
 +impl SplitWildcard {
 +    pub(super) fn new(pcx: PatCtxt<'_, '_>) -> Self {
 +        let cx = pcx.cx;
 +        let make_range = |start, end, scalar| IntRange(IntRange::from_range(start, end, scalar));
 +
 +        // Unhandled types are treated as non-exhaustive. Being explicit here instead of falling
 +        // to catchall arm to ease further implementation.
 +        let unhandled = || smallvec![NonExhaustive];
 +
 +        // This determines the set of all possible constructors for the type `pcx.ty`. For numbers,
 +        // arrays and slices we use ranges and variable-length slices when appropriate.
 +        //
 +        // If the `exhaustive_patterns` feature is enabled, we make sure to omit constructors that
 +        // are statically impossible. E.g., for `Option<!>`, we do not include `Some(_)` in the
 +        // returned list of constructors.
 +        // Invariant: this is empty if and only if the type is uninhabited (as determined by
 +        // `cx.is_uninhabited()`).
 +        let all_ctors = match pcx.ty.kind(Interner) {
 +            TyKind::Scalar(Scalar::Bool) => smallvec![make_range(0, 1, Scalar::Bool)],
 +            // TyKind::Array(..) if ... => unhandled(),
 +            TyKind::Array(..) | TyKind::Slice(..) => unhandled(),
-                     .filter(|&(_, _v)| {
++            TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), subst) => {
++                let enum_data = cx.db.enum_data(*enum_id);
 +
 +                // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
 +                // additional "unknown" constructor.
 +                // There is no point in enumerating all possible variants, because the user can't
 +                // actually match against them all themselves. So we always return only the fictitious
 +                // constructor.
 +                // E.g., in an example like:
 +                //
 +                // ```
 +                //     let err: io::ErrorKind = ...;
 +                //     match err {
 +                //         io::ErrorKind::NotFound => {},
 +                //     }
 +                // ```
 +                //
 +                // we don't want to show every possible IO error, but instead have only `_` as the
 +                // witness.
 +                let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty);
 +
 +                let is_exhaustive_pat_feature = cx.feature_exhaustive_patterns();
 +
 +                // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
 +                // as though it had an "unknown" constructor to avoid exposing its emptiness. The
 +                // exception is if the pattern is at the top level, because we want empty matches to be
 +                // considered exhaustive.
 +                let is_secretly_empty = enum_data.variants.is_empty()
 +                    && !is_exhaustive_pat_feature
 +                    && !pcx.is_top_level;
 +
 +                let mut ctors: SmallVec<[_; 1]> = enum_data
 +                    .variants
 +                    .iter()
-                             && unimplemented!("after MatchCheckCtx.feature_exhaustive_patterns()");
++                    .map(|(local_id, _)| EnumVariantId { parent: *enum_id, local_id })
++                    .filter(|&variant| {
 +                        // If `exhaustive_patterns` is enabled, we exclude variants known to be
 +                        // uninhabited.
 +                        let is_uninhabited = is_exhaustive_pat_feature
-                     .map(|(local_id, _)| Variant(EnumVariantId { parent: enum_id, local_id }))
++                            && is_enum_variant_uninhabited_from(variant, subst, cx.module, cx.db);
 +                        !is_uninhabited
 +                    })
++                    .map(Variant)
 +                    .collect();
 +
 +                if is_secretly_empty || is_declared_nonexhaustive {
 +                    ctors.push(NonExhaustive);
 +                }
 +                ctors
 +            }
 +            TyKind::Scalar(Scalar::Char) => unhandled(),
 +            TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(),
 +            TyKind::Never if !cx.feature_exhaustive_patterns() && !pcx.is_top_level => {
 +                smallvec![NonExhaustive]
 +            }
 +            TyKind::Never => SmallVec::new(),
 +            _ if cx.is_uninhabited(pcx.ty) => SmallVec::new(),
 +            TyKind::Adt(..) | TyKind::Tuple(..) | TyKind::Ref(..) => smallvec![Single],
 +            // This type is one for which we cannot list constructors, like `str` or `f64`.
 +            _ => smallvec![NonExhaustive],
 +        };
 +
 +        SplitWildcard { matrix_ctors: Vec::new(), all_ctors }
 +    }
 +
 +    /// Pass a set of constructors relative to which to split this one. Don't call twice, it won't
 +    /// do what you want.
 +    pub(super) fn split<'a>(
 +        &mut self,
 +        pcx: PatCtxt<'_, '_>,
 +        ctors: impl Iterator<Item = &'a Constructor> + Clone,
 +    ) {
 +        // Since `all_ctors` never contains wildcards, this won't recurse further.
 +        self.all_ctors =
 +            self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect();
 +        self.matrix_ctors = ctors.filter(|c| !c.is_wildcard()).cloned().collect();
 +    }
 +
 +    /// Whether there are any value constructors for this type that are not present in the matrix.
 +    fn any_missing(&self, pcx: PatCtxt<'_, '_>) -> bool {
 +        self.iter_missing(pcx).next().is_some()
 +    }
 +
 +    /// Iterate over the constructors for this type that are not present in the matrix.
 +    pub(super) fn iter_missing<'a, 'p>(
 +        &'a self,
 +        pcx: PatCtxt<'a, 'p>,
 +    ) -> impl Iterator<Item = &'a Constructor> + Captures<'p> {
 +        self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.matrix_ctors))
 +    }
 +
 +    /// Return the set of constructors resulting from splitting the wildcard. As explained at the
 +    /// top of the file, if any constructors are missing we can ignore the present ones.
 +    fn into_ctors(self, pcx: PatCtxt<'_, '_>) -> SmallVec<[Constructor; 1]> {
 +        if self.any_missing(pcx) {
 +            // Some constructors are missing, thus we can specialize with the special `Missing`
 +            // constructor, which stands for those constructors that are not seen in the matrix,
 +            // and matches the same rows as any of them (namely the wildcard rows). See the top of
 +            // the file for details.
 +            // However, when all constructors are missing we can also specialize with the full
 +            // `Wildcard` constructor. The difference will depend on what we want in diagnostics.
 +
 +            // If some constructors are missing, we typically want to report those constructors,
 +            // e.g.:
 +            // ```
 +            //     enum Direction { N, S, E, W }
 +            //     let Direction::N = ...;
 +            // ```
 +            // we can report 3 witnesses: `S`, `E`, and `W`.
 +            //
 +            // However, if the user didn't actually specify a constructor
 +            // in this arm, e.g., in
 +            // ```
 +            //     let x: (Direction, Direction, bool) = ...;
 +            //     let (_, _, false) = x;
 +            // ```
 +            // we don't want to show all 16 possible witnesses `(<direction-1>, <direction-2>,
 +            // true)` - we are satisfied with `(_, _, true)`. So if all constructors are missing we
 +            // prefer to report just a wildcard `_`.
 +            //
 +            // The exception is: if we are at the top-level, for example in an empty match, we
 +            // sometimes prefer reporting the list of constructors instead of just `_`.
 +            let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty);
 +            let ctor = if !self.matrix_ctors.is_empty() || report_when_all_missing {
 +                if pcx.is_non_exhaustive {
 +                    Missing {
 +                        nonexhaustive_enum_missing_real_variants: self
 +                            .iter_missing(pcx)
 +                            .any(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))),
 +                    }
 +                } else {
 +                    Missing { nonexhaustive_enum_missing_real_variants: false }
 +                }
 +            } else {
 +                Wildcard
 +            };
 +            return smallvec![ctor];
 +        }
 +
 +        // All the constructors are present in the matrix, so we just go through them all.
 +        self.all_ctors
 +    }
 +}
 +
 +/// A value can be decomposed into a constructor applied to some fields. This struct represents
 +/// those fields, generalized to allow patterns in each field. See also `Constructor`.
 +///
 +/// This is constructed for a constructor using [`Fields::wildcards()`]. The idea is that
 +/// [`Fields::wildcards()`] constructs a list of fields where all entries are wildcards, and then
 +/// given a pattern we fill some of the fields with its subpatterns.
 +/// In the following example `Fields::wildcards` returns `[_, _, _, _]`. Then in
 +/// `extract_pattern_arguments` we fill some of the entries, and the result is
 +/// `[Some(0), _, _, _]`.
 +/// ```rust
 +/// let x: [Option<u8>; 4] = foo();
 +/// match x {
 +///     [Some(0), ..] => {}
 +/// }
 +/// ```
 +///
 +/// Note that the number of fields of a constructor may not match the fields declared in the
 +/// original struct/variant. This happens if a private or `non_exhaustive` field is uninhabited,
 +/// because the code mustn't observe that it is uninhabited. In that case that field is not
 +/// included in `fields`. For that reason, when you have a `mir::Field` you must use
 +/// `index_with_declared_idx`.
 +#[derive(Clone, Copy)]
 +pub(super) struct Fields<'p> {
 +    fields: &'p [DeconstructedPat<'p>],
 +}
 +
 +impl<'p> Fields<'p> {
 +    fn empty() -> Self {
 +        Fields { fields: &[] }
 +    }
 +
 +    fn singleton(cx: &MatchCheckCtx<'_, 'p>, field: DeconstructedPat<'p>) -> Self {
 +        let field = cx.pattern_arena.alloc(field);
 +        Fields { fields: std::slice::from_ref(field) }
 +    }
 +
 +    pub(super) fn from_iter(
 +        cx: &MatchCheckCtx<'_, 'p>,
 +        fields: impl IntoIterator<Item = DeconstructedPat<'p>>,
 +    ) -> Self {
 +        let fields: &[_] = cx.pattern_arena.alloc_extend(fields);
 +        Fields { fields }
 +    }
 +
 +    fn wildcards_from_tys(cx: &MatchCheckCtx<'_, 'p>, tys: impl IntoIterator<Item = Ty>) -> Self {
 +        Fields::from_iter(cx, tys.into_iter().map(DeconstructedPat::wildcard))
 +    }
 +
 +    // In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide
 +    // uninhabited fields in order not to reveal the uninhabitedness of the whole variant.
 +    // This lists the fields we keep along with their types.
 +    fn list_variant_nonhidden_fields<'a>(
 +        cx: &'a MatchCheckCtx<'a, 'p>,
 +        ty: &'a Ty,
 +        variant: VariantId,
 +    ) -> impl Iterator<Item = (LocalFieldId, Ty)> + Captures<'a> + Captures<'p> {
 +        let (adt, substs) = ty.as_adt().unwrap();
 +
 +        let adt_is_local = variant.module(cx.db.upcast()).krate() == cx.module.krate();
 +        // Whether we must not match the fields of this variant exhaustively.
 +        let is_non_exhaustive = is_field_list_non_exhaustive(variant, cx) && !adt_is_local;
 +
 +        let visibility = cx.db.field_visibilities(variant);
 +        let field_ty = cx.db.field_types(variant);
 +        let fields_len = variant.variant_data(cx.db.upcast()).fields().len() as u32;
 +
 +        (0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).filter_map(move |fid| {
 +            let ty = field_ty[fid].clone().substitute(Interner, substs);
 +            let ty = normalize(cx.db, cx.body, ty);
 +            let is_visible = matches!(adt, hir_def::AdtId::EnumId(..))
 +                || visibility[fid].is_visible_from(cx.db.upcast(), cx.module);
 +            let is_uninhabited = cx.is_uninhabited(&ty);
 +
 +            if is_uninhabited && (!is_visible || is_non_exhaustive) {
 +                None
 +            } else {
 +                Some((fid, ty))
 +            }
 +        })
 +    }
 +
 +    /// Creates a new list of wildcard fields for a given constructor. The result must have a
 +    /// length of `constructor.arity()`.
 +    pub(crate) fn wildcards(
 +        cx: &MatchCheckCtx<'_, 'p>,
 +        ty: &Ty,
 +        constructor: &Constructor,
 +    ) -> Self {
 +        let ret = match constructor {
 +            Single | Variant(_) => match ty.kind(Interner) {
 +                TyKind::Tuple(_, substs) => {
 +                    let tys = substs.iter(Interner).map(|ty| ty.assert_ty_ref(Interner));
 +                    Fields::wildcards_from_tys(cx, tys.cloned())
 +                }
 +                TyKind::Ref(.., rty) => Fields::wildcards_from_tys(cx, once(rty.clone())),
 +                &TyKind::Adt(AdtId(adt), ref substs) => {
 +                    if is_box(adt, cx.db) {
 +                        // The only legal patterns of type `Box` (outside `std`) are `_` and box
 +                        // patterns. If we're here we can assume this is a box pattern.
 +                        let subst_ty = substs.at(Interner, 0).assert_ty_ref(Interner).clone();
 +                        Fields::wildcards_from_tys(cx, once(subst_ty))
 +                    } else {
 +                        let variant = constructor.variant_id_for_adt(adt);
 +                        let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant)
 +                            .map(|(_, ty)| ty);
 +                        Fields::wildcards_from_tys(cx, tys)
 +                    }
 +                }
 +                ty_kind => {
 +                    never!("Unexpected type for `Single` constructor: {:?}", ty_kind);
 +                    Fields::wildcards_from_tys(cx, once(ty.clone()))
 +                }
 +            },
 +            Slice(slice) => match slice._unimplemented {},
 +            Str(..)
 +            | FloatRange(..)
 +            | IntRange(..)
 +            | NonExhaustive
 +            | Opaque
 +            | Missing { .. }
 +            | Wildcard => Fields::empty(),
 +            Or => {
 +                never!("called `Fields::wildcards` on an `Or` ctor");
 +                Fields::empty()
 +            }
 +        };
 +        ret
 +    }
 +
 +    /// Returns the list of patterns.
 +    pub(super) fn iter_patterns<'a>(
 +        &'a self,
 +    ) -> impl Iterator<Item = &'p DeconstructedPat<'p>> + Captures<'a> {
 +        self.fields.iter()
 +    }
 +}
 +
 +/// Values and patterns can be represented as a constructor applied to some fields. This represents
 +/// a pattern in this form.
 +/// This also keeps track of whether the pattern has been found reachable during analysis. For this
 +/// reason we should be careful not to clone patterns for which we care about that. Use
 +/// `clone_and_forget_reachability` if you're sure.
 +pub(crate) struct DeconstructedPat<'p> {
 +    ctor: Constructor,
 +    fields: Fields<'p>,
 +    ty: Ty,
 +    reachable: Cell<bool>,
 +}
 +
 +impl<'p> DeconstructedPat<'p> {
 +    pub(super) fn wildcard(ty: Ty) -> Self {
 +        Self::new(Wildcard, Fields::empty(), ty)
 +    }
 +
 +    pub(super) fn new(ctor: Constructor, fields: Fields<'p>, ty: Ty) -> Self {
 +        DeconstructedPat { ctor, fields, ty, reachable: Cell::new(false) }
 +    }
 +
 +    /// Construct a pattern that matches everything that starts with this constructor.
 +    /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
 +    /// `Some(_)`.
 +    pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p>, ctor: Constructor) -> Self {
 +        let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor);
 +        DeconstructedPat::new(ctor, fields, pcx.ty.clone())
 +    }
 +
 +    /// Clone this value. This method emphasizes that cloning loses reachability information and
 +    /// should be done carefully.
 +    pub(super) fn clone_and_forget_reachability(&self) -> Self {
 +        DeconstructedPat::new(self.ctor.clone(), self.fields, self.ty.clone())
 +    }
 +
 +    pub(crate) fn from_pat(cx: &MatchCheckCtx<'_, 'p>, pat: &Pat) -> Self {
 +        let mkpat = |pat| DeconstructedPat::from_pat(cx, pat);
 +        let ctor;
 +        let fields;
 +        match pat.kind.as_ref() {
 +            PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat),
 +            PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
 +                ctor = Wildcard;
 +                fields = Fields::empty();
 +            }
 +            PatKind::Deref { subpattern } => {
 +                ctor = Single;
 +                fields = Fields::singleton(cx, mkpat(subpattern));
 +            }
 +            PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
 +                match pat.ty.kind(Interner) {
 +                    TyKind::Tuple(_, substs) => {
 +                        ctor = Single;
 +                        let mut wilds: SmallVec<[_; 2]> = substs
 +                            .iter(Interner)
 +                            .map(|arg| arg.assert_ty_ref(Interner).clone())
 +                            .map(DeconstructedPat::wildcard)
 +                            .collect();
 +                        for pat in subpatterns {
 +                            let idx: u32 = pat.field.into_raw().into();
 +                            wilds[idx as usize] = mkpat(&pat.pattern);
 +                        }
 +                        fields = Fields::from_iter(cx, wilds)
 +                    }
 +                    TyKind::Adt(adt, substs) if is_box(adt.0, cx.db) => {
 +                        // The only legal patterns of type `Box` (outside `std`) are `_` and box
 +                        // patterns. If we're here we can assume this is a box pattern.
 +                        // FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_,
 +                        // _)` or a box pattern. As a hack to avoid an ICE with the former, we
 +                        // ignore other fields than the first one. This will trigger an error later
 +                        // anyway.
 +                        // See https://github.com/rust-lang/rust/issues/82772 ,
 +                        // explanation: https://github.com/rust-lang/rust/pull/82789#issuecomment-796921977
 +                        // The problem is that we can't know from the type whether we'll match
 +                        // normally or through box-patterns. We'll have to figure out a proper
 +                        // solution when we introduce generalized deref patterns. Also need to
 +                        // prevent mixing of those two options.
 +                        let pat =
 +                            subpatterns.iter().find(|pat| pat.field.into_raw() == 0u32.into());
 +                        let field = if let Some(pat) = pat {
 +                            mkpat(&pat.pattern)
 +                        } else {
 +                            let ty = substs.at(Interner, 0).assert_ty_ref(Interner).clone();
 +                            DeconstructedPat::wildcard(ty)
 +                        };
 +                        ctor = Single;
 +                        fields = Fields::singleton(cx, field)
 +                    }
 +                    &TyKind::Adt(adt, _) => {
 +                        ctor = match pat.kind.as_ref() {
 +                            PatKind::Leaf { .. } => Single,
 +                            PatKind::Variant { enum_variant, .. } => Variant(*enum_variant),
 +                            _ => {
 +                                never!();
 +                                Wildcard
 +                            }
 +                        };
 +                        let variant = ctor.variant_id_for_adt(adt.0);
 +                        let fields_len = variant.variant_data(cx.db.upcast()).fields().len();
 +                        // For each field in the variant, we store the relevant index into `self.fields` if any.
 +                        let mut field_id_to_id: Vec<Option<usize>> = vec![None; fields_len];
 +                        let tys = Fields::list_variant_nonhidden_fields(cx, &pat.ty, variant)
 +                            .enumerate()
 +                            .map(|(i, (fid, ty))| {
 +                                let field_idx: u32 = fid.into_raw().into();
 +                                field_id_to_id[field_idx as usize] = Some(i);
 +                                ty
 +                            });
 +                        let mut wilds: SmallVec<[_; 2]> =
 +                            tys.map(DeconstructedPat::wildcard).collect();
 +                        for pat in subpatterns {
 +                            let field_idx: u32 = pat.field.into_raw().into();
 +                            if let Some(i) = field_id_to_id[field_idx as usize] {
 +                                wilds[i] = mkpat(&pat.pattern);
 +                            }
 +                        }
 +                        fields = Fields::from_iter(cx, wilds);
 +                    }
 +                    _ => {
 +                        never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty);
 +                        ctor = Wildcard;
 +                        fields = Fields::empty();
 +                    }
 +                }
 +            }
 +            &PatKind::LiteralBool { value } => {
 +                ctor = IntRange(IntRange::from_bool(value));
 +                fields = Fields::empty();
 +            }
 +            PatKind::Or { .. } => {
 +                ctor = Or;
 +                let pats: SmallVec<[_; 2]> = expand_or_pat(pat).into_iter().map(mkpat).collect();
 +                fields = Fields::from_iter(cx, pats)
 +            }
 +        }
 +        DeconstructedPat::new(ctor, fields, pat.ty.clone())
 +    }
 +
 +    pub(crate) fn to_pat(&self, cx: &MatchCheckCtx<'_, 'p>) -> Pat {
 +        let mut subpatterns = self.iter_fields().map(|p| p.to_pat(cx));
 +        let pat = match &self.ctor {
 +            Single | Variant(_) => match self.ty.kind(Interner) {
 +                TyKind::Tuple(..) => PatKind::Leaf {
 +                    subpatterns: subpatterns
 +                        .zip(0u32..)
 +                        .map(|(p, i)| FieldPat {
 +                            field: LocalFieldId::from_raw(i.into()),
 +                            pattern: p,
 +                        })
 +                        .collect(),
 +                },
 +                TyKind::Adt(adt, _) if is_box(adt.0, cx.db) => {
 +                    // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
 +                    // of `std`). So this branch is only reachable when the feature is enabled and
 +                    // the pattern is a box pattern.
 +                    PatKind::Deref { subpattern: subpatterns.next().unwrap() }
 +                }
 +                TyKind::Adt(adt, substs) => {
 +                    let variant = self.ctor.variant_id_for_adt(adt.0);
 +                    let subpatterns = Fields::list_variant_nonhidden_fields(cx, self.ty(), variant)
 +                        .zip(subpatterns)
 +                        .map(|((field, _ty), pattern)| FieldPat { field, pattern })
 +                        .collect();
 +
 +                    if let VariantId::EnumVariantId(enum_variant) = variant {
 +                        PatKind::Variant { substs: substs.clone(), enum_variant, subpatterns }
 +                    } else {
 +                        PatKind::Leaf { subpatterns }
 +                    }
 +                }
 +                // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
 +                // be careful to reconstruct the correct constant pattern here. However a string
 +                // literal pattern will never be reported as a non-exhaustiveness witness, so we
 +                // ignore this issue.
 +                TyKind::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
 +                _ => {
 +                    never!("unexpected ctor for type {:?} {:?}", self.ctor, self.ty);
 +                    PatKind::Wild
 +                }
 +            },
 +            &Slice(slice) => match slice._unimplemented {},
 +            &Str(void) => match void {},
 +            &FloatRange(void) => match void {},
 +            IntRange(range) => return range.to_pat(cx, self.ty.clone()),
 +            Wildcard | NonExhaustive => PatKind::Wild,
 +            Missing { .. } => {
 +                never!(
 +                    "trying to convert a `Missing` constructor into a `Pat`; this is a bug, \
 +                    `Missing` should have been processed in `apply_constructors`"
 +                );
 +                PatKind::Wild
 +            }
 +            Opaque | Or => {
 +                never!("can't convert to pattern: {:?}", self.ctor);
 +                PatKind::Wild
 +            }
 +        };
 +        Pat { ty: self.ty.clone(), kind: Box::new(pat) }
 +    }
 +
 +    pub(super) fn is_or_pat(&self) -> bool {
 +        matches!(self.ctor, Or)
 +    }
 +
 +    pub(super) fn ctor(&self) -> &Constructor {
 +        &self.ctor
 +    }
 +
 +    pub(super) fn ty(&self) -> &Ty {
 +        &self.ty
 +    }
 +
 +    pub(super) fn iter_fields<'a>(&'a self) -> impl Iterator<Item = &'p DeconstructedPat<'p>> + 'a {
 +        self.fields.iter_patterns()
 +    }
 +
 +    /// Specialize this pattern with a constructor.
 +    /// `other_ctor` can be different from `self.ctor`, but must be covered by it.
 +    pub(super) fn specialize<'a>(
 +        &'a self,
 +        cx: &MatchCheckCtx<'_, 'p>,
 +        other_ctor: &Constructor,
 +    ) -> SmallVec<[&'p DeconstructedPat<'p>; 2]> {
 +        match (&self.ctor, other_ctor) {
 +            (Wildcard, _) => {
 +                // We return a wildcard for each field of `other_ctor`.
 +                Fields::wildcards(cx, &self.ty, other_ctor).iter_patterns().collect()
 +            }
 +            (Slice(self_slice), Slice(other_slice))
 +                if self_slice.arity() != other_slice.arity() =>
 +            {
 +                match self_slice._unimplemented {}
 +            }
 +            _ => self.fields.iter_patterns().collect(),
 +        }
 +    }
 +
 +    /// We keep track for each pattern if it was ever reachable during the analysis. This is used
 +    /// with `unreachable_spans` to report unreachable subpatterns arising from or patterns.
 +    pub(super) fn set_reachable(&self) {
 +        self.reachable.set(true)
 +    }
 +    pub(super) fn is_reachable(&self) -> bool {
 +        self.reachable.get()
 +    }
 +}
 +
 +fn is_field_list_non_exhaustive(variant_id: VariantId, cx: &MatchCheckCtx<'_, '_>) -> bool {
 +    let attr_def_id = match variant_id {
 +        VariantId::EnumVariantId(id) => id.into(),
 +        VariantId::StructId(id) => id.into(),
 +        VariantId::UnionId(id) => id.into(),
 +    };
 +    cx.db.attrs(attr_def_id).by_key("non_exhaustive").exists()
 +}
index 1221327b9510a9791984da46e12ab43d5ee142b9,0000000000000000000000000000000000000000..c4d709a975b0299a7a0a0374b83d9e12824a8236
mode 100644,000000..100644
--- /dev/null
@@@ -1,811 -1,0 +1,824 @@@
- use crate::{db::HirDatabase, Ty, TyExt};
 +//! Based on rust-lang/rust (last sync f31622a50 2021-11-12)
 +//! <https://github.com/rust-lang/rust/blob/f31622a50/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs>
 +//!
 +//! -----
 +//!
 +//! This file includes the logic for exhaustiveness and reachability checking for pattern-matching.
 +//! Specifically, given a list of patterns for a type, we can tell whether:
 +//! (a) each pattern is reachable (reachability)
 +//! (b) the patterns cover every possible value for the type (exhaustiveness)
 +//!
 +//! The algorithm implemented here is a modified version of the one described in [this
 +//! paper](http://moscova.inria.fr/~maranget/papers/warn/index.html). We have however generalized
 +//! it to accommodate the variety of patterns that Rust supports. We thus explain our version here,
 +//! without being as rigorous.
 +//!
 +//!
 +//! # Summary
 +//!
 +//! The core of the algorithm is the notion of "usefulness". A pattern `q` is said to be *useful*
 +//! relative to another pattern `p` of the same type if there is a value that is matched by `q` and
 +//! not matched by `p`. This generalizes to many `p`s: `q` is useful w.r.t. a list of patterns
 +//! `p_1 .. p_n` if there is a value that is matched by `q` and by none of the `p_i`. We write
 +//! `usefulness(p_1 .. p_n, q)` for a function that returns a list of such values. The aim of this
 +//! file is to compute it efficiently.
 +//!
 +//! This is enough to compute reachability: a pattern in a `match` expression is reachable iff it
 +//! is useful w.r.t. the patterns above it:
 +//! ```rust
 +//! match x {
 +//!     Some(_) => ...,
 +//!     None => ..., // reachable: `None` is matched by this but not the branch above
 +//!     Some(0) => ..., // unreachable: all the values this matches are already matched by
 +//!                     // `Some(_)` above
 +//! }
 +//! ```
 +//!
 +//! This is also enough to compute exhaustiveness: a match is exhaustive iff the wildcard `_`
 +//! pattern is _not_ useful w.r.t. the patterns in the match. The values returned by `usefulness`
 +//! are used to tell the user which values are missing.
 +//! ```rust
 +//! match x {
 +//!     Some(0) => ...,
 +//!     None => ...,
 +//!     // not exhaustive: `_` is useful because it matches `Some(1)`
 +//! }
 +//! ```
 +//!
 +//! The entrypoint of this file is the [`compute_match_usefulness`] function, which computes
 +//! reachability for each match branch and exhaustiveness for the whole match.
 +//!
 +//!
 +//! # Constructors and fields
 +//!
 +//! Note: we will often abbreviate "constructor" as "ctor".
 +//!
 +//! The idea that powers everything that is done in this file is the following: a (matcheable)
 +//! value is made from a constructor applied to a number of subvalues. Examples of constructors are
 +//! `Some`, `None`, `(,)` (the 2-tuple constructor), `Foo {..}` (the constructor for a struct
 +//! `Foo`), and `2` (the constructor for the number `2`). This is natural when we think of
 +//! pattern-matching, and this is the basis for what follows.
 +//!
 +//! Some of the ctors listed above might feel weird: `None` and `2` don't take any arguments.
 +//! That's ok: those are ctors that take a list of 0 arguments; they are the simplest case of
 +//! ctors. We treat `2` as a ctor because `u64` and other number types behave exactly like a huge
 +//! `enum`, with one variant for each number. This allows us to see any matcheable value as made up
 +//! from a tree of ctors, each having a set number of children. For example: `Foo { bar: None,
 +//! baz: Ok(0) }` is made from 4 different ctors, namely `Foo{..}`, `None`, `Ok` and `0`.
 +//!
 +//! This idea can be extended to patterns: they are also made from constructors applied to fields.
 +//! A pattern for a given type is allowed to use all the ctors for values of that type (which we
 +//! call "value constructors"), but there are also pattern-only ctors. The most important one is
 +//! the wildcard (`_`), and the others are integer ranges (`0..=10`), variable-length slices (`[x,
 +//! ..]`), and or-patterns (`Ok(0) | Err(_)`). Examples of valid patterns are `42`, `Some(_)`, `Foo
 +//! { bar: Some(0) | None, baz: _ }`. Note that a binder in a pattern (e.g. `Some(x)`) matches the
 +//! same values as a wildcard (e.g. `Some(_)`), so we treat both as wildcards.
 +//!
 +//! From this deconstruction we can compute whether a given value matches a given pattern; we
 +//! simply look at ctors one at a time. Given a pattern `p` and a value `v`, we want to compute
 +//! `matches!(v, p)`. It's mostly straightforward: we compare the head ctors and when they match
 +//! we compare their fields recursively. A few representative examples:
 +//!
 +//! - `matches!(v, _) := true`
 +//! - `matches!((v0,  v1), (p0,  p1)) := matches!(v0, p0) && matches!(v1, p1)`
 +//! - `matches!(Foo { bar: v0, baz: v1 }, Foo { bar: p0, baz: p1 }) := matches!(v0, p0) && matches!(v1, p1)`
 +//! - `matches!(Ok(v0), Ok(p0)) := matches!(v0, p0)`
 +//! - `matches!(Ok(v0), Err(p0)) := false` (incompatible variants)
 +//! - `matches!(v, 1..=100) := matches!(v, 1) || ... || matches!(v, 100)`
 +//! - `matches!([v0], [p0, .., p1]) := false` (incompatible lengths)
 +//! - `matches!([v0, v1, v2], [p0, .., p1]) := matches!(v0, p0) && matches!(v2, p1)`
 +//! - `matches!(v, p0 | p1) := matches!(v, p0) || matches!(v, p1)`
 +//!
 +//! Constructors, fields and relevant operations are defined in the [`super::deconstruct_pat`] module.
 +//!
 +//! Note: this constructors/fields distinction may not straightforwardly apply to every Rust type.
 +//! For example a value of type `Rc<u64>` can't be deconstructed that way, and `&str` has an
 +//! infinitude of constructors. There are also subtleties with visibility of fields and
 +//! uninhabitedness and various other things. The constructors idea can be extended to handle most
 +//! of these subtleties though; caveats are documented where relevant throughout the code.
 +//!
 +//! Whether constructors cover each other is computed by [`Constructor::is_covered_by`].
 +//!
 +//!
 +//! # Specialization
 +//!
 +//! Recall that we wish to compute `usefulness(p_1 .. p_n, q)`: given a list of patterns `p_1 ..
 +//! p_n` and a pattern `q`, all of the same type, we want to find a list of values (called
 +//! "witnesses") that are matched by `q` and by none of the `p_i`. We obviously don't just
 +//! enumerate all possible values. From the discussion above we see that we can proceed
 +//! ctor-by-ctor: for each value ctor of the given type, we ask "is there a value that starts with
 +//! this constructor and matches `q` and none of the `p_i`?". As we saw above, there's a lot we can
 +//! say from knowing only the first constructor of our candidate value.
 +//!
 +//! Let's take the following example:
 +//! ```
 +//! match x {
 +//!     Enum::Variant1(_) => {} // `p1`
 +//!     Enum::Variant2(None, 0) => {} // `p2`
 +//!     Enum::Variant2(Some(_), 0) => {} // `q`
 +//! }
 +//! ```
 +//!
 +//! We can easily see that if our candidate value `v` starts with `Variant1` it will not match `q`.
 +//! If `v = Variant2(v0, v1)` however, whether or not it matches `p2` and `q` will depend on `v0`
 +//! and `v1`. In fact, such a `v` will be a witness of usefulness of `q` exactly when the tuple
 +//! `(v0, v1)` is a witness of usefulness of `q'` in the following reduced match:
 +//!
 +//! ```
 +//! match x {
 +//!     (None, 0) => {} // `p2'`
 +//!     (Some(_), 0) => {} // `q'`
 +//! }
 +//! ```
 +//!
 +//! This motivates a new step in computing usefulness, that we call _specialization_.
 +//! Specialization consist of filtering a list of patterns for those that match a constructor, and
 +//! then looking into the constructor's fields. This enables usefulness to be computed recursively.
 +//!
 +//! Instead of acting on a single pattern in each row, we will consider a list of patterns for each
 +//! row, and we call such a list a _pattern-stack_. The idea is that we will specialize the
 +//! leftmost pattern, which amounts to popping the constructor and pushing its fields, which feels
 +//! like a stack. We note a pattern-stack simply with `[p_1 ... p_n]`.
 +//! Here's a sequence of specializations of a list of pattern-stacks, to illustrate what's
 +//! happening:
 +//! ```
 +//! [Enum::Variant1(_)]
 +//! [Enum::Variant2(None, 0)]
 +//! [Enum::Variant2(Some(_), 0)]
 +//! //==>> specialize with `Variant2`
 +//! [None, 0]
 +//! [Some(_), 0]
 +//! //==>> specialize with `Some`
 +//! [_, 0]
 +//! //==>> specialize with `true` (say the type was `bool`)
 +//! [0]
 +//! //==>> specialize with `0`
 +//! []
 +//! ```
 +//!
 +//! The function `specialize(c, p)` takes a value constructor `c` and a pattern `p`, and returns 0
 +//! or more pattern-stacks. If `c` does not match the head constructor of `p`, it returns nothing;
 +//! otherwise if returns the fields of the constructor. This only returns more than one
 +//! pattern-stack if `p` has a pattern-only constructor.
 +//!
 +//! - Specializing for the wrong constructor returns nothing
 +//!
 +//!   `specialize(None, Some(p0)) := []`
 +//!
 +//! - Specializing for the correct constructor returns a single row with the fields
 +//!
 +//!   `specialize(Variant1, Variant1(p0, p1, p2)) := [[p0, p1, p2]]`
 +//!
 +//!   `specialize(Foo{..}, Foo { bar: p0, baz: p1 }) := [[p0, p1]]`
 +//!
 +//! - For or-patterns, we specialize each branch and concatenate the results
 +//!
 +//!   `specialize(c, p0 | p1) := specialize(c, p0) ++ specialize(c, p1)`
 +//!
 +//! - We treat the other pattern constructors as if they were a large or-pattern of all the
 +//!   possibilities:
 +//!
 +//!   `specialize(c, _) := specialize(c, Variant1(_) | Variant2(_, _) | ...)`
 +//!
 +//!   `specialize(c, 1..=100) := specialize(c, 1 | ... | 100)`
 +//!
 +//!   `specialize(c, [p0, .., p1]) := specialize(c, [p0, p1] | [p0, _, p1] | [p0, _, _, p1] | ...)`
 +//!
 +//! - If `c` is a pattern-only constructor, `specialize` is defined on a case-by-case basis. See
 +//!   the discussion about constructor splitting in [`super::deconstruct_pat`].
 +//!
 +//!
 +//! We then extend this function to work with pattern-stacks as input, by acting on the first
 +//! column and keeping the other columns untouched.
 +//!
 +//! Specialization for the whole matrix is done in [`Matrix::specialize_constructor`]. Note that
 +//! or-patterns in the first column are expanded before being stored in the matrix. Specialization
 +//! for a single patstack is done from a combination of [`Constructor::is_covered_by`] and
 +//! [`PatStack::pop_head_constructor`]. The internals of how it's done mostly live in the
 +//! [`Fields`] struct.
 +//!
 +//!
 +//! # Computing usefulness
 +//!
 +//! We now have all we need to compute usefulness. The inputs to usefulness are a list of
 +//! pattern-stacks `p_1 ... p_n` (one per row), and a new pattern_stack `q`. The paper and this
 +//! file calls the list of patstacks a _matrix_. They must all have the same number of columns and
 +//! the patterns in a given column must all have the same type. `usefulness` returns a (possibly
 +//! empty) list of witnesses of usefulness. These witnesses will also be pattern-stacks.
 +//!
 +//! - base case: `n_columns == 0`.
 +//!     Since a pattern-stack functions like a tuple of patterns, an empty one functions like the
 +//!     unit type. Thus `q` is useful iff there are no rows above it, i.e. if `n == 0`.
 +//!
 +//! - inductive case: `n_columns > 0`.
 +//!     We need a way to list the constructors we want to try. We will be more clever in the next
 +//!     section but for now assume we list all value constructors for the type of the first column.
 +//!
 +//!     - for each such ctor `c`:
 +//!
 +//!         - for each `q'` returned by `specialize(c, q)`:
 +//!
 +//!             - we compute `usefulness(specialize(c, p_1) ... specialize(c, p_n), q')`
 +//!
 +//!         - for each witness found, we revert specialization by pushing the constructor `c` on top.
 +//!
 +//!     - We return the concatenation of all the witnesses found, if any.
 +//!
 +//! Example:
 +//! ```
 +//! [Some(true)] // p_1
 +//! [None] // p_2
 +//! [Some(_)] // q
 +//! //==>> try `None`: `specialize(None, q)` returns nothing
 +//! //==>> try `Some`: `specialize(Some, q)` returns a single row
 +//! [true] // p_1'
 +//! [_] // q'
 +//! //==>> try `true`: `specialize(true, q')` returns a single row
 +//! [] // p_1''
 +//! [] // q''
 +//! //==>> base case; `n != 0` so `q''` is not useful.
 +//! //==>> go back up a step
 +//! [true] // p_1'
 +//! [_] // q'
 +//! //==>> try `false`: `specialize(false, q')` returns a single row
 +//! [] // q''
 +//! //==>> base case; `n == 0` so `q''` is useful. We return the single witness `[]`
 +//! witnesses:
 +//! []
 +//! //==>> undo the specialization with `false`
 +//! witnesses:
 +//! [false]
 +//! //==>> undo the specialization with `Some`
 +//! witnesses:
 +//! [Some(false)]
 +//! //==>> we have tried all the constructors. The output is the single witness `[Some(false)]`.
 +//! ```
 +//!
 +//! This computation is done in [`is_useful`]. In practice we don't care about the list of
 +//! witnesses when computing reachability; we only need to know whether any exist. We do keep the
 +//! witnesses when computing exhaustiveness to report them to the user.
 +//!
 +//!
 +//! # Making usefulness tractable: constructor splitting
 +//!
 +//! We're missing one last detail: which constructors do we list? Naively listing all value
 +//! constructors cannot work for types like `u64` or `&str`, so we need to be more clever. The
 +//! first obvious insight is that we only want to list constructors that are covered by the head
 +//! constructor of `q`. If it's a value constructor, we only try that one. If it's a pattern-only
 +//! constructor, we use the final clever idea for this algorithm: _constructor splitting_, where we
 +//! group together constructors that behave the same.
 +//!
 +//! The details are not necessary to understand this file, so we explain them in
 +//! [`super::deconstruct_pat`]. Splitting is done by the [`Constructor::split`] function.
 +
 +use std::iter::once;
 +
 +use hir_def::{AdtId, DefWithBodyId, HasModule, ModuleId};
 +use smallvec::{smallvec, SmallVec};
 +use typed_arena::Arena;
 +
-     pub(super) fn is_uninhabited(&self, _ty: &Ty) -> bool {
-         // FIXME(iDawer) implement exhaustive_patterns feature. More info in:
-         // Tracking issue for RFC 1872: exhaustive_patterns feature https://github.com/rust-lang/rust/issues/51085
-         false
++use crate::{db::HirDatabase, inhabitedness::is_ty_uninhabited_from, Ty, TyExt};
 +
 +use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard};
 +
 +use self::{helper::Captures, ArmType::*, Usefulness::*};
 +
 +pub(crate) struct MatchCheckCtx<'a, 'p> {
 +    pub(crate) module: ModuleId,
 +    pub(crate) body: DefWithBodyId,
 +    pub(crate) db: &'a dyn HirDatabase,
 +    /// Lowered patterns from arms plus generated by the check.
 +    pub(crate) pattern_arena: &'p Arena<DeconstructedPat<'p>>,
++    exhaustive_patterns: bool,
 +}
 +
 +impl<'a, 'p> MatchCheckCtx<'a, 'p> {
-     // Rust feature described as "Allows exhaustive pattern matching on types that contain uninhabited types."
++    pub(crate) fn new(
++        module: ModuleId,
++        body: DefWithBodyId,
++        db: &'a dyn HirDatabase,
++        pattern_arena: &'p Arena<DeconstructedPat<'p>>,
++    ) -> Self {
++        let def_map = db.crate_def_map(module.krate());
++        let exhaustive_patterns = def_map.is_unstable_feature_enabled("exhaustive_patterns");
++        Self { module, body, db, pattern_arena, exhaustive_patterns }
++    }
++
++    pub(super) fn is_uninhabited(&self, ty: &Ty) -> bool {
++        if self.feature_exhaustive_patterns() {
++            is_ty_uninhabited_from(ty, self.module, self.db)
++        } else {
++            false
++        }
 +    }
 +
 +    /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
 +    pub(super) fn is_foreign_non_exhaustive_enum(&self, ty: &Ty) -> bool {
 +        match ty.as_adt() {
 +            Some((adt @ AdtId::EnumId(_), _)) => {
 +                let has_non_exhaustive_attr =
 +                    self.db.attrs(adt.into()).by_key("non_exhaustive").exists();
 +                let is_local = adt.module(self.db.upcast()).krate() == self.module.krate();
 +                has_non_exhaustive_attr && !is_local
 +            }
 +            _ => false,
 +        }
 +    }
 +
-         // FIXME see MatchCheckCtx::is_uninhabited
-         false
++    // Rust's unstable feature described as "Allows exhaustive pattern matching on types that contain uninhabited types."
 +    pub(super) fn feature_exhaustive_patterns(&self) -> bool {
++        self.exhaustive_patterns
 +    }
 +}
 +
 +#[derive(Copy, Clone)]
 +pub(super) struct PatCtxt<'a, 'p> {
 +    pub(super) cx: &'a MatchCheckCtx<'a, 'p>,
 +    /// Type of the current column under investigation.
 +    pub(super) ty: &'a Ty,
 +    /// Whether the current pattern is the whole pattern as found in a match arm, or if it's a
 +    /// subpattern.
 +    pub(super) is_top_level: bool,
 +    /// Whether the current pattern is from a `non_exhaustive` enum.
 +    pub(super) is_non_exhaustive: bool,
 +}
 +
 +/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
 +/// works well.
 +#[derive(Clone)]
 +pub(super) struct PatStack<'p> {
 +    pats: SmallVec<[&'p DeconstructedPat<'p>; 2]>,
 +}
 +
 +impl<'p> PatStack<'p> {
 +    fn from_pattern(pat: &'p DeconstructedPat<'p>) -> Self {
 +        Self::from_vec(smallvec![pat])
 +    }
 +
 +    fn from_vec(vec: SmallVec<[&'p DeconstructedPat<'p>; 2]>) -> Self {
 +        PatStack { pats: vec }
 +    }
 +
 +    fn is_empty(&self) -> bool {
 +        self.pats.is_empty()
 +    }
 +
 +    fn len(&self) -> usize {
 +        self.pats.len()
 +    }
 +
 +    fn head(&self) -> &'p DeconstructedPat<'p> {
 +        self.pats[0]
 +    }
 +
 +    // Recursively expand the first pattern into its subpatterns. Only useful if the pattern is an
 +    // or-pattern. Panics if `self` is empty.
 +    fn expand_or_pat(&self) -> impl Iterator<Item = PatStack<'p>> + Captures<'_> {
 +        self.head().iter_fields().map(move |pat| {
 +            let mut new_patstack = PatStack::from_pattern(pat);
 +            new_patstack.pats.extend_from_slice(&self.pats[1..]);
 +            new_patstack
 +        })
 +    }
 +
 +    /// This computes `S(self.head().ctor(), self)`. See top of the file for explanations.
 +    ///
 +    /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
 +    /// fields filled with wild patterns.
 +    ///
 +    /// This is roughly the inverse of `Constructor::apply`.
 +    fn pop_head_constructor(&self, cx: &MatchCheckCtx<'_, 'p>, ctor: &Constructor) -> PatStack<'p> {
 +        // We pop the head pattern and push the new fields extracted from the arguments of
 +        // `self.head()`.
 +        let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(cx, ctor);
 +        new_fields.extend_from_slice(&self.pats[1..]);
 +        PatStack::from_vec(new_fields)
 +    }
 +}
 +
 +/// A 2D matrix.
 +#[derive(Clone)]
 +pub(super) struct Matrix<'p> {
 +    patterns: Vec<PatStack<'p>>,
 +}
 +
 +impl<'p> Matrix<'p> {
 +    fn empty() -> Self {
 +        Matrix { patterns: vec![] }
 +    }
 +
 +    /// Number of columns of this matrix. `None` is the matrix is empty.
 +    pub(super) fn _column_count(&self) -> Option<usize> {
 +        self.patterns.get(0).map(|r| r.len())
 +    }
 +
 +    /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
 +    /// expands it.
 +    fn push(&mut self, row: PatStack<'p>) {
 +        if !row.is_empty() && row.head().is_or_pat() {
 +            self.patterns.extend(row.expand_or_pat());
 +        } else {
 +            self.patterns.push(row);
 +        }
 +    }
 +
 +    /// Iterate over the first component of each row
 +    fn heads(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p>> + Clone + Captures<'_> {
 +        self.patterns.iter().map(|r| r.head())
 +    }
 +
 +    /// This computes `S(constructor, self)`. See top of the file for explanations.
 +    fn specialize_constructor(&self, pcx: PatCtxt<'_, 'p>, ctor: &Constructor) -> Matrix<'p> {
 +        let mut matrix = Matrix::empty();
 +        for row in &self.patterns {
 +            if ctor.is_covered_by(pcx, row.head().ctor()) {
 +                let new_row = row.pop_head_constructor(pcx.cx, ctor);
 +                matrix.push(new_row);
 +            }
 +        }
 +        matrix
 +    }
 +}
 +
 +/// This carries the results of computing usefulness, as described at the top of the file. When
 +/// checking usefulness of a match branch, we use the `NoWitnesses` variant, which also keeps track
 +/// of potential unreachable sub-patterns (in the presence of or-patterns). When checking
 +/// exhaustiveness of a whole match, we use the `WithWitnesses` variant, which carries a list of
 +/// witnesses of non-exhaustiveness when there are any.
 +/// Which variant to use is dictated by `ArmType`.
 +enum Usefulness<'p> {
 +    /// If we don't care about witnesses, simply remember if the pattern was useful.
 +    NoWitnesses { useful: bool },
 +    /// Carries a list of witnesses of non-exhaustiveness. If empty, indicates that the whole
 +    /// pattern is unreachable.
 +    WithWitnesses(Vec<Witness<'p>>),
 +}
 +
 +impl<'p> Usefulness<'p> {
 +    fn new_useful(preference: ArmType) -> Self {
 +        match preference {
 +            // A single (empty) witness of reachability.
 +            FakeExtraWildcard => WithWitnesses(vec![Witness(vec![])]),
 +            RealArm => NoWitnesses { useful: true },
 +        }
 +    }
 +    fn new_not_useful(preference: ArmType) -> Self {
 +        match preference {
 +            FakeExtraWildcard => WithWitnesses(vec![]),
 +            RealArm => NoWitnesses { useful: false },
 +        }
 +    }
 +
 +    fn is_useful(&self) -> bool {
 +        match self {
 +            Usefulness::NoWitnesses { useful } => *useful,
 +            Usefulness::WithWitnesses(witnesses) => !witnesses.is_empty(),
 +        }
 +    }
 +
 +    /// Combine usefulnesses from two branches. This is an associative operation.
 +    fn extend(&mut self, other: Self) {
 +        match (&mut *self, other) {
 +            (WithWitnesses(_), WithWitnesses(o)) if o.is_empty() => {}
 +            (WithWitnesses(s), WithWitnesses(o)) if s.is_empty() => *self = WithWitnesses(o),
 +            (WithWitnesses(s), WithWitnesses(o)) => s.extend(o),
 +            (NoWitnesses { useful: s_useful }, NoWitnesses { useful: o_useful }) => {
 +                *s_useful = *s_useful || o_useful
 +            }
 +            _ => unreachable!(),
 +        }
 +    }
 +
 +    /// After calculating usefulness after a specialization, call this to reconstruct a usefulness
 +    /// that makes sense for the matrix pre-specialization. This new usefulness can then be merged
 +    /// with the results of specializing with the other constructors.
 +    fn apply_constructor(
 +        self,
 +        pcx: PatCtxt<'_, 'p>,
 +        matrix: &Matrix<'p>,
 +        ctor: &Constructor,
 +    ) -> Self {
 +        match self {
 +            NoWitnesses { .. } => self,
 +            WithWitnesses(ref witnesses) if witnesses.is_empty() => self,
 +            WithWitnesses(witnesses) => {
 +                let new_witnesses = if let Constructor::Missing { .. } = ctor {
 +                    // We got the special `Missing` constructor, so each of the missing constructors
 +                    // gives a new pattern that is not caught by the match. We list those patterns.
 +                    let new_patterns = if pcx.is_non_exhaustive {
 +                        // Here we don't want the user to try to list all variants, we want them to add
 +                        // a wildcard, so we only suggest that.
 +                        vec![DeconstructedPat::wildcard(pcx.ty.clone())]
 +                    } else {
 +                        let mut split_wildcard = SplitWildcard::new(pcx);
 +                        split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
 +
 +                        // This lets us know if we skipped any variants because they are marked
 +                        // `doc(hidden)` or they are unstable feature gate (only stdlib types).
 +                        let mut hide_variant_show_wild = false;
 +                        // Construct for each missing constructor a "wild" version of this
 +                        // constructor, that matches everything that can be built with
 +                        // it. For example, if `ctor` is a `Constructor::Variant` for
 +                        // `Option::Some`, we get the pattern `Some(_)`.
 +                        let mut new: Vec<DeconstructedPat<'_>> = split_wildcard
 +                            .iter_missing(pcx)
 +                            .filter_map(|missing_ctor| {
 +                                // Check if this variant is marked `doc(hidden)`
 +                                if missing_ctor.is_doc_hidden_variant(pcx)
 +                                    || missing_ctor.is_unstable_variant(pcx)
 +                                {
 +                                    hide_variant_show_wild = true;
 +                                    return None;
 +                                }
 +                                Some(DeconstructedPat::wild_from_ctor(pcx, missing_ctor.clone()))
 +                            })
 +                            .collect();
 +
 +                        if hide_variant_show_wild {
 +                            new.push(DeconstructedPat::wildcard(pcx.ty.clone()))
 +                        }
 +
 +                        new
 +                    };
 +
 +                    witnesses
 +                        .into_iter()
 +                        .flat_map(|witness| {
 +                            new_patterns.iter().map(move |pat| {
 +                                Witness(
 +                                    witness
 +                                        .0
 +                                        .iter()
 +                                        .chain(once(pat))
 +                                        .map(DeconstructedPat::clone_and_forget_reachability)
 +                                        .collect(),
 +                                )
 +                            })
 +                        })
 +                        .collect()
 +                } else {
 +                    witnesses
 +                        .into_iter()
 +                        .map(|witness| witness.apply_constructor(pcx, ctor))
 +                        .collect()
 +                };
 +                WithWitnesses(new_witnesses)
 +            }
 +        }
 +    }
 +}
 +
 +#[derive(Copy, Clone, Debug)]
 +enum ArmType {
 +    FakeExtraWildcard,
 +    RealArm,
 +}
 +
 +/// A witness of non-exhaustiveness for error reporting, represented
 +/// as a list of patterns (in reverse order of construction) with
 +/// wildcards inside to represent elements that can take any inhabitant
 +/// of the type as a value.
 +///
 +/// A witness against a list of patterns should have the same types
 +/// and length as the pattern matched against. Because Rust `match`
 +/// is always against a single pattern, at the end the witness will
 +/// have length 1, but in the middle of the algorithm, it can contain
 +/// multiple patterns.
 +///
 +/// For example, if we are constructing a witness for the match against
 +///
 +/// ```
 +/// struct Pair(Option<(u32, u32)>, bool);
 +///
 +/// match (p: Pair) {
 +///    Pair(None, _) => {}
 +///    Pair(_, false) => {}
 +/// }
 +/// ```
 +///
 +/// We'll perform the following steps:
 +/// 1. Start with an empty witness
 +///     `Witness(vec![])`
 +/// 2. Push a witness `true` against the `false`
 +///     `Witness(vec![true])`
 +/// 3. Push a witness `Some(_)` against the `None`
 +///     `Witness(vec![true, Some(_)])`
 +/// 4. Apply the `Pair` constructor to the witnesses
 +///     `Witness(vec![Pair(Some(_), true)])`
 +///
 +/// The final `Pair(Some(_), true)` is then the resulting witness.
 +pub(crate) struct Witness<'p>(Vec<DeconstructedPat<'p>>);
 +
 +impl<'p> Witness<'p> {
 +    /// Asserts that the witness contains a single pattern, and returns it.
 +    fn single_pattern(self) -> DeconstructedPat<'p> {
 +        assert_eq!(self.0.len(), 1);
 +        self.0.into_iter().next().unwrap()
 +    }
 +
 +    /// Constructs a partial witness for a pattern given a list of
 +    /// patterns expanded by the specialization step.
 +    ///
 +    /// When a pattern P is discovered to be useful, this function is used bottom-up
 +    /// to reconstruct a complete witness, e.g., a pattern P' that covers a subset
 +    /// of values, V, where each value in that set is not covered by any previously
 +    /// used patterns and is covered by the pattern P'. Examples:
 +    ///
 +    /// left_ty: tuple of 3 elements
 +    /// pats: [10, 20, _]           => (10, 20, _)
 +    ///
 +    /// left_ty: struct X { a: (bool, &'static str), b: usize}
 +    /// pats: [(false, "foo"), 42]  => X { a: (false, "foo"), b: 42 }
 +    fn apply_constructor(mut self, pcx: PatCtxt<'_, 'p>, ctor: &Constructor) -> Self {
 +        let pat = {
 +            let len = self.0.len();
 +            let arity = ctor.arity(pcx);
 +            let pats = self.0.drain((len - arity)..).rev();
 +            let fields = Fields::from_iter(pcx.cx, pats);
 +            DeconstructedPat::new(ctor.clone(), fields, pcx.ty.clone())
 +        };
 +
 +        self.0.push(pat);
 +
 +        self
 +    }
 +}
 +
 +/// Algorithm from <http://moscova.inria.fr/~maranget/papers/warn/index.html>.
 +/// The algorithm from the paper has been modified to correctly handle empty
 +/// types. The changes are:
 +///   (0) We don't exit early if the pattern matrix has zero rows. We just
 +///       continue to recurse over columns.
 +///   (1) all_constructors will only return constructors that are statically
 +///       possible. E.g., it will only return `Ok` for `Result<T, !>`.
 +///
 +/// This finds whether a (row) vector `v` of patterns is 'useful' in relation
 +/// to a set of such vectors `m` - this is defined as there being a set of
 +/// inputs that will match `v` but not any of the sets in `m`.
 +///
 +/// All the patterns at each column of the `matrix ++ v` matrix must have the same type.
 +///
 +/// This is used both for reachability checking (if a pattern isn't useful in
 +/// relation to preceding patterns, it is not reachable) and exhaustiveness
 +/// checking (if a wildcard pattern is useful in relation to a matrix, the
 +/// matrix isn't exhaustive).
 +///
 +/// `is_under_guard` is used to inform if the pattern has a guard. If it
 +/// has one it must not be inserted into the matrix. This shouldn't be
 +/// relied on for soundness.
 +fn is_useful<'p>(
 +    cx: &MatchCheckCtx<'_, 'p>,
 +    matrix: &Matrix<'p>,
 +    v: &PatStack<'p>,
 +    witness_preference: ArmType,
 +    is_under_guard: bool,
 +    is_top_level: bool,
 +) -> Usefulness<'p> {
 +    let Matrix { patterns: rows, .. } = matrix;
 +
 +    // The base case. We are pattern-matching on () and the return value is
 +    // based on whether our matrix has a row or not.
 +    // NOTE: This could potentially be optimized by checking rows.is_empty()
 +    // first and then, if v is non-empty, the return value is based on whether
 +    // the type of the tuple we're checking is inhabited or not.
 +    if v.is_empty() {
 +        let ret = if rows.is_empty() {
 +            Usefulness::new_useful(witness_preference)
 +        } else {
 +            Usefulness::new_not_useful(witness_preference)
 +        };
 +        return ret;
 +    }
 +
 +    debug_assert!(rows.iter().all(|r| r.len() == v.len()));
 +
 +    let ty = v.head().ty();
 +    let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
 +    let pcx = PatCtxt { cx, ty, is_top_level, is_non_exhaustive };
 +
 +    // If the first pattern is an or-pattern, expand it.
 +    let mut ret = Usefulness::new_not_useful(witness_preference);
 +    if v.head().is_or_pat() {
 +        // We try each or-pattern branch in turn.
 +        let mut matrix = matrix.clone();
 +        for v in v.expand_or_pat() {
 +            let usefulness = is_useful(cx, &matrix, &v, witness_preference, is_under_guard, false);
 +            ret.extend(usefulness);
 +            // If pattern has a guard don't add it to the matrix.
 +            if !is_under_guard {
 +                // We push the already-seen patterns into the matrix in order to detect redundant
 +                // branches like `Some(_) | Some(0)`.
 +                matrix.push(v);
 +            }
 +        }
 +    } else {
 +        let v_ctor = v.head().ctor();
 +
 +        // FIXME: implement `overlapping_range_endpoints` lint
 +
 +        // We split the head constructor of `v`.
 +        let split_ctors = v_ctor.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
 +        // For each constructor, we compute whether there's a value that starts with it that would
 +        // witness the usefulness of `v`.
 +        let start_matrix = matrix;
 +        for ctor in split_ctors {
 +            // We cache the result of `Fields::wildcards` because it is used a lot.
 +            let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor);
 +            let v = v.pop_head_constructor(cx, &ctor);
 +            let usefulness =
 +                is_useful(cx, &spec_matrix, &v, witness_preference, is_under_guard, false);
 +            let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor);
 +
 +            // FIXME: implement `non_exhaustive_omitted_patterns` lint
 +
 +            ret.extend(usefulness);
 +        }
 +    };
 +
 +    if ret.is_useful() {
 +        v.head().set_reachable();
 +    }
 +
 +    ret
 +}
 +
 +/// The arm of a match expression.
 +#[derive(Clone, Copy)]
 +pub(crate) struct MatchArm<'p> {
 +    pub(crate) pat: &'p DeconstructedPat<'p>,
 +    pub(crate) has_guard: bool,
 +}
 +
 +/// Indicates whether or not a given arm is reachable.
 +#[derive(Clone, Debug)]
 +pub(crate) enum Reachability {
 +    /// The arm is reachable. This additionally carries a set of or-pattern branches that have been
 +    /// found to be unreachable despite the overall arm being reachable. Used only in the presence
 +    /// of or-patterns, otherwise it stays empty.
 +    // FIXME: store ureachable subpattern IDs
 +    Reachable,
 +    /// The arm is unreachable.
 +    Unreachable,
 +}
 +
 +/// The output of checking a match for exhaustiveness and arm reachability.
 +pub(crate) struct UsefulnessReport<'p> {
 +    /// For each arm of the input, whether that arm is reachable after the arms above it.
 +    pub(crate) _arm_usefulness: Vec<(MatchArm<'p>, Reachability)>,
 +    /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
 +    /// exhaustiveness.
 +    pub(crate) non_exhaustiveness_witnesses: Vec<DeconstructedPat<'p>>,
 +}
 +
 +/// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which
 +/// of its arms are reachable.
 +///
 +/// Note: the input patterns must have been lowered through
 +/// `check_match::MatchVisitor::lower_pattern`.
 +pub(crate) fn compute_match_usefulness<'p>(
 +    cx: &MatchCheckCtx<'_, 'p>,
 +    arms: &[MatchArm<'p>],
 +    scrut_ty: &Ty,
 +) -> UsefulnessReport<'p> {
 +    let mut matrix = Matrix::empty();
 +    let arm_usefulness = arms
 +        .iter()
 +        .copied()
 +        .map(|arm| {
 +            let v = PatStack::from_pattern(arm.pat);
 +            is_useful(cx, &matrix, &v, RealArm, arm.has_guard, true);
 +            if !arm.has_guard {
 +                matrix.push(v);
 +            }
 +            let reachability = if arm.pat.is_reachable() {
 +                Reachability::Reachable
 +            } else {
 +                Reachability::Unreachable
 +            };
 +            (arm, reachability)
 +        })
 +        .collect();
 +
 +    let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty.clone()));
 +    let v = PatStack::from_pattern(wild_pattern);
 +    let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, false, true);
 +    let non_exhaustiveness_witnesses = match usefulness {
 +        WithWitnesses(pats) => pats.into_iter().map(Witness::single_pattern).collect(),
 +        NoWitnesses { .. } => panic!("bug"),
 +    };
 +    UsefulnessReport { _arm_usefulness: arm_usefulness, non_exhaustiveness_witnesses }
 +}
 +
 +pub(crate) mod helper {
 +    // Copy-pasted from rust/compiler/rustc_data_structures/src/captures.rs
 +    /// "Signaling" trait used in impl trait to tag lifetimes that you may
 +    /// need to capture but don't really need for other reasons.
 +    /// Basically a workaround; see [this comment] for details.
 +    ///
 +    /// [this comment]: https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999
 +    // FIXME(eddyb) false positive, the lifetime parameter is "phantom" but needed.
 +    #[allow(unused_lifetimes)]
 +    pub(crate) trait Captures<'a> {}
 +
 +    impl<'a, T: ?Sized> Captures<'a> for T {}
 +}
index 5df48e5fdcbaf40502d0aa11f3b9bd666132b771,0000000000000000000000000000000000000000..10ffde87eef1491b4c6777db2c19309ff6f36f4e
mode 100644,000000..100644
--- /dev/null
@@@ -1,1092 -1,0 +1,1119 @@@
-     BreakOutsideOfLoop { expr: ExprId },
 +//! Type inference, i.e. the process of walking through the code and determining
 +//! the type of each expression and pattern.
 +//!
 +//! For type inference, compare the implementations in rustc (the various
 +//! check_* methods in librustc_typeck/check/mod.rs are a good entry point) and
 +//! IntelliJ-Rust (org.rust.lang.core.types.infer). Our entry point for
 +//! inference here is the `infer` function, which infers the types of all
 +//! expressions in a given function.
 +//!
 +//! During inference, types (i.e. the `Ty` struct) can contain type 'variables'
 +//! which represent currently unknown types; as we walk through the expressions,
 +//! we might determine that certain variables need to be equal to each other, or
 +//! to certain types. To record this, we use the union-find implementation from
 +//! the `ena` crate, which is extracted from rustc.
 +
 +use std::ops::Index;
 +use std::sync::Arc;
 +
 +use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
 +use hir_def::{
 +    body::Body,
 +    data::{ConstData, StaticData},
 +    expr::{BindingAnnotation, ExprId, PatId},
 +    lang_item::LangItemTarget,
 +    path::{path, Path},
 +    resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
 +    type_ref::TypeRef,
 +    AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup,
 +    TraitId, TypeAliasId, VariantId,
 +};
 +use hir_expand::name::{name, Name};
 +use itertools::Either;
 +use la_arena::ArenaMap;
 +use rustc_hash::FxHashMap;
 +use stdx::{always, impl_from};
 +
 +use crate::{
 +    db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany,
 +    lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal,
 +    GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, Substitution,
 +    TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
 +};
 +
 +// This lint has a false positive here. See the link below for details.
 +//
 +// https://github.com/rust-lang/rust/issues/57411
 +#[allow(unreachable_pub)]
 +pub use coerce::could_coerce;
 +#[allow(unreachable_pub)]
 +pub use unify::could_unify;
 +
 +pub(crate) mod unify;
 +mod path;
 +mod expr;
 +mod pat;
 +mod coerce;
 +mod closure;
 +
 +/// The entry point of type inference.
 +pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
 +    let _p = profile::span("infer_query");
 +    let resolver = def.resolver(db.upcast());
 +    let body = db.body(def);
 +    let mut ctx = InferenceContext::new(db, def, &body, resolver);
 +
 +    match def {
 +        DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
 +        DefWithBodyId::FunctionId(f) => ctx.collect_fn(f),
 +        DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
 +    }
 +
 +    ctx.infer_body();
 +
 +    Arc::new(ctx.resolve_all())
 +}
 +
 +/// Fully normalize all the types found within `ty` in context of `owner` body definition.
 +///
 +/// This is appropriate to use only after type-check: it assumes
 +/// that normalization will succeed, for example.
 +pub(crate) fn normalize(db: &dyn HirDatabase, owner: DefWithBodyId, ty: Ty) -> Ty {
 +    if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION) {
 +        return ty;
 +    }
 +    let krate = owner.module(db.upcast()).krate();
 +    let trait_env = owner
 +        .as_generic_def_id()
 +        .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
 +    let mut table = unify::InferenceTable::new(db, trait_env);
 +
 +    let ty_with_vars = table.normalize_associated_types_in(ty);
 +    table.resolve_obligations_as_possible();
 +    table.propagate_diverging_flag();
 +    table.resolve_completely(ty_with_vars)
 +}
 +
 +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 +enum ExprOrPatId {
 +    ExprId(ExprId),
 +    PatId(PatId),
 +}
 +impl_from!(ExprId, PatId for ExprOrPatId);
 +
 +/// Binding modes inferred for patterns.
 +/// <https://doc.rust-lang.org/reference/patterns.html#binding-modes>
 +#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 +pub enum BindingMode {
 +    Move,
 +    Ref(Mutability),
 +}
 +
 +impl BindingMode {
 +    fn convert(annotation: BindingAnnotation) -> BindingMode {
 +        match annotation {
 +            BindingAnnotation::Unannotated | BindingAnnotation::Mutable => BindingMode::Move,
 +            BindingAnnotation::Ref => BindingMode::Ref(Mutability::Not),
 +            BindingAnnotation::RefMut => BindingMode::Ref(Mutability::Mut),
 +        }
 +    }
 +}
 +
 +impl Default for BindingMode {
 +    fn default() -> Self {
 +        BindingMode::Move
 +    }
 +}
 +
 +/// Used to generalize patterns and assignee expressions.
 +trait PatLike: Into<ExprOrPatId> + Copy {
 +    type BindingMode: Copy;
 +
 +    fn infer(
 +        this: &mut InferenceContext<'_>,
 +        id: Self,
 +        expected_ty: &Ty,
 +        default_bm: Self::BindingMode,
 +    ) -> Ty;
 +}
 +
 +impl PatLike for ExprId {
 +    type BindingMode = ();
 +
 +    fn infer(
 +        this: &mut InferenceContext<'_>,
 +        id: Self,
 +        expected_ty: &Ty,
 +        _: Self::BindingMode,
 +    ) -> Ty {
 +        this.infer_assignee_expr(id, expected_ty)
 +    }
 +}
 +
 +impl PatLike for PatId {
 +    type BindingMode = BindingMode;
 +
 +    fn infer(
 +        this: &mut InferenceContext<'_>,
 +        id: Self,
 +        expected_ty: &Ty,
 +        default_bm: Self::BindingMode,
 +    ) -> Ty {
 +        this.infer_pat(id, expected_ty, default_bm)
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub(crate) struct InferOk<T> {
 +    value: T,
 +    goals: Vec<InEnvironment<Goal>>,
 +}
 +
 +impl<T> InferOk<T> {
 +    fn map<U>(self, f: impl FnOnce(T) -> U) -> InferOk<U> {
 +        InferOk { value: f(self.value), goals: self.goals }
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub(crate) struct TypeError;
 +pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
 +
 +#[derive(Debug, PartialEq, Eq, Clone)]
 +pub enum InferenceDiagnostic {
 +    NoSuchField { expr: ExprId },
-         Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label),
-         None => ctxs.last_mut(),
++    BreakOutsideOfLoop { expr: ExprId, is_break: bool },
 +    MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
 +}
 +
 +/// A mismatch between an expected and an inferred type.
 +#[derive(Clone, PartialEq, Eq, Debug, Hash)]
 +pub struct TypeMismatch {
 +    pub expected: Ty,
 +    pub actual: Ty,
 +}
 +
 +#[derive(Clone, PartialEq, Eq, Debug)]
 +struct InternedStandardTypes {
 +    unknown: Ty,
 +    bool_: Ty,
 +    unit: Ty,
 +}
 +
 +impl Default for InternedStandardTypes {
 +    fn default() -> Self {
 +        InternedStandardTypes {
 +            unknown: TyKind::Error.intern(Interner),
 +            bool_: TyKind::Scalar(Scalar::Bool).intern(Interner),
 +            unit: TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner),
 +        }
 +    }
 +}
 +/// Represents coercing a value to a different type of value.
 +///
 +/// We transform values by following a number of `Adjust` steps in order.
 +/// See the documentation on variants of `Adjust` for more details.
 +///
 +/// Here are some common scenarios:
 +///
 +/// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
 +///    Here the pointer will be dereferenced N times (where a dereference can
 +///    happen to raw or borrowed pointers or any smart pointer which implements
 +///    Deref, including Box<_>). The types of dereferences is given by
 +///    `autoderefs`. It can then be auto-referenced zero or one times, indicated
 +///    by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
 +///    `false`.
 +///
 +/// 2. A thin-to-fat coercion involves unsizing the underlying data. We start
 +///    with a thin pointer, deref a number of times, unsize the underlying data,
 +///    then autoref. The 'unsize' phase may change a fixed length array to a
 +///    dynamically sized one, a concrete object to a trait object, or statically
 +///    sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is
 +///    represented by:
 +///
 +///    ```
 +///    Deref(None) -> [i32; 4],
 +///    Borrow(AutoBorrow::Ref) -> &[i32; 4],
 +///    Unsize -> &[i32],
 +///    ```
 +///
 +///    Note that for a struct, the 'deep' unsizing of the struct is not recorded.
 +///    E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
 +///    The autoderef and -ref are the same as in the above example, but the type
 +///    stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
 +///    the underlying conversions from `[i32; 4]` to `[i32]`.
 +///
 +/// 3. Coercing a `Box<T>` to `Box<dyn Trait>` is an interesting special case. In
 +///    that case, we have the pointer we need coming in, so there are no
 +///    autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
 +///    At some point, of course, `Box` should move out of the compiler, in which
 +///    case this is analogous to transforming a struct. E.g., Box<[i32; 4]> ->
 +///    Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`.
 +#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 +pub struct Adjustment {
 +    pub kind: Adjust,
 +    pub target: Ty,
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum Adjust {
 +    /// Go from ! to any type.
 +    NeverToAny,
 +    /// Dereference once, producing a place.
 +    Deref(Option<OverloadedDeref>),
 +    /// Take the address and produce either a `&` or `*` pointer.
 +    Borrow(AutoBorrow),
 +    Pointer(PointerCast),
 +}
 +
 +/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
 +/// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`.
 +/// The target type is `U` in both cases, with the region and mutability
 +/// being those shared by both the receiver and the returned reference.
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct OverloadedDeref(pub Mutability);
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum AutoBorrow {
 +    /// Converts from T to &T.
 +    Ref(Mutability),
 +    /// Converts from T to *T.
 +    RawPtr(Mutability),
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum PointerCast {
 +    /// Go from a fn-item type to a fn-pointer type.
 +    ReifyFnPointer,
 +
 +    /// Go from a safe fn pointer to an unsafe fn pointer.
 +    UnsafeFnPointer,
 +
 +    /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
 +    /// It cannot convert a closure that requires unsafe.
 +    ClosureFnPointer(Safety),
 +
 +    /// Go from a mut raw pointer to a const raw pointer.
 +    MutToConstPointer,
 +
 +    #[allow(dead_code)]
 +    /// Go from `*const [T; N]` to `*const T`
 +    ArrayToPointer,
 +
 +    /// Unsize a pointer/reference value, e.g., `&[T; n]` to
 +    /// `&[T]`. Note that the source could be a thin or fat pointer.
 +    /// This will do things like convert thin pointers to fat
 +    /// pointers, or convert structs containing thin pointers to
 +    /// structs containing fat pointers, or convert between fat
 +    /// pointers. We don't store the details of how the transform is
 +    /// done (in fact, we don't know that, because it might depend on
 +    /// the precise type parameters). We just store the target
 +    /// type. Codegen backends and miri figure out what has to be done
 +    /// based on the precise source/target type at hand.
 +    Unsize,
 +}
 +
 +/// The result of type inference: A mapping from expressions and patterns to types.
 +#[derive(Clone, PartialEq, Eq, Debug, Default)]
 +pub struct InferenceResult {
 +    /// For each method call expr, records the function it resolves to.
 +    method_resolutions: FxHashMap<ExprId, (FunctionId, Substitution)>,
 +    /// For each field access expr, records the field it resolves to.
 +    field_resolutions: FxHashMap<ExprId, FieldId>,
 +    /// For each struct literal or pattern, records the variant it resolves to.
 +    variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
 +    /// For each associated item record what it resolves to
 +    assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
 +    pub diagnostics: Vec<InferenceDiagnostic>,
 +    pub type_of_expr: ArenaMap<ExprId, Ty>,
 +    /// For each pattern record the type it resolves to.
 +    ///
 +    /// **Note**: When a pattern type is resolved it may still contain
 +    /// unresolved or missing subpatterns or subpatterns of mismatched types.
 +    pub type_of_pat: ArenaMap<PatId, Ty>,
 +    type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
 +    /// Interned Unknown to return references to.
 +    standard_types: InternedStandardTypes,
 +    /// Stores the types which were implicitly dereferenced in pattern binding modes.
 +    pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
 +    pub pat_binding_modes: FxHashMap<PatId, BindingMode>,
 +    pub expr_adjustments: FxHashMap<ExprId, Vec<Adjustment>>,
 +}
 +
 +impl InferenceResult {
 +    pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> {
 +        self.method_resolutions.get(&expr).cloned()
 +    }
 +    pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> {
 +        self.field_resolutions.get(&expr).copied()
 +    }
 +    pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> {
 +        self.variant_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
 +        self.variant_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<AssocItemId> {
 +        self.assoc_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<AssocItemId> {
 +        self.assoc_resolutions.get(&id.into()).copied()
 +    }
 +    pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
 +        self.type_mismatches.get(&expr.into())
 +    }
 +    pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch> {
 +        self.type_mismatches.get(&pat.into())
 +    }
 +    pub fn expr_type_mismatches(&self) -> impl Iterator<Item = (ExprId, &TypeMismatch)> {
 +        self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat {
 +            ExprOrPatId::ExprId(expr) => Some((expr, mismatch)),
 +            _ => None,
 +        })
 +    }
 +    pub fn pat_type_mismatches(&self) -> impl Iterator<Item = (PatId, &TypeMismatch)> {
 +        self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat {
 +            ExprOrPatId::PatId(pat) => Some((pat, mismatch)),
 +            _ => None,
 +        })
 +    }
 +}
 +
 +impl Index<ExprId> for InferenceResult {
 +    type Output = Ty;
 +
 +    fn index(&self, expr: ExprId) -> &Ty {
 +        self.type_of_expr.get(expr).unwrap_or(&self.standard_types.unknown)
 +    }
 +}
 +
 +impl Index<PatId> for InferenceResult {
 +    type Output = Ty;
 +
 +    fn index(&self, pat: PatId) -> &Ty {
 +        self.type_of_pat.get(pat).unwrap_or(&self.standard_types.unknown)
 +    }
 +}
 +
 +/// The inference context contains all information needed during type inference.
 +#[derive(Clone, Debug)]
 +pub(crate) struct InferenceContext<'a> {
 +    pub(crate) db: &'a dyn HirDatabase,
 +    pub(crate) owner: DefWithBodyId,
 +    pub(crate) body: &'a Body,
 +    pub(crate) resolver: Resolver,
 +    table: unify::InferenceTable<'a>,
 +    trait_env: Arc<TraitEnvironment>,
 +    pub(crate) result: InferenceResult,
 +    /// The return type of the function being inferred, the closure or async block if we're
 +    /// currently within one.
 +    ///
 +    /// We might consider using a nested inference context for checking
 +    /// closures, but currently this is the only field that will change there,
 +    /// so it doesn't make sense.
 +    return_ty: Ty,
 +    diverges: Diverges,
 +    breakables: Vec<BreakableContext>,
 +}
 +
 +#[derive(Clone, Debug)]
 +struct BreakableContext {
++    /// 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
 +            db,
 +            owner,
 +            body,
 +            resolver,
 +            diverges: Diverges::Maybe,
 +            breakables: Vec::new(),
 +        }
 +    }
 +
 +    fn resolve_all(self) -> InferenceResult {
 +        let InferenceContext { mut table, mut result, .. } = self;
 +
 +        // FIXME resolve obligations as well (use Guidance if necessary)
 +        table.resolve_obligations_as_possible();
 +
 +        // make sure diverging type variables are marked as such
 +        table.propagate_diverging_flag();
 +        for ty in result.type_of_expr.values_mut() {
 +            *ty = table.resolve_completely(ty.clone());
 +        }
 +        for ty in result.type_of_pat.values_mut() {
 +            *ty = table.resolve_completely(ty.clone());
 +        }
 +        for mismatch in result.type_mismatches.values_mut() {
 +            mismatch.expected = table.resolve_completely(mismatch.expected.clone());
 +            mismatch.actual = table.resolve_completely(mismatch.actual.clone());
 +        }
 +        for (_, subst) in result.method_resolutions.values_mut() {
 +            *subst = table.resolve_completely(subst.clone());
 +        }
 +        for adjustment in result.expr_adjustments.values_mut().flatten() {
 +            adjustment.target = table.resolve_completely(adjustment.target.clone());
 +        }
 +        for adjustment in result.pat_adjustments.values_mut().flatten() {
 +            *adjustment = table.resolve_completely(adjustment.clone());
 +        }
 +        result
 +    }
 +
 +    fn collect_const(&mut self, data: &ConstData) {
 +        self.return_ty = self.make_ty(&data.type_ref);
 +    }
 +
 +    fn collect_static(&mut self, data: &StaticData) {
 +        self.return_ty = self.make_ty(&data.type_ref);
 +    }
 +
 +    fn collect_fn(&mut self, func: FunctionId) {
 +        let data = self.db.function_data(func);
 +        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
 +            .with_impl_trait_mode(ImplTraitLoweringMode::Param);
 +        let param_tys =
 +            data.params.iter().map(|(_, type_ref)| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
 +        for (ty, pat) in param_tys.into_iter().zip(self.body.params.iter()) {
 +            let ty = self.insert_type_vars(ty);
 +            let ty = self.normalize_associated_types_in(ty);
 +
 +            self.infer_pat(*pat, &ty, BindingMode::default());
 +        }
 +        let error_ty = &TypeRef::Error;
 +        let return_ty = if data.has_async_kw() {
 +            data.async_ret_type.as_deref().unwrap_or(error_ty)
 +        } else {
 +            &*data.ret_type
 +        };
 +        let return_ty = self.make_ty_with_mode(return_ty, ImplTraitLoweringMode::Opaque);
 +        self.return_ty = return_ty;
 +
 +        if let Some(rpits) = self.db.return_type_impl_traits(func) {
 +            // RPIT opaque types use substitution of their parent function.
 +            let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
 +            self.return_ty = fold_tys(
 +                self.return_ty.clone(),
 +                |ty, _| {
 +                    let opaque_ty_id = match ty.kind(Interner) {
 +                        TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id,
 +                        _ => return ty,
 +                    };
 +                    let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
 +                        ImplTraitId::ReturnTypeImplTrait(_, idx) => idx,
 +                        _ => unreachable!(),
 +                    };
 +                    let bounds = (*rpits).map_ref(|rpits| {
 +                        rpits.impl_traits[idx as usize].bounds.map_ref(|it| it.into_iter())
 +                    });
 +                    let var = self.table.new_type_var();
 +                    let var_subst = Substitution::from1(Interner, var.clone());
 +                    for bound in bounds {
 +                        let predicate =
 +                            bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders);
 +                        let (var_predicate, binders) = predicate
 +                            .substitute(Interner, &var_subst)
 +                            .into_value_and_skipped_binders();
 +                        always!(binders.len(Interner) == 0); // quantified where clauses not yet handled
 +                        self.push_obligation(var_predicate.cast(Interner));
 +                    }
 +                    var
 +                },
 +                DebruijnIndex::INNERMOST,
 +            );
 +        }
 +    }
 +
 +    fn infer_body(&mut self) {
 +        self.infer_expr_coerce(self.body.body_expr, &Expectation::has_type(self.return_ty.clone()));
 +    }
 +
 +    fn write_expr_ty(&mut self, expr: ExprId, ty: Ty) {
 +        self.result.type_of_expr.insert(expr, ty);
 +    }
 +
 +    fn write_expr_adj(&mut self, expr: ExprId, adjustments: Vec<Adjustment>) {
 +        self.result.expr_adjustments.insert(expr, adjustments);
 +    }
 +
 +    fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) {
 +        self.result.method_resolutions.insert(expr, (func, subst));
 +    }
 +
 +    fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantId) {
 +        self.result.variant_resolutions.insert(id, variant);
 +    }
 +
 +    fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId) {
 +        self.result.assoc_resolutions.insert(id, item);
 +    }
 +
 +    fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
 +        self.result.type_of_pat.insert(pat, ty);
 +    }
 +
 +    fn push_diagnostic(&mut self, diagnostic: InferenceDiagnostic) {
 +        self.result.diagnostics.push(diagnostic);
 +    }
 +
 +    fn make_ty_with_mode(
 +        &mut self,
 +        type_ref: &TypeRef,
 +        impl_trait_mode: ImplTraitLoweringMode,
 +    ) -> Ty {
 +        // FIXME use right resolver for block
 +        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
 +            .with_impl_trait_mode(impl_trait_mode);
 +        let ty = ctx.lower_ty(type_ref);
 +        let ty = self.insert_type_vars(ty);
 +        self.normalize_associated_types_in(ty)
 +    }
 +
 +    fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
 +        self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed)
 +    }
 +
 +    fn err_ty(&self) -> Ty {
 +        self.result.standard_types.unknown.clone()
 +    }
 +
 +    /// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it.
 +    fn insert_const_vars_shallow(&mut self, c: Const) -> Const {
 +        let data = c.data(Interner);
 +        match data.value {
 +            ConstValue::Concrete(cc) => match cc.interned {
 +                hir_def::type_ref::ConstScalar::Unknown => {
 +                    self.table.new_const_var(data.ty.clone())
 +                }
 +                _ => c,
 +            },
 +            _ => c,
 +        }
 +    }
 +
 +    /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
 +    fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
 +        match ty.kind(Interner) {
 +            TyKind::Error => self.table.new_type_var(),
 +            TyKind::InferenceVar(..) => {
 +                let ty_resolved = self.resolve_ty_shallow(&ty);
 +                if ty_resolved.is_unknown() {
 +                    self.table.new_type_var()
 +                } else {
 +                    ty
 +                }
 +            }
 +            _ => ty,
 +        }
 +    }
 +
 +    fn insert_type_vars(&mut self, ty: Ty) -> Ty {
 +        fold_tys_and_consts(
 +            ty,
 +            |x, _| match x {
 +                Either::Left(ty) => Either::Left(self.insert_type_vars_shallow(ty)),
 +                Either::Right(c) => Either::Right(self.insert_const_vars_shallow(c)),
 +            },
 +            DebruijnIndex::INNERMOST,
 +        )
 +    }
 +
 +    fn resolve_obligations_as_possible(&mut self) {
 +        self.table.resolve_obligations_as_possible();
 +    }
 +
 +    fn push_obligation(&mut self, o: DomainGoal) {
 +        self.table.register_obligation(o.cast(Interner));
 +    }
 +
 +    fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
 +        self.table.unify(ty1, ty2)
 +    }
 +
 +    /// Recurses through the given type, normalizing associated types mentioned
 +    /// in it by replacing them by type variables and registering obligations to
 +    /// resolve later. This should be done once for every type we get from some
 +    /// type annotation (e.g. from a let type annotation, field type or function
 +    /// call). `make_ty` handles this already, but e.g. for field types we need
 +    /// to do it as well.
 +    fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
 +        self.table.normalize_associated_types_in(ty)
 +    }
 +
 +    fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
 +        self.resolve_obligations_as_possible();
 +        self.table.resolve_ty_shallow(ty)
 +    }
 +
 +    fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty {
 +        self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[])
 +    }
 +
 +    fn resolve_associated_type_with_params(
 +        &mut self,
 +        inner_ty: Ty,
 +        assoc_ty: Option<TypeAliasId>,
 +        params: &[GenericArg],
 +    ) -> Ty {
 +        match assoc_ty {
 +            Some(res_assoc_ty) => {
 +                let trait_ = match res_assoc_ty.lookup(self.db.upcast()).container {
 +                    hir_def::ItemContainerId::TraitId(trait_) => trait_,
 +                    _ => panic!("resolve_associated_type called with non-associated type"),
 +                };
 +                let ty = self.table.new_type_var();
 +                let mut param_iter = params.iter().cloned();
 +                let trait_ref = TyBuilder::trait_ref(self.db, trait_)
 +                    .push(inner_ty)
 +                    .fill(|_| param_iter.next().unwrap())
 +                    .build();
 +                let alias_eq = AliasEq {
 +                    alias: AliasTy::Projection(ProjectionTy {
 +                        associated_ty_id: to_assoc_type_id(res_assoc_ty),
 +                        substitution: trait_ref.substitution.clone(),
 +                    }),
 +                    ty: ty.clone(),
 +                };
 +                self.push_obligation(trait_ref.cast(Interner));
 +                self.push_obligation(alias_eq.cast(Interner));
 +                ty
 +            }
 +            None => self.err_ty(),
 +        }
 +    }
 +
 +    fn resolve_variant(&mut self, path: Option<&Path>, value_ns: bool) -> (Ty, Option<VariantId>) {
 +        let path = match path {
 +            Some(path) => path,
 +            None => return (self.err_ty(), None),
 +        };
 +        let resolver = &self.resolver;
 +        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
 +        // FIXME: this should resolve assoc items as well, see this example:
 +        // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
 +        let (resolution, unresolved) = if value_ns {
 +            match resolver.resolve_path_in_value_ns(self.db.upcast(), path.mod_path()) {
 +                Some(ResolveValueResult::ValueNs(value)) => match value {
 +                    ValueNs::EnumVariantId(var) => {
 +                        let substs = ctx.substs_from_path(path, var.into(), true);
 +                        let ty = self.db.ty(var.parent.into());
 +                        let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                        return (ty, Some(var.into()));
 +                    }
 +                    ValueNs::StructId(strukt) => {
 +                        let substs = ctx.substs_from_path(path, strukt.into(), true);
 +                        let ty = self.db.ty(strukt.into());
 +                        let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                        return (ty, Some(strukt.into()));
 +                    }
 +                    ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
 +                    _ => return (self.err_ty(), None),
 +                },
 +                Some(ResolveValueResult::Partial(typens, unresolved)) => (typens, Some(unresolved)),
 +                None => return (self.err_ty(), None),
 +            }
 +        } else {
 +            match resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
 +                Some(it) => it,
 +                None => return (self.err_ty(), None),
 +            }
 +        };
 +        return match resolution {
 +            TypeNs::AdtId(AdtId::StructId(strukt)) => {
 +                let substs = ctx.substs_from_path(path, strukt.into(), true);
 +                let ty = self.db.ty(strukt.into());
 +                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
 +            }
 +            TypeNs::AdtId(AdtId::UnionId(u)) => {
 +                let substs = ctx.substs_from_path(path, u.into(), true);
 +                let ty = self.db.ty(u.into());
 +                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                forbid_unresolved_segments((ty, Some(u.into())), unresolved)
 +            }
 +            TypeNs::EnumVariantId(var) => {
 +                let substs = ctx.substs_from_path(path, var.into(), true);
 +                let ty = self.db.ty(var.parent.into());
 +                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
 +                forbid_unresolved_segments((ty, Some(var.into())), unresolved)
 +            }
 +            TypeNs::SelfType(impl_id) => {
 +                let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
 +                let substs = generics.placeholder_subst(self.db);
 +                let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
 +                self.resolve_variant_on_alias(ty, unresolved, path)
 +            }
 +            TypeNs::TypeAliasId(it) => {
 +                let ty = TyBuilder::def_ty(self.db, it.into())
 +                    .fill_with_inference_vars(&mut self.table)
 +                    .build();
 +                self.resolve_variant_on_alias(ty, unresolved, path)
 +            }
 +            TypeNs::AdtSelfType(_) => {
 +                // FIXME this could happen in array size expressions, once we're checking them
 +                (self.err_ty(), None)
 +            }
 +            TypeNs::GenericParam(_) => {
 +                // FIXME potentially resolve assoc type
 +                (self.err_ty(), None)
 +            }
 +            TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::TraitId(_) => {
 +                // FIXME diagnostic
 +                (self.err_ty(), None)
 +            }
 +        };
 +
 +        fn forbid_unresolved_segments(
 +            result: (Ty, Option<VariantId>),
 +            unresolved: Option<usize>,
 +        ) -> (Ty, Option<VariantId>) {
 +            if unresolved.is_none() {
 +                result
 +            } else {
 +                // FIXME diagnostic
 +                (TyKind::Error.intern(Interner), None)
 +            }
 +        }
 +    }
 +
 +    fn resolve_variant_on_alias(
 +        &mut self,
 +        ty: Ty,
 +        unresolved: Option<usize>,
 +        path: &Path,
 +    ) -> (Ty, Option<VariantId>) {
 +        let remaining = unresolved.map(|x| path.segments().skip(x).len()).filter(|x| x > &0);
 +        match remaining {
 +            None => {
 +                let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id {
 +                    AdtId::StructId(s) => Some(VariantId::StructId(s)),
 +                    AdtId::UnionId(u) => Some(VariantId::UnionId(u)),
 +                    AdtId::EnumId(_) => {
 +                        // FIXME Error E0071, expected struct, variant or union type, found enum `Foo`
 +                        None
 +                    }
 +                });
 +                (ty, variant)
 +            }
 +            Some(1) => {
 +                let segment = path.mod_path().segments().last().unwrap();
 +                // this could be an enum variant or associated type
 +                if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
 +                    let enum_data = self.db.enum_data(enum_id);
 +                    if let Some(local_id) = enum_data.variant(segment) {
 +                        let variant = EnumVariantId { parent: enum_id, local_id };
 +                        return (ty, Some(variant.into()));
 +                    }
 +                }
 +                // FIXME potentially resolve assoc type
 +                (self.err_ty(), None)
 +            }
 +            Some(_) => {
 +                // FIXME diagnostic
 +                (self.err_ty(), None)
 +            }
 +        }
 +    }
 +
 +    fn resolve_lang_item(&self, name: Name) -> Option<LangItemTarget> {
 +        let krate = self.resolver.krate();
 +        self.db.lang_item(krate, name.to_smol_str())
 +    }
 +
 +    fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
 +        let path = path![core::iter::IntoIterator];
 +        let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Item])
 +    }
 +
 +    fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
 +        // FIXME resolve via lang_item once try v2 is stable
 +        let path = path![core::ops::Try];
 +        let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
 +        let trait_data = self.db.trait_data(trait_);
 +        trait_data
 +            // FIXME remove once try v2 is stable
 +            .associated_type_by_name(&name![Ok])
 +            .or_else(|| trait_data.associated_type_by_name(&name![Output]))
 +    }
 +
 +    fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
 +        let trait_ = self.resolve_lang_item(name![neg])?.as_trait()?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Output])
 +    }
 +
 +    fn resolve_ops_not_output(&self) -> Option<TypeAliasId> {
 +        let trait_ = self.resolve_lang_item(name![not])?.as_trait()?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Output])
 +    }
 +
 +    fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
 +        let trait_ = self
 +            .resolver
 +            .resolve_known_trait(self.db.upcast(), &path![core::future::IntoFuture])
 +            .or_else(|| self.resolve_lang_item(name![future_trait])?.as_trait())?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Output])
 +    }
 +
 +    fn resolve_boxed_box(&self) -> Option<AdtId> {
 +        let struct_ = self.resolve_lang_item(name![owned_box])?.as_struct()?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range_full(&self) -> Option<AdtId> {
 +        let path = path![core::ops::RangeFull];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range(&self) -> Option<AdtId> {
 +        let path = path![core::ops::Range];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range_inclusive(&self) -> Option<AdtId> {
 +        let path = path![core::ops::RangeInclusive];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range_from(&self) -> Option<AdtId> {
 +        let path = path![core::ops::RangeFrom];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range_to(&self) -> Option<AdtId> {
 +        let path = path![core::ops::RangeTo];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_range_to_inclusive(&self) -> Option<AdtId> {
 +        let path = path![core::ops::RangeToInclusive];
 +        let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?;
 +        Some(struct_.into())
 +    }
 +
 +    fn resolve_ops_index(&self) -> Option<TraitId> {
 +        self.resolve_lang_item(name![index])?.as_trait()
 +    }
 +
 +    fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
 +        let trait_ = self.resolve_ops_index()?;
 +        self.db.trait_data(trait_).associated_type_by_name(&name![Output])
 +    }
 +}
 +
 +/// When inferring an expression, we propagate downward whatever type hint we
 +/// are able in the form of an `Expectation`.
 +#[derive(Clone, PartialEq, Eq, Debug)]
 +pub(crate) enum Expectation {
 +    None,
 +    HasType(Ty),
 +    // Castable(Ty), // rustc has this, we currently just don't propagate an expectation for casts
 +    RValueLikeUnsized(Ty),
 +}
 +
 +impl Expectation {
 +    /// The expectation that the type of the expression needs to equal the given
 +    /// type.
 +    fn has_type(ty: Ty) -> Self {
 +        if ty.is_unknown() {
 +            // FIXME: get rid of this?
 +            Expectation::None
 +        } else {
 +            Expectation::HasType(ty)
 +        }
 +    }
 +
 +    fn from_option(ty: Option<Ty>) -> Self {
 +        ty.map_or(Expectation::None, Expectation::HasType)
 +    }
 +
 +    /// The following explanation is copied straight from rustc:
 +    /// Provides an expectation for an rvalue expression given an *optional*
 +    /// hint, which is not required for type safety (the resulting type might
 +    /// be checked higher up, as is the case with `&expr` and `box expr`), but
 +    /// is useful in determining the concrete type.
 +    ///
 +    /// The primary use case is where the expected type is a fat pointer,
 +    /// like `&[isize]`. For example, consider the following statement:
 +    ///
 +    ///    let x: &[isize] = &[1, 2, 3];
 +    ///
 +    /// In this case, the expected type for the `&[1, 2, 3]` expression is
 +    /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
 +    /// expectation `ExpectHasType([isize])`, that would be too strong --
 +    /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`.
 +    /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced
 +    /// to the type `&[isize]`. Therefore, we propagate this more limited hint,
 +    /// which still is useful, because it informs integer literals and the like.
 +    /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
 +    /// for examples of where this comes up,.
 +    fn rvalue_hint(table: &mut unify::InferenceTable<'_>, ty: Ty) -> Self {
 +        // FIXME: do struct_tail_without_normalization
 +        match table.resolve_ty_shallow(&ty).kind(Interner) {
 +            TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => Expectation::RValueLikeUnsized(ty),
 +            _ => Expectation::has_type(ty),
 +        }
 +    }
 +
 +    /// This expresses no expectation on the type.
 +    fn none() -> Self {
 +        Expectation::None
 +    }
 +
 +    fn resolve(&self, table: &mut unify::InferenceTable<'_>) -> Expectation {
 +        match self {
 +            Expectation::None => Expectation::None,
 +            Expectation::HasType(t) => Expectation::HasType(table.resolve_ty_shallow(t)),
 +            Expectation::RValueLikeUnsized(t) => {
 +                Expectation::RValueLikeUnsized(table.resolve_ty_shallow(t))
 +            }
 +        }
 +    }
 +
 +    fn to_option(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> {
 +        match self.resolve(table) {
 +            Expectation::None => None,
 +            Expectation::HasType(t) |
 +            // Expectation::Castable(t) |
 +            Expectation::RValueLikeUnsized(t) => Some(t),
 +        }
 +    }
 +
 +    fn only_has_type(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> {
 +        match self {
 +            Expectation::HasType(t) => Some(table.resolve_ty_shallow(t)),
 +            // Expectation::Castable(_) |
 +            Expectation::RValueLikeUnsized(_) | Expectation::None => None,
 +        }
 +    }
 +
 +    /// Comment copied from rustc:
 +    /// Disregard "castable to" expectations because they
 +    /// can lead us astray. Consider for example `if cond
 +    /// {22} else {c} as u8` -- if we propagate the
 +    /// "castable to u8" constraint to 22, it will pick the
 +    /// type 22u8, which is overly constrained (c might not
 +    /// be a u8). In effect, the problem is that the
 +    /// "castable to" expectation is not the tightest thing
 +    /// we can say, so we want to drop it in this case.
 +    /// The tightest thing we can say is "must unify with
 +    /// else branch". Note that in the case of a "has type"
 +    /// constraint, this limitation does not hold.
 +    ///
 +    /// If the expected type is just a type variable, then don't use
 +    /// an expected type. Otherwise, we might write parts of the type
 +    /// when checking the 'then' block which are incompatible with the
 +    /// 'else' branch.
 +    fn adjust_for_branches(&self, table: &mut unify::InferenceTable<'_>) -> Expectation {
 +        match self {
 +            Expectation::HasType(ety) => {
 +                let ety = table.resolve_ty_shallow(ety);
 +                if !ety.is_ty_var() {
 +                    Expectation::HasType(ety)
 +                } else {
 +                    Expectation::None
 +                }
 +            }
 +            Expectation::RValueLikeUnsized(ety) => Expectation::RValueLikeUnsized(ety.clone()),
 +            _ => Expectation::None,
 +        }
 +    }
 +}
 +
 +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
 +enum Diverges {
 +    Maybe,
 +    Always,
 +}
 +
 +impl Diverges {
 +    fn is_always(self) -> bool {
 +        self == Diverges::Always
 +    }
 +}
 +
 +impl std::ops::BitAnd for Diverges {
 +    type Output = Self;
 +    fn bitand(self, other: Self) -> Self {
 +        std::cmp::min(self, other)
 +    }
 +}
 +
 +impl std::ops::BitOr for Diverges {
 +    type Output = Self;
 +    fn bitor(self, other: Self) -> Self {
 +        std::cmp::max(self, other)
 +    }
 +}
 +
 +impl std::ops::BitAndAssign for Diverges {
 +    fn bitand_assign(&mut self, other: Self) {
 +        *self = *self & other;
 +    }
 +}
 +
 +impl std::ops::BitOrAssign for Diverges {
 +    fn bitor_assign(&mut self, other: Self) {
 +        *self = *self | other;
 +    }
 +}
index 2a13106390d9f7f90773d1377bdc8b24351ca393,0000000000000000000000000000000000000000..2d04a864a2cfd98455a5d198edaec33cc8303f0b
mode 100644,000000..100644
--- /dev/null
@@@ -1,1478 -1,0 +1,1499 @@@
-     expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Statement, UnaryOp},
 +//! 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::{
-     infer::coerce::CoerceMany,
++    expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, LabelId, Literal, Statement, UnaryOp},
 +    generics::TypeOrConstParamData,
 +    path::{GenericArg, GenericArgs},
 +    resolver::resolver_for_expr,
 +    ConstParamId, FieldId, ItemContainerId, Lookup,
 +};
 +use hir_expand::name::Name;
 +use stdx::always;
 +use syntax::ast::RangeOp;
 +
 +use crate::{
 +    autoderef::{self, Autoderef},
 +    consteval,
-                         self.breakables.push(BreakableContext {
-                             may_break: false,
-                             coerce: CoerceMany::new(break_ty.clone()),
-                             label: label.map(|label| self.body[label].name.clone()),
-                         });
-                         let ty = self.infer_block(
-                             tgt_expr,
-                             statements,
-                             *tail,
-                             &Expectation::has_type(break_ty),
++    infer::{coerce::CoerceMany, find_continuable, BreakableKind},
 +    lower::{
 +        const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
 +    },
 +    mapping::{from_chalk, ToChalk},
 +    method_resolution::{self, lang_names_for_bin_op, VisibleFromModule},
 +    primitive::{self, UintTy},
 +    static_lifetime, to_chalk_trait_id,
 +    utils::{generics, Generics},
 +    AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar,
 +    Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
 +};
 +
 +use super::{
 +    coerce::auto_deref_adjust_steps, find_breakable, BindingMode, BreakableContext, Diverges,
 +    Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch,
 +};
 +
 +impl<'a> InferenceContext<'a> {
 +    pub(crate) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
 +        let ty = self.infer_expr_inner(tgt_expr, expected);
 +        if let Some(expected_ty) = expected.only_has_type(&mut self.table) {
 +            let could_unify = self.unify(&ty, &expected_ty);
 +            if !could_unify {
 +                self.result.type_mismatches.insert(
 +                    tgt_expr.into(),
 +                    TypeMismatch { expected: expected_ty, actual: ty.clone() },
 +                );
 +            }
 +        }
 +        ty
 +    }
 +
 +    /// Infer type of expression with possibly implicit coerce to the expected type.
 +    /// Return the type after possible coercion.
 +    pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
 +        let ty = self.infer_expr_inner(expr, expected);
 +        if let Some(target) = expected.only_has_type(&mut self.table) {
 +            match self.coerce(Some(expr), &ty, &target) {
 +                Ok(res) => res,
 +                Err(_) => {
 +                    self.result.type_mismatches.insert(
 +                        expr.into(),
 +                        TypeMismatch { expected: target.clone(), actual: ty.clone() },
 +                    );
 +                    target
 +                }
 +            }
 +        } else {
 +            ty
 +        }
 +    }
 +
 +    fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
 +        self.db.unwind_if_cancelled();
 +
 +        let ty = match &self.body[tgt_expr] {
 +            Expr::Missing => self.err_ty(),
 +            &Expr::If { condition, then_branch, else_branch } => {
 +                self.infer_expr(
 +                    condition,
 +                    &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
 +                );
 +
 +                let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
 +                let mut both_arms_diverge = Diverges::Always;
 +
 +                let result_ty = self.table.new_type_var();
 +                let then_ty = self.infer_expr_inner(then_branch, expected);
 +                both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe);
 +                let mut coerce = CoerceMany::new(result_ty);
 +                coerce.coerce(self, Some(then_branch), &then_ty);
 +                let else_ty = match else_branch {
 +                    Some(else_branch) => self.infer_expr_inner(else_branch, expected),
 +                    None => TyBuilder::unit(),
 +                };
 +                both_arms_diverge &= self.diverges;
 +                // FIXME: create a synthetic `else {}` so we have something to refer to here instead of None?
 +                coerce.coerce(self, else_branch, &else_ty);
 +
 +                self.diverges = condition_diverges | both_arms_diverge;
 +
 +                coerce.complete()
 +            }
 +            &Expr::Let { pat, expr } => {
 +                let input_ty = self.infer_expr(expr, &Expectation::none());
 +                self.infer_pat(pat, &input_ty, BindingMode::default());
 +                TyKind::Scalar(Scalar::Bool).intern(Interner)
 +            }
 +            Expr::Block { statements, tail, label, id: _ } => {
 +                let old_resolver = mem::replace(
 +                    &mut self.resolver,
 +                    resolver_for_expr(self.db.upcast(), self.owner, tgt_expr),
 +                );
 +                let ty = match label {
 +                    Some(_) => {
 +                        let break_ty = self.table.new_type_var();
-                         let ctxt = self.breakables.pop().expect("breakable stack broken");
-                         if ctxt.may_break {
-                             ctxt.coerce.complete()
-                         } else {
-                             ty
-                         }
++                        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),
++                                )
++                            },
 +                        );
-             Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected),
++                        breaks.unwrap_or(ty)
 +                    }
 +                    None => self.infer_block(tgt_expr, statements, *tail, expected),
 +                };
 +                self.resolver = old_resolver;
 +                ty
 +            }
-                 let _inner = self.infer_expr(*body, expected);
++            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 } => {
-                 let inner_ty = self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
++                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());
 +
-             Expr::Loop { body, label } => {
-                 self.breakables.push(BreakableContext {
-                     may_break: false,
-                     coerce: CoerceMany::new(self.table.new_type_var()),
-                     label: label.map(|label| self.body[label].name.clone()),
-                 });
-                 self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
-                 let ctxt = self.breakables.pop().expect("breakable stack broken");
++                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)
 +            }
-                 if ctxt.may_break {
-                     self.diverges = Diverges::Maybe;
-                     ctxt.coerce.complete()
-                 } else {
-                     TyKind::Never.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()));
++                    });
 +
-             Expr::While { condition, body, label } => {
-                 self.breakables.push(BreakableContext {
-                     may_break: false,
-                     coerce: CoerceMany::new(self.err_ty()),
-                     label: label.map(|label| self.body[label].name.clone()),
++                match breaks {
++                    Some(breaks) => {
++                        self.diverges = Diverges::Maybe;
++                        breaks
++                    }
++                    None => TyKind::Never.intern(Interner),
 +                }
 +            }
-                 self.infer_expr(
-                     *condition,
-                     &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
-                 );
-                 self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
-                 let _ctxt = self.breakables.pop().expect("breakable stack broken");
++            &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()));
 +                });
-             Expr::For { iterable, body, pat, label } => {
-                 let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
-                 self.breakables.push(BreakableContext {
-                     may_break: false,
-                     coerce: CoerceMany::new(self.err_ty()),
-                     label: label.map(|label| self.body[label].name.clone()),
-                 });
++
 +                // the body may not run, so it diverging doesn't mean we diverge
 +                self.diverges = Diverges::Maybe;
 +                TyBuilder::unit()
 +            }
-                 self.infer_pat(*pat, &pat_ty, BindingMode::default());
++            &Expr::For { iterable, body, pat, label } => {
++                let iterable_ty = self.infer_expr(iterable, &Expectation::none());
 +                let pat_ty =
 +                    self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
 +
-                 self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
-                 let _ctxt = self.breakables.pop().expect("breakable stack broken");
++                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()));
++                });
 +
-                 self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
 +                // 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 } => {
 +                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 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);
 +
 +                // 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,
 +                    &closure_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());
 +
-             Expr::Continue { .. } => TyKind::Never.intern(Interner),
-             Expr::Break { expr, label } => {
-                 let mut coerce = match find_breakable(&mut self.breakables, label.as_ref()) {
-                     Some(ctxt) => {
-                         // avoiding the borrowck
-                         mem::replace(
-                             &mut ctxt.coerce,
-                             CoerceMany::new(self.result.standard_types.unknown.clone()),
-                         )
-                     }
-                     None => CoerceMany::new(self.result.standard_types.unknown.clone()),
++                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;
 +
 +                closure_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,
++                    });
 +                };
-                 // FIXME: create a synthetic `()` during lowering so we have something to refer to here?
-                 coerce.coerce(self, *expr, &val_ty);
++                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()
 +                };
 +
-                 if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
-                     ctxt.coerce = coerce;
-                     ctxt.may_break = true;
-                 } else {
-                     self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
-                         expr: tgt_expr,
-                     });
-                 };
++                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()),
++                        );
 +
-             Expr::MacroStmts { tail, statements } => {
-                 self.infer_block(tgt_expr, statements, *tail, expected)
-             }
++                        // 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 } => {
 +                // FIXME: track yield type for coercion
 +                if let Some(expr) = expr {
 +                    self.infer_expr(*expr, &Expectation::none());
 +                }
 +                TyKind::Never.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());
 +                self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok())
 +            }
 +            Expr::Cast { expr, type_ref } => {
 +                // FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary)
 +                let _inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
 +                let cast_ty = self.make_ty(type_ref);
 +                // FIXME check the cast...
 +                cast_ty
 +            }
 +            Expr::Ref { expr, rawness, mutability } => {
 +                let mutability = lower_to_chalk_mutability(*mutability);
 +                let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = expected
 +                    .only_has_type(&mut self.table)
 +                    .as_ref()
 +                    .and_then(|t| t.as_reference_or_ptr())
 +                {
 +                    if exp_mutability == Mutability::Mut && mutability == Mutability::Not {
 +                        // FIXME: record type error - expected mut reference but found shared ref,
 +                        // which cannot be coerced
 +                    }
 +                    if exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr {
 +                        // FIXME: record type error - expected reference but found ptr,
 +                        // which cannot be coerced
 +                    }
 +                    Expectation::rvalue_hint(&mut self.table, Ty::clone(exp_inner))
 +                } else {
 +                    Expectation::none()
 +                };
 +                let inner_ty = self.infer_expr_inner(*expr, &expectation);
 +                match rawness {
 +                    Rawness::RawPtr => TyKind::Raw(mutability, inner_ty),
 +                    Rawness::Ref => TyKind::Ref(mutability, static_lifetime(), inner_ty),
 +                }
 +                .intern(Interner)
 +            }
 +            &Expr::Box { expr } => self.infer_expr_box(expr, expected),
 +            Expr::UnaryOp { expr, op } => {
 +                let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
 +                let inner_ty = self.resolve_ty_shallow(&inner_ty);
 +                match op {
 +                    UnaryOp::Deref => {
 +                        autoderef::deref(&mut self.table, inner_ty).unwrap_or_else(|| self.err_ty())
 +                    }
 +                    UnaryOp::Neg => {
 +                        match inner_ty.kind(Interner) {
 +                            // Fast path for builtins
 +                            TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_))
 +                            | TyKind::InferenceVar(
 +                                _,
 +                                TyVariableKind::Integer | TyVariableKind::Float,
 +                            ) => inner_ty,
 +                            // Otherwise we resolve via the std::ops::Neg trait
 +                            _ => self
 +                                .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()),
 +                        }
 +                    }
 +                    UnaryOp::Not => {
 +                        match inner_ty.kind(Interner) {
 +                            // Fast path for builtins
 +                            TyKind::Scalar(Scalar::Bool | Scalar::Int(_) | Scalar::Uint(_))
 +                            | TyKind::InferenceVar(_, TyVariableKind::Integer) => inner_ty,
 +                            // Otherwise we resolve via the std::ops::Not trait
 +                            _ => self
 +                                .resolve_associated_type(inner_ty, self.resolve_ops_not_output()),
 +                        }
 +                    }
 +                }
 +            }
 +            Expr::BinaryOp { lhs, rhs, op } => match op {
 +                Some(BinaryOp::Assignment { op: None }) => {
 +                    let lhs = *lhs;
 +                    let is_ordinary = match &self.body[lhs] {
 +                        Expr::Array(_)
 +                        | Expr::RecordLit { .. }
 +                        | Expr::Tuple { .. }
 +                        | Expr::Underscore => false,
 +                        Expr::Call { callee, .. } => !matches!(&self.body[*callee], Expr::Path(_)),
 +                        _ => true,
 +                    };
 +
 +                    // In ordinary (non-destructuring) assignments, the type of
 +                    // `lhs` must be inferred first so that the ADT fields
 +                    // instantiations in RHS can be coerced to it. Note that this
 +                    // cannot happen in destructuring assignments because of how
 +                    // they are desugared.
 +                    if is_ordinary {
 +                        let lhs_ty = self.infer_expr(lhs, &Expectation::none());
 +                        self.infer_expr_coerce(*rhs, &Expectation::has_type(lhs_ty));
 +                    } else {
 +                        let rhs_ty = self.infer_expr(*rhs, &Expectation::none());
 +                        self.infer_assignee_expr(lhs, &rhs_ty);
 +                    }
 +                    self.result.standard_types.unit.clone()
 +                }
 +                Some(BinaryOp::LogicOp(_)) => {
 +                    let bool_ty = self.result.standard_types.bool_.clone();
 +                    self.infer_expr_coerce(*lhs, &Expectation::HasType(bool_ty.clone()));
 +                    let lhs_diverges = self.diverges;
 +                    self.infer_expr_coerce(*rhs, &Expectation::HasType(bool_ty.clone()));
 +                    // Depending on the LHS' value, the RHS can never execute.
 +                    self.diverges = lhs_diverges;
 +                    bool_ty
 +                }
 +                Some(op) => self.infer_overloadable_binop(*lhs, *op, *rhs, tgt_expr),
 +                _ => self.err_ty(),
 +            },
 +            Expr::Range { lhs, rhs, range_type } => {
 +                let lhs_ty = lhs.map(|e| self.infer_expr_inner(e, &Expectation::none()));
 +                let rhs_expect = lhs_ty
 +                    .as_ref()
 +                    .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone()));
 +                let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect));
 +                match (range_type, lhs_ty, rhs_ty) {
 +                    (RangeOp::Exclusive, None, None) => match self.resolve_range_full() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Inclusive, None, Some(ty)) => {
 +                        match self.resolve_range_to_inclusive() {
 +                            Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                            None => self.err_ty(),
 +                        }
 +                    }
 +                    (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Inclusive, Some(_), Some(ty)) => {
 +                        match self.resolve_range_inclusive() {
 +                            Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                            None => self.err_ty(),
 +                        }
 +                    }
 +                    (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() {
 +                        Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
 +                        None => self.err_ty(),
 +                    },
 +                    (RangeOp::Inclusive, _, None) => self.err_ty(),
 +                }
 +            }
 +            Expr::Index { base, index } => {
 +                let base_ty = self.infer_expr_inner(*base, &Expectation::none());
 +                let index_ty = self.infer_expr(*index, &Expectation::none());
 +
 +                if let Some(index_trait) = self.resolve_ops_index() {
 +                    let canonicalized = self.canonicalize(base_ty.clone());
 +                    let receiver_adjustments = method_resolution::resolve_indexing_op(
 +                        self.db,
 +                        self.trait_env.clone(),
 +                        canonicalized.value,
 +                        index_trait,
 +                    );
 +                    let (self_ty, adj) = receiver_adjustments
 +                        .map_or((self.err_ty(), Vec::new()), |adj| {
 +                            adj.apply(&mut self.table, base_ty)
 +                        });
 +                    self.write_expr_adj(*base, adj);
 +                    self.resolve_associated_type_with_params(
 +                        self_ty,
 +                        self.resolve_ops_index_output(),
 +                        &[GenericArgData::Ty(index_ty).intern(Interner)],
 +                    )
 +                } else {
 +                    self.err_ty()
 +                }
 +            }
 +            Expr::Tuple { exprs, .. } => {
 +                let mut tys = match expected
 +                    .only_has_type(&mut self.table)
 +                    .as_ref()
 +                    .map(|t| t.kind(Interner))
 +                {
 +                    Some(TyKind::Tuple(_, substs)) => substs
 +                        .iter(Interner)
 +                        .map(|a| a.assert_ty_ref(Interner).clone())
 +                        .chain(repeat_with(|| self.table.new_type_var()))
 +                        .take(exprs.len())
 +                        .collect::<Vec<_>>(),
 +                    _ => (0..exprs.len()).map(|_| self.table.new_type_var()).collect(),
 +                };
 +
 +                for (expr, ty) in exprs.iter().zip(tys.iter_mut()) {
 +                    self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
 +                }
 +
 +                TyKind::Tuple(tys.len(), Substitution::from_iter(Interner, tys)).intern(Interner)
 +            }
 +            Expr::Array(array) => {
 +                let elem_ty =
 +                    match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(Interner)) {
 +                        Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st.clone(),
 +                        _ => self.table.new_type_var(),
 +                    };
 +                let mut coerce = CoerceMany::new(elem_ty.clone());
 +
 +                let expected = Expectation::has_type(elem_ty.clone());
 +                let len = match array {
 +                    Array::ElementList { elements, .. } => {
 +                        for &expr in elements.iter() {
 +                            let cur_elem_ty = self.infer_expr_inner(expr, &expected);
 +                            coerce.coerce(self, Some(expr), &cur_elem_ty);
 +                        }
 +                        consteval::usize_const(Some(elements.len() as u128))
 +                    }
 +                    &Array::Repeat { initializer, repeat } => {
 +                        self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty));
 +                        self.infer_expr(
 +                            repeat,
 +                            &Expectation::has_type(
 +                                TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
 +                            ),
 +                        );
 +
 +                        if let Some(g_def) = self.owner.as_generic_def_id() {
 +                            let generics = generics(self.db.upcast(), g_def);
 +                            consteval::eval_to_const(
 +                                repeat,
 +                                ParamLoweringMode::Placeholder,
 +                                self,
 +                                || generics,
 +                                DebruijnIndex::INNERMOST,
 +                            )
 +                        } else {
 +                            consteval::usize_const(None)
 +                        }
 +                    }
 +                };
 +
 +                TyKind::Array(coerce.complete(), len).intern(Interner)
 +            }
 +            Expr::Literal(lit) => match lit {
 +                Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(Interner),
 +                Literal::String(..) => {
 +                    TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(Interner))
 +                        .intern(Interner)
 +                }
 +                Literal::ByteString(bs) => {
 +                    let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner);
 +
 +                    let len = consteval::usize_const(Some(bs.len() as u128));
 +
 +                    let array_type = TyKind::Array(byte_type, len).intern(Interner);
 +                    TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(Interner)
 +                }
 +                Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(Interner),
 +                Literal::Int(_v, ty) => match ty {
 +                    Some(int_ty) => {
 +                        TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(*int_ty)))
 +                            .intern(Interner)
 +                    }
 +                    None => self.table.new_integer_var(),
 +                },
 +                Literal::Uint(_v, ty) => match ty {
 +                    Some(int_ty) => {
 +                        TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(*int_ty)))
 +                            .intern(Interner)
 +                    }
 +                    None => self.table.new_integer_var(),
 +                },
 +                Literal::Float(_v, ty) => match ty {
 +                    Some(float_ty) => {
 +                        TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(*float_ty)))
 +                            .intern(Interner)
 +                    }
 +                    None => self.table.new_float_var(),
 +                },
 +            },
 +            Expr::Underscore => {
 +                // Underscore expressions may only appear in assignee expressions,
 +                // which are handled by `infer_assignee_expr()`, so any underscore
 +                // expression reaching this branch is an error.
 +                self.err_ty()
 +            }
 +        };
 +        // use a new type variable if we got unknown here
 +        let ty = self.insert_type_vars_shallow(ty);
 +        self.write_expr_ty(tgt_expr, ty.clone());
 +        if self.resolve_ty_shallow(&ty).is_never() {
 +            // Any expression that produces a value of type `!` must have diverged
 +            self.diverges = Diverges::Always;
 +        }
 +        ty
 +    }
 +
 +    fn infer_expr_box(&mut self, inner_expr: ExprId, expected: &Expectation) -> Ty {
 +        if let Some(box_id) = self.resolve_boxed_box() {
 +            let table = &mut self.table;
 +            let inner_exp = expected
 +                .to_option(table)
 +                .as_ref()
 +                .map(|e| e.as_adt())
 +                .flatten()
 +                .filter(|(e_adt, _)| e_adt == &box_id)
 +                .map(|(_, subts)| {
 +                    let g = subts.at(Interner, 0);
 +                    Expectation::rvalue_hint(table, Ty::clone(g.assert_ty_ref(Interner)))
 +                })
 +                .unwrap_or_else(Expectation::none);
 +
 +            let inner_ty = self.infer_expr_inner(inner_expr, &inner_exp);
 +            TyBuilder::adt(self.db, box_id)
 +                .push(inner_ty)
 +                .fill_with_defaults(self.db, || self.table.new_type_var())
 +                .build()
 +        } else {
 +            self.err_ty()
 +        }
 +    }
 +
 +    pub(super) fn infer_assignee_expr(&mut self, lhs: ExprId, rhs_ty: &Ty) -> Ty {
 +        let is_rest_expr = |expr| {
 +            matches!(
 +                &self.body[expr],
 +                Expr::Range { lhs: None, rhs: None, range_type: RangeOp::Exclusive },
 +            )
 +        };
 +
 +        let rhs_ty = self.resolve_ty_shallow(rhs_ty);
 +
 +        let ty = match &self.body[lhs] {
 +            Expr::Tuple { exprs, .. } => {
 +                // We don't consider multiple ellipses. This is analogous to
 +                // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
 +                let ellipsis = exprs.iter().position(|e| is_rest_expr(*e));
 +                let exprs: Vec<_> = exprs.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
 +
 +                self.infer_tuple_pat_like(&rhs_ty, (), ellipsis, &exprs)
 +            }
 +            Expr::Call { callee, args, .. } => {
 +                // Tuple structs
 +                let path = match &self.body[*callee] {
 +                    Expr::Path(path) => Some(path),
 +                    _ => None,
 +                };
 +
 +                // We don't consider multiple ellipses. This is analogous to
 +                // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
 +                let ellipsis = args.iter().position(|e| is_rest_expr(*e));
 +                let args: Vec<_> = args.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
 +
 +                self.infer_tuple_struct_pat_like(path, &rhs_ty, (), lhs, ellipsis, &args)
 +            }
 +            Expr::Array(Array::ElementList { elements, .. }) => {
 +                let elem_ty = match rhs_ty.kind(Interner) {
 +                    TyKind::Array(st, _) => st.clone(),
 +                    _ => self.err_ty(),
 +                };
 +
 +                // There's no need to handle `..` as it cannot be bound.
 +                let sub_exprs = elements.iter().filter(|e| !is_rest_expr(**e));
 +
 +                for e in sub_exprs {
 +                    self.infer_assignee_expr(*e, &elem_ty);
 +                }
 +
 +                match rhs_ty.kind(Interner) {
 +                    TyKind::Array(_, _) => rhs_ty.clone(),
 +                    // Even when `rhs_ty` is not an array type, this assignee
 +                    // expression is inferred to be an array (of unknown element
 +                    // type and length). This should not be just an error type,
 +                    // because we are to compute the unifiability of this type and
 +                    // `rhs_ty` in the end of this function to issue type mismatches.
 +                    _ => TyKind::Array(self.err_ty(), crate::consteval::usize_const(None))
 +                        .intern(Interner),
 +                }
 +            }
 +            Expr::RecordLit { path, fields, .. } => {
 +                let subs = fields.iter().map(|f| (f.name.clone(), f.expr));
 +
 +                self.infer_record_pat_like(path.as_deref(), &rhs_ty, (), lhs.into(), subs)
 +            }
 +            Expr::Underscore => rhs_ty.clone(),
 +            _ => {
 +                // `lhs` is a place expression, a unit struct, or an enum variant.
 +                let lhs_ty = self.infer_expr(lhs, &Expectation::none());
 +
 +                // This is the only branch where this function may coerce any type.
 +                // We are returning early to avoid the unifiability check below.
 +                let lhs_ty = self.insert_type_vars_shallow(lhs_ty);
 +                let ty = match self.coerce(None, &rhs_ty, &lhs_ty) {
 +                    Ok(ty) => ty,
 +                    Err(_) => {
 +                        self.result.type_mismatches.insert(
 +                            lhs.into(),
 +                            TypeMismatch { expected: rhs_ty.clone(), actual: lhs_ty.clone() },
 +                        );
 +                        // `rhs_ty` is returned so no further type mismatches are
 +                        // reported because of this mismatch.
 +                        rhs_ty
 +                    }
 +                };
 +                self.write_expr_ty(lhs, ty.clone());
 +                return ty;
 +            }
 +        };
 +
 +        let ty = self.insert_type_vars_shallow(ty);
 +        if !self.unify(&ty, &rhs_ty) {
 +            self.result
 +                .type_mismatches
 +                .insert(lhs.into(), TypeMismatch { expected: rhs_ty.clone(), actual: ty.clone() });
 +        }
 +        self.write_expr_ty(lhs, ty.clone());
 +        ty
 +    }
 +
 +    fn infer_overloadable_binop(
 +        &mut self,
 +        lhs: ExprId,
 +        op: BinaryOp,
 +        rhs: ExprId,
 +        tgt_expr: ExprId,
 +    ) -> Ty {
 +        let lhs_expectation = Expectation::none();
 +        let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
 +        let rhs_ty = self.table.new_type_var();
 +
 +        let func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
 +            self.db.trait_data(self.resolve_lang_item(lang_item)?.as_trait()?).method_by_name(&name)
 +        });
 +        let func = match func {
 +            Some(func) => func,
 +            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());
 +            }
 +        };
 +
 +        let subst = TyBuilder::subst_for_def(self.db, func)
 +            .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);
 +        // Parent arguments are unknown
 +        for (id, param) in def_generics.iter_parent() {
 +            match param {
 +                TypeOrConstParamData::TypeParamData(_) => {
 +                    substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner));
 +                }
 +                TypeOrConstParamData::ConstParamData(_) => {
 +                    let ty = self.db.const_param_ty(ConstParamId::from_unchecked(id));
 +                    substs
 +                        .push(GenericArgData::Const(self.table.new_const_var(ty)).intern(Interner));
 +                }
 +            }
 +        }
 +        // 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().skip(parent_params))
 +            {
 +                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);
 +                }
 +            }
 +        };
 +        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 substs = crate::subst_prefix(
 +                            &*parameters,
 +                            generics(self.db.upcast(), trait_.into()).len(),
 +                        );
 +                        self.push_obligation(
 +                            TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
 +                                .cast(Interner),
 +                        );
 +                    }
 +                }
 +                CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {}
 +            }
 +        }
 +    }
 +
 +    /// Returns the argument indices to skip.
 +    fn check_legacy_const_generics(&mut self, callee: Ty, args: &[ExprId]) -> Box<[u32]> {
 +        let (func, subst) = match callee.kind(Interner) {
 +            TyKind::FnDef(fn_id, subst) => {
 +                let callable = CallableDefId::from_chalk(self.db, *fn_id);
 +                let func = match callable {
 +                    CallableDefId::FunctionId(f) => f,
 +                    _ => return Default::default(),
 +                };
 +                (func, subst)
 +            }
 +            _ => return Default::default(),
 +        };
 +
 +        let data = self.db.function_data(func);
 +        if data.legacy_const_generics_indices.is_empty() {
 +            return Default::default();
 +        }
 +
 +        // only use legacy const generics if the param count matches with them
 +        if data.params.len() + data.legacy_const_generics_indices.len() != args.len() {
 +            if args.len() <= data.params.len() {
 +                return Default::default();
 +            } else {
 +                // there are more parameters than there should be without legacy
 +                // const params; use them
 +                let mut indices = data.legacy_const_generics_indices.clone();
 +                indices.sort();
 +                return indices;
 +            }
 +        }
 +
 +        // check legacy const parameters
 +        for (subst_idx, arg_idx) in data.legacy_const_generics_indices.iter().copied().enumerate() {
 +            let arg = match subst.at(Interner, subst_idx).constant(Interner) {
 +                Some(c) => c,
 +                None => continue, // not a const parameter?
 +            };
 +            if arg_idx >= args.len() as u32 {
 +                continue;
 +            }
 +            let _ty = arg.data(Interner).ty.clone();
 +            let expected = Expectation::none(); // FIXME use actual const ty, when that is lowered correctly
 +            self.infer_expr(args[arg_idx as usize], &expected);
 +            // FIXME: evaluate and unify with the const
 +        }
 +        let mut indices = data.legacy_const_generics_indices.clone();
 +        indices.sort();
 +        indices
 +    }
 +
 +    fn builtin_binary_op_return_ty(&mut self, op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Option<Ty> {
 +        let lhs_ty = self.resolve_ty_shallow(&lhs_ty);
 +        let rhs_ty = self.resolve_ty_shallow(&rhs_ty);
 +        match op {
 +            BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => {
 +                Some(TyKind::Scalar(Scalar::Bool).intern(Interner))
 +            }
 +            BinaryOp::Assignment { .. } => Some(TyBuilder::unit()),
 +            BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => {
 +                // all integer combinations are valid here
 +                if matches!(
 +                    lhs_ty.kind(Interner),
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
 +                        | TyKind::InferenceVar(_, TyVariableKind::Integer)
 +                ) && matches!(
 +                    rhs_ty.kind(Interner),
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
 +                        | TyKind::InferenceVar(_, TyVariableKind::Integer)
 +                ) {
 +                    Some(lhs_ty)
 +                } else {
 +                    None
 +                }
 +            }
 +            BinaryOp::ArithOp(_) => match (lhs_ty.kind(Interner), rhs_ty.kind(Interner)) {
 +                // (int, int) | (uint, uint) | (float, float)
 +                (TyKind::Scalar(Scalar::Int(_)), TyKind::Scalar(Scalar::Int(_)))
 +                | (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_)))
 +                | (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => {
 +                    Some(rhs_ty)
 +                }
 +                // ({int}, int) | ({int}, uint)
 +                (
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
 +                ) => Some(rhs_ty),
 +                // (int, {int}) | (uint, {int})
 +                (
 +                    TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                ) => Some(lhs_ty),
 +                // ({float} | float)
 +                (
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                    TyKind::Scalar(Scalar::Float(_)),
 +                ) => Some(rhs_ty),
 +                // (float, {float})
 +                (
 +                    TyKind::Scalar(Scalar::Float(_)),
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                ) => Some(lhs_ty),
 +                // ({int}, {int}) | ({float}, {float})
 +                (
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                    TyKind::InferenceVar(_, TyVariableKind::Integer),
 +                )
 +                | (
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                    TyKind::InferenceVar(_, TyVariableKind::Float),
 +                ) => Some(rhs_ty),
 +                _ => None,
 +            },
 +        }
 +    }
 +
 +    fn builtin_binary_op_rhs_expectation(&mut self, op: BinaryOp, lhs_ty: Ty) -> Option<Ty> {
 +        Some(match op {
 +            BinaryOp::LogicOp(..) => TyKind::Scalar(Scalar::Bool).intern(Interner),
 +            BinaryOp::Assignment { op: None } => lhs_ty,
 +            BinaryOp::CmpOp(CmpOp::Eq { .. }) => match self
 +                .resolve_ty_shallow(&lhs_ty)
 +                .kind(Interner)
 +            {
 +                TyKind::Scalar(_) | TyKind::Str => lhs_ty,
 +                TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
 +                _ => return None,
 +            },
 +            BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => return None,
 +            BinaryOp::CmpOp(CmpOp::Ord { .. })
 +            | BinaryOp::Assignment { op: Some(_) }
 +            | BinaryOp::ArithOp(_) => match self.resolve_ty_shallow(&lhs_ty).kind(Interner) {
 +                TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_)) => lhs_ty,
 +                TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
 +                _ => return None,
 +            },
 +        })
 +    }
++
++    fn with_breakable_ctx<T>(
++        &mut self,
++        kind: BreakableKind,
++        ty: Ty,
++        label: Option<LabelId>,
++        cb: impl FnOnce(&mut Self) -> T,
++    ) -> (Option<Ty>, T) {
++        self.breakables.push({
++            let label = label.map(|label| self.body[label].name.clone());
++            BreakableContext { kind, may_break: false, coerce: CoerceMany::new(ty), label }
++        });
++        let res = cb(self);
++        let ctx = self.breakables.pop().expect("breakable stack broken");
++        (ctx.may_break.then(|| ctx.coerce.complete()), res)
++    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0c547192ac0d0dd81b87ac0339d655f29eaeaa5a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,173 @@@
++//! Type inhabitedness logic.
++use std::ops::ControlFlow::{self, Break, Continue};
++
++use chalk_ir::{
++    visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
++    DebruijnIndex,
++};
++use hir_def::{
++    adt::VariantData, attr::Attrs, type_ref::ConstScalar, visibility::Visibility, AdtId,
++    EnumVariantId, HasModule, Lookup, ModuleId, VariantId,
++};
++
++use crate::{
++    db::HirDatabase, Binders, ConcreteConst, Const, ConstValue, Interner, Substitution, Ty, TyKind,
++};
++
++/// Checks whether a type is visibly uninhabited from a particular module.
++pub(crate) fn is_ty_uninhabited_from(ty: &Ty, target_mod: ModuleId, db: &dyn HirDatabase) -> bool {
++    let mut uninhabited_from = UninhabitedFrom { target_mod, db };
++    let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST);
++    inhabitedness == BREAK_VISIBLY_UNINHABITED
++}
++
++/// Checks whether a variant is visibly uninhabited from a particular module.
++pub(crate) fn is_enum_variant_uninhabited_from(
++    variant: EnumVariantId,
++    subst: &Substitution,
++    target_mod: ModuleId,
++    db: &dyn HirDatabase,
++) -> bool {
++    let enum_data = db.enum_data(variant.parent);
++    let vars_attrs = db.variants_attrs(variant.parent);
++    let is_local = variant.parent.lookup(db.upcast()).container.krate() == target_mod.krate();
++
++    let mut uninhabited_from = UninhabitedFrom { target_mod, db };
++    let inhabitedness = uninhabited_from.visit_variant(
++        variant.into(),
++        &enum_data.variants[variant.local_id].variant_data,
++        subst,
++        &vars_attrs[variant.local_id],
++        is_local,
++    );
++    inhabitedness == BREAK_VISIBLY_UNINHABITED
++}
++
++struct UninhabitedFrom<'a> {
++    target_mod: ModuleId,
++    db: &'a dyn HirDatabase,
++}
++
++const CONTINUE_OPAQUELY_INHABITED: ControlFlow<VisiblyUninhabited> = Continue(());
++const BREAK_VISIBLY_UNINHABITED: ControlFlow<VisiblyUninhabited> = Break(VisiblyUninhabited);
++#[derive(PartialEq, Eq)]
++struct VisiblyUninhabited;
++
++impl TypeVisitor<Interner> for UninhabitedFrom<'_> {
++    type BreakTy = VisiblyUninhabited;
++
++    fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = VisiblyUninhabited> {
++        self
++    }
++
++    fn visit_ty(
++        &mut self,
++        ty: &Ty,
++        outer_binder: DebruijnIndex,
++    ) -> ControlFlow<VisiblyUninhabited> {
++        match ty.kind(Interner) {
++            TyKind::Adt(adt, subst) => self.visit_adt(adt.0, subst),
++            TyKind::Never => BREAK_VISIBLY_UNINHABITED,
++            TyKind::Tuple(..) => ty.super_visit_with(self, outer_binder),
++            TyKind::Array(item_ty, len) => match try_usize_const(len) {
++                Some(0) | None => CONTINUE_OPAQUELY_INHABITED,
++                Some(1..) => item_ty.super_visit_with(self, outer_binder),
++            },
++
++            TyKind::Ref(..) | _ => CONTINUE_OPAQUELY_INHABITED,
++        }
++    }
++
++    fn interner(&self) -> Interner {
++        Interner
++    }
++}
++
++impl UninhabitedFrom<'_> {
++    fn visit_adt(&mut self, adt: AdtId, subst: &Substitution) -> ControlFlow<VisiblyUninhabited> {
++        let attrs = self.db.attrs(adt.into());
++        let adt_non_exhaustive = attrs.by_key("non_exhaustive").exists();
++        let is_local = adt.module(self.db.upcast()).krate() == self.target_mod.krate();
++        if adt_non_exhaustive && !is_local {
++            return CONTINUE_OPAQUELY_INHABITED;
++        }
++
++        // An ADT is uninhabited iff all its variants uninhabited.
++        match adt {
++            // rustc: For now, `union`s are never considered uninhabited.
++            AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED,
++            AdtId::StructId(s) => {
++                let struct_data = self.db.struct_data(s);
++                self.visit_variant(s.into(), &struct_data.variant_data, subst, &attrs, is_local)
++            }
++            AdtId::EnumId(e) => {
++                let vars_attrs = self.db.variants_attrs(e);
++                let enum_data = self.db.enum_data(e);
++
++                for (local_id, enum_var) in enum_data.variants.iter() {
++                    let variant_inhabitedness = self.visit_variant(
++                        EnumVariantId { parent: e, local_id }.into(),
++                        &enum_var.variant_data,
++                        subst,
++                        &vars_attrs[local_id],
++                        is_local,
++                    );
++                    match variant_inhabitedness {
++                        Break(VisiblyUninhabited) => continue,
++                        Continue(()) => return CONTINUE_OPAQUELY_INHABITED,
++                    }
++                }
++                BREAK_VISIBLY_UNINHABITED
++            }
++        }
++    }
++
++    fn visit_variant(
++        &mut self,
++        variant: VariantId,
++        variant_data: &VariantData,
++        subst: &Substitution,
++        attrs: &Attrs,
++        is_local: bool,
++    ) -> ControlFlow<VisiblyUninhabited> {
++        let non_exhaustive_field_list = attrs.by_key("non_exhaustive").exists();
++        if non_exhaustive_field_list && !is_local {
++            return CONTINUE_OPAQUELY_INHABITED;
++        }
++
++        let is_enum = matches!(variant, VariantId::EnumVariantId(..));
++        let field_tys = self.db.field_types(variant);
++        let field_vis = self.db.field_visibilities(variant);
++
++        for (fid, _) in variant_data.fields().iter() {
++            self.visit_field(field_vis[fid], &field_tys[fid], subst, is_enum)?;
++        }
++        CONTINUE_OPAQUELY_INHABITED
++    }
++
++    fn visit_field(
++        &mut self,
++        vis: Visibility,
++        ty: &Binders<Ty>,
++        subst: &Substitution,
++        is_enum: bool,
++    ) -> ControlFlow<VisiblyUninhabited> {
++        if is_enum || vis.is_visible_from(self.db.upcast(), self.target_mod) {
++            let ty = ty.clone().substitute(Interner, subst);
++            ty.visit_with(self, DebruijnIndex::INNERMOST)
++        } else {
++            CONTINUE_OPAQUELY_INHABITED
++        }
++    }
++}
++
++fn try_usize_const(c: &Const) -> Option<u128> {
++    let data = &c.data(Interner);
++    if data.ty.kind(Interner) != &TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)) {
++        return None;
++    }
++    match data.value {
++        ConstValue::Concrete(ConcreteConst { interned: ConstScalar::UInt(value) }) => Some(value),
++        _ => None,
++    }
++}
index 5a5d610e360ffba3d4318288faa1b4422987a929,0000000000000000000000000000000000000000..a82a331d4b8750e99c5fb8f69b6b04cf8007e96e
mode 100644,000000..100644
--- /dev/null
@@@ -1,525 -1,0 +1,526 @@@
 +//! 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
 +pub fn make_canonical<T: HasInterner<Interner = Interner>>(
 +    value: T,
 +    kinds: impl IntoIterator<Item = TyVariableKind>,
 +) -> Canonical<T> {
 +    let kinds = kinds.into_iter().map(|tk| {
 +        chalk_ir::CanonicalVarKind::new(
 +            chalk_ir::VariableKind::Ty(tk),
 +            chalk_ir::UniverseIndex::ROOT,
 +        )
 +    });
 +    Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
 +}
 +
 +// 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 {
 +    fn fold_with<E>(
 +        self,
 +        folder: &mut dyn chalk_ir::fold::TypeFolder<Interner, Error = E>,
 +        outer_binder: DebruijnIndex,
 +    ) -> Result<Self, E> {
 +        let vec = self.params_and_return.to_vec();
 +        let folded = vec.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 {
 +    use chalk_ir::{fold::TypeFolder, Fallible};
 +    struct FreeVarFolder<F1, F2>(F1, F2);
 +    impl<
 +            'i,
 +            F1: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i,
 +            F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const + 'i,
 +        > TypeFolder<Interner> for FreeVarFolder<F1, F2>
 +    {
 +        type Error = NoSolution;
 +
 +        fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
 +            self
 +        }
 +
 +        fn interner(&self) -> Interner {
 +            Interner
 +        }
 +
 +        fn fold_free_var_ty(
 +            &mut self,
 +            bound_var: BoundVar,
 +            outer_binder: DebruijnIndex,
 +        ) -> Fallible<Ty> {
 +            Ok(self.0(bound_var, outer_binder))
 +        }
 +
 +        fn fold_free_var_const(
 +            &mut self,
 +            ty: Ty,
 +            bound_var: BoundVar,
 +            outer_binder: DebruijnIndex,
 +        ) -> Fallible<Const> {
 +            Ok(self.1(ty, bound_var, outer_binder))
 +        }
 +    }
 +    t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST)
 +        .expect("fold failed unexpectedly")
 +}
 +
 +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 {
 +    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>
 +    {
 +        type Error = NoSolution;
 +
 +        fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
 +            self
 +        }
 +
 +        fn interner(&self) -> Interner {
 +            Interner
 +        }
 +
 +        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 fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Fallible<Const> {
 +            Ok(self.0(Either::Right(c), outer_binder).right().unwrap())
 +        }
 +    }
 +    t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
 +}
 +
 +/// '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::{
 +        fold::{TypeFolder, TypeSuperFoldable},
 +        Fallible,
 +    };
 +    struct ErrorReplacer {
 +        vars: usize,
 +    }
 +    impl TypeFolder<Interner> for ErrorReplacer {
 +        type Error = NoSolution;
 +
 +        fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
 +            self
 +        }
 +
 +        fn interner(&self) -> Interner {
 +            Interner
 +        }
 +
 +        fn 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 {
 +                let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
 +                Ok(ty)
 +            }
 +        }
 +
 +        fn 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_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_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_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_inference_lifetime(
 +            &mut self,
 +            _var: InferenceVar,
 +            _outer_binder: DebruijnIndex,
 +        ) -> Fallible<Lifetime> {
 +            if cfg!(debug_assertions) {
 +                Err(NoSolution)
 +            } else {
 +                Ok(static_lifetime())
 +            }
 +        }
 +
 +        fn 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().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 3f6d0844e9c1f27afc10ece6dde6b3414c169937,0000000000000000000000000000000000000000..4a37a7945330cc2a216a3eb6582ca7bbd0db0287
mode 100644,000000..100644
--- /dev/null
@@@ -1,1774 -1,0 +1,1813 @@@
- //!    type: The entry point for this is `Ty::from_hir`.
- //!  - Building the type for an item: This happens through the `type_for_def` query.
 +//! Methods for lowering the HIR to types. There are two main cases here:
 +//!
 +//!  - Lowering a type reference like `&usize` or `Option<foo::bar::Baz>` to a
-     mapping::ToChalk,
++//!    type: The entry point for this is `TyLoweringContext::lower_ty`.
++//!  - Building the type for an item: This happens through the `ty` query.
 +//!
 +//! This usually involves resolving names, collecting generic arguments etc.
 +use std::{
 +    cell::{Cell, RefCell, RefMut},
 +    iter,
 +    sync::Arc,
 +};
 +
 +use base_db::CrateId;
 +use chalk_ir::{
 +    cast::Cast, fold::Shift, fold::TypeFoldable, interner::HasInterner, Mutability, Safety,
 +};
 +
 +use hir_def::{
 +    adt::StructKind,
 +    body::{Expander, LowerCtx},
 +    builtin_type::BuiltinType,
 +    generics::{
 +        TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
 +    },
 +    intern::Interned,
 +    lang_item::lang_attr,
 +    path::{GenericArg, ModPath, Path, PathKind, PathSegment, PathSegments},
 +    resolver::{HasResolver, Resolver, TypeNs},
 +    type_ref::{
 +        ConstScalarOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
 +    },
 +    AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
 +    HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
 +    TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId,
 +};
 +use hir_expand::{name::Name, ExpandResult};
 +use itertools::Either;
 +use la_arena::ArenaMap;
 +use rustc_hash::FxHashSet;
 +use smallvec::SmallVec;
 +use stdx::{impl_from, never};
 +use syntax::{ast, SmolStr};
 +
 +use crate::{
 +    all_super_traits,
 +    consteval::{intern_const_scalar, path_to_const, unknown_const, unknown_const_as_generic},
 +    db::HirDatabase,
 +    make_binders,
-                         _ => None,
++    mapping::{from_chalk_trait_id, ToChalk},
 +    static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
 +    utils::Generics,
 +    utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics},
 +    AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DynTy, FnPointer,
 +    FnSig, FnSubst, GenericArgData, ImplTraitId, Interner, ParamKind, PolyFnSig, ProjectionTy,
 +    QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits,
 +    Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
 +};
 +
 +#[derive(Debug)]
 +pub struct TyLoweringContext<'a> {
 +    pub db: &'a dyn HirDatabase,
 +    pub resolver: &'a Resolver,
 +    in_binders: DebruijnIndex,
 +    /// Note: Conceptually, it's thinkable that we could be in a location where
 +    /// some type params should be represented as placeholders, and others
 +    /// should be converted to variables. I think in practice, this isn't
 +    /// possible currently, so this should be fine for now.
 +    pub type_param_mode: ParamLoweringMode,
 +    pub impl_trait_mode: ImplTraitLoweringMode,
 +    impl_trait_counter: Cell<u16>,
 +    /// When turning `impl Trait` into opaque types, we have to collect the
 +    /// bounds at the same time to get the IDs correct (without becoming too
 +    /// complicated). I don't like using interior mutability (as for the
 +    /// counter), but I've tried and failed to make the lifetimes work for
 +    /// passing around a `&mut TyLoweringContext`. The core problem is that
 +    /// we're grouping the mutable data (the counter and this field) together
 +    /// with the immutable context (the references to the DB and resolver).
 +    /// Splitting this up would be a possible fix.
 +    opaque_type_data: RefCell<Vec<ReturnTypeImplTrait>>,
 +    expander: RefCell<Option<Expander>>,
 +    /// Tracks types with explicit `?Sized` bounds.
 +    pub(crate) unsized_types: RefCell<FxHashSet<Ty>>,
 +}
 +
 +impl<'a> TyLoweringContext<'a> {
 +    pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self {
 +        let impl_trait_counter = Cell::new(0);
 +        let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
 +        let type_param_mode = ParamLoweringMode::Placeholder;
 +        let in_binders = DebruijnIndex::INNERMOST;
 +        let opaque_type_data = RefCell::new(Vec::new());
 +        Self {
 +            db,
 +            resolver,
 +            in_binders,
 +            impl_trait_mode,
 +            impl_trait_counter,
 +            type_param_mode,
 +            opaque_type_data,
 +            expander: RefCell::new(None),
 +            unsized_types: RefCell::default(),
 +        }
 +    }
 +
 +    pub fn with_debruijn<T>(
 +        &self,
 +        debruijn: DebruijnIndex,
 +        f: impl FnOnce(&TyLoweringContext<'_>) -> T,
 +    ) -> T {
 +        let opaque_ty_data_vec = self.opaque_type_data.take();
 +        let expander = self.expander.take();
 +        let unsized_types = self.unsized_types.take();
 +        let new_ctx = Self {
 +            in_binders: debruijn,
 +            impl_trait_counter: Cell::new(self.impl_trait_counter.get()),
 +            opaque_type_data: RefCell::new(opaque_ty_data_vec),
 +            expander: RefCell::new(expander),
 +            unsized_types: RefCell::new(unsized_types),
 +            ..*self
 +        };
 +        let result = f(&new_ctx);
 +        self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
 +        self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner());
 +        self.expander.replace(new_ctx.expander.into_inner());
 +        self.unsized_types.replace(new_ctx.unsized_types.into_inner());
 +        result
 +    }
 +
 +    pub fn with_shifted_in<T>(
 +        &self,
 +        debruijn: DebruijnIndex,
 +        f: impl FnOnce(&TyLoweringContext<'_>) -> T,
 +    ) -> T {
 +        self.with_debruijn(self.in_binders.shifted_in_from(debruijn), f)
 +    }
 +
 +    pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
 +        Self { impl_trait_mode, ..self }
 +    }
 +
 +    pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self {
 +        Self { type_param_mode, ..self }
 +    }
 +}
 +
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +pub enum ImplTraitLoweringMode {
 +    /// `impl Trait` gets lowered into an opaque type that doesn't unify with
 +    /// anything except itself. This is used in places where values flow 'out',
 +    /// i.e. for arguments of the function we're currently checking, and return
 +    /// types of functions we're calling.
 +    Opaque,
 +    /// `impl Trait` gets lowered into a type variable. Used for argument
 +    /// position impl Trait when inside the respective function, since it allows
 +    /// us to support that without Chalk.
 +    Param,
 +    /// `impl Trait` gets lowered into a variable that can unify with some
 +    /// type. This is used in places where values flow 'in', i.e. for arguments
 +    /// of functions we're calling, and the return type of the function we're
 +    /// currently checking.
 +    Variable,
 +    /// `impl Trait` is disallowed and will be an error.
 +    Disallowed,
 +}
 +
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +pub enum ParamLoweringMode {
 +    Placeholder,
 +    Variable,
 +}
 +
 +impl<'a> TyLoweringContext<'a> {
 +    pub fn lower_ty(&self, type_ref: &TypeRef) -> Ty {
 +        self.lower_ty_ext(type_ref).0
 +    }
 +
 +    fn generics(&self) -> Generics {
 +        generics(
 +            self.db.upcast(),
 +            self.resolver
 +                .generic_def()
 +                .expect("there should be generics if there's a generic param"),
 +        )
 +    }
 +
 +    pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
 +        let mut res = None;
 +        let ty = match type_ref {
 +            TypeRef::Never => TyKind::Never.intern(Interner),
 +            TypeRef::Tuple(inner) => {
 +                let inner_tys = inner.iter().map(|tr| self.lower_ty(tr));
 +                TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
 +                    .intern(Interner)
 +            }
 +            TypeRef::Path(path) => {
 +                let (ty, res_) = self.lower_path(path);
 +                res = res_;
 +                ty
 +            }
 +            TypeRef::RawPtr(inner, mutability) => {
 +                let inner_ty = self.lower_ty(inner);
 +                TyKind::Raw(lower_to_chalk_mutability(*mutability), inner_ty).intern(Interner)
 +            }
 +            TypeRef::Array(inner, len) => {
 +                let inner_ty = self.lower_ty(inner);
 +                let const_len = const_or_path_to_chalk(
 +                    self.db,
 +                    self.resolver,
 +                    TyBuilder::usize(),
 +                    len,
 +                    self.type_param_mode,
 +                    || self.generics(),
 +                    self.in_binders,
 +                );
 +
 +                TyKind::Array(inner_ty, const_len).intern(Interner)
 +            }
 +            TypeRef::Slice(inner) => {
 +                let inner_ty = self.lower_ty(inner);
 +                TyKind::Slice(inner_ty).intern(Interner)
 +            }
 +            TypeRef::Reference(inner, _, mutability) => {
 +                let inner_ty = self.lower_ty(inner);
 +                let lifetime = static_lifetime();
 +                TyKind::Ref(lower_to_chalk_mutability(*mutability), lifetime, inner_ty)
 +                    .intern(Interner)
 +            }
 +            TypeRef::Placeholder => TyKind::Error.intern(Interner),
 +            TypeRef::Fn(params, is_varargs) => {
 +                let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
 +                    Substitution::from_iter(Interner, params.iter().map(|(_, tr)| ctx.lower_ty(tr)))
 +                });
 +                TyKind::Function(FnPointer {
 +                    num_binders: 0, // FIXME lower `for<'a> fn()` correctly
 +                    sig: FnSig { abi: (), safety: Safety::Safe, variadic: *is_varargs },
 +                    substitution: FnSubst(substs),
 +                })
 +                .intern(Interner)
 +            }
 +            TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds),
 +            TypeRef::ImplTrait(bounds) => {
 +                match self.impl_trait_mode {
 +                    ImplTraitLoweringMode::Opaque => {
 +                        let idx = self.impl_trait_counter.get();
 +                        self.impl_trait_counter.set(idx + 1);
 +                        let func = match self.resolver.generic_def() {
 +                            Some(GenericDefId::FunctionId(f)) => f,
 +                            _ => panic!("opaque impl trait lowering in non-function"),
 +                        };
 +
 +                        assert!(idx as usize == self.opaque_type_data.borrow().len());
 +                        // this dance is to make sure the data is in the right
 +                        // place even if we encounter more opaque types while
 +                        // lowering the bounds
 +                        self.opaque_type_data.borrow_mut().push(ReturnTypeImplTrait {
 +                            bounds: crate::make_single_type_binders(Vec::new()),
 +                        });
 +                        // We don't want to lower the bounds inside the binders
 +                        // we're currently in, because they don't end up inside
 +                        // those binders. E.g. when we have `impl Trait<impl
 +                        // OtherTrait<T>>`, the `impl OtherTrait<T>` can't refer
 +                        // to the self parameter from `impl Trait`, and the
 +                        // bounds aren't actually stored nested within each
 +                        // other, but separately. So if the `T` refers to a type
 +                        // parameter of the outer function, it's just one binder
 +                        // away instead of two.
 +                        let actual_opaque_type_data = self
 +                            .with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
 +                                ctx.lower_impl_trait(bounds, func)
 +                            });
 +                        self.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data;
 +
 +                        let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx);
 +                        let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
 +                        let generics = generics(self.db.upcast(), func.into());
 +                        let parameters = generics.bound_vars_subst(self.db, self.in_binders);
 +                        TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner)
 +                    }
 +                    ImplTraitLoweringMode::Param => {
 +                        let idx = self.impl_trait_counter.get();
 +                        // FIXME we're probably doing something wrong here
 +                        self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
 +                        if let Some(def) = self.resolver.generic_def() {
 +                            let generics = generics(self.db.upcast(), def);
 +                            let param = generics
 +                                .iter()
 +                                .filter(|(_, data)| {
 +                                    matches!(
 +                                        data,
 +                                        TypeOrConstParamData::TypeParamData(data)
 +                                        if data.provenance == TypeParamProvenance::ArgumentImplTrait
 +                                    )
 +                                })
 +                                .nth(idx as usize)
 +                                .map_or(TyKind::Error, |(id, _)| {
 +                                    TyKind::Placeholder(to_placeholder_idx(self.db, id))
 +                                });
 +                            param.intern(Interner)
 +                        } else {
 +                            TyKind::Error.intern(Interner)
 +                        }
 +                    }
 +                    ImplTraitLoweringMode::Variable => {
 +                        let idx = self.impl_trait_counter.get();
 +                        // FIXME we're probably doing something wrong here
 +                        self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
 +                        let (
 +                            parent_params,
 +                            self_params,
 +                            list_params,
 +                            const_params,
 +                            _impl_trait_params,
 +                        ) = if let Some(def) = self.resolver.generic_def() {
 +                            let generics = generics(self.db.upcast(), def);
 +                            generics.provenance_split()
 +                        } else {
 +                            (0, 0, 0, 0, 0)
 +                        };
 +                        TyKind::BoundVar(BoundVar::new(
 +                            self.in_binders,
 +                            idx as usize + parent_params + self_params + list_params + const_params,
 +                        ))
 +                        .intern(Interner)
 +                    }
 +                    ImplTraitLoweringMode::Disallowed => {
 +                        // FIXME: report error
 +                        TyKind::Error.intern(Interner)
 +                    }
 +                }
 +            }
 +            TypeRef::Macro(macro_call) => {
 +                let (mut expander, recursion_start) = {
 +                    match RefMut::filter_map(self.expander.borrow_mut(), Option::as_mut) {
++                        // There already is an expander here, this means we are already recursing
 +                        Ok(expander) => (expander, false),
++                        // No expander was created yet, so we are at the start of the expansion recursion
++                        // and therefore have to create an expander.
 +                        Err(expander) => (
 +                            RefMut::map(expander, |it| {
 +                                it.insert(Expander::new(
 +                                    self.db.upcast(),
 +                                    macro_call.file_id,
 +                                    self.resolver.module(),
 +                                ))
 +                            }),
 +                            true,
 +                        ),
 +                    }
 +                };
 +                let ty = {
 +                    let macro_call = macro_call.to_node(self.db.upcast());
 +                    match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call) {
 +                        Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
 +                            let ctx = LowerCtx::new(self.db.upcast(), expander.current_file_id());
 +                            let type_ref = TypeRef::from_ast(&ctx, expanded);
 +
 +                            drop(expander);
 +                            let ty = self.lower_ty(&type_ref);
 +
 +                            self.expander
 +                                .borrow_mut()
 +                                .as_mut()
 +                                .unwrap()
 +                                .exit(self.db.upcast(), mark);
 +                            Some(ty)
 +                        }
-             QuantifiedWhereClauses::from_iter(
++                        _ => {
++                            drop(expander);
++                            None
++                        }
 +                    }
 +                };
++
++                // drop the expander, resetting it to pre-recursion state
 +                if recursion_start {
 +                    *self.expander.borrow_mut() = None;
 +                }
 +                ty.unwrap_or_else(|| TyKind::Error.intern(Interner))
 +            }
 +            TypeRef::Error => TyKind::Error.intern(Interner),
 +        };
 +        (ty, res)
 +    }
 +
 +    /// This is only for `generic_predicates_for_param`, where we can't just
 +    /// lower the self types of the predicates since that could lead to cycles.
 +    /// So we just check here if the `type_ref` resolves to a generic param, and which.
 +    fn lower_ty_only_param(&self, type_ref: &TypeRef) -> Option<TypeOrConstParamId> {
 +        let path = match type_ref {
 +            TypeRef::Path(path) => path,
 +            _ => return None,
 +        };
 +        if path.type_anchor().is_some() {
 +            return None;
 +        }
 +        if path.segments().len() > 1 {
 +            return None;
 +        }
 +        let resolution =
 +            match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
 +                Some((it, None)) => it,
 +                _ => return None,
 +            };
 +        match resolution {
 +            TypeNs::GenericParam(param_id) => Some(param_id.into()),
 +            _ => None,
 +        }
 +    }
 +
 +    pub(crate) fn lower_ty_relative_path(
 +        &self,
 +        ty: Ty,
 +        // We need the original resolution to lower `Self::AssocTy` correctly
 +        res: Option<TypeNs>,
 +        remaining_segments: PathSegments<'_>,
 +    ) -> (Ty, Option<TypeNs>) {
 +        match remaining_segments.len() {
 +            0 => (ty, res),
 +            1 => {
 +                // resolve unselected assoc types
 +                let segment = remaining_segments.first().unwrap();
 +                (self.select_associated_type(res, segment), None)
 +            }
 +            _ => {
 +                // FIXME report error (ambiguous associated type)
 +                (TyKind::Error.intern(Interner), None)
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn lower_partly_resolved_path(
 +        &self,
 +        resolution: TypeNs,
 +        resolved_segment: PathSegment<'_>,
 +        remaining_segments: PathSegments<'_>,
 +        infer_args: bool,
 +    ) -> (Ty, Option<TypeNs>) {
 +        let ty = match resolution {
 +            TypeNs::TraitId(trait_) => {
 +                let ty = match remaining_segments.len() {
 +                    1 => {
 +                        let trait_ref =
 +                            self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None);
 +                        let segment = remaining_segments.first().unwrap();
 +                        let found = self
 +                            .db
 +                            .trait_data(trait_ref.hir_trait_id())
 +                            .associated_type_by_name(segment.name);
 +                        match found {
 +                            Some(associated_ty) => {
 +                                // FIXME handle type parameters on the segment
 +                                TyKind::Alias(AliasTy::Projection(ProjectionTy {
 +                                    associated_ty_id: to_assoc_type_id(associated_ty),
 +                                    substitution: trait_ref.substitution,
 +                                }))
 +                                .intern(Interner)
 +                            }
 +                            None => {
 +                                // FIXME: report error (associated type not found)
 +                                TyKind::Error.intern(Interner)
 +                            }
 +                        }
 +                    }
 +                    0 => {
 +                        // Trait object type without dyn; this should be handled in upstream. See
 +                        // `lower_path()`.
 +                        stdx::never!("unexpected fully resolved trait path");
 +                        TyKind::Error.intern(Interner)
 +                    }
 +                    _ => {
 +                        // FIXME report error (ambiguous associated type)
 +                        TyKind::Error.intern(Interner)
 +                    }
 +                };
 +                return (ty, None);
 +            }
 +            TypeNs::GenericParam(param_id) => {
 +                let generics = generics(
 +                    self.db.upcast(),
 +                    self.resolver.generic_def().expect("generics in scope"),
 +                );
 +                match self.type_param_mode {
 +                    ParamLoweringMode::Placeholder => {
 +                        TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
 +                    }
 +                    ParamLoweringMode::Variable => {
 +                        let idx = match generics.param_idx(param_id.into()) {
 +                            None => {
 +                                never!("no matching generics");
 +                                return (TyKind::Error.intern(Interner), None);
 +                            }
 +                            Some(idx) => idx,
 +                        };
 +
 +                        TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
 +                    }
 +                }
 +                .intern(Interner)
 +            }
 +            TypeNs::SelfType(impl_id) => {
 +                let generics = generics(self.db.upcast(), impl_id.into());
 +                let substs = match self.type_param_mode {
 +                    ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
 +                    ParamLoweringMode::Variable => {
 +                        generics.bound_vars_subst(self.db, self.in_binders)
 +                    }
 +                };
 +                self.db.impl_self_ty(impl_id).substitute(Interner, &substs)
 +            }
 +            TypeNs::AdtSelfType(adt) => {
 +                let generics = generics(self.db.upcast(), adt.into());
 +                let substs = match self.type_param_mode {
 +                    ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
 +                    ParamLoweringMode::Variable => {
 +                        generics.bound_vars_subst(self.db, self.in_binders)
 +                    }
 +                };
 +                self.db.ty(adt.into()).substitute(Interner, &substs)
 +            }
 +
 +            TypeNs::AdtId(it) => self.lower_path_inner(resolved_segment, it.into(), infer_args),
 +            TypeNs::BuiltinType(it) => {
 +                self.lower_path_inner(resolved_segment, it.into(), infer_args)
 +            }
 +            TypeNs::TypeAliasId(it) => {
 +                self.lower_path_inner(resolved_segment, it.into(), infer_args)
 +            }
 +            // FIXME: report error
 +            TypeNs::EnumVariantId(_) => return (TyKind::Error.intern(Interner), None),
 +        };
 +        self.lower_ty_relative_path(ty, Some(resolution), remaining_segments)
 +    }
 +
 +    pub(crate) fn lower_path(&self, path: &Path) -> (Ty, Option<TypeNs>) {
 +        // Resolve the path (in type namespace)
 +        if let Some(type_ref) = path.type_anchor() {
 +            let (ty, res) = self.lower_ty_ext(type_ref);
 +            return self.lower_ty_relative_path(ty, res, path.segments());
 +        }
 +
 +        let (resolution, remaining_index) =
 +            match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
 +                Some(it) => it,
 +                None => return (TyKind::Error.intern(Interner), None),
 +            };
 +
 +        if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
 +            // trait object type without dyn
 +            let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None);
 +            let ty = self.lower_dyn_trait(&[Interned::new(bound)]);
 +            return (ty, None);
 +        }
 +
 +        let (resolved_segment, remaining_segments) = match remaining_index {
 +            None => (
 +                path.segments().last().expect("resolved path has at least one element"),
 +                PathSegments::EMPTY,
 +            ),
 +            Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)),
 +        };
 +        self.lower_partly_resolved_path(resolution, resolved_segment, remaining_segments, false)
 +    }
 +
 +    fn select_associated_type(&self, res: Option<TypeNs>, segment: PathSegment<'_>) -> Ty {
 +        let (def, res) = match (self.resolver.generic_def(), res) {
 +            (Some(def), Some(res)) => (def, res),
 +            _ => return TyKind::Error.intern(Interner),
 +        };
 +        let ty = named_associated_type_shorthand_candidates(
 +            self.db,
 +            def,
 +            res,
 +            Some(segment.name.clone()),
 +            move |name, t, associated_ty| {
 +                if name == segment.name {
 +                    let substs = match self.type_param_mode {
 +                        ParamLoweringMode::Placeholder => {
 +                            // if we're lowering to placeholders, we have to put
 +                            // them in now
 +                            let generics = generics(
 +                                self.db.upcast(),
 +                                self.resolver
 +                                    .generic_def()
 +                                    .expect("there should be generics if there's a generic param"),
 +                            );
 +                            let s = generics.placeholder_subst(self.db);
 +                            s.apply(t.substitution.clone(), Interner)
 +                        }
 +                        ParamLoweringMode::Variable => t.substitution.clone(),
 +                    };
 +                    // We need to shift in the bound vars, since
 +                    // associated_type_shorthand_candidates does not do that
 +                    let substs = substs.shifted_in_from(Interner, self.in_binders);
 +                    // FIXME handle type parameters on the segment
 +                    Some(
 +                        TyKind::Alias(AliasTy::Projection(ProjectionTy {
 +                            associated_ty_id: to_assoc_type_id(associated_ty),
 +                            substitution: substs,
 +                        }))
 +                        .intern(Interner),
 +                    )
 +                } else {
 +                    None
 +                }
 +            },
 +        );
 +
 +        ty.unwrap_or_else(|| TyKind::Error.intern(Interner))
 +    }
 +
 +    fn lower_path_inner(
 +        &self,
 +        segment: PathSegment<'_>,
 +        typeable: TyDefId,
 +        infer_args: bool,
 +    ) -> Ty {
 +        let generic_def = match typeable {
 +            TyDefId::BuiltinType(_) => None,
 +            TyDefId::AdtId(it) => Some(it.into()),
 +            TyDefId::TypeAliasId(it) => Some(it.into()),
 +        };
 +        let substs = self.substs_from_path_segment(segment, generic_def, infer_args, None);
 +        self.db.ty(typeable).substitute(Interner, &substs)
 +    }
 +
 +    /// Collect generic arguments from a path into a `Substs`. See also
 +    /// `create_substs_for_ast_path` and `def_to_ty` in rustc.
 +    pub(super) fn substs_from_path(
 +        &self,
 +        path: &Path,
 +        // Note that we don't call `db.value_type(resolved)` here,
 +        // `ValueTyDefId` is just a convenient way to pass generics and
 +        // special-case enum variants
 +        resolved: ValueTyDefId,
 +        infer_args: bool,
 +    ) -> Substitution {
 +        let last = path.segments().last().expect("path should have at least one segment");
 +        let (segment, generic_def) = match resolved {
 +            ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
 +            ValueTyDefId::StructId(it) => (last, Some(it.into())),
 +            ValueTyDefId::UnionId(it) => (last, Some(it.into())),
 +            ValueTyDefId::ConstId(it) => (last, Some(it.into())),
 +            ValueTyDefId::StaticId(_) => (last, None),
 +            ValueTyDefId::EnumVariantId(var) => {
 +                // the generic args for an enum variant may be either specified
 +                // on the segment referring to the enum, or on the segment
 +                // referring to the variant. So `Option::<T>::None` and
 +                // `Option::None::<T>` are both allowed (though the former is
 +                // preferred). See also `def_ids_for_path_segments` in rustc.
 +                let len = path.segments().len();
 +                let penultimate = len.checked_sub(2).and_then(|idx| path.segments().get(idx));
 +                let segment = match penultimate {
 +                    Some(segment) if segment.args_and_bindings.is_some() => segment,
 +                    _ => last,
 +                };
 +                (segment, Some(var.parent.into()))
 +            }
 +        };
 +        self.substs_from_path_segment(segment, generic_def, infer_args, None)
 +    }
 +
 +    fn substs_from_path_segment(
 +        &self,
 +        segment: PathSegment<'_>,
 +        def_generic: Option<GenericDefId>,
 +        infer_args: bool,
 +        explicit_self_ty: Option<Ty>,
 +    ) -> Substitution {
 +        let mut substs = Vec::new();
 +        let def_generics = if let Some(def) = def_generic {
 +            generics(self.db.upcast(), def)
 +        } else {
 +            return Substitution::empty(Interner);
 +        };
 +        let (parent_params, self_params, type_params, const_params, impl_trait_params) =
 +            def_generics.provenance_split();
 +        let total_len =
 +            parent_params + self_params + type_params + const_params + impl_trait_params;
 +
 +        let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
 +
 +        let mut def_generic_iter = def_generics.iter_id();
 +
 +        for _ in 0..parent_params {
 +            if let Some(eid) = def_generic_iter.next() {
 +                match eid {
 +                    Either::Left(_) => substs.push(ty_error.clone()),
 +                    Either::Right(x) => {
 +                        substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
 +                    }
 +                }
 +            }
 +        }
 +
 +        let fill_self_params = || {
 +            for x in explicit_self_ty
 +                .into_iter()
 +                .map(|x| GenericArgData::Ty(x).intern(Interner))
 +                .chain(iter::repeat(ty_error.clone()))
 +                .take(self_params)
 +            {
 +                if let Some(id) = def_generic_iter.next() {
 +                    assert!(id.is_left());
 +                    substs.push(x);
 +                }
 +            }
 +        };
 +        let mut had_explicit_args = false;
 +
 +        if let Some(generic_args) = &segment.args_and_bindings {
 +            if !generic_args.has_self_type {
 +                fill_self_params();
 +            }
 +            let expected_num = if generic_args.has_self_type {
 +                self_params + type_params + const_params
 +            } else {
 +                type_params + const_params
 +            };
 +            let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 };
 +            // if args are provided, it should be all of them, but we can't rely on that
 +            for arg in generic_args
 +                .args
 +                .iter()
 +                .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
 +                .skip(skip)
 +                .take(expected_num)
 +            {
 +                if let Some(id) = def_generic_iter.next() {
 +                    if let Some(x) = generic_arg_to_chalk(
 +                        self.db,
 +                        id,
 +                        arg,
 +                        &mut (),
 +                        |_, type_ref| self.lower_ty(type_ref),
 +                        |_, c, ty| {
 +                            const_or_path_to_chalk(
 +                                self.db,
 +                                &self.resolver,
 +                                ty,
 +                                c,
 +                                self.type_param_mode,
 +                                || self.generics(),
 +                                self.in_binders,
 +                            )
 +                        },
 +                    ) {
 +                        had_explicit_args = true;
 +                        substs.push(x);
 +                    } else {
 +                        // we just filtered them out
 +                        never!("Unexpected lifetime argument");
 +                    }
 +                }
 +            }
 +        } else {
 +            fill_self_params();
 +        }
 +
 +        // handle defaults. In expression or pattern path segments without
 +        // explicitly specified type arguments, missing type arguments are inferred
 +        // (i.e. defaults aren't used).
 +        if !infer_args || had_explicit_args {
 +            if let Some(def_generic) = def_generic {
 +                let defaults = self.db.generic_defaults(def_generic);
 +                assert_eq!(total_len, defaults.len());
 +
 +                for default_ty in defaults.iter().skip(substs.len()) {
 +                    // each default can depend on the previous parameters
 +                    let substs_so_far = Substitution::from_iter(Interner, substs.clone());
 +                    if let Some(_id) = def_generic_iter.next() {
 +                        substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
 +                    }
 +                }
 +            }
 +        }
 +
 +        // add placeholders for args that were not provided
 +        // FIXME: emit diagnostics in contexts where this is not allowed
 +        for eid in def_generic_iter {
 +            match eid {
 +                Either::Left(_) => substs.push(ty_error.clone()),
 +                Either::Right(x) => {
 +                    substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
 +                }
 +            }
 +        }
 +        // If this assert fails, it means you pushed into subst but didn't call .next() of def_generic_iter
 +        assert_eq!(substs.len(), total_len);
 +
 +        Substitution::from_iter(Interner, substs)
 +    }
 +
 +    fn lower_trait_ref_from_path(
 +        &self,
 +        path: &Path,
 +        explicit_self_ty: Option<Ty>,
 +    ) -> Option<TraitRef> {
 +        let resolved =
 +            match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path.mod_path())? {
 +                TypeNs::TraitId(tr) => tr,
 +                _ => return None,
 +            };
 +        let segment = path.segments().last().expect("path should have at least one segment");
 +        Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty))
 +    }
 +
 +    pub(crate) fn lower_trait_ref_from_resolved_path(
 +        &self,
 +        resolved: TraitId,
 +        segment: PathSegment<'_>,
 +        explicit_self_ty: Option<Ty>,
 +    ) -> TraitRef {
 +        let substs = self.trait_ref_substs_from_path(segment, resolved, explicit_self_ty);
 +        TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
 +    }
 +
 +    fn lower_trait_ref(
 +        &self,
 +        trait_ref: &HirTraitRef,
 +        explicit_self_ty: Option<Ty>,
 +    ) -> Option<TraitRef> {
 +        self.lower_trait_ref_from_path(&trait_ref.path, explicit_self_ty)
 +    }
 +
 +    fn trait_ref_substs_from_path(
 +        &self,
 +        segment: PathSegment<'_>,
 +        resolved: TraitId,
 +        explicit_self_ty: Option<Ty>,
 +    ) -> Substitution {
 +        self.substs_from_path_segment(segment, Some(resolved.into()), false, explicit_self_ty)
 +    }
 +
 +    pub(crate) fn lower_where_predicate(
 +        &'a self,
 +        where_predicate: &'a WherePredicate,
 +        ignore_bindings: bool,
 +    ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
 +        match where_predicate {
 +            WherePredicate::ForLifetime { target, bound, .. }
 +            | WherePredicate::TypeBound { target, bound } => {
 +                let self_ty = match target {
 +                    WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref),
 +                    WherePredicateTypeTarget::TypeOrConstParam(param_id) => {
 +                        let generic_def = self.resolver.generic_def().expect("generics in scope");
 +                        let generics = generics(self.db.upcast(), generic_def);
 +                        let param_id = hir_def::TypeOrConstParamId {
 +                            parent: generic_def,
 +                            local_id: *param_id,
 +                        };
 +                        let placeholder = to_placeholder_idx(self.db, param_id);
 +                        match self.type_param_mode {
 +                            ParamLoweringMode::Placeholder => TyKind::Placeholder(placeholder),
 +                            ParamLoweringMode::Variable => {
 +                                let idx = generics.param_idx(param_id).expect("matching generics");
 +                                TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, idx))
 +                            }
 +                        }
 +                        .intern(Interner)
 +                    }
 +                };
 +                self.lower_type_bound(bound, self_ty, ignore_bindings)
 +                    .collect::<Vec<_>>()
 +                    .into_iter()
 +            }
 +            WherePredicate::Lifetime { .. } => vec![].into_iter(),
 +        }
 +    }
 +
 +    pub(crate) fn lower_type_bound(
 +        &'a self,
 +        bound: &'a TypeBound,
 +        self_ty: Ty,
 +        ignore_bindings: bool,
 +    ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
 +        let mut bindings = None;
 +        let trait_ref = match bound {
 +            TypeBound::Path(path, TraitBoundModifier::None) => {
 +                bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
 +                bindings
 +                    .clone()
 +                    .filter(|tr| {
 +                        // ignore `T: Drop` or `T: Destruct` bounds.
 +                        // - `T: ~const Drop` has a special meaning in Rust 1.61 that we don't implement.
 +                        //   (So ideally, we'd only ignore `~const Drop` here)
 +                        // - `Destruct` impls are built-in in 1.62 (current nightlies as of 08-04-2022), so until
 +                        //   the builtin impls are supported by Chalk, we ignore them here.
 +                        if let Some(lang) = lang_attr(self.db.upcast(), tr.hir_trait_id()) {
 +                            if lang == "drop" || lang == "destruct" {
 +                                return false;
 +                            }
 +                        }
 +                        true
 +                    })
 +                    .map(WhereClause::Implemented)
 +                    .map(crate::wrap_empty_binders)
 +            }
 +            TypeBound::Path(path, TraitBoundModifier::Maybe) => {
 +                let sized_trait = self
 +                    .db
 +                    .lang_item(self.resolver.krate(), SmolStr::new_inline("sized"))
 +                    .and_then(|lang_item| lang_item.as_trait());
 +                // Don't lower associated type bindings as the only possible relaxed trait bound
 +                // `?Sized` has no of them.
 +                // If we got another trait here ignore the bound completely.
 +                let trait_id = self
 +                    .lower_trait_ref_from_path(path, Some(self_ty.clone()))
 +                    .map(|trait_ref| trait_ref.hir_trait_id());
 +                if trait_id == sized_trait {
 +                    self.unsized_types.borrow_mut().insert(self_ty);
 +                }
 +                None
 +            }
 +            TypeBound::ForLifetime(_, path) => {
 +                // FIXME Don't silently drop the hrtb lifetimes here
 +                bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
 +                bindings.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
 +            }
 +            TypeBound::Lifetime(_) => None,
 +            TypeBound::Error => None,
 +        };
 +        trait_ref.into_iter().chain(
 +            bindings
 +                .into_iter()
 +                .filter(move |_| !ignore_bindings)
 +                .flat_map(move |tr| self.assoc_type_bindings_from_type_bound(bound, tr)),
 +        )
 +    }
 +
 +    fn assoc_type_bindings_from_type_bound(
 +        &'a self,
 +        bound: &'a TypeBound,
 +        trait_ref: TraitRef,
 +    ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
 +        let last_segment = match bound {
 +            TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => {
 +                path.segments().last()
 +            }
 +            TypeBound::Path(_, TraitBoundModifier::Maybe)
 +            | TypeBound::Error
 +            | TypeBound::Lifetime(_) => None,
 +        };
 +        last_segment
 +            .into_iter()
 +            .filter_map(|segment| segment.args_and_bindings)
 +            .flat_map(|args_and_bindings| &args_and_bindings.bindings)
 +            .flat_map(move |binding| {
 +                let found = associated_type_by_name_including_super_traits(
 +                    self.db,
 +                    trait_ref.clone(),
 +                    &binding.name,
 +                );
 +                let (super_trait_ref, associated_ty) = match found {
 +                    None => return SmallVec::new(),
 +                    Some(t) => t,
 +                };
 +                let projection_ty = ProjectionTy {
 +                    associated_ty_id: to_assoc_type_id(associated_ty),
 +                    substitution: super_trait_ref.substitution,
 +                };
 +                let mut preds: SmallVec<[_; 1]> = SmallVec::with_capacity(
 +                    binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
 +                );
 +                if let Some(type_ref) = &binding.type_ref {
 +                    let ty = self.lower_ty(type_ref);
 +                    let alias_eq =
 +                        AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
 +                    preds.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
 +                }
 +                for bound in &binding.bounds {
 +                    preds.extend(self.lower_type_bound(
 +                        bound,
 +                        TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(Interner),
 +                        false,
 +                    ));
 +                }
 +                preds
 +            })
 +    }
 +
 +    fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
 +        let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
 +        let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
-                 bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
-             )
++            let bounds =
++                bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false));
++
++            let mut auto_traits = SmallVec::<[_; 8]>::new();
++            let mut regular_traits = SmallVec::<[_; 2]>::new();
++            let mut other_bounds = SmallVec::<[_; 8]>::new();
++            for bound in bounds {
++                if let Some(id) = bound.trait_id() {
++                    if ctx.db.trait_data(from_chalk_trait_id(id)).is_auto {
++                        auto_traits.push(bound);
++                    } else {
++                        regular_traits.push(bound);
++                    }
++                } else {
++                    other_bounds.push(bound);
++                }
++            }
++
++            if regular_traits.len() > 1 {
++                return None;
++            }
++
++            auto_traits.sort_unstable_by_key(|b| b.trait_id().unwrap());
++            auto_traits.dedup();
++
++            Some(QuantifiedWhereClauses::from_iter(
 +                Interner,
-         let bounds = crate::make_single_type_binders(bounds);
-         TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
++                regular_traits.into_iter().chain(other_bounds).chain(auto_traits),
++            ))
 +        });
++
++        if let Some(bounds) = bounds {
++            let bounds = crate::make_single_type_binders(bounds);
++            TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
++        } else {
++            // FIXME: report error (additional non-auto traits)
++            TyKind::Error.intern(Interner)
++        }
 +    }
 +
 +    fn lower_impl_trait(
 +        &self,
 +        bounds: &[Interned<TypeBound>],
 +        func: FunctionId,
 +    ) -> ReturnTypeImplTrait {
 +        cov_mark::hit!(lower_rpit);
 +        let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
 +        let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
 +            let mut predicates: Vec<_> = bounds
 +                .iter()
 +                .flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false))
 +                .collect();
 +
 +            if !ctx.unsized_types.borrow().contains(&self_ty) {
 +                let krate = func.lookup(ctx.db.upcast()).module(ctx.db.upcast()).krate();
 +                let sized_trait = ctx
 +                    .db
 +                    .lang_item(krate, SmolStr::new_inline("sized"))
 +                    .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
 +                let sized_clause = sized_trait.map(|trait_id| {
 +                    let clause = WhereClause::Implemented(TraitRef {
 +                        trait_id,
 +                        substitution: Substitution::from1(Interner, self_ty.clone()),
 +                    });
 +                    crate::wrap_empty_binders(clause)
 +                });
 +                predicates.extend(sized_clause.into_iter());
 +                predicates.shrink_to_fit();
 +            }
 +            predicates
 +        });
 +        ReturnTypeImplTrait { bounds: crate::make_single_type_binders(predicates) }
 +    }
 +}
 +
 +fn count_impl_traits(type_ref: &TypeRef) -> usize {
 +    let mut count = 0;
 +    type_ref.walk(&mut |type_ref| {
 +        if matches!(type_ref, TypeRef::ImplTrait(_)) {
 +            count += 1;
 +        }
 +    });
 +    count
 +}
 +
 +/// Build the signature of a callable item (function, struct or enum variant).
 +pub(crate) fn callable_item_sig(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig {
 +    match def {
 +        CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f),
 +        CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s),
 +        CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e),
 +    }
 +}
 +
 +pub fn associated_type_shorthand_candidates<R>(
 +    db: &dyn HirDatabase,
 +    def: GenericDefId,
 +    res: TypeNs,
 +    cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
 +) -> Option<R> {
 +    named_associated_type_shorthand_candidates(db, def, res, None, cb)
 +}
 +
 +fn named_associated_type_shorthand_candidates<R>(
 +    db: &dyn HirDatabase,
 +    // If the type parameter is defined in an impl and we're in a method, there
 +    // might be additional where clauses to consider
 +    def: GenericDefId,
 +    res: TypeNs,
 +    assoc_name: Option<Name>,
 +    mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
 +) -> Option<R> {
 +    let mut search = |t| {
 +        for t in all_super_trait_refs(db, t) {
 +            let data = db.trait_data(t.hir_trait_id());
 +
 +            for (name, assoc_id) in &data.items {
 +                if let AssocItemId::TypeAliasId(alias) = assoc_id {
 +                    if let Some(result) = cb(name, &t, *alias) {
 +                        return Some(result);
 +                    }
 +                }
 +            }
 +        }
 +        None
 +    };
 +
 +    match res {
 +        TypeNs::SelfType(impl_id) => search(
 +            // we're _in_ the impl -- the binders get added back later. Correct,
 +            // but it would be nice to make this more explicit
 +            db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
 +        ),
 +        TypeNs::GenericParam(param_id) => {
 +            let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
 +            let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
 +                // FIXME: how to correctly handle higher-ranked bounds here?
 +                WhereClause::Implemented(tr) => search(
 +                    tr.clone()
 +                        .shifted_out_to(Interner, DebruijnIndex::ONE)
 +                        .expect("FIXME unexpected higher-ranked trait bound"),
 +                ),
 +                _ => None,
 +            });
 +            if let Some(_) = res {
 +                return res;
 +            }
 +            // Handle `Self::Type` referring to own associated type in trait definitions
 +            if let GenericDefId::TraitId(trait_id) = param_id.parent() {
 +                let generics = generics(db.upcast(), trait_id.into());
 +                if generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
 +                    let trait_ref = TyBuilder::trait_ref(db, trait_id)
 +                        .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
 +                        .build();
 +                    return search(trait_ref);
 +                }
 +            }
 +            None
 +        }
 +        _ => None,
 +    }
 +}
 +
 +/// Build the type of all specific fields of a struct or enum variant.
 +pub(crate) fn field_types_query(
 +    db: &dyn HirDatabase,
 +    variant_id: VariantId,
 +) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> {
 +    let var_data = variant_id.variant_data(db.upcast());
 +    let (resolver, def): (_, GenericDefId) = match variant_id {
 +        VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()),
 +        VariantId::UnionId(it) => (it.resolver(db.upcast()), it.into()),
 +        VariantId::EnumVariantId(it) => (it.parent.resolver(db.upcast()), it.parent.into()),
 +    };
 +    let generics = generics(db.upcast(), def);
 +    let mut res = ArenaMap::default();
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    for (field_id, field_data) in var_data.fields().iter() {
 +        res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref)));
 +    }
 +    Arc::new(res)
 +}
 +
 +/// This query exists only to be used when resolving short-hand associated types
 +/// like `T::Item`.
 +///
 +/// See the analogous query in rustc and its comment:
 +/// <https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46>
 +/// This is a query mostly to handle cycles somewhat gracefully; e.g. the
 +/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but
 +/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
 +pub(crate) fn generic_predicates_for_param_query(
 +    db: &dyn HirDatabase,
 +    def: GenericDefId,
 +    param_id: TypeOrConstParamId,
 +    assoc_name: Option<Name>,
 +) -> Arc<[Binders<QuantifiedWhereClause>]> {
 +    let resolver = def.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    let generics = generics(db.upcast(), def);
 +    let mut predicates: Vec<_> = resolver
 +        .where_predicates_in_scope()
 +        // we have to filter out all other predicates *first*, before attempting to lower them
 +        .filter(|pred| match pred {
 +            WherePredicate::ForLifetime { target, bound, .. }
 +            | WherePredicate::TypeBound { target, bound, .. } => {
 +                match target {
 +                    WherePredicateTypeTarget::TypeRef(type_ref) => {
 +                        if ctx.lower_ty_only_param(type_ref) != Some(param_id) {
 +                            return false;
 +                        }
 +                    }
 +                    &WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
 +                        let target_id = TypeOrConstParamId { parent: def, local_id };
 +                        if target_id != param_id {
 +                            return false;
 +                        }
 +                    }
 +                };
 +
 +                match &**bound {
 +                    TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => {
 +                        // Only lower the bound if the trait could possibly define the associated
 +                        // type we're looking for.
 +
 +                        let assoc_name = match &assoc_name {
 +                            Some(it) => it,
 +                            None => return true,
 +                        };
 +                        let tr = match resolver
 +                            .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path())
 +                        {
 +                            Some(TypeNs::TraitId(tr)) => tr,
 +                            _ => return false,
 +                        };
 +
 +                        all_super_traits(db.upcast(), tr).iter().any(|tr| {
 +                            db.trait_data(*tr).items.iter().any(|(name, item)| {
 +                                matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
 +                            })
 +                        })
 +                    }
 +                    TypeBound::Lifetime(_) | TypeBound::Error => false,
 +                }
 +            }
 +            WherePredicate::Lifetime { .. } => false,
 +        })
 +        .flat_map(|pred| {
 +            ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p))
 +        })
 +        .collect();
 +
 +    let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
 +    let implicitly_sized_predicates =
 +        implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &subst, &resolver)
 +            .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p)));
 +    predicates.extend(implicitly_sized_predicates);
 +    predicates.into()
 +}
 +
 +pub(crate) fn generic_predicates_for_param_recover(
 +    _db: &dyn HirDatabase,
 +    _cycle: &[String],
 +    _def: &GenericDefId,
 +    _param_id: &TypeOrConstParamId,
 +    _assoc_name: &Option<Name>,
 +) -> Arc<[Binders<QuantifiedWhereClause>]> {
 +    Arc::new([])
 +}
 +
 +pub(crate) fn trait_environment_query(
 +    db: &dyn HirDatabase,
 +    def: GenericDefId,
 +) -> Arc<TraitEnvironment> {
 +    let resolver = def.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Placeholder);
 +    let mut traits_in_scope = Vec::new();
 +    let mut clauses = Vec::new();
 +    for pred in resolver.where_predicates_in_scope() {
 +        for pred in ctx.lower_where_predicate(pred, false) {
 +            if let WhereClause::Implemented(tr) = &pred.skip_binders() {
 +                traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
 +            }
 +            let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
 +            clauses.push(program_clause.into_from_env_clause(Interner));
 +        }
 +    }
 +
 +    let container: Option<ItemContainerId> = match def {
 +        // FIXME: is there a function for this?
 +        GenericDefId::FunctionId(f) => Some(f.lookup(db.upcast()).container),
 +        GenericDefId::AdtId(_) => None,
 +        GenericDefId::TraitId(_) => None,
 +        GenericDefId::TypeAliasId(t) => Some(t.lookup(db.upcast()).container),
 +        GenericDefId::ImplId(_) => None,
 +        GenericDefId::EnumVariantId(_) => None,
 +        GenericDefId::ConstId(c) => Some(c.lookup(db.upcast()).container),
 +    };
 +    if let Some(ItemContainerId::TraitId(trait_id)) = container {
 +        // add `Self: Trait<T1, T2, ...>` to the environment in trait
 +        // function default implementations (and speculative code
 +        // inside consts or type aliases)
 +        cov_mark::hit!(trait_self_implements_self);
 +        let substs = TyBuilder::placeholder_subst(db, trait_id);
 +        let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
 +        let pred = WhereClause::Implemented(trait_ref);
 +        let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
 +        clauses.push(program_clause.into_from_env_clause(Interner));
 +    }
 +
 +    let subst = generics(db.upcast(), def).placeholder_subst(db);
 +    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
 +    let implicitly_sized_clauses =
 +        implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver).map(|pred| {
 +            let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
 +            program_clause.into_from_env_clause(Interner)
 +        });
 +    clauses.extend(implicitly_sized_clauses);
 +
 +    let krate = def.module(db.upcast()).krate();
 +
 +    let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses);
 +
 +    Arc::new(TraitEnvironment { krate, traits_from_clauses: traits_in_scope, env })
 +}
 +
 +/// Resolve the where clause(s) of an item with generics.
 +pub(crate) fn generic_predicates_query(
 +    db: &dyn HirDatabase,
 +    def: GenericDefId,
 +) -> Arc<[Binders<QuantifiedWhereClause>]> {
 +    let resolver = def.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    let generics = generics(db.upcast(), def);
 +
 +    let mut predicates = resolver
 +        .where_predicates_in_scope()
 +        .flat_map(|pred| {
 +            ctx.lower_where_predicate(pred, false).map(|p| make_binders(db, &generics, p))
 +        })
 +        .collect::<Vec<_>>();
 +
 +    let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +    let explicitly_unsized_tys = ctx.unsized_types.into_inner();
 +    let implicitly_sized_predicates =
 +        implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
 +            .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p)));
 +    predicates.extend(implicitly_sized_predicates);
 +    predicates.into()
 +}
 +
 +/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
 +/// Exception is Self of a trait def.
 +fn implicitly_sized_clauses<'a>(
 +    db: &dyn HirDatabase,
 +    def: GenericDefId,
 +    explicitly_unsized_tys: &'a FxHashSet<Ty>,
 +    substitution: &'a Substitution,
 +    resolver: &Resolver,
 +) -> impl Iterator<Item = WhereClause> + 'a {
 +    let is_trait_def = matches!(def, GenericDefId::TraitId(..));
 +    let generic_args = &substitution.as_slice(Interner)[is_trait_def as usize..];
 +    let sized_trait = db
 +        .lang_item(resolver.krate(), SmolStr::new_inline("sized"))
 +        .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
 +
 +    sized_trait.into_iter().flat_map(move |sized_trait| {
 +        let implicitly_sized_tys = generic_args
 +            .iter()
 +            .filter_map(|generic_arg| generic_arg.ty(Interner))
 +            .filter(move |&self_ty| !explicitly_unsized_tys.contains(self_ty));
 +        implicitly_sized_tys.map(move |self_ty| {
 +            WhereClause::Implemented(TraitRef {
 +                trait_id: sized_trait,
 +                substitution: Substitution::from1(Interner, self_ty.clone()),
 +            })
 +        })
 +    })
 +}
 +
 +/// Resolve the default type params from generics
 +pub(crate) fn generic_defaults_query(
 +    db: &dyn HirDatabase,
 +    def: GenericDefId,
 +) -> Arc<[Binders<chalk_ir::GenericArg<Interner>>]> {
 +    let resolver = def.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    let generic_params = generics(db.upcast(), def);
 +
 +    let defaults = generic_params
 +        .iter()
 +        .enumerate()
 +        .map(|(idx, (id, p))| {
 +            let p = match p {
 +                TypeOrConstParamData::TypeParamData(p) => p,
 +                TypeOrConstParamData::ConstParamData(_) => {
 +                    // FIXME: implement const generic defaults
 +                    let val = unknown_const_as_generic(
 +                        db.const_param_ty(ConstParamId::from_unchecked(id)),
 +                    );
 +                    return crate::make_binders_with_count(db, idx, &generic_params, val);
 +                }
 +            };
 +            let mut ty =
 +                p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
 +
 +            // Each default can only refer to previous parameters.
 +            // type variable default referring to parameter coming
 +            // after it. This is forbidden (FIXME: report
 +            // diagnostic)
 +            ty = fallback_bound_vars(ty, idx);
 +            let val = GenericArgData::Ty(ty).intern(Interner);
 +            crate::make_binders_with_count(db, idx, &generic_params, val)
 +        })
 +        .collect();
 +
 +    defaults
 +}
 +
 +pub(crate) fn generic_defaults_recover(
 +    db: &dyn HirDatabase,
 +    _cycle: &[String],
 +    def: &GenericDefId,
 +) -> Arc<[Binders<crate::GenericArg>]> {
 +    let generic_params = generics(db.upcast(), *def);
 +    // FIXME: this code is not covered in tests.
 +    // we still need one default per parameter
 +    let defaults = generic_params
 +        .iter_id()
 +        .enumerate()
 +        .map(|(count, id)| {
 +            let val = match id {
 +                itertools::Either::Left(_) => {
 +                    GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
 +                }
 +                itertools::Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
 +            };
 +            crate::make_binders_with_count(db, count, &generic_params, val)
 +        })
 +        .collect();
 +
 +    defaults
 +}
 +
 +fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
 +    let data = db.function_data(def);
 +    let resolver = def.resolver(db.upcast());
 +    let ctx_params = TyLoweringContext::new(db, &resolver)
 +        .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
 +        .with_type_param_mode(ParamLoweringMode::Variable);
 +    let params = data.params.iter().map(|(_, tr)| ctx_params.lower_ty(tr)).collect::<Vec<_>>();
 +    let ctx_ret = TyLoweringContext::new(db, &resolver)
 +        .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
 +        .with_type_param_mode(ParamLoweringMode::Variable);
 +    let ret = ctx_ret.lower_ty(&data.ret_type);
 +    let generics = generics(db.upcast(), def.into());
 +    let sig = CallableSig::from_params_and_return(params, ret, data.is_varargs());
 +    make_binders(db, &generics, sig)
 +}
 +
 +/// Build the declared type of a function. This should not need to look at the
 +/// function body.
 +fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> {
 +    let generics = generics(db.upcast(), def.into());
 +    let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +    make_binders(
 +        db,
 +        &generics,
 +        TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(Interner),
 +    )
 +}
 +
 +/// Build the declared type of a const.
 +fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> {
 +    let data = db.const_data(def);
 +    let generics = generics(db.upcast(), def.into());
 +    let resolver = def.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +
 +    make_binders(db, &generics, ctx.lower_ty(&data.type_ref))
 +}
 +
 +/// Build the declared type of a static.
 +fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> {
 +    let data = db.static_data(def);
 +    let resolver = def.resolver(db.upcast());
 +    let ctx = TyLoweringContext::new(db, &resolver);
 +
 +    Binders::empty(Interner, ctx.lower_ty(&data.type_ref))
 +}
 +
 +fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig {
 +    let struct_data = db.struct_data(def);
 +    let fields = struct_data.variant_data.fields();
 +    let resolver = def.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
 +    let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
 +    Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
 +}
 +
 +/// Build the type of a tuple struct constructor.
 +fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders<Ty> {
 +    let struct_data = db.struct_data(def);
 +    if let StructKind::Unit = struct_data.variant_data.kind() {
 +        return type_for_adt(db, def.into());
 +    }
 +    let generics = generics(db.upcast(), def.into());
 +    let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +    make_binders(
 +        db,
 +        &generics,
 +        TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(Interner),
 +    )
 +}
 +
 +fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> PolyFnSig {
 +    let enum_data = db.enum_data(def.parent);
 +    let var_data = &enum_data.variants[def.local_id];
 +    let fields = var_data.variant_data.fields();
 +    let resolver = def.parent.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
 +    let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders();
 +    Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
 +}
 +
 +/// Build the type of a tuple enum variant constructor.
 +fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> Binders<Ty> {
 +    let enum_data = db.enum_data(def.parent);
 +    let var_data = &enum_data.variants[def.local_id].variant_data;
 +    if let StructKind::Unit = var_data.kind() {
 +        return type_for_adt(db, def.parent.into());
 +    }
 +    let generics = generics(db.upcast(), def.parent.into());
 +    let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +    make_binders(
 +        db,
 +        &generics,
 +        TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs).intern(Interner),
 +    )
 +}
 +
 +fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
 +    let generics = generics(db.upcast(), adt.into());
 +    let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
 +    let ty = TyKind::Adt(crate::AdtId(adt), subst).intern(Interner);
 +    make_binders(db, &generics, ty)
 +}
 +
 +fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
 +    let generics = generics(db.upcast(), t.into());
 +    let resolver = t.resolver(db.upcast());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    if db.type_alias_data(t).is_extern {
 +        Binders::empty(Interner, TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner))
 +    } else {
 +        let type_ref = &db.type_alias_data(t).type_ref;
 +        let inner = ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error));
 +        make_binders(db, &generics, inner)
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum CallableDefId {
 +    FunctionId(FunctionId),
 +    StructId(StructId),
 +    EnumVariantId(EnumVariantId),
 +}
 +impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId);
 +
 +impl CallableDefId {
 +    pub fn krate(self, db: &dyn HirDatabase) -> CrateId {
 +        let db = db.upcast();
 +        match self {
 +            CallableDefId::FunctionId(f) => f.lookup(db).module(db),
 +            CallableDefId::StructId(s) => s.lookup(db).container,
 +            CallableDefId::EnumVariantId(e) => e.parent.lookup(db).container,
 +        }
 +        .krate()
 +    }
 +}
 +
 +impl From<CallableDefId> for GenericDefId {
 +    fn from(def: CallableDefId) -> GenericDefId {
 +        match def {
 +            CallableDefId::FunctionId(f) => f.into(),
 +            CallableDefId::StructId(s) => s.into(),
 +            CallableDefId::EnumVariantId(e) => e.into(),
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum TyDefId {
 +    BuiltinType(BuiltinType),
 +    AdtId(AdtId),
 +    TypeAliasId(TypeAliasId),
 +}
 +impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefId);
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum ValueTyDefId {
 +    FunctionId(FunctionId),
 +    StructId(StructId),
 +    UnionId(UnionId),
 +    EnumVariantId(EnumVariantId),
 +    ConstId(ConstId),
 +    StaticId(StaticId),
 +}
 +impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
 +
 +/// Build the declared type of an item. This depends on the namespace; e.g. for
 +/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
 +/// the constructor function `(usize) -> Foo` which lives in the values
 +/// namespace.
 +pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> {
 +    match def {
 +        TyDefId::BuiltinType(it) => Binders::empty(Interner, TyBuilder::builtin(it)),
 +        TyDefId::AdtId(it) => type_for_adt(db, it),
 +        TyDefId::TypeAliasId(it) => type_for_type_alias(db, it),
 +    }
 +}
 +
 +pub(crate) fn ty_recover(db: &dyn HirDatabase, _cycle: &[String], def: &TyDefId) -> Binders<Ty> {
 +    let generics = match *def {
 +        TyDefId::BuiltinType(_) => return Binders::empty(Interner, TyKind::Error.intern(Interner)),
 +        TyDefId::AdtId(it) => generics(db.upcast(), it.into()),
 +        TyDefId::TypeAliasId(it) => generics(db.upcast(), it.into()),
 +    };
 +    make_binders(db, &generics, TyKind::Error.intern(Interner))
 +}
 +
 +pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders<Ty> {
 +    match def {
 +        ValueTyDefId::FunctionId(it) => type_for_fn(db, it),
 +        ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it),
 +        ValueTyDefId::UnionId(it) => type_for_adt(db, it.into()),
 +        ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it),
 +        ValueTyDefId::ConstId(it) => type_for_const(db, it),
 +        ValueTyDefId::StaticId(it) => type_for_static(db, it),
 +    }
 +}
 +
 +pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders<Ty> {
 +    let impl_loc = impl_id.lookup(db.upcast());
 +    let impl_data = db.impl_data(impl_id);
 +    let resolver = impl_id.resolver(db.upcast());
 +    let _cx = stdx::panic_context::enter(format!(
 +        "impl_self_ty_query({:?} -> {:?} -> {:?})",
 +        impl_id, impl_loc, impl_data
 +    ));
 +    let generics = generics(db.upcast(), impl_id.into());
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    make_binders(db, &generics, ctx.lower_ty(&impl_data.self_ty))
 +}
 +
 +// returns None if def is a type arg
 +pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
 +    let parent_data = db.generic_params(def.parent());
 +    let data = &parent_data.type_or_consts[def.local_id()];
 +    let resolver = def.parent().resolver(db.upcast());
 +    let ctx = TyLoweringContext::new(db, &resolver);
 +    match data {
 +        TypeOrConstParamData::TypeParamData(_) => {
 +            never!();
 +            Ty::new(Interner, TyKind::Error)
 +        }
 +        TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(&d.ty),
 +    }
 +}
 +
 +pub(crate) fn impl_self_ty_recover(
 +    db: &dyn HirDatabase,
 +    _cycle: &[String],
 +    impl_id: &ImplId,
 +) -> Binders<Ty> {
 +    let generics = generics(db.upcast(), (*impl_id).into());
 +    make_binders(db, &generics, TyKind::Error.intern(Interner))
 +}
 +
 +pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
 +    let impl_loc = impl_id.lookup(db.upcast());
 +    let impl_data = db.impl_data(impl_id);
 +    let resolver = impl_id.resolver(db.upcast());
 +    let _cx = stdx::panic_context::enter(format!(
 +        "impl_trait_query({:?} -> {:?} -> {:?})",
 +        impl_id, impl_loc, impl_data
 +    ));
 +    let ctx =
 +        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
 +    let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
 +    let target_trait = impl_data.target_trait.as_ref()?;
 +    Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, Some(self_ty))?))
 +}
 +
 +pub(crate) fn return_type_impl_traits(
 +    db: &dyn HirDatabase,
 +    def: hir_def::FunctionId,
 +) -> Option<Arc<Binders<ReturnTypeImplTraits>>> {
 +    // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
 +    let data = db.function_data(def);
 +    let resolver = def.resolver(db.upcast());
 +    let ctx_ret = TyLoweringContext::new(db, &resolver)
 +        .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
 +        .with_type_param_mode(ParamLoweringMode::Variable);
 +    let _ret = (&ctx_ret).lower_ty(&data.ret_type);
 +    let generics = generics(db.upcast(), def.into());
 +    let return_type_impl_traits =
 +        ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() };
 +    if return_type_impl_traits.impl_traits.is_empty() {
 +        None
 +    } else {
 +        Some(Arc::new(make_binders(db, &generics, return_type_impl_traits)))
 +    }
 +}
 +
 +pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mutability {
 +    match m {
 +        hir_def::type_ref::Mutability::Shared => Mutability::Not,
 +        hir_def::type_ref::Mutability::Mut => Mutability::Mut,
 +    }
 +}
 +
 +/// Checks if the provided generic arg matches its expected kind, then lower them via
 +/// provided closures. Use unknown if there was kind mismatch.
 +///
 +/// Returns `Some` of the lowered generic arg. `None` if the provided arg is a lifetime.
 +pub(crate) fn generic_arg_to_chalk<'a, T>(
 +    db: &dyn HirDatabase,
 +    kind_id: Either<TypeParamId, ConstParamId>,
 +    arg: &'a GenericArg,
 +    this: &mut T,
 +    for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
 +    for_const: impl FnOnce(&mut T, &ConstScalarOrPath, Ty) -> Const + 'a,
 +) -> Option<crate::GenericArg> {
 +    let kind = match kind_id {
 +        Either::Left(_) => ParamKind::Type,
 +        Either::Right(id) => {
 +            let ty = db.const_param_ty(id);
 +            ParamKind::Const(ty)
 +        }
 +    };
 +    Some(match (arg, kind) {
 +        (GenericArg::Type(type_ref), ParamKind::Type) => {
 +            let ty = for_type(this, type_ref);
 +            GenericArgData::Ty(ty).intern(Interner)
 +        }
 +        (GenericArg::Const(c), ParamKind::Const(c_ty)) => {
 +            GenericArgData::Const(for_const(this, c, c_ty)).intern(Interner)
 +        }
 +        (GenericArg::Const(_), ParamKind::Type) => {
 +            GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
 +        }
 +        (GenericArg::Type(t), ParamKind::Const(c_ty)) => {
 +            // We want to recover simple idents, which parser detects them
 +            // as types. Maybe here is not the best place to do it, but
 +            // it works.
 +            if let TypeRef::Path(p) = t {
 +                let p = p.mod_path();
 +                if p.kind == PathKind::Plain {
 +                    if let [n] = p.segments() {
 +                        let c = ConstScalarOrPath::Path(n.clone());
 +                        return Some(
 +                            GenericArgData::Const(for_const(this, &c, c_ty)).intern(Interner),
 +                        );
 +                    }
 +                }
 +            }
 +            unknown_const_as_generic(c_ty)
 +        }
 +        (GenericArg::Lifetime(_), _) => return None,
 +    })
 +}
 +
 +pub(crate) fn const_or_path_to_chalk(
 +    db: &dyn HirDatabase,
 +    resolver: &Resolver,
 +    expected_ty: Ty,
 +    value: &ConstScalarOrPath,
 +    mode: ParamLoweringMode,
 +    args: impl FnOnce() -> Generics,
 +    debruijn: DebruijnIndex,
 +) -> Const {
 +    match value {
 +        ConstScalarOrPath::Scalar(s) => intern_const_scalar(s.clone(), expected_ty),
 +        ConstScalarOrPath::Path(n) => {
 +            let path = ModPath::from_segments(PathKind::Plain, Some(n.clone()));
 +            path_to_const(db, resolver, &path, mode, args, debruijn)
 +                .unwrap_or_else(|| unknown_const(expected_ty))
 +        }
 +    }
 +}
 +
 +/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
 +/// num_vars_to_keep) by `TyKind::Unknown`.
 +fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
 +    s: T,
 +    num_vars_to_keep: usize,
 +) -> T {
 +    crate::fold_free_vars(
 +        s,
 +        |bound, binders| {
 +            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
 +                TyKind::Error.intern(Interner)
 +            } else {
 +                bound.shifted_in_from(binders).to_ty(Interner)
 +            }
 +        },
 +        |ty, bound, binders| {
 +            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
 +                unknown_const(ty.clone())
 +            } else {
 +                bound.shifted_in_from(binders).to_const(Interner, ty)
 +            }
 +        },
 +    )
 +}
index a1ab6060e790c0cdb4a9a02ffcd33e7b66d2aa0e,0000000000000000000000000000000000000000..b3adafaafd38de8ea411754aa963079da3f3a309
mode 100644,000000..100644
--- /dev/null
@@@ -1,1338 -1,0 +1,1326 @@@
-             !0..6 '1isize': isize
-             !0..6 '1isize': isize
 +use expect_test::expect;
 +use test_utils::{bench, bench_fixture, skip_slow_tests};
 +
 +use crate::tests::check_infer_with_mismatches;
 +
 +use super::{check_infer, check_types};
 +
 +#[test]
 +fn cfg_impl_def() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:foo cfg:test
 +use foo::S as T;
 +struct S;
 +
 +#[cfg(test)]
 +impl S {
 +    fn foo1(&self) -> i32 { 0 }
 +}
 +
 +#[cfg(not(test))]
 +impl S {
 +    fn foo2(&self) -> i32 { 0 }
 +}
 +
 +fn test() {
 +    let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4());
 +    t;
 +} //^ (i32, {unknown}, i32, {unknown})
 +
 +//- /foo.rs crate:foo
 +pub struct S;
 +
 +#[cfg(not(test))]
 +impl S {
 +    pub fn foo3(&self) -> i32 { 0 }
 +}
 +
 +#[cfg(test)]
 +impl S {
 +    pub fn foo4(&self) -> i32 { 0 }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_macros_expanded() {
 +    check_infer(
 +        r#"
 +        struct Foo(Vec<i32>);
 +
 +        macro_rules! foo {
 +            ($($item:expr),*) => {
 +                    {
 +                        Foo(vec![$($item,)*])
 +                    }
 +            };
 +        }
 +
 +        fn main() {
 +            let x = foo!(1,2);
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..17 '{Foo(v...,2,])}': Foo
 +            !1..4 'Foo': Foo({unknown}) -> Foo
 +            !1..16 'Foo(vec![1,2,])': Foo
 +            !5..15 'vec![1,2,]': {unknown}
 +            155..181 '{     ...,2); }': ()
 +            165..166 'x': Foo
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_legacy_textual_scoped_macros_expanded() {
 +    check_infer(
 +        r#"
 +        struct Foo(Vec<i32>);
 +
 +        #[macro_use]
 +        mod m {
 +            macro_rules! foo {
 +                ($($item:expr),*) => {
 +                    {
 +                        Foo(vec![$($item,)*])
 +                    }
 +                };
 +            }
 +        }
 +
 +        fn main() {
 +            let x = foo!(1,2);
 +            let y = crate::foo!(1,2);
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..17 '{Foo(v...,2,])}': Foo
 +            !1..4 'Foo': Foo({unknown}) -> Foo
 +            !1..16 'Foo(vec![1,2,])': Foo
 +            !5..15 'vec![1,2,]': {unknown}
 +            194..250 '{     ...,2); }': ()
 +            204..205 'x': Foo
 +            227..228 'y': {unknown}
 +            231..247 'crate:...!(1,2)': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_path_qualified_macros_expanded() {
 +    check_infer(
 +        r#"
 +        #[macro_export]
 +        macro_rules! foo {
 +            () => { 42i32 }
 +        }
 +
 +        mod m {
 +            pub use super::foo as bar;
 +        }
 +
 +        fn main() {
 +            let x = crate::foo!();
 +            let y = m::bar!();
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..5 '42i32': i32
 +            !0..5 '42i32': i32
 +            110..163 '{     ...!(); }': ()
 +            120..121 'x': i32
 +            147..148 'y': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn expr_macro_def_expanded_in_various_places() {
 +    check_infer(
 +        r#"
 +        macro spam() {
 +            1isize
 +        }
 +
 +        fn spam() {
 +            spam!();
 +            (spam!());
 +            spam!().spam(spam!());
 +            for _ in spam!() {}
 +            || spam!();
 +            while spam!() {}
 +            break spam!();
 +            return spam!();
 +            match spam!() {
 +                _ if spam!() => spam!(),
 +            }
 +            spam!()(spam!());
 +            Spam { spam: spam!() };
 +            spam!()[spam!()];
 +            await spam!();
 +            spam!() as usize;
 +            &spam!();
 +            -spam!();
 +            spam!()..spam!();
 +            spam!() + spam!();
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
-             !0..6 '1isize': isize
-             !0..6 '1isize': isize
 +            39..442 '{     ...!(); }': ()
 +            73..94 'spam!(...am!())': {unknown}
 +            100..119 'for _ ...!() {}': ()
 +            104..105 '_': {unknown}
 +            117..119 '{}': ()
 +            124..134 '|| spam!()': || -> isize
 +            140..156 'while ...!() {}': ()
 +            154..156 '{}': ()
 +            161..174 'break spam!()': !
 +            180..194 'return spam!()': !
 +            200..254 'match ...     }': isize
 +            224..225 '_': isize
 +            259..275 'spam!(...am!())': {unknown}
 +            281..303 'Spam {...m!() }': {unknown}
 +            309..325 'spam!(...am!()]': {unknown}
 +            350..366 'spam!(... usize': usize
 +            372..380 '&spam!()': &isize
 +            386..394 '-spam!()': isize
 +            400..416 'spam!(...pam!()': {unknown}
 +            422..439 'spam!(...pam!()': isize
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn expr_macro_rules_expanded_in_various_places() {
 +    check_infer(
 +        r#"
 +        macro_rules! spam {
 +            () => (1isize);
 +        }
 +
 +        fn spam() {
 +            spam!();
 +            (spam!());
 +            spam!().spam(spam!());
 +            for _ in spam!() {}
 +            || spam!();
 +            while spam!() {}
 +            break spam!();
 +            return spam!();
 +            match spam!() {
 +                _ if spam!() => spam!(),
 +            }
 +            spam!()(spam!());
 +            Spam { spam: spam!() };
 +            spam!()[spam!()];
 +            await spam!();
 +            spam!() as usize;
 +            &spam!();
 +            -spam!();
 +            spam!()..spam!();
 +            spam!() + spam!();
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
 +            !0..6 '1isize': isize
-             !0..8 'leta=();': ()
 +            53..456 '{     ...!(); }': ()
 +            87..108 'spam!(...am!())': {unknown}
 +            114..133 'for _ ...!() {}': ()
 +            118..119 '_': {unknown}
 +            131..133 '{}': ()
 +            138..148 '|| spam!()': || -> isize
 +            154..170 'while ...!() {}': ()
 +            168..170 '{}': ()
 +            175..188 'break spam!()': !
 +            194..208 'return spam!()': !
 +            214..268 'match ...     }': isize
 +            238..239 '_': isize
 +            273..289 'spam!(...am!())': {unknown}
 +            295..317 'Spam {...m!() }': {unknown}
 +            323..339 'spam!(...am!()]': {unknown}
 +            364..380 'spam!(... usize': usize
 +            386..394 '&spam!()': &isize
 +            400..408 '-spam!()': isize
 +            414..430 'spam!(...pam!()': {unknown}
 +            436..453 'spam!(...pam!()': isize
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn expr_macro_expanded_in_stmts() {
 +    check_infer(
 +        r#"
 +        macro_rules! id { ($($es:tt)*) => { $($es)* } }
 +        fn foo() {
 +            id! { let a = (); }
 +        }
 +        "#,
 +        expect![[r#"
- fn recurisve_macro_expanded_in_stmts() {
 +            !3..4 'a': ()
 +            !5..7 '()': ()
 +            57..84 '{     ...); } }': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
-             !0..7 'leta=3;': ()
-             !0..13 'ng!{[leta=3]}': ()
-             !0..13 'ng!{[leta=]3}': ()
-             !0..13 'ng!{[leta]=3}': ()
-             !0..13 'ng!{[let]a=3}': ()
++fn recursive_macro_expanded_in_stmts() {
 +    check_infer(
 +        r#"
 +        macro_rules! ng {
 +            ([$($tts:tt)*]) => {
 +                $($tts)*;
 +            };
 +            ([$($tts:tt)*] $head:tt $($rest:tt)*) => {
 +                ng! {
 +                    [$($tts)* $head] $($rest)*
 +                }
 +            };
 +        }
 +        fn foo() {
 +            ng!([] let a = 3);
 +            let b = a;
 +        }
 +        "#,
 +        expect![[r#"
-             !0..7 'mac!($)': ()
-             !0..26 'macro_...>{1};}': ()
 +            !3..4 'a': i32
 +            !5..6 '3': i32
 +            196..237 '{     ...= a; }': ()
 +            229..230 'b': i32
 +            233..234 'a': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn recursive_inner_item_macro_rules() {
 +    check_infer(
 +        r#"
 +        macro_rules! mac {
 +            () => { mac!($)};
 +            ($x:tt) => { macro_rules! blub { () => { 1 }; } };
 +        }
 +        fn foo() {
 +            mac!();
 +            let a = blub!();
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..1 '1': i32
 +            107..143 '{     ...!(); }': ()
 +            129..130 'a': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_macro_defining_block_with_items() {
 +    check_infer(
 +        r#"
 +        macro_rules! foo {
 +            () => {{
 +                fn bar() -> usize { 0 }
 +                bar()
 +            }};
 +        }
 +        fn main() {
 +            let _a = foo!();
 +        }
 +    "#,
 +        expect![[r#"
 +            !15..18 '{0}': usize
 +            !16..17 '0': usize
 +            !0..24 '{fnbar...bar()}': usize
 +            !18..21 'bar': fn bar() -> usize
 +            !18..23 'bar()': usize
 +            98..122 '{     ...!(); }': ()
 +            108..110 '_a': usize
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_type_value_macro_having_same_name() {
 +    check_infer(
 +        r#"
 +        #[macro_export]
 +        macro_rules! foo {
 +            () => {
 +                mod foo {
 +                    pub use super::foo;
 +                }
 +            };
 +            ($x:tt) => {
 +                $x
 +            };
 +        }
 +
 +        foo!();
 +
 +        fn foo() {
 +            let foo = foo::foo!(42i32);
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..5 '42i32': i32
 +            170..205 '{     ...32); }': ()
 +            180..183 'foo': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn processes_impls_generated_by_macros() {
 +    check_types(
 +        r#"
 +macro_rules! m {
 +    ($ident:ident) => (impl Trait for $ident {})
 +}
 +trait Trait { fn foo(self) -> u128 { 0 } }
 +struct S;
 +m!(S);
 +fn test() { S.foo(); }
 +          //^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_assoc_items_generated_by_macros() {
 +    check_types(
 +        r#"
 +macro_rules! m {
 +    () => (fn foo(&self) -> u128 {0})
 +}
 +struct S;
 +impl S {
 +    m!();
 +}
 +
 +fn test() { S.foo(); }
 +          //^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_assoc_items_generated_by_macros_chain() {
 +    check_types(
 +        r#"
 +macro_rules! m_inner {
 +    () => {fn foo(&self) -> u128 {0}}
 +}
 +macro_rules! m {
 +    () => {m_inner!();}
 +}
 +
 +struct S;
 +impl S {
 +    m!();
 +}
 +
 +fn test() { S.foo(); }
 +          //^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_macro_with_dollar_crate_is_correct_in_expr() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:foo
 +fn test() {
 +    let x = (foo::foo!(1), foo::foo!(2));
 +    x;
 +} //^ (i32, usize)
 +
 +//- /lib.rs crate:foo
 +#[macro_export]
 +macro_rules! foo {
 +    (1) => { $crate::bar!() };
 +    (2) => { 1 + $crate::baz() };
 +}
 +
 +#[macro_export]
 +macro_rules! bar {
 +    () => { 42 }
 +}
 +
 +pub fn baz() -> usize { 31usize }
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:foo
 +use foo::Trait;
 +
 +fn test() {
 +    let msg = foo::Message(foo::MessageRef);
 +    let r = msg.deref();
 +    r;
 +  //^ &MessageRef
 +}
 +
 +//- /lib.rs crate:foo
 +pub struct MessageRef;
 +pub struct Message(MessageRef);
 +
 +pub trait Trait {
 +    type Target;
 +    fn deref(&self) -> &Self::Target;
 +}
 +
 +#[macro_export]
 +macro_rules! expand {
 +    () => {
 +        impl Trait for Message {
 +            type Target = $crate::MessageRef;
 +            fn deref(&self) ->  &Self::Target {
 +                &self.0
 +            }
 +        }
 +    }
 +}
 +
 +expand!();
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_macro_with_dollar_crate_in_def_site() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:foo
 +use foo::expand;
 +
 +macro_rules! list {
 +    ($($tt:tt)*) => { $($tt)* }
 +}
 +
 +fn test() {
 +    let r = expand!();
 +    r;
 +  //^ u128
 +}
 +
 +//- /lib.rs crate:foo
 +#[macro_export]
 +macro_rules! expand {
 +    () => { list!($crate::m!()) };
 +}
 +
 +#[macro_export]
 +macro_rules! m {
 +    () => { 0u128 };
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_type_value_non_legacy_macro_use_as() {
 +    check_infer(
 +        r#"
 +        mod m {
 +            macro_rules! _foo {
 +                ($x:ident) => { type $x = u64; }
 +            }
 +            pub(crate) use _foo as foo;
 +        }
 +
 +        m::foo!(foo);
 +        use foo as bar;
 +        fn f() -> bar { 0 }
 +        fn main() {
 +            let _a  = f();
 +        }
 +        "#,
 +        expect![[r#"
 +            158..163 '{ 0 }': u64
 +            160..161 '0': u64
 +            174..196 '{     ...f(); }': ()
 +            184..186 '_a': u64
 +            190..191 'f': fn f() -> u64
 +            190..193 'f()': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_local_macro() {
 +    check_infer(
 +        r#"
 +        fn main() {
 +            macro_rules! foo {
 +                () => { 1usize }
 +            }
 +            let _a  = foo!();
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..6 '1usize': usize
 +            10..89 '{     ...!(); }': ()
 +            74..76 '_a': usize
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_local_inner_macros() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:foo
 +fn test() {
 +    let x = foo::foo!(1);
 +    x;
 +} //^ i32
 +
 +//- /lib.rs crate:foo
 +#[macro_export(local_inner_macros)]
 +macro_rules! foo {
 +    (1) => { bar!() };
 +}
 +
 +#[macro_export]
 +macro_rules! bar {
 +    () => { 42 }
 +}
 +
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_builtin_macros_line() {
 +    check_infer(
 +        r#"
 +        #[rustc_builtin_macro]
 +        macro_rules! line {() => {}}
 +
 +        fn main() {
 +            let x = line!();
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..1 '0': i32
 +            63..87 '{     ...!(); }': ()
 +            73..74 'x': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_builtin_macros_file() {
 +    check_infer(
 +        r#"
 +        #[rustc_builtin_macro]
 +        macro_rules! file {() => {}}
 +
 +        fn main() {
 +            let x = file!();
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..2 '""': &str
 +            63..87 '{     ...!(); }': ()
 +            73..74 'x': &str
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_builtin_macros_column() {
 +    check_infer(
 +        r#"
 +        #[rustc_builtin_macro]
 +        macro_rules! column {() => {}}
 +
 +        fn main() {
 +            let x = column!();
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..1 '0': i32
 +            65..91 '{     ...!(); }': ()
 +            75..76 'x': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_builtin_macros_concat() {
 +    check_infer(
 +        r#"
 +        #[rustc_builtin_macro]
 +        macro_rules! concat {() => {}}
 +
 +        fn main() {
 +            let x = concat!("hello", concat!("world", "!"));
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..13 '"helloworld!"': &str
 +            65..121 '{     ...")); }': ()
 +            75..76 'x': &str
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_builtin_macros_include() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +#[rustc_builtin_macro]
 +macro_rules! include {() => {}}
 +
 +include!("foo.rs");
 +
 +fn main() {
 +    bar();
 +} //^^^^^ u32
 +
 +//- /foo.rs
 +fn bar() -> u32 {0}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_builtin_macros_include_expression() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +#[rustc_builtin_macro]
 +macro_rules! include {() => {}}
 +fn main() {
 +    let i = include!("bla.rs");
 +    i;
 +  //^ i32
 +}
 +//- /bla.rs
 +0
 +        "#,
 +    )
 +}
 +
 +#[test]
 +fn infer_builtin_macros_include_child_mod() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +#[rustc_builtin_macro]
 +macro_rules! include {() => {}}
 +
 +include!("f/foo.rs");
 +
 +fn main() {
 +    bar::bar();
 +} //^^^^^^^^^^ u32
 +
 +//- /f/foo.rs
 +pub mod bar;
 +
 +//- /f/bar.rs
 +pub fn bar() -> u32 {0}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_builtin_macros_include_str() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +#[rustc_builtin_macro]
 +macro_rules! include_str {() => {}}
 +
 +fn main() {
 +    let a = include_str!("foo.rs");
 +    a;
 +} //^ &str
 +
 +//- /foo.rs
 +hello
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_builtin_macros_include_str_with_lazy_nested() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +#[rustc_builtin_macro]
 +macro_rules! concat {() => {}}
 +#[rustc_builtin_macro]
 +macro_rules! include_str {() => {}}
 +
 +macro_rules! m {
 +    ($x:expr) => {
 +        concat!("foo", $x)
 +    };
 +}
 +
 +fn main() {
 +    let a = include_str!(m!(".rs"));
 +    a;
 +} //^ &str
 +
 +//- /foo.rs
 +hello
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn benchmark_include_macro() {
 +    if skip_slow_tests() {
 +        return;
 +    }
 +    let data = bench_fixture::big_struct();
 +    let fixture = r#"
 +//- /main.rs
 +#[rustc_builtin_macro]
 +macro_rules! include {() => {}}
 +
 +include!("foo.rs");
 +
 +fn main() {
 +    RegisterBlock { };
 +  //^^^^^^^^^^^^^^^^^ RegisterBlock
 +}
 +    "#;
 +    let fixture = format!("{}\n//- /foo.rs\n{}", fixture, data);
 +
 +    {
 +        let _b = bench("include macro");
 +        check_types(&fixture);
 +    }
 +}
 +
 +#[test]
 +fn infer_builtin_macros_include_concat() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +#[rustc_builtin_macro]
 +macro_rules! include {() => {}}
 +
 +#[rustc_builtin_macro]
 +macro_rules! concat {() => {}}
 +
 +include!(concat!("f", "oo.rs"));
 +
 +fn main() {
 +    bar();
 +} //^^^^^ u32
 +
 +//- /foo.rs
 +fn bar() -> u32 {0}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_builtin_macros_include_concat_with_bad_env_should_failed() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +#[rustc_builtin_macro]
 +macro_rules! include {() => {}}
 +
 +#[rustc_builtin_macro]
 +macro_rules! concat {() => {}}
 +
 +#[rustc_builtin_macro]
 +macro_rules! env {() => {}}
 +
 +include!(concat!(env!("OUT_DIR"), "/foo.rs"));
 +
 +fn main() {
 +    bar();
 +} //^^^^^ {unknown}
 +
 +//- /foo.rs
 +fn bar() -> u32 {0}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_builtin_macros_include_itself_should_failed() {
 +    check_types(
 +        r#"
 +#[rustc_builtin_macro]
 +macro_rules! include {() => {}}
 +
 +include!("main.rs");
 +
 +fn main() {
 +    0;
 +} //^ i32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_builtin_macros_concat_with_lazy() {
 +    check_infer(
 +        r#"
 +        macro_rules! hello {() => {"hello"}}
 +
 +        #[rustc_builtin_macro]
 +        macro_rules! concat {() => {}}
 +
 +        fn main() {
 +            let x = concat!(hello!(), concat!("world", "!"));
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..13 '"helloworld!"': &str
 +            103..160 '{     ...")); }': ()
 +            113..114 'x': &str
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_builtin_macros_env() {
 +    check_infer(
 +        r#"
 +        //- /main.rs env:foo=bar
 +        #[rustc_builtin_macro]
 +        macro_rules! env {() => {}}
 +
 +        fn main() {
 +            let x = env!("foo");
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..22 '"__RA_...TED__"': &str
 +            62..90 '{     ...o"); }': ()
 +            72..73 'x': &str
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_derive_clone_simple() {
 +    check_types(
 +        r#"
 +//- minicore: derive, clone
 +#[derive(Clone)]
 +struct S;
 +fn test() {
 +    S.clone();
 +} //^^^^^^^^^ S
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_derive_clone_with_params() {
 +    check_types(
 +        r#"
 +//- minicore: clone, derive
 +#[derive(Clone)]
 +struct S;
 +#[derive(Clone)]
 +struct Wrapper<T>(T);
 +struct NonClone;
 +fn test() {
 +    let x = (Wrapper(S).clone(), Wrapper(NonClone).clone());
 +    x;
 +  //^ (Wrapper<S>, {unknown})
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_custom_derive_simple() {
 +    // FIXME: this test current now do nothing
 +    check_types(
 +        r#"
 +//- minicore: derive
 +use foo::Foo;
 +
 +#[derive(Foo)]
 +struct S{}
 +
 +fn test() {
 +    S{};
 +} //^^^ S
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn macro_in_arm() {
 +    check_infer(
 +        r#"
 +        macro_rules! unit {
 +            () => { () };
 +        }
 +
 +        fn main() {
 +            let x = match () {
 +                unit!() => 92u32,
 +            };
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..2 '()': ()
 +            51..110 '{     ...  }; }': ()
 +            61..62 'x': u32
 +            65..107 'match ...     }': u32
 +            71..73 '()': ()
 +            95..100 '92u32': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn macro_in_type_alias_position() {
 +    check_infer(
 +        r#"
 +        macro_rules! U32 {
 +            () => { u32 };
 +        }
 +
 +        trait Foo {
 +            type Ty;
 +        }
 +
 +        impl<T> Foo for T {
 +            type Ty = U32!();
 +        }
 +
 +        type TayTo = U32!();
 +
 +        fn testy() {
 +            let a: <() as Foo>::Ty;
 +            let b: TayTo;
 +        }
 +        "#,
 +        expect![[r#"
 +            147..196 '{     ...yTo; }': ()
 +            157..158 'a': u32
 +            185..186 'b': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn nested_macro_in_type_alias_position() {
 +    check_infer(
 +        r#"
 +        macro_rules! U32Inner2 {
 +            () => { u32 };
 +        }
 +
 +        macro_rules! U32Inner1 {
 +            () => { U32Inner2!() };
 +        }
 +
 +        macro_rules! U32 {
 +            () => { U32Inner1!() };
 +        }
 +
 +        trait Foo {
 +            type Ty;
 +        }
 +
 +        impl<T> Foo for T {
 +            type Ty = U32!();
 +        }
 +
 +        type TayTo = U32!();
 +
 +        fn testy() {
 +            let a: <() as Foo>::Ty;
 +            let b: TayTo;
 +        }
 +        "#,
 +        expect![[r#"
 +            259..308 '{     ...yTo; }': ()
 +            269..270 'a': u32
 +            297..298 'b': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn macros_in_type_alias_position_generics() {
 +    check_infer(
 +        r#"
 +        struct Foo<A, B>(A, B);
 +
 +        macro_rules! U32 {
 +            () => { u32 };
 +        }
 +
 +        macro_rules! Bar {
 +            () => { Foo<U32!(), U32!()> };
 +        }
 +
 +        trait Moo {
 +            type Ty;
 +        }
 +
 +        impl<T> Moo for T {
 +            type Ty = Bar!();
 +        }
 +
 +        type TayTo = Bar!();
 +
 +        fn main() {
 +            let a: <() as Moo>::Ty;
 +            let b: TayTo;
 +        }
 +        "#,
 +        expect![[r#"
 +            228..277 '{     ...yTo; }': ()
 +            238..239 'a': Foo<u32, u32>
 +            266..267 'b': Foo<u32, u32>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn macros_in_type_position() {
 +    check_infer(
 +        r#"
 +        struct Foo<A, B>(A, B);
 +
 +        macro_rules! U32 {
 +            () => { u32 };
 +        }
 +
 +        macro_rules! Bar {
 +            () => { Foo<U32!(), U32!()> };
 +        }
 +
 +        fn main() {
 +            let a: Bar!();
 +        }
 +        "#,
 +        expect![[r#"
 +            133..155 '{     ...!(); }': ()
 +            143..144 'a': Foo<u32, u32>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn macros_in_type_generics() {
 +    check_infer(
 +        r#"
 +        struct Foo<A, B>(A, B);
 +
 +        macro_rules! U32 {
 +            () => { u32 };
 +        }
 +
 +        macro_rules! Bar {
 +            () => { Foo<U32!(), U32!()> };
 +        }
 +
 +        trait Moo {
 +            type Ty;
 +        }
 +
 +        impl<T> Moo for T {
 +            type Ty = Foo<Bar!(), Bar!()>;
 +        }
 +
 +        type TayTo = Foo<Bar!(), U32!()>;
 +
 +        fn main() {
 +            let a: <() as Moo>::Ty;
 +            let b: TayTo;
 +        }
 +        "#,
 +        expect![[r#"
 +            254..303 '{     ...yTo; }': ()
 +            264..265 'a': Foo<Foo<u32, u32>, Foo<u32, u32>>
 +            292..293 'b': Foo<Foo<u32, u32>, u32>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infinitely_recursive_macro_type() {
 +    check_infer(
 +        r#"
 +        struct Bar<T, X>(T, X);
 +
 +        macro_rules! Foo {
 +            () => { Foo!() }
 +        }
 +
 +        macro_rules! U32 {
 +            () => { u32 }
 +        }
 +
 +        type A = Foo!();
 +        type B = Bar<Foo!(), U32!()>;
 +
 +        fn main() {
 +            let a: A;
 +            let b: B;
 +        }
 +        "#,
 +        expect![[r#"
 +            166..197 '{     ...: B; }': ()
 +            176..177 'a': {unknown}
 +            190..191 'b': Bar<{unknown}, u32>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn cfg_tails() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- /lib.rs crate:foo cfg:feature=foo
 +struct S {}
 +
 +impl S {
 +    fn new2(bar: u32) -> Self {
 +        #[cfg(feature = "foo")]
 +        { Self { } }
 +        #[cfg(not(feature = "foo"))]
 +        { Self { } }
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            34..37 'bar': u32
 +            52..170 '{     ...     }': S
 +            62..106 '#[cfg(... { } }': S
 +            96..104 'Self { }': S
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_in_unexpandable_attr_proc_macro_1() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:mac
 +#[mac::attr_macro]
 +fn foo() {
 +    let xxx = 1;
 +      //^^^ i32
 +}
 +
 +//- /mac.rs crate:mac
 +#![crate_type="proc-macro"]
 +#[proc_macro_attribute]
 +pub fn attr_macro() {}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_in_unexpandable_attr_proc_macro_in_impl() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:mac
 +struct Foo;
 +impl Foo {
 +    #[mac::attr_macro]
 +    fn foo() {
 +        let xxx = 1;
 +          //^^^ i32
 +    }
 +}
 +
 +//- /mac.rs crate:mac
 +#![crate_type="proc-macro"]
 +#[proc_macro_attribute]
 +pub fn attr_macro() {}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_in_unexpandable_attr_proc_macro_in_trait() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:mac
 +trait Foo {
 +    #[mac::attr_macro]
 +    fn foo() {
 +        let xxx = 1;
 +          //^^^ i32
 +    }
 +}
 +
 +//- /mac.rs crate:mac
 +#![crate_type="proc-macro"]
 +#[proc_macro_attribute]
 +pub fn attr_macro() {}
 +"#,
 +    );
 +}
index c7895db1afbf5e523a3e6c9a03f09df74cd0aa73,0000000000000000000000000000000000000000..23e51a9c16a5600138e3e519e2ae952c4a68c95e
mode 100644,000000..100644
--- /dev/null
@@@ -1,1695 -1,0 +1,1693 @@@
-             !0..16 'let_a=...t_b=1;': ()
 +use expect_test::expect;
 +
 +use super::{check_infer, check_no_mismatches, check_types};
 +
 +#[test]
 +fn bug_484() {
 +    check_infer(
 +        r#"
 +        fn test() {
 +            let x = if true {};
 +        }
 +        "#,
 +        expect![[r#"
 +            10..37 '{     ... {}; }': ()
 +            20..21 'x': ()
 +            24..34 'if true {}': ()
 +            27..31 'true': bool
 +            32..34 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn no_panic_on_field_of_enum() {
 +    check_infer(
 +        r#"
 +        enum X {}
 +
 +        fn test(x: X) {
 +            x.some_field;
 +        }
 +        "#,
 +        expect![[r#"
 +            19..20 'x': X
 +            25..46 '{     ...eld; }': ()
 +            31..32 'x': X
 +            31..43 'x.some_field': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn bug_585() {
 +    check_infer(
 +        r#"
 +        fn test() {
 +            X {};
 +            match x {
 +                A::B {} => (),
 +                A::Y() => (),
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            10..88 '{     ...   } }': ()
 +            16..20 'X {}': {unknown}
 +            26..86 'match ...     }': ()
 +            32..33 'x': {unknown}
 +            44..51 'A::B {}': {unknown}
 +            55..57 '()': ()
 +            67..73 'A::Y()': {unknown}
 +            77..79 '()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn bug_651() {
 +    check_infer(
 +        r#"
 +        fn quux() {
 +            let y = 92;
 +            1 + y;
 +        }
 +        "#,
 +        expect![[r#"
 +            10..40 '{     ...+ y; }': ()
 +            20..21 'y': i32
 +            24..26 '92': i32
 +            32..33 '1': i32
 +            32..37 '1 + y': i32
 +            36..37 'y': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn recursive_vars() {
 +    check_infer(
 +        r#"
 +        fn test() {
 +            let y = unknown;
 +            [y, &y];
 +        }
 +        "#,
 +        expect![[r#"
 +            10..47 '{     ...&y]; }': ()
 +            20..21 'y': {unknown}
 +            24..31 'unknown': {unknown}
 +            37..44 '[y, &y]': [{unknown}; 2]
 +            38..39 'y': {unknown}
 +            41..43 '&y': &{unknown}
 +            42..43 'y': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn recursive_vars_2() {
 +    check_infer(
 +        r#"
 +        fn test() {
 +            let x = unknown;
 +            let y = unknown;
 +            [(x, y), (&y, &x)];
 +        }
 +        "#,
 +        expect![[r#"
 +            10..79 '{     ...x)]; }': ()
 +            20..21 'x': &{unknown}
 +            24..31 'unknown': &{unknown}
 +            41..42 'y': {unknown}
 +            45..52 'unknown': {unknown}
 +            58..76 '[(x, y..., &x)]': [(&{unknown}, {unknown}); 2]
 +            59..65 '(x, y)': (&{unknown}, {unknown})
 +            60..61 'x': &{unknown}
 +            63..64 'y': {unknown}
 +            67..75 '(&y, &x)': (&{unknown}, {unknown})
 +            68..70 '&y': &{unknown}
 +            69..70 'y': {unknown}
 +            72..74 '&x': &&{unknown}
 +            73..74 'x': &{unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn array_elements_expected_type() {
 +    check_no_mismatches(
 +        r#"
 +        fn test() {
 +            let x: [[u32; 2]; 2] = [[1, 2], [3, 4]];
 +        }
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_std_crash_1() {
 +    // caused stack overflow, taken from std
 +    check_infer(
 +        r#"
 +        enum Maybe<T> {
 +            Real(T),
 +            Fake,
 +        }
 +
 +        fn write() {
 +            match something_unknown {
 +                Maybe::Real(ref mut something) => (),
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            53..138 '{     ...   } }': ()
 +            59..136 'match ...     }': ()
 +            65..82 'someth...nknown': Maybe<{unknown}>
 +            93..123 'Maybe:...thing)': Maybe<{unknown}>
 +            105..122 'ref mu...ething': &mut {unknown}
 +            127..129 '()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_std_crash_2() {
 +    // caused "equating two type variables, ...", taken from std
 +    check_infer(
 +        r#"
 +        fn test_line_buffer() {
 +            &[0, b'\n', 1, b'\n'];
 +        }
 +        "#,
 +        expect![[r#"
 +            22..52 '{     ...n']; }': ()
 +            28..49 '&[0, b...b'\n']': &[u8; 4]
 +            29..49 '[0, b'...b'\n']': [u8; 4]
 +            30..31 '0': u8
 +            33..38 'b'\n'': u8
 +            40..41 '1': u8
 +            43..48 'b'\n'': u8
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_std_crash_3() {
 +    // taken from rustc
 +    check_infer(
 +        r#"
 +        pub fn compute() {
 +            match nope!() {
 +                SizeSkeleton::Pointer { non_zero: true, tail } => {}
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            17..107 '{     ...   } }': ()
 +            23..105 'match ...     }': ()
 +            29..36 'nope!()': {unknown}
 +            47..93 'SizeSk...tail }': {unknown}
 +            81..85 'true': bool
 +            81..85 'true': bool
 +            87..91 'tail': {unknown}
 +            97..99 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_std_crash_4() {
 +    // taken from rustc
 +    check_infer(
 +        r#"
 +        pub fn primitive_type() {
 +            match *self {
 +                BorrowedRef { type_: Primitive(p), ..} => {},
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            24..105 '{     ...   } }': ()
 +            30..103 'match ...     }': ()
 +            36..41 '*self': {unknown}
 +            37..41 'self': {unknown}
 +            52..90 'Borrow...), ..}': {unknown}
 +            73..85 'Primitive(p)': {unknown}
 +            83..84 'p': {unknown}
 +            94..96 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_std_crash_5() {
 +    // taken from rustc
 +    check_infer(
 +        r#"
 +        fn extra_compiler_flags() {
 +            for content in doesnt_matter {
 +                let name = if doesnt_matter {
 +                    first
 +                } else {
 +                    &content
 +                };
 +
 +                let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) {
 +                    name
 +                } else {
 +                    content
 +                };
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            26..322 '{     ...   } }': ()
 +            32..320 'for co...     }': ()
 +            36..43 'content': {unknown}
 +            47..60 'doesnt_matter': {unknown}
 +            61..320 '{     ...     }': ()
 +            75..79 'name': &{unknown}
 +            82..166 'if doe...     }': &{unknown}
 +            85..98 'doesnt_matter': bool
 +            99..128 '{     ...     }': &{unknown}
 +            113..118 'first': &{unknown}
 +            134..166 '{     ...     }': &{unknown}
 +            148..156 '&content': &{unknown}
 +            149..156 'content': {unknown}
 +            181..188 'content': &{unknown}
 +            191..313 'if ICE...     }': &{unknown}
 +            194..231 'ICE_RE..._VALUE': {unknown}
 +            194..247 'ICE_RE...&name)': bool
 +            241..246 '&name': &&{unknown}
 +            242..246 'name': &{unknown}
 +            248..276 '{     ...     }': &{unknown}
 +            262..266 'name': &{unknown}
 +            282..313 '{     ...     }': {unknown}
 +            296..303 'content': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_nested_generics_crash() {
 +    // another crash found typechecking rustc
 +    check_infer(
 +        r#"
 +        struct Canonical<V> {
 +            value: V,
 +        }
 +        struct QueryResponse<V> {
 +            value: V,
 +        }
 +        fn test<R>(query_response: Canonical<QueryResponse<R>>) {
 +            &query_response.value;
 +        }
 +        "#,
 +        expect![[r#"
 +            91..105 'query_response': Canonical<QueryResponse<R>>
 +            136..166 '{     ...lue; }': ()
 +            142..163 '&query....value': &QueryResponse<R>
 +            143..157 'query_response': Canonical<QueryResponse<R>>
 +            143..163 'query_....value': QueryResponse<R>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_paren_macro_call() {
 +    check_infer(
 +        r#"
 +        macro_rules! bar { () => {0u32} }
 +        fn test() {
 +            let a = (bar!());
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..4 '0u32': u32
 +            44..69 '{     ...()); }': ()
 +            54..55 'a': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_array_macro_call() {
 +    check_infer(
 +        r#"
 +        macro_rules! bar { () => {0u32} }
 +        fn test() {
 +            let a = [bar!()];
 +        }
 +        "#,
 +        expect![[r#"
 +            !0..4 '0u32': u32
 +            44..69 '{     ...()]; }': ()
 +            54..55 'a': [u32; 1]
 +            58..66 '[bar!()]': [u32; 1]
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn bug_1030() {
 +    check_infer(
 +        r#"
 +        struct HashSet<T, H>;
 +        struct FxHasher;
 +        type FxHashSet<T> = HashSet<T, FxHasher>;
 +
 +        impl<T, H> HashSet<T, H> {
 +            fn default() -> HashSet<T, H> {}
 +        }
 +
 +        pub fn main_loop() {
 +            FxHashSet::default();
 +        }
 +        "#,
 +        expect![[r#"
 +            143..145 '{}': HashSet<T, H>
 +            168..197 '{     ...t(); }': ()
 +            174..192 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<{unknown}, FxHasher>
 +            174..194 'FxHash...ault()': HashSet<{unknown}, FxHasher>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_2669() {
 +    check_infer(
 +        r#"
 +        trait A {}
 +        trait Write {}
 +        struct Response<T> {}
 +
 +        trait D {
 +            fn foo();
 +        }
 +
 +        impl<T:A> D for Response<T> {
 +            fn foo() {
 +                end();
 +                fn end<W: Write>() {
 +                    let _x: T =  loop {};
 +                }
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            119..214 '{     ...     }': ()
 +            129..132 'end': fn end<{unknown}>()
 +            129..134 'end()': ()
 +            163..208 '{     ...     }': ()
 +            181..183 '_x': !
 +            190..197 'loop {}': !
 +            195..197 '{}': ()
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn issue_2705() {
 +    check_infer(
 +        r#"
 +        trait Trait {}
 +        fn test() {
 +            <Trait<u32>>::foo()
 +        }
 +        "#,
 +        expect![[r#"
 +            25..52 '{     ...oo() }': ()
 +            31..48 '<Trait...>::foo': {unknown}
 +            31..50 '<Trait...:foo()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_2683_chars_impl() {
 +    check_types(
 +        r#"
 +//- minicore: iterator
 +pub struct Chars<'a> {}
 +impl<'a> Iterator for Chars<'a> {
 +    type Item = char;
 +    fn next(&mut self) -> Option<char> { loop {} }
 +}
 +
 +fn test() {
 +    let chars: Chars<'_>;
 +    (chars.next(), chars.nth(1));
 +} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (Option<char>, Option<char>)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn issue_3999_slice() {
 +    check_infer(
 +        r#"
 +        fn foo(params: &[usize]) {
 +            match params {
 +                [ps @ .., _] => {}
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            7..13 'params': &[usize]
 +            25..80 '{     ...   } }': ()
 +            31..78 'match ...     }': ()
 +            37..43 'params': &[usize]
 +            54..66 '[ps @ .., _]': [usize]
 +            55..62 'ps @ ..': &[usize]
 +            60..62 '..': [usize]
 +            64..65 '_': usize
 +            70..72 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_3999_struct() {
 +    // rust-analyzer should not panic on seeing this malformed
 +    // record pattern.
 +    check_infer(
 +        r#"
 +        struct Bar {
 +            a: bool,
 +        }
 +        fn foo(b: Bar) {
 +            match b {
 +                Bar { a: .. } => {},
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            35..36 'b': Bar
 +            43..95 '{     ...   } }': ()
 +            49..93 'match ...     }': ()
 +            55..56 'b': Bar
 +            67..80 'Bar { a: .. }': Bar
 +            76..78 '..': bool
 +            84..86 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4235_name_conflicts() {
 +    check_infer(
 +        r#"
 +        struct FOO {}
 +        static FOO:FOO = FOO {};
 +
 +        impl FOO {
 +            fn foo(&self) {}
 +        }
 +
 +        fn main() {
 +            let a = &FOO;
 +            a.foo();
 +        }
 +        "#,
 +        expect![[r#"
 +            31..37 'FOO {}': FOO
 +            63..67 'self': &FOO
 +            69..71 '{}': ()
 +            85..119 '{     ...o(); }': ()
 +            95..96 'a': &FOO
 +            99..103 '&FOO': &FOO
 +            100..103 'FOO': FOO
 +            109..110 'a': &FOO
 +            109..116 'a.foo()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4465_dollar_crate_at_type() {
 +    check_infer(
 +        r#"
 +        pub struct Foo {}
 +        pub fn anything<T>() -> T {
 +            loop {}
 +        }
 +        macro_rules! foo {
 +            () => {{
 +                let r: $crate::Foo = anything();
 +                r
 +            }};
 +        }
 +        fn main() {
 +            let _a = foo!();
 +        }
 +        "#,
 +        expect![[r#"
 +            44..59 '{     loop {} }': T
 +            50..57 'loop {}': !
 +            55..57 '{}': ()
 +            !0..31 '{letr:...g();r}': Foo
 +            !4..5 'r': Foo
 +            !18..26 'anything': fn anything<Foo>() -> Foo
 +            !18..28 'anything()': Foo
 +            !29..30 'r': Foo
 +            163..187 '{     ...!(); }': ()
 +            173..175 '_a': Foo
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_6811() {
 +    check_infer(
 +        r#"
 +        macro_rules! profile_function {
 +            () => {
 +                let _a = 1;
 +                let _b = 1;
 +            };
 +        }
 +        fn main() {
 +            profile_function!();
 +        }
 +        "#,
 +        expect![[r#"
-     cov_mark::check!(empty_macro_in_trailing_position_is_removed);
 +            !3..5 '_a': i32
 +            !6..7 '1': i32
 +            !11..13 '_b': i32
 +            !14..15 '1': i32
 +            103..131 '{     ...!(); }': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4053_diesel_where_clauses() {
 +    check_infer(
 +        r#"
 +        trait BoxedDsl<DB> {
 +            type Output;
 +            fn internal_into_boxed(self) -> Self::Output;
 +        }
 +
 +        struct SelectStatement<From, Select, Distinct, Where, Order, LimitOffset, GroupBy, Locking> {
 +            order: Order,
 +        }
 +
 +        trait QueryFragment<DB: Backend> {}
 +
 +        trait Into<T> { fn into(self) -> T; }
 +
 +        impl<F, S, D, W, O, LOf, DB> BoxedDsl<DB>
 +            for SelectStatement<F, S, D, W, O, LOf, G>
 +        where
 +            O: Into<dyn QueryFragment<DB>>,
 +        {
 +            type Output = XXX;
 +
 +            fn internal_into_boxed(self) -> Self::Output {
 +                self.order.into();
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            65..69 'self': Self
 +            267..271 'self': Self
 +            466..470 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
 +            488..522 '{     ...     }': ()
 +            498..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
 +            498..508 'self.order': O
 +            498..515 'self.o...into()': dyn QueryFragment<DB>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4953() {
 +    check_infer(
 +        r#"
 +        pub struct Foo(pub i64);
 +        impl Foo {
 +            fn test() -> Self { Self(0i64) }
 +        }
 +        "#,
 +        expect![[r#"
 +            58..72 '{ Self(0i64) }': Foo
 +            60..64 'Self': Foo(i64) -> Foo
 +            60..70 'Self(0i64)': Foo
 +            65..69 '0i64': i64
 +        "#]],
 +    );
 +    check_infer(
 +        r#"
 +        pub struct Foo<T>(pub T);
 +        impl Foo<i64> {
 +            fn test() -> Self { Self(0i64) }
 +        }
 +        "#,
 +        expect![[r#"
 +            64..78 '{ Self(0i64) }': Foo<i64>
 +            66..70 'Self': Foo<i64>(i64) -> Foo<i64>
 +            66..76 'Self(0i64)': Foo<i64>
 +            71..75 '0i64': i64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4931() {
 +    check_infer(
 +        r#"
 +        trait Div<T> {
 +            type Output;
 +        }
 +
 +        trait CheckedDiv: Div<()> {}
 +
 +        trait PrimInt: CheckedDiv<Output = ()> {
 +            fn pow(self);
 +        }
 +
 +        fn check<T: PrimInt>(i: T) {
 +            i.pow();
 +        }
 +        "#,
 +        expect![[r#"
 +            117..121 'self': Self
 +            148..149 'i': T
 +            154..170 '{     ...w(); }': ()
 +            160..161 'i': T
 +            160..167 'i.pow()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4885() {
 +    check_infer(
 +        r#"
 +        //- minicore: coerce_unsized, future
 +        use core::future::Future;
 +        trait Foo<R> {
 +            type Bar;
 +        }
 +        fn foo<R, K>(key: &K) -> impl Future<Output = K::Bar>
 +        where
 +            K: Foo<R>,
 +        {
 +            bar(key)
 +        }
 +        fn bar<R, K>(key: &K) -> impl Future<Output = K::Bar>
 +        where
 +            K: Foo<R>,
 +        {
 +        }
 +        "#,
 +        expect![[r#"
 +            70..73 'key': &K
 +            132..148 '{     ...key) }': impl Future<Output = <K as Foo<R>>::Bar>
 +            138..141 'bar': fn bar<R, K>(&K) -> impl Future<Output = <K as Foo<R>>::Bar>
 +            138..146 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar>
 +            142..145 'key': &K
 +            162..165 'key': &K
 +            224..227 '{ }': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4800() {
 +    check_infer(
 +        r#"
 +        trait Debug {}
 +
 +        struct Foo<T>;
 +
 +        type E1<T> = (T, T, T);
 +        type E2<T> = E1<E1<E1<(T, T, T)>>>;
 +
 +        impl Debug for Foo<E2<()>> {}
 +
 +        struct Request;
 +
 +        pub trait Future {
 +            type Output;
 +        }
 +
 +        pub struct PeerSet<D>;
 +
 +        impl<D> Service<Request> for PeerSet<D>
 +        where
 +            D: Discover,
 +            D::Key: Debug,
 +        {
 +            type Error = ();
 +            type Future = dyn Future<Output = Self::Error>;
 +
 +            fn call(&mut self) -> Self::Future {
 +                loop {}
 +            }
 +        }
 +
 +        pub trait Discover {
 +            type Key;
 +        }
 +
 +        pub trait Service<Request> {
 +            type Error;
 +            type Future: Future<Output = Self::Error>;
 +            fn call(&mut self) -> Self::Future;
 +        }
 +        "#,
 +        expect![[r#"
 +            379..383 'self': &mut PeerSet<D>
 +            401..424 '{     ...     }': dyn Future<Output = ()>
 +            411..418 'loop {}': !
 +            416..418 '{}': ()
 +            575..579 'self': &mut Self
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_4966() {
 +    check_infer(
 +        r#"
 +        //- minicore: deref
 +        pub trait IntoIterator {
 +            type Item;
 +        }
 +
 +        struct Repeat<A> { element: A }
 +
 +        struct Map<F> { f: F }
 +
 +        struct Vec<T> {}
 +
 +        impl<T> core::ops::Deref for Vec<T> {
 +            type Target = [T];
 +        }
 +
 +        fn from_iter<A, T: IntoIterator<Item = A>>(iter: T) -> Vec<A> {}
 +
 +        fn main() {
 +            let inner = Map { f: |_: &f64| 0.0 };
 +
 +            let repeat = Repeat { element: inner };
 +
 +            let vec = from_iter(repeat);
 +
 +            vec.foo_bar();
 +        }
 +        "#,
 +        expect![[r#"
 +            225..229 'iter': T
 +            244..246 '{}': Vec<A>
 +            258..402 '{     ...r(); }': ()
 +            268..273 'inner': Map<|&f64| -> f64>
 +            276..300 'Map { ... 0.0 }': Map<|&f64| -> f64>
 +            285..298 '|_: &f64| 0.0': |&f64| -> f64
 +            286..287 '_': &f64
 +            295..298 '0.0': f64
 +            311..317 'repeat': Repeat<Map<|&f64| -> f64>>
 +            320..345 'Repeat...nner }': Repeat<Map<|&f64| -> f64>>
 +            338..343 'inner': Map<|&f64| -> f64>
 +            356..359 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
 +            362..371 'from_iter': fn from_iter<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>, Repeat<Map<|&f64| -> f64>>>(Repeat<Map<|&f64| -> f64>>) -> Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
 +            362..379 'from_i...epeat)': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
 +            372..378 'repeat': Repeat<Map<|&f64| -> f64>>
 +            386..389 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
 +            386..399 'vec.foo_bar()': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_6628() {
 +    check_infer(
 +        r#"
 +//- minicore: fn
 +struct S<T>();
 +impl<T> S<T> {
 +    fn f(&self, _t: T) {}
 +    fn g<F: FnOnce(&T)>(&self, _f: F) {}
 +}
 +fn main() {
 +    let s = S();
 +    s.g(|_x| {});
 +    s.f(10);
 +}
 +"#,
 +        expect![[r#"
 +            40..44 'self': &S<T>
 +            46..48 '_t': T
 +            53..55 '{}': ()
 +            81..85 'self': &S<T>
 +            87..89 '_f': F
 +            94..96 '{}': ()
 +            109..160 '{     ...10); }': ()
 +            119..120 's': S<i32>
 +            123..124 'S': S<i32>() -> S<i32>
 +            123..126 'S()': S<i32>
 +            132..133 's': S<i32>
 +            132..144 's.g(|_x| {})': ()
 +            136..143 '|_x| {}': |&i32| -> ()
 +            137..139 '_x': &i32
 +            141..143 '{}': ()
 +            150..151 's': S<i32>
 +            150..157 's.f(10)': ()
 +            154..156 '10': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn issue_6852() {
 +    check_infer(
 +        r#"
 +//- minicore: deref
 +use core::ops::Deref;
 +
 +struct BufWriter {}
 +
 +struct Mutex<T> {}
 +struct MutexGuard<'a, T> {}
 +impl<T> Mutex<T> {
 +    fn lock(&self) -> MutexGuard<'_, T> {}
 +}
 +impl<'a, T: 'a> Deref for MutexGuard<'a, T> {
 +    type Target = T;
 +}
 +fn flush(&self) {
 +    let w: &Mutex<BufWriter>;
 +    *(w.lock());
 +}
 +"#,
 +        expect![[r#"
 +            123..127 'self': &Mutex<T>
 +            150..152 '{}': MutexGuard<T>
 +            234..238 'self': &{unknown}
 +            240..290 '{     ...()); }': ()
 +            250..251 'w': &Mutex<BufWriter>
 +            276..287 '*(w.lock())': BufWriter
 +            278..279 'w': &Mutex<BufWriter>
 +            278..286 'w.lock()': MutexGuard<BufWriter>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn param_overrides_fn() {
 +    check_types(
 +        r#"
 +        fn example(example: i32) {
 +            fn f() {}
 +            example;
 +          //^^^^^^^ i32
 +        }
 +        "#,
 +    )
 +}
 +
 +#[test]
 +fn lifetime_from_chalk_during_deref() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Box<T: ?Sized> {}
 +impl<T: ?Sized> core::ops::Deref for Box<T> {
 +    type Target = T;
 +
 +    fn deref(&self) -> &Self::Target {
 +        loop {}
 +    }
 +}
 +
 +trait Iterator {
 +    type Item;
 +}
 +
 +pub struct Iter<'a, T: 'a> {
 +    inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>,
 +}
 +
 +trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> {
 +    fn clone_box(&self);
 +}
 +
 +fn clone_iter<T>(s: Iter<T>) {
 +    s.inner.clone_box();
 +  //^^^^^^^^^^^^^^^^^^^ ()
 +}
 +"#,
 +    )
 +}
 +
 +#[test]
 +fn issue_8686() {
 +    check_infer(
 +        r#"
 +pub trait Try: FromResidual {
 +    type Output;
 +    type Residual;
 +}
 +pub trait FromResidual<R = <Self as Try>::Residual> {
 +     fn from_residual(residual: R) -> Self;
 +}
 +
 +struct ControlFlow<B, C>;
 +impl<B, C> Try for ControlFlow<B, C> {
 +    type Output = C;
 +    type Residual = ControlFlow<B, !>;
 +}
 +impl<B, C> FromResidual for ControlFlow<B, C> {
 +    fn from_residual(r: ControlFlow<B, !>) -> Self { ControlFlow }
 +}
 +
 +fn test() {
 +    ControlFlow::from_residual(ControlFlow::<u32, !>);
 +}
 +        "#,
 +        expect![[r#"
 +            144..152 'residual': R
 +            365..366 'r': ControlFlow<B, !>
 +            395..410 '{ ControlFlow }': ControlFlow<B, C>
 +            397..408 'ControlFlow': ControlFlow<B, C>
 +            424..482 '{     ...!>); }': ()
 +            430..456 'Contro...sidual': fn from_residual<ControlFlow<u32, {unknown}>, ControlFlow<u32, !>>(ControlFlow<u32, !>) -> ControlFlow<u32, {unknown}>
 +            430..479 'Contro...2, !>)': ControlFlow<u32, {unknown}>
 +            457..478 'Contro...32, !>': ControlFlow<u32, !>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn cfg_tail() {
 +    // https://github.com/rust-lang/rust-analyzer/issues/8378
 +    check_infer(
 +        r#"
 +        fn fake_tail(){
 +            { "first" }
 +            #[cfg(never)] 9
 +        }
 +        fn multiple_fake(){
 +            { "fake" }
 +            { "fake" }
 +            { "second" }
 +            #[cfg(never)] { 11 }
 +            #[cfg(never)] 12;
 +            #[cfg(never)] 13
 +        }
 +        fn no_normal_tail(){
 +            { "third" }
 +            #[cfg(never)] 14;
 +            #[cfg(never)] 15;
 +        }
 +        fn no_actual_tail(){
 +            { "fourth" };
 +            #[cfg(never)] 14;
 +            #[cfg(never)] 15
 +        }
 +        "#,
 +        expect![[r#"
 +            14..53 '{     ...)] 9 }': ()
 +            20..31 '{ "first" }': ()
 +            22..29 '"first"': &str
 +            72..190 '{     ...] 13 }': ()
 +            78..88 '{ "fake" }': &str
 +            80..86 '"fake"': &str
 +            93..103 '{ "fake" }': &str
 +            95..101 '"fake"': &str
 +            108..120 '{ "second" }': ()
 +            110..118 '"second"': &str
 +            210..273 '{     ... 15; }': ()
 +            216..227 '{ "third" }': ()
 +            218..225 '"third"': &str
 +            293..357 '{     ...] 15 }': ()
 +            299..311 '{ "fourth" }': &str
 +            301..309 '"fourth"': &str
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn impl_trait_in_option_9530() {
 +    check_types(
 +        r#"
 +//- minicore: sized
 +struct Option<T>;
 +impl<T> Option<T> {
 +    fn unwrap(self) -> T { loop {} }
 +}
 +fn make() -> Option<impl Copy> { Option }
 +trait Copy {}
 +fn test() {
 +    let o = make();
 +    o.unwrap();
 +  //^^^^^^^^^^ impl Copy
 +}
 +        "#,
 +    )
 +}
 +
 +#[test]
 +fn bare_dyn_trait_binders_9639() {
 +    check_no_mismatches(
 +        r#"
 +//- minicore: fn, coerce_unsized
 +fn infix_parse<T, S>(_state: S, _level_code: &Fn(S)) -> T {
 +    loop {}
 +}
 +
 +fn parse_arule() {
 +    infix_parse((), &(|_recurse| ()))
 +}
 +        "#,
 +    )
 +}
 +
 +#[test]
 +fn call_expected_type_closure() {
 +    check_types(
 +        r#"
 +//- minicore: fn, option
 +
 +fn map<T, U>(o: Option<T>, f: impl FnOnce(T) -> U) -> Option<U> { loop {} }
 +struct S {
 +    field: u32
 +}
 +
 +fn test() {
 +    let o = Some(S { field: 2 });
 +    let _: Option<()> = map(o, |s| { s.field; });
 +                                  // ^^^^^^^ u32
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn coerce_diesel_panic() {
 +    check_no_mismatches(
 +        r#"
 +//- minicore: option
 +
 +trait TypeMetadata {
 +    type MetadataLookup;
 +}
 +
 +pub struct Output<'a, T, DB>
 +where
 +    DB: TypeMetadata,
 +    DB::MetadataLookup: 'a,
 +{
 +    out: T,
 +    metadata_lookup: Option<&'a DB::MetadataLookup>,
 +}
 +
 +impl<'a, T, DB: TypeMetadata> Output<'a, T, DB> {
 +    pub fn new(out: T, metadata_lookup: &'a DB::MetadataLookup) -> Self {
 +        Output {
 +            out,
 +            metadata_lookup: Some(metadata_lookup),
 +        }
 +    }
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn bitslice_panic() {
 +    check_no_mismatches(
 +        r#"
 +//- minicore: option, deref
 +
 +pub trait BitView {
 +    type Store;
 +}
 +
 +pub struct Lsb0;
 +
 +pub struct BitArray<V: BitView> { }
 +
 +pub struct BitSlice<T> { }
 +
 +impl<V: BitView> core::ops::Deref for BitArray<V> {
 +    type Target = BitSlice<V::Store>;
 +}
 +
 +impl<T> BitSlice<T> {
 +    pub fn split_first(&self) -> Option<(T, &Self)> { loop {} }
 +}
 +
 +fn multiexp_inner() {
 +    let exp: &BitArray<Foo>;
 +    exp.split_first();
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn macro_expands_to_impl_trait() {
 +    check_no_mismatches(
 +        r#"
 +trait Foo {}
 +
 +macro_rules! ty {
 +    () => {
 +        impl Foo
 +    }
 +}
 +
 +fn foo(_: ty!()) {}
 +
 +fn bar() {
 +    foo(());
 +}
 +    "#,
 +    )
 +}
 +
 +#[test]
 +fn nested_macro_in_fn_params() {
 +    check_no_mismatches(
 +        r#"
 +macro_rules! U32Inner {
 +    () => {
 +        u32
 +    };
 +}
 +
 +macro_rules! U32 {
 +    () => {
 +        U32Inner!()
 +    };
 +}
 +
 +fn mamba(a: U32!(), p: u32) -> u32 {
 +    a
 +}
 +    "#,
 +    )
 +}
 +
 +#[test]
 +fn for_loop_block_expr_iterable() {
 +    check_infer(
 +        r#"
 +fn test() {
 +    for _ in { let x = 0; } {
 +        let y = 0;
 +    }
 +}
 +        "#,
 +        expect![[r#"
 +            10..68 '{     ...   } }': ()
 +            16..66 'for _ ...     }': ()
 +            20..21 '_': {unknown}
 +            25..39 '{ let x = 0; }': ()
 +            31..32 'x': i32
 +            35..36 '0': i32
 +            40..66 '{     ...     }': ()
 +            54..55 'y': i32
 +            58..59 '0': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn while_loop_block_expr_iterable() {
 +    check_infer(
 +        r#"
 +fn test() {
 +    while { true } {
 +        let y = 0;
 +    }
 +}
 +        "#,
 +        expect![[r#"
 +            10..59 '{     ...   } }': ()
 +            16..57 'while ...     }': ()
 +            22..30 '{ true }': bool
 +            24..28 'true': bool
 +            31..57 '{     ...     }': ()
 +            45..46 'y': i32
 +            49..50 '0': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn bug_11242() {
 +    // FIXME: wrong, should be u32
 +    check_types(
 +        r#"
 +fn foo<A, B>()
 +where
 +    A: IntoIterator<Item = u32>,
 +    B: IntoIterator<Item = usize>,
 +{
 +    let _x: <A as IntoIterator>::Item;
 +     // ^^ {unknown}
 +}
 +
 +pub trait Iterator {
 +    type Item;
 +}
 +
 +pub trait IntoIterator {
 +    type Item;
 +    type IntoIter: Iterator<Item = Self::Item>;
 +}
 +
 +impl<I: Iterator> IntoIterator for I {
 +    type Item = I::Item;
 +    type IntoIter = I;
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn bug_11659() {
 +    check_no_mismatches(
 +        r#"
 +struct LinkArray<const N: usize, LD>(LD);
 +fn f<const N: usize, LD>(x: LD) -> LinkArray<N, LD> {
 +    let r = LinkArray::<N, LD>(x);
 +    r
 +}
 +
 +fn test() {
 +    let x = f::<2, i32>(5);
 +    let y = LinkArray::<52, LinkArray<2, i32>>(x);
 +}
 +        "#,
 +    );
 +    check_no_mismatches(
 +        r#"
 +struct LinkArray<LD, const N: usize>(LD);
 +fn f<const N: usize, LD>(x: LD) -> LinkArray<LD, N> {
 +    let r = LinkArray::<LD, N>(x);
 +    r
 +}
 +
 +fn test() {
 +    let x = f::<i32, 2>(5);
 +    let y = LinkArray::<LinkArray<i32, 2>, 52>(x);
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn const_generic_error_tolerance() {
 +    check_no_mismatches(
 +        r#"
 +#[lang = "sized"]
 +pub trait Sized {}
 +
 +struct CT<const N: usize, T>(T);
 +struct TC<T, const N: usize>(T);
 +fn f<const N: usize, T>(x: T) -> (CT<N, T>, TC<T, N>) {
 +    let l = CT::<N, T>(x);
 +    let r = TC::<N, T>(x);
 +    (l, r)
 +}
 +
 +trait TR1<const N: usize>;
 +trait TR2<const N: usize>;
 +
 +impl<const N: usize, T> TR1<N> for CT<N, T>;
 +impl<const N: usize, T> TR1<5> for TC<T, N>;
 +impl<const N: usize, T> TR2<N> for CT<T, N>;
 +
 +trait TR3<const N: usize> {
 +    fn tr3(&self) -> &Self;
 +}
 +
 +impl<const N: usize, T> TR3<5> for TC<T, N> {
 +    fn tr3(&self) -> &Self {
 +        self
 +    }
 +}
 +
 +impl<const N: usize, T> TR3<Item = 5> for TC<T, N> {}
 +impl<const N: usize, T> TR3<T> for TC<T, N> {}
 +
 +fn impl_trait<const N: usize>(inp: impl TR1<N>) {}
 +fn dyn_trait<const N: usize>(inp: &dyn TR2<N>) {}
 +fn impl_trait_bad<'a, const N: usize>(inp: impl TR1<i32>) -> impl TR1<'a, i32> {}
 +fn impl_trait_very_bad<const N: usize>(inp: impl TR1<Item = i32>) -> impl TR1<'a, Item = i32, 5, Foo = N> {}
 +
 +fn test() {
 +    f::<2, i32>(5);
 +    f::<2, 2>(5);
 +    f(5);
 +    f::<i32>(5);
 +    CT::<52, CT<2, i32>>(x);
 +    CT::<CT<2, i32>>(x);
 +    impl_trait_bad(5);
 +    impl_trait_bad(12);
 +    TR3<5>::tr3();
 +    TR3<{ 2+3 }>::tr3();
 +    TC::<i32, 10>(5).tr3();
 +    TC::<i32, 20>(5).tr3();
 +    TC::<i32, i32>(5).tr3();
 +    TC::<i32, { 7 + 3 }>(5).tr3();
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn const_generic_impl_trait() {
 +    check_no_mismatches(
 +        r#"
 +        //- minicore: from
 +
 +        struct Foo<T, const M: usize>;
 +
 +        trait Tr<T> {
 +            fn f(T) -> Self;
 +        }
 +
 +        impl<T, const M: usize> Tr<[T; M]> for Foo<T, M> {
 +            fn f(_: [T; M]) -> Self {
 +                Self
 +            }
 +        }
 +
 +        fn test() {
 +            Foo::f([1, 2, 7, 10]);
 +        }
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn nalgebra_factorial() {
 +    check_no_mismatches(
 +        r#"
 +        const FACTORIAL: [u128; 4] = [1, 1, 2, 6];
 +
 +        fn factorial(n: usize) -> u128 {
 +            match FACTORIAL.get(n) {
 +                Some(f) => *f,
 +                None => panic!("{}! is greater than u128::MAX", n),
 +            }
 +        }
 +        "#,
 +    )
 +}
 +
 +#[test]
 +fn regression_11688_1() {
 +    check_no_mismatches(
 +        r#"
 +        pub struct Buffer<T>(T);
 +        type Writer = Buffer<u8>;
 +        impl<T> Buffer<T> {
 +            fn extend_from_array<const N: usize>(&mut self, xs: &[T; N]) {
 +                loop {}
 +            }
 +        }
 +        trait Encode<S> {
 +            fn encode(self, w: &mut Writer, s: &mut S);
 +        }
 +        impl<S> Encode<S> for u8 {
 +            fn encode(self, w: &mut Writer, _: &mut S) {
 +                w.extend_from_array(&self.to_le_bytes());
 +            }
 +        }
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn regression_11688_2() {
 +    check_types(
 +        r#"
 +        union MaybeUninit<T> {
 +            uninit: (),
 +            value: T,
 +        }
 +
 +        impl<T> MaybeUninit<T> {
 +            fn uninit_array<const LEN: usize>() -> [Self; LEN] {
 +                loop {}
 +            }
 +        }
 +
 +        fn main() {
 +            let x = MaybeUninit::<i32>::uninit_array::<1>();
 +              //^ [MaybeUninit<i32>; 1]
 +        }
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn regression_11688_3() {
 +    check_types(
 +        r#"
 +        //- minicore: iterator
 +        struct Ar<T, const N: u8>(T);
 +        fn f<const LEN: usize, T, const BASE: u8>(
 +            num_zeros: usize,
 +        ) -> dyn Iterator<Item = [Ar<T, BASE>; LEN]> {
 +            loop {}
 +        }
 +        fn dynamic_programming() {
 +            for board in f::<9, u8, 7>(1) {
 +              //^^^^^ [Ar<u8, 7>; 9]
 +            }
 +        }
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn regression_11688_4() {
 +    check_types(
 +        r#"
 +        trait Bar<const C: usize> {
 +            fn baz(&self) -> [i32; C];
 +        }
 +
 +        fn foo(x: &dyn Bar<2>) {
 +            x.baz();
 +          //^^^^^^^ [i32; 2]
 +        }
 +        "#,
 +    )
 +}
 +
 +#[test]
 +fn gat_crash_1() {
 +    cov_mark::check!(ignore_gats);
 +    check_no_mismatches(
 +        r#"
 +trait ATrait {}
 +
 +trait Crash {
 +    type Member<const N: usize>: ATrait;
 +    fn new<const N: usize>() -> Self::Member<N>;
 +}
 +
 +fn test<T: Crash>() {
 +    T::new();
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn gat_crash_2() {
 +    check_no_mismatches(
 +        r#"
 +pub struct InlineStorage {}
 +
 +pub struct InlineStorageHandle<T: ?Sized> {}
 +
 +pub unsafe trait Storage {
 +    type Handle<T: ?Sized>;
 +    fn create<T: ?Sized>() -> Self::Handle<T>;
 +}
 +
 +unsafe impl Storage for InlineStorage {
 +    type Handle<T: ?Sized> = InlineStorageHandle<T>;
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn gat_crash_3() {
 +    // FIXME: This test currently crashes rust analyzer in a debug build but not in a
 +    // release build (i.e. for the user). With the assumption that tests will always be run
 +    // in debug mode, we catch the unwind and expect that it panicked. See the
 +    // [`crate::utils::generics`] function for more information.
 +    cov_mark::check!(ignore_gats);
 +    std::panic::catch_unwind(|| {
 +        check_no_mismatches(
 +            r#"
 +trait Collection {
 +    type Item;
 +    type Member<T>: Collection<Item = T>;
 +    fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>;
 +}
 +struct ConstGen<T, const N: usize> {
 +    data: [T; N],
 +}
 +impl<T, const N: usize> Collection for ConstGen<T, N> {
 +    type Item = T;
 +    type Member<U> = ConstGen<U, N>;
 +}
 +        "#,
 +        );
 +    })
 +    .expect_err("must panic");
 +}
 +
 +#[test]
 +fn cfgd_out_self_param() {
 +    cov_mark::check!(cfgd_out_self_param);
 +    check_no_mismatches(
 +        r#"
 +struct S;
 +impl S {
 +    fn f(#[cfg(never)] &self) {}
 +}
 +
 +fn f(s: S) {
 +    s.f();
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn rust_161_option_clone() {
 +    check_types(
 +        r#"
 +//- minicore: option, drop
 +
 +fn test(o: &Option<i32>) {
 +    o.my_clone();
 +  //^^^^^^^^^^^^ Option<i32>
 +}
 +
 +pub trait MyClone: Sized {
 +    fn my_clone(&self) -> Self;
 +}
 +
 +impl<T> const MyClone for Option<T>
 +where
 +    T: ~const MyClone + ~const Drop + ~const Destruct,
 +{
 +    fn my_clone(&self) -> Self {
 +        match self {
 +            Some(x) => Some(x.my_clone()),
 +            None => None,
 +        }
 +    }
 +}
 +
 +impl const MyClone for i32 {
 +    fn my_clone(&self) -> Self {
 +        *self
 +    }
 +}
 +
 +pub trait Destruct {}
 +
 +impl<T: ?Sized> const Destruct for T {}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn rust_162_option_clone() {
 +    check_types(
 +        r#"
 +//- minicore: option, drop
 +
 +fn test(o: &Option<i32>) {
 +    o.my_clone();
 +  //^^^^^^^^^^^^ Option<i32>
 +}
 +
 +pub trait MyClone: Sized {
 +    fn my_clone(&self) -> Self;
 +}
 +
 +impl<T> const MyClone for Option<T>
 +where
 +    T: ~const MyClone + ~const Destruct,
 +{
 +    fn my_clone(&self) -> Self {
 +        match self {
 +            Some(x) => Some(x.my_clone()),
 +            None => None,
 +        }
 +    }
 +}
 +
 +impl const MyClone for i32 {
 +    fn my_clone(&self) -> Self {
 +        *self
 +    }
 +}
 +
 +#[lang = "destruct"]
 +pub trait Destruct {}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn tuple_struct_pattern_with_unmatched_args_crash() {
 +    check_infer(
 +        r#"
 +struct S(usize);
 +fn main() {
 +    let S(.., a, b) = S(1);
 +    let (.., a, b) = (1,);
 +}
 +        "#,
 +        expect![[r#"
 +        27..85 '{     ...1,); }': ()
 +        37..48 'S(.., a, b)': S
 +        43..44 'a': usize
 +        46..47 'b': {unknown}
 +        51..52 'S': S(usize) -> S
 +        51..55 'S(1)': S
 +        53..54 '1': usize
 +        65..75 '(.., a, b)': (i32, {unknown})
 +        70..71 'a': i32
 +        73..74 'b': {unknown}
 +        78..82 '(1,)': (i32,)
 +        79..80 '1': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn trailing_empty_macro() {
 +    check_no_mismatches(
 +        r#"
 +macro_rules! m2 {
 +    ($($t:tt)*) => {$($t)*};
 +}
 +
 +fn macrostmts() -> u8 {
 +    m2! { 0 }
 +    m2! {}
 +}
 +    "#,
 +    );
 +}
index 5b08f552109efe4a533c134e15046079056636ad,0000000000000000000000000000000000000000..4ea103e5d9ec3cf1bc5fc85e4ff0866b18388826
mode 100644,000000..100644
--- /dev/null
@@@ -1,3072 -1,0 +1,3085 @@@
-             612..628 'unimpl...ted!()': Vec<T, A>
 +use expect_test::expect;
 +
 +use super::{check, check_infer, check_no_mismatches, check_types};
 +
 +#[test]
 +fn infer_box() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:std
 +fn test() {
 +    let x = box 1;
 +    let t = (x, box x, box &1, box [1]);
 +    t;
 +} //^ (Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; 1]>)
 +
 +//- /std.rs crate:std
 +#[prelude_import] use prelude::*;
 +mod prelude {}
 +
 +mod boxed {
 +    #[lang = "owned_box"]
 +    pub struct Box<T: ?Sized> {
 +        inner: *mut T,
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_box_with_allocator() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:std
 +fn test() {
 +    let x = box 1;
 +    let t = (x, box x, box &1, box [1]);
 +    t;
 +} //^ (Box<i32, {unknown}>, Box<Box<i32, {unknown}>, {unknown}>, Box<&i32, {unknown}>, Box<[i32; 1], {unknown}>)
 +
 +//- /std.rs crate:std
 +#[prelude_import] use prelude::*;
 +mod boxed {
 +    #[lang = "owned_box"]
 +    pub struct Box<T: ?Sized, A: Allocator> {
 +        inner: *mut T,
 +        allocator: A,
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_adt_self() {
 +    check_types(
 +        r#"
 +enum Nat { Succ(Self), Demo(Nat), Zero }
 +
 +fn test() {
 +    let foo: Nat = Nat::Zero;
 +    if let Nat::Succ(x) = foo {
 +        x;
 +    } //^ Nat
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn self_in_struct_lit() {
 +    check_infer(
 +        r#"
 +        //- /main.rs
 +        struct S<T> { x: T }
 +
 +        impl S<u32> {
 +            fn foo() {
 +                Self { x: 1 };
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            49..79 '{     ...     }': ()
 +            59..72 'Self { x: 1 }': S<u32>
 +            69..70 '1': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn type_alias_in_struct_lit() {
 +    check_infer(
 +        r#"
 +        //- /main.rs
 +        struct S<T> { x: T }
 +
 +        type SS = S<u32>;
 +
 +        fn foo() {
 +            SS { x: 1 };
 +        }
 +        "#,
 +        expect![[r#"
 +            50..70 '{     ...1 }; }': ()
 +            56..67 'SS { x: 1 }': S<u32>
 +            64..65 '1': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_ranges() {
 +    check_types(
 +        r#"
 +//- minicore: range
 +fn test() {
 +    let a = ..;
 +    let b = 1..;
 +    let c = ..2u32;
 +    let d = 1..2usize;
 +    let e = ..=10;
 +    let f = 'a'..='z';
 +
 +    let t = (a, b, c, d, e, f);
 +    t;
 +} //^ (RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_while_let() {
 +    check_types(
 +        r#"
 +enum Option<T> { Some(T), None }
 +
 +fn test() {
 +    let foo: Option<f32> = None;
 +    while let Option::Some(x) = foo {
 +        x;
 +    } //^ f32
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_basics() {
 +    check_infer(
 +        r#"
 +fn test(a: u32, b: isize, c: !, d: &str) {
 +    a;
 +    b;
 +    c;
 +    d;
 +    1usize;
 +    1isize;
 +    "test";
 +    1.0f32;
 +}
 +"#,
 +        expect![[r#"
 +            8..9 'a': u32
 +            16..17 'b': isize
 +            26..27 'c': !
 +            32..33 'd': &str
 +            41..120 '{     ...f32; }': ()
 +            47..48 'a': u32
 +            54..55 'b': isize
 +            61..62 'c': !
 +            68..69 'd': &str
 +            75..81 '1usize': usize
 +            87..93 '1isize': isize
 +            99..105 '"test"': &str
 +            111..117 '1.0f32': f32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_let() {
 +    check_infer(
 +        r#"
 +fn test() {
 +    let a = 1isize;
 +    let b: usize = 1;
 +    let c = b;
 +    let d: u32;
 +    let e;
 +    let f: i32 = e;
 +}
 +"#,
 +        expect![[r#"
 +            10..117 '{     ...= e; }': ()
 +            20..21 'a': isize
 +            24..30 '1isize': isize
 +            40..41 'b': usize
 +            51..52 '1': usize
 +            62..63 'c': usize
 +            66..67 'b': usize
 +            77..78 'd': u32
 +            93..94 'e': i32
 +            104..105 'f': i32
 +            113..114 'e': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_paths() {
 +    check_infer(
 +        r#"
 +fn a() -> u32 { 1 }
 +
 +mod b {
 +    fn c() -> u32 { 1 }
 +}
 +
 +fn test() {
 +    a();
 +    b::c();
 +}
 +"#,
 +        expect![[r#"
 +            14..19 '{ 1 }': u32
 +            16..17 '1': u32
 +            47..52 '{ 1 }': u32
 +            49..50 '1': u32
 +            66..90 '{     ...c(); }': ()
 +            72..73 'a': fn a() -> u32
 +            72..75 'a()': u32
 +            81..85 'b::c': fn c() -> u32
 +            81..87 'b::c()': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_path_type() {
 +    check_infer(
 +        r#"
 +struct S;
 +
 +impl S {
 +    fn foo() -> i32 { 1 }
 +}
 +
 +fn test() {
 +    S::foo();
 +    <S>::foo();
 +}
 +"#,
 +        expect![[r#"
 +            40..45 '{ 1 }': i32
 +            42..43 '1': i32
 +            59..92 '{     ...o(); }': ()
 +            65..71 'S::foo': fn foo() -> i32
 +            65..73 'S::foo()': i32
 +            79..87 '<S>::foo': fn foo() -> i32
 +            79..89 '<S>::foo()': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_struct() {
 +    check_infer(
 +        r#"
 +struct A {
 +    b: B,
 +    c: C,
 +}
 +struct B;
 +struct C(usize);
 +
 +fn test() {
 +    let c = C(1);
 +    B;
 +    let a: A = A { b: B, c: C(1) };
 +    a.b;
 +    a.c;
 +}
 +"#,
 +        expect![[r#"
 +            71..153 '{     ...a.c; }': ()
 +            81..82 'c': C
 +            85..86 'C': C(usize) -> C
 +            85..89 'C(1)': C
 +            87..88 '1': usize
 +            95..96 'B': B
 +            106..107 'a': A
 +            113..132 'A { b:...C(1) }': A
 +            120..121 'B': B
 +            126..127 'C': C(usize) -> C
 +            126..130 'C(1)': C
 +            128..129 '1': usize
 +            138..139 'a': A
 +            138..141 'a.b': B
 +            147..148 'a': A
 +            147..150 'a.c': C
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_enum() {
 +    check_infer(
 +        r#"
 +enum E {
 +    V1 { field: u32 },
 +    V2
 +}
 +fn test() {
 +    E::V1 { field: 1 };
 +    E::V2;
 +}
 +"#,
 +        expect![[r#"
 +            51..89 '{     ...:V2; }': ()
 +            57..75 'E::V1 ...d: 1 }': E
 +            72..73 '1': u32
 +            81..86 'E::V2': E
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_union() {
 +    check_infer(
 +        r#"
 +union MyUnion {
 +    foo: u32,
 +    bar: f32,
 +}
 +
 +fn test() {
 +    let u = MyUnion { foo: 0 };
 +    unsafe { baz(u); }
 +    let u = MyUnion { bar: 0.0 };
 +    unsafe { baz(u); }
 +}
 +
 +unsafe fn baz(u: MyUnion) {
 +    let inner = u.foo;
 +    let inner = u.bar;
 +}
 +"#,
 +        expect![[r#"
 +            57..172 '{     ...); } }': ()
 +            67..68 'u': MyUnion
 +            71..89 'MyUnio...o: 0 }': MyUnion
 +            86..87 '0': u32
 +            95..113 'unsafe...(u); }': ()
 +            95..113 'unsafe...(u); }': ()
 +            104..107 'baz': fn baz(MyUnion)
 +            104..110 'baz(u)': ()
 +            108..109 'u': MyUnion
 +            122..123 'u': MyUnion
 +            126..146 'MyUnio... 0.0 }': MyUnion
 +            141..144 '0.0': f32
 +            152..170 'unsafe...(u); }': ()
 +            152..170 'unsafe...(u); }': ()
 +            161..164 'baz': fn baz(MyUnion)
 +            161..167 'baz(u)': ()
 +            165..166 'u': MyUnion
 +            188..189 'u': MyUnion
 +            200..249 '{     ...bar; }': ()
 +            210..215 'inner': u32
 +            218..219 'u': MyUnion
 +            218..223 'u.foo': u32
 +            233..238 'inner': f32
 +            241..242 'u': MyUnion
 +            241..246 'u.bar': f32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_refs() {
 +    check_infer(
 +        r#"
 +fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
 +    a;
 +    *a;
 +    &a;
 +    &mut a;
 +    b;
 +    *b;
 +    &b;
 +    c;
 +    *c;
 +    d;
 +    *d;
 +}
 +        "#,
 +        expect![[r#"
 +            8..9 'a': &u32
 +            17..18 'b': &mut u32
 +            30..31 'c': *const u32
 +            45..46 'd': *mut u32
 +            58..149 '{     ... *d; }': ()
 +            64..65 'a': &u32
 +            71..73 '*a': u32
 +            72..73 'a': &u32
 +            79..81 '&a': &&u32
 +            80..81 'a': &u32
 +            87..93 '&mut a': &mut &u32
 +            92..93 'a': &u32
 +            99..100 'b': &mut u32
 +            106..108 '*b': u32
 +            107..108 'b': &mut u32
 +            114..116 '&b': &&mut u32
 +            115..116 'b': &mut u32
 +            122..123 'c': *const u32
 +            129..131 '*c': u32
 +            130..131 'c': *const u32
 +            137..138 'd': *mut u32
 +            144..146 '*d': u32
 +            145..146 'd': *mut u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_raw_ref() {
 +    check_infer(
 +        r#"
 +fn test(a: i32) {
 +    &raw mut a;
 +    &raw const a;
 +}
 +"#,
 +        expect![[r#"
 +            8..9 'a': i32
 +            16..53 '{     ...t a; }': ()
 +            22..32 '&raw mut a': *mut i32
 +            31..32 'a': i32
 +            38..50 '&raw const a': *const i32
 +            49..50 'a': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_literals() {
 +    check_infer(
 +        r##"
 +        fn test() {
 +            5i32;
 +            5f32;
 +            5f64;
 +            "hello";
 +            b"bytes";
 +            'c';
 +            b'b';
 +            3.14;
 +            5000;
 +            false;
 +            true;
 +            r#"
 +                //! doc
 +                // non-doc
 +                mod foo {}
 +            "#;
 +            br#"yolo"#;
 +            let a = b"a\x20b\
 +            c";
 +            let b = br"g\
 +h";
 +            let c = br#"x"\"yb"#;
 +        }
 +        "##,
 +        expect![[r##"
 +            18..478 '{     ...     }': ()
 +            32..36 '5i32': i32
 +            50..54 '5f32': f32
 +            68..72 '5f64': f64
 +            86..93 '"hello"': &str
 +            107..115 'b"bytes"': &[u8; 5]
 +            129..132 ''c'': char
 +            146..150 'b'b'': u8
 +            164..168 '3.14': f64
 +            182..186 '5000': i32
 +            200..205 'false': bool
 +            219..223 'true': bool
 +            237..333 'r#"   ...    "#': &str
 +            347..357 'br#"yolo"#': &[u8; 4]
 +            375..376 'a': &[u8; 4]
 +            379..403 'b"a\x2...    c"': &[u8; 4]
 +            421..422 'b': &[u8; 4]
 +            425..433 'br"g\ h"': &[u8; 4]
 +            451..452 'c': &[u8; 6]
 +            455..467 'br#"x"\"yb"#': &[u8; 6]
 +        "##]],
 +    );
 +}
 +
 +#[test]
 +fn infer_unary_op() {
 +    check_infer(
 +        r#"
 +enum SomeType {}
 +
 +fn test(x: SomeType) {
 +    let b = false;
 +    let c = !b;
 +    let a = 100;
 +    let d: i128 = -a;
 +    let e = -100;
 +    let f = !!!true;
 +    let g = !42;
 +    let h = !10u32;
 +    let j = !a;
 +    -3.14;
 +    !3;
 +    -x;
 +    !x;
 +    -"hello";
 +    !"hello";
 +}
 +"#,
 +        expect![[r#"
 +            26..27 'x': SomeType
 +            39..271 '{     ...lo"; }': ()
 +            49..50 'b': bool
 +            53..58 'false': bool
 +            68..69 'c': bool
 +            72..74 '!b': bool
 +            73..74 'b': bool
 +            84..85 'a': i128
 +            88..91 '100': i128
 +            101..102 'd': i128
 +            111..113 '-a': i128
 +            112..113 'a': i128
 +            123..124 'e': i32
 +            127..131 '-100': i32
 +            128..131 '100': i32
 +            141..142 'f': bool
 +            145..152 '!!!true': bool
 +            146..152 '!!true': bool
 +            147..152 '!true': bool
 +            148..152 'true': bool
 +            162..163 'g': i32
 +            166..169 '!42': i32
 +            167..169 '42': i32
 +            179..180 'h': u32
 +            183..189 '!10u32': u32
 +            184..189 '10u32': u32
 +            199..200 'j': i128
 +            203..205 '!a': i128
 +            204..205 'a': i128
 +            211..216 '-3.14': f64
 +            212..216 '3.14': f64
 +            222..224 '!3': i32
 +            223..224 '3': i32
 +            230..232 '-x': {unknown}
 +            231..232 'x': SomeType
 +            238..240 '!x': {unknown}
 +            239..240 'x': SomeType
 +            246..254 '-"hello"': {unknown}
 +            247..254 '"hello"': &str
 +            260..268 '!"hello"': {unknown}
 +            261..268 '"hello"': &str
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_backwards() {
 +    check_infer(
 +        r#"
 +fn takes_u32(x: u32) {}
 +
 +struct S { i32_field: i32 }
 +
 +fn test() -> &mut &f64 {
 +    let a = unknown_function();
 +    takes_u32(a);
 +    let b = unknown_function();
 +    S { i32_field: b };
 +    let c = unknown_function();
 +    &mut &c
 +}
 +"#,
 +        expect![[r#"
 +            13..14 'x': u32
 +            21..23 '{}': ()
 +            77..230 '{     ...t &c }': &mut &f64
 +            87..88 'a': u32
 +            91..107 'unknow...nction': {unknown}
 +            91..109 'unknow...tion()': u32
 +            115..124 'takes_u32': fn takes_u32(u32)
 +            115..127 'takes_u32(a)': ()
 +            125..126 'a': u32
 +            137..138 'b': i32
 +            141..157 'unknow...nction': {unknown}
 +            141..159 'unknow...tion()': i32
 +            165..183 'S { i3...d: b }': S
 +            180..181 'b': i32
 +            193..194 'c': f64
 +            197..213 'unknow...nction': {unknown}
 +            197..215 'unknow...tion()': f64
 +            221..228 '&mut &c': &mut &f64
 +            226..228 '&c': &f64
 +            227..228 'c': f64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_self() {
 +    check_infer(
 +        r#"
 +struct S;
 +
 +impl S {
 +    fn test(&self) {
 +        self;
 +    }
 +    fn test2(self: &Self) {
 +        self;
 +    }
 +    fn test3() -> Self {
 +        S {}
 +    }
 +    fn test4() -> Self {
 +        Self {}
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            33..37 'self': &S
 +            39..60 '{     ...     }': ()
 +            49..53 'self': &S
 +            74..78 'self': &S
 +            87..108 '{     ...     }': ()
 +            97..101 'self': &S
 +            132..152 '{     ...     }': S
 +            142..146 'S {}': S
 +            176..199 '{     ...     }': S
 +            186..193 'Self {}': S
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_self_as_path() {
 +    check_infer(
 +        r#"
 +struct S1;
 +struct S2(isize);
 +enum E {
 +    V1,
 +    V2(u32),
 +}
 +
 +impl S1 {
 +    fn test() {
 +        Self;
 +    }
 +}
 +impl S2 {
 +    fn test() {
 +        Self(1);
 +    }
 +}
 +impl E {
 +    fn test() {
 +        Self::V1;
 +        Self::V2(1);
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            86..107 '{     ...     }': ()
 +            96..100 'Self': S1
 +            134..158 '{     ...     }': ()
 +            144..148 'Self': S2(isize) -> S2
 +            144..151 'Self(1)': S2
 +            149..150 '1': isize
 +            184..230 '{     ...     }': ()
 +            194..202 'Self::V1': E
 +            212..220 'Self::V2': V2(u32) -> E
 +            212..223 'Self::V2(1)': E
 +            221..222 '1': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_binary_op() {
 +    check_infer(
 +        r#"
 +fn f(x: bool) -> i32 {
 +    0i32
 +}
 +
 +fn test() -> bool {
 +    let x = a && b;
 +    let y = true || false;
 +    let z = x == y;
 +    let t = x != y;
 +    let minus_forty: isize = -40isize;
 +    let h = minus_forty <= CONST_2;
 +    let c = f(z || y) + 5;
 +    let d = b;
 +    let g = minus_forty ^= i;
 +    let ten: usize = 10;
 +    let ten_is_eleven = ten == some_num;
 +
 +    ten < 3
 +}
 +"#,
 +        expect![[r#"
 +            5..6 'x': bool
 +            21..33 '{     0i32 }': i32
 +            27..31 '0i32': i32
 +            53..369 '{     ... < 3 }': bool
 +            63..64 'x': bool
 +            67..68 'a': bool
 +            67..73 'a && b': bool
 +            72..73 'b': bool
 +            83..84 'y': bool
 +            87..91 'true': bool
 +            87..100 'true || false': bool
 +            95..100 'false': bool
 +            110..111 'z': bool
 +            114..115 'x': bool
 +            114..120 'x == y': bool
 +            119..120 'y': bool
 +            130..131 't': bool
 +            134..135 'x': bool
 +            134..140 'x != y': bool
 +            139..140 'y': bool
 +            150..161 'minus_forty': isize
 +            171..179 '-40isize': isize
 +            172..179 '40isize': isize
 +            189..190 'h': bool
 +            193..204 'minus_forty': isize
 +            193..215 'minus_...ONST_2': bool
 +            208..215 'CONST_2': isize
 +            225..226 'c': i32
 +            229..230 'f': fn f(bool) -> i32
 +            229..238 'f(z || y)': i32
 +            229..242 'f(z || y) + 5': i32
 +            231..232 'z': bool
 +            231..237 'z || y': bool
 +            236..237 'y': bool
 +            241..242 '5': i32
 +            252..253 'd': {unknown}
 +            256..257 'b': {unknown}
 +            267..268 'g': ()
 +            271..282 'minus_forty': isize
 +            271..287 'minus_...y ^= i': ()
 +            286..287 'i': isize
 +            297..300 'ten': usize
 +            310..312 '10': usize
 +            322..335 'ten_is_eleven': bool
 +            338..341 'ten': usize
 +            338..353 'ten == some_num': bool
 +            345..353 'some_num': usize
 +            360..363 'ten': usize
 +            360..367 'ten < 3': bool
 +            366..367 '3': usize
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_shift_op() {
 +    check_infer(
 +        r#"
 +fn test() {
 +    1u32 << 5u8;
 +    1u32 >> 5u8;
 +}
 +"#,
 +        expect![[r#"
 +            10..47 '{     ...5u8; }': ()
 +            16..20 '1u32': u32
 +            16..27 '1u32 << 5u8': u32
 +            24..27 '5u8': u8
 +            33..37 '1u32': u32
 +            33..44 '1u32 >> 5u8': u32
 +            41..44 '5u8': u8
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_field_autoderef() {
 +    check_infer(
 +        r#"
 +struct A {
 +    b: B,
 +}
 +struct B;
 +
 +fn test1(a: A) {
 +    let a1 = a;
 +    a1.b;
 +    let a2 = &a;
 +    a2.b;
 +    let a3 = &mut a;
 +    a3.b;
 +    let a4 = &&&&&&&a;
 +    a4.b;
 +    let a5 = &mut &&mut &&mut a;
 +    a5.b;
 +}
 +
 +fn test2(a1: *const A, a2: *mut A) {
 +    a1.b;
 +    a2.b;
 +}
 +"#,
 +        expect![[r#"
 +            43..44 'a': A
 +            49..212 '{     ...5.b; }': ()
 +            59..61 'a1': A
 +            64..65 'a': A
 +            71..73 'a1': A
 +            71..75 'a1.b': B
 +            85..87 'a2': &A
 +            90..92 '&a': &A
 +            91..92 'a': A
 +            98..100 'a2': &A
 +            98..102 'a2.b': B
 +            112..114 'a3': &mut A
 +            117..123 '&mut a': &mut A
 +            122..123 'a': A
 +            129..131 'a3': &mut A
 +            129..133 'a3.b': B
 +            143..145 'a4': &&&&&&&A
 +            148..156 '&&&&&&&a': &&&&&&&A
 +            149..156 '&&&&&&a': &&&&&&A
 +            150..156 '&&&&&a': &&&&&A
 +            151..156 '&&&&a': &&&&A
 +            152..156 '&&&a': &&&A
 +            153..156 '&&a': &&A
 +            154..156 '&a': &A
 +            155..156 'a': A
 +            162..164 'a4': &&&&&&&A
 +            162..166 'a4.b': B
 +            176..178 'a5': &mut &&mut &&mut A
 +            181..199 '&mut &...&mut a': &mut &&mut &&mut A
 +            186..199 '&&mut &&mut a': &&mut &&mut A
 +            187..199 '&mut &&mut a': &mut &&mut A
 +            192..199 '&&mut a': &&mut A
 +            193..199 '&mut a': &mut A
 +            198..199 'a': A
 +            205..207 'a5': &mut &&mut &&mut A
 +            205..209 'a5.b': B
 +            223..225 'a1': *const A
 +            237..239 'a2': *mut A
 +            249..272 '{     ...2.b; }': ()
 +            255..257 'a1': *const A
 +            255..259 'a1.b': B
 +            265..267 'a2': *mut A
 +            265..269 'a2.b': B
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_argument_autoderef() {
 +    check_infer(
 +        r#"
 +//- minicore: deref
 +use core::ops::Deref;
 +struct A<T>(T);
 +
 +impl<T> A<T> {
 +    fn foo(&self) -> &T {
 +        &self.0
 +    }
 +}
 +
 +struct B<T>(T);
 +
 +impl<T> Deref for B<T> {
 +    type Target = T;
 +    fn deref(&self) -> &Self::Target {
 +        &self.0
 +    }
 +}
 +
 +fn test() {
 +    let t = A::foo(&&B(B(A(42))));
 +}
 +"#,
 +        expect![[r#"
 +            66..70 'self': &A<T>
 +            78..101 '{     ...     }': &T
 +            88..95 '&self.0': &T
 +            89..93 'self': &A<T>
 +            89..95 'self.0': T
 +            182..186 'self': &B<T>
 +            205..228 '{     ...     }': &T
 +            215..222 '&self.0': &T
 +            216..220 'self': &B<T>
 +            216..222 'self.0': T
 +            242..280 '{     ...))); }': ()
 +            252..253 't': &i32
 +            256..262 'A::foo': fn foo<i32>(&A<i32>) -> &i32
 +            256..277 'A::foo...42))))': &i32
 +            263..276 '&&B(B(A(42)))': &&B<B<A<i32>>>
 +            264..276 '&B(B(A(42)))': &B<B<A<i32>>>
 +            265..266 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>>
 +            265..276 'B(B(A(42)))': B<B<A<i32>>>
 +            267..268 'B': B<A<i32>>(A<i32>) -> B<A<i32>>
 +            267..275 'B(A(42))': B<A<i32>>
 +            269..270 'A': A<i32>(i32) -> A<i32>
 +            269..274 'A(42)': A<i32>
 +            271..273 '42': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_method_argument_autoderef() {
 +    check_infer(
 +        r#"
 +//- minicore: deref
 +use core::ops::Deref;
 +struct A<T>(*mut T);
 +
 +impl<T> A<T> {
 +    fn foo(&self, x: &A<T>) -> &T {
 +        &*x.0
 +    }
 +}
 +
 +struct B<T>(T);
 +
 +impl<T> Deref for B<T> {
 +    type Target = T;
 +    fn deref(&self) -> &Self::Target {
 +        &self.0
 +    }
 +}
 +
 +fn test(a: A<i32>) {
 +    let t = A(0 as *mut _).foo(&&B(B(a)));
 +}
 +"#,
 +        expect![[r#"
 +            71..75 'self': &A<T>
 +            77..78 'x': &A<T>
 +            93..114 '{     ...     }': &T
 +            103..108 '&*x.0': &T
 +            104..108 '*x.0': T
 +            105..106 'x': &A<T>
 +            105..108 'x.0': *mut T
 +            195..199 'self': &B<T>
 +            218..241 '{     ...     }': &T
 +            228..235 '&self.0': &T
 +            229..233 'self': &B<T>
 +            229..235 'self.0': T
 +            253..254 'a': A<i32>
 +            264..310 '{     ...))); }': ()
 +            274..275 't': &i32
 +            278..279 'A': A<i32>(*mut i32) -> A<i32>
 +            278..292 'A(0 as *mut _)': A<i32>
 +            278..307 'A(0 as...B(a)))': &i32
 +            280..281 '0': i32
 +            280..291 '0 as *mut _': *mut i32
 +            297..306 '&&B(B(a))': &&B<B<A<i32>>>
 +            298..306 '&B(B(a))': &B<B<A<i32>>>
 +            299..300 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>>
 +            299..306 'B(B(a))': B<B<A<i32>>>
 +            301..302 'B': B<A<i32>>(A<i32>) -> B<A<i32>>
 +            301..305 'B(a)': B<A<i32>>
 +            303..304 'a': A<i32>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_in_elseif() {
 +    check_infer(
 +        r#"
 +struct Foo { field: i32 }
 +fn main(foo: Foo) {
 +    if true {
 +
 +    } else if false {
 +        foo.field
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            34..37 'foo': Foo
 +            44..108 '{     ...   } }': ()
 +            50..106 'if tru...     }': ()
 +            53..57 'true': bool
 +            58..66 '{      }': ()
 +            72..106 'if fal...     }': ()
 +            75..80 'false': bool
 +            81..106 '{     ...     }': ()
 +            91..94 'foo': Foo
 +            91..100 'foo.field': i32
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn infer_if_match_with_return() {
 +    check_infer(
 +        r#"
 +fn foo() {
 +    let _x1 = if true {
 +        1
 +    } else {
 +        return;
 +    };
 +    let _x2 = if true {
 +        2
 +    } else {
 +        return
 +    };
 +    let _x3 = match true {
 +        true => 3,
 +        _ => {
 +            return;
 +        }
 +    };
 +    let _x4 = match true {
 +        true => 4,
 +        _ => return
 +    };
 +}
 +"#,
 +        expect![[r#"
 +            9..322 '{     ...  }; }': ()
 +            19..22 '_x1': i32
 +            25..79 'if tru...     }': i32
 +            28..32 'true': bool
 +            33..50 '{     ...     }': i32
 +            43..44 '1': i32
 +            56..79 '{     ...     }': i32
 +            66..72 'return': !
 +            89..92 '_x2': i32
 +            95..148 'if tru...     }': i32
 +            98..102 'true': bool
 +            103..120 '{     ...     }': i32
 +            113..114 '2': i32
 +            126..148 '{     ...     }': !
 +            136..142 'return': !
 +            158..161 '_x3': i32
 +            164..246 'match ...     }': i32
 +            170..174 'true': bool
 +            185..189 'true': bool
 +            185..189 'true': bool
 +            193..194 '3': i32
 +            204..205 '_': bool
 +            209..240 '{     ...     }': i32
 +            223..229 'return': !
 +            256..259 '_x4': i32
 +            262..319 'match ...     }': i32
 +            268..272 'true': bool
 +            283..287 'true': bool
 +            283..287 'true': bool
 +            291..292 '4': i32
 +            302..303 '_': bool
 +            307..313 'return': !
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn infer_inherent_method() {
 +    check_infer(
 +        r#"
 +        struct A;
 +
 +        impl A {
 +            fn foo(self, x: u32) -> i32 {}
 +        }
 +
 +        mod b {
 +            impl super::A {
 +                pub fn bar(&self, x: u64) -> i64 {}
 +            }
 +        }
 +
 +        fn test(a: A) {
 +            a.foo(1);
 +            (&a).bar(1);
 +            a.bar(1);
 +        }
 +        "#,
 +        expect![[r#"
 +            31..35 'self': A
 +            37..38 'x': u32
 +            52..54 '{}': i32
 +            106..110 'self': &A
 +            112..113 'x': u64
 +            127..129 '{}': i64
 +            147..148 'a': A
 +            153..201 '{     ...(1); }': ()
 +            159..160 'a': A
 +            159..167 'a.foo(1)': i32
 +            165..166 '1': u32
 +            173..184 '(&a).bar(1)': i64
 +            174..176 '&a': &A
 +            175..176 'a': A
 +            182..183 '1': u64
 +            190..191 'a': A
 +            190..198 'a.bar(1)': i64
 +            196..197 '1': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_inherent_method_str() {
 +    check_infer(
 +        r#"
 +        #[lang = "str"]
 +        impl str {
 +            fn foo(&self) -> i32 {}
 +        }
 +
 +        fn test() {
 +            "foo".foo();
 +        }
 +        "#,
 +        expect![[r#"
 +            39..43 'self': &str
 +            52..54 '{}': i32
 +            68..88 '{     ...o(); }': ()
 +            74..79 '"foo"': &str
 +            74..85 '"foo".foo()': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_tuple() {
 +    check_infer(
 +        r#"
 +        fn test(x: &str, y: isize) {
 +            let a: (u32, &str) = (1, "a");
 +            let b = (a, x);
 +            let c = (y, x);
 +            let d = (c, x);
 +            let e = (1, "e");
 +            let f = (e, "d");
 +        }
 +        "#,
 +        expect![[r#"
 +            8..9 'x': &str
 +            17..18 'y': isize
 +            27..169 '{     ...d"); }': ()
 +            37..38 'a': (u32, &str)
 +            54..62 '(1, "a")': (u32, &str)
 +            55..56 '1': u32
 +            58..61 '"a"': &str
 +            72..73 'b': ((u32, &str), &str)
 +            76..82 '(a, x)': ((u32, &str), &str)
 +            77..78 'a': (u32, &str)
 +            80..81 'x': &str
 +            92..93 'c': (isize, &str)
 +            96..102 '(y, x)': (isize, &str)
 +            97..98 'y': isize
 +            100..101 'x': &str
 +            112..113 'd': ((isize, &str), &str)
 +            116..122 '(c, x)': ((isize, &str), &str)
 +            117..118 'c': (isize, &str)
 +            120..121 'x': &str
 +            132..133 'e': (i32, &str)
 +            136..144 '(1, "e")': (i32, &str)
 +            137..138 '1': i32
 +            140..143 '"e"': &str
 +            154..155 'f': ((i32, &str), &str)
 +            158..166 '(e, "d")': ((i32, &str), &str)
 +            159..160 'e': (i32, &str)
 +            162..165 '"d"': &str
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_array() {
 +    check_infer(
 +        r#"
 +        fn test(x: &str, y: isize) {
 +            let a = [x];
 +            let b = [a, a];
 +            let c = [b, b];
 +
 +            let d = [y, 1, 2, 3];
 +            let d = [1, y, 2, 3];
 +            let e = [y];
 +            let f = [d, d];
 +            let g = [e, e];
 +
 +            let h = [1, 2];
 +            let i = ["a", "b"];
 +
 +            let b = [a, ["b"]];
 +            let x: [u8; 0] = [];
 +            let y: [u8; 2+2] = [1,2,3,4];
 +        }
 +        "#,
 +        expect![[r#"
 +            8..9 'x': &str
 +            17..18 'y': isize
 +            27..326 '{     ...,4]; }': ()
 +            37..38 'a': [&str; 1]
 +            41..44 '[x]': [&str; 1]
 +            42..43 'x': &str
 +            54..55 'b': [[&str; 1]; 2]
 +            58..64 '[a, a]': [[&str; 1]; 2]
 +            59..60 'a': [&str; 1]
 +            62..63 'a': [&str; 1]
 +            74..75 'c': [[[&str; 1]; 2]; 2]
 +            78..84 '[b, b]': [[[&str; 1]; 2]; 2]
 +            79..80 'b': [[&str; 1]; 2]
 +            82..83 'b': [[&str; 1]; 2]
 +            95..96 'd': [isize; 4]
 +            99..111 '[y, 1, 2, 3]': [isize; 4]
 +            100..101 'y': isize
 +            103..104 '1': isize
 +            106..107 '2': isize
 +            109..110 '3': isize
 +            121..122 'd': [isize; 4]
 +            125..137 '[1, y, 2, 3]': [isize; 4]
 +            126..127 '1': isize
 +            129..130 'y': isize
 +            132..133 '2': isize
 +            135..136 '3': isize
 +            147..148 'e': [isize; 1]
 +            151..154 '[y]': [isize; 1]
 +            152..153 'y': isize
 +            164..165 'f': [[isize; 4]; 2]
 +            168..174 '[d, d]': [[isize; 4]; 2]
 +            169..170 'd': [isize; 4]
 +            172..173 'd': [isize; 4]
 +            184..185 'g': [[isize; 1]; 2]
 +            188..194 '[e, e]': [[isize; 1]; 2]
 +            189..190 'e': [isize; 1]
 +            192..193 'e': [isize; 1]
 +            205..206 'h': [i32; 2]
 +            209..215 '[1, 2]': [i32; 2]
 +            210..211 '1': i32
 +            213..214 '2': i32
 +            225..226 'i': [&str; 2]
 +            229..239 '["a", "b"]': [&str; 2]
 +            230..233 '"a"': &str
 +            235..238 '"b"': &str
 +            250..251 'b': [[&str; 1]; 2]
 +            254..264 '[a, ["b"]]': [[&str; 1]; 2]
 +            255..256 'a': [&str; 1]
 +            258..263 '["b"]': [&str; 1]
 +            259..262 '"b"': &str
 +            274..275 'x': [u8; 0]
 +            287..289 '[]': [u8; 0]
 +            299..300 'y': [u8; 4]
 +            314..323 '[1,2,3,4]': [u8; 4]
 +            315..316 '1': u8
 +            317..318 '2': u8
 +            319..320 '3': u8
 +            321..322 '4': u8
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_struct_generics() {
 +    check_infer(
 +        r#"
 +        struct A<T> {
 +            x: T,
 +        }
 +
 +        fn test(a1: A<u32>, i: i32) {
 +            a1.x;
 +            let a2 = A { x: i };
 +            a2.x;
 +            let a3 = A::<i128> { x: 1 };
 +            a3.x;
 +        }
 +        "#,
 +        expect![[r#"
 +            35..37 'a1': A<u32>
 +            47..48 'i': i32
 +            55..146 '{     ...3.x; }': ()
 +            61..63 'a1': A<u32>
 +            61..65 'a1.x': u32
 +            75..77 'a2': A<i32>
 +            80..90 'A { x: i }': A<i32>
 +            87..88 'i': i32
 +            96..98 'a2': A<i32>
 +            96..100 'a2.x': i32
 +            110..112 'a3': A<i128>
 +            115..133 'A::<i1...x: 1 }': A<i128>
 +            130..131 '1': i128
 +            139..141 'a3': A<i128>
 +            139..143 'a3.x': i128
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_tuple_struct_generics() {
 +    check_infer(
 +        r#"
 +        struct A<T>(T);
 +        enum Option<T> { Some(T), None }
 +        use Option::*;
 +
 +        fn test() {
 +            A(42);
 +            A(42u128);
 +            Some("x");
 +            Option::Some("x");
 +            None;
 +            let x: Option<i64> = None;
 +        }
 +        "#,
 +        expect![[r#"
 +            75..183 '{     ...one; }': ()
 +            81..82 'A': A<i32>(i32) -> A<i32>
 +            81..86 'A(42)': A<i32>
 +            83..85 '42': i32
 +            92..93 'A': A<u128>(u128) -> A<u128>
 +            92..101 'A(42u128)': A<u128>
 +            94..100 '42u128': u128
 +            107..111 'Some': Some<&str>(&str) -> Option<&str>
 +            107..116 'Some("x")': Option<&str>
 +            112..115 '"x"': &str
 +            122..134 'Option::Some': Some<&str>(&str) -> Option<&str>
 +            122..139 'Option...e("x")': Option<&str>
 +            135..138 '"x"': &str
 +            145..149 'None': Option<{unknown}>
 +            159..160 'x': Option<i64>
 +            176..180 'None': Option<i64>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_function_generics() {
 +    check_infer(
 +        r#"
 +        fn id<T>(t: T) -> T { t }
 +
 +        fn test() {
 +            id(1u32);
 +            id::<i128>(1);
 +            let x: u64 = id(1);
 +        }
 +        "#,
 +        expect![[r#"
 +            9..10 't': T
 +            20..25 '{ t }': T
 +            22..23 't': T
 +            37..97 '{     ...(1); }': ()
 +            43..45 'id': fn id<u32>(u32) -> u32
 +            43..51 'id(1u32)': u32
 +            46..50 '1u32': u32
 +            57..67 'id::<i128>': fn id<i128>(i128) -> i128
 +            57..70 'id::<i128>(1)': i128
 +            68..69 '1': i128
 +            80..81 'x': u64
 +            89..91 'id': fn id<u64>(u64) -> u64
 +            89..94 'id(1)': u64
 +            92..93 '1': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_impl_generics_basic() {
 +    check_infer(
 +        r#"
 +        struct A<T1, T2> {
 +            x: T1,
 +            y: T2,
 +        }
 +        impl<Y, X> A<X, Y> {
 +            fn x(self) -> X {
 +                self.x
 +            }
 +            fn y(self) -> Y {
 +                self.y
 +            }
 +            fn z<T>(self, t: T) -> (X, Y, T) {
 +                (self.x, self.y, t)
 +            }
 +        }
 +
 +        fn test() -> i128 {
 +            let a = A { x: 1u64, y: 1i64 };
 +            a.x();
 +            a.y();
 +            a.z(1i128);
 +            a.z::<u128>(1);
 +        }
 +        "#,
 +        expect![[r#"
 +            73..77 'self': A<X, Y>
 +            84..106 '{     ...     }': X
 +            94..98 'self': A<X, Y>
 +            94..100 'self.x': X
 +            116..120 'self': A<X, Y>
 +            127..149 '{     ...     }': Y
 +            137..141 'self': A<X, Y>
 +            137..143 'self.y': Y
 +            162..166 'self': A<X, Y>
 +            168..169 't': T
 +            187..222 '{     ...     }': (X, Y, T)
 +            197..216 '(self.....y, t)': (X, Y, T)
 +            198..202 'self': A<X, Y>
 +            198..204 'self.x': X
 +            206..210 'self': A<X, Y>
 +            206..212 'self.y': Y
 +            214..215 't': T
 +            244..341 '{     ...(1); }': i128
 +            254..255 'a': A<u64, i64>
 +            258..280 'A { x:...1i64 }': A<u64, i64>
 +            265..269 '1u64': u64
 +            274..278 '1i64': i64
 +            286..287 'a': A<u64, i64>
 +            286..291 'a.x()': u64
 +            297..298 'a': A<u64, i64>
 +            297..302 'a.y()': i64
 +            308..309 'a': A<u64, i64>
 +            308..318 'a.z(1i128)': (u64, i64, i128)
 +            312..317 '1i128': i128
 +            324..325 'a': A<u64, i64>
 +            324..338 'a.z::<u128>(1)': (u64, i64, u128)
 +            336..337 '1': u128
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_impl_generics_with_autoderef() {
 +    check_infer(
 +        r#"
 +        enum Option<T> {
 +            Some(T),
 +            None,
 +        }
 +        impl<T> Option<T> {
 +            fn as_ref(&self) -> Option<&T> {}
 +        }
 +        fn test(o: Option<u32>) {
 +            (&o).as_ref();
 +            o.as_ref();
 +        }
 +        "#,
 +        expect![[r#"
 +            77..81 'self': &Option<T>
 +            97..99 '{}': Option<&T>
 +            110..111 'o': Option<u32>
 +            126..164 '{     ...f(); }': ()
 +            132..145 '(&o).as_ref()': Option<&u32>
 +            133..135 '&o': &Option<u32>
 +            134..135 'o': Option<u32>
 +            151..152 'o': Option<u32>
 +            151..161 'o.as_ref()': Option<&u32>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_generic_chain() {
 +    check_infer(
 +        r#"
 +        struct A<T> {
 +            x: T,
 +        }
 +        impl<T2> A<T2> {
 +            fn x(self) -> T2 {
 +                self.x
 +            }
 +        }
 +        fn id<T>(t: T) -> T { t }
 +
 +        fn test() -> i128 {
 +            let x = 1;
 +            let y = id(x);
 +            let a = A { x: id(y) };
 +            let z = id(a.x);
 +            let b = A { x: z };
 +            b.x()
 +        }
 +        "#,
 +        expect![[r#"
 +            52..56 'self': A<T2>
 +            64..86 '{     ...     }': T2
 +            74..78 'self': A<T2>
 +            74..80 'self.x': T2
 +            98..99 't': T
 +            109..114 '{ t }': T
 +            111..112 't': T
 +            134..254 '{     ....x() }': i128
 +            144..145 'x': i128
 +            148..149 '1': i128
 +            159..160 'y': i128
 +            163..165 'id': fn id<i128>(i128) -> i128
 +            163..168 'id(x)': i128
 +            166..167 'x': i128
 +            178..179 'a': A<i128>
 +            182..196 'A { x: id(y) }': A<i128>
 +            189..191 'id': fn id<i128>(i128) -> i128
 +            189..194 'id(y)': i128
 +            192..193 'y': i128
 +            206..207 'z': i128
 +            210..212 'id': fn id<i128>(i128) -> i128
 +            210..217 'id(a.x)': i128
 +            213..214 'a': A<i128>
 +            213..216 'a.x': i128
 +            227..228 'b': A<i128>
 +            231..241 'A { x: z }': A<i128>
 +            238..239 'z': i128
 +            247..248 'b': A<i128>
 +            247..252 'b.x()': i128
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_const() {
 +    check_infer(
 +        r#"
 +        struct Struct;
 +
 +        impl Struct {
 +            const FOO: u32 = 1;
 +        }
 +
 +        enum Enum {}
 +
 +        impl Enum {
 +            const BAR: u32 = 2;
 +        }
 +
 +        trait Trait {
 +            const ID: u32;
 +        }
 +
 +        struct TraitTest;
 +
 +        impl Trait for TraitTest {
 +            const ID: u32 = 5;
 +        }
 +
 +        fn test() {
 +            let x = Struct::FOO;
 +            let y = Enum::BAR;
 +            let z = TraitTest::ID;
 +        }
 +        "#,
 +        expect![[r#"
 +            51..52 '1': u32
 +            104..105 '2': u32
 +            212..213 '5': u32
 +            228..306 '{     ...:ID; }': ()
 +            238..239 'x': u32
 +            242..253 'Struct::FOO': u32
 +            263..264 'y': u32
 +            267..276 'Enum::BAR': u32
 +            286..287 'z': u32
 +            290..303 'TraitTest::ID': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_type_alias() {
 +    check_infer(
 +        r#"
 +        struct A<X, Y> { x: X, y: Y }
 +        type Foo = A<u32, i128>;
 +        type Bar<T> = A<T, u128>;
 +        type Baz<U, V> = A<V, U>;
 +        fn test(x: Foo, y: Bar<&str>, z: Baz<i8, u8>) {
 +            x.x;
 +            x.y;
 +            y.x;
 +            y.y;
 +            z.x;
 +            z.y;
 +        }
 +        mod m {
 +            pub enum Enum {
 +                Foo(u8),
 +            }
 +            pub type Alias = Enum;
 +        }
 +        fn f() {
 +            let e = m::Alias::Foo(0);
 +            let m::Alias::Foo(x) = &e;
 +        }
 +        "#,
 +        expect![[r#"
 +            115..116 'x': A<u32, i128>
 +            123..124 'y': A<&str, u128>
 +            137..138 'z': A<u8, i8>
 +            153..210 '{     ...z.y; }': ()
 +            159..160 'x': A<u32, i128>
 +            159..162 'x.x': u32
 +            168..169 'x': A<u32, i128>
 +            168..171 'x.y': i128
 +            177..178 'y': A<&str, u128>
 +            177..180 'y.x': &str
 +            186..187 'y': A<&str, u128>
 +            186..189 'y.y': u128
 +            195..196 'z': A<u8, i8>
 +            195..198 'z.x': u8
 +            204..205 'z': A<u8, i8>
 +            204..207 'z.y': i8
 +            298..362 '{     ... &e; }': ()
 +            308..309 'e': Enum
 +            312..325 'm::Alias::Foo': Foo(u8) -> Enum
 +            312..328 'm::Ali...Foo(0)': Enum
 +            326..327 '0': u8
 +            338..354 'm::Ali...Foo(x)': Enum
 +            352..353 'x': &u8
 +            357..359 '&e': &Enum
 +            358..359 'e': Enum
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn recursive_type_alias() {
 +    check_infer(
 +        r#"
 +        struct A<X> {}
 +        type Foo = Foo;
 +        type Bar = A<Bar>;
 +        fn test(x: Foo) {}
 +        "#,
 +        expect![[r#"
 +            58..59 'x': {unknown}
 +            66..68 '{}': ()
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn infer_type_param() {
 +    check_infer(
 +        r#"
 +        fn id<T>(x: T) -> T {
 +            x
 +        }
 +
 +        fn clone<T>(x: &T) -> T {
 +            *x
 +        }
 +
 +        fn test() {
 +            let y = 10u32;
 +            id(y);
 +            let x: bool = clone(z);
 +            id::<i128>(1);
 +        }
 +        "#,
 +        expect![[r#"
 +            9..10 'x': T
 +            20..29 '{     x }': T
 +            26..27 'x': T
 +            43..44 'x': &T
 +            55..65 '{     *x }': T
 +            61..63 '*x': T
 +            62..63 'x': &T
 +            77..157 '{     ...(1); }': ()
 +            87..88 'y': u32
 +            91..96 '10u32': u32
 +            102..104 'id': fn id<u32>(u32) -> u32
 +            102..107 'id(y)': u32
 +            105..106 'y': u32
 +            117..118 'x': bool
 +            127..132 'clone': fn clone<bool>(&bool) -> bool
 +            127..135 'clone(z)': bool
 +            133..134 'z': &bool
 +            141..151 'id::<i128>': fn id<i128>(i128) -> i128
 +            141..154 'id::<i128>(1)': i128
 +            152..153 '1': i128
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_const() {
 +    check_infer(
 +        r#"
 +        struct Foo;
 +        impl Foo { const ASSOC_CONST: u32 = 0; }
 +        const GLOBAL_CONST: u32 = 101;
 +        fn test() {
 +            const LOCAL_CONST: u32 = 99;
 +            let x = LOCAL_CONST;
 +            let z = GLOBAL_CONST;
 +            let id = Foo::ASSOC_CONST;
 +        }
 +        "#,
 +        expect![[r#"
 +            48..49 '0': u32
 +            79..82 '101': u32
 +            94..212 '{     ...NST; }': ()
 +            137..138 'x': u32
 +            141..152 'LOCAL_CONST': u32
 +            162..163 'z': u32
 +            166..178 'GLOBAL_CONST': u32
 +            188..190 'id': u32
 +            193..209 'Foo::A..._CONST': u32
 +            125..127 '99': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_static() {
 +    check_infer(
 +        r#"
 +        static GLOBAL_STATIC: u32 = 101;
 +        static mut GLOBAL_STATIC_MUT: u32 = 101;
 +        fn test() {
 +            static LOCAL_STATIC: u32 = 99;
 +            static mut LOCAL_STATIC_MUT: u32 = 99;
 +            let x = LOCAL_STATIC;
 +            let y = LOCAL_STATIC_MUT;
 +            let z = GLOBAL_STATIC;
 +            let w = GLOBAL_STATIC_MUT;
 +        }
 +        "#,
 +        expect![[r#"
 +            28..31 '101': u32
 +            69..72 '101': u32
 +            84..279 '{     ...MUT; }': ()
 +            172..173 'x': u32
 +            176..188 'LOCAL_STATIC': u32
 +            198..199 'y': u32
 +            202..218 'LOCAL_...IC_MUT': u32
 +            228..229 'z': u32
 +            232..245 'GLOBAL_STATIC': u32
 +            255..256 'w': u32
 +            259..276 'GLOBAL...IC_MUT': u32
 +            117..119 '99': u32
 +            160..162 '99': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn shadowing_primitive() {
 +    check_types(
 +        r#"
 +struct i32;
 +struct Foo;
 +
 +impl i32 { fn foo(&self) -> Foo { Foo } }
 +
 +fn main() {
 +    let x: i32 = i32;
 +    x.foo();
 +  //^^^^^^^ Foo
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn const_eval_array_repeat_expr() {
 +    check_types(
 +        r#"
 +fn main() {
 +    const X: usize = 6 - 1;
 +    let t = [(); X + 2];
 +      //^ [(); 7]
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn shadowing_primitive_with_inner_items() {
 +    check_types(
 +        r#"
 +struct i32;
 +struct Foo;
 +
 +impl i32 { fn foo(&self) -> Foo { Foo } }
 +
 +fn main() {
 +    fn inner() {}
 +    let x: i32 = i32;
 +    x.foo();
 +  //^^^^^^^ Foo
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn not_shadowing_primitive_by_module() {
 +    check_types(
 +        r#"
 +//- /str.rs
 +fn foo() {}
 +
 +//- /main.rs
 +mod str;
 +fn foo() -> &'static str { "" }
 +
 +fn main() {
 +    foo();
 +  //^^^^^ &str
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn not_shadowing_module_by_primitive() {
 +    check_types(
 +        r#"
 +//- /str.rs
 +fn foo() -> u32 {0}
 +
 +//- /main.rs
 +mod str;
 +fn foo() -> &'static str { "" }
 +
 +fn main() {
 +    str::foo();
 +  //^^^^^^^^^^ u32
 +}"#,
 +    );
 +}
 +
 +// This test is actually testing the shadowing behavior within hir_def. It
 +// lives here because the testing infrastructure in hir_def isn't currently
 +// capable of asserting the necessary conditions.
 +#[test]
 +fn should_be_shadowing_imports() {
 +    check_types(
 +        r#"
 +mod a {
 +    pub fn foo() -> i8 {0}
 +    pub struct foo { a: i8 }
 +}
 +mod b { pub fn foo () -> u8 {0} }
 +mod c { pub struct foo { a: u8 } }
 +mod d {
 +    pub use super::a::*;
 +    pub use super::c::foo;
 +    pub use super::b::foo;
 +}
 +
 +fn main() {
 +    d::foo();
 +  //^^^^^^^^ u8
 +    d::foo{a:0};
 +  //^^^^^^^^^^^ foo
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn closure_return() {
 +    check_infer(
 +        r#"
 +        fn foo() -> u32 {
 +            let x = || -> usize { return 1; };
 +        }
 +        "#,
 +        expect![[r#"
 +            16..58 '{     ...; }; }': u32
 +            26..27 'x': || -> usize
 +            30..55 '|| -> ...n 1; }': || -> usize
 +            42..55 '{ return 1; }': usize
 +            44..52 'return 1': !
 +            51..52 '1': usize
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn closure_return_unit() {
 +    check_infer(
 +        r#"
 +        fn foo() -> u32 {
 +            let x = || { return; };
 +        }
 +        "#,
 +        expect![[r#"
 +            16..47 '{     ...; }; }': u32
 +            26..27 'x': || -> ()
 +            30..44 '|| { return; }': || -> ()
 +            33..44 '{ return; }': ()
 +            35..41 'return': !
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn closure_return_inferred() {
 +    check_infer(
 +        r#"
 +        fn foo() -> u32 {
 +            let x = || { "test" };
 +        }
 +        "#,
 +        expect![[r#"
 +            16..46 '{     ..." }; }': u32
 +            26..27 'x': || -> &str
 +            30..43 '|| { "test" }': || -> &str
 +            33..43 '{ "test" }': &str
 +            35..41 '"test"': &str
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn fn_pointer_return() {
 +    check_infer(
 +        r#"
 +        struct Vtable {
 +            method: fn(),
 +        }
 +
 +        fn main() {
 +            let vtable = Vtable { method: || {} };
 +            let m = vtable.method;
 +        }
 +        "#,
 +        expect![[r#"
 +            47..120 '{     ...hod; }': ()
 +            57..63 'vtable': Vtable
 +            66..90 'Vtable...| {} }': Vtable
 +            83..88 '|| {}': || -> ()
 +            86..88 '{}': ()
 +            100..101 'm': fn()
 +            104..110 'vtable': Vtable
 +            104..117 'vtable.method': fn()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn block_modifiers_smoke_test() {
 +    check_infer(
 +        r#"
 +//- minicore: future
 +async fn main() {
 +    let x = unsafe { 92 };
 +    let y = async { async { () }.await };
 +    let z = try { () };
 +    let w = const { 92 };
 +    let t = 'a: { 92 };
 +}
 +        "#,
 +        expect![[r#"
 +            16..162 '{     ...2 }; }': ()
 +            26..27 'x': i32
 +            30..43 'unsafe { 92 }': i32
 +            30..43 'unsafe { 92 }': i32
 +            39..41 '92': i32
 +            53..54 'y': impl Future<Output = ()>
 +            57..85 'async ...wait }': ()
 +            57..85 'async ...wait }': impl Future<Output = ()>
 +            65..77 'async { () }': ()
 +            65..77 'async { () }': impl Future<Output = ()>
 +            65..83 'async ....await': ()
 +            73..75 '()': ()
 +            95..96 'z': {unknown}
 +            99..109 'try { () }': ()
 +            99..109 'try { () }': {unknown}
 +            105..107 '()': ()
 +            119..120 'w': i32
 +            123..135 'const { 92 }': i32
 +            123..135 'const { 92 }': i32
 +            131..133 '92': i32
 +            145..146 't': i32
 +            149..159 ''a: { 92 }': i32
 +            155..157 '92': i32
 +        "#]],
 +    )
 +}
 +#[test]
 +fn async_block_early_return() {
 +    check_infer(
 +        r#"
 +//- minicore: future, result, fn
 +fn test<I, E, F: FnMut() -> Fut, Fut: core::future::Future<Output = Result<I, E>>>(f: F) {}
 +
 +fn main() {
 +    async {
 +        return Err(());
 +        Ok(())
 +    };
 +    test(|| async {
 +        return Err(());
 +        Ok(())
 +    });
 +}
 +        "#,
 +        expect![[r#"
 +            83..84 'f': F
 +            89..91 '{}': ()
 +            103..231 '{     ... }); }': ()
 +            109..161 'async ...     }': Result<(), ()>
 +            109..161 'async ...     }': impl Future<Output = Result<(), ()>>
 +            125..139 'return Err(())': !
 +            132..135 'Err': Err<(), ()>(()) -> Result<(), ()>
 +            132..139 'Err(())': Result<(), ()>
 +            136..138 '()': ()
 +            149..151 'Ok': Ok<(), ()>(()) -> Result<(), ()>
 +            149..155 'Ok(())': Result<(), ()>
 +            152..154 '()': ()
 +            167..171 'test': fn test<(), (), || -> impl Future<Output = Result<(), ()>>, impl Future<Output = Result<(), ()>>>(|| -> impl Future<Output = Result<(), ()>>)
 +            167..228 'test(|...    })': ()
 +            172..227 '|| asy...     }': || -> impl Future<Output = Result<(), ()>>
 +            175..227 'async ...     }': Result<(), ()>
 +            175..227 'async ...     }': impl Future<Output = Result<(), ()>>
 +            191..205 'return Err(())': !
 +            198..201 'Err': Err<(), ()>(()) -> Result<(), ()>
 +            198..205 'Err(())': Result<(), ()>
 +            202..204 '()': ()
 +            215..217 'Ok': Ok<(), ()>(()) -> Result<(), ()>
 +            215..221 'Ok(())': Result<(), ()>
 +            218..220 '()': ()
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn infer_generic_from_later_assignment() {
 +    check_infer(
 +        r#"
 +        enum Option<T> { Some(T), None }
 +        use Option::*;
 +
 +        fn test() {
 +            let mut end = None;
 +            loop {
 +                end = Some(true);
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            59..129 '{     ...   } }': ()
 +            69..76 'mut end': Option<bool>
 +            79..83 'None': Option<bool>
 +            89..127 'loop {...     }': !
 +            94..127 '{     ...     }': ()
 +            104..107 'end': Option<bool>
 +            104..120 'end = ...(true)': ()
 +            110..114 'Some': Some<bool>(bool) -> Option<bool>
 +            110..120 'Some(true)': Option<bool>
 +            115..119 'true': bool
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_loop_break_with_val() {
 +    check_infer(
 +        r#"
 +        enum Option<T> { Some(T), None }
 +        use Option::*;
 +
 +        fn test() {
 +            let x = loop {
 +                if false {
 +                    break None;
 +                }
 +
 +                break Some(true);
 +            };
 +        }
 +        "#,
 +        expect![[r#"
 +            59..168 '{     ...  }; }': ()
 +            69..70 'x': Option<bool>
 +            73..165 'loop {...     }': Option<bool>
 +            78..165 '{     ...     }': ()
 +            88..132 'if fal...     }': ()
 +            91..96 'false': bool
 +            97..132 '{     ...     }': ()
 +            111..121 'break None': !
 +            117..121 'None': Option<bool>
 +            142..158 'break ...(true)': !
 +            148..152 'Some': Some<bool>(bool) -> Option<bool>
 +            148..158 'Some(true)': Option<bool>
 +            153..157 'true': bool
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_loop_break_without_val() {
 +    check_infer(
 +        r#"
 +        enum Option<T> { Some(T), None }
 +        use Option::*;
 +
 +        fn test() {
 +            let x = loop {
 +                if false {
 +                    break;
 +                }
 +            };
 +        }
 +        "#,
 +        expect![[r#"
 +            59..136 '{     ...  }; }': ()
 +            69..70 'x': ()
 +            73..133 'loop {...     }': ()
 +            78..133 '{     ...     }': ()
 +            88..127 'if fal...     }': ()
 +            91..96 'false': bool
 +            97..127 '{     ...     }': ()
 +            111..116 'break': !
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_labelled_break_with_val() {
 +    check_infer(
 +        r#"
 +        fn foo() {
 +            let _x = || 'outer: loop {
 +                let inner = 'inner: loop {
 +                    let i = Default::default();
 +                    if (break 'outer i) {
 +                        loop { break 'inner 5i8; };
 +                    } else if true {
 +                        break 'inner 6;
 +                    }
 +                    break 7;
 +                };
 +                break inner < 8;
 +            };
 +        }
 +        "#,
 +        expect![[r#"
 +            9..335 '{     ...  }; }': ()
 +            19..21 '_x': || -> bool
 +            24..332 '|| 'ou...     }': || -> bool
 +            27..332 ''outer...     }': bool
 +            40..332 '{     ...     }': ()
 +            54..59 'inner': i8
 +            62..300 ''inner...     }': i8
 +            75..300 '{     ...     }': ()
 +            93..94 'i': bool
 +            97..113 'Defaul...efault': {unknown}
 +            97..115 'Defaul...ault()': bool
 +            129..269 'if (br...     }': ()
 +            133..147 'break 'outer i': !
 +            146..147 'i': bool
 +            149..208 '{     ...     }': ()
 +            167..193 'loop {...5i8; }': !
 +            172..193 '{ brea...5i8; }': ()
 +            174..190 'break ...er 5i8': !
 +            187..190 '5i8': i8
 +            214..269 'if tru...     }': ()
 +            217..221 'true': bool
 +            222..269 '{     ...     }': ()
 +            240..254 'break 'inner 6': !
 +            253..254 '6': i8
 +            282..289 'break 7': !
 +            288..289 '7': i8
 +            310..325 'break inner < 8': !
 +            316..321 'inner': i8
 +            316..325 'inner < 8': bool
 +            324..325 '8': i8
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_labelled_block_break_with_val() {
 +    check_infer(
 +        r#"
 +fn default<T>() -> T { loop {} }
 +fn foo() {
 +    let _x = 'outer: {
 +        let inner = 'inner: {
 +            let i = default();
 +            if (break 'outer i) {
 +                break 'inner 5i8;
 +            } else if true {
 +                break 'inner 6;
 +            }
 +            break 'inner 'innermost: { 0 };
 +            42
 +        };
 +        break 'outer inner < 8;
 +    };
 +}
 +"#,
 +        expect![[r#"
 +            21..32 '{ loop {} }': T
 +            23..30 'loop {}': !
 +            28..30 '{}': ()
 +            42..381 '{     ...  }; }': ()
 +            52..54 '_x': bool
 +            57..378 ''outer...     }': bool
 +            79..84 'inner': i8
 +            87..339 ''inner...     }': i8
 +            113..114 'i': bool
 +            117..124 'default': fn default<bool>() -> bool
 +            117..126 'default()': bool
 +            140..270 'if (br...     }': ()
 +            144..158 'break 'outer i': !
 +            157..158 'i': bool
 +            160..209 '{     ...     }': ()
 +            178..194 'break ...er 5i8': !
 +            191..194 '5i8': i8
 +            215..270 'if tru...     }': ()
 +            218..222 'true': bool
 +            223..270 '{     ...     }': ()
 +            241..255 'break 'inner 6': !
 +            254..255 '6': i8
 +            283..313 'break ... { 0 }': !
 +            296..313 ''inner... { 0 }': i8
 +            310..311 '0': i8
 +            327..329 '42': i8
 +            349..371 'break ...er < 8': !
 +            362..367 'inner': i8
 +            362..371 'inner < 8': bool
 +            370..371 '8': i8
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn generic_default() {
 +    check_infer(
 +        r#"
 +        struct Thing<T = ()> { t: T }
 +        enum OtherThing<T = ()> {
 +            One { t: T },
 +            Two(T),
 +        }
 +
 +        fn test(t1: Thing, t2: OtherThing, t3: Thing<i32>, t4: OtherThing<i32>) {
 +            t1.t;
 +            t3.t;
 +            match t2 {
 +                OtherThing::One { t } => { t; },
 +                OtherThing::Two(t) => { t; },
 +            }
 +            match t4 {
 +                OtherThing::One { t } => { t; },
 +                OtherThing::Two(t) => { t; },
 +            }
 +        }
 +        "#,
 +        expect![[r#"
 +            97..99 't1': Thing<()>
 +            108..110 't2': OtherThing<()>
 +            124..126 't3': Thing<i32>
 +            140..142 't4': OtherThing<i32>
 +            161..384 '{     ...   } }': ()
 +            167..169 't1': Thing<()>
 +            167..171 't1.t': ()
 +            177..179 't3': Thing<i32>
 +            177..181 't3.t': i32
 +            187..282 'match ...     }': ()
 +            193..195 't2': OtherThing<()>
 +            206..227 'OtherT... { t }': OtherThing<()>
 +            224..225 't': ()
 +            231..237 '{ t; }': ()
 +            233..234 't': ()
 +            247..265 'OtherT...Two(t)': OtherThing<()>
 +            263..264 't': ()
 +            269..275 '{ t; }': ()
 +            271..272 't': ()
 +            287..382 'match ...     }': ()
 +            293..295 't4': OtherThing<i32>
 +            306..327 'OtherT... { t }': OtherThing<i32>
 +            324..325 't': i32
 +            331..337 '{ t; }': ()
 +            333..334 't': i32
 +            347..365 'OtherT...Two(t)': OtherThing<i32>
 +            363..364 't': i32
 +            369..375 '{ t; }': ()
 +            371..372 't': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn generic_default_in_struct_literal() {
 +    check_infer(
 +        r#"
 +        struct Thing<T = ()> { t: T }
 +        enum OtherThing<T = ()> {
 +            One { t: T },
 +            Two(T),
 +        }
 +
 +        fn test() {
 +            let x = Thing { t: loop {} };
 +            let y = Thing { t: () };
 +            let z = Thing { t: 1i32 };
 +            if let Thing { t } = z {
 +                t;
 +            }
 +
 +            let a = OtherThing::One { t: 1i32 };
 +            let b = OtherThing::Two(1i32);
 +        }
 +        "#,
 +        expect![[r#"
 +            99..319 '{     ...32); }': ()
 +            109..110 'x': Thing<!>
 +            113..133 'Thing ...p {} }': Thing<!>
 +            124..131 'loop {}': !
 +            129..131 '{}': ()
 +            143..144 'y': Thing<()>
 +            147..162 'Thing { t: () }': Thing<()>
 +            158..160 '()': ()
 +            172..173 'z': Thing<i32>
 +            176..193 'Thing ...1i32 }': Thing<i32>
 +            187..191 '1i32': i32
 +            199..240 'if let...     }': ()
 +            202..221 'let Th... } = z': bool
 +            206..217 'Thing { t }': Thing<i32>
 +            214..215 't': i32
 +            220..221 'z': Thing<i32>
 +            222..240 '{     ...     }': ()
 +            232..233 't': i32
 +            250..251 'a': OtherThing<i32>
 +            254..281 'OtherT...1i32 }': OtherThing<i32>
 +            275..279 '1i32': i32
 +            291..292 'b': OtherThing<i32>
 +            295..310 'OtherThing::Two': Two<i32>(i32) -> OtherThing<i32>
 +            295..316 'OtherT...(1i32)': OtherThing<i32>
 +            311..315 '1i32': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn generic_default_depending_on_other_type_arg() {
 +    // FIXME: the {unknown} is a bug
 +    check_infer(
 +        r#"
 +        struct Thing<T = u128, F = fn() -> T> { t: T }
 +
 +        fn test(t1: Thing<u32>, t2: Thing) {
 +            t1;
 +            t2;
 +            Thing::<_> { t: 1u32 };
 +        }
 +        "#,
 +        expect![[r#"
 +            56..58 't1': Thing<u32, fn() -> u32>
 +            72..74 't2': Thing<u128, fn() -> u128>
 +            83..130 '{     ...2 }; }': ()
 +            89..91 't1': Thing<u32, fn() -> u32>
 +            97..99 't2': Thing<u128, fn() -> u128>
 +            105..127 'Thing:...1u32 }': Thing<u32, fn() -> {unknown}>
 +            121..125 '1u32': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn generic_default_depending_on_other_type_arg_forward() {
 +    // the {unknown} here is intentional, as defaults are not allowed to
 +    // refer to type parameters coming later
 +    check_infer(
 +        r#"
 +        struct Thing<F = fn() -> T, T = u128> { t: T }
 +
 +        fn test(t1: Thing) {
 +            t1;
 +        }
 +        "#,
 +        expect![[r#"
 +            56..58 't1': Thing<fn() -> {unknown}, u128>
 +            67..78 '{     t1; }': ()
 +            73..75 't1': Thing<fn() -> {unknown}, u128>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_operator_overload() {
 +    check_types(
 +        r#"
 +//- minicore: add
 +struct V2([f32; 2]);
 +
 +impl core::ops::Add<V2> for V2 {
 +    type Output = V2;
 +}
 +
 +fn test() {
 +    let va = V2([0.0, 1.0]);
 +    let vb = V2([0.0, 1.0]);
 +
 +    let r = va + vb;
 +    //      ^^^^^^^ V2
 +}
 +
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_const_params() {
 +    check_infer(
 +        r#"
 +        fn foo<const FOO: usize>() {
 +            let bar = FOO;
 +        }
 +        "#,
 +        expect![[r#"
 +            27..49 '{     ...FOO; }': ()
 +            37..40 'bar': usize
 +            43..46 'FOO': usize
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_inner_type() {
 +    check_infer(
 +        r#"
 +        fn foo() {
 +            struct S { field: u32 }
 +            let s = S { field: 0 };
 +            let f = s.field;
 +        }
 +    "#,
 +        expect![[r#"
 +            9..89 '{     ...eld; }': ()
 +            47..48 's': S
 +            51..65 'S { field: 0 }': S
 +            62..63 '0': u32
 +            75..76 'f': u32
 +            79..80 's': S
 +            79..86 's.field': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_nested_inner_type() {
 +    check_infer(
 +        r#"
 +        fn foo() {
 +            {
 +                let s = S { field: 0 };
 +                let f = s.field;
 +            }
 +            struct S { field: u32 }
 +        }
 +    "#,
 +        expect![[r#"
 +            9..109 '{     ...32 } }': ()
 +            15..79 '{     ...     }': ()
 +            29..30 's': S
 +            33..47 'S { field: 0 }': S
 +            44..45 '0': u32
 +            61..62 'f': u32
 +            65..66 's': S
 +            65..72 's.field': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn inner_use_enum_rename() {
 +    check_infer(
 +        r#"
 +        enum Request {
 +            Info
 +        }
 +
 +        fn f() {
 +            use Request as R;
 +
 +            let r = R::Info;
 +            match r {
 +                R::Info => {}
 +            }
 +        }
 +    "#,
 +        expect![[r#"
 +            34..123 '{     ...   } }': ()
 +            67..68 'r': Request
 +            71..78 'R::Info': Request
 +            84..121 'match ...     }': ()
 +            90..91 'r': Request
 +            102..109 'R::Info': Request
 +            113..115 '{}': ()
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn box_into_vec() {
 +    check_infer(
 +        r#"
 +#[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> {}
 +
 +pub struct Vec<T, A: Allocator = Global> {}
 +
 +#[lang = "slice"]
 +impl<T> [T] {}
 +
 +#[lang = "slice_alloc"]
 +impl<T> [T] {
 +    pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> {
 +        unimplemented!()
 +    }
 +}
 +
 +fn test() {
 +    let vec = <[_]>::into_vec(box [1i32]);
 +    let v: Vec<Box<dyn B>> = <[_]> :: into_vec(box [box Astruct]);
 +}
 +
 +trait B{}
 +struct Astruct;
 +impl B for Astruct {}
 +"#,
 +        expect![[r#"
 +            569..573 'self': Box<[T], A>
 +            602..634 '{     ...     }': Vec<T, A>
 +            648..761 '{     ...t]); }': ()
 +            658..661 'vec': Vec<i32, Global>
 +            664..679 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
 +            664..691 '<[_]>:...1i32])': Vec<i32, Global>
 +            680..690 'box [1i32]': Box<[i32; 1], Global>
 +            684..690 '[1i32]': [i32; 1]
 +            685..689 '1i32': i32
 +            701..702 'v': Vec<Box<dyn B, Global>, Global>
 +            722..739 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
 +            722..758 '<[_]> ...ruct])': Vec<Box<dyn B, Global>, Global>
 +            740..757 'box [b...truct]': Box<[Box<dyn B, Global>; 1], Global>
 +            744..757 '[box Astruct]': [Box<dyn B, Global>; 1]
 +            745..756 'box Astruct': Box<Astruct, Global>
 +            749..756 'Astruct': Astruct
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn cfgd_out_assoc_items() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +impl S {
 +    #[cfg(FALSE)]
 +    const C: S = S;
 +}
 +
 +fn f() {
 +    S::C;
 +  //^^^^ {unknown}
 +}
 +    "#,
 +    )
 +}
 +
 +#[test]
 +fn infer_missing_type() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +fn f() {
 +    let s: = S;
 +      //^ S
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_type_alias_variant() {
 +    check_infer(
 +        r#"
 +type Qux = Foo;
 +enum Foo {
 +    Bar(i32),
 +    Baz { baz: f32 }
 +}
 +
 +fn f() {
 +    match Foo::Bar(3) {
 +        Qux::Bar(bar) => (),
 +        Qux::Baz { baz } => (),
 +    }
 +}
 +    "#,
 +        expect![[r#"
 +            72..166 '{     ...   } }': ()
 +            78..164 'match ...     }': ()
 +            84..92 'Foo::Bar': Bar(i32) -> Foo
 +            84..95 'Foo::Bar(3)': Foo
 +            93..94 '3': i32
 +            106..119 'Qux::Bar(bar)': Foo
 +            115..118 'bar': i32
 +            123..125 '()': ()
 +            135..151 'Qux::B... baz }': Foo
 +            146..149 'baz': f32
 +            155..157 '()': ()
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn infer_boxed_self_receiver() {
 +    check_infer(
 +        r#"
 +//- minicore: deref
 +use core::ops::Deref;
 +
 +struct Box<T>(T);
 +
 +impl<T> Deref for Box<T> {
 +    type Target = T;
 +    fn deref(&self) -> &Self::Target;
 +}
 +
 +struct Foo<T>(T);
 +
 +impl<T> Foo<T> {
 +    fn get_inner<'a>(self: &'a Box<Self>) -> &'a T {}
 +
 +    fn get_self<'a>(self: &'a Box<Self>) -> &'a Self {}
 +
 +    fn into_inner(self: Box<Self>) -> Self {}
 +}
 +
 +fn main() {
 +    let boxed = Box(Foo(0_i32));
 +
 +    let bad1 = boxed.get_inner();
 +    let good1 = Foo::get_inner(&boxed);
 +
 +    let bad2 = boxed.get_self();
 +    let good2 = Foo::get_self(&boxed);
 +
 +    let inner = boxed.into_inner();
 +}
 +        "#,
 +        expect![[r#"
 +            104..108 'self': &Box<T>
 +            188..192 'self': &Box<Foo<T>>
 +            218..220 '{}': &T
 +            242..246 'self': &Box<Foo<T>>
 +            275..277 '{}': &Foo<T>
 +            297..301 'self': Box<Foo<T>>
 +            322..324 '{}': Foo<T>
 +            338..559 '{     ...r(); }': ()
 +            348..353 'boxed': Box<Foo<i32>>
 +            356..359 'Box': Box<Foo<i32>>(Foo<i32>) -> Box<Foo<i32>>
 +            356..371 'Box(Foo(0_i32))': Box<Foo<i32>>
 +            360..363 'Foo': Foo<i32>(i32) -> Foo<i32>
 +            360..370 'Foo(0_i32)': Foo<i32>
 +            364..369 '0_i32': i32
 +            382..386 'bad1': &i32
 +            389..394 'boxed': Box<Foo<i32>>
 +            389..406 'boxed....nner()': &i32
 +            416..421 'good1': &i32
 +            424..438 'Foo::get_inner': fn get_inner<i32>(&Box<Foo<i32>>) -> &i32
 +            424..446 'Foo::g...boxed)': &i32
 +            439..445 '&boxed': &Box<Foo<i32>>
 +            440..445 'boxed': Box<Foo<i32>>
 +            457..461 'bad2': &Foo<i32>
 +            464..469 'boxed': Box<Foo<i32>>
 +            464..480 'boxed....self()': &Foo<i32>
 +            490..495 'good2': &Foo<i32>
 +            498..511 'Foo::get_self': fn get_self<i32>(&Box<Foo<i32>>) -> &Foo<i32>
 +            498..519 'Foo::g...boxed)': &Foo<i32>
 +            512..518 '&boxed': &Box<Foo<i32>>
 +            513..518 'boxed': Box<Foo<i32>>
 +            530..535 'inner': Foo<i32>
 +            538..543 'boxed': Box<Foo<i32>>
 +            538..556 'boxed....nner()': Foo<i32>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn prelude_2015() {
 +    check_types(
 +        r#"
 +//- /main.rs edition:2015 crate:main deps:core
 +fn f() {
 +    Rust;
 +  //^^^^ Rust
 +}
 +
 +//- /core.rs crate:core
 +pub mod prelude {
 +    pub mod rust_2015 {
 +        pub struct Rust;
 +    }
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn legacy_const_generics() {
 +    check_no_mismatches(
 +        r#"
 +#[rustc_legacy_const_generics(1, 3)]
 +fn mixed<const N1: &'static str, const N2: bool>(
 +    a: u8,
 +    b: i8,
 +) {}
 +
 +fn f() {
 +    mixed(0, "", -1, true);
 +    mixed::<"", true>(0, -1);
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn destructuring_assignment_slice() {
 +    check_types(
 +        r#"
 +fn main() {
 +    let a;
 +      //^usize
 +    [a,] = [0usize];
 +
 +    let a;
 +      //^usize
 +    [a, ..] = [0usize; 5];
 +
 +    let a;
 +      //^usize
 +    [.., a] = [0usize; 5];
 +
 +    let a;
 +      //^usize
 +    [.., a, _] = [0usize; 5];
 +
 +    let a;
 +      //^usize
 +    [_, a, ..] = [0usize; 5];
 +
 +    let a: &mut i64 = &mut 0;
 +    [*a, ..] = [1, 2, 3];
 +
 +    let a: usize;
 +    let b;
 +      //^usize
 +    [a, _, b] = [3, 4, 5];
 +      //^usize
 +
 +    let a;
 +      //^i64
 +    let b;
 +      //^i64
 +    [[a, ..], .., [.., b]] = [[1, 2], [3i64, 4], [5, 6], [7, 8]];
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn destructuring_assignment_tuple() {
 +    check_types(
 +        r#"
 +fn main() {
 +    let a;
 +      //^char
 +    let b;
 +      //^i64
 +    (a, b) = ('c', 0i64);
 +
 +    let a;
 +      //^char
 +    (a, ..) = ('c', 0i64);
 +
 +    let a;
 +      //^i64
 +    (.., a) = ('c', 0i64);
 +
 +    let a;
 +      //^char
 +    let b;
 +      //^i64
 +    (a, .., b) = ('c', 0i64);
 +
 +    let a;
 +      //^char
 +    let b;
 +      //^bool
 +    (a, .., b) = ('c', 0i64, true);
 +
 +    let a;
 +      //^i64
 +    let b;
 +      //^bool
 +    (_, a, .., b) = ('c', 0i64, true);
 +
 +    let a;
 +      //^i64
 +    let b;
 +      //^usize
 +    (_, a, .., b) = ('c', 0i64, true, 0usize);
 +
 +    let mut a = 1;
 +      //^^^^^i64
 +    let mut b: i64 = 0;
 +    (a, b) = (b, a);
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn destructuring_assignment_tuple_struct() {
 +    check_types(
 +        r#"
 +struct S2(char, i64);
 +struct S3(char, i64, bool);
 +struct S4(char, i64, bool usize);
 +fn main() {
 +    let a;
 +      //^char
 +    let b;
 +      //^i64
 +    S2(a, b) = S2('c', 0i64);
 +
 +    let a;
 +      //^char
 +    let b;
 +      //^i64
 +    S2(a, .., b) = S2('c', 0i64);
 +
 +    let a;
 +      //^char
 +    let b;
 +      //^bool
 +    S3(a, .., b) = S3('c', 0i64, true);
 +
 +    let a;
 +      //^i64
 +    let b;
 +      //^bool
 +    S3(_, a, .., b) = S3('c', 0i64, true);
 +
 +    let a;
 +      //^i64
 +    let b;
 +      //^usize
 +    S4(_, a, .., b) = S4('c', 0i64, true, 0usize);
 +
 +    struct Swap(i64, i64);
 +
 +    let mut a = 1;
 +      //^^^^^i64
 +    let mut b = 0;
 +      //^^^^^i64
 +    Swap(a, b) = Swap(b, a);
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn destructuring_assignment_struct() {
 +    check_types(
 +        r#"
 +struct S {
 +    a: usize,
 +    b: char,
 +}
 +struct T {
 +    s: S,
 +    t: i64,
 +}
 +
 +fn main() {
 +    let a;
 +      //^usize
 +    let c;
 +      //^char
 +    S { a, b: c } = S { a: 3, b: 'b' };
 +
 +    let a;
 +      //^char
 +    S { b: a, .. } = S { a: 3, b: 'b' };
 +
 +    let a;
 +      //^char
 +    S { b: a, _ } = S { a: 3, b: 'b' };
 +
 +    let a;
 +      //^usize
 +    let c;
 +      //^char
 +    let t;
 +      //^i64
 +    T { s: S { a, b: c }, t } = T { s: S { a: 3, b: 'b' }, t: 0 };
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn destructuring_assignment_nested() {
 +    check_types(
 +        r#"
 +struct S {
 +    a: TS,
 +    b: [char; 3],
 +}
 +struct TS(usize, i64);
 +
 +fn main() {
 +    let a;
 +      //^i32
 +    let b;
 +      //^bool
 +    ([.., a], .., b, _) = ([0, 1, 2], true, 'c');
 +
 +    let a;
 +      //^i32
 +    let b;
 +      //^i32
 +    [(.., a, _), .., (b, ..)] = [(1, 2); 5];
 +
 +    let a;
 +      //^usize
 +    let b;
 +      //^char
 +    S { a: TS(a, ..), b: [_, b, ..] } = S { a: TS(0, 0), b: ['a'; 3] };
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn destructuring_assignment_unit_struct() {
 +    // taken from rustc; see https://github.com/rust-lang/rust/pull/95380
 +    check_no_mismatches(
 +        r#"
 +struct S;
 +enum E { V, }
 +type A = E;
 +
 +fn main() {
 +    let mut a;
 +
 +    (S, a) = (S, ());
 +
 +    (E::V, a) = (E::V, ());
 +
 +    (<E>::V, a) = (E::V, ());
 +    (A::V, a) = (E::V, ());
 +}
 +
 +impl S {
 +    fn check() {
 +        let a;
 +        (Self, a) = (S, ());
 +    }
 +}
 +
 +impl E {
 +    fn check() {
 +        let a;
 +        (Self::V, a) = (E::V, ());
 +    }
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn destructuring_assignment_no_default_binding_mode() {
 +    check(
 +        r#"
 +struct S { a: usize }
 +struct TS(usize);
 +fn main() {
 +    let x;
 +    [x,] = &[1,];
 +  //^^^^expected &[i32; 1], got [{unknown}; _]
 +
 +    // FIXME we only want the outermost error, but this matches the current
 +    // behavior of slice patterns
 +    let x;
 +    [(x,),] = &[(1,),];
 +  // ^^^^expected {unknown}, got ({unknown},)
 +  //^^^^^^^expected &[(i32,); 1], got [{unknown}; _]
 +
 +    let x;
 +    ((x,),) = &((1,),);
 +  //^^^^^^^expected &((i32,),), got (({unknown},),)
 +
 +    let x;
 +    (x,) = &(1,);
 +  //^^^^expected &(i32,), got ({unknown},)
 +
 +    let x;
 +    (S { a: x },) = &(S { a: 42 },);
 +  //^^^^^^^^^^^^^expected &(S,), got (S,)
 +
 +    let x;
 +    S { a: x } = &S { a: 42 };
 +  //^^^^^^^^^^expected &S, got S
 +
 +    let x;
 +    TS(x) = &TS(42);
 +  //^^^^^expected &TS, got TS
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn destructuring_assignment_type_mismatch_on_identifier() {
 +    check(
 +        r#"
 +struct S { v: i64 }
 +struct TS(i64);
 +fn main() {
 +    let mut a: usize = 0;
 +    (a,) = (0i64,);
 +   //^expected i64, got usize
 +
 +    let mut a: usize = 0;
 +    [a,] = [0i64,];
 +   //^expected i64, got usize
 +
 +    let mut a: usize = 0;
 +    S { v: a } = S { v: 0 };
 +         //^expected i64, got usize
 +
 +    let mut a: usize = 0;
 +    TS(a) = TS(0);
 +     //^expected i64, got usize
 +}
 +        "#,
 +    );
 +}
++
++#[test]
++fn nested_break() {
++    check_no_mismatches(
++        r#"
++fn func() {
++    let int = loop {
++        break 0;
++        break (break 0);
++    };
++}
++    "#,
++    );
++}
index 0f37970e2b38d7fe678e101b19873789b2fbdd7e,0000000000000000000000000000000000000000..e67c27aa2db97fb4cff6fd19475fa448aa422cc9
mode 100644,000000..100644
--- /dev/null
@@@ -1,3835 -1,0 +1,3927 @@@
 +use cov_mark::check;
 +use expect_test::expect;
 +
 +use super::{check, check_infer, check_infer_with_mismatches, check_no_mismatches, check_types};
 +
 +#[test]
 +fn infer_await() {
 +    check_types(
 +        r#"
 +//- minicore: future
 +struct IntFuture;
 +
 +impl core::future::Future for IntFuture {
 +    type Output = u64;
 +}
 +
 +fn test() {
 +    let r = IntFuture;
 +    let v = r.await;
 +    v;
 +} //^ u64
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_async() {
 +    check_types(
 +        r#"
 +//- minicore: future
 +async fn foo() -> u64 { 128 }
 +
 +fn test() {
 +    let r = foo();
 +    let v = r.await;
 +    v;
 +} //^ u64
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_desugar_async() {
 +    check_types(
 +        r#"
 +//- minicore: future, sized
 +async fn foo() -> u64 { 128 }
 +
 +fn test() {
 +    let r = foo();
 +    r;
 +} //^ impl Future<Output = u64>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_async_block() {
 +    check_types(
 +        r#"
 +//- minicore: future, option
 +async fn test() {
 +    let a = async { 42 };
 +    a;
 +//  ^ impl Future<Output = i32>
 +    let x = a.await;
 +    x;
 +//  ^ i32
 +    let b = async {}.await;
 +    b;
 +//  ^ ()
 +    let c = async {
 +        let y = None;
 +        y
 +    //  ^ Option<u64>
 +    };
 +    let _: Option<u64> = c.await;
 +    c;
 +//  ^ impl Future<Output = Option<u64>>
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn auto_sized_async_block() {
 +    check_no_mismatches(
 +        r#"
 +//- minicore: future, sized
 +
 +use core::future::Future;
 +struct MyFut<Fut>(Fut);
 +
 +impl<Fut> Future for MyFut<Fut>
 +where Fut: Future
 +{
 +    type Output = Fut::Output;
 +}
 +async fn reproduction() -> usize {
 +    let f = async {999usize};
 +    MyFut(f).await
 +}
 +    "#,
 +    );
 +    check_no_mismatches(
 +        r#"
 +//- minicore: future
 +//#11815
 +#[lang = "sized"]
 +pub trait Sized {}
 +
 +#[lang = "unsize"]
 +pub trait Unsize<T: ?Sized> {}
 +
 +#[lang = "coerce_unsized"]
 +pub trait CoerceUnsized<T> {}
 +
 +pub unsafe trait Allocator {}
 +
 +pub struct Global;
 +unsafe impl Allocator for Global {}
 +
 +#[lang = "owned_box"]
 +#[fundamental]
 +pub struct Box<T: ?Sized, A: Allocator = Global>;
 +
 +impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
 +
 +fn send() ->  Box<dyn Future<Output = ()> + Send + 'static>{
 +    box async move {}
 +}
 +
 +fn not_send() -> Box<dyn Future<Output = ()> + 'static> {
 +    box async move {}
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn into_future_trait() {
 +    check_types(
 +        r#"
 +//- minicore: future
 +struct Futurable;
 +impl core::future::IntoFuture for Futurable {
 +    type Output = u64;
 +    type IntoFuture = IntFuture;
 +}
 +
 +struct IntFuture;
 +impl core::future::Future for IntFuture {
 +    type Output = u64;
 +}
 +
 +fn test() {
 +    let r = Futurable;
 +    let v = r.await;
 +    v;
 +} //^ u64
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_try() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:core
 +fn test() {
 +    let r: Result<i32, u64> = Result::Ok(1);
 +    let v = r?;
 +    v;
 +} //^ i32
 +
 +//- /core.rs crate:core
 +pub mod ops {
 +    pub trait Try {
 +        type Ok;
 +        type Error;
 +    }
 +}
 +
 +pub mod result {
 +    pub enum Result<O, E> {
 +        Ok(O),
 +        Err(E)
 +    }
 +
 +    impl<O, E> crate::ops::Try for Result<O, E> {
 +        type Ok = O;
 +        type Error = E;
 +    }
 +}
 +
 +pub mod prelude {
 +    pub mod rust_2018 {
 +        pub use crate::{result::*, ops::*};
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_try_trait_v2() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:core
 +fn test() {
 +    let r: Result<i32, u64> = Result::Ok(1);
 +    let v = r?;
 +    v;
 +} //^ i32
 +
 +//- /core.rs crate:core
 +mod ops {
 +    mod try_trait {
 +        pub trait Try: FromResidual {
 +            type Output;
 +            type Residual;
 +        }
 +        pub trait FromResidual<R = <Self as Try>::Residual> {}
 +    }
 +
 +    pub use self::try_trait::FromResidual;
 +    pub use self::try_trait::Try;
 +}
 +
 +mod convert {
 +    pub trait From<T> {}
 +    impl<T> From<T> for T {}
 +}
 +
 +pub mod result {
 +    use crate::convert::From;
 +    use crate::ops::{Try, FromResidual};
 +
 +    pub enum Infallible {}
 +    pub enum Result<O, E> {
 +        Ok(O),
 +        Err(E)
 +    }
 +
 +    impl<O, E> Try for Result<O, E> {
 +        type Output = O;
 +        type Error = Result<Infallible, E>;
 +    }
 +
 +    impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {}
 +}
 +
 +pub mod prelude {
 +    pub mod rust_2018 {
 +        pub use crate::result::*;
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_for_loop() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:core,alloc
 +#![no_std]
 +use alloc::collections::Vec;
 +
 +fn test() {
 +    let v = Vec::new();
 +    v.push("foo");
 +    for x in v {
 +        x;
 +    } //^ &str
 +}
 +
 +//- /core.rs crate:core
 +pub mod iter {
 +    pub trait IntoIterator {
 +        type Item;
 +    }
 +}
 +pub mod prelude {
 +    pub mod rust_2018 {
 +        pub use crate::iter::*;
 +    }
 +}
 +
 +//- /alloc.rs crate:alloc deps:core
 +#![no_std]
 +pub mod collections {
 +    pub struct Vec<T> {}
 +    impl<T> Vec<T> {
 +        pub fn new() -> Self { Vec {} }
 +        pub fn push(&mut self, t: T) { }
 +    }
 +
 +    impl<T> IntoIterator for Vec<T> {
 +        type Item=T;
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_neg() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:std
 +struct Bar;
 +struct Foo;
 +
 +impl std::ops::Neg for Bar {
 +    type Output = Foo;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = -a;
 +    b;
 +} //^ Foo
 +
 +//- /std.rs crate:std
 +#[prelude_import] use ops::*;
 +mod ops {
 +    #[lang = "neg"]
 +    pub trait Neg {
 +        type Output;
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_not() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:std
 +struct Bar;
 +struct Foo;
 +
 +impl std::ops::Not for Bar {
 +    type Output = Foo;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = !a;
 +    b;
 +} //^ Foo
 +
 +//- /std.rs crate:std
 +#[prelude_import] use ops::*;
 +mod ops {
 +    #[lang = "not"]
 +    pub trait Not {
 +        type Output;
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_from_bound_1() {
 +    check_types(
 +        r#"
 +trait Trait<T> {}
 +struct S<T>(T);
 +impl<U> Trait<U> for S<U> {}
 +fn foo<T: Trait<u32>>(t: T) {}
 +fn test() {
 +    let s = S(unknown);
 +           // ^^^^^^^ u32
 +    foo(s);
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_from_bound_2() {
 +    check_types(
 +        r#"
 +trait Trait<T> {}
 +struct S<T>(T);
 +impl<U> Trait<U> for S<U> {}
 +fn foo<U, T: Trait<U>>(t: T) -> U { loop {} }
 +fn test() {
 +    let s = S(unknown);
 +           // ^^^^^^^ u32
 +    let x: u32 = foo(s);
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_default_method_self_bound_implements_trait() {
 +    cov_mark::check!(trait_self_implements_self);
 +    check(
 +        r#"
 +trait Trait {
 +    fn foo(&self) -> i64;
 +    fn bar(&self) -> () {
 +        self.foo();
 +     // ^^^^^^^^^^ type: i64
 +    }
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_default_method_self_bound_implements_super_trait() {
 +    check(
 +        r#"
 +trait SuperTrait {
 +    fn foo(&self) -> i64;
 +}
 +trait Trait: SuperTrait {
 +    fn bar(&self) -> () {
 +        self.foo();
 +     // ^^^^^^^^^^ type: i64
 +    }
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_project_associated_type() {
 +    check_types(
 +        r#"
 +trait Iterable {
 +    type Item;
 +}
 +struct S;
 +impl Iterable for S { type Item = u32; }
 +fn test<T: Iterable>() {
 +    let x: <S as Iterable>::Item = 1;
 +                                // ^ u32
 +    let y: <T as Iterable>::Item = u;
 +                                // ^ Iterable::Item<T>
 +    let z: T::Item = u;
 +                  // ^ Iterable::Item<T>
 +    let a: <T>::Item = u;
 +                    // ^ Iterable::Item<T>
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_return_associated_type() {
 +    check_types(
 +        r#"
 +trait Iterable {
 +    type Item;
 +}
 +struct S;
 +impl Iterable for S { type Item = u32; }
 +fn foo1<T: Iterable>(t: T) -> T::Item { loop {} }
 +fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item { loop {} }
 +fn foo3<T: Iterable>(t: T) -> <T>::Item { loop {} }
 +fn test() {
 +    foo1(S);
 + // ^^^^^^^ u32
 +    foo2(S);
 + // ^^^^^^^ u32
 +    foo3(S);
 + // ^^^^^^^ u32
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn associated_type_shorthand_from_method_bound() {
 +    check_types(
 +        r#"
 +trait Iterable {
 +    type Item;
 +}
 +struct S<T>;
 +impl<T> S<T> {
 +    fn foo(self) -> T::Item where T: Iterable { loop {} }
 +}
 +fn test<T: Iterable>() {
 +    let s: S<T>;
 +    s.foo();
 + // ^^^^^^^ Iterable::Item<T>
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn associated_type_shorthand_from_self_issue_12484() {
 +    check_types(
 +        r#"
 +trait Bar {
 +    type A;
 +}
 +trait Foo {
 +    type A;
 +    fn test(a: Self::A, _: impl Bar) {
 +        a;
 +      //^ Foo::A<Self>
 +    }
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_associated_type_bound() {
 +    check_types(
 +        r#"
 +trait Iterable {
 +    type Item;
 +}
 +fn test<T: Iterable<Item=u32>>() {
 +    let y: T::Item = unknown;
 +                  // ^^^^^^^ u32
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_const_body() {
 +    // FIXME make check_types work with other bodies
 +    check_infer(
 +        r#"
 +const A: u32 = 1 + 1;
 +static B: u64 = { let x = 1; x };
 +"#,
 +        expect![[r#"
 +            15..16 '1': u32
 +            15..20 '1 + 1': u32
 +            19..20 '1': u32
 +            38..54 '{ let ...1; x }': u64
 +            44..45 'x': u64
 +            48..49 '1': u64
 +            51..52 'x': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn tuple_struct_fields() {
 +    check_infer(
 +        r#"
 +struct S(i32, u64);
 +fn test() -> u64 {
 +    let a = S(4, 6);
 +    let b = a.0;
 +    a.1
 +}"#,
 +        expect![[r#"
 +            37..86 '{     ... a.1 }': u64
 +            47..48 'a': S
 +            51..52 'S': S(i32, u64) -> S
 +            51..58 'S(4, 6)': S
 +            53..54 '4': i32
 +            56..57 '6': u64
 +            68..69 'b': i32
 +            72..73 'a': S
 +            72..75 'a.0': i32
 +            81..82 'a': S
 +            81..84 'a.1': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn tuple_struct_with_fn() {
 +    check_infer(
 +        r#"
 +struct S(fn(u32) -> u64);
 +fn test() -> u64 {
 +    let a = S(|i| 2*i);
 +    let b = a.0(4);
 +    a.0(2)
 +}"#,
 +        expect![[r#"
 +            43..101 '{     ...0(2) }': u64
 +            53..54 'a': S
 +            57..58 'S': S(fn(u32) -> u64) -> S
 +            57..67 'S(|i| 2*i)': S
 +            59..66 '|i| 2*i': |u32| -> u64
 +            60..61 'i': u32
 +            63..64 '2': u32
 +            63..66 '2*i': u32
 +            65..66 'i': u32
 +            77..78 'b': u64
 +            81..82 'a': S
 +            81..84 'a.0': fn(u32) -> u64
 +            81..87 'a.0(4)': u64
 +            85..86 '4': u32
 +            93..94 'a': S
 +            93..96 'a.0': fn(u32) -> u64
 +            93..99 'a.0(2)': u64
 +            97..98 '2': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn indexing_arrays() {
 +    check_infer(
 +        "fn main() { &mut [9][2]; }",
 +        expect![[r#"
 +            10..26 '{ &mut...[2]; }': ()
 +            12..23 '&mut [9][2]': &mut {unknown}
 +            17..20 '[9]': [i32; 1]
 +            17..23 '[9][2]': {unknown}
 +            18..19 '9': i32
 +            21..22 '2': i32
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn infer_ops_index() {
 +    check_types(
 +        r#"
 +//- minicore: index
 +struct Bar;
 +struct Foo;
 +
 +impl core::ops::Index<u32> for Bar {
 +    type Output = Foo;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = a[1u32];
 +    b;
 +} //^ Foo
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_index_field() {
 +    check_types(
 +        r#"
 +//- minicore: index
 +struct Bar;
 +struct Foo {
 +    field: u32;
 +}
 +
 +impl core::ops::Index<u32> for Bar {
 +    type Output = Foo;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = a[1u32].field;
 +    b;
 +} //^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_index_field_autoderef() {
 +    check_types(
 +        r#"
 +//- minicore: index
 +struct Bar;
 +struct Foo {
 +    field: u32;
 +}
 +
 +impl core::ops::Index<u32> for Bar {
 +    type Output = Foo;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = (&a[1u32]).field;
 +    b;
 +} //^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_index_int() {
 +    check_types(
 +        r#"
 +//- minicore: index
 +struct Bar;
 +struct Foo;
 +
 +impl core::ops::Index<u32> for Bar {
 +    type Output = Foo;
 +}
 +
 +struct Range;
 +impl core::ops::Index<Range> for Bar {
 +    type Output = Bar;
 +}
 +
 +fn test() {
 +    let a = Bar;
 +    let b = a[1];
 +    b;
 +  //^ Foo
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_ops_index_autoderef() {
 +    check_types(
 +        r#"
 +//- minicore: index, slice
 +fn test() {
 +    let a = &[1u32, 2, 3];
 +    let b = a[1];
 +    b;
 +} //^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_trait() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Arc<T: ?Sized>;
 +impl<T: ?Sized> core::ops::Deref for Arc<T> {
 +    type Target = T;
 +}
 +
 +struct S;
 +impl S {
 +    fn foo(&self) -> u128 { 0 }
 +}
 +
 +fn test(s: Arc<S>) {
 +    (*s, s.foo());
 +} //^^^^^^^^^^^^^ (S, u128)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_trait_with_inference_var() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Arc<T: ?Sized>;
 +fn new_arc<T: ?Sized>() -> Arc<T> { Arc }
 +impl<T: ?Sized> core::ops::Deref for Arc<T> {
 +    type Target = T;
 +}
 +
 +struct S;
 +fn foo(a: Arc<S>) {}
 +
 +fn test() {
 +    let a = new_arc();
 +    let b = *a;
 +          //^^ S
 +    foo(a);
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_trait_infinite_recursion() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct S;
 +
 +impl core::ops::Deref for S {
 +    type Target = S;
 +}
 +
 +fn test(s: S) {
 +    s.foo();
 +} //^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_trait_with_question_mark_size() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Arc<T: ?Sized>;
 +impl<T: ?Sized> core::ops::Deref for Arc<T> {
 +    type Target = T;
 +}
 +
 +struct S;
 +impl S {
 +    fn foo(&self) -> u128 { 0 }
 +}
 +
 +fn test(s: Arc<S>) {
 +    (*s, s.foo());
 +} //^^^^^^^^^^^^^ (S, u128)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn deref_trait_with_implicit_sized_requirement_on_inference_var() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Foo<T>;
 +impl<T> core::ops::Deref for Foo<T> {
 +    type Target = ();
 +}
 +fn test() {
 +    let foo = Foo;
 +    *foo;
 +  //^^^^ ()
 +    let _: Foo<u8> = foo;
 +}
 +"#,
 +    )
 +}
 +
 +#[test]
 +fn obligation_from_function_clause() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +trait Trait<T> {}
 +impl Trait<u32> for S {}
 +
 +fn foo<T: Trait<U>, U>(t: T) -> U { loop {} }
 +
 +fn test(s: S) {
 +    foo(s);
 +} //^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn obligation_from_method_clause() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +struct S;
 +
 +trait Trait<T> {}
 +impl Trait<isize> for S {}
 +
 +struct O;
 +impl O {
 +    fn foo<T: Trait<U>, U>(&self, t: T) -> U { loop {} }
 +}
 +
 +fn test() {
 +    O.foo(S);
 +} //^^^^^^^^ isize
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn obligation_from_self_method_clause() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +trait Trait<T> {}
 +impl Trait<i64> for S {}
 +
 +impl S {
 +    fn foo<U>(&self) -> U where Self: Trait<U> { loop {} }
 +}
 +
 +fn test() {
 +    S.foo();
 +} //^^^^^^^ i64
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn obligation_from_impl_clause() {
 +    check_types(
 +        r#"
 +struct S;
 +
 +trait Trait<T> {}
 +impl Trait<&str> for S {}
 +
 +struct O<T>;
 +impl<U, T: Trait<U>> O<T> {
 +    fn foo(&self) -> U { loop {} }
 +}
 +
 +fn test(o: O<S>) {
 +    o.foo();
 +} //^^^^^^^ &str
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn generic_param_env_1() {
 +    check_types(
 +        r#"
 +trait Clone {}
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl Clone for S {}
 +impl<T> Trait for T where T: Clone {}
 +fn test<T: Clone>(t: T) { t.foo(); }
 +                        //^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn generic_param_env_1_not_met() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +trait Clone {}
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl Clone for S {}
 +impl<T> Trait for T where T: Clone {}
 +fn test<T>(t: T) { t.foo(); }
 +                 //^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn generic_param_env_2() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl Trait for S {}
 +fn test<T: Trait>(t: T) { t.foo(); }
 +                        //^^^^^^^ u128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn generic_param_env_2_not_met() {
 +    check_types(
 +        r#"
 +trait Trait { fn foo(self) -> u128; }
 +struct S;
 +impl Trait for S {}
 +fn test<T>(t: T) { t.foo(); }
 +                 //^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn generic_param_env_deref() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +trait Trait {}
 +impl<T> core::ops::Deref for T where T: Trait {
 +    type Target = i128;
 +}
 +fn test<T: Trait>(t: T) { *t; }
 +                        //^^ i128
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn associated_type_placeholder() {
 +    // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types].
 +    check_types(
 +        r#"
 +pub trait ApplyL {
 +    type Out;
 +}
 +
 +pub struct RefMutL<T>;
 +
 +impl<T> ApplyL for RefMutL<T> {
 +    type Out = <T as ApplyL>::Out;
 +}
 +
 +fn test<T: ApplyL>() {
 +    let y: <RefMutL<T> as ApplyL>::Out = no_matter;
 +    y;
 +} //^ ApplyL::Out<T>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn associated_type_placeholder_2() {
 +    check_types(
 +        r#"
 +pub trait ApplyL {
 +    type Out;
 +}
 +fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out;
 +
 +fn test<T: ApplyL>(t: T) {
 +    let y = foo(t);
 +    y;
 +} //^ ApplyL::Out<T>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn argument_impl_trait() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +    fn foo2(&self) -> i64;
 +}
 +fn bar(x: impl Trait<u16>) {}
 +struct S<T>(T);
 +impl<T> Trait<T> for S<T> {}
 +
 +fn test(x: impl Trait<u64>, y: &impl Trait<u32>) {
 +    x;
 +    y;
 +    let z = S(1);
 +    bar(z);
 +    x.foo();
 +    y.foo();
 +    z.foo();
 +    x.foo2();
 +    y.foo2();
 +    z.foo2();
 +}"#,
 +        expect![[r#"
 +            29..33 'self': &Self
 +            54..58 'self': &Self
 +            77..78 'x': impl Trait<u16>
 +            97..99 '{}': ()
 +            154..155 'x': impl Trait<u64>
 +            174..175 'y': &impl Trait<u32>
 +            195..323 '{     ...2(); }': ()
 +            201..202 'x': impl Trait<u64>
 +            208..209 'y': &impl Trait<u32>
 +            219..220 'z': S<u16>
 +            223..224 'S': S<u16>(u16) -> S<u16>
 +            223..227 'S(1)': S<u16>
 +            225..226 '1': u16
 +            233..236 'bar': fn bar(S<u16>)
 +            233..239 'bar(z)': ()
 +            237..238 'z': S<u16>
 +            245..246 'x': impl Trait<u64>
 +            245..252 'x.foo()': u64
 +            258..259 'y': &impl Trait<u32>
 +            258..265 'y.foo()': u32
 +            271..272 'z': S<u16>
 +            271..278 'z.foo()': u16
 +            284..285 'x': impl Trait<u64>
 +            284..292 'x.foo2()': i64
 +            298..299 'y': &impl Trait<u32>
 +            298..306 'y.foo2()': i64
 +            312..313 'z': S<u16>
 +            312..320 'z.foo2()': i64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn argument_impl_trait_type_args_1() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +trait Foo {
 +    // this function has an implicit Self param, an explicit type param,
 +    // and an implicit impl Trait param!
 +    fn bar<T>(x: impl Trait) -> T { loop {} }
 +}
 +fn foo<T>(x: impl Trait) -> T { loop {} }
 +struct S;
 +impl Trait for S {}
 +struct F;
 +impl Foo for F {}
 +
 +fn test() {
 +    Foo::bar(S);
 +    <F as Foo>::bar(S);
 +    F::bar(S);
 +    Foo::bar::<u32>(S);
 +    <F as Foo>::bar::<u32>(S);
 +
 +    foo(S);
 +    foo::<u32>(S);
 +    foo::<u32, i32>(S); // we should ignore the extraneous i32
 +}"#,
 +        expect![[r#"
 +            155..156 'x': impl Trait
 +            175..186 '{ loop {} }': T
 +            177..184 'loop {}': !
 +            182..184 '{}': ()
 +            199..200 'x': impl Trait
 +            219..230 '{ loop {} }': T
 +            221..228 'loop {}': !
 +            226..228 '{}': ()
 +            300..509 '{     ... i32 }': ()
 +            306..314 'Foo::bar': fn bar<{unknown}, {unknown}>(S) -> {unknown}
 +            306..317 'Foo::bar(S)': {unknown}
 +            315..316 'S': S
 +            323..338 '<F as Foo>::bar': fn bar<F, {unknown}>(S) -> {unknown}
 +            323..341 '<F as ...bar(S)': {unknown}
 +            339..340 'S': S
 +            347..353 'F::bar': fn bar<F, {unknown}>(S) -> {unknown}
 +            347..356 'F::bar(S)': {unknown}
 +            354..355 'S': S
 +            362..377 'Foo::bar::<u32>': fn bar<{unknown}, u32>(S) -> u32
 +            362..380 'Foo::b...32>(S)': u32
 +            378..379 'S': S
 +            386..408 '<F as ...:<u32>': fn bar<F, u32>(S) -> u32
 +            386..411 '<F as ...32>(S)': u32
 +            409..410 'S': S
 +            418..421 'foo': fn foo<{unknown}>(S) -> {unknown}
 +            418..424 'foo(S)': {unknown}
 +            422..423 'S': S
 +            430..440 'foo::<u32>': fn foo<u32>(S) -> u32
 +            430..443 'foo::<u32>(S)': u32
 +            441..442 'S': S
 +            449..464 'foo::<u32, i32>': fn foo<u32>(S) -> u32
 +            449..467 'foo::<...32>(S)': u32
 +            465..466 'S': S
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn argument_impl_trait_type_args_2() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +struct S;
 +impl Trait for S {}
 +struct F<T>;
 +impl<T> F<T> {
 +    fn foo<U>(self, x: impl Trait) -> (T, U) { loop {} }
 +}
 +
 +fn test() {
 +    F.foo(S);
 +    F::<u32>.foo(S);
 +    F::<u32>.foo::<i32>(S);
 +    F::<u32>.foo::<i32, u32>(S); // extraneous argument should be ignored
 +}"#,
 +        expect![[r#"
 +            87..91 'self': F<T>
 +            93..94 'x': impl Trait
 +            118..129 '{ loop {} }': (T, U)
 +            120..127 'loop {}': !
 +            125..127 '{}': ()
 +            143..283 '{     ...ored }': ()
 +            149..150 'F': F<{unknown}>
 +            149..157 'F.foo(S)': ({unknown}, {unknown})
 +            155..156 'S': S
 +            163..171 'F::<u32>': F<u32>
 +            163..178 'F::<u32>.foo(S)': (u32, {unknown})
 +            176..177 'S': S
 +            184..192 'F::<u32>': F<u32>
 +            184..206 'F::<u3...32>(S)': (u32, i32)
 +            204..205 'S': S
 +            212..220 'F::<u32>': F<u32>
 +            212..239 'F::<u3...32>(S)': (u32, i32)
 +            237..238 'S': S
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn argument_impl_trait_to_fn_pointer() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +fn foo(x: impl Trait) { loop {} }
 +struct S;
 +impl Trait for S {}
 +
 +fn test() {
 +    let f: fn(S) -> () = foo;
 +}"#,
 +        expect![[r#"
 +            22..23 'x': impl Trait
 +            37..48 '{ loop {} }': ()
 +            39..46 'loop {}': !
 +            44..46 '{}': ()
 +            90..123 '{     ...foo; }': ()
 +            100..101 'f': fn(S)
 +            117..120 'foo': fn foo(S)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn impl_trait() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +    fn foo2(&self) -> i64;
 +}
 +fn bar() -> impl Trait<u64> {}
 +
 +fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
 +    x;
 +    y;
 +    let z = bar();
 +    x.foo();
 +    y.foo();
 +    z.foo();
 +    x.foo2();
 +    y.foo2();
 +    z.foo2();
 +}"#,
 +        expect![[r#"
 +            29..33 'self': &Self
 +            54..58 'self': &Self
 +            98..100 '{}': ()
 +            110..111 'x': impl Trait<u64>
 +            130..131 'y': &impl Trait<u64>
 +            151..268 '{     ...2(); }': ()
 +            157..158 'x': impl Trait<u64>
 +            164..165 'y': &impl Trait<u64>
 +            175..176 'z': impl Trait<u64>
 +            179..182 'bar': fn bar() -> impl Trait<u64>
 +            179..184 'bar()': impl Trait<u64>
 +            190..191 'x': impl Trait<u64>
 +            190..197 'x.foo()': u64
 +            203..204 'y': &impl Trait<u64>
 +            203..210 'y.foo()': u64
 +            216..217 'z': impl Trait<u64>
 +            216..223 'z.foo()': u64
 +            229..230 'x': impl Trait<u64>
 +            229..237 'x.foo2()': i64
 +            243..244 'y': &impl Trait<u64>
 +            243..251 'y.foo2()': i64
 +            257..258 'z': impl Trait<u64>
 +            257..265 'z.foo2()': i64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn simple_return_pos_impl_trait() {
 +    cov_mark::check!(lower_rpit);
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +}
 +fn bar() -> impl Trait<u64> { loop {} }
 +
 +fn test() {
 +    let a = bar();
 +    a.foo();
 +}"#,
 +        expect![[r#"
 +            29..33 'self': &Self
 +            71..82 '{ loop {} }': !
 +            73..80 'loop {}': !
 +            78..80 '{}': ()
 +            94..129 '{     ...o(); }': ()
 +            104..105 'a': impl Trait<u64>
 +            108..111 'bar': fn bar() -> impl Trait<u64>
 +            108..113 'bar()': impl Trait<u64>
 +            119..120 'a': impl Trait<u64>
 +            119..126 'a.foo()': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn more_return_pos_impl_trait() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Iterator {
 +    type Item;
 +    fn next(&mut self) -> Self::Item;
 +}
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +}
 +fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) { loop {} }
 +fn baz<T>(t: T) -> (impl Iterator<Item = impl Trait<T>>, impl Trait<T>) { loop {} }
 +
 +fn test() {
 +    let (a, b) = bar();
 +    a.next().foo();
 +    b.foo();
 +    let (c, d) = baz(1u128);
 +    c.next().foo();
 +    d.foo();
 +}"#,
 +        expect![[r#"
 +            49..53 'self': &mut Self
 +            101..105 'self': &Self
 +            184..195 '{ loop {} }': ({unknown}, {unknown})
 +            186..193 'loop {}': !
 +            191..193 '{}': ()
 +            206..207 't': T
 +            268..279 '{ loop {} }': ({unknown}, {unknown})
 +            270..277 'loop {}': !
 +            275..277 '{}': ()
 +            291..413 '{     ...o(); }': ()
 +            301..307 '(a, b)': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
 +            302..303 'a': impl Iterator<Item = impl Trait<u32>>
 +            305..306 'b': impl Trait<u64>
 +            310..313 'bar': fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
 +            310..315 'bar()': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
 +            321..322 'a': impl Iterator<Item = impl Trait<u32>>
 +            321..329 'a.next()': impl Trait<u32>
 +            321..335 'a.next().foo()': u32
 +            341..342 'b': impl Trait<u64>
 +            341..348 'b.foo()': u64
 +            358..364 '(c, d)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
 +            359..360 'c': impl Iterator<Item = impl Trait<u128>>
 +            362..363 'd': impl Trait<u128>
 +            367..370 'baz': fn baz<u128>(u128) -> (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
 +            367..377 'baz(1u128)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
 +            371..376 '1u128': u128
 +            383..384 'c': impl Iterator<Item = impl Trait<u128>>
 +            383..391 'c.next()': impl Trait<u128>
 +            383..397 'c.next().foo()': u128
 +            403..404 'd': impl Trait<u128>
 +            403..410 'd.foo()': u128
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_from_return_pos_impl_trait() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn, sized
 +trait Trait<T> {}
 +struct Bar<T>(T);
 +impl<T> Trait<T> for Bar<T> {}
 +fn foo<const C: u8, T>() -> (impl FnOnce(&str, T), impl Trait<u8>) {
 +    (|input, t| {}, Bar(C))
 +}
 +"#,
 +        expect![[r#"
 +            134..165 '{     ...(C)) }': (|&str, T| -> (), Bar<u8>)
 +            140..163 '(|inpu...ar(C))': (|&str, T| -> (), Bar<u8>)
 +            141..154 '|input, t| {}': |&str, T| -> ()
 +            142..147 'input': &str
 +            149..150 't': T
 +            152..154 '{}': ()
 +            156..159 'Bar': Bar<u8>(u8) -> Bar<u8>
 +            156..162 'Bar(C)': Bar<u8>
 +            160..161 'C': u8
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn dyn_trait() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +    fn foo2(&self) -> i64;
 +}
 +fn bar() -> dyn Trait<u64> {}
 +
 +fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
 +    x;
 +    y;
 +    let z = bar();
 +    x.foo();
 +    y.foo();
 +    z.foo();
 +    x.foo2();
 +    y.foo2();
 +    z.foo2();
 +}"#,
 +        expect![[r#"
 +            29..33 'self': &Self
 +            54..58 'self': &Self
 +            97..99 '{}': dyn Trait<u64>
 +            109..110 'x': dyn Trait<u64>
 +            128..129 'y': &dyn Trait<u64>
 +            148..265 '{     ...2(); }': ()
 +            154..155 'x': dyn Trait<u64>
 +            161..162 'y': &dyn Trait<u64>
 +            172..173 'z': dyn Trait<u64>
 +            176..179 'bar': fn bar() -> dyn Trait<u64>
 +            176..181 'bar()': dyn Trait<u64>
 +            187..188 'x': dyn Trait<u64>
 +            187..194 'x.foo()': u64
 +            200..201 'y': &dyn Trait<u64>
 +            200..207 'y.foo()': u64
 +            213..214 'z': dyn Trait<u64>
 +            213..220 'z.foo()': u64
 +            226..227 'x': dyn Trait<u64>
 +            226..234 'x.foo2()': i64
 +            240..241 'y': &dyn Trait<u64>
 +            240..248 'y.foo2()': i64
 +            254..255 'z': dyn Trait<u64>
 +            254..262 'z.foo2()': i64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn dyn_trait_in_impl() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait<T, U> {
 +    fn foo(&self) -> (T, U);
 +}
 +struct S<T, U> {}
 +impl<T, U> S<T, U> {
 +    fn bar(&self) -> &dyn Trait<T, U> { loop {} }
 +}
 +trait Trait2<T, U> {
 +    fn baz(&self) -> (T, U);
 +}
 +impl<T, U> Trait2<T, U> for dyn Trait<T, U> { }
 +
 +fn test(s: S<u32, i32>) {
 +    s.bar().baz();
 +}"#,
 +        expect![[r#"
 +            32..36 'self': &Self
 +            102..106 'self': &S<T, U>
 +            128..139 '{ loop {} }': &dyn Trait<T, U>
 +            130..137 'loop {}': !
 +            135..137 '{}': ()
 +            175..179 'self': &Self
 +            251..252 's': S<u32, i32>
 +            267..289 '{     ...z(); }': ()
 +            273..274 's': S<u32, i32>
 +            273..280 's.bar()': &dyn Trait<u32, i32>
 +            273..286 's.bar().baz()': (u32, i32)
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn dyn_trait_bare() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait {
 +    fn foo(&self) -> u64;
 +}
 +fn bar() -> Trait {}
 +
 +fn test(x: Trait, y: &Trait) -> u64 {
 +    x;
 +    y;
 +    let z = bar();
 +    x.foo();
 +    y.foo();
 +    z.foo();
 +}"#,
 +        expect![[r#"
 +            26..30 'self': &Self
 +            60..62 '{}': dyn Trait
 +            72..73 'x': dyn Trait
 +            82..83 'y': &dyn Trait
 +            100..175 '{     ...o(); }': u64
 +            106..107 'x': dyn Trait
 +            113..114 'y': &dyn Trait
 +            124..125 'z': dyn Trait
 +            128..131 'bar': fn bar() -> dyn Trait
 +            128..133 'bar()': dyn Trait
 +            139..140 'x': dyn Trait
 +            139..146 'x.foo()': u64
 +            152..153 'y': &dyn Trait
 +            152..159 'y.foo()': u64
 +            165..166 'z': dyn Trait
 +            165..172 'z.foo()': u64
 +        "#]],
 +    );
 +
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn, coerce_unsized
 +struct S;
 +impl S {
 +    fn foo(&self) {}
 +}
 +fn f(_: &Fn(S)) {}
 +fn main() {
 +    f(&|number| number.foo());
 +}
 +        "#,
 +        expect![[r#"
 +            31..35 'self': &S
 +            37..39 '{}': ()
 +            47..48 '_': &dyn Fn(S)
 +            58..60 '{}': ()
 +            71..105 '{     ...()); }': ()
 +            77..78 'f': fn f(&dyn Fn(S))
 +            77..102 'f(&|nu...foo())': ()
 +            79..101 '&|numb....foo()': &|S| -> ()
 +            80..101 '|numbe....foo()': |S| -> ()
 +            81..87 'number': S
 +            89..95 'number': S
 +            89..101 'number.foo()': ()
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn weird_bounds() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait {}
 +fn test(
 +    a: impl Trait + 'lifetime,
 +    b: impl 'lifetime,
 +    c: impl (Trait),
 +    d: impl ('lifetime),
 +    e: impl ?Sized,
 +    f: impl Trait + ?Sized
 +) {}
 +"#,
 +        expect![[r#"
 +            28..29 'a': impl Trait
 +            59..60 'b': impl Sized
 +            82..83 'c': impl Trait
 +            103..104 'd': impl Sized
 +            128..129 'e': impl ?Sized
 +            148..149 'f': impl Trait + ?Sized
 +            173..175 '{}': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn error_bound_chalk() {
 +    check_types(
 +        r#"
 +trait Trait {
 +    fn foo(&self) -> u32 { 0 }
 +}
 +
 +fn test(x: (impl Trait + UnknownTrait)) {
 +    x.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn assoc_type_bindings() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +trait Trait {
 +    type Type;
 +}
 +
 +fn get<T: Trait>(t: T) -> <T as Trait>::Type {}
 +fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
 +fn set<T: Trait<Type = u64>>(t: T) -> T {t}
 +
 +struct S<T>;
 +impl<T> Trait for S<T> { type Type = T; }
 +
 +fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
 +    get(x);
 +    get2(x);
 +    get(y);
 +    get2(y);
 +    get(set(S));
 +    get2(set(S));
 +    get2(S::<str>);
 +}"#,
 +        expect![[r#"
 +            49..50 't': T
 +            77..79 '{}': Trait::Type<T>
 +            111..112 't': T
 +            122..124 '{}': U
 +            154..155 't': T
 +            165..168 '{t}': T
 +            166..167 't': T
 +            256..257 'x': T
 +            262..263 'y': impl Trait<Type = i64>
 +            289..397 '{     ...r>); }': ()
 +            295..298 'get': fn get<T>(T) -> <T as Trait>::Type
 +            295..301 'get(x)': u32
 +            299..300 'x': T
 +            307..311 'get2': fn get2<u32, T>(T) -> u32
 +            307..314 'get2(x)': u32
 +            312..313 'x': T
 +            320..323 'get': fn get<impl Trait<Type = i64>>(impl Trait<Type = i64>) -> <impl Trait<Type = i64> as Trait>::Type
 +            320..326 'get(y)': i64
 +            324..325 'y': impl Trait<Type = i64>
 +            332..336 'get2': fn get2<i64, impl Trait<Type = i64>>(impl Trait<Type = i64>) -> i64
 +            332..339 'get2(y)': i64
 +            337..338 'y': impl Trait<Type = i64>
 +            345..348 'get': fn get<S<u64>>(S<u64>) -> <S<u64> as Trait>::Type
 +            345..356 'get(set(S))': u64
 +            349..352 'set': fn set<S<u64>>(S<u64>) -> S<u64>
 +            349..355 'set(S)': S<u64>
 +            353..354 'S': S<u64>
 +            362..366 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64
 +            362..374 'get2(set(S))': u64
 +            367..370 'set': fn set<S<u64>>(S<u64>) -> S<u64>
 +            367..373 'set(S)': S<u64>
 +            371..372 'S': S<u64>
 +            380..384 'get2': fn get2<str, S<str>>(S<str>) -> str
 +            380..394 'get2(S::<str>)': str
 +            385..393 'S::<str>': S<str>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn impl_trait_assoc_binding_projection_bug() {
 +    check_types(
 +        r#"
 +//- minicore: iterator
 +pub trait Language {
 +    type Kind;
 +}
 +pub enum RustLanguage {}
 +impl Language for RustLanguage {
 +    type Kind = SyntaxKind;
 +}
 +struct SyntaxNode<L> {}
 +fn foo() -> impl Iterator<Item = SyntaxNode<RustLanguage>> {}
 +
 +trait Clone {
 +    fn clone(&self) -> Self;
 +}
 +
 +fn api_walkthrough() {
 +    for node in foo() {
 +        node.clone();
 +    } //^^^^^^^^^^^^ {unknown}
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn projection_eq_within_chalk() {
 +    check_infer(
 +        r#"
 +trait Trait1 {
 +    type Type;
 +}
 +trait Trait2<T> {
 +    fn foo(self) -> T;
 +}
 +impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {}
 +
 +fn test<T: Trait1<Type = u32>>(x: T) {
 +    x.foo();
 +}"#,
 +        expect![[r#"
 +            61..65 'self': Self
 +            163..164 'x': T
 +            169..185 '{     ...o(); }': ()
 +            175..176 'x': T
 +            175..182 'x.foo()': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn where_clause_trait_in_scope_for_method_resolution() {
 +    check_types(
 +        r#"
 +mod foo {
 +    trait Trait {
 +        fn foo(&self) -> u32 { 0 }
 +    }
 +}
 +
 +fn test<T: foo::Trait>(x: T) {
 +    x.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn super_trait_method_resolution() {
 +    check_infer(
 +        r#"
 +mod foo {
 +    trait SuperTrait {
 +        fn foo(&self) -> u32 {}
 +    }
 +}
 +trait Trait1: foo::SuperTrait {}
 +trait Trait2 where Self: foo::SuperTrait {}
 +
 +fn test<T: Trait1, U: Trait2>(x: T, y: U) {
 +    x.foo();
 +    y.foo();
 +}"#,
 +        expect![[r#"
 +            49..53 'self': &Self
 +            62..64 '{}': u32
 +            181..182 'x': T
 +            187..188 'y': U
 +            193..222 '{     ...o(); }': ()
 +            199..200 'x': T
 +            199..206 'x.foo()': u32
 +            212..213 'y': U
 +            212..219 'y.foo()': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn super_trait_impl_trait_method_resolution() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +mod foo {
 +    trait SuperTrait {
 +        fn foo(&self) -> u32 {}
 +    }
 +}
 +trait Trait1: foo::SuperTrait {}
 +
 +fn test(x: &impl Trait1) {
 +    x.foo();
 +}"#,
 +        expect![[r#"
 +            49..53 'self': &Self
 +            62..64 '{}': u32
 +            115..116 'x': &impl Trait1
 +            132..148 '{     ...o(); }': ()
 +            138..139 'x': &impl Trait1
 +            138..145 'x.foo()': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn super_trait_cycle() {
 +    // This just needs to not crash
 +    check_infer(
 +        r#"
 +        trait A: B {}
 +        trait B: A {}
 +
 +        fn test<T: A>(x: T) {
 +            x.foo();
 +        }
 +        "#,
 +        expect![[r#"
 +            43..44 'x': T
 +            49..65 '{     ...o(); }': ()
 +            55..56 'x': T
 +            55..62 'x.foo()': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn super_trait_assoc_type_bounds() {
 +    check_infer(
 +        r#"
 +trait SuperTrait { type Type; }
 +trait Trait where Self: SuperTrait {}
 +
 +fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
 +fn set<T: Trait<Type = u64>>(t: T) -> T {t}
 +
 +struct S<T>;
 +impl<T> SuperTrait for S<T> { type Type = T; }
 +impl<T> Trait for S<T> {}
 +
 +fn test() {
 +    get2(set(S));
 +}"#,
 +        expect![[r#"
 +            102..103 't': T
 +            113..115 '{}': U
 +            145..146 't': T
 +            156..159 '{t}': T
 +            157..158 't': T
 +            258..279 '{     ...S)); }': ()
 +            264..268 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64
 +            264..276 'get2(set(S))': u64
 +            269..272 'set': fn set<S<u64>>(S<u64>) -> S<u64>
 +            269..275 'set(S)': S<u64>
 +            273..274 'S': S<u64>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn fn_trait() {
 +    check_infer_with_mismatches(
 +        r#"
 +trait FnOnce<Args> {
 +    type Output;
 +
 +    fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output;
 +}
 +
 +fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
 +    f.call_once((1, 2));
 +}"#,
 +        expect![[r#"
 +            56..60 'self': Self
 +            62..66 'args': Args
 +            149..150 'f': F
 +            155..183 '{     ...2)); }': ()
 +            161..162 'f': F
 +            161..180 'f.call...1, 2))': u128
 +            173..179 '(1, 2)': (u32, u64)
 +            174..175 '1': u32
 +            177..178 '2': u64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn fn_ptr_and_item() {
 +    check_infer_with_mismatches(
 +        r#"
 +#[lang="fn_once"]
 +trait FnOnce<Args> {
 +    type Output;
 +
 +    fn call_once(self, args: Args) -> Self::Output;
 +}
 +
 +trait Foo<T> {
 +    fn foo(&self) -> T;
 +}
 +
 +struct Bar<T>(T);
 +
 +impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> {
 +    fn foo(&self) -> (A1, R) { loop {} }
 +}
 +
 +enum Opt<T> { None, Some(T) }
 +impl<T> Opt<T> {
 +    fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> { loop {} }
 +}
 +
 +fn test() {
 +    let bar: Bar<fn(u8) -> u32>;
 +    bar.foo();
 +
 +    let opt: Opt<u8>;
 +    let f: fn(u8) -> u32;
 +    opt.map(f);
 +}"#,
 +        expect![[r#"
 +            74..78 'self': Self
 +            80..84 'args': Args
 +            139..143 'self': &Self
 +            243..247 'self': &Bar<F>
 +            260..271 '{ loop {} }': (A1, R)
 +            262..269 'loop {}': !
 +            267..269 '{}': ()
 +            355..359 'self': Opt<T>
 +            361..362 'f': F
 +            377..388 '{ loop {} }': Opt<U>
 +            379..386 'loop {}': !
 +            384..386 '{}': ()
 +            402..518 '{     ...(f); }': ()
 +            412..415 'bar': Bar<fn(u8) -> u32>
 +            441..444 'bar': Bar<fn(u8) -> u32>
 +            441..450 'bar.foo()': (u8, u32)
 +            461..464 'opt': Opt<u8>
 +            483..484 'f': fn(u8) -> u32
 +            505..508 'opt': Opt<u8>
 +            505..515 'opt.map(f)': Opt<u32>
 +            513..514 'f': fn(u8) -> u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn fn_trait_deref_with_ty_default() {
 +    check_infer(
 +        r#"
 +//- minicore: deref, fn
 +struct Foo;
 +
 +impl Foo {
 +    fn foo(&self) -> usize {}
 +}
 +
 +struct Lazy<T, F = fn() -> T>(F);
 +
 +impl<T, F> Lazy<T, F> {
 +    pub fn new(f: F) -> Lazy<T, F> {}
 +}
 +
 +impl<T, F: FnOnce() -> T> core::ops::Deref for Lazy<T, F> {
 +    type Target = T;
 +}
 +
 +fn test() {
 +    let lazy1: Lazy<Foo, _> = Lazy::new(|| Foo);
 +    let r1 = lazy1.foo();
 +
 +    fn make_foo_fn() -> Foo {}
 +    let make_foo_fn_ptr: fn() -> Foo = make_foo_fn;
 +    let lazy2: Lazy<Foo, _> = Lazy::new(make_foo_fn_ptr);
 +    let r2 = lazy2.foo();
 +}"#,
 +        expect![[r#"
 +            36..40 'self': &Foo
 +            51..53 '{}': usize
 +            131..132 'f': F
 +            151..153 '{}': Lazy<T, F>
 +            251..497 '{     ...o(); }': ()
 +            261..266 'lazy1': Lazy<Foo, || -> Foo>
 +            283..292 'Lazy::new': fn new<Foo, || -> Foo>(|| -> Foo) -> Lazy<Foo, || -> Foo>
 +            283..300 'Lazy::...| Foo)': Lazy<Foo, || -> Foo>
 +            293..299 '|| Foo': || -> Foo
 +            296..299 'Foo': Foo
 +            310..312 'r1': usize
 +            315..320 'lazy1': Lazy<Foo, || -> Foo>
 +            315..326 'lazy1.foo()': usize
 +            368..383 'make_foo_fn_ptr': fn() -> Foo
 +            399..410 'make_foo_fn': fn make_foo_fn() -> Foo
 +            420..425 'lazy2': Lazy<Foo, fn() -> Foo>
 +            442..451 'Lazy::new': fn new<Foo, fn() -> Foo>(fn() -> Foo) -> Lazy<Foo, fn() -> Foo>
 +            442..468 'Lazy::...n_ptr)': Lazy<Foo, fn() -> Foo>
 +            452..467 'make_foo_fn_ptr': fn() -> Foo
 +            478..480 'r2': usize
 +            483..488 'lazy2': Lazy<Foo, fn() -> Foo>
 +            483..494 'lazy2.foo()': usize
 +            357..359 '{}': Foo
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn closure_1() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn
 +enum Option<T> { Some(T), None }
 +impl<T> Option<T> {
 +    fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { loop {} }
 +}
 +
 +fn test() {
 +    let x = Option::Some(1u32);
 +    x.map(|v| v + 1);
 +    x.map(|_v| 1u64);
 +    let y: Option<i64> = x.map(|_v| 1);
 +}"#,
 +        expect![[r#"
 +            86..90 'self': Option<T>
 +            92..93 'f': F
 +            111..122 '{ loop {} }': Option<U>
 +            113..120 'loop {}': !
 +            118..120 '{}': ()
 +            136..255 '{     ... 1); }': ()
 +            146..147 'x': Option<u32>
 +            150..162 'Option::Some': Some<u32>(u32) -> Option<u32>
 +            150..168 'Option...(1u32)': Option<u32>
 +            163..167 '1u32': u32
 +            174..175 'x': Option<u32>
 +            174..190 'x.map(...v + 1)': Option<u32>
 +            180..189 '|v| v + 1': |u32| -> u32
 +            181..182 'v': u32
 +            184..185 'v': u32
 +            184..189 'v + 1': u32
 +            188..189 '1': u32
 +            196..197 'x': Option<u32>
 +            196..212 'x.map(... 1u64)': Option<u64>
 +            202..211 '|_v| 1u64': |u32| -> u64
 +            203..205 '_v': u32
 +            207..211 '1u64': u64
 +            222..223 'y': Option<i64>
 +            239..240 'x': Option<u32>
 +            239..252 'x.map(|_v| 1)': Option<i64>
 +            245..251 '|_v| 1': |u32| -> i64
 +            246..248 '_v': u32
 +            250..251 '1': i64
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn closure_2() {
 +    check_types(
 +        r#"
 +//- minicore: add, fn
 +
 +impl core::ops::Add for u64 {
 +    type Output = Self;
 +    fn add(self, rhs: u64) -> Self::Output {0}
 +}
 +
 +impl core::ops::Add for u128 {
 +    type Output = Self;
 +    fn add(self, rhs: u128) -> Self::Output {0}
 +}
 +
 +fn test<F: FnOnce(u32) -> u64>(f: F) {
 +    f(1);
 +  //  ^ u32
 +  //^^^^ u64
 +    let g = |v| v + 1;
 +              //^^^^^ u64
 +          //^^^^^^^^^ |u64| -> u64
 +    g(1u64);
 +  //^^^^^^^ u64
 +    let h = |v| 1u128 + v;
 +          //^^^^^^^^^^^^^ |u128| -> u128
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn closure_as_argument_inference_order() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn
 +fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U { loop {} }
 +fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U { loop {} }
 +
 +struct S;
 +impl S {
 +    fn method(self) -> u64;
 +
 +    fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U { loop {} }
 +    fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U { loop {} }
 +}
 +
 +fn test() {
 +    let x1 = foo1(S, |s| s.method());
 +    let x2 = foo2(|s| s.method(), S);
 +    let x3 = S.foo1(S, |s| s.method());
 +    let x4 = S.foo2(|s| s.method(), S);
 +}"#,
 +        expect![[r#"
 +            33..34 'x': T
 +            39..40 'f': F
 +            50..61 '{ loop {} }': U
 +            52..59 'loop {}': !
 +            57..59 '{}': ()
 +            95..96 'f': F
 +            101..102 'x': T
 +            112..123 '{ loop {} }': U
 +            114..121 'loop {}': !
 +            119..121 '{}': ()
 +            158..162 'self': S
 +            210..214 'self': S
 +            216..217 'x': T
 +            222..223 'f': F
 +            233..244 '{ loop {} }': U
 +            235..242 'loop {}': !
 +            240..242 '{}': ()
 +            282..286 'self': S
 +            288..289 'f': F
 +            294..295 'x': T
 +            305..316 '{ loop {} }': U
 +            307..314 'loop {}': !
 +            312..314 '{}': ()
 +            330..489 '{     ... S); }': ()
 +            340..342 'x1': u64
 +            345..349 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64
 +            345..368 'foo1(S...hod())': u64
 +            350..351 'S': S
 +            353..367 '|s| s.method()': |S| -> u64
 +            354..355 's': S
 +            357..358 's': S
 +            357..367 's.method()': u64
 +            378..380 'x2': u64
 +            383..387 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64
 +            383..406 'foo2(|...(), S)': u64
 +            388..402 '|s| s.method()': |S| -> u64
 +            389..390 's': S
 +            392..393 's': S
 +            392..402 's.method()': u64
 +            404..405 'S': S
 +            416..418 'x3': u64
 +            421..422 'S': S
 +            421..446 'S.foo1...hod())': u64
 +            428..429 'S': S
 +            431..445 '|s| s.method()': |S| -> u64
 +            432..433 's': S
 +            435..436 's': S
 +            435..445 's.method()': u64
 +            456..458 'x4': u64
 +            461..462 'S': S
 +            461..486 'S.foo2...(), S)': u64
 +            468..482 '|s| s.method()': |S| -> u64
 +            469..470 's': S
 +            472..473 's': S
 +            472..482 's.method()': u64
 +            484..485 'S': S
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn fn_item_fn_trait() {
 +    check_types(
 +        r#"
 +//- minicore: fn
 +struct S;
 +
 +fn foo() -> S { S }
 +
 +fn takes_closure<U, F: FnOnce() -> U>(f: F) -> U { f() }
 +
 +fn test() {
 +    takes_closure(foo);
 +} //^^^^^^^^^^^^^^^^^^ S
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_1() {
 +    check_types(
 +        r#"
 +//- /main.rs
 +trait Trait {
 +    type Item;
 +}
 +
 +trait Trait2 {
 +    fn foo(&self) -> u32;
 +}
 +
 +fn test<T: Trait>() where T::Item: Trait2 {
 +    let x: T::Item = no_matter;
 +    x.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_2() {
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +    type Item;
 +}
 +
 +trait Trait2 {
 +    fn foo(&self) -> u32;
 +}
 +
 +fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
 +    let x: T::Item = no_matter;
 +    x.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_on_impl_self() {
 +    check_infer(
 +        r#"
 +//- /main.rs
 +trait Trait {
 +    type Item;
 +
 +    fn f(&self, x: Self::Item);
 +}
 +
 +struct S;
 +
 +impl Trait for S {
 +    type Item = u32;
 +    fn f(&self, x: Self::Item) { let y = x; }
 +}
 +
 +struct S2;
 +
 +impl Trait for S2 {
 +    type Item = i32;
 +    fn f(&self, x: <Self>::Item) { let y = x; }
 +}"#,
 +        expect![[r#"
 +            40..44 'self': &Self
 +            46..47 'x': Trait::Item<Self>
 +            126..130 'self': &S
 +            132..133 'x': u32
 +            147..161 '{ let y = x; }': ()
 +            153..154 'y': u32
 +            157..158 'x': u32
 +            228..232 'self': &S2
 +            234..235 'x': i32
 +            251..265 '{ let y = x; }': ()
 +            257..258 'y': i32
 +            261..262 'x': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_on_trait_self() {
 +    check_types(
 +        r#"
 +trait Trait {
 +    type Item;
 +
 +    fn f(&self) -> Self::Item { loop {} }
 +}
 +
 +struct S;
 +impl Trait for S {
 +    type Item = u32;
 +}
 +
 +fn test() {
 +    S.f();
 +} //^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_chalk_fold() {
 +    check_types(
 +        r#"
 +trait Interner {}
 +trait Fold<I: Interner, TI = I> {
 +    type Result;
 +}
 +
 +struct Ty<I: Interner> {}
 +impl<I: Interner, TI: Interner> Fold<I, TI> for Ty<I> {
 +    type Result = Ty<TI>;
 +}
 +
 +fn fold<I: Interner, T>(interner: &I, t: T) -> T::Result
 +where
 +    T: Fold<I, I>,
 +{
 +    loop {}
 +}
 +
 +fn foo<I: Interner>(interner: &I, t: Ty<I>) {
 +    fold(interner, t);
 +} //^^^^^^^^^^^^^^^^^ Ty<I>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_impl_self_ty() {
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +   fn foo(&self);
 +}
 +
 +struct S;
 +
 +impl Trait<Self> for S {}
 +
 +fn test() {
 +    S.foo();
 +} //^^^^^^^ ()
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_impl_self_ty_cycle() {
 +    check_types(
 +        r#"
 +trait Trait {
 +   fn foo(&self);
 +}
 +
 +struct S<T>;
 +
 +impl Trait for S<Self> {}
 +
 +fn test() {
 +    S.foo();
 +} //^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_cycle_1() {
 +    // This is not a cycle, because the `T: Trait2<T::Item>` bound depends only on the `T: Trait`
 +    // bound, not on itself (since only `Trait` can define `Item`).
 +    check_types(
 +        r#"
 +trait Trait {
 +    type Item;
 +}
 +
 +trait Trait2<T> {}
 +
 +fn test<T: Trait>() where T: Trait2<T::Item> {
 +    let x: T::Item = no_matter;
 +}                  //^^^^^^^^^ Trait::Item<T>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_cycle_2() {
 +    // this is a legitimate cycle
 +    check_types(
 +        r#"
 +//- /main.rs
 +trait Trait<T> {
 +    type Item;
 +}
 +
 +fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
 +    let x: T::Item = no_matter;
 +}                  //^^^^^^^^^ {unknown}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_cycle_3() {
 +    // this is a cycle for rustc; we currently accept it
 +    check_types(
 +        r#"
 +//- /main.rs
 +trait Trait {
 +    type Item;
 +    type OtherItem;
 +}
 +
 +fn test<T>() where T: Trait<OtherItem = T::Item> {
 +    let x: T::Item = no_matter;
 +}                  //^^^^^^^^^ Trait::Item<T>
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn unselected_projection_in_trait_env_no_cycle() {
 +    // this is not a cycle
 +    check_types(
 +        r#"
 +//- /main.rs
 +trait Index {
 +    type Output;
 +}
 +
 +type Key<S: UnificationStoreBase> = <S as UnificationStoreBase>::Key;
 +
 +pub trait UnificationStoreBase: Index<Output = Key<Self>> {
 +    type Key;
 +
 +    fn len(&self) -> usize;
 +}
 +
 +pub trait UnificationStoreMut: UnificationStoreBase {
 +    fn push(&mut self, value: Self::Key);
 +}
 +
 +fn test<T>(t: T) where T: UnificationStoreMut {
 +    let x;
 +    t.push(x);
 +    let y: Key<T>;
 +    (x, y);
 +} //^^^^^^ (UnificationStoreBase::Key<T>, UnificationStoreBase::Key<T>)
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn inline_assoc_type_bounds_1() {
 +    check_types(
 +        r#"
 +trait Iterator {
 +    type Item;
 +}
 +trait OtherTrait<T> {
 +    fn foo(&self) -> T;
 +}
 +
 +// workaround for Chalk assoc type normalization problems
 +pub struct S<T>;
 +impl<T: Iterator> Iterator for S<T> {
 +    type Item = <T as Iterator>::Item;
 +}
 +
 +fn test<I: Iterator<Item: OtherTrait<u32>>>() {
 +    let x: <S<I> as Iterator>::Item;
 +    x.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn inline_assoc_type_bounds_2() {
 +    check_types(
 +        r#"
 +trait Iterator {
 +    type Item;
 +}
 +
 +fn test<I: Iterator<Item: Iterator<Item = u32>>>() {
 +    let x: <<I as Iterator>::Item as Iterator>::Item;
 +    x;
 +} //^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn proc_macro_server_types() {
 +    check_infer(
 +        r#"
 +macro_rules! with_api {
 +    ($S:ident, $self:ident, $m:ident) => {
 +        $m! {
 +            TokenStream {
 +                fn new() -> $S::TokenStream;
 +            },
 +            Group {
 +            },
 +        }
 +    };
 +}
 +macro_rules! associated_item {
 +    (type TokenStream) =>
 +        (type TokenStream: 'static;);
 +    (type Group) =>
 +        (type Group: 'static;);
 +    ($($item:tt)*) => ($($item)*;)
 +}
 +macro_rules! declare_server_traits {
 +    ($($name:ident {
 +        $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
 +    }),* $(,)?) => {
 +        pub trait Types {
 +            $(associated_item!(type $name);)*
 +        }
 +
 +        $(pub trait $name: Types {
 +            $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)*
 +        })*
 +
 +        pub trait Server: Types $(+ $name)* {}
 +        impl<S: Types $(+ $name)*> Server for S {}
 +    }
 +}
 +
 +with_api!(Self, self_, declare_server_traits);
 +struct G {}
 +struct T {}
 +struct RustAnalyzer;
 +impl Types for RustAnalyzer {
 +    type TokenStream = T;
 +    type Group = G;
 +}
 +
 +fn make<T>() -> T { loop {} }
 +impl TokenStream for RustAnalyzer {
 +    fn new() -> Self::TokenStream {
 +        let group: Self::Group = make();
 +        make()
 +    }
 +}"#,
 +        expect![[r#"
 +            1075..1086 '{ loop {} }': T
 +            1077..1084 'loop {}': !
 +            1082..1084 '{}': ()
 +            1157..1220 '{     ...     }': T
 +            1171..1176 'group': G
 +            1192..1196 'make': fn make<G>() -> G
 +            1192..1198 'make()': G
 +            1208..1212 'make': fn make<T>() -> T
 +            1208..1214 'make()': T
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn unify_impl_trait() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Trait<T> {}
 +
 +fn foo(x: impl Trait<u32>) { loop {} }
 +fn bar<T>(x: impl Trait<T>) -> T { loop {} }
 +
 +struct S<T>(T);
 +impl<T> Trait<T> for S<T> {}
 +
 +fn default<T>() -> T { loop {} }
 +
 +fn test() -> impl Trait<i32> {
 +    let s1 = S(default());
 +    foo(s1);
 +    let x: i32 = bar(S(default()));
 +    S(default())
 +}"#,
 +        expect![[r#"
 +            26..27 'x': impl Trait<u32>
 +            46..57 '{ loop {} }': ()
 +            48..55 'loop {}': !
 +            53..55 '{}': ()
 +            68..69 'x': impl Trait<T>
 +            91..102 '{ loop {} }': T
 +            93..100 'loop {}': !
 +            98..100 '{}': ()
 +            171..182 '{ loop {} }': T
 +            173..180 'loop {}': !
 +            178..180 '{}': ()
 +            213..309 '{     ...t()) }': S<i32>
 +            223..225 's1': S<u32>
 +            228..229 'S': S<u32>(u32) -> S<u32>
 +            228..240 'S(default())': S<u32>
 +            230..237 'default': fn default<u32>() -> u32
 +            230..239 'default()': u32
 +            246..249 'foo': fn foo(S<u32>)
 +            246..253 'foo(s1)': ()
 +            250..252 's1': S<u32>
 +            263..264 'x': i32
 +            272..275 'bar': fn bar<i32>(S<i32>) -> i32
 +            272..289 'bar(S(...lt()))': i32
 +            276..277 'S': S<i32>(i32) -> S<i32>
 +            276..288 'S(default())': S<i32>
 +            278..285 'default': fn default<i32>() -> i32
 +            278..287 'default()': i32
 +            295..296 'S': S<i32>(i32) -> S<i32>
 +            295..307 'S(default())': S<i32>
 +            297..304 'default': fn default<i32>() -> i32
 +            297..306 'default()': i32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn assoc_types_from_bounds() {
 +    check_infer(
 +        r#"
 +//- minicore: fn
 +trait T {
 +    type O;
 +}
 +
 +impl T for () {
 +    type O = ();
 +}
 +
 +fn f<X, F>(_v: F)
 +where
 +    X: T,
 +    F: FnOnce(&X::O),
 +{ }
 +
 +fn main() {
 +    f::<(), _>(|z| { z; });
 +}"#,
 +        expect![[r#"
 +            72..74 '_v': F
 +            117..120 '{ }': ()
 +            132..163 '{     ... }); }': ()
 +            138..148 'f::<(), _>': fn f<(), |&()| -> ()>(|&()| -> ())
 +            138..160 'f::<()... z; })': ()
 +            149..159 '|z| { z; }': |&()| -> ()
 +            150..151 'z': &()
 +            153..159 '{ z; }': ()
 +            155..156 'z': &()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn associated_type_bound() {
 +    check_types(
 +        r#"
 +pub trait Trait {
 +    type Item: OtherTrait<u32>;
 +}
 +pub trait OtherTrait<T> {
 +    fn foo(&self) -> T;
 +}
 +
 +// this is just a workaround for chalk#234
 +pub struct S<T>;
 +impl<T: Trait> Trait for S<T> {
 +    type Item = <T as Trait>::Item;
 +}
 +
 +fn test<T: Trait>() {
 +    let y: <S<T> as Trait>::Item = no_matter;
 +    y.foo();
 +} //^^^^^^^ u32
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn dyn_trait_through_chalk() {
 +    check_types(
 +        r#"
 +//- minicore: deref
 +struct Box<T: ?Sized> {}
 +impl<T: ?Sized> core::ops::Deref for Box<T> {
 +    type Target = T;
 +}
 +trait Trait {
 +    fn foo(&self);
 +}
 +
 +fn test(x: Box<dyn Trait>) {
 +    x.foo();
 +} //^^^^^^^ ()
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn string_to_owned() {
 +    check_types(
 +        r#"
 +struct String {}
 +pub trait ToOwned {
 +    type Owned;
 +    fn to_owned(&self) -> Self::Owned;
 +}
 +impl ToOwned for str {
 +    type Owned = String;
 +}
 +fn test() {
 +    "foo".to_owned();
 +} //^^^^^^^^^^^^^^^^ String
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn iterator_chain() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn, option
 +pub trait Iterator {
 +    type Item;
 +
 +    fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
 +    where
 +        F: FnMut(Self::Item) -> Option<B>,
 +    { loop {} }
 +
 +    fn for_each<F>(self, f: F)
 +    where
 +        F: FnMut(Self::Item),
 +    { loop {} }
 +}
 +
 +pub trait IntoIterator {
 +    type Item;
 +    type IntoIter: Iterator<Item = Self::Item>;
 +    fn into_iter(self) -> Self::IntoIter;
 +}
 +
 +pub struct FilterMap<I, F> { }
 +impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
 +where
 +    F: FnMut(I::Item) -> Option<B>,
 +{
 +    type Item = B;
 +}
 +
 +#[stable(feature = "rust1", since = "1.0.0")]
 +impl<I: Iterator> IntoIterator for I {
 +    type Item = I::Item;
 +    type IntoIter = I;
 +
 +    fn into_iter(self) -> I {
 +        self
 +    }
 +}
 +
 +struct Vec<T> {}
 +impl<T> Vec<T> {
 +    fn new() -> Self { loop {} }
 +}
 +
 +impl<T> IntoIterator for Vec<T> {
 +    type Item = T;
 +    type IntoIter = IntoIter<T>;
 +}
 +
 +pub struct IntoIter<T> { }
 +impl<T> Iterator for IntoIter<T> {
 +    type Item = T;
 +}
 +
 +fn main() {
 +    Vec::<i32>::new().into_iter()
 +    .filter_map(|x| if x > 0 { Some(x as u32) } else { None })
 +    .for_each(|y| { y; });
 +}"#,
 +        expect![[r#"
 +            61..65 'self': Self
 +            67..68 'f': F
 +            152..163 '{ loop {} }': FilterMap<Self, F>
 +            154..161 'loop {}': !
 +            159..161 '{}': ()
 +            184..188 'self': Self
 +            190..191 'f': F
 +            240..251 '{ loop {} }': ()
 +            242..249 'loop {}': !
 +            247..249 '{}': ()
 +            360..364 'self': Self
 +            689..693 'self': I
 +            700..720 '{     ...     }': I
 +            710..714 'self': I
 +            779..790 '{ loop {} }': Vec<T>
 +            781..788 'loop {}': !
 +            786..788 '{}': ()
 +            977..1104 '{     ... }); }': ()
 +            983..998 'Vec::<i32>::new': fn new<i32>() -> Vec<i32>
 +            983..1000 'Vec::<...:new()': Vec<i32>
 +            983..1012 'Vec::<...iter()': IntoIter<i32>
 +            983..1075 'Vec::<...one })': FilterMap<IntoIter<i32>, |i32| -> Option<u32>>
 +            983..1101 'Vec::<... y; })': ()
 +            1029..1074 '|x| if...None }': |i32| -> Option<u32>
 +            1030..1031 'x': i32
 +            1033..1074 'if x >...None }': Option<u32>
 +            1036..1037 'x': i32
 +            1036..1041 'x > 0': bool
 +            1040..1041 '0': i32
 +            1042..1060 '{ Some...u32) }': Option<u32>
 +            1044..1048 'Some': Some<u32>(u32) -> Option<u32>
 +            1044..1058 'Some(x as u32)': Option<u32>
 +            1049..1050 'x': i32
 +            1049..1057 'x as u32': u32
 +            1066..1074 '{ None }': Option<u32>
 +            1068..1072 'None': Option<u32>
 +            1090..1100 '|y| { y; }': |u32| -> ()
 +            1091..1092 'y': u32
 +            1094..1100 '{ y; }': ()
 +            1096..1097 'y': u32
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn nested_assoc() {
 +    check_types(
 +        r#"
 +struct Bar;
 +struct Foo;
 +
 +trait A {
 +    type OutputA;
 +}
 +
 +impl A for Bar {
 +    type OutputA = Foo;
 +}
 +
 +trait B {
 +    type Output;
 +    fn foo() -> Self::Output;
 +}
 +
 +impl<T:A> B for T {
 +    type Output = T::OutputA;
 +    fn foo() -> Self::Output { loop {} }
 +}
 +
 +fn main() {
 +    Bar::foo();
 +} //^^^^^^^^^^ Foo
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn trait_object_no_coercion() {
 +    check_infer_with_mismatches(
 +        r#"
 +trait Foo {}
 +
 +fn foo(x: &dyn Foo) {}
 +
 +fn test(x: &dyn Foo) {
 +    foo(x);
 +}"#,
 +        expect![[r#"
 +            21..22 'x': &dyn Foo
 +            34..36 '{}': ()
 +            46..47 'x': &dyn Foo
 +            59..74 '{     foo(x); }': ()
 +            65..68 'foo': fn foo(&dyn Foo)
 +            65..71 'foo(x)': ()
 +            69..70 'x': &dyn Foo
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn builtin_copy() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: copy
 +struct IsCopy;
 +impl Copy for IsCopy {}
 +struct NotCopy;
 +
 +trait Test { fn test(&self) -> bool; }
 +impl<T: Copy> Test for T {}
 +
 +fn test() {
 +    IsCopy.test();
 +    NotCopy.test();
 +    (IsCopy, IsCopy).test();
 +    (IsCopy, NotCopy).test();
 +}"#,
 +        expect![[r#"
 +            78..82 'self': &Self
 +            134..235 '{     ...t(); }': ()
 +            140..146 'IsCopy': IsCopy
 +            140..153 'IsCopy.test()': bool
 +            159..166 'NotCopy': NotCopy
 +            159..173 'NotCopy.test()': {unknown}
 +            179..195 '(IsCop...sCopy)': (IsCopy, IsCopy)
 +            179..202 '(IsCop...test()': bool
 +            180..186 'IsCopy': IsCopy
 +            188..194 'IsCopy': IsCopy
 +            208..225 '(IsCop...tCopy)': (IsCopy, NotCopy)
 +            208..232 '(IsCop...test()': {unknown}
 +            209..215 'IsCopy': IsCopy
 +            217..224 'NotCopy': NotCopy
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn builtin_fn_def_copy() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: copy
 +fn foo() {}
 +fn bar<T: Copy>(T) -> T {}
 +struct Struct(usize);
 +enum Enum { Variant(usize) }
 +
 +trait Test { fn test(&self) -> bool; }
 +impl<T: Copy> Test for T {}
 +
 +fn test() {
 +    foo.test();
 +    bar.test();
 +    Struct.test();
 +    Enum::Variant.test();
 +}"#,
 +        expect![[r#"
 +            9..11 '{}': ()
 +            28..29 'T': {unknown}
 +            36..38 '{}': T
 +            36..38: expected T, got ()
 +            113..117 'self': &Self
 +            169..249 '{     ...t(); }': ()
 +            175..178 'foo': fn foo()
 +            175..185 'foo.test()': bool
 +            191..194 'bar': fn bar<{unknown}>({unknown}) -> {unknown}
 +            191..201 'bar.test()': bool
 +            207..213 'Struct': Struct(usize) -> Struct
 +            207..220 'Struct.test()': bool
 +            226..239 'Enum::Variant': Variant(usize) -> Enum
 +            226..246 'Enum::...test()': bool
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn builtin_fn_ptr_copy() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: copy
 +trait Test { fn test(&self) -> bool; }
 +impl<T: Copy> Test for T {}
 +
 +fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) {
 +    f1.test();
 +    f2.test();
 +    f3.test();
 +}"#,
 +        expect![[r#"
 +            22..26 'self': &Self
 +            76..78 'f1': fn()
 +            86..88 'f2': fn(usize) -> u8
 +            107..109 'f3': fn(u8, u8) -> &u8
 +            130..178 '{     ...t(); }': ()
 +            136..138 'f1': fn()
 +            136..145 'f1.test()': bool
 +            151..153 'f2': fn(usize) -> u8
 +            151..160 'f2.test()': bool
 +            166..168 'f3': fn(u8, u8) -> &u8
 +            166..175 'f3.test()': bool
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn builtin_sized() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: sized
 +trait Test { fn test(&self) -> bool; }
 +impl<T: Sized> Test for T {}
 +
 +fn test() {
 +    1u8.test();
 +    (*"foo").test(); // not Sized
 +    (1u8, 1u8).test();
 +    (1u8, *"foo").test(); // not Sized
 +}"#,
 +        expect![[r#"
 +            22..26 'self': &Self
 +            79..194 '{     ...ized }': ()
 +            85..88 '1u8': u8
 +            85..95 '1u8.test()': bool
 +            101..116 '(*"foo").test()': {unknown}
 +            102..108 '*"foo"': str
 +            103..108 '"foo"': &str
 +            135..145 '(1u8, 1u8)': (u8, u8)
 +            135..152 '(1u8, ...test()': bool
 +            136..139 '1u8': u8
 +            141..144 '1u8': u8
 +            158..171 '(1u8, *"foo")': (u8, str)
 +            158..178 '(1u8, ...test()': {unknown}
 +            159..162 '1u8': u8
 +            164..170 '*"foo"': str
 +            165..170 '"foo"': &str
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn integer_range_iterate() {
 +    check_types(
 +        r#"
 +//- /main.rs crate:main deps:core
 +fn test() {
 +    for x in 0..100 { x; }
 +}                   //^ i32
 +
 +//- /core.rs crate:core
 +pub mod ops {
 +    pub struct Range<Idx> {
 +        pub start: Idx,
 +        pub end: Idx,
 +    }
 +}
 +
 +pub mod iter {
 +    pub trait Iterator {
 +        type Item;
 +    }
 +
 +    pub trait IntoIterator {
 +        type Item;
 +        type IntoIter: Iterator<Item = Self::Item>;
 +    }
 +
 +    impl<T> IntoIterator for T where T: Iterator {
 +        type Item = <T as Iterator>::Item;
 +        type IntoIter = Self;
 +    }
 +}
 +
 +trait Step {}
 +impl Step for i32 {}
 +impl Step for i64 {}
 +
 +impl<A: Step> iter::Iterator for ops::Range<A> {
 +    type Item = A;
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_closure_arg() {
 +    check_infer(
 +        r#"
 +//- /lib.rs
 +
 +enum Option<T> {
 +    None,
 +    Some(T)
 +}
 +
 +fn foo() {
 +    let s = Option::None;
 +    let f = |x: Option<i32>| {};
 +    (&f)(s)
 +}"#,
 +        expect![[r#"
 +            52..126 '{     ...)(s) }': ()
 +            62..63 's': Option<i32>
 +            66..78 'Option::None': Option<i32>
 +            88..89 'f': |Option<i32>| -> ()
 +            92..111 '|x: Op...2>| {}': |Option<i32>| -> ()
 +            93..94 'x': Option<i32>
 +            109..111 '{}': ()
 +            117..124 '(&f)(s)': ()
 +            118..120 '&f': &|Option<i32>| -> ()
 +            119..120 'f': |Option<i32>| -> ()
 +            122..123 's': Option<i32>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn dyn_fn_param_informs_call_site_closure_signature() {
 +    cov_mark::check!(dyn_fn_param_informs_call_site_closure_signature);
 +    check_types(
 +        r#"
 +//- minicore: fn, coerce_unsized
 +struct S;
 +impl S {
 +    fn inherent(&self) -> u8 { 0 }
 +}
 +fn take_dyn_fn(f: &dyn Fn(S)) {}
 +
 +fn f() {
 +    take_dyn_fn(&|x| { x.inherent(); });
 +                     //^^^^^^^^^^^^ u8
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn infer_fn_trait_arg() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn, option
 +fn foo<F, T>(f: F) -> T
 +where
 +    F: Fn(Option<i32>) -> T,
 +{
 +    let s = None;
 +    f(s)
 +}
 +"#,
 +        expect![[r#"
 +            13..14 'f': F
 +            59..89 '{     ...f(s) }': T
 +            69..70 's': Option<i32>
 +            73..77 'None': Option<i32>
 +            83..84 'f': F
 +            83..87 'f(s)': T
 +            85..86 's': Option<i32>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_box_fn_arg() {
 +    // The type mismatch is because we don't define Unsize and CoerceUnsized
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn, deref, option
 +#[lang = "owned_box"]
 +pub struct Box<T: ?Sized> {
 +    inner: *mut T,
 +}
 +
 +impl<T: ?Sized> core::ops::Deref for Box<T> {
 +    type Target = T;
 +
 +    fn deref(&self) -> &T {
 +        &self.inner
 +    }
 +}
 +
 +fn foo() {
 +    let s = None;
 +    let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {});
 +    f(&s);
 +}"#,
 +        expect![[r#"
 +            154..158 'self': &Box<T>
 +            166..193 '{     ...     }': &T
 +            176..187 '&self.inner': &*mut T
 +            177..181 'self': &Box<T>
 +            177..187 'self.inner': *mut T
 +            206..296 '{     ...&s); }': ()
 +            216..217 's': Option<i32>
 +            220..224 'None': Option<i32>
 +            234..235 'f': Box<dyn FnOnce(&Option<i32>)>
 +            269..282 'box (|ps| {})': Box<|&Option<i32>| -> ()>
 +            274..281 '|ps| {}': |&Option<i32>| -> ()
 +            275..277 'ps': &Option<i32>
 +            279..281 '{}': ()
 +            288..289 'f': Box<dyn FnOnce(&Option<i32>)>
 +            288..293 'f(&s)': ()
 +            290..292 '&s': &Option<i32>
 +            291..292 's': Option<i32>
 +            269..282: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|&Option<i32>| -> ()>
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_dyn_fn_output() {
 +    check_types(
 +        r#"
 +//- minicore: fn
 +fn foo() {
 +    let f: &dyn Fn() -> i32;
 +    f();
 +  //^^^ i32
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn infer_dyn_fn_once_output() {
 +    check_types(
 +        r#"
 +//- minicore: fn
 +fn foo() {
 +    let f: dyn FnOnce() -> i32;
 +    f();
 +  //^^^ i32
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn variable_kinds_1() {
 +    check_types(
 +        r#"
 +trait Trait<T> { fn get(self, t: T) -> T; }
 +struct S;
 +impl Trait<u128> for S {}
 +impl Trait<f32> for S {}
 +fn test() {
 +    S.get(1);
 +  //^^^^^^^^ u128
 +    S.get(1.);
 +  //^^^^^^^^^ f32
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn variable_kinds_2() {
 +    check_types(
 +        r#"
 +trait Trait { fn get(self) -> Self; }
 +impl Trait for u128 {}
 +impl Trait for f32 {}
 +fn test() {
 +    1.get();
 +  //^^^^^^^ u128
 +    (1.).get();
 +  //^^^^^^^^^^ f32
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn underscore_import() {
 +    check_types(
 +        r#"
 +mod tr {
 +    pub trait Tr {
 +        fn method(&self) -> u8 { 0 }
 +    }
 +}
 +
 +struct Tr;
 +impl crate::tr::Tr for Tr {}
 +
 +use crate::tr::Tr as _;
 +fn test() {
 +    Tr.method();
 +  //^^^^^^^^^^^ u8
 +}
 +    "#,
 +    );
 +}
 +
 +#[test]
 +fn inner_use() {
 +    check_types(
 +        r#"
 +mod m {
 +    pub trait Tr {
 +        fn method(&self) -> u8 { 0 }
 +    }
 +
 +    impl Tr for () {}
 +}
 +
 +fn f() {
 +    use m::Tr;
 +
 +    ().method();
 +  //^^^^^^^^^^^ u8
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn trait_in_scope_with_inner_item() {
 +    check_infer(
 +        r#"
 +mod m {
 +    pub trait Tr {
 +        fn method(&self) -> u8 { 0 }
 +    }
 +
 +    impl Tr for () {}
 +}
 +
 +use m::Tr;
 +
 +fn f() {
 +    fn inner() {
 +        ().method();
 +      //^^^^^^^^^^^ u8
 +    }
 +}"#,
 +        expect![[r#"
 +            46..50 'self': &Self
 +            58..63 '{ 0 }': u8
 +            60..61 '0': u8
 +            115..185 '{     ...   } }': ()
 +            132..183 '{     ...     }': ()
 +            142..144 '()': ()
 +            142..153 '().method()': u8
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn inner_use_in_block() {
 +    check_types(
 +        r#"
 +mod m {
 +    pub trait Tr {
 +        fn method(&self) -> u8 { 0 }
 +    }
 +
 +    impl Tr for () {}
 +}
 +
 +fn f() {
 +    {
 +        use m::Tr;
 +
 +        ().method();
 +      //^^^^^^^^^^^ u8
 +    }
 +
 +    {
 +        ().method();
 +      //^^^^^^^^^^^ {unknown}
 +    }
 +
 +    ().method();
 +  //^^^^^^^^^^^ {unknown}
 +}
 +        "#,
 +    );
 +}
 +
 +#[test]
 +fn nested_inner_function_calling_self() {
 +    check_infer(
 +        r#"
 +struct S;
 +fn f() {
 +    fn inner() -> S {
 +        let s = inner();
 +    }
 +}"#,
 +        expect![[r#"
 +            17..73 '{     ...   } }': ()
 +            39..71 '{     ...     }': S
 +            53..54 's': S
 +            57..62 'inner': fn inner() -> S
 +            57..64 'inner()': S
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn infer_default_trait_type_parameter() {
 +    check_infer(
 +        r#"
 +struct A;
 +
 +trait Op<RHS=Self> {
 +    type Output;
 +
 +    fn do_op(self, rhs: RHS) -> Self::Output;
 +}
 +
 +impl Op for A {
 +    type Output = bool;
 +
 +    fn do_op(self, rhs: Self) -> Self::Output {
 +        true
 +    }
 +}
 +
 +fn test() {
 +    let x = A;
 +    let y = A;
 +    let r = x.do_op(y);
 +}"#,
 +        expect![[r#"
 +            63..67 'self': Self
 +            69..72 'rhs': RHS
 +            153..157 'self': A
 +            159..162 'rhs': A
 +            186..206 '{     ...     }': bool
 +            196..200 'true': bool
 +            220..277 '{     ...(y); }': ()
 +            230..231 'x': A
 +            234..235 'A': A
 +            245..246 'y': A
 +            249..250 'A': A
 +            260..261 'r': bool
 +            264..265 'x': A
 +            264..274 'x.do_op(y)': bool
 +            272..273 'y': A
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn qualified_path_as_qualified_trait() {
 +    check_infer(
 +        r#"
 +mod foo {
 +
 +    pub trait Foo {
 +        type Target;
 +    }
 +    pub trait Bar {
 +        type Output;
 +        fn boo() -> Self::Output {
 +            loop {}
 +        }
 +    }
 +}
 +
 +struct F;
 +impl foo::Foo for F {
 +    type Target = ();
 +}
 +impl foo::Bar for F {
 +    type Output = <F as foo::Foo>::Target;
 +}
 +
 +fn foo() {
 +    use foo::Bar;
 +    let x = <F as Bar>::boo();
 +}"#,
 +        expect![[r#"
 +            132..163 '{     ...     }': Bar::Output<Self>
 +            146..153 'loop {}': !
 +            151..153 '{}': ()
 +            306..358 '{     ...o(); }': ()
 +            334..335 'x': ()
 +            338..353 '<F as Bar>::boo': fn boo<F>() -> <F as Bar>::Output
 +            338..355 '<F as ...:boo()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn renamed_extern_crate_in_block() {
 +    check_types(
 +        r#"
 +//- /lib.rs crate:lib deps:serde
 +use serde::Deserialize;
 +
 +struct Foo {}
 +
 +const _ : () = {
 +    extern crate serde as _serde;
 +    impl _serde::Deserialize for Foo {
 +        fn deserialize() -> u8 { 0 }
 +    }
 +};
 +
 +fn foo() {
 +    Foo::deserialize();
 +  //^^^^^^^^^^^^^^^^^^ u8
 +}
 +
 +//- /serde.rs crate:serde
 +
 +pub trait Deserialize {
 +    fn deserialize() -> u8;
 +}"#,
 +    );
 +}
 +
 +#[test]
 +fn bin_op_with_rhs_is_self_for_assoc_bound() {
 +    check_no_mismatches(
 +        r#"//- minicore: eq
 +        fn repro<T>(t: T) -> bool
 +where
 +    T: Request,
 +    T::Output: Convertable,
 +{
 +    let a = execute(&t).convert();
 +    let b = execute(&t).convert();
 +    a.eq(&b);
 +    let a = execute(&t).convert2();
 +    let b = execute(&t).convert2();
 +    a.eq(&b)
 +}
 +fn execute<T>(t: &T) -> T::Output
 +where
 +    T: Request,
 +{
 +    <T as Request>::output()
 +}
 +trait Convertable {
 +    type TraitSelf: PartialEq<Self::TraitSelf>;
 +    type AssocAsDefaultSelf: PartialEq;
 +    fn convert(self) -> Self::AssocAsDefaultSelf;
 +    fn convert2(self) -> Self::TraitSelf;
 +}
 +trait Request {
 +    type Output;
 +    fn output() -> Self::Output;
 +}
 +     "#,
 +    );
 +}
 +
 +#[test]
 +fn bin_op_adt_with_rhs_primitive() {
 +    check_infer_with_mismatches(
 +        r#"
 +#[lang = "add"]
 +pub trait Add<Rhs = Self> {
 +    type Output;
 +    fn add(self, rhs: Rhs) -> Self::Output;
 +}
 +
 +struct Wrapper(u32);
 +impl Add<u32> for Wrapper {
 +    type Output = Self;
 +    fn add(self, rhs: u32) -> Wrapper {
 +        Wrapper(rhs)
 +    }
 +}
 +fn main(){
 +    let wrapped = Wrapper(10);
 +    let num: u32 = 2;
 +    let res = wrapped + num;
 +
 +}"#,
 +        expect![[r#"
 +            72..76 'self': Self
 +            78..81 'rhs': Rhs
 +            192..196 'self': Wrapper
 +            198..201 'rhs': u32
 +            219..247 '{     ...     }': Wrapper
 +            229..236 'Wrapper': Wrapper(u32) -> Wrapper
 +            229..241 'Wrapper(rhs)': Wrapper
 +            237..240 'rhs': u32
 +            259..345 '{     ...um;  }': ()
 +            269..276 'wrapped': Wrapper
 +            279..286 'Wrapper': Wrapper(u32) -> Wrapper
 +            279..290 'Wrapper(10)': Wrapper
 +            287..289 '10': u32
 +            300..303 'num': u32
 +            311..312 '2': u32
 +            322..325 'res': Wrapper
 +            328..335 'wrapped': Wrapper
 +            328..341 'wrapped + num': Wrapper
 +            338..341 'num': u32
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn array_length() {
 +    check_infer(
 +        r#"
 +trait T {
 +    type Output;
 +    fn do_thing(&self) -> Self::Output;
 +}
 +
 +impl T for [u8; 4] {
 +    type Output = usize;
 +    fn do_thing(&self) -> Self::Output {
 +        2
 +    }
 +}
 +
 +impl T for [u8; 2] {
 +    type Output = u8;
 +    fn do_thing(&self) -> Self::Output {
 +        2
 +    }
 +}
 +
 +fn main() {
 +    let v = [0u8; 2];
 +    let v2 = v.do_thing();
 +    let v3 = [0u8; 4];
 +    let v4 = v3.do_thing();
 +}
 +"#,
 +        expect![[r#"
 +            44..48 'self': &Self
 +            133..137 'self': &[u8; 4]
 +            155..172 '{     ...     }': usize
 +            165..166 '2': usize
 +            236..240 'self': &[u8; 2]
 +            258..275 '{     ...     }': u8
 +            268..269 '2': u8
 +            289..392 '{     ...g(); }': ()
 +            299..300 'v': [u8; 2]
 +            303..311 '[0u8; 2]': [u8; 2]
 +            304..307 '0u8': u8
 +            309..310 '2': usize
 +            321..323 'v2': u8
 +            326..327 'v': [u8; 2]
 +            326..338 'v.do_thing()': u8
 +            348..350 'v3': [u8; 4]
 +            353..361 '[0u8; 4]': [u8; 4]
 +            354..357 '0u8': u8
 +            359..360 '4': usize
 +            371..373 'v4': usize
 +            376..378 'v3': [u8; 4]
 +            376..389 'v3.do_thing()': usize
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn const_generics() {
 +    check_infer(
 +        r#"
 +trait T {
 +    type Output;
 +    fn do_thing(&self) -> Self::Output;
 +}
 +
 +impl<const L: usize> T for [u8; L] {
 +    type Output = [u8; L];
 +    fn do_thing(&self) -> Self::Output {
 +        *self
 +    }
 +}
 +
 +fn main() {
 +    let v = [0u8; 2];
 +    let v2 = v.do_thing();
 +}
 +"#,
 +        expect![[r#"
 +            44..48 'self': &Self
 +            151..155 'self': &[u8; L]
 +            173..194 '{     ...     }': [u8; L]
 +            183..188 '*self': [u8; L]
 +            184..188 'self': &[u8; L]
 +            208..260 '{     ...g(); }': ()
 +            218..219 'v': [u8; 2]
 +            222..230 '[0u8; 2]': [u8; 2]
 +            223..226 '0u8': u8
 +            228..229 '2': usize
 +            240..242 'v2': [u8; 2]
 +            245..246 'v': [u8; 2]
 +            245..257 'v.do_thing()': [u8; 2]
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn fn_returning_unit() {
 +    check_infer_with_mismatches(
 +        r#"
 +//- minicore: fn
 +fn test<F: FnOnce()>(f: F) {
 +    let _: () = f();
 +}"#,
 +        expect![[r#"
 +            21..22 'f': F
 +            27..51 '{     ...f(); }': ()
 +            37..38 '_': ()
 +            45..46 'f': F
 +            45..48 'f()': ()
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn trait_in_scope_of_trait_impl() {
 +    check_infer(
 +        r#"
 +mod foo {
 +    pub trait Foo {
 +        fn foo(self);
 +        fn bar(self) -> usize { 0 }
 +    }
 +}
 +impl foo::Foo for u32 {
 +    fn foo(self) {
 +        let _x = self.bar();
 +    }
 +}
 +    "#,
 +        expect![[r#"
 +            45..49 'self': Self
 +            67..71 'self': Self
 +            82..87 '{ 0 }': usize
 +            84..85 '0': usize
 +            131..135 'self': u32
 +            137..173 '{     ...     }': ()
 +            151..153 '_x': usize
 +            156..160 'self': u32
 +            156..166 'self.bar()': usize
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn infer_async_ret_type() {
 +    check_types(
 +        r#"
 +//- minicore: future, result
 +struct Fooey;
 +
 +impl Fooey {
 +    fn collect<B: Convert>(self) -> B {
 +        B::new()
 +    }
 +}
 +
 +trait Convert {
 +    fn new() -> Self;
 +}
 +impl Convert for u32 {
 +    fn new() -> Self { 0 }
 +}
 +
 +async fn get_accounts() -> Result<u32, ()> {
 +    let ret = Fooey.collect();
 +    //        ^^^^^^^^^^^^^^^ u32
 +    Ok(ret)
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn local_impl_1() {
 +    check!(block_local_impls);
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +}
 +
 +fn test() {
 +    struct S;
 +    impl Trait<u32> for S {
 +        fn foo(&self) -> u32 { 0 }
 +    }
 +
 +    S.foo();
 + // ^^^^^^^ u32
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn local_impl_2() {
 +    check!(block_local_impls);
 +    check_types(
 +        r#"
 +struct S;
 +
 +fn test() {
 +    trait Trait<T> {
 +        fn foo(&self) -> T;
 +    }
 +    impl Trait<u32> for S {
 +        fn foo(&self) -> u32 { 0 }
 +    }
 +
 +    S.foo();
 + // ^^^^^^^ u32
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn local_impl_3() {
 +    check!(block_local_impls);
 +    check_types(
 +        r#"
 +trait Trait<T> {
 +    fn foo(&self) -> T;
 +}
 +
 +fn test() {
 +    struct S1;
 +    {
 +        struct S2;
 +
 +        impl Trait<S1> for S2 {
 +            fn foo(&self) -> S1 { S1 }
 +        }
 +
 +        S2.foo();
 +     // ^^^^^^^^ S1
 +    }
 +}
 +"#,
 +    );
 +}
 +
 +#[test]
 +fn associated_type_sized_bounds() {
 +    check_infer(
 +        r#"
 +//- minicore: sized
 +struct Yes;
 +trait IsSized { const IS_SIZED: Yes; }
 +impl<T: Sized> IsSized for T { const IS_SIZED: Yes = Yes; }
 +
 +trait Foo {
 +    type Explicit: Sized;
 +    type Implicit;
 +    type Relaxed: ?Sized;
 +}
 +fn f<F: Foo>() {
 +    F::Explicit::IS_SIZED;
 +    F::Implicit::IS_SIZED;
 +    F::Relaxed::IS_SIZED;
 +}
 +"#,
 +        expect![[r#"
 +            104..107 'Yes': Yes
 +            212..295 '{     ...ZED; }': ()
 +            218..239 'F::Exp..._SIZED': Yes
 +            245..266 'F::Imp..._SIZED': Yes
 +            272..292 'F::Rel..._SIZED': {unknown}
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn dyn_map() {
 +    check_types(
 +        r#"
 +pub struct Key<K, V, P = (K, V)> {}
 +
 +pub trait Policy {
 +    type K;
 +    type V;
 +}
 +
 +impl<K, V> Policy for (K, V) {
 +    type K = K;
 +    type V = V;
 +}
 +
 +pub struct KeyMap<KEY> {}
 +
 +impl<P: Policy> KeyMap<Key<P::K, P::V, P>> {
 +    pub fn get(&self, key: &P::K) -> P::V {
 +        loop {}
 +    }
 +}
 +
 +struct Fn {}
 +struct FunctionId {}
 +
 +fn test() {
 +    let key_map: &KeyMap<Key<Fn, FunctionId>> = loop {};
 +    let key;
 +    let result = key_map.get(key);
 +      //^^^^^^ FunctionId
 +}
 +"#,
 +    )
 +}
++
++#[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_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 50374f4b3fe47ebdd8e6907c26430a013b185687,0000000000000000000000000000000000000000..5edc16d8bce9060262914d14060b4bfd1cb3e6d2
mode 100644,000000..100644
--- /dev/null
@@@ -1,171 -1,0 +1,172 @@@
 +//! 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, diagnistics 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;
 +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,
 +    InvalidDeriveTarget,
 +    MacroError,
 +    MalformedDerive,
 +    MismatchedArgCount,
 +    MissingFields,
 +    MissingMatchArms,
 +    MissingUnsafe,
 +    NoSuchField,
 +    ReplaceFilterMapNextWithFindMap,
 +    TypeMismatch,
 +    UnimplementedBuiltinMacro,
 +    UnresolvedExternCrate,
 +    UnresolvedImport,
 +    UnresolvedMacroCall,
 +    UnresolvedModule,
 +    UnresolvedProcMacro,
 +];
 +
 +#[derive(Debug)]
 +pub struct UnresolvedModule {
 +    pub decl: InFile<AstPtr<ast::Module>>,
 +    pub candidates: Box<[String]>,
 +}
 +
 +#[derive(Debug)]
 +pub struct UnresolvedExternCrate {
 +    pub decl: InFile<AstPtr<ast::ExternCrate>>,
 +}
 +
 +#[derive(Debug)]
 +pub struct UnresolvedImport {
 +    pub decl: InFile<AstPtr<ast::UseTree>>,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct UnresolvedMacroCall {
 +    pub macro_call: InFile<SyntaxNodePtr>,
 +    pub precise_location: Option<TextRange>,
 +    pub path: ModPath,
 +    pub is_bang: bool,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct InactiveCode {
 +    pub node: InFile<SyntaxNodePtr>,
 +    pub cfg: CfgExpr,
 +    pub opts: CfgOptions,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct UnresolvedProcMacro {
 +    pub node: InFile<SyntaxNodePtr>,
 +    /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange`
 +    /// to use instead.
 +    pub precise_location: Option<TextRange>,
 +    pub macro_name: Option<String>,
 +    pub kind: MacroKind,
 +    /// The crate id of the proc-macro this macro belongs to, or `None` if the proc-macro can't be found.
 +    pub krate: CrateId,
 +}
 +
 +#[derive(Debug, Clone, Eq, PartialEq)]
 +pub struct MacroError {
 +    pub node: InFile<SyntaxNodePtr>,
 +    pub precise_location: Option<TextRange>,
 +    pub message: String,
 +}
 +
 +#[derive(Debug)]
 +pub struct UnimplementedBuiltinMacro {
 +    pub node: InFile<SyntaxNodePtr>,
 +}
 +
 +#[derive(Debug)]
 +pub struct InvalidDeriveTarget {
 +    pub node: InFile<SyntaxNodePtr>,
 +}
 +
 +#[derive(Debug)]
 +pub struct MalformedDerive {
 +    pub node: InFile<SyntaxNodePtr>,
 +}
 +
 +#[derive(Debug)]
 +pub struct NoSuchField {
 +    pub field: InFile<AstPtr<ast::RecordExprField>>,
 +}
 +
 +#[derive(Debug)]
 +pub struct BreakOutsideOfLoop {
 +    pub expr: InFile<AstPtr<ast::Expr>>,
++    pub is_break: bool,
 +}
 +
 +#[derive(Debug)]
 +pub struct MissingUnsafe {
 +    pub expr: InFile<AstPtr<ast::Expr>>,
 +}
 +
 +#[derive(Debug)]
 +pub struct MissingFields {
 +    pub file: HirFileId,
 +    pub field_list_parent: Either<AstPtr<ast::RecordExpr>, AstPtr<ast::RecordPat>>,
 +    pub field_list_parent_path: Option<AstPtr<ast::Path>>,
 +    pub missed_fields: Vec<Name>,
 +}
 +
 +#[derive(Debug)]
 +pub struct ReplaceFilterMapNextWithFindMap {
 +    pub file: HirFileId,
 +    /// This expression is the whole method chain up to and including `.filter_map(..).next()`.
 +    pub next_expr: AstPtr<ast::Expr>,
 +}
 +
 +#[derive(Debug)]
 +pub struct MismatchedArgCount {
 +    pub call_expr: InFile<AstPtr<ast::Expr>>,
 +    pub expected: usize,
 +    pub found: usize,
 +}
 +
 +#[derive(Debug)]
 +pub struct MissingMatchArms {
 +    pub file: HirFileId,
 +    pub match_expr: AstPtr<ast::Expr>,
 +    pub uncovered_patterns: String,
 +}
 +
 +#[derive(Debug)]
 +pub struct TypeMismatch {
 +    // FIXME: add mismatches in patterns as well
 +    pub expr: InFile<AstPtr<ast::Expr>>,
 +    pub expected: Type,
 +    pub actual: Type,
 +}
 +
 +pub use hir_ty::diagnostics::IncorrectCase;
index 6dccf2ed20b8e8e6dc00534678e42e7a558de526,0000000000000000000000000000000000000000..e4bb63a864719956e4b31b76e8994852f3b3ca55
mode 100644,000000..100644
--- /dev/null
@@@ -1,3663 -1,0 +1,3663 @@@
-                 hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
 +//! HIR (previously known as descriptors) provides a high-level object oriented
 +//! access to Rust code.
 +//!
 +//! The principal difference between HIR and syntax trees is that HIR is bound
 +//! to a particular crate instance. That is, it has cfg flags and features
 +//! applied. So, the relation between syntax and HIR is many-to-one.
 +//!
 +//! HIR is the public API of the all of the compiler logic above syntax trees.
 +//! It is written in "OO" style. Each type is self contained (as in, it knows it's
 +//! parents and full context). It should be "clean code".
 +//!
 +//! `hir_*` crates are the implementation of the compiler logic.
 +//! They are written in "ECS" style, with relatively little abstractions.
 +//! Many types are not self-contained, and explicitly use local indexes, arenas, etc.
 +//!
 +//! `hir` is what insulates the "we don't know how to actually write an incremental compiler"
 +//! from the ide with completions, hovers, etc. It is a (soft, internal) boundary:
 +//! <https://www.tedinski.com/2018/02/06/system-boundaries.html>.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +#![recursion_limit = "512"]
 +
 +mod semantics;
 +mod source_analyzer;
 +
 +mod from_id;
 +mod attrs;
 +mod has_source;
 +
 +pub mod diagnostics;
 +pub mod db;
 +pub mod symbols;
 +
 +mod display;
 +
 +use std::{iter, ops::ControlFlow, sync::Arc};
 +
 +use arrayvec::ArrayVec;
 +use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind};
 +use either::Either;
 +use hir_def::{
 +    adt::{ReprKind, VariantData},
 +    body::{BodyDiagnostic, SyntheticSyntax},
 +    expr::{BindingAnnotation, LabelId, Pat, PatId},
 +    generics::{TypeOrConstParamData, TypeParamProvenance},
 +    item_tree::ItemTreeNode,
 +    lang_item::LangItemTarget,
 +    nameres::{self, diagnostics::DefDiagnostic},
 +    per_ns::PerNs,
 +    resolver::{HasResolver, Resolver},
 +    src::HasSource as _,
 +    AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
 +    FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
 +    LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId,
 +    TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
 +};
 +use hir_expand::{name::name, MacroCallKind};
 +use hir_ty::{
 +    all_super_traits, autoderef,
 +    consteval::{unknown_const_as_generic, ComputedExpr, ConstEvalError, ConstExt},
 +    diagnostics::BodyValidationDiagnostic,
 +    method_resolution::{self, TyFingerprint},
 +    primitive::UintTy,
 +    subst_prefix,
 +    traits::FnTrait,
 +    AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
 +    ClosureId, DebruijnIndex, GenericArgData, InEnvironment, Interner, ParamKind,
 +    QuantifiedWhereClause, Scalar, Solution, Substitution, TraitEnvironment, TraitRefExt, Ty,
 +    TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind, WhereClause,
 +};
 +use itertools::Itertools;
 +use nameres::diagnostics::DefDiagnosticKind;
 +use once_cell::unsync::Lazy;
 +use rustc_hash::FxHashSet;
 +use stdx::{impl_from, never};
 +use syntax::{
 +    ast::{self, HasAttrs as _, HasDocComments, HasName},
 +    AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T,
 +};
 +
 +use crate::db::{DefDatabase, HirDatabase};
 +
 +pub use crate::{
 +    attrs::{HasAttrs, Namespace},
 +    diagnostics::{
 +        AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, InvalidDeriveTarget,
 +        MacroError, MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms,
 +        MissingUnsafe, NoSuchField, ReplaceFilterMapNextWithFindMap, TypeMismatch,
 +        UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
 +        UnresolvedModule, UnresolvedProcMacro,
 +    },
 +    has_source::HasSource,
 +    semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
 +};
 +
 +// Be careful with these re-exports.
 +//
 +// `hir` is the boundary between the compiler and the IDE. It should try hard to
 +// isolate the compiler from the ide, to allow the two to be refactored
 +// independently. Re-exporting something from the compiler is the sure way to
 +// breach the boundary.
 +//
 +// Generally, a refactoring which *removes* a name from this list is a good
 +// idea!
 +pub use {
 +    cfg::{CfgAtom, CfgExpr, CfgOptions},
 +    hir_def::{
 +        adt::StructKind,
 +        attr::{Attr, Attrs, AttrsWithOwner, Documentation},
 +        builtin_attr::AttributeTemplate,
 +        find_path::PrefixKind,
 +        import_map,
 +        nameres::ModuleSource,
 +        path::{ModPath, PathKind},
 +        type_ref::{Mutability, TypeRef},
 +        visibility::Visibility,
 +    },
 +    hir_expand::{
 +        name::{known, Name},
 +        ExpandResult, HirFileId, InFile, MacroFile, Origin,
 +    },
 +    hir_ty::display::HirDisplay,
 +};
 +
 +// These are negative re-exports: pub using these names is forbidden, they
 +// should remain private to hir internals.
 +#[allow(unused)]
 +use {
 +    hir_def::path::Path,
 +    hir_expand::{hygiene::Hygiene, name::AsName},
 +};
 +
 +/// hir::Crate describes a single crate. It's the main interface with which
 +/// a crate's dependencies interact. Mostly, it should be just a proxy for the
 +/// root module.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Crate {
 +    pub(crate) id: CrateId,
 +}
 +
 +#[derive(Debug)]
 +pub struct CrateDependency {
 +    pub krate: Crate,
 +    pub name: Name,
 +}
 +
 +impl Crate {
 +    pub fn origin(self, db: &dyn HirDatabase) -> CrateOrigin {
 +        db.crate_graph()[self.id].origin.clone()
 +    }
 +
 +    pub fn is_builtin(self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.origin(db), CrateOrigin::Lang(_))
 +    }
 +
 +    pub fn dependencies(self, db: &dyn HirDatabase) -> Vec<CrateDependency> {
 +        db.crate_graph()[self.id]
 +            .dependencies
 +            .iter()
 +            .map(|dep| {
 +                let krate = Crate { id: dep.crate_id };
 +                let name = dep.as_name();
 +                CrateDependency { krate, name }
 +            })
 +            .collect()
 +    }
 +
 +    pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec<Crate> {
 +        let crate_graph = db.crate_graph();
 +        crate_graph
 +            .iter()
 +            .filter(|&krate| {
 +                crate_graph[krate].dependencies.iter().any(|it| it.crate_id == self.id)
 +            })
 +            .map(|id| Crate { id })
 +            .collect()
 +    }
 +
 +    pub fn transitive_reverse_dependencies(
 +        self,
 +        db: &dyn HirDatabase,
 +    ) -> impl Iterator<Item = Crate> {
 +        db.crate_graph().transitive_rev_deps(self.id).map(|id| Crate { id })
 +    }
 +
 +    pub fn root_module(self, db: &dyn HirDatabase) -> Module {
 +        let def_map = db.crate_def_map(self.id);
 +        Module { id: def_map.module_id(def_map.root()) }
 +    }
 +
 +    pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> {
 +        let def_map = db.crate_def_map(self.id);
 +        def_map.modules().map(|(id, _)| def_map.module_id(id).into()).collect()
 +    }
 +
 +    pub fn root_file(self, db: &dyn HirDatabase) -> FileId {
 +        db.crate_graph()[self.id].root_file_id
 +    }
 +
 +    pub fn edition(self, db: &dyn HirDatabase) -> Edition {
 +        db.crate_graph()[self.id].edition
 +    }
 +
 +    pub fn version(self, db: &dyn HirDatabase) -> Option<String> {
 +        db.crate_graph()[self.id].version.clone()
 +    }
 +
 +    pub fn display_name(self, db: &dyn HirDatabase) -> Option<CrateDisplayName> {
 +        db.crate_graph()[self.id].display_name.clone()
 +    }
 +
 +    pub fn query_external_importables(
 +        self,
 +        db: &dyn DefDatabase,
 +        query: import_map::Query,
 +    ) -> impl Iterator<Item = Either<ModuleDef, Macro>> {
 +        let _p = profile::span("query_external_importables");
 +        import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| {
 +            match ItemInNs::from(item) {
 +                ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id),
 +                ItemInNs::Macros(mac_id) => Either::Right(mac_id),
 +            }
 +        })
 +    }
 +
 +    pub fn all(db: &dyn HirDatabase) -> Vec<Crate> {
 +        db.crate_graph().iter().map(|id| Crate { id }).collect()
 +    }
 +
 +    /// Try to get the root URL of the documentation of a crate.
 +    pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> {
 +        // Look for #![doc(html_root_url = "...")]
 +        let attrs = db.attrs(AttrDefId::ModuleId(self.root_module(db).into()));
 +        let doc_url = attrs.by_key("doc").find_string_value_in_tt("html_root_url");
 +        doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/")
 +    }
 +
 +    pub fn cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
 +        db.crate_graph()[self.id].cfg_options.clone()
 +    }
 +
 +    pub fn potential_cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
 +        db.crate_graph()[self.id].potential_cfg_options.clone()
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Module {
 +    pub(crate) id: ModuleId,
 +}
 +
 +/// The defs which can be visible in the module.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum ModuleDef {
 +    Module(Module),
 +    Function(Function),
 +    Adt(Adt),
 +    // Can't be directly declared, but can be imported.
 +    Variant(Variant),
 +    Const(Const),
 +    Static(Static),
 +    Trait(Trait),
 +    TypeAlias(TypeAlias),
 +    BuiltinType(BuiltinType),
 +    Macro(Macro),
 +}
 +impl_from!(
 +    Module,
 +    Function,
 +    Adt(Struct, Enum, Union),
 +    Variant,
 +    Const,
 +    Static,
 +    Trait,
 +    TypeAlias,
 +    BuiltinType,
 +    Macro
 +    for ModuleDef
 +);
 +
 +impl From<VariantDef> for ModuleDef {
 +    fn from(var: VariantDef) -> Self {
 +        match var {
 +            VariantDef::Struct(t) => Adt::from(t).into(),
 +            VariantDef::Union(t) => Adt::from(t).into(),
 +            VariantDef::Variant(t) => t.into(),
 +        }
 +    }
 +}
 +
 +impl ModuleDef {
 +    pub fn module(self, db: &dyn HirDatabase) -> Option<Module> {
 +        match self {
 +            ModuleDef::Module(it) => it.parent(db),
 +            ModuleDef::Function(it) => Some(it.module(db)),
 +            ModuleDef::Adt(it) => Some(it.module(db)),
 +            ModuleDef::Variant(it) => Some(it.module(db)),
 +            ModuleDef::Const(it) => Some(it.module(db)),
 +            ModuleDef::Static(it) => Some(it.module(db)),
 +            ModuleDef::Trait(it) => Some(it.module(db)),
 +            ModuleDef::TypeAlias(it) => Some(it.module(db)),
 +            ModuleDef::Macro(it) => Some(it.module(db)),
 +            ModuleDef::BuiltinType(_) => None,
 +        }
 +    }
 +
 +    pub fn canonical_path(&self, db: &dyn HirDatabase) -> Option<String> {
 +        let mut segments = vec![self.name(db)?];
 +        for m in self.module(db)?.path_to_root(db) {
 +            segments.extend(m.name(db))
 +        }
 +        segments.reverse();
 +        Some(segments.into_iter().join("::"))
 +    }
 +
 +    pub fn canonical_module_path(
 +        &self,
 +        db: &dyn HirDatabase,
 +    ) -> Option<impl Iterator<Item = Module>> {
 +        self.module(db).map(|it| it.path_to_root(db).into_iter().rev())
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        let name = match self {
 +            ModuleDef::Module(it) => it.name(db)?,
 +            ModuleDef::Const(it) => it.name(db)?,
 +            ModuleDef::Adt(it) => it.name(db),
 +            ModuleDef::Trait(it) => it.name(db),
 +            ModuleDef::Function(it) => it.name(db),
 +            ModuleDef::Variant(it) => it.name(db),
 +            ModuleDef::TypeAlias(it) => it.name(db),
 +            ModuleDef::Static(it) => it.name(db),
 +            ModuleDef::Macro(it) => it.name(db),
 +            ModuleDef::BuiltinType(it) => it.name(),
 +        };
 +        Some(name)
 +    }
 +
 +    pub fn diagnostics(self, db: &dyn HirDatabase) -> Vec<AnyDiagnostic> {
 +        let id = match self {
 +            ModuleDef::Adt(it) => match it {
 +                Adt::Struct(it) => it.id.into(),
 +                Adt::Enum(it) => it.id.into(),
 +                Adt::Union(it) => it.id.into(),
 +            },
 +            ModuleDef::Trait(it) => it.id.into(),
 +            ModuleDef::Function(it) => it.id.into(),
 +            ModuleDef::TypeAlias(it) => it.id.into(),
 +            ModuleDef::Module(it) => it.id.into(),
 +            ModuleDef::Const(it) => it.id.into(),
 +            ModuleDef::Static(it) => it.id.into(),
 +            _ => return Vec::new(),
 +        };
 +
 +        let module = match self.module(db) {
 +            Some(it) => it,
 +            None => return Vec::new(),
 +        };
 +
 +        let mut acc = Vec::new();
 +
 +        match self.as_def_with_body() {
 +            Some(def) => {
 +                def.diagnostics(db, &mut acc);
 +            }
 +            None => {
 +                for diag in hir_ty::diagnostics::incorrect_case(db, module.id.krate(), id) {
 +                    acc.push(diag.into())
 +                }
 +            }
 +        }
 +
 +        acc
 +    }
 +
 +    pub fn as_def_with_body(self) -> Option<DefWithBody> {
 +        match self {
 +            ModuleDef::Function(it) => Some(it.into()),
 +            ModuleDef::Const(it) => Some(it.into()),
 +            ModuleDef::Static(it) => Some(it.into()),
 +
 +            ModuleDef::Module(_)
 +            | ModuleDef::Adt(_)
 +            | ModuleDef::Variant(_)
 +            | ModuleDef::Trait(_)
 +            | ModuleDef::TypeAlias(_)
 +            | ModuleDef::Macro(_)
 +            | ModuleDef::BuiltinType(_) => None,
 +        }
 +    }
 +
 +    pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
 +        Some(match self {
 +            ModuleDef::Module(it) => it.attrs(db),
 +            ModuleDef::Function(it) => it.attrs(db),
 +            ModuleDef::Adt(it) => it.attrs(db),
 +            ModuleDef::Variant(it) => it.attrs(db),
 +            ModuleDef::Const(it) => it.attrs(db),
 +            ModuleDef::Static(it) => it.attrs(db),
 +            ModuleDef::Trait(it) => it.attrs(db),
 +            ModuleDef::TypeAlias(it) => it.attrs(db),
 +            ModuleDef::Macro(it) => it.attrs(db),
 +            ModuleDef::BuiltinType(_) => return None,
 +        })
 +    }
 +}
 +
 +impl HasVisibility for ModuleDef {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match *self {
 +            ModuleDef::Module(it) => it.visibility(db),
 +            ModuleDef::Function(it) => it.visibility(db),
 +            ModuleDef::Adt(it) => it.visibility(db),
 +            ModuleDef::Const(it) => it.visibility(db),
 +            ModuleDef::Static(it) => it.visibility(db),
 +            ModuleDef::Trait(it) => it.visibility(db),
 +            ModuleDef::TypeAlias(it) => it.visibility(db),
 +            ModuleDef::Variant(it) => it.visibility(db),
 +            ModuleDef::Macro(it) => it.visibility(db),
 +            ModuleDef::BuiltinType(_) => Visibility::Public,
 +        }
 +    }
 +}
 +
 +impl Module {
 +    /// Name of this module.
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        let def_map = self.id.def_map(db.upcast());
 +        let parent = def_map[self.id.local_id].parent?;
 +        def_map[parent].children.iter().find_map(|(name, module_id)| {
 +            if *module_id == self.id.local_id {
 +                Some(name.clone())
 +            } else {
 +                None
 +            }
 +        })
 +    }
 +
 +    /// Returns the crate this module is part of.
 +    pub fn krate(self) -> Crate {
 +        Crate { id: self.id.krate() }
 +    }
 +
 +    /// Topmost parent of this module. Every module has a `crate_root`, but some
 +    /// might be missing `krate`. This can happen if a module's file is not included
 +    /// in the module tree of any target in `Cargo.toml`.
 +    pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
 +        let def_map = db.crate_def_map(self.id.krate());
 +        Module { id: def_map.module_id(def_map.root()) }
 +    }
 +
 +    pub fn is_crate_root(self, db: &dyn HirDatabase) -> bool {
 +        let def_map = db.crate_def_map(self.id.krate());
 +        def_map.root() == self.id.local_id
 +    }
 +
 +    /// Iterates over all child modules.
 +    pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> {
 +        let def_map = self.id.def_map(db.upcast());
 +        let children = def_map[self.id.local_id]
 +            .children
 +            .iter()
 +            .map(|(_, module_id)| Module { id: def_map.module_id(*module_id) })
 +            .collect::<Vec<_>>();
 +        children.into_iter()
 +    }
 +
 +    /// Finds a parent module.
 +    pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> {
 +        // FIXME: handle block expressions as modules (their parent is in a different DefMap)
 +        let def_map = self.id.def_map(db.upcast());
 +        let parent_id = def_map[self.id.local_id].parent?;
 +        Some(Module { id: def_map.module_id(parent_id) })
 +    }
 +
 +    pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> {
 +        let mut res = vec![self];
 +        let mut curr = self;
 +        while let Some(next) = curr.parent(db) {
 +            res.push(next);
 +            curr = next
 +        }
 +        res
 +    }
 +
 +    /// Returns a `ModuleScope`: a set of items, visible in this module.
 +    pub fn scope(
 +        self,
 +        db: &dyn HirDatabase,
 +        visible_from: Option<Module>,
 +    ) -> Vec<(Name, ScopeDef)> {
 +        self.id.def_map(db.upcast())[self.id.local_id]
 +            .scope
 +            .entries()
 +            .filter_map(|(name, def)| {
 +                if let Some(m) = visible_from {
 +                    let filtered =
 +                        def.filter_visibility(|vis| vis.is_visible_from(db.upcast(), m.id));
 +                    if filtered.is_none() && !def.is_none() {
 +                        None
 +                    } else {
 +                        Some((name, filtered))
 +                    }
 +                } else {
 +                    Some((name, def))
 +                }
 +            })
 +            .flat_map(|(name, def)| {
 +                ScopeDef::all_items(def).into_iter().map(move |item| (name.clone(), item))
 +            })
 +            .collect()
 +    }
 +
 +    /// 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))
 +                }
 +                _ => 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>) -> Option<ModPath> {
 +        hir_def::find_path::find_path(db, item.into().into(), self.into())
 +    }
 +
 +    /// Finds a path that can be used to refer to the given item from within
 +    /// this module, if possible. This is used for returning import paths for use-statements.
 +    pub fn find_use_path_prefixed(
 +        self,
 +        db: &dyn DefDatabase,
 +        item: impl Into<ItemInNs>,
 +        prefix_kind: PrefixKind,
 +    ) -> Option<ModPath> {
 +        hir_def::find_path::find_path_prefixed(db, item.into().into(), self.into(), prefix_kind)
 +    }
 +}
 +
 +fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: &DefDiagnostic) {
 +    match &diag.kind {
 +        DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => {
 +            let decl = declaration.to_node(db.upcast());
 +            acc.push(
 +                UnresolvedModule {
 +                    decl: InFile::new(declaration.file_id, AstPtr::new(&decl)),
 +                    candidates: candidates.clone(),
 +                }
 +                .into(),
 +            )
 +        }
 +        DefDiagnosticKind::UnresolvedExternCrate { ast } => {
 +            let item = ast.to_node(db.upcast());
 +            acc.push(
 +                UnresolvedExternCrate { decl: InFile::new(ast.file_id, AstPtr::new(&item)) }.into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnresolvedImport { id, index } => {
 +            let file_id = id.file_id();
 +            let item_tree = id.item_tree(db.upcast());
 +            let import = &item_tree[id.value];
 +
 +            let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index);
 +            acc.push(
 +                UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }.into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
 +            let item = ast.to_node(db.upcast());
 +            acc.push(
 +                InactiveCode {
 +                    node: ast.with_value(AstPtr::new(&item).into()),
 +                    cfg: cfg.clone(),
 +                    opts: opts.clone(),
 +                }
 +                .into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnresolvedProcMacro { ast, krate } => {
 +            let (node, precise_location, macro_name, kind) = precise_macro_call_location(ast, db);
 +            acc.push(
 +                UnresolvedProcMacro { node, precise_location, macro_name, kind, krate: *krate }
 +                    .into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
 +            let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
 +            acc.push(
 +                UnresolvedMacroCall {
 +                    macro_call: node,
 +                    precise_location,
 +                    path: path.clone(),
 +                    is_bang: matches!(ast, MacroCallKind::FnLike { .. }),
 +                }
 +                .into(),
 +            );
 +        }
 +
 +        DefDiagnosticKind::MacroError { ast, message } => {
 +            let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
 +            acc.push(MacroError { node, precise_location, message: message.clone() }.into());
 +        }
 +
 +        DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
 +            let node = ast.to_node(db.upcast());
 +            // Must have a name, otherwise we wouldn't emit it.
 +            let name = node.name().expect("unimplemented builtin macro with no name");
 +            acc.push(
 +                UnimplementedBuiltinMacro {
 +                    node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&name))),
 +                }
 +                .into(),
 +            );
 +        }
 +        DefDiagnosticKind::InvalidDeriveTarget { ast, id } => {
 +            let node = ast.to_node(db.upcast());
 +            let derive = node.attrs().nth(*id as usize);
 +            match derive {
 +                Some(derive) => {
 +                    acc.push(
 +                        InvalidDeriveTarget {
 +                            node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
 +                        }
 +                        .into(),
 +                    );
 +                }
 +                None => stdx::never!("derive diagnostic on item without derive attribute"),
 +            }
 +        }
 +        DefDiagnosticKind::MalformedDerive { ast, id } => {
 +            let node = ast.to_node(db.upcast());
 +            let derive = node.attrs().nth(*id as usize);
 +            match derive {
 +                Some(derive) => {
 +                    acc.push(
 +                        MalformedDerive {
 +                            node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
 +                        }
 +                        .into(),
 +                    );
 +                }
 +                None => stdx::never!("derive diagnostic on item without derive attribute"),
 +            }
 +        }
 +    }
 +}
 +
 +fn precise_macro_call_location(
 +    ast: &MacroCallKind,
 +    db: &dyn HirDatabase,
 +) -> (InFile<SyntaxNodePtr>, Option<TextRange>, Option<String>, MacroKind) {
 +    // FIXME: maaybe we actually want slightly different ranges for the different macro diagnostics
 +    // - e.g. the full attribute for macro errors, but only the name for name resolution
 +    match ast {
 +        MacroCallKind::FnLike { ast_id, .. } => {
 +            let node = ast_id.to_node(db.upcast());
 +            (
 +                ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
 +                node.path()
 +                    .and_then(|it| it.segment())
 +                    .and_then(|it| it.name_ref())
 +                    .map(|it| it.syntax().text_range()),
 +                node.path().and_then(|it| it.segment()).map(|it| it.to_string()),
 +                MacroKind::ProcMacro,
 +            )
 +        }
 +        MacroCallKind::Derive { ast_id, derive_attr_index, derive_index } => {
 +            let node = ast_id.to_node(db.upcast());
 +            // Compute the precise location of the macro name's token in the derive
 +            // list.
 +            let token = (|| {
 +                let derive_attr = node
 +                    .doc_comments_and_attrs()
 +                    .nth(*derive_attr_index as usize)
 +                    .and_then(Either::left)?;
 +                let token_tree = derive_attr.meta()?.token_tree()?;
 +                let group_by = token_tree
 +                    .syntax()
 +                    .children_with_tokens()
 +                    .filter_map(|elem| match elem {
 +                        syntax::NodeOrToken::Token(tok) => Some(tok),
 +                        _ => None,
 +                    })
 +                    .group_by(|t| t.kind() == T![,]);
 +                let (_, mut group) = group_by
 +                    .into_iter()
 +                    .filter(|&(comma, _)| !comma)
 +                    .nth(*derive_index as usize)?;
 +                group.find(|t| t.kind() == T![ident])
 +            })();
 +            (
 +                ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
 +                token.as_ref().map(|tok| tok.text_range()),
 +                token.as_ref().map(ToString::to_string),
 +                MacroKind::Derive,
 +            )
 +        }
 +        MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
 +            let node = ast_id.to_node(db.upcast());
 +            let attr = node
 +                .doc_comments_and_attrs()
 +                .nth((*invoc_attr_index) as usize)
 +                .and_then(Either::left)
 +                .unwrap_or_else(|| panic!("cannot find attribute #{}", invoc_attr_index));
 +
 +            (
 +                ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))),
 +                Some(attr.syntax().text_range()),
 +                attr.path()
 +                    .and_then(|path| path.segment())
 +                    .and_then(|seg| seg.name_ref())
 +                    .as_ref()
 +                    .map(ToString::to_string),
 +                MacroKind::Attr,
 +            )
 +        }
 +    }
 +}
 +
 +impl HasVisibility for Module {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        let def_map = self.id.def_map(db.upcast());
 +        let module_data = &def_map[self.id.local_id];
 +        module_data.visibility
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Field {
 +    pub(crate) parent: VariantDef,
 +    pub(crate) id: LocalFieldId,
 +}
 +
 +#[derive(Debug, PartialEq, Eq)]
 +pub enum FieldSource {
 +    Named(ast::RecordField),
 +    Pos(ast::TupleField),
 +}
 +
 +impl Field {
 +    pub fn name(&self, db: &dyn HirDatabase) -> Name {
 +        self.parent.variant_data(db).fields()[self.id].name.clone()
 +    }
 +
 +    /// Returns the type as in the signature of the struct (i.e., with
 +    /// placeholder types for type parameters). Only use this in the context of
 +    /// the field definition.
 +    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
 +        let var_id = self.parent.into();
 +        let generic_def_id: GenericDefId = match self.parent {
 +            VariantDef::Struct(it) => it.id.into(),
 +            VariantDef::Union(it) => it.id.into(),
 +            VariantDef::Variant(it) => it.parent.id.into(),
 +        };
 +        let substs = TyBuilder::placeholder_subst(db, generic_def_id);
 +        let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
 +        Type::new(db, var_id, ty)
 +    }
 +
 +    pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
 +        self.parent
 +    }
 +}
 +
 +impl HasVisibility for Field {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        let variant_data = self.parent.variant_data(db);
 +        let visibility = &variant_data.fields()[self.id].visibility;
 +        let parent_id: hir_def::VariantId = self.parent.into();
 +        visibility.resolve(db.upcast(), &parent_id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Struct {
 +    pub(crate) id: StructId,
 +}
 +
 +impl Struct {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.struct_data(self.id).name.clone()
 +    }
 +
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        db.struct_data(self.id)
 +            .variant_data
 +            .fields()
 +            .iter()
 +            .map(|(id, _)| Field { parent: self.into(), id })
 +            .collect()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +
 +    pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> {
 +        db.struct_data(self.id).repr.clone()
 +    }
 +
 +    pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
 +        self.variant_data(db).kind()
 +    }
 +
 +    fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        db.struct_data(self.id).variant_data.clone()
 +    }
 +}
 +
 +impl HasVisibility for Struct {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.struct_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Union {
 +    pub(crate) id: UnionId,
 +}
 +
 +impl Union {
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.union_data(self.id).name.clone()
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        db.union_data(self.id)
 +            .variant_data
 +            .fields()
 +            .iter()
 +            .map(|(id, _)| Field { parent: self.into(), id })
 +            .collect()
 +    }
 +
 +    fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        db.union_data(self.id).variant_data.clone()
 +    }
 +}
 +
 +impl HasVisibility for Union {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.union_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Enum {
 +    pub(crate) id: EnumId,
 +}
 +
 +impl Enum {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.enum_data(self.id).name.clone()
 +    }
 +
 +    pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> {
 +        db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +}
 +
 +impl HasVisibility for Enum {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.enum_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Variant {
 +    pub(crate) parent: Enum,
 +    pub(crate) id: LocalEnumVariantId,
 +}
 +
 +impl Variant {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.parent.module(db)
 +    }
 +
 +    pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum {
 +        self.parent
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.enum_data(self.parent.id).variants[self.id].name.clone()
 +    }
 +
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        self.variant_data(db)
 +            .fields()
 +            .iter()
 +            .map(|(id, _)| Field { parent: self.into(), id })
 +            .collect()
 +    }
 +
 +    pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
 +        self.variant_data(db).kind()
 +    }
 +
 +    pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
 +    }
 +}
 +
 +/// Variants inherit visibility from the parent enum.
 +impl HasVisibility for Variant {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        self.parent_enum(db).visibility(db)
 +    }
 +}
 +
 +/// A Data Type
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum Adt {
 +    Struct(Struct),
 +    Union(Union),
 +    Enum(Enum),
 +}
 +impl_from!(Struct, Union, Enum for Adt);
 +
 +impl Adt {
 +    pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
 +        let subst = db.generic_defaults(self.into());
 +        subst.iter().any(|ty| match ty.skip_binders().data(Interner) {
 +            GenericArgData::Ty(x) => x.is_unknown(),
 +            _ => false,
 +        })
 +    }
 +
 +    /// Turns this ADT into a type. Any type parameters of the ADT will be
 +    /// turned into unknown types, which is good for e.g. finding the most
 +    /// general set of completions, but will not look very nice when printed.
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let id = AdtId::from(self);
 +        Type::from_def(db, id)
 +    }
 +
 +    /// Turns this ADT into a type with the given type parameters. This isn't
 +    /// the greatest API, FIXME find a better one.
 +    pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type {
 +        let id = AdtId::from(self);
 +        let mut it = args.iter().map(|t| t.ty.clone());
 +        let ty = TyBuilder::def_ty(db, id.into())
 +            .fill(|x| {
 +                let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
 +                match x {
 +                    ParamKind::Type => GenericArgData::Ty(r).intern(Interner),
 +                    ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
 +                }
 +            })
 +            .build();
 +        Type::new(db, id, ty)
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            Adt::Struct(s) => s.module(db),
 +            Adt::Union(s) => s.module(db),
 +            Adt::Enum(e) => e.module(db),
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        match self {
 +            Adt::Struct(s) => s.name(db),
 +            Adt::Union(u) => u.name(db),
 +            Adt::Enum(e) => e.name(db),
 +        }
 +    }
 +
 +    pub fn as_enum(&self) -> Option<Enum> {
 +        if let Self::Enum(v) = self {
 +            Some(*v)
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +impl HasVisibility for Adt {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match self {
 +            Adt::Struct(it) => it.visibility(db),
 +            Adt::Union(it) => it.visibility(db),
 +            Adt::Enum(it) => it.visibility(db),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum VariantDef {
 +    Struct(Struct),
 +    Union(Union),
 +    Variant(Variant),
 +}
 +impl_from!(Struct, Union, Variant for VariantDef);
 +
 +impl VariantDef {
 +    pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
 +        match self {
 +            VariantDef::Struct(it) => it.fields(db),
 +            VariantDef::Union(it) => it.fields(db),
 +            VariantDef::Variant(it) => it.fields(db),
 +        }
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            VariantDef::Struct(it) => it.module(db),
 +            VariantDef::Union(it) => it.module(db),
 +            VariantDef::Variant(it) => it.module(db),
 +        }
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> Name {
 +        match self {
 +            VariantDef::Struct(s) => s.name(db),
 +            VariantDef::Union(u) => u.name(db),
 +            VariantDef::Variant(e) => e.name(db),
 +        }
 +    }
 +
 +    pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
 +        match self {
 +            VariantDef::Struct(it) => it.variant_data(db),
 +            VariantDef::Union(it) => it.variant_data(db),
 +            VariantDef::Variant(it) => it.variant_data(db),
 +        }
 +    }
 +}
 +
 +/// The defs which have a body.
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum DefWithBody {
 +    Function(Function),
 +    Static(Static),
 +    Const(Const),
 +}
 +impl_from!(Function, Const, Static for DefWithBody);
 +
 +impl DefWithBody {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            DefWithBody::Const(c) => c.module(db),
 +            DefWithBody::Function(f) => f.module(db),
 +            DefWithBody::Static(s) => s.module(db),
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        match self {
 +            DefWithBody::Function(f) => Some(f.name(db)),
 +            DefWithBody::Static(s) => Some(s.name(db)),
 +            DefWithBody::Const(c) => c.name(db),
 +        }
 +    }
 +
 +    /// Returns the type this def's body has to evaluate to.
 +    pub fn body_type(self, db: &dyn HirDatabase) -> Type {
 +        match self {
 +            DefWithBody::Function(it) => it.ret_type(db),
 +            DefWithBody::Static(it) => it.ty(db),
 +            DefWithBody::Const(it) => it.ty(db),
 +        }
 +    }
 +
 +    fn id(&self) -> DefWithBodyId {
 +        match self {
 +            DefWithBody::Function(it) => it.id.into(),
 +            DefWithBody::Static(it) => it.id.into(),
 +            DefWithBody::Const(it) => it.id.into(),
 +        }
 +    }
 +
 +    /// A textual representation of the HIR of this def's body for debugging purposes.
 +    pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
 +        let body = db.body(self.id());
 +        body.pretty_print(db.upcast(), self.id())
 +    }
 +
 +    pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
 +        let krate = self.module(db).id.krate();
 +
 +        let (body, source_map) = db.body_with_source_map(self.into());
 +
 +        for (_, def_map) in body.blocks(db.upcast()) {
 +            for diag in def_map.diagnostics() {
 +                emit_def_diagnostic(db, acc, diag);
 +            }
 +        }
 +
 +        for diag in source_map.diagnostics() {
 +            match diag {
 +                BodyDiagnostic::InactiveCode { node, cfg, opts } => acc.push(
 +                    InactiveCode { node: node.clone(), cfg: cfg.clone(), opts: opts.clone() }
 +                        .into(),
 +                ),
 +                BodyDiagnostic::MacroError { node, message } => acc.push(
 +                    MacroError {
 +                        node: node.clone().map(|it| it.into()),
 +                        precise_location: None,
 +                        message: message.to_string(),
 +                    }
 +                    .into(),
 +                ),
 +                BodyDiagnostic::UnresolvedProcMacro { node, krate } => acc.push(
 +                    UnresolvedProcMacro {
 +                        node: node.clone().map(|it| it.into()),
 +                        precise_location: None,
 +                        macro_name: None,
 +                        kind: MacroKind::ProcMacro,
 +                        krate: *krate,
 +                    }
 +                    .into(),
 +                ),
 +                BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push(
 +                    UnresolvedMacroCall {
 +                        macro_call: node.clone().map(|ast_ptr| ast_ptr.into()),
 +                        precise_location: None,
 +                        path: path.clone(),
 +                        is_bang: true,
 +                    }
 +                    .into(),
 +                ),
 +            }
 +        }
 +
 +        let infer = db.infer(self.into());
 +        let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1);
 +        for d in &infer.diagnostics {
 +            match d {
 +                hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
 +                    let field = source_map.field_syntax(*expr);
 +                    acc.push(NoSuchField { field }.into())
 +                }
-                         .expr_syntax(*expr)
++                &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
 +                    let expr = source_map
-                     acc.push(BreakOutsideOfLoop { expr }.into())
++                        .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 } => {
 +                    match source_map.expr_syntax(*call_expr) {
 +                        Ok(source_ptr) => acc.push(
 +                            MismatchedArgCount {
 +                                call_expr: source_ptr,
 +                                expected: *expected,
 +                                found: *found,
 +                            }
 +                            .into(),
 +                        ),
 +                        Err(SyntheticSyntax) => (),
 +                    }
 +                }
 +            }
 +        }
 +        for (expr, mismatch) in infer.expr_type_mismatches() {
 +            let expr = match source_map.expr_syntax(expr) {
 +                Ok(expr) => expr,
 +                Err(SyntheticSyntax) => continue,
 +            };
 +            acc.push(
 +                TypeMismatch {
 +                    expr,
 +                    expected: Type::new(db, DefWithBodyId::from(self), mismatch.expected.clone()),
 +                    actual: Type::new(db, DefWithBodyId::from(self), mismatch.actual.clone()),
 +                }
 +                .into(),
 +            );
 +        }
 +
 +        for expr in hir_ty::diagnostics::missing_unsafe(db, self.into()) {
 +            match source_map.expr_syntax(expr) {
 +                Ok(expr) => acc.push(MissingUnsafe { expr }.into()),
 +                Err(SyntheticSyntax) => {
 +                    // FIXME: Here and eslwhere in this file, the `expr` was
 +                    // desugared, report or assert that this doesn't happen.
 +                }
 +            }
 +        }
 +
 +        for diagnostic in BodyValidationDiagnostic::collect(db, self.into()) {
 +            match diagnostic {
 +                BodyValidationDiagnostic::RecordMissingFields {
 +                    record,
 +                    variant,
 +                    missed_fields,
 +                } => {
 +                    let variant_data = variant.variant_data(db.upcast());
 +                    let missed_fields = missed_fields
 +                        .into_iter()
 +                        .map(|idx| variant_data.fields()[idx].name.clone())
 +                        .collect();
 +
 +                    match record {
 +                        Either::Left(record_expr) => match source_map.expr_syntax(record_expr) {
 +                            Ok(source_ptr) => {
 +                                let root = source_ptr.file_syntax(db.upcast());
 +                                if let ast::Expr::RecordExpr(record_expr) =
 +                                    &source_ptr.value.to_node(&root)
 +                                {
 +                                    if record_expr.record_expr_field_list().is_some() {
 +                                        acc.push(
 +                                            MissingFields {
 +                                                file: source_ptr.file_id,
 +                                                field_list_parent: Either::Left(AstPtr::new(
 +                                                    record_expr,
 +                                                )),
 +                                                field_list_parent_path: record_expr
 +                                                    .path()
 +                                                    .map(|path| AstPtr::new(&path)),
 +                                                missed_fields,
 +                                            }
 +                                            .into(),
 +                                        )
 +                                    }
 +                                }
 +                            }
 +                            Err(SyntheticSyntax) => (),
 +                        },
 +                        Either::Right(record_pat) => match source_map.pat_syntax(record_pat) {
 +                            Ok(source_ptr) => {
 +                                if let Some(expr) = source_ptr.value.as_ref().left() {
 +                                    let root = source_ptr.file_syntax(db.upcast());
 +                                    if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) {
 +                                        if record_pat.record_pat_field_list().is_some() {
 +                                            acc.push(
 +                                                MissingFields {
 +                                                    file: source_ptr.file_id,
 +                                                    field_list_parent: Either::Right(AstPtr::new(
 +                                                        &record_pat,
 +                                                    )),
 +                                                    field_list_parent_path: record_pat
 +                                                        .path()
 +                                                        .map(|path| AstPtr::new(&path)),
 +                                                    missed_fields,
 +                                                }
 +                                                .into(),
 +                                            )
 +                                        }
 +                                    }
 +                                }
 +                            }
 +                            Err(SyntheticSyntax) => (),
 +                        },
 +                    }
 +                }
 +                BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => {
 +                    if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) {
 +                        acc.push(
 +                            ReplaceFilterMapNextWithFindMap {
 +                                file: next_source_ptr.file_id,
 +                                next_expr: next_source_ptr.value,
 +                            }
 +                            .into(),
 +                        );
 +                    }
 +                }
 +                BodyValidationDiagnostic::MissingMatchArms { match_expr, uncovered_patterns } => {
 +                    match source_map.expr_syntax(match_expr) {
 +                        Ok(source_ptr) => {
 +                            let root = source_ptr.file_syntax(db.upcast());
 +                            if let ast::Expr::MatchExpr(match_expr) =
 +                                &source_ptr.value.to_node(&root)
 +                            {
 +                                if let Some(match_expr) = match_expr.expr() {
 +                                    acc.push(
 +                                        MissingMatchArms {
 +                                            file: source_ptr.file_id,
 +                                            match_expr: AstPtr::new(&match_expr),
 +                                            uncovered_patterns,
 +                                        }
 +                                        .into(),
 +                                    );
 +                                }
 +                            }
 +                        }
 +                        Err(SyntheticSyntax) => (),
 +                    }
 +                }
 +            }
 +        }
 +
 +        let def: ModuleDef = match self {
 +            DefWithBody::Function(it) => it.into(),
 +            DefWithBody::Static(it) => it.into(),
 +            DefWithBody::Const(it) => it.into(),
 +        };
 +        for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) {
 +            acc.push(diag.into())
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Function {
 +    pub(crate) id: FunctionId,
 +}
 +
 +impl Function {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.lookup(db.upcast()).module(db.upcast()).into()
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.function_data(self.id).name.clone()
 +    }
 +
 +    /// Get this function's return type
 +    pub fn ret_type(self, db: &dyn HirDatabase) -> Type {
 +        let resolver = self.id.resolver(db.upcast());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        let ty = callable_sig.ret().clone();
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    pub fn async_ret_type(self, db: &dyn HirDatabase) -> Option<Type> {
 +        if !self.is_async(db) {
 +            return None;
 +        }
 +        let resolver = self.id.resolver(db.upcast());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        let ret_ty = callable_sig.ret().clone();
 +        for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() {
 +            if let WhereClause::AliasEq(output_eq) = pred.into_value_and_skipped_binders().0 {
 +                return Type::new_with_resolver_inner(db, &resolver, output_eq.ty).into();
 +            }
 +        }
 +        never!("Async fn ret_type should be impl Future");
 +        None
 +    }
 +
 +    pub fn has_self_param(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_self_param()
 +    }
 +
 +    pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
 +        self.has_self_param(db).then(|| SelfParam { func: self.id })
 +    }
 +
 +    pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> {
 +        let environment = db.trait_environment(self.id.into());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        callable_sig
 +            .params()
 +            .iter()
 +            .enumerate()
 +            .map(|(idx, ty)| {
 +                let ty = Type { env: environment.clone(), ty: ty.clone() };
 +                Param { func: self, ty, idx }
 +            })
 +            .collect()
 +    }
 +
 +    pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> {
 +        if self.self_param(db).is_none() {
 +            return None;
 +        }
 +        Some(self.params_without_self(db))
 +    }
 +
 +    pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param> {
 +        let environment = db.trait_environment(self.id.into());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
 +        let skip = if db.function_data(self.id).has_self_param() { 1 } else { 0 };
 +        callable_sig
 +            .params()
 +            .iter()
 +            .enumerate()
 +            .skip(skip)
 +            .map(|(idx, ty)| {
 +                let ty = Type { env: environment.clone(), ty: ty.clone() };
 +                Param { func: self, ty, idx }
 +            })
 +            .collect()
 +    }
 +
 +    pub fn is_const(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_const_kw()
 +    }
 +
 +    pub fn is_async(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_async_kw()
 +    }
 +
 +    pub fn is_unsafe_to_call(self, db: &dyn HirDatabase) -> bool {
 +        hir_ty::is_fn_unsafe_to_call(db, self.id)
 +    }
 +
 +    /// Whether this function declaration has a definition.
 +    ///
 +    /// This is false in the case of required (not provided) trait methods.
 +    pub fn has_body(self, db: &dyn HirDatabase) -> bool {
 +        db.function_data(self.id).has_body()
 +    }
 +
 +    pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> {
 +        let function_data = db.function_data(self.id);
 +        let attrs = &function_data.attrs;
 +        // FIXME: Store this in FunctionData flags?
 +        if !(attrs.is_proc_macro()
 +            || attrs.is_proc_macro_attribute()
 +            || attrs.is_proc_macro_derive())
 +        {
 +            return None;
 +        }
 +        let loc = self.id.lookup(db.upcast());
 +        let def_map = db.crate_def_map(loc.krate(db).into());
 +        def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() })
 +    }
 +}
 +
 +// Note: logically, this belongs to `hir_ty`, but we are not using it there yet.
 +#[derive(Clone, Copy, PartialEq, Eq)]
 +pub enum Access {
 +    Shared,
 +    Exclusive,
 +    Owned,
 +}
 +
 +impl From<hir_ty::Mutability> for Access {
 +    fn from(mutability: hir_ty::Mutability) -> Access {
 +        match mutability {
 +            hir_ty::Mutability::Not => Access::Shared,
 +            hir_ty::Mutability::Mut => Access::Exclusive,
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Debug)]
 +pub struct Param {
 +    func: Function,
 +    /// The index in parameter list, including self parameter.
 +    idx: usize,
 +    ty: Type,
 +}
 +
 +impl Param {
 +    pub fn ty(&self) -> &Type {
 +        &self.ty
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
 +        db.function_data(self.func.id).params[self.idx].0.clone()
 +    }
 +
 +    pub fn as_local(&self, db: &dyn HirDatabase) -> Option<Local> {
 +        let parent = DefWithBodyId::FunctionId(self.func.into());
 +        let body = db.body(parent);
 +        let pat_id = body.params[self.idx];
 +        if let Pat::Bind { .. } = &body[pat_id] {
 +            Some(Local { parent, pat_id: body.params[self.idx] })
 +        } else {
 +            None
 +        }
 +    }
 +
 +    pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option<ast::Pat> {
 +        self.source(db).and_then(|p| p.value.pat())
 +    }
 +
 +    pub fn source(&self, db: &dyn HirDatabase) -> Option<InFile<ast::Param>> {
 +        let InFile { file_id, value } = self.func.source(db)?;
 +        let params = value.param_list()?;
 +        if params.self_param().is_some() {
 +            params.params().nth(self.idx.checked_sub(1)?)
 +        } else {
 +            params.params().nth(self.idx)
 +        }
 +        .map(|value| InFile { file_id, value })
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct SelfParam {
 +    func: FunctionId,
 +}
 +
 +impl SelfParam {
 +    pub fn access(self, db: &dyn HirDatabase) -> Access {
 +        let func_data = db.function_data(self.func);
 +        func_data
 +            .params
 +            .first()
 +            .map(|(_, param)| match &**param {
 +                TypeRef::Reference(.., mutability) => match mutability {
 +                    hir_def::type_ref::Mutability::Shared => Access::Shared,
 +                    hir_def::type_ref::Mutability::Mut => Access::Exclusive,
 +                },
 +                _ => Access::Owned,
 +            })
 +            .unwrap_or(Access::Owned)
 +    }
 +
 +    pub fn display(self, db: &dyn HirDatabase) -> &'static str {
 +        match self.access(db) {
 +            Access::Shared => "&self",
 +            Access::Exclusive => "&mut self",
 +            Access::Owned => "self",
 +        }
 +    }
 +
 +    pub fn source(&self, db: &dyn HirDatabase) -> Option<InFile<ast::SelfParam>> {
 +        let InFile { file_id, value } = Function::from(self.func).source(db)?;
 +        value
 +            .param_list()
 +            .and_then(|params| params.self_param())
 +            .map(|value| InFile { file_id, value })
 +    }
 +
 +    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
 +        let substs = TyBuilder::placeholder_subst(db, self.func);
 +        let callable_sig =
 +            db.callable_item_signature(self.func.into()).substitute(Interner, &substs);
 +        let environment = db.trait_environment(self.func.into());
 +        let ty = callable_sig.params()[0].clone();
 +        Type { env: environment, ty }
 +    }
 +}
 +
 +impl HasVisibility for Function {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.function_visibility(self.id)
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Const {
 +    pub(crate) id: ConstId,
 +}
 +
 +impl Const {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        db.const_data(self.id).name.clone()
 +    }
 +
 +    pub fn value(self, db: &dyn HirDatabase) -> Option<ast::Expr> {
 +        self.source(db)?.value.body()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let data = db.const_data(self.id);
 +        let resolver = self.id.resolver(db.upcast());
 +        let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
 +        let ty = ctx.lower_ty(&data.type_ref);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    pub fn eval(self, db: &dyn HirDatabase) -> Result<ComputedExpr, ConstEvalError> {
 +        db.const_eval(self.id)
 +    }
 +}
 +
 +impl HasVisibility for Const {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.const_visibility(self.id)
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Static {
 +    pub(crate) id: StaticId,
 +}
 +
 +impl Static {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.static_data(self.id).name.clone()
 +    }
 +
 +    pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
 +        db.static_data(self.id).mutable
 +    }
 +
 +    pub fn value(self, db: &dyn HirDatabase) -> Option<ast::Expr> {
 +        self.source(db)?.value.body()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let data = db.static_data(self.id);
 +        let resolver = self.id.resolver(db.upcast());
 +        let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
 +        let ty = ctx.lower_ty(&data.type_ref);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +}
 +
 +impl HasVisibility for Static {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.static_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Trait {
 +    pub(crate) id: TraitId,
 +}
 +
 +impl Trait {
 +    pub fn lang(db: &dyn HirDatabase, krate: Crate, name: &Name) -> Option<Trait> {
 +        db.lang_item(krate.into(), name.to_smol_str())
 +            .and_then(LangItemTarget::as_trait)
 +            .map(Into::into)
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).container }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.trait_data(self.id).name.clone()
 +    }
 +
 +    pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
 +        db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
 +    }
 +
 +    pub fn items_with_supertraits(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
 +        let traits = all_super_traits(db.upcast(), self.into());
 +        traits.iter().flat_map(|tr| Trait::from(*tr).items(db)).collect()
 +    }
 +
 +    pub fn is_auto(self, db: &dyn HirDatabase) -> bool {
 +        db.trait_data(self.id).is_auto
 +    }
 +
 +    pub fn is_unsafe(&self, db: &dyn HirDatabase) -> bool {
 +        db.trait_data(self.id).is_unsafe
 +    }
 +
 +    pub fn type_or_const_param_count(
 +        &self,
 +        db: &dyn HirDatabase,
 +        count_required_only: bool,
 +    ) -> usize {
 +        db.generic_params(GenericDefId::from(self.id))
 +            .type_or_consts
 +            .iter()
 +            .filter(|(_, ty)| match ty {
 +                TypeOrConstParamData::TypeParamData(ty)
 +                    if ty.provenance != TypeParamProvenance::TypeParamList =>
 +                {
 +                    false
 +                }
 +                _ => true,
 +            })
 +            .filter(|(_, ty)| !count_required_only || !ty.has_default())
 +            .count()
 +    }
 +}
 +
 +impl HasVisibility for Trait {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        db.trait_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct TypeAlias {
 +    pub(crate) id: TypeAliasId,
 +}
 +
 +impl TypeAlias {
 +    pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
 +        let subst = db.generic_defaults(self.id.into());
 +        subst.iter().any(|ty| match ty.skip_binders().data(Interner) {
 +            GenericArgData::Ty(x) => x.is_unknown(),
 +            _ => false,
 +        })
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
 +    }
 +
 +    pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
 +        db.type_alias_data(self.id).type_ref.as_deref().cloned()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::from_def(db, self.id)
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        db.type_alias_data(self.id).name.clone()
 +    }
 +}
 +
 +impl HasVisibility for TypeAlias {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        let function_data = db.type_alias_data(self.id);
 +        let visibility = &function_data.visibility;
 +        visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct BuiltinType {
 +    pub(crate) inner: hir_def::builtin_type::BuiltinType,
 +}
 +
 +impl BuiltinType {
 +    pub fn str() -> BuiltinType {
 +        BuiltinType { inner: hir_def::builtin_type::BuiltinType::Str }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::new_for_crate(db.crate_graph().iter().next().unwrap(), TyBuilder::builtin(self.inner))
 +    }
 +
 +    pub fn name(self) -> Name {
 +        self.inner.as_name()
 +    }
 +
 +    pub fn is_int(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Int(_))
 +    }
 +
 +    pub fn is_uint(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Uint(_))
 +    }
 +
 +    pub fn is_float(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_))
 +    }
 +
 +    pub fn is_char(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Char)
 +    }
 +
 +    pub fn is_bool(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Bool)
 +    }
 +
 +    pub fn is_str(&self) -> bool {
 +        matches!(self.inner, hir_def::builtin_type::BuiltinType::Str)
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub enum MacroKind {
 +    /// `macro_rules!` or Macros 2.0 macro.
 +    Declarative,
 +    /// A built-in or custom derive.
 +    Derive,
 +    /// A built-in function-like macro.
 +    BuiltIn,
 +    /// A procedural attribute macro.
 +    Attr,
 +    /// A function-like procedural macro.
 +    ProcMacro,
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Macro {
 +    pub(crate) id: MacroId,
 +}
 +
 +impl Macro {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        Module { id: self.id.module(db.upcast()) }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        match self.id {
 +            MacroId::Macro2Id(id) => db.macro2_data(id).name.clone(),
 +            MacroId::MacroRulesId(id) => db.macro_rules_data(id).name.clone(),
 +            MacroId::ProcMacroId(id) => db.proc_macro_data(id).name.clone(),
 +        }
 +    }
 +
 +    pub fn is_macro_export(self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.id, MacroId::MacroRulesId(id) if db.macro_rules_data(id).macro_export)
 +    }
 +
 +    pub fn kind(&self, db: &dyn HirDatabase) -> MacroKind {
 +        match self.id {
 +            MacroId::Macro2Id(it) => match it.lookup(db.upcast()).expander {
 +                MacroExpander::Declarative => MacroKind::Declarative,
 +                MacroExpander::BuiltIn(_) | MacroExpander::BuiltInEager(_) => MacroKind::BuiltIn,
 +                MacroExpander::BuiltInAttr(_) => MacroKind::Attr,
 +                MacroExpander::BuiltInDerive(_) => MacroKind::Derive,
 +            },
 +            MacroId::MacroRulesId(it) => match it.lookup(db.upcast()).expander {
 +                MacroExpander::Declarative => MacroKind::Declarative,
 +                MacroExpander::BuiltIn(_) | MacroExpander::BuiltInEager(_) => MacroKind::BuiltIn,
 +                MacroExpander::BuiltInAttr(_) => MacroKind::Attr,
 +                MacroExpander::BuiltInDerive(_) => MacroKind::Derive,
 +            },
 +            MacroId::ProcMacroId(it) => match it.lookup(db.upcast()).kind {
 +                ProcMacroKind::CustomDerive => MacroKind::Derive,
 +                ProcMacroKind::FuncLike => MacroKind::ProcMacro,
 +                ProcMacroKind::Attr => MacroKind::Attr,
 +            },
 +        }
 +    }
 +
 +    pub fn is_fn_like(&self, db: &dyn HirDatabase) -> bool {
 +        match self.kind(db) {
 +            MacroKind::Declarative | MacroKind::BuiltIn | MacroKind::ProcMacro => true,
 +            MacroKind::Attr | MacroKind::Derive => false,
 +        }
 +    }
 +
 +    pub fn is_builtin_derive(&self, db: &dyn HirDatabase) -> bool {
 +        match self.id {
 +            MacroId::Macro2Id(it) => {
 +                matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInDerive(_))
 +            }
 +            MacroId::MacroRulesId(it) => {
 +                matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInDerive(_))
 +            }
 +            MacroId::ProcMacroId(_) => false,
 +        }
 +    }
 +
 +    pub fn is_attr(&self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.kind(db), MacroKind::Attr)
 +    }
 +
 +    pub fn is_derive(&self, db: &dyn HirDatabase) -> bool {
 +        matches!(self.kind(db), MacroKind::Derive)
 +    }
 +}
 +
 +impl HasVisibility for Macro {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match self.id {
 +            MacroId::Macro2Id(id) => {
 +                let data = db.macro2_data(id);
 +                let visibility = &data.visibility;
 +                visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
 +            }
 +            MacroId::MacroRulesId(_) => Visibility::Public,
 +            MacroId::ProcMacroId(_) => Visibility::Public,
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 +pub enum ItemInNs {
 +    Types(ModuleDef),
 +    Values(ModuleDef),
 +    Macros(Macro),
 +}
 +
 +impl From<Macro> for ItemInNs {
 +    fn from(it: Macro) -> Self {
 +        Self::Macros(it)
 +    }
 +}
 +
 +impl From<ModuleDef> for ItemInNs {
 +    fn from(module_def: ModuleDef) -> Self {
 +        match module_def {
 +            ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => {
 +                ItemInNs::Values(module_def)
 +            }
 +            _ => ItemInNs::Types(module_def),
 +        }
 +    }
 +}
 +
 +impl ItemInNs {
 +    pub fn as_module_def(self) -> Option<ModuleDef> {
 +        match self {
 +            ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
 +            ItemInNs::Macros(_) => None,
 +        }
 +    }
 +
 +    /// Returns the crate defining this item (or `None` if `self` is built-in).
 +    pub fn krate(&self, db: &dyn HirDatabase) -> Option<Crate> {
 +        match self {
 +            ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate()),
 +            ItemInNs::Macros(id) => Some(id.module(db).krate()),
 +        }
 +    }
 +
 +    pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
 +        match self {
 +            ItemInNs::Types(it) | ItemInNs::Values(it) => it.attrs(db),
 +            ItemInNs::Macros(it) => Some(it.attrs(db)),
 +        }
 +    }
 +}
 +
 +/// Invariant: `inner.as_assoc_item(db).is_some()`
 +/// We do not actively enforce this invariant.
 +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 +pub enum AssocItem {
 +    Function(Function),
 +    Const(Const),
 +    TypeAlias(TypeAlias),
 +}
 +#[derive(Debug)]
 +pub enum AssocItemContainer {
 +    Trait(Trait),
 +    Impl(Impl),
 +}
 +pub trait AsAssocItem {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem>;
 +}
 +
 +impl AsAssocItem for Function {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        as_assoc_item(db, AssocItem::Function, self.id)
 +    }
 +}
 +impl AsAssocItem for Const {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        as_assoc_item(db, AssocItem::Const, self.id)
 +    }
 +}
 +impl AsAssocItem for TypeAlias {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        as_assoc_item(db, AssocItem::TypeAlias, self.id)
 +    }
 +}
 +impl AsAssocItem for ModuleDef {
 +    fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
 +        match self {
 +            ModuleDef::Function(it) => it.as_assoc_item(db),
 +            ModuleDef::Const(it) => it.as_assoc_item(db),
 +            ModuleDef::TypeAlias(it) => it.as_assoc_item(db),
 +            _ => None,
 +        }
 +    }
 +}
 +fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem>
 +where
 +    ID: Lookup<Data = AssocItemLoc<AST>>,
 +    DEF: From<ID>,
 +    CTOR: FnOnce(DEF) -> AssocItem,
 +    AST: ItemTreeNode,
 +{
 +    match id.lookup(db.upcast()).container {
 +        ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
 +        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
 +    }
 +}
 +
 +impl AssocItem {
 +    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 +        match self {
 +            AssocItem::Function(it) => Some(it.name(db)),
 +            AssocItem::Const(it) => it.name(db),
 +            AssocItem::TypeAlias(it) => Some(it.name(db)),
 +        }
 +    }
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            AssocItem::Function(f) => f.module(db),
 +            AssocItem::Const(c) => c.module(db),
 +            AssocItem::TypeAlias(t) => t.module(db),
 +        }
 +    }
 +    pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer {
 +        let container = match self {
 +            AssocItem::Function(it) => it.id.lookup(db.upcast()).container,
 +            AssocItem::Const(it) => it.id.lookup(db.upcast()).container,
 +            AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container,
 +        };
 +        match container {
 +            ItemContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
 +            ItemContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
 +            ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
 +                panic!("invalid AssocItem")
 +            }
 +        }
 +    }
 +
 +    pub fn containing_trait(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        match self.container(db) {
 +            AssocItemContainer::Trait(t) => Some(t),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn containing_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        match self.container(db) {
 +            AssocItemContainer::Impl(i) => i.trait_(db),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn containing_trait_or_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        match self.container(db) {
 +            AssocItemContainer::Trait(t) => Some(t),
 +            AssocItemContainer::Impl(i) => i.trait_(db),
 +        }
 +    }
 +}
 +
 +impl HasVisibility for AssocItem {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
 +        match self {
 +            AssocItem::Function(f) => f.visibility(db),
 +            AssocItem::Const(c) => c.visibility(db),
 +            AssocItem::TypeAlias(t) => t.visibility(db),
 +        }
 +    }
 +}
 +
 +impl From<AssocItem> for ModuleDef {
 +    fn from(assoc: AssocItem) -> Self {
 +        match assoc {
 +            AssocItem::Function(it) => ModuleDef::Function(it),
 +            AssocItem::Const(it) => ModuleDef::Const(it),
 +            AssocItem::TypeAlias(it) => ModuleDef::TypeAlias(it),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 +pub enum GenericDef {
 +    Function(Function),
 +    Adt(Adt),
 +    Trait(Trait),
 +    TypeAlias(TypeAlias),
 +    Impl(Impl),
 +    // enum variants cannot have generics themselves, but their parent enums
 +    // can, and this makes some code easier to write
 +    Variant(Variant),
 +    // consts can have type parameters from their parents (i.e. associated consts of traits)
 +    Const(Const),
 +}
 +impl_from!(
 +    Function,
 +    Adt(Struct, Enum, Union),
 +    Trait,
 +    TypeAlias,
 +    Impl,
 +    Variant,
 +    Const
 +    for GenericDef
 +);
 +
 +impl GenericDef {
 +    pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
 +        let generics = db.generic_params(self.into());
 +        let ty_params = generics.type_or_consts.iter().map(|(local_id, _)| {
 +            let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } };
 +            match toc.split(db) {
 +                Either::Left(x) => GenericParam::ConstParam(x),
 +                Either::Right(x) => GenericParam::TypeParam(x),
 +            }
 +        });
 +        let lt_params = generics
 +            .lifetimes
 +            .iter()
 +            .map(|(local_id, _)| LifetimeParam {
 +                id: LifetimeParamId { parent: self.into(), local_id },
 +            })
 +            .map(GenericParam::LifetimeParam);
 +        lt_params.chain(ty_params).collect()
 +    }
 +
 +    pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
 +        let generics = db.generic_params(self.into());
 +        generics
 +            .type_or_consts
 +            .iter()
 +            .map(|(local_id, _)| TypeOrConstParam {
 +                id: TypeOrConstParamId { parent: self.into(), local_id },
 +            })
 +            .collect()
 +    }
 +}
 +
 +/// A single local definition.
 +///
 +/// If the definition of this is part of a "MultiLocal", that is a local that has multiple declarations due to or-patterns
 +/// then this only references a single one of those.
 +/// To retrieve the other locals you should use [`Local::associated_locals`]
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct Local {
 +    pub(crate) parent: DefWithBodyId,
 +    pub(crate) pat_id: PatId,
 +}
 +
 +impl Local {
 +    pub fn is_param(self, db: &dyn HirDatabase) -> bool {
 +        let src = self.source(db);
 +        match src.value {
 +            Either::Left(pat) => pat
 +                .syntax()
 +                .ancestors()
 +                .map(|it| it.kind())
 +                .take_while(|&kind| ast::Pat::can_cast(kind) || ast::Param::can_cast(kind))
 +                .any(ast::Param::can_cast),
 +            Either::Right(_) => true,
 +        }
 +    }
 +
 +    pub fn as_self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
 +        match self.parent {
 +            DefWithBodyId::FunctionId(func) if self.is_self(db) => Some(SelfParam { func }),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let body = db.body(self.parent);
 +        match &body[self.pat_id] {
 +            Pat::Bind { name, .. } => name.clone(),
 +            _ => {
 +                stdx::never!("hir::Local is missing a name!");
 +                Name::missing()
 +            }
 +        }
 +    }
 +
 +    pub fn is_self(self, db: &dyn HirDatabase) -> bool {
 +        self.name(db) == name![self]
 +    }
 +
 +    pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
 +        let body = db.body(self.parent);
 +        matches!(&body[self.pat_id], Pat::Bind { mode: BindingAnnotation::Mutable, .. })
 +    }
 +
 +    pub fn is_ref(self, db: &dyn HirDatabase) -> bool {
 +        let body = db.body(self.parent);
 +        matches!(
 +            &body[self.pat_id],
 +            Pat::Bind { mode: BindingAnnotation::Ref | BindingAnnotation::RefMut, .. }
 +        )
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
 +        self.parent.into()
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.parent(db).module(db)
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let def = self.parent;
 +        let infer = db.infer(def);
 +        let ty = infer[self.pat_id].clone();
 +        Type::new(db, def, ty)
 +    }
 +
 +    pub fn associated_locals(self, db: &dyn HirDatabase) -> Box<[Local]> {
 +        let body = db.body(self.parent);
 +        body.ident_patterns_for(&self.pat_id)
 +            .iter()
 +            .map(|&pat_id| Local { parent: self.parent, pat_id })
 +            .collect()
 +    }
 +
 +    /// If this local is part of a multi-local, retrieve the representative local.
 +    /// That is the local that references are being resolved to.
 +    pub fn representative(self, db: &dyn HirDatabase) -> Local {
 +        let body = db.body(self.parent);
 +        Local { pat_id: body.pattern_representative(self.pat_id), ..self }
 +    }
 +
 +    pub fn source(self, db: &dyn HirDatabase) -> InFile<Either<ast::IdentPat, ast::SelfParam>> {
 +        let (_body, source_map) = db.body_with_source_map(self.parent);
 +        let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm...
 +        let root = src.file_syntax(db.upcast());
 +        src.map(|ast| match ast {
 +            // Suspicious unwrap
 +            Either::Left(it) => Either::Left(it.cast().unwrap().to_node(&root)),
 +            Either::Right(it) => Either::Right(it.to_node(&root)),
 +        })
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct DeriveHelper {
 +    pub(crate) derive: MacroId,
 +    pub(crate) idx: usize,
 +}
 +
 +impl DeriveHelper {
 +    pub fn derive(&self) -> Macro {
 +        Macro { id: self.derive.into() }
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> Name {
 +        match self.derive {
 +            MacroId::Macro2Id(_) => None,
 +            MacroId::MacroRulesId(_) => None,
 +            MacroId::ProcMacroId(proc_macro) => db
 +                .proc_macro_data(proc_macro)
 +                .helpers
 +                .as_ref()
 +                .and_then(|it| it.get(self.idx))
 +                .cloned(),
 +        }
 +        .unwrap_or_else(|| Name::missing())
 +    }
 +}
 +
 +// FIXME: Wrong name? This is could also be a registered attribute
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct BuiltinAttr {
 +    krate: Option<CrateId>,
 +    idx: usize,
 +}
 +
 +impl BuiltinAttr {
 +    // FIXME: consider crates\hir_def\src\nameres\attr_resolution.rs?
 +    pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<Self> {
 +        if let builtin @ Some(_) = Self::builtin(name) {
 +            return builtin;
 +        }
 +        let idx = db.crate_def_map(krate.id).registered_attrs().iter().position(|it| it == name)?;
 +        Some(BuiltinAttr { krate: Some(krate.id), idx })
 +    }
 +
 +    fn builtin(name: &str) -> Option<Self> {
 +        hir_def::builtin_attr::INERT_ATTRIBUTES
 +            .iter()
 +            .position(|tool| tool.name == name)
 +            .map(|idx| BuiltinAttr { krate: None, idx })
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> SmolStr {
 +        // FIXME: Return a `Name` here
 +        match self.krate {
 +            Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx].clone(),
 +            None => SmolStr::new(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].name),
 +        }
 +    }
 +
 +    pub fn template(&self, _: &dyn HirDatabase) -> Option<AttributeTemplate> {
 +        match self.krate {
 +            Some(_) => None,
 +            None => Some(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].template),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct ToolModule {
 +    krate: Option<CrateId>,
 +    idx: usize,
 +}
 +
 +impl ToolModule {
 +    // FIXME: consider crates\hir_def\src\nameres\attr_resolution.rs?
 +    pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<Self> {
 +        if let builtin @ Some(_) = Self::builtin(name) {
 +            return builtin;
 +        }
 +        let idx = db.crate_def_map(krate.id).registered_tools().iter().position(|it| it == name)?;
 +        Some(ToolModule { krate: Some(krate.id), idx })
 +    }
 +
 +    fn builtin(name: &str) -> Option<Self> {
 +        hir_def::builtin_attr::TOOL_MODULES
 +            .iter()
 +            .position(|&tool| tool == name)
 +            .map(|idx| ToolModule { krate: None, idx })
 +    }
 +
 +    pub fn name(&self, db: &dyn HirDatabase) -> SmolStr {
 +        // FIXME: Return a `Name` here
 +        match self.krate {
 +            Some(krate) => db.crate_def_map(krate).registered_tools()[self.idx].clone(),
 +            None => SmolStr::new(hir_def::builtin_attr::TOOL_MODULES[self.idx]),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct Label {
 +    pub(crate) parent: DefWithBodyId,
 +    pub(crate) label_id: LabelId,
 +}
 +
 +impl Label {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.parent(db).module(db)
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
 +        self.parent.into()
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let body = db.body(self.parent);
 +        body[self.label_id].name.clone()
 +    }
 +
 +    pub fn source(self, db: &dyn HirDatabase) -> InFile<ast::Label> {
 +        let (_body, source_map) = db.body_with_source_map(self.parent);
 +        let src = source_map.label_syntax(self.label_id);
 +        let root = src.file_syntax(db.upcast());
 +        src.map(|ast| ast.to_node(&root))
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub enum GenericParam {
 +    TypeParam(TypeParam),
 +    ConstParam(ConstParam),
 +    LifetimeParam(LifetimeParam),
 +}
 +impl_from!(TypeParam, ConstParam, LifetimeParam for GenericParam);
 +
 +impl GenericParam {
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        match self {
 +            GenericParam::TypeParam(it) => it.module(db),
 +            GenericParam::ConstParam(it) => it.module(db),
 +            GenericParam::LifetimeParam(it) => it.module(db),
 +        }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        match self {
 +            GenericParam::TypeParam(it) => it.name(db),
 +            GenericParam::ConstParam(it) => it.name(db),
 +            GenericParam::LifetimeParam(it) => it.name(db),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct TypeParam {
 +    pub(crate) id: TypeParamId,
 +}
 +
 +impl TypeParam {
 +    pub fn merge(self) -> TypeOrConstParam {
 +        TypeOrConstParam { id: self.id.into() }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        self.merge().name(db)
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent().module(db.upcast()).into()
 +    }
 +
 +    /// Is this type parameter implicitly introduced (eg. `Self` in a trait or an `impl Trait`
 +    /// argument)?
 +    pub fn is_implicit(self, db: &dyn HirDatabase) -> bool {
 +        let params = db.generic_params(self.id.parent());
 +        let data = &params.type_or_consts[self.id.local_id()];
 +        match data.type_param().unwrap().provenance {
 +            hir_def::generics::TypeParamProvenance::TypeParamList => false,
 +            hir_def::generics::TypeParamProvenance::TraitSelf
 +            | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => true,
 +        }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        let resolver = self.id.parent().resolver(db.upcast());
 +        let ty =
 +            TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id.into())).intern(Interner);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    /// FIXME: this only lists trait bounds from the item defining the type
 +    /// parameter, not additional bounds that might be added e.g. by a method if
 +    /// the parameter comes from an impl!
 +    pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
 +        db.generic_predicates_for_param(self.id.parent(), self.id.into(), None)
 +            .iter()
 +            .filter_map(|pred| match &pred.skip_binders().skip_binders() {
 +                hir_ty::WhereClause::Implemented(trait_ref) => {
 +                    Some(Trait::from(trait_ref.hir_trait_id()))
 +                }
 +                _ => None,
 +            })
 +            .collect()
 +    }
 +
 +    pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
 +        let params = db.generic_defaults(self.id.parent());
 +        let local_idx = hir_ty::param_idx(db, self.id.into())?;
 +        let resolver = self.id.parent().resolver(db.upcast());
 +        let ty = params.get(local_idx)?.clone();
 +        let subst = TyBuilder::placeholder_subst(db, self.id.parent());
 +        let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx));
 +        match ty.data(Interner) {
 +            GenericArgData::Ty(x) => Some(Type::new_with_resolver_inner(db, &resolver, x.clone())),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct LifetimeParam {
 +    pub(crate) id: LifetimeParamId,
 +}
 +
 +impl LifetimeParam {
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let params = db.generic_params(self.id.parent);
 +        params.lifetimes[self.id.local_id].name.clone()
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent.module(db.upcast()).into()
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
 +        self.id.parent.into()
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct ConstParam {
 +    pub(crate) id: ConstParamId,
 +}
 +
 +impl ConstParam {
 +    pub fn merge(self) -> TypeOrConstParam {
 +        TypeOrConstParam { id: self.id.into() }
 +    }
 +
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let params = db.generic_params(self.id.parent());
 +        match params.type_or_consts[self.id.local_id()].name() {
 +            Some(x) => x.clone(),
 +            None => {
 +                never!();
 +                Name::missing()
 +            }
 +        }
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent().module(db.upcast()).into()
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
 +        self.id.parent().into()
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        Type::new(db, self.id.parent(), db.const_param_ty(self.id))
 +    }
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 +pub struct TypeOrConstParam {
 +    pub(crate) id: TypeOrConstParamId,
 +}
 +
 +impl TypeOrConstParam {
 +    pub fn name(self, db: &dyn HirDatabase) -> Name {
 +        let params = db.generic_params(self.id.parent);
 +        match params.type_or_consts[self.id.local_id].name() {
 +            Some(n) => n.clone(),
 +            _ => Name::missing(),
 +        }
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.parent.module(db.upcast()).into()
 +    }
 +
 +    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
 +        self.id.parent.into()
 +    }
 +
 +    pub fn split(self, db: &dyn HirDatabase) -> Either<ConstParam, TypeParam> {
 +        let params = db.generic_params(self.id.parent);
 +        match &params.type_or_consts[self.id.local_id] {
 +            hir_def::generics::TypeOrConstParamData::TypeParamData(_) => {
 +                Either::Right(TypeParam { id: TypeParamId::from_unchecked(self.id) })
 +            }
 +            hir_def::generics::TypeOrConstParamData::ConstParamData(_) => {
 +                Either::Left(ConstParam { id: ConstParamId::from_unchecked(self.id) })
 +            }
 +        }
 +    }
 +
 +    pub fn ty(self, db: &dyn HirDatabase) -> Type {
 +        match self.split(db) {
 +            Either::Left(x) => x.ty(db),
 +            Either::Right(x) => x.ty(db),
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 +pub struct Impl {
 +    pub(crate) id: ImplId,
 +}
 +
 +impl Impl {
 +    pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<Impl> {
 +        let inherent = db.inherent_impls_in_crate(krate.id);
 +        let trait_ = db.trait_impls_in_crate(krate.id);
 +
 +        inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
 +    }
 +
 +    pub fn all_for_type(db: &dyn HirDatabase, Type { ty, env }: Type) -> Vec<Impl> {
 +        let def_crates = match method_resolution::def_crates(db, &ty, env.krate) {
 +            Some(def_crates) => def_crates,
 +            None => return Vec::new(),
 +        };
 +
 +        let filter = |impl_def: &Impl| {
 +            let self_ty = impl_def.self_ty(db);
 +            let rref = self_ty.remove_ref();
 +            ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty))
 +        };
 +
 +        let fp = TyFingerprint::for_inherent_impl(&ty);
 +        let fp = match fp {
 +            Some(fp) => fp,
 +            None => return Vec::new(),
 +        };
 +
 +        let mut all = Vec::new();
 +        def_crates.iter().for_each(|&id| {
 +            all.extend(
 +                db.inherent_impls_in_crate(id)
 +                    .for_self_ty(&ty)
 +                    .iter()
 +                    .cloned()
 +                    .map(Self::from)
 +                    .filter(filter),
 +            )
 +        });
 +        for id in def_crates
 +            .iter()
 +            .flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db))
 +            .map(|Crate { id }| id)
 +            .chain(def_crates.iter().copied())
 +            .unique()
 +        {
 +            all.extend(
 +                db.trait_impls_in_crate(id)
 +                    .for_self_ty_without_blanket_impls(fp)
 +                    .map(Self::from)
 +                    .filter(filter),
 +            );
 +        }
 +        all
 +    }
 +
 +    pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec<Impl> {
 +        let krate = trait_.module(db).krate();
 +        let mut all = Vec::new();
 +        for Crate { id } in krate.transitive_reverse_dependencies(db).into_iter() {
 +            let impls = db.trait_impls_in_crate(id);
 +            all.extend(impls.for_trait(trait_.id).map(Self::from))
 +        }
 +        all
 +    }
 +
 +    // FIXME: the return type is wrong. This should be a hir version of
 +    // `TraitRef` (to account for parameters and qualifiers)
 +    pub fn trait_(self, db: &dyn HirDatabase) -> Option<Trait> {
 +        let trait_ref = db.impl_trait(self.id)?.skip_binders().clone();
 +        let id = hir_ty::from_chalk_trait_id(trait_ref.trait_id);
 +        Some(Trait { id })
 +    }
 +
 +    pub fn self_ty(self, db: &dyn HirDatabase) -> Type {
 +        let resolver = self.id.resolver(db.upcast());
 +        let substs = TyBuilder::placeholder_subst(db, self.id);
 +        let ty = db.impl_self_ty(self.id).substitute(Interner, &substs);
 +        Type::new_with_resolver_inner(db, &resolver, ty)
 +    }
 +
 +    pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
 +        db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect()
 +    }
 +
 +    pub fn is_negative(self, db: &dyn HirDatabase) -> bool {
 +        db.impl_data(self.id).is_negative
 +    }
 +
 +    pub fn module(self, db: &dyn HirDatabase) -> Module {
 +        self.id.lookup(db.upcast()).container.into()
 +    }
 +
 +    pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> {
 +        let src = self.source(db)?;
 +        src.file_id.is_builtin_derive(db.upcast())
 +    }
 +}
 +
 +#[derive(Clone, PartialEq, Eq, Debug)]
 +pub struct Type {
 +    env: Arc<TraitEnvironment>,
 +    ty: Ty,
 +}
 +
 +impl Type {
 +    pub(crate) fn new_with_resolver(db: &dyn HirDatabase, resolver: &Resolver, ty: Ty) -> Type {
 +        Type::new_with_resolver_inner(db, resolver, ty)
 +    }
 +
 +    pub(crate) fn new_with_resolver_inner(
 +        db: &dyn HirDatabase,
 +        resolver: &Resolver,
 +        ty: Ty,
 +    ) -> Type {
 +        let environment = resolver.generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(resolver.krate())),
 +            |d| db.trait_environment(d),
 +        );
 +        Type { env: environment, ty }
 +    }
 +
 +    pub(crate) fn new_for_crate(krate: CrateId, ty: Ty) -> Type {
 +        Type { env: Arc::new(TraitEnvironment::empty(krate)), ty }
 +    }
 +
 +    pub fn reference(inner: &Type, m: Mutability) -> Type {
 +        inner.derived(
 +            TyKind::Ref(
 +                if m.is_mut() { hir_ty::Mutability::Mut } else { hir_ty::Mutability::Not },
 +                hir_ty::static_lifetime(),
 +                inner.ty.clone(),
 +            )
 +            .intern(Interner),
 +        )
 +    }
 +
 +    fn new(db: &dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty) -> Type {
 +        let resolver = lexical_env.resolver(db.upcast());
 +        let environment = resolver.generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(resolver.krate())),
 +            |d| db.trait_environment(d),
 +        );
 +        Type { env: environment, ty }
 +    }
 +
 +    fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into<TyDefId>) -> Type {
 +        let ty = TyBuilder::def_ty(db, def.into()).fill_with_unknown().build();
 +        Type::new(db, def, ty)
 +    }
 +
 +    pub fn new_slice(ty: Type) -> Type {
 +        Type { env: ty.env, ty: TyBuilder::slice(ty.ty) }
 +    }
 +
 +    pub fn is_unit(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Tuple(0, ..))
 +    }
 +
 +    pub fn is_bool(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Bool))
 +    }
 +
 +    pub fn is_never(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Never)
 +    }
 +
 +    pub fn is_mutable_reference(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..))
 +    }
 +
 +    pub fn is_reference(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Ref(..))
 +    }
 +
 +    pub fn as_reference(&self) -> Option<(Type, Mutability)> {
 +        let (ty, _lt, m) = self.ty.as_reference()?;
 +        let m = Mutability::from_mutable(matches!(m, hir_ty::Mutability::Mut));
 +        Some((self.derived(ty.clone()), m))
 +    }
 +
 +    pub fn is_slice(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Slice(..))
 +    }
 +
 +    pub fn is_usize(&self) -> bool {
 +        matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)))
 +    }
 +
 +    pub fn remove_ref(&self) -> Option<Type> {
 +        match &self.ty.kind(Interner) {
 +            TyKind::Ref(.., ty) => Some(self.derived(ty.clone())),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn strip_references(&self) -> Type {
 +        self.derived(self.ty.strip_references().clone())
 +    }
 +
 +    pub fn strip_reference(&self) -> Type {
 +        self.derived(self.ty.strip_reference().clone())
 +    }
 +
 +    pub fn is_unknown(&self) -> bool {
 +        self.ty.is_unknown()
 +    }
 +
 +    /// 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 projection = TyBuilder::assoc_type_projection(db, alias.id)
 +            .push(self.ty.clone())
 +            .fill(|x| {
 +                // FIXME: this code is not covered in tests.
 +                match x {
 +                    ParamKind::Type => {
 +                        GenericArgData::Ty(args.next().unwrap().ty.clone()).intern(Interner)
 +                    }
 +                    ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
 +                }
 +            })
 +            .build();
 +        let goal = hir_ty::make_canonical(
 +            InEnvironment::new(
 +                &self.env.env,
 +                AliasEq {
 +                    alias: AliasTy::Projection(projection),
 +                    ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
 +                        .intern(Interner),
 +                }
 +                .cast(Interner),
 +            ),
 +            [TyVariableKind::General].into_iter(),
 +        );
 +
 +        match db.trait_solve(self.env.krate, goal)? {
 +            Solution::Unique(s) => s
 +                .value
 +                .subst
 +                .as_slice(Interner)
 +                .first()
 +                .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone())),
 +            Solution::Ambig(_) => None,
 +        }
 +    }
 +
 +    pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
 +        let lang_item = db.lang_item(self.env.krate, SmolStr::new_inline("copy"));
 +        let copy_trait = match lang_item {
 +            Some(LangItemTarget::TraitId(it)) => it,
 +            _ => return false,
 +        };
 +        self.impls_trait(db, copy_trait.into(), &[])
 +    }
 +
 +    pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
 +        let callee = match self.ty.kind(Interner) {
 +            TyKind::Closure(id, _) => Callee::Closure(*id),
 +            TyKind::Function(_) => Callee::FnPtr,
 +            _ => Callee::Def(self.ty.callable_def(db)?),
 +        };
 +
 +        let sig = self.ty.callable_sig(db)?;
 +        Some(Callable { ty: self.clone(), sig, callee, is_bound_method: false })
 +    }
 +
 +    pub fn is_closure(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::Closure { .. })
 +    }
 +
 +    pub fn is_fn(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::FnDef(..) | TyKind::Function { .. })
 +    }
 +
 +    pub fn is_array(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::Array(..))
 +    }
 +
 +    pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
 +        let adt_id = match *self.ty.kind(Interner) {
 +            TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id,
 +            _ => return false,
 +        };
 +
 +        let adt = adt_id.into();
 +        match adt {
 +            Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)),
 +            _ => false,
 +        }
 +    }
 +
 +    pub fn is_raw_ptr(&self) -> bool {
 +        matches!(&self.ty.kind(Interner), TyKind::Raw(..))
 +    }
 +
 +    pub fn contains_unknown(&self) -> bool {
 +        return go(&self.ty);
 +
 +        fn go(ty: &Ty) -> bool {
 +            match ty.kind(Interner) {
 +                TyKind::Error => true,
 +
 +                TyKind::Adt(_, substs)
 +                | TyKind::AssociatedType(_, substs)
 +                | TyKind::Tuple(_, substs)
 +                | TyKind::OpaqueType(_, substs)
 +                | TyKind::FnDef(_, substs)
 +                | TyKind::Closure(_, substs) => {
 +                    substs.iter(Interner).filter_map(|a| a.ty(Interner)).any(go)
 +                }
 +
 +                TyKind::Array(_ty, len) if len.is_unknown() => true,
 +                TyKind::Array(ty, _)
 +                | TyKind::Slice(ty)
 +                | TyKind::Raw(_, ty)
 +                | TyKind::Ref(_, _, ty) => go(ty),
 +
 +                TyKind::Scalar(_)
 +                | TyKind::Str
 +                | TyKind::Never
 +                | TyKind::Placeholder(_)
 +                | TyKind::BoundVar(_)
 +                | TyKind::InferenceVar(_, _)
 +                | TyKind::Dyn(_)
 +                | TyKind::Function(_)
 +                | TyKind::Alias(_)
 +                | TyKind::Foreign(_)
 +                | TyKind::Generator(..)
 +                | TyKind::GeneratorWitness(..) => false,
 +            }
 +        }
 +    }
 +
 +    pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
 +        let (variant_id, substs) = match self.ty.kind(Interner) {
 +            TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), substs) => ((*s).into(), substs),
 +            TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), substs) => ((*u).into(), substs),
 +            _ => return Vec::new(),
 +        };
 +
 +        db.field_types(variant_id)
 +            .iter()
 +            .map(|(local_id, ty)| {
 +                let def = Field { parent: variant_id.into(), id: local_id };
 +                let ty = ty.clone().substitute(Interner, substs);
 +                (def, self.derived(ty))
 +            })
 +            .collect()
 +    }
 +
 +    pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> {
 +        if let TyKind::Tuple(_, substs) = &self.ty.kind(Interner) {
 +            substs
 +                .iter(Interner)
 +                .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone()))
 +                .collect()
 +        } else {
 +            Vec::new()
 +        }
 +    }
 +
 +    pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
 +        self.autoderef_(db).map(move |ty| self.derived(ty))
 +    }
 +
 +    fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a {
 +        // There should be no inference vars in types passed here
 +        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 +        let environment = self.env.clone();
 +        autoderef(db, environment, canonical).map(|canonical| canonical.value)
 +    }
 +
 +    // This would be nicer if it just returned an iterator, but that runs into
 +    // lifetime problems, because we need to borrow temp `CrateImplDefs`.
 +    pub fn iterate_assoc_items<T>(
 +        &self,
 +        db: &dyn HirDatabase,
 +        krate: Crate,
 +        mut callback: impl FnMut(AssocItem) -> Option<T>,
 +    ) -> Option<T> {
 +        let mut slot = None;
 +        self.iterate_assoc_items_dyn(db, krate, &mut |assoc_item_id| {
 +            slot = callback(assoc_item_id.into());
 +            slot.is_some()
 +        });
 +        slot
 +    }
 +
 +    fn iterate_assoc_items_dyn(
 +        &self,
 +        db: &dyn HirDatabase,
 +        krate: Crate,
 +        callback: &mut dyn FnMut(AssocItemId) -> bool,
 +    ) {
 +        let def_crates = match method_resolution::def_crates(db, &self.ty, krate.id) {
 +            Some(it) => it,
 +            None => return,
 +        };
 +        for krate in def_crates {
 +            let impls = db.inherent_impls_in_crate(krate);
 +
 +            for impl_def in impls.for_self_ty(&self.ty) {
 +                for &item in db.impl_data(*impl_def).items.iter() {
 +                    if callback(item) {
 +                        return;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    pub fn type_arguments(&self) -> impl Iterator<Item = Type> + '_ {
 +        self.ty
 +            .strip_references()
 +            .as_adt()
 +            .into_iter()
 +            .flat_map(|(_, substs)| substs.iter(Interner))
 +            .filter_map(|arg| arg.ty(Interner).cloned())
 +            .map(move |ty| self.derived(ty))
 +    }
 +
 +    pub fn iterate_method_candidates<T>(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        // FIXME this can be retrieved from `scope`, except autoimport uses this
 +        // to specify a different set, so the method needs to be split
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        mut callback: impl FnMut(Function) -> Option<T>,
 +    ) -> Option<T> {
 +        let _p = profile::span("iterate_method_candidates");
 +        let mut slot = None;
 +
 +        self.iterate_method_candidates_dyn(
 +            db,
 +            scope,
 +            traits_in_scope,
 +            with_local_impls,
 +            name,
 +            &mut |assoc_item_id| {
 +                if let AssocItemId::FunctionId(func) = assoc_item_id {
 +                    if let Some(res) = callback(func.into()) {
 +                        slot = Some(res);
 +                        return ControlFlow::Break(());
 +                    }
 +                }
 +                ControlFlow::Continue(())
 +            },
 +        );
 +        slot
 +    }
 +
 +    fn iterate_method_candidates_dyn(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
 +    ) {
 +        // There should be no inference vars in types passed here
 +        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 +
 +        let krate = scope.krate();
 +        let environment = scope.resolver().generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(krate.id)),
 +            |d| db.trait_environment(d),
 +        );
 +
 +        method_resolution::iterate_method_candidates_dyn(
 +            &canonical,
 +            db,
 +            environment,
 +            traits_in_scope,
 +            with_local_impls.and_then(|b| b.id.containing_block()).into(),
 +            name,
 +            method_resolution::LookupMode::MethodCall,
 +            &mut |_adj, id| callback(id),
 +        );
 +    }
 +
 +    pub fn iterate_path_candidates<T>(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        mut callback: impl FnMut(AssocItem) -> Option<T>,
 +    ) -> Option<T> {
 +        let _p = profile::span("iterate_path_candidates");
 +        let mut slot = None;
 +        self.iterate_path_candidates_dyn(
 +            db,
 +            scope,
 +            traits_in_scope,
 +            with_local_impls,
 +            name,
 +            &mut |assoc_item_id| {
 +                if let Some(res) = callback(assoc_item_id.into()) {
 +                    slot = Some(res);
 +                    return ControlFlow::Break(());
 +                }
 +                ControlFlow::Continue(())
 +            },
 +        );
 +        slot
 +    }
 +
 +    fn iterate_path_candidates_dyn(
 +        &self,
 +        db: &dyn HirDatabase,
 +        scope: &SemanticsScope<'_>,
 +        traits_in_scope: &FxHashSet<TraitId>,
 +        with_local_impls: Option<Module>,
 +        name: Option<&Name>,
 +        callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
 +    ) {
 +        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 +
 +        let krate = scope.krate();
 +        let environment = scope.resolver().generic_def().map_or_else(
 +            || Arc::new(TraitEnvironment::empty(krate.id)),
 +            |d| db.trait_environment(d),
 +        );
 +
 +        method_resolution::iterate_path_candidates(
 +            &canonical,
 +            db,
 +            environment,
 +            traits_in_scope,
 +            with_local_impls.and_then(|b| b.id.containing_block()).into(),
 +            name,
 +            &mut |id| callback(id),
 +        );
 +    }
 +
 +    pub fn as_adt(&self) -> Option<Adt> {
 +        let (adt, _subst) = self.ty.as_adt()?;
 +        Some(adt.into())
 +    }
 +
 +    pub fn as_builtin(&self) -> Option<BuiltinType> {
 +        self.ty.as_builtin().map(|inner| BuiltinType { inner })
 +    }
 +
 +    pub fn as_dyn_trait(&self) -> Option<Trait> {
 +        self.ty.dyn_trait().map(Into::into)
 +    }
 +
 +    /// If a type can be represented as `dyn Trait`, returns all traits accessible via this type,
 +    /// or an empty iterator otherwise.
 +    pub fn applicable_inherent_traits<'a>(
 +        &'a self,
 +        db: &'a dyn HirDatabase,
 +    ) -> impl Iterator<Item = Trait> + 'a {
 +        let _p = profile::span("applicable_inherent_traits");
 +        self.autoderef_(db)
 +            .filter_map(|ty| ty.dyn_trait())
 +            .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id))
 +            .map(Trait::from)
 +    }
 +
 +    pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Trait> + 'a {
 +        let _p = profile::span("env_traits");
 +        self.autoderef_(db)
 +            .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_)))
 +            .flat_map(|ty| {
 +                self.env
 +                    .traits_in_scope_from_clauses(ty)
 +                    .flat_map(|t| hir_ty::all_super_traits(db.upcast(), t))
 +            })
 +            .map(Trait::from)
 +    }
 +
 +    pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<impl Iterator<Item = Trait>> {
 +        self.ty.impl_trait_bounds(db).map(|it| {
 +            it.into_iter().filter_map(|pred| match pred.skip_binders() {
 +                hir_ty::WhereClause::Implemented(trait_ref) => {
 +                    Some(Trait::from(trait_ref.hir_trait_id()))
 +                }
 +                _ => None,
 +            })
 +        })
 +    }
 +
 +    pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> {
 +        self.ty.associated_type_parent_trait(db).map(Into::into)
 +    }
 +
 +    fn derived(&self, ty: Ty) -> Type {
 +        Type { env: self.env.clone(), ty }
 +    }
 +
 +    pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) {
 +        // TypeWalk::walk for a Ty at first visits parameters and only after that the Ty itself.
 +        // We need a different order here.
 +
 +        fn walk_substs(
 +            db: &dyn HirDatabase,
 +            type_: &Type,
 +            substs: &Substitution,
 +            cb: &mut impl FnMut(Type),
 +        ) {
 +            for ty in substs.iter(Interner).filter_map(|a| a.ty(Interner)) {
 +                walk_type(db, &type_.derived(ty.clone()), cb);
 +            }
 +        }
 +
 +        fn walk_bounds(
 +            db: &dyn HirDatabase,
 +            type_: &Type,
 +            bounds: &[QuantifiedWhereClause],
 +            cb: &mut impl FnMut(Type),
 +        ) {
 +            for pred in bounds {
 +                if let WhereClause::Implemented(trait_ref) = pred.skip_binders() {
 +                    cb(type_.clone());
 +                    // skip the self type. it's likely the type we just got the bounds from
 +                    for ty in
 +                        trait_ref.substitution.iter(Interner).skip(1).filter_map(|a| a.ty(Interner))
 +                    {
 +                        walk_type(db, &type_.derived(ty.clone()), cb);
 +                    }
 +                }
 +            }
 +        }
 +
 +        fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
 +            let ty = type_.ty.strip_references();
 +            match ty.kind(Interner) {
 +                TyKind::Adt(_, substs) => {
 +                    cb(type_.derived(ty.clone()));
 +                    walk_substs(db, type_, substs, cb);
 +                }
 +                TyKind::AssociatedType(_, substs) => {
 +                    if ty.associated_type_parent_trait(db).is_some() {
 +                        cb(type_.derived(ty.clone()));
 +                    }
 +                    walk_substs(db, type_, substs, cb);
 +                }
 +                TyKind::OpaqueType(_, subst) => {
 +                    if let Some(bounds) = ty.impl_trait_bounds(db) {
 +                        walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
 +                    }
 +
 +                    walk_substs(db, type_, subst, cb);
 +                }
 +                TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
 +                    if let Some(bounds) = ty.impl_trait_bounds(db) {
 +                        walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
 +                    }
 +
 +                    walk_substs(db, type_, &opaque_ty.substitution, cb);
 +                }
 +                TyKind::Placeholder(_) => {
 +                    if let Some(bounds) = ty.impl_trait_bounds(db) {
 +                        walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
 +                    }
 +                }
 +                TyKind::Dyn(bounds) => {
 +                    walk_bounds(
 +                        db,
 +                        &type_.derived(ty.clone()),
 +                        bounds.bounds.skip_binders().interned(),
 +                        cb,
 +                    );
 +                }
 +
 +                TyKind::Ref(_, _, ty)
 +                | TyKind::Raw(_, ty)
 +                | TyKind::Array(ty, _)
 +                | TyKind::Slice(ty) => {
 +                    walk_type(db, &type_.derived(ty.clone()), cb);
 +                }
 +
 +                TyKind::FnDef(_, substs)
 +                | TyKind::Tuple(_, substs)
 +                | TyKind::Closure(.., substs) => {
 +                    walk_substs(db, type_, substs, cb);
 +                }
 +                TyKind::Function(hir_ty::FnPointer { substitution, .. }) => {
 +                    walk_substs(db, type_, &substitution.0, cb);
 +                }
 +
 +                _ => {}
 +            }
 +        }
 +
 +        walk_type(db, self, &mut cb);
 +    }
 +
 +    pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
 +        let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
 +        hir_ty::could_unify(db, self.env.clone(), &tys)
 +    }
 +
 +    pub fn could_coerce_to(&self, db: &dyn HirDatabase, to: &Type) -> bool {
 +        let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), to.ty.clone()));
 +        hir_ty::could_coerce(db, self.env.clone(), &tys)
 +    }
 +
 +    pub fn as_type_param(&self, db: &dyn HirDatabase) -> Option<TypeParam> {
 +        match self.ty.kind(Interner) {
 +            TyKind::Placeholder(p) => Some(TypeParam {
 +                id: TypeParamId::from_unchecked(hir_ty::from_placeholder_idx(db, *p)),
 +            }),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub struct Callable {
 +    ty: Type,
 +    sig: CallableSig,
 +    callee: Callee,
 +    pub(crate) is_bound_method: bool,
 +}
 +
 +#[derive(Debug)]
 +enum Callee {
 +    Def(CallableDefId),
 +    Closure(ClosureId),
 +    FnPtr,
 +}
 +
 +pub enum CallableKind {
 +    Function(Function),
 +    TupleStruct(Struct),
 +    TupleEnumVariant(Variant),
 +    Closure,
 +    FnPtr,
 +}
 +
 +impl Callable {
 +    pub fn kind(&self) -> CallableKind {
 +        use Callee::*;
 +        match self.callee {
 +            Def(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()),
 +            Def(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()),
 +            Def(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()),
 +            Closure(_) => CallableKind::Closure,
 +            FnPtr => CallableKind::FnPtr,
 +        }
 +    }
 +    pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> {
 +        let func = match self.callee {
 +            Callee::Def(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
 +            _ => return None,
 +        };
 +        let src = func.lookup(db.upcast()).source(db.upcast());
 +        let param_list = src.value.param_list()?;
 +        param_list.self_param()
 +    }
 +    pub fn n_params(&self) -> usize {
 +        self.sig.params().len() - if self.is_bound_method { 1 } else { 0 }
 +    }
 +    pub fn params(
 +        &self,
 +        db: &dyn HirDatabase,
 +    ) -> Vec<(Option<Either<ast::SelfParam, ast::Pat>>, Type)> {
 +        let types = self
 +            .sig
 +            .params()
 +            .iter()
 +            .skip(if self.is_bound_method { 1 } else { 0 })
 +            .map(|ty| self.ty.derived(ty.clone()));
 +        let map_param = |it: ast::Param| it.pat().map(Either::Right);
 +        let patterns = match self.callee {
 +            Callee::Def(CallableDefId::FunctionId(func)) => {
 +                let src = func.lookup(db.upcast()).source(db.upcast());
 +                src.value.param_list().map(|param_list| {
 +                    param_list
 +                        .self_param()
 +                        .map(|it| Some(Either::Left(it)))
 +                        .filter(|_| !self.is_bound_method)
 +                        .into_iter()
 +                        .chain(param_list.params().map(map_param))
 +                })
 +            }
 +            Callee::Closure(closure_id) => match closure_source(db, closure_id) {
 +                Some(src) => src.param_list().map(|param_list| {
 +                    param_list
 +                        .self_param()
 +                        .map(|it| Some(Either::Left(it)))
 +                        .filter(|_| !self.is_bound_method)
 +                        .into_iter()
 +                        .chain(param_list.params().map(map_param))
 +                }),
 +                None => None,
 +            },
 +            _ => None,
 +        };
 +        patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect()
 +    }
 +    pub fn return_type(&self) -> Type {
 +        self.ty.derived(self.sig.ret().clone())
 +    }
 +}
 +
 +fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option<ast::ClosureExpr> {
 +    let (owner, expr_id) = db.lookup_intern_closure(closure.into());
 +    let (_, source_map) = db.body_with_source_map(owner);
 +    let ast = source_map.expr_syntax(expr_id).ok()?;
 +    let root = ast.file_syntax(db.upcast());
 +    let expr = ast.value.to_node(&root);
 +    match expr {
 +        ast::Expr::ClosureExpr(it) => Some(it),
 +        _ => None,
 +    }
 +}
 +
 +#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 +pub enum BindingMode {
 +    Move,
 +    Ref(Mutability),
 +}
 +
 +/// For IDE only
 +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 +pub enum ScopeDef {
 +    ModuleDef(ModuleDef),
 +    GenericParam(GenericParam),
 +    ImplSelfType(Impl),
 +    AdtSelfType(Adt),
 +    Local(Local),
 +    Label(Label),
 +    Unknown,
 +}
 +
 +impl ScopeDef {
 +    pub fn all_items(def: PerNs) -> ArrayVec<Self, 3> {
 +        let mut items = ArrayVec::new();
 +
 +        match (def.take_types(), def.take_values()) {
 +            (Some(m1), None) => items.push(ScopeDef::ModuleDef(m1.into())),
 +            (None, Some(m2)) => items.push(ScopeDef::ModuleDef(m2.into())),
 +            (Some(m1), Some(m2)) => {
 +                // Some items, like unit structs and enum variants, are
 +                // returned as both a type and a value. Here we want
 +                // to de-duplicate them.
 +                if m1 != m2 {
 +                    items.push(ScopeDef::ModuleDef(m1.into()));
 +                    items.push(ScopeDef::ModuleDef(m2.into()));
 +                } else {
 +                    items.push(ScopeDef::ModuleDef(m1.into()));
 +                }
 +            }
 +            (None, None) => {}
 +        };
 +
 +        if let Some(macro_def_id) = def.take_macros() {
 +            items.push(ScopeDef::ModuleDef(ModuleDef::Macro(macro_def_id.into())));
 +        }
 +
 +        if items.is_empty() {
 +            items.push(ScopeDef::Unknown);
 +        }
 +
 +        items
 +    }
 +
 +    pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
 +        match self {
 +            ScopeDef::ModuleDef(it) => it.attrs(db),
 +            ScopeDef::GenericParam(it) => Some(it.attrs(db)),
 +            ScopeDef::ImplSelfType(_)
 +            | ScopeDef::AdtSelfType(_)
 +            | ScopeDef::Local(_)
 +            | ScopeDef::Label(_)
 +            | ScopeDef::Unknown => None,
 +        }
 +    }
 +
 +    pub fn krate(&self, db: &dyn HirDatabase) -> Option<Crate> {
 +        match self {
 +            ScopeDef::ModuleDef(it) => it.module(db).map(|m| m.krate()),
 +            ScopeDef::GenericParam(it) => Some(it.module(db).krate()),
 +            ScopeDef::ImplSelfType(_) => None,
 +            ScopeDef::AdtSelfType(it) => Some(it.module(db).krate()),
 +            ScopeDef::Local(it) => Some(it.module(db).krate()),
 +            ScopeDef::Label(it) => Some(it.module(db).krate()),
 +            ScopeDef::Unknown => None,
 +        }
 +    }
 +}
 +
 +impl From<ItemInNs> for ScopeDef {
 +    fn from(item: ItemInNs) -> Self {
 +        match item {
 +            ItemInNs::Types(id) => ScopeDef::ModuleDef(id),
 +            ItemInNs::Values(id) => ScopeDef::ModuleDef(id),
 +            ItemInNs::Macros(id) => ScopeDef::ModuleDef(ModuleDef::Macro(id)),
 +        }
 +    }
 +}
 +
 +pub trait HasVisibility {
 +    fn visibility(&self, db: &dyn HirDatabase) -> Visibility;
 +    fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool {
 +        let vis = self.visibility(db);
 +        vis.is_visible_from(db.upcast(), module.id)
 +    }
 +}
 +
 +/// Trait for obtaining the defining crate of an item.
 +pub trait HasCrate {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate;
 +}
 +
 +impl<T: hir_def::HasModule> HasCrate for T {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db.upcast()).krate().into()
 +    }
 +}
 +
 +impl HasCrate for AssocItem {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Struct {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Union {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Field {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.parent_def(db).module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Variant {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Function {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Const {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for TypeAlias {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Type {
 +    fn krate(&self, _db: &dyn HirDatabase) -> Crate {
 +        self.env.krate.into()
 +    }
 +}
 +
 +impl HasCrate for Macro {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Trait {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Static {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Adt {
 +    fn krate(&self, db: &dyn HirDatabase) -> Crate {
 +        self.module(db).krate()
 +    }
 +}
 +
 +impl HasCrate for Module {
 +    fn krate(&self, _: &dyn HirDatabase) -> Crate {
 +        Module::krate(*self)
 +    }
 +}
index bd35af06e23eb0ccbbd29146b61ca99394db1bfa,0000000000000000000000000000000000000000..342912b678a1db836de2a77eb92f674fbc7246cd
mode 100644,000000..100644
--- /dev/null
@@@ -1,1048 -1,0 +1,1056 @@@
-         let res = match ast::MacroCall::cast(expanded.clone()) {
-             Some(call) => self.expand_expr(db, InFile::new(macro_file, call))?,
-             _ => InFile::new(macro_file, ast::Expr::cast(expanded)?),
 +//! Lookup hir elements using positions in the source code. This is a lossy
 +//! transformation: in general, a single source might correspond to several
 +//! modules, functions, etc, due to macros, cfgs and `#[path=]` attributes on
 +//! modules.
 +//!
 +//! So, this modules should not be used during hir construction, it exists
 +//! purely for "IDE needs".
 +use std::{
 +    iter::{self, once},
 +    sync::Arc,
 +};
 +
 +use hir_def::{
 +    body::{
 +        self,
 +        scope::{ExprScopes, ScopeId},
 +        Body, BodySourceMap,
 +    },
 +    expr::{ExprId, Pat, PatId},
 +    macro_id_to_def_id,
 +    path::{ModPath, Path, PathKind},
 +    resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
 +    type_ref::Mutability,
 +    AsMacroCall, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, LocalFieldId,
 +    Lookup, ModuleDefId, VariantId,
 +};
 +use hir_expand::{
 +    builtin_fn_macro::BuiltinFnLikeExpander,
 +    hygiene::Hygiene,
 +    mod_path::path,
 +    name,
 +    name::{AsName, Name},
 +    HirFileId, InFile,
 +};
 +use hir_ty::{
 +    diagnostics::{
 +        record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
 +        UnsafeExpr,
 +    },
 +    method_resolution::{self, lang_names_for_bin_op},
 +    Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind,
 +    TyLoweringContext,
 +};
 +use itertools::Itertools;
 +use smallvec::SmallVec;
 +use syntax::{
 +    ast::{self, AstNode},
 +    SyntaxKind, SyntaxNode, TextRange, TextSize,
 +};
 +
 +use crate::{
 +    db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
 +    BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static,
 +    Struct, ToolModule, Trait, Type, TypeAlias, Variant,
 +};
 +
 +/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
 +/// original source files. It should not be used inside the HIR itself.
 +#[derive(Debug)]
 +pub(crate) struct SourceAnalyzer {
 +    pub(crate) file_id: HirFileId,
 +    pub(crate) resolver: Resolver,
 +    def: Option<(DefWithBodyId, Arc<Body>, Arc<BodySourceMap>)>,
 +    infer: Option<Arc<InferenceResult>>,
 +}
 +
 +impl SourceAnalyzer {
 +    pub(crate) fn new_for_body(
 +        db: &dyn HirDatabase,
 +        def: DefWithBodyId,
 +        node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
 +        offset: Option<TextSize>,
 +    ) -> SourceAnalyzer {
 +        let (body, source_map) = db.body_with_source_map(def);
 +        let scopes = db.expr_scopes(def);
 +        let scope = match offset {
 +            None => scope_for(&scopes, &source_map, node),
 +            Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
 +        };
 +        let resolver = resolver_for_scope(db.upcast(), def, scope);
 +        SourceAnalyzer {
 +            resolver,
 +            def: Some((def, body, source_map)),
 +            infer: Some(db.infer(def)),
 +            file_id,
 +        }
 +    }
 +
 +    pub(crate) fn new_for_body_no_infer(
 +        db: &dyn HirDatabase,
 +        def: DefWithBodyId,
 +        node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
 +        offset: Option<TextSize>,
 +    ) -> SourceAnalyzer {
 +        let (body, source_map) = db.body_with_source_map(def);
 +        let scopes = db.expr_scopes(def);
 +        let scope = match offset {
 +            None => scope_for(&scopes, &source_map, node),
 +            Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
 +        };
 +        let resolver = resolver_for_scope(db.upcast(), def, scope);
 +        SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer: None, file_id }
 +    }
 +
 +    pub(crate) fn new_for_resolver(
 +        resolver: Resolver,
 +        node: InFile<&SyntaxNode>,
 +    ) -> SourceAnalyzer {
 +        SourceAnalyzer { resolver, def: None, infer: None, file_id: node.file_id }
 +    }
 +
 +    fn body_source_map(&self) -> Option<&BodySourceMap> {
 +        self.def.as_ref().map(|(.., source_map)| &**source_map)
 +    }
 +    fn body(&self) -> Option<&Body> {
 +        self.def.as_ref().map(|(_, body, _)| &**body)
 +    }
 +
 +    fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
 +        let src = match expr {
 +            ast::Expr::MacroExpr(expr) => {
 +                self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?.clone()))?
 +            }
 +            _ => InFile::new(self.file_id, expr.clone()),
 +        };
 +        let sm = self.body_source_map()?;
 +        sm.node_expr(src.as_ref())
 +    }
 +
 +    fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
 +        // FIXME: macros, see `expr_id`
 +        let src = InFile { file_id: self.file_id, value: pat };
 +        self.body_source_map()?.node_pat(src)
 +    }
 +
 +    fn expand_expr(
 +        &self,
 +        db: &dyn HirDatabase,
 +        expr: InFile<ast::MacroCall>,
 +    ) -> Option<InFile<ast::Expr>> {
 +        let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?;
 +        let expanded = db.parse_or_expand(macro_file)?;
++        let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) {
++            match stmts.expr()? {
++                ast::Expr::MacroExpr(mac) => {
++                    self.expand_expr(db, InFile::new(macro_file, mac.macro_call()?))?
++                }
++                expr => InFile::new(macro_file, expr),
++            }
++        } else if let Some(call) = ast::MacroCall::cast(expanded.clone()) {
++            self.expand_expr(db, InFile::new(macro_file, call))?
++        } else {
++            InFile::new(macro_file, ast::Expr::cast(expanded)?)
 +        };
++
 +        Some(res)
 +    }
 +
 +    pub(crate) fn is_implicit_reborrow(
 +        &self,
 +        db: &dyn HirDatabase,
 +        expr: &ast::Expr,
 +    ) -> Option<Mutability> {
 +        let expr_id = self.expr_id(db, expr)?;
 +        let infer = self.infer.as_ref()?;
 +        let adjustments = infer.expr_adjustments.get(&expr_id)?;
 +        adjustments.windows(2).find_map(|slice| match slice {
 +            &[Adjustment {kind: Adjust::Deref(None), ..}, Adjustment {kind: Adjust::Borrow(AutoBorrow::Ref(m)), ..}] => Some(match m {
 +                hir_ty::Mutability::Mut => Mutability::Mut,
 +                hir_ty::Mutability::Not => Mutability::Shared,
 +            }),
 +            _ => None,
 +        })
 +    }
 +
 +    pub(crate) fn type_of_expr(
 +        &self,
 +        db: &dyn HirDatabase,
 +        expr: &ast::Expr,
 +    ) -> Option<(Type, Option<Type>)> {
 +        let expr_id = self.expr_id(db, expr)?;
 +        let infer = self.infer.as_ref()?;
 +        let coerced = infer
 +            .expr_adjustments
 +            .get(&expr_id)
 +            .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
 +        let ty = infer[expr_id].clone();
 +        let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
 +        Some((mk_ty(ty), coerced.map(mk_ty)))
 +    }
 +
 +    pub(crate) fn type_of_pat(
 +        &self,
 +        db: &dyn HirDatabase,
 +        pat: &ast::Pat,
 +    ) -> Option<(Type, Option<Type>)> {
 +        let pat_id = self.pat_id(pat)?;
 +        let infer = self.infer.as_ref()?;
 +        let coerced = infer
 +            .pat_adjustments
 +            .get(&pat_id)
 +            .and_then(|adjusts| adjusts.last().map(|adjust| adjust.clone()));
 +        let ty = infer[pat_id].clone();
 +        let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
 +        Some((mk_ty(ty), coerced.map(mk_ty)))
 +    }
 +
 +    pub(crate) fn type_of_self(
 +        &self,
 +        db: &dyn HirDatabase,
 +        param: &ast::SelfParam,
 +    ) -> Option<Type> {
 +        let src = InFile { file_id: self.file_id, value: param };
 +        let pat_id = self.body_source_map()?.node_self_param(src)?;
 +        let ty = self.infer.as_ref()?[pat_id].clone();
 +        Some(Type::new_with_resolver(db, &self.resolver, ty))
 +    }
 +
 +    pub(crate) fn binding_mode_of_pat(
 +        &self,
 +        _db: &dyn HirDatabase,
 +        pat: &ast::IdentPat,
 +    ) -> Option<BindingMode> {
 +        let pat_id = self.pat_id(&pat.clone().into())?;
 +        let infer = self.infer.as_ref()?;
 +        infer.pat_binding_modes.get(&pat_id).map(|bm| match bm {
 +            hir_ty::BindingMode::Move => BindingMode::Move,
 +            hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut),
 +            hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => {
 +                BindingMode::Ref(Mutability::Shared)
 +            }
 +        })
 +    }
 +    pub(crate) fn pattern_adjustments(
 +        &self,
 +        db: &dyn HirDatabase,
 +        pat: &ast::Pat,
 +    ) -> Option<SmallVec<[Type; 1]>> {
 +        let pat_id = self.pat_id(&pat)?;
 +        let infer = self.infer.as_ref()?;
 +        Some(
 +            infer
 +                .pat_adjustments
 +                .get(&pat_id)?
 +                .iter()
 +                .map(|ty| Type::new_with_resolver(db, &self.resolver, ty.clone()))
 +                .collect(),
 +        )
 +    }
 +
 +    pub(crate) fn resolve_method_call_as_callable(
 +        &self,
 +        db: &dyn HirDatabase,
 +        call: &ast::MethodCallExpr,
 +    ) -> Option<Callable> {
 +        let expr_id = self.expr_id(db, &call.clone().into())?;
 +        let (func, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
 +        let ty = db.value_ty(func.into()).substitute(Interner, &substs);
 +        let ty = Type::new_with_resolver(db, &self.resolver, ty);
 +        let mut res = ty.as_callable(db)?;
 +        res.is_bound_method = true;
 +        Some(res)
 +    }
 +
 +    pub(crate) fn resolve_method_call(
 +        &self,
 +        db: &dyn HirDatabase,
 +        call: &ast::MethodCallExpr,
 +    ) -> Option<FunctionId> {
 +        let expr_id = self.expr_id(db, &call.clone().into())?;
 +        let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
 +
 +        Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, &substs))
 +    }
 +
 +    pub(crate) fn resolve_await_to_poll(
 +        &self,
 +        db: &dyn HirDatabase,
 +        await_expr: &ast::AwaitExpr,
 +    ) -> Option<FunctionId> {
 +        let mut ty = self.ty_of_expr(db, &await_expr.expr()?.into())?.clone();
 +
 +        let into_future_trait = self
 +            .resolver
 +            .resolve_known_trait(db.upcast(), &path![core::future::IntoFuture])
 +            .map(Trait::from);
 +
 +        if let Some(into_future_trait) = into_future_trait {
 +            let type_ = Type::new_with_resolver(db, &self.resolver, ty.clone());
 +            if type_.impls_trait(db, into_future_trait, &[]) {
 +                let items = into_future_trait.items(db);
 +                let into_future_type = items.into_iter().find_map(|item| match item {
 +                    AssocItem::TypeAlias(alias)
 +                        if alias.name(db) == hir_expand::name![IntoFuture] =>
 +                    {
 +                        Some(alias)
 +                    }
 +                    _ => None,
 +                })?;
 +                let future_trait = type_.normalize_trait_assoc_type(db, &[], into_future_type)?;
 +                ty = future_trait.ty;
 +            }
 +        }
 +
 +        let poll_fn = db
 +            .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
 +            .as_function()?;
 +        let substs = hir_ty::TyBuilder::subst_for_def(db, poll_fn).push(ty.clone()).build();
 +        Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs))
 +    }
 +
 +    pub(crate) fn resolve_prefix_expr(
 +        &self,
 +        db: &dyn HirDatabase,
 +        prefix_expr: &ast::PrefixExpr,
 +    ) -> Option<FunctionId> {
 +        let lang_item_name = match prefix_expr.op_kind()? {
 +            ast::UnaryOp::Deref => name![deref],
 +            ast::UnaryOp::Not => name![not],
 +            ast::UnaryOp::Neg => name![neg],
 +        };
 +        let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?;
 +
 +        let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
 +        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
 +
 +        Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
 +    }
 +
 +    pub(crate) fn resolve_index_expr(
 +        &self,
 +        db: &dyn HirDatabase,
 +        index_expr: &ast::IndexExpr,
 +    ) -> Option<FunctionId> {
 +        let base_ty = self.ty_of_expr(db, &index_expr.base()?.into())?;
 +        let index_ty = self.ty_of_expr(db, &index_expr.index()?.into())?;
 +
 +        let lang_item_name = name![index];
 +
 +        let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
 +        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn)
 +            .push(base_ty.clone())
 +            .push(index_ty.clone())
 +            .build();
 +        Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
 +    }
 +
 +    pub(crate) fn resolve_bin_expr(
 +        &self,
 +        db: &dyn HirDatabase,
 +        binop_expr: &ast::BinExpr,
 +    ) -> Option<FunctionId> {
 +        let op = binop_expr.op_kind()?;
 +        let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?;
 +        let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?;
 +
 +        let op_fn = lang_names_for_bin_op(op)
 +            .and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?;
 +        let substs =
 +            hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build();
 +
 +        Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
 +    }
 +
 +    pub(crate) fn resolve_try_expr(
 +        &self,
 +        db: &dyn HirDatabase,
 +        try_expr: &ast::TryExpr,
 +    ) -> Option<FunctionId> {
 +        let ty = self.ty_of_expr(db, &try_expr.expr()?.into())?;
 +
 +        let op_fn =
 +            db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?;
 +        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
 +
 +        Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
 +    }
 +
 +    pub(crate) fn resolve_field(
 +        &self,
 +        db: &dyn HirDatabase,
 +        field: &ast::FieldExpr,
 +    ) -> Option<Field> {
 +        let expr_id = self.expr_id(db, &field.clone().into())?;
 +        self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into())
 +    }
 +
 +    pub(crate) fn resolve_record_field(
 +        &self,
 +        db: &dyn HirDatabase,
 +        field: &ast::RecordExprField,
 +    ) -> Option<(Field, Option<Local>, Type)> {
 +        let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
 +        let expr = ast::Expr::from(record_expr);
 +        let expr_id = self.body_source_map()?.node_expr(InFile::new(self.file_id, &expr))?;
 +
 +        let local_name = field.field_name()?.as_name();
 +        let local = if field.name_ref().is_some() {
 +            None
 +        } else {
 +            // Shorthand syntax, resolve to the local
 +            let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone()));
 +            match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
 +                Some(ValueNs::LocalBinding(pat_id)) => {
 +                    Some(Local { pat_id, parent: self.resolver.body_owner()? })
 +                }
 +                _ => None,
 +            }
 +        };
 +        let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?;
 +        let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?;
 +        let variant_data = variant.variant_data(db.upcast());
 +        let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
 +        let field_ty =
 +            db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst);
 +        Some((field.into(), local, Type::new_with_resolver(db, &self.resolver, field_ty)))
 +    }
 +
 +    pub(crate) fn resolve_record_pat_field(
 +        &self,
 +        db: &dyn HirDatabase,
 +        field: &ast::RecordPatField,
 +    ) -> Option<Field> {
 +        let field_name = field.field_name()?.as_name();
 +        let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
 +        let pat_id = self.pat_id(&record_pat.into())?;
 +        let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id)?;
 +        let variant_data = variant.variant_data(db.upcast());
 +        let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
 +        Some(field.into())
 +    }
 +
 +    pub(crate) fn resolve_macro_call(
 +        &self,
 +        db: &dyn HirDatabase,
 +        macro_call: InFile<&ast::MacroCall>,
 +    ) -> Option<Macro> {
 +        let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id);
 +        let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?;
 +        self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into())
 +    }
 +
 +    pub(crate) fn resolve_bind_pat_to_const(
 +        &self,
 +        db: &dyn HirDatabase,
 +        pat: &ast::IdentPat,
 +    ) -> Option<ModuleDef> {
 +        let pat_id = self.pat_id(&pat.clone().into())?;
 +        let body = self.body()?;
 +        let path = match &body[pat_id] {
 +            Pat::Path(path) => path,
 +            _ => return None,
 +        };
 +        let res = resolve_hir_path(db, &self.resolver, path)?;
 +        match res {
 +            PathResolution::Def(def) => Some(def),
 +            _ => None,
 +        }
 +    }
 +
 +    pub(crate) fn resolve_path(
 +        &self,
 +        db: &dyn HirDatabase,
 +        path: &ast::Path,
 +    ) -> Option<PathResolution> {
 +        let parent = path.syntax().parent();
 +        let parent = || parent.clone();
 +
 +        let mut prefer_value_ns = false;
 +        let resolved = (|| {
 +            if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {
 +                let expr_id = self.expr_id(db, &path_expr.into())?;
 +                let infer = self.infer.as_ref()?;
 +                if let Some(assoc) = infer.assoc_resolutions_for_expr(expr_id) {
 +                    let assoc = match assoc {
 +                        AssocItemId::FunctionId(f_in_trait) => {
 +                            match infer.type_of_expr.get(expr_id) {
 +                                None => assoc,
 +                                Some(func_ty) => {
 +                                    if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) {
 +                                        self.resolve_impl_method(db, f_in_trait, subs)
 +                                            .map(AssocItemId::FunctionId)
 +                                            .unwrap_or(assoc)
 +                                    } else {
 +                                        assoc
 +                                    }
 +                                }
 +                            }
 +                        }
 +
 +                        _ => assoc,
 +                    };
 +
 +                    return Some(PathResolution::Def(AssocItem::from(assoc).into()));
 +                }
 +                if let Some(VariantId::EnumVariantId(variant)) =
 +                    infer.variant_resolution_for_expr(expr_id)
 +                {
 +                    return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
 +                }
 +                prefer_value_ns = true;
 +            } else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) {
 +                let pat_id = self.pat_id(&path_pat.into())?;
 +                if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) {
 +                    return Some(PathResolution::Def(AssocItem::from(assoc).into()));
 +                }
 +                if let Some(VariantId::EnumVariantId(variant)) =
 +                    self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
 +                {
 +                    return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
 +                }
 +            } else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) {
 +                let expr_id = self.expr_id(db, &rec_lit.into())?;
 +                if let Some(VariantId::EnumVariantId(variant)) =
 +                    self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
 +                {
 +                    return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
 +                }
 +            } else {
 +                let record_pat = parent().and_then(ast::RecordPat::cast).map(ast::Pat::from);
 +                let tuple_struct_pat =
 +                    || parent().and_then(ast::TupleStructPat::cast).map(ast::Pat::from);
 +                if let Some(pat) = record_pat.or_else(tuple_struct_pat) {
 +                    let pat_id = self.pat_id(&pat)?;
 +                    let variant_res_for_pat =
 +                        self.infer.as_ref()?.variant_resolution_for_pat(pat_id);
 +                    if let Some(VariantId::EnumVariantId(variant)) = variant_res_for_pat {
 +                        return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
 +                    }
 +                }
 +            }
 +            None
 +        })();
 +        if let Some(_) = resolved {
 +            return resolved;
 +        }
 +
 +        // This must be a normal source file rather than macro file.
 +        let hygiene = Hygiene::new(db.upcast(), self.file_id);
 +        let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene);
 +        let hir_path = Path::from_src(path.clone(), &ctx)?;
 +
 +        // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
 +        // trying to resolve foo::bar.
 +        if let Some(use_tree) = parent().and_then(ast::UseTree::cast) {
 +            if use_tree.coloncolon_token().is_some() {
 +                return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
 +            }
 +        }
 +
 +        let meta_path = path
 +            .syntax()
 +            .ancestors()
 +            .take_while(|it| {
 +                let kind = it.kind();
 +                ast::Path::can_cast(kind) || ast::Meta::can_cast(kind)
 +            })
 +            .last()
 +            .and_then(ast::Meta::cast);
 +
 +        // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
 +        // trying to resolve foo::bar.
 +        if path.parent_path().is_some() {
 +            return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path) {
 +                None if meta_path.is_some() => {
 +                    path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
 +                        ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
 +                            .map(PathResolution::ToolModule)
 +                    })
 +                }
 +                res => res,
 +            };
 +        } else if let Some(meta_path) = meta_path {
 +            // Case where we are resolving the final path segment of a path in an attribute
 +            // in this case we have to check for inert/builtin attributes and tools and prioritize
 +            // resolution of attributes over other namespaces
 +            if let Some(name_ref) = path.as_single_name_ref() {
 +                let builtin =
 +                    BuiltinAttr::by_name(db, self.resolver.krate().into(), &name_ref.text());
 +                if let Some(_) = builtin {
 +                    return builtin.map(PathResolution::BuiltinAttr);
 +                }
 +
 +                if let Some(attr) = meta_path.parent_attr() {
 +                    let adt = if let Some(field) =
 +                        attr.syntax().parent().and_then(ast::RecordField::cast)
 +                    {
 +                        field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
 +                    } else if let Some(field) =
 +                        attr.syntax().parent().and_then(ast::TupleField::cast)
 +                    {
 +                        field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
 +                    } else if let Some(variant) =
 +                        attr.syntax().parent().and_then(ast::Variant::cast)
 +                    {
 +                        variant.syntax().ancestors().nth(2).and_then(ast::Adt::cast)
 +                    } else {
 +                        None
 +                    };
 +                    if let Some(adt) = adt {
 +                        let ast_id = db.ast_id_map(self.file_id).ast_id(&adt);
 +                        if let Some(helpers) = self
 +                            .resolver
 +                            .def_map()
 +                            .derive_helpers_in_scope(InFile::new(self.file_id, ast_id))
 +                        {
 +                            // FIXME: Multiple derives can have the same helper
 +                            let name_ref = name_ref.as_name();
 +                            for (macro_id, mut helpers) in
 +                                helpers.iter().group_by(|(_, macro_id, ..)| macro_id).into_iter()
 +                            {
 +                                if let Some(idx) = helpers.position(|(name, ..)| *name == name_ref)
 +                                {
 +                                    return Some(PathResolution::DeriveHelper(DeriveHelper {
 +                                        derive: *macro_id,
 +                                        idx,
 +                                    }));
 +                                }
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +            return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) {
 +                Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))),
 +                // this labels any path that starts with a tool module as the tool itself, this is technically wrong
 +                // but there is no benefit in differentiating these two cases for the time being
 +                None => path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
 +                    ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
 +                        .map(PathResolution::ToolModule)
 +                }),
 +            };
 +        }
 +        if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) {
 +            resolve_hir_path_qualifier(db, &self.resolver, &hir_path)
 +        } else {
 +            resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns)
 +        }
 +    }
 +
 +    pub(crate) fn record_literal_missing_fields(
 +        &self,
 +        db: &dyn HirDatabase,
 +        literal: &ast::RecordExpr,
 +    ) -> Option<Vec<(Field, Type)>> {
 +        let body = self.body()?;
 +        let infer = self.infer.as_ref()?;
 +
 +        let expr_id = self.expr_id(db, &literal.clone().into())?;
 +        let substs = infer.type_of_expr[expr_id].as_adt()?.1;
 +
 +        let (variant, missing_fields, _exhaustive) =
 +            record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;
 +        let res = self.missing_fields(db, substs, variant, missing_fields);
 +        Some(res)
 +    }
 +
 +    pub(crate) fn record_pattern_missing_fields(
 +        &self,
 +        db: &dyn HirDatabase,
 +        pattern: &ast::RecordPat,
 +    ) -> Option<Vec<(Field, Type)>> {
 +        let body = self.body()?;
 +        let infer = self.infer.as_ref()?;
 +
 +        let pat_id = self.pat_id(&pattern.clone().into())?;
 +        let substs = infer.type_of_pat[pat_id].as_adt()?.1;
 +
 +        let (variant, missing_fields, _exhaustive) =
 +            record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?;
 +        let res = self.missing_fields(db, substs, variant, missing_fields);
 +        Some(res)
 +    }
 +
 +    fn missing_fields(
 +        &self,
 +        db: &dyn HirDatabase,
 +        substs: &Substitution,
 +        variant: VariantId,
 +        missing_fields: Vec<LocalFieldId>,
 +    ) -> Vec<(Field, Type)> {
 +        let field_types = db.field_types(variant);
 +
 +        missing_fields
 +            .into_iter()
 +            .map(|local_id| {
 +                let field = FieldId { parent: variant, local_id };
 +                let ty = field_types[local_id].clone().substitute(Interner, substs);
 +                (field.into(), Type::new_with_resolver_inner(db, &self.resolver, ty))
 +            })
 +            .collect()
 +    }
 +
 +    pub(crate) fn expand(
 +        &self,
 +        db: &dyn HirDatabase,
 +        macro_call: InFile<&ast::MacroCall>,
 +    ) -> Option<HirFileId> {
 +        let krate = self.resolver.krate();
 +        let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
 +            self.resolver
 +                .resolve_path_as_macro(db.upcast(), &path)
 +                .map(|it| macro_id_to_def_id(db.upcast(), it))
 +        })?;
 +        Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64)
 +    }
 +
 +    pub(crate) fn resolve_variant(
 +        &self,
 +        db: &dyn HirDatabase,
 +        record_lit: ast::RecordExpr,
 +    ) -> Option<VariantId> {
 +        let infer = self.infer.as_ref()?;
 +        let expr_id = self.expr_id(db, &record_lit.into())?;
 +        infer.variant_resolution_for_expr(expr_id)
 +    }
 +
 +    pub(crate) fn is_unsafe_macro_call(
 +        &self,
 +        db: &dyn HirDatabase,
 +        macro_call: InFile<&ast::MacroCall>,
 +    ) -> bool {
 +        // check for asm/global_asm
 +        if let Some(mac) = self.resolve_macro_call(db, macro_call) {
 +            let ex = match mac.id {
 +                hir_def::MacroId::Macro2Id(it) => it.lookup(db.upcast()).expander,
 +                hir_def::MacroId::MacroRulesId(it) => it.lookup(db.upcast()).expander,
 +                _ => hir_def::MacroExpander::Declarative,
 +            };
 +            match ex {
 +                hir_def::MacroExpander::BuiltIn(e)
 +                    if e == BuiltinFnLikeExpander::Asm || e == BuiltinFnLikeExpander::GlobalAsm =>
 +                {
 +                    return true
 +                }
 +                _ => (),
 +            }
 +        }
 +        let macro_expr = match macro_call
 +            .map(|it| it.syntax().parent().and_then(ast::MacroExpr::cast))
 +            .transpose()
 +        {
 +            Some(it) => it,
 +            None => return false,
 +        };
 +
 +        if let (Some((def, body, sm)), Some(infer)) = (&self.def, &self.infer) {
 +            if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr.as_ref()) {
 +                let mut is_unsafe = false;
 +                unsafe_expressions(
 +                    db,
 +                    infer,
 +                    *def,
 +                    body,
 +                    expanded_expr,
 +                    &mut |UnsafeExpr { inside_unsafe_block, .. }| is_unsafe |= !inside_unsafe_block,
 +                );
 +                return is_unsafe;
 +            }
 +        }
 +        false
 +    }
 +
 +    fn resolve_impl_method(
 +        &self,
 +        db: &dyn HirDatabase,
 +        func: FunctionId,
 +        substs: &Substitution,
 +    ) -> Option<FunctionId> {
 +        let impled_trait = match func.lookup(db.upcast()).container {
 +            ItemContainerId::TraitId(trait_id) => trait_id,
 +            _ => return None,
 +        };
 +        if substs.is_empty(Interner) {
 +            return None;
 +        }
 +        let self_ty = substs.at(Interner, 0).ty(Interner)?;
 +        let krate = self.resolver.krate();
 +        let trait_env = self.resolver.body_owner()?.as_generic_def_id().map_or_else(
 +            || Arc::new(hir_ty::TraitEnvironment::empty(krate)),
 +            |d| db.trait_environment(d),
 +        );
 +
 +        let fun_data = db.function_data(func);
 +        method_resolution::lookup_impl_method(self_ty, db, trait_env, impled_trait, &fun_data.name)
 +    }
 +
 +    fn resolve_impl_method_or_trait_def(
 +        &self,
 +        db: &dyn HirDatabase,
 +        func: FunctionId,
 +        substs: &Substitution,
 +    ) -> FunctionId {
 +        self.resolve_impl_method(db, func, substs).unwrap_or(func)
 +    }
 +
 +    fn lang_trait_fn(
 +        &self,
 +        db: &dyn HirDatabase,
 +        lang_trait: &Name,
 +        method_name: &Name,
 +    ) -> Option<FunctionId> {
 +        db.trait_data(db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?)
 +            .method_by_name(method_name)
 +    }
 +
 +    fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
 +        self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, &expr)?)
 +    }
 +}
 +
 +fn scope_for(
 +    scopes: &ExprScopes,
 +    source_map: &BodySourceMap,
 +    node: InFile<&SyntaxNode>,
 +) -> Option<ScopeId> {
 +    node.value
 +        .ancestors()
 +        .filter_map(ast::Expr::cast)
 +        .filter_map(|it| source_map.node_expr(InFile::new(node.file_id, &it)))
 +        .find_map(|it| scopes.scope_for(it))
 +}
 +
 +fn scope_for_offset(
 +    db: &dyn HirDatabase,
 +    scopes: &ExprScopes,
 +    source_map: &BodySourceMap,
 +    from_file: HirFileId,
 +    offset: TextSize,
 +) -> Option<ScopeId> {
 +    scopes
 +        .scope_by_expr()
 +        .iter()
 +        .filter_map(|(id, scope)| {
 +            let InFile { file_id, value } = source_map.expr_syntax(*id).ok()?;
 +            if from_file == file_id {
 +                return Some((value.text_range(), scope));
 +            }
 +
 +            // FIXME handle attribute expansion
 +            let source = iter::successors(file_id.call_node(db.upcast()), |it| {
 +                it.file_id.call_node(db.upcast())
 +            })
 +            .find(|it| it.file_id == from_file)
 +            .filter(|it| it.value.kind() == SyntaxKind::MACRO_CALL)?;
 +            Some((source.value.text_range(), scope))
 +        })
 +        .filter(|(expr_range, _scope)| expr_range.start() <= offset && offset <= expr_range.end())
 +        // find containing scope
 +        .min_by_key(|(expr_range, _scope)| expr_range.len())
 +        .map(|(expr_range, scope)| {
 +            adjust(db, scopes, source_map, expr_range, from_file, offset).unwrap_or(*scope)
 +        })
 +}
 +
 +// XXX: during completion, cursor might be outside of any particular
 +// expression. Try to figure out the correct scope...
 +fn adjust(
 +    db: &dyn HirDatabase,
 +    scopes: &ExprScopes,
 +    source_map: &BodySourceMap,
 +    expr_range: TextRange,
 +    from_file: HirFileId,
 +    offset: TextSize,
 +) -> Option<ScopeId> {
 +    let child_scopes = scopes
 +        .scope_by_expr()
 +        .iter()
 +        .filter_map(|(id, scope)| {
 +            let source = source_map.expr_syntax(*id).ok()?;
 +            // FIXME: correctly handle macro expansion
 +            if source.file_id != from_file {
 +                return None;
 +            }
 +            let root = source.file_syntax(db.upcast());
 +            let node = source.value.to_node(&root);
 +            Some((node.syntax().text_range(), scope))
 +        })
 +        .filter(|&(range, _)| {
 +            range.start() <= offset && expr_range.contains_range(range) && range != expr_range
 +        });
 +
 +    child_scopes
 +        .max_by(|&(r1, _), &(r2, _)| {
 +            if r1.contains_range(r2) {
 +                std::cmp::Ordering::Greater
 +            } else if r2.contains_range(r1) {
 +                std::cmp::Ordering::Less
 +            } else {
 +                r1.start().cmp(&r2.start())
 +            }
 +        })
 +        .map(|(_ptr, scope)| *scope)
 +}
 +
 +#[inline]
 +pub(crate) fn resolve_hir_path(
 +    db: &dyn HirDatabase,
 +    resolver: &Resolver,
 +    path: &Path,
 +) -> Option<PathResolution> {
 +    resolve_hir_path_(db, resolver, path, false)
 +}
 +
 +#[inline]
 +pub(crate) fn resolve_hir_path_as_macro(
 +    db: &dyn HirDatabase,
 +    resolver: &Resolver,
 +    path: &Path,
 +) -> Option<Macro> {
 +    resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(Into::into)
 +}
 +
 +fn resolve_hir_path_(
 +    db: &dyn HirDatabase,
 +    resolver: &Resolver,
 +    path: &Path,
 +    prefer_value_ns: bool,
 +) -> Option<PathResolution> {
 +    let types = || {
 +        let (ty, unresolved) = match path.type_anchor() {
 +            Some(type_ref) => {
 +                let (_, res) = TyLoweringContext::new(db, resolver).lower_ty_ext(type_ref);
 +                res.map(|ty_ns| (ty_ns, path.segments().first()))
 +            }
 +            None => {
 +                let (ty, remaining) =
 +                    resolver.resolve_path_in_type_ns(db.upcast(), path.mod_path())?;
 +                match remaining {
 +                    Some(remaining) if remaining > 1 => {
 +                        if remaining + 1 == path.segments().len() {
 +                            Some((ty, path.segments().last()))
 +                        } else {
 +                            None
 +                        }
 +                    }
 +                    _ => Some((ty, path.segments().get(1))),
 +                }
 +            }
 +        }?;
 +
 +        // If we are in a TypeNs for a Trait, and we have an unresolved name, try to resolve it as a type
 +        // within the trait's associated types.
 +        if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) {
 +            if let Some(type_alias_id) =
 +                db.trait_data(trait_id).associated_type_by_name(unresolved.name)
 +            {
 +                return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));
 +            }
 +        }
 +
 +        let res = match ty {
 +            TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
 +            TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
 +            TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
 +                PathResolution::Def(Adt::from(it).into())
 +            }
 +            TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
 +            TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
 +            TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
 +            TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
 +        };
 +        match unresolved {
 +            Some(unresolved) => resolver
 +                .generic_def()
 +                .and_then(|def| {
 +                    hir_ty::associated_type_shorthand_candidates(
 +                        db,
 +                        def,
 +                        res.in_type_ns()?,
 +                        |name, _, id| (name == unresolved.name).then(|| id),
 +                    )
 +                })
 +                .map(TypeAlias::from)
 +                .map(Into::into)
 +                .map(PathResolution::Def),
 +            None => Some(res),
 +        }
 +    };
 +
 +    let body_owner = resolver.body_owner();
 +    let values = || {
 +        resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| {
 +            let res = match val {
 +                ValueNs::LocalBinding(pat_id) => {
 +                    let var = Local { parent: body_owner?, pat_id };
 +                    PathResolution::Local(var)
 +                }
 +                ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()),
 +                ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()),
 +                ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()),
 +                ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
 +                ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
 +                ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()),
 +                ValueNs::GenericParam(id) => PathResolution::ConstParam(id.into()),
 +            };
 +            Some(res)
 +        })
 +    };
 +
 +    let items = || {
 +        resolver
 +            .resolve_module_path_in_items(db.upcast(), path.mod_path())
 +            .take_types()
 +            .map(|it| PathResolution::Def(it.into()))
 +    };
 +
 +    let macros = || {
 +        resolver
 +            .resolve_path_as_macro(db.upcast(), path.mod_path())
 +            .map(|def| PathResolution::Def(ModuleDef::Macro(def.into())))
 +    };
 +
 +    if prefer_value_ns { values().or_else(types) } else { types().or_else(values) }
 +        .or_else(items)
 +        .or_else(macros)
 +}
 +
 +/// Resolves a path where we know it is a qualifier of another path.
 +///
 +/// For example, if we have:
 +/// ```
 +/// mod my {
 +///     pub mod foo {
 +///         struct Bar;
 +///     }
 +///
 +///     pub fn foo() {}
 +/// }
 +/// ```
 +/// then we know that `foo` in `my::foo::Bar` refers to the module, not the function.
 +fn resolve_hir_path_qualifier(
 +    db: &dyn HirDatabase,
 +    resolver: &Resolver,
 +    path: &Path,
 +) -> Option<PathResolution> {
 +    resolver
 +        .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path())
 +        .map(|ty| match ty {
 +            TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
 +            TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
 +            TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
 +                PathResolution::Def(Adt::from(it).into())
 +            }
 +            TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
 +            TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
 +            TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
 +            TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
 +        })
 +        .or_else(|| {
 +            resolver
 +                .resolve_module_path_in_items(db.upcast(), path.mod_path())
 +                .take_types()
 +                .map(|it| PathResolution::Def(it.into()))
 +        })
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..54a7f480a4e46abd5316a3cc719e8c54ede8a69f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,294 @@@
++use syntax::ast::{self, AstNode};
++
++use crate::{AssistContext, AssistId, AssistKind, Assists};
++
++// Assist: convert_two_arm_bool_match_to_matches_macro
++//
++// Convert 2-arm match that evaluates to a boolean into the equivalent matches! invocation.
++//
++// ```
++// fn main() {
++//     match scrutinee$0 {
++//         Some(val) if val.cond() => true,
++//         _ => false,
++//     }
++// }
++// ```
++// ->
++// ```
++// fn main() {
++//     matches!(scrutinee, Some(val) if val.cond())
++// }
++// ```
++pub(crate) fn convert_two_arm_bool_match_to_matches_macro(
++    acc: &mut Assists,
++    ctx: &AssistContext<'_>,
++) -> Option<()> {
++    let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?;
++    let match_arm_list = match_expr.match_arm_list()?;
++    let mut arms = match_arm_list.arms();
++    let first_arm = arms.next()?;
++    let second_arm = arms.next()?;
++    if arms.next().is_some() {
++        cov_mark::hit!(non_two_arm_match);
++        return None;
++    }
++    let first_arm_expr = first_arm.expr();
++    let second_arm_expr = second_arm.expr();
++
++    let invert_matches = if is_bool_literal_expr(&first_arm_expr, true)
++        && is_bool_literal_expr(&second_arm_expr, false)
++    {
++        false
++    } else if is_bool_literal_expr(&first_arm_expr, false)
++        && is_bool_literal_expr(&second_arm_expr, true)
++    {
++        true
++    } else {
++        cov_mark::hit!(non_invert_bool_literal_arms);
++        return None;
++    };
++
++    let target_range = ctx.sema.original_range(match_expr.syntax()).range;
++    let expr = match_expr.expr()?;
++
++    acc.add(
++        AssistId("convert_two_arm_bool_match_to_matches_macro", AssistKind::RefactorRewrite),
++        "Convert to matches!",
++        target_range,
++        |builder| {
++            let mut arm_str = String::new();
++            if let Some(ref pat) = first_arm.pat() {
++                arm_str += &pat.to_string();
++            }
++            if let Some(ref guard) = first_arm.guard() {
++                arm_str += &format!(" {}", &guard.to_string());
++            }
++            if invert_matches {
++                builder.replace(target_range, format!("!matches!({}, {})", expr, arm_str));
++            } else {
++                builder.replace(target_range, format!("matches!({}, {})", expr, arm_str));
++            }
++        },
++    )
++}
++
++fn is_bool_literal_expr(expr: &Option<ast::Expr>, expect_bool: bool) -> bool {
++    if let Some(ast::Expr::Literal(lit)) = expr {
++        if let ast::LiteralKind::Bool(b) = lit.kind() {
++            return b == expect_bool;
++        }
++    }
++
++    return false;
++}
++
++#[cfg(test)]
++mod tests {
++    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
++
++    use super::convert_two_arm_bool_match_to_matches_macro;
++
++    #[test]
++    fn not_applicable_outside_of_range_left() {
++        check_assist_not_applicable(
++            convert_two_arm_bool_match_to_matches_macro,
++            r#"
++fn foo(a: Option<u32>) -> bool {
++    $0 match a {
++        Some(_val) => true,
++        _ => false
++    }
++}
++        "#,
++        );
++    }
++
++    #[test]
++    fn not_applicable_non_two_arm_match() {
++        cov_mark::check!(non_two_arm_match);
++        check_assist_not_applicable(
++            convert_two_arm_bool_match_to_matches_macro,
++            r#"
++fn foo(a: Option<u32>) -> bool {
++    match a$0 {
++        Some(3) => true,
++        Some(4) => true,
++        _ => false
++    }
++}
++        "#,
++        );
++    }
++
++    #[test]
++    fn not_applicable_non_bool_literal_arms() {
++        cov_mark::check!(non_invert_bool_literal_arms);
++        check_assist_not_applicable(
++            convert_two_arm_bool_match_to_matches_macro,
++            r#"
++fn foo(a: Option<u32>) -> bool {
++    match a$0 {
++        Some(val) => val == 3,
++        _ => false
++    }
++}
++        "#,
++        );
++    }
++    #[test]
++    fn not_applicable_both_false_arms() {
++        cov_mark::check!(non_invert_bool_literal_arms);
++        check_assist_not_applicable(
++            convert_two_arm_bool_match_to_matches_macro,
++            r#"
++fn foo(a: Option<u32>) -> bool {
++    match a$0 {
++        Some(val) => false,
++        _ => false
++    }
++}
++        "#,
++        );
++    }
++
++    #[test]
++    fn not_applicable_both_true_arms() {
++        cov_mark::check!(non_invert_bool_literal_arms);
++        check_assist_not_applicable(
++            convert_two_arm_bool_match_to_matches_macro,
++            r#"
++fn foo(a: Option<u32>) -> bool {
++    match a$0 {
++        Some(val) => true,
++        _ => true
++    }
++}
++        "#,
++        );
++    }
++
++    #[test]
++    fn convert_simple_case() {
++        check_assist(
++            convert_two_arm_bool_match_to_matches_macro,
++            r#"
++fn foo(a: Option<u32>) -> bool {
++    match a$0 {
++        Some(_val) => true,
++        _ => false
++    }
++}
++"#,
++            r#"
++fn foo(a: Option<u32>) -> bool {
++    matches!(a, Some(_val))
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn convert_simple_invert_case() {
++        check_assist(
++            convert_two_arm_bool_match_to_matches_macro,
++            r#"
++fn foo(a: Option<u32>) -> bool {
++    match a$0 {
++        Some(_val) => false,
++        _ => true
++    }
++}
++"#,
++            r#"
++fn foo(a: Option<u32>) -> bool {
++    !matches!(a, Some(_val))
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn convert_with_guard_case() {
++        check_assist(
++            convert_two_arm_bool_match_to_matches_macro,
++            r#"
++fn foo(a: Option<u32>) -> bool {
++    match a$0 {
++        Some(val) if val > 3 => true,
++        _ => false
++    }
++}
++"#,
++            r#"
++fn foo(a: Option<u32>) -> bool {
++    matches!(a, Some(val) if val > 3)
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn convert_enum_match_cases() {
++        check_assist(
++            convert_two_arm_bool_match_to_matches_macro,
++            r#"
++enum X { A, B }
++
++fn foo(a: X) -> bool {
++    match a$0 {
++        X::A => true,
++        _ => false
++    }
++}
++"#,
++            r#"
++enum X { A, B }
++
++fn foo(a: X) -> bool {
++    matches!(a, X::A)
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn convert_target_simple() {
++        check_assist_target(
++            convert_two_arm_bool_match_to_matches_macro,
++            r#"
++fn foo(a: Option<u32>) -> bool {
++    match a$0 {
++        Some(val) => true,
++        _ => false
++    }
++}
++"#,
++            r#"match a {
++        Some(val) => true,
++        _ => false
++    }"#,
++        );
++    }
++
++    #[test]
++    fn convert_target_complex() {
++        check_assist_target(
++            convert_two_arm_bool_match_to_matches_macro,
++            r#"
++enum E { X, Y }
++
++fn main() {
++    match E::X$0 {
++        E::X => true,
++        _ => false,
++    }
++}
++"#,
++            "match E::X {
++        E::X => true,
++        _ => false,
++    }",
++        );
++    }
++}
index dfb5652126467ee974ca77dc60820836d796f6f0,0000000000000000000000000000000000000000..ddc2052e7aa240f92f32c3122423138edea0f4da
mode 100644,000000..100644
--- /dev/null
@@@ -1,1076 -1,0 +1,1097 @@@
-             let indent = enum_ast.indent_level();
 +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,
 +};
 +use itertools::{Itertools, Position};
 +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 start_offset = &variant.parent_enum().syntax().clone();
-             ted::insert_all_raw(
-                 ted::Position::before(start_offset),
 +            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);
 +
-                     make::tokens::whitespace(&format!("\n\n{}", indent)).into(),
++            ted::insert_all(
++                ted::Position::before(enum_ast.syntax()),
 +                vec![
 +                    def.syntax().clone().into(),
-     variant_name: ast::Name,
++                    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()
 +        }
 +    };
-     let strukt = make::struct_(enum_vis, variant_name, generics, field_list).clone_for_update();
-     // FIXME: Consider making this an actual function somewhere (like in `AttrsOwnerEdit`) after some deliberation
-     let attrs_and_docs = |node: &SyntaxNode| {
-         let mut select_next_ws = false;
-         node.children_with_tokens().filter(move |child| {
-             let accept = match child.kind() {
-                 ATTR | COMMENT => {
-                     select_next_ws = true;
-                     return true;
-                 }
-                 WHITESPACE if select_next_ws => true,
-                 _ => false,
-             };
-             select_next_ws = false;
-             accept
-         })
-     };
 +    field_list.reindent_to(IndentLevel::single());
 +
-     // copy attributes & comments from variant
-     let variant_attrs = attrs_and_docs(variant.syntax())
-         .map(|tok| match tok.kind() {
-             WHITESPACE => make::tokens::single_newline().into(),
-             _ => tok,
-         })
-         .collect();
-     ted::insert_all(ted::Position::first_child_of(strukt.syntax()), variant_attrs);
++    let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update();
 +
-         enum_.attrs().map(|it| it.syntax().clone_for_update().into()).collect(),
++    // 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()),
-     let replacement = make::variant(
-         name,
-         Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))),
-     )
-     .clone_for_update();
-     ted::replace(variant.syntax(), replacement.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| {
 +            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))
 +        })
 +        .unwrap_or_else(|| make::ty(&name.text()));
 +
++    // change from a record to a tuple field list
 +    let tuple_field = make::tuple_field(None, ty);
-             r#"#[derive(Debug)]
++    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,
 +                );
 +                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)] struct Variant{ field: u32 }
++            r#"
++#[derive(Debug)]
 +#[derive(Clone)]
 +enum Enum { Variant{ field: u32$0 } }"#,
-     fn test_extract_struct_keep_comments_and_attrs_on_variant_struct() {
++            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]
- #[attr]
++    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
-     fn test_extract_struct_keep_comments_and_attrs_on_variant_tuple() {
 +struct One{
 +    a: u32
 +}
 +
 +enum A {
++    #[attr]
 +    One(One)
 +}"#,
 +        );
 +    }
 +
 +    #[test]
- #[attr]
++    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 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7d91be621013653aca193b1f23fc8a0469eaf376
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,364 @@@
++use ide_db::{
++    assists::{AssistId, AssistKind},
++    famous_defs::FamousDefs,
++};
++use syntax::{
++    ast::{self, make, Expr, HasArgList},
++    AstNode,
++};
++
++use crate::{AssistContext, Assists};
++
++// Assist: replace_or_with_or_else
++//
++// Replace `unwrap_or` with `unwrap_or_else` and `ok_or` with `ok_or_else`.
++//
++// ```
++// # //- minicore:option
++// fn foo() {
++//     let a = Some(1);
++//     a.unwra$0p_or(2);
++// }
++// ```
++// ->
++// ```
++// fn foo() {
++//     let a = Some(1);
++//     a.unwrap_or_else(|| 2);
++// }
++// ```
++pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
++    let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
++
++    let kind = is_option_or_result(call.receiver()?, ctx)?;
++
++    let (name, arg_list) = (call.name_ref()?, call.arg_list()?);
++
++    let mut map_or = false;
++
++    let replace = match &*name.text() {
++        "unwrap_or" => "unwrap_or_else".to_string(),
++        "or" => "or_else".to_string(),
++        "ok_or" if kind == Kind::Option => "ok_or_else".to_string(),
++        "map_or" => {
++            map_or = true;
++            "map_or_else".to_string()
++        }
++        _ => return None,
++    };
++
++    let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
++        [] => make::arg_list(Vec::new()),
++        [first] => {
++            let param = into_closure(first);
++            make::arg_list(vec![param])
++        }
++        [first, second] if map_or => {
++            let param = into_closure(first);
++            make::arg_list(vec![param, second.clone()])
++        }
++        _ => return None,
++    };
++
++    acc.add(
++        AssistId("replace_or_with_or_else", AssistKind::RefactorRewrite),
++        format!("Replace {} with {}", name.text(), replace),
++        call.syntax().text_range(),
++        |builder| {
++            builder.replace(name.syntax().text_range(), replace);
++            builder.replace_ast(arg_list, arg)
++        },
++    )
++}
++
++fn into_closure(param: &Expr) -> Expr {
++    (|| {
++        if let ast::Expr::CallExpr(call) = param {
++            if call.arg_list()?.args().count() == 0 {
++                Some(call.expr()?.clone())
++            } else {
++                None
++            }
++        } else {
++            None
++        }
++    })()
++    .unwrap_or_else(|| make::expr_closure(None, param.clone()))
++}
++
++// Assist: replace_or_else_with_or
++//
++// Replace `unwrap_or_else` with `unwrap_or` and `ok_or_else` with `ok_or`.
++//
++// ```
++// # //- minicore:option
++// fn foo() {
++//     let a = Some(1);
++//     a.unwra$0p_or_else(|| 2);
++// }
++// ```
++// ->
++// ```
++// fn foo() {
++//     let a = Some(1);
++//     a.unwrap_or(2);
++// }
++// ```
++pub(crate) fn replace_or_else_with_or(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
++    let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
++
++    let kind = is_option_or_result(call.receiver()?, ctx)?;
++
++    let (name, arg_list) = (call.name_ref()?, call.arg_list()?);
++
++    let mut map_or = false;
++    let replace = match &*name.text() {
++        "unwrap_or_else" => "unwrap_or".to_string(),
++        "or_else" => "or".to_string(),
++        "ok_or_else" if kind == Kind::Option => "ok_or".to_string(),
++        "map_or_else" => {
++            map_or = true;
++            "map_or".to_string()
++        }
++        _ => return None,
++    };
++
++    let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
++        [] => make::arg_list(Vec::new()),
++        [first] => {
++            let param = into_call(first);
++            make::arg_list(vec![param])
++        }
++        [first, second] if map_or => {
++            let param = into_call(first);
++            make::arg_list(vec![param, second.clone()])
++        }
++        _ => return None,
++    };
++
++    acc.add(
++        AssistId("replace_or_else_with_or", AssistKind::RefactorRewrite),
++        format!("Replace {} with {}", name.text(), replace),
++        call.syntax().text_range(),
++        |builder| {
++            builder.replace(name.syntax().text_range(), replace);
++            builder.replace_ast(arg_list, arg)
++        },
++    )
++}
++
++fn into_call(param: &Expr) -> Expr {
++    (|| {
++        if let ast::Expr::ClosureExpr(closure) = param {
++            if closure.param_list()?.params().count() == 0 {
++                Some(closure.body()?.clone())
++            } else {
++                None
++            }
++        } else {
++            None
++        }
++    })()
++    .unwrap_or_else(|| make::expr_call(param.clone(), make::arg_list(Vec::new())))
++}
++
++#[derive(PartialEq, Eq)]
++enum Kind {
++    Option,
++    Result,
++}
++
++fn is_option_or_result(receiver: Expr, ctx: &AssistContext<'_>) -> Option<Kind> {
++    let ty = ctx.sema.type_of_expr(&receiver)?.adjusted().as_adt()?.as_enum()?;
++    let option_enum =
++        FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_option_Option();
++
++    if let Some(option_enum) = option_enum {
++        if ty == option_enum {
++            return Some(Kind::Option);
++        }
++    }
++
++    let result_enum =
++        FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_result_Result();
++
++    if let Some(result_enum) = result_enum {
++        if ty == result_enum {
++            return Some(Kind::Result);
++        }
++    }
++
++    None
++}
++
++#[cfg(test)]
++mod tests {
++    use crate::tests::{check_assist, check_assist_not_applicable};
++
++    use super::*;
++
++    #[test]
++    fn replace_or_with_or_else_simple() {
++        check_assist(
++            replace_or_with_or_else,
++            r#"
++//- minicore: option
++fn foo() {
++    let foo = Some(1);
++    return foo.unwrap_$0or(2);
++}
++"#,
++            r#"
++fn foo() {
++    let foo = Some(1);
++    return foo.unwrap_or_else(|| 2);
++}
++"#,
++        )
++    }
++
++    #[test]
++    fn replace_or_with_or_else_call() {
++        check_assist(
++            replace_or_with_or_else,
++            r#"
++//- minicore: option
++fn foo() {
++    let foo = Some(1);
++    return foo.unwrap_$0or(x());
++}
++"#,
++            r#"
++fn foo() {
++    let foo = Some(1);
++    return foo.unwrap_or_else(x);
++}
++"#,
++        )
++    }
++
++    #[test]
++    fn replace_or_with_or_else_block() {
++        check_assist(
++            replace_or_with_or_else,
++            r#"
++//- minicore: option
++fn foo() {
++    let foo = Some(1);
++    return foo.unwrap_$0or({
++        let mut x = bar();
++        for i in 0..10 {
++            x += i;
++        }
++        x
++    });
++}
++"#,
++            r#"
++fn foo() {
++    let foo = Some(1);
++    return foo.unwrap_or_else(|| {
++        let mut x = bar();
++        for i in 0..10 {
++            x += i;
++        }
++        x
++    });
++}
++"#,
++        )
++    }
++
++    #[test]
++    fn replace_or_else_with_or_simple() {
++        check_assist(
++            replace_or_else_with_or,
++            r#"
++//- minicore: option
++fn foo() {
++    let foo = Some(1);
++    return foo.unwrap_$0or_else(|| 2);
++}
++"#,
++            r#"
++fn foo() {
++    let foo = Some(1);
++    return foo.unwrap_or(2);
++}
++"#,
++        )
++    }
++
++    #[test]
++    fn replace_or_else_with_or_call() {
++        check_assist(
++            replace_or_else_with_or,
++            r#"
++//- minicore: option
++fn foo() {
++    let foo = Some(1);
++    return foo.unwrap_$0or_else(x);
++}
++"#,
++            r#"
++fn foo() {
++    let foo = Some(1);
++    return foo.unwrap_or(x());
++}
++"#,
++        )
++    }
++
++    #[test]
++    fn replace_or_else_with_or_result() {
++        check_assist(
++            replace_or_else_with_or,
++            r#"
++//- minicore: result
++fn foo() {
++    let foo = Ok(1);
++    return foo.unwrap_$0or_else(x);
++}
++"#,
++            r#"
++fn foo() {
++    let foo = Ok(1);
++    return foo.unwrap_or(x());
++}
++"#,
++        )
++    }
++
++    #[test]
++    fn replace_or_else_with_or_map() {
++        check_assist(
++            replace_or_else_with_or,
++            r#"
++//- minicore: result
++fn foo() {
++    let foo = Ok("foo");
++    return foo.map$0_or_else(|| 42, |v| v.len());
++}
++"#,
++            r#"
++fn foo() {
++    let foo = Ok("foo");
++    return foo.map_or(42, |v| v.len());
++}
++"#,
++        )
++    }
++
++    #[test]
++    fn replace_or_else_with_or_not_applicable() {
++        check_assist_not_applicable(
++            replace_or_else_with_or,
++            r#"
++fn foo() {
++    let foo = Ok(1);
++    return foo.unwrap_$0or_else(x);
++}
++"#,
++        )
++    }
++}
index 5242f3b5100cfa9357d322ac8f2cc647def5385f,0000000000000000000000000000000000000000..521447c26dfbed01d20ac10592fd127a286f16ec
mode 100644,000000..100644
--- /dev/null
@@@ -1,243 -1,0 +1,365 @@@
-     ast::{Expr, GenericArg},
++use hir::HirDisplay;
 +use syntax::{
-     let generic_args = match &initializer {
-         Expr::MethodCallExpr(ce) => ce.generic_arg_list()?,
-         Expr::CallExpr(ce) => {
-             if let Expr::PathExpr(pe) = ce.expr()? {
-                 pe.path()?.segment()?.generic_arg_list()?
-             } else {
-                 cov_mark::hit!(not_applicable_if_non_path_function_call);
-                 return None;
-             }
-         }
-         _ => {
-             cov_mark::hit!(not_applicable_if_non_function_call_initializer);
-             return None;
-         }
-     };
++    ast::{Expr, GenericArg, GenericArgList},
 +    ast::{LetStmt, Type::InferType},
 +    AstNode, TextRange,
 +};
 +
 +use crate::{
 +    assist_context::{AssistContext, Assists},
 +    AssistId, AssistKind,
 +};
 +
 +// Assist: replace_turbofish_with_explicit_type
 +//
 +// Converts `::<_>` to an explicit type assignment.
 +//
 +// ```
 +// fn make<T>() -> T { ) }
 +// fn main() {
 +//     let a = make$0::<i32>();
 +// }
 +// ```
 +// ->
 +// ```
 +// fn make<T>() -> T { ) }
 +// fn main() {
 +//     let a: i32 = make();
 +// }
 +// ```
 +pub(crate) fn replace_turbofish_with_explicit_type(
 +    acc: &mut Assists,
 +    ctx: &AssistContext<'_>,
 +) -> Option<()> {
 +    let let_stmt = ctx.find_node_at_offset::<LetStmt>()?;
 +
 +    let initializer = let_stmt.initializer()?;
 +
-     let turbofish_type = &turbofish_args[0];
++    let generic_args = generic_arg_list(&initializer)?;
 +
 +    // Find range of ::<_>
 +    let colon2 = generic_args.coloncolon_token()?;
 +    let r_angle = generic_args.r_angle_token()?;
 +    let turbofish_range = TextRange::new(colon2.text_range().start(), r_angle.text_range().end());
 +
 +    let turbofish_args: Vec<GenericArg> = generic_args.generic_args().into_iter().collect();
 +
 +    // Find type of ::<_>
 +    if turbofish_args.len() != 1 {
 +        cov_mark::hit!(not_applicable_if_not_single_arg);
 +        return None;
 +    }
 +
 +    // An improvement would be to check that this is correctly part of the return value of the
 +    // function call, or sub in the actual return type.
-                 builder.insert(ident_range.end(), format!(": {}", turbofish_type));
++    let returned_type = match ctx.sema.type_of_expr(&initializer) {
++        Some(returned_type) if !returned_type.original.contains_unknown() => {
++            let module = ctx.sema.scope(let_stmt.syntax())?.module();
++            returned_type.original.display_source_code(ctx.db(), module.into()).ok()?
++        }
++        _ => {
++            cov_mark::hit!(fallback_to_turbofish_type_if_type_info_not_available);
++            turbofish_args[0].to_string()
++        }
++    };
 +
 +    let initializer_start = initializer.syntax().text_range().start();
 +    if ctx.offset() > turbofish_range.end() || ctx.offset() < initializer_start {
 +        cov_mark::hit!(not_applicable_outside_turbofish);
 +        return None;
 +    }
 +
 +    if let None = let_stmt.colon_token() {
 +        // If there's no colon in a let statement, then there is no explicit type.
 +        // let x = fn::<...>();
 +        let ident_range = let_stmt.pat()?.syntax().text_range();
 +
 +        return acc.add(
 +            AssistId("replace_turbofish_with_explicit_type", AssistKind::RefactorRewrite),
 +            "Replace turbofish with explicit type",
 +            TextRange::new(initializer_start, turbofish_range.end()),
 +            |builder| {
-                 builder.replace(underscore_range, turbofish_type.to_string());
++                builder.insert(ident_range.end(), format!(": {}", returned_type));
 +                builder.delete(turbofish_range);
 +            },
 +        );
 +    } else if let Some(InferType(t)) = let_stmt.ty() {
 +        // If there's a type inference underscore, we can offer to replace it with the type in
 +        // the turbofish.
 +        // let x: _ = fn::<...>();
 +        let underscore_range = t.syntax().text_range();
 +
 +        return acc.add(
 +            AssistId("replace_turbofish_with_explicit_type", AssistKind::RefactorRewrite),
 +            "Replace `_` with turbofish type",
 +            turbofish_range,
 +            |builder| {
++                builder.replace(underscore_range, returned_type);
 +                builder.delete(turbofish_range);
 +            },
 +        );
 +    }
 +
 +    None
 +}
 +
++fn generic_arg_list(expr: &Expr) -> Option<GenericArgList> {
++    match expr {
++        Expr::MethodCallExpr(expr) => expr.generic_arg_list(),
++        Expr::CallExpr(expr) => {
++            if let Expr::PathExpr(pe) = expr.expr()? {
++                pe.path()?.segment()?.generic_arg_list()
++            } else {
++                cov_mark::hit!(not_applicable_if_non_path_function_call);
++                return None;
++            }
++        }
++        Expr::AwaitExpr(expr) => generic_arg_list(&expr.expr()?),
++        Expr::TryExpr(expr) => generic_arg_list(&expr.expr()?),
++        _ => {
++            cov_mark::hit!(not_applicable_if_non_function_call_initializer);
++            None
++        }
++    }
++}
++
 +#[cfg(test)]
 +mod tests {
 +    use super::*;
 +
 +    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
 +
 +    #[test]
 +    fn replaces_turbofish_for_vec_string() {
++        cov_mark::check!(fallback_to_turbofish_type_if_type_info_not_available);
 +        check_assist(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a = make$0::<Vec<String>>();
 +}
 +"#,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a: Vec<String> = make();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn replaces_method_calls() {
 +        // foo.make() is a method call which uses a different expr in the let initializer
++        cov_mark::check!(fallback_to_turbofish_type_if_type_info_not_available);
 +        check_assist(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a = foo.make$0::<Vec<String>>();
 +}
 +"#,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a: Vec<String> = foo.make();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn replace_turbofish_target() {
 +        check_assist_target(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a = $0make::<Vec<String>>();
 +}
 +"#,
 +            r#"make::<Vec<String>>"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_outside_turbofish() {
 +        cov_mark::check!(not_applicable_outside_turbofish);
 +        check_assist_not_applicable(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let $0a = make::<Vec<String>>();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn replace_inferred_type_placeholder() {
 +        check_assist(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a: _ = make$0::<Vec<String>>();
 +}
 +"#,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a: Vec<String> = make();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_constant_initializer() {
 +        cov_mark::check!(not_applicable_if_non_function_call_initializer);
 +        check_assist_not_applicable(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a = "foo"$0;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn not_applicable_non_path_function_call() {
 +        cov_mark::check!(not_applicable_if_non_path_function_call);
 +        check_assist_not_applicable(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    $0let a = (|| {})();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn non_applicable_multiple_generic_args() {
 +        cov_mark::check!(not_applicable_if_not_single_arg);
 +        check_assist_not_applicable(
 +            replace_turbofish_with_explicit_type,
 +            r#"
 +fn make<T>() -> T {}
 +fn main() {
 +    let a = make$0::<Vec<String>, i32>();
 +}
++"#,
++        );
++    }
++
++    #[test]
++    fn replaces_turbofish_for_known_type() {
++        check_assist(
++            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();
++}
++"#,
++        );
++        check_assist(
++            replace_turbofish_with_explicit_type,
++            r#"
++//- minicore: option
++fn make<T>() -> T {}
++fn main() {
++    let a = make$0::<Option<bool>>();
++}
++"#,
++            r#"
++fn make<T>() -> T {}
++fn main() {
++    let a: Option<bool> = make();
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn replaces_turbofish_not_same_type() {
++        check_assist(
++            replace_turbofish_with_explicit_type,
++            r#"
++//- minicore: option
++fn make<T>() -> Option<T> {}
++fn main() {
++    let a = make$0::<u128>();
++}
++"#,
++            r#"
++fn make<T>() -> Option<T> {}
++fn main() {
++    let a: Option<u128> = make();
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn replaces_turbofish_for_type_with_defaulted_generic_param() {
++        check_assist(
++            replace_turbofish_with_explicit_type,
++            r#"
++struct HasDefault<T, U = i32>(T, U);
++fn make<T>() -> HasDefault<T> {}
++fn main() {
++    let a = make$0::<bool>();
++}
++"#,
++            r#"
++struct HasDefault<T, U = i32>(T, U);
++fn make<T>() -> HasDefault<T> {}
++fn main() {
++    let a: HasDefault<bool> = make();
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn replaces_turbofish_try_await() {
++        check_assist(
++            replace_turbofish_with_explicit_type,
++            r#"
++//- minicore: option, future
++struct Fut<T>(T);
++impl<T> core::future::Future for Fut<T> {
++    type Output = Option<T>;
++}
++fn make<T>() -> Fut<T> {}
++fn main() {
++    let a = make$0::<bool>().await?;
++}
++"#,
++            r#"
++struct Fut<T>(T);
++impl<T> core::future::Future for Fut<T> {
++    type Output = Option<T>;
++}
++fn make<T>() -> Fut<T> {}
++fn main() {
++    let a: bool = make().await?;
++}
 +"#,
 +        );
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9565f0ee6f26f96833dd35d7977d03070033b619
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,293 @@@
++use syntax::{
++    algo::neighbor,
++    ast::{self, edit::IndentLevel, make, AstNode},
++    ted::{self, Position},
++    Direction, SyntaxKind, T,
++};
++
++use crate::{AssistContext, AssistId, AssistKind, Assists};
++
++// Assist: unmerge_match_arm
++//
++// Splits the current match with a `|` pattern into two arms with identical bodies.
++//
++// ```
++// enum Action { Move { distance: u32 }, Stop }
++//
++// fn handle(action: Action) {
++//     match action {
++//         Action::Move(..) $0| Action::Stop => foo(),
++//     }
++// }
++// ```
++// ->
++// ```
++// enum Action { Move { distance: u32 }, Stop }
++//
++// fn handle(action: Action) {
++//     match action {
++//         Action::Move(..) => foo(),
++//         Action::Stop => foo(),
++//     }
++// }
++// ```
++pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
++    let pipe_token = ctx.find_token_syntax_at_offset(T![|])?;
++    let or_pat = ast::OrPat::cast(pipe_token.parent()?)?.clone_for_update();
++    let match_arm = ast::MatchArm::cast(or_pat.syntax().parent()?)?;
++    let match_arm_body = match_arm.expr()?;
++
++    // We don't need to check for leading pipe because it is directly under `MatchArm`
++    // without `OrPat`.
++
++    let new_parent = match_arm.syntax().parent()?;
++    let old_parent_range = new_parent.text_range();
++
++    acc.add(
++        AssistId("unmerge_match_arm", AssistKind::RefactorRewrite),
++        "Unmerge match arm",
++        pipe_token.text_range(),
++        |edit| {
++            let pats_after = pipe_token
++                .siblings_with_tokens(Direction::Next)
++                .filter_map(|it| ast::Pat::cast(it.into_node()?));
++            // FIXME: We should add a leading pipe if the original arm has one.
++            let new_match_arm = make::match_arm(
++                pats_after,
++                match_arm.guard().and_then(|guard| guard.condition()),
++                match_arm_body,
++            )
++            .clone_for_update();
++
++            let mut pipe_index = pipe_token.index();
++            if pipe_token
++                .prev_sibling_or_token()
++                .map_or(false, |it| it.kind() == SyntaxKind::WHITESPACE)
++            {
++                pipe_index -= 1;
++            }
++            or_pat.syntax().splice_children(
++                pipe_index..or_pat.syntax().children_with_tokens().count(),
++                Vec::new(),
++            );
++
++            let mut insert_after_old_arm = Vec::new();
++
++            // A comma can be:
++            //  - After the arm. In this case we always want to insert a comma after the newly
++            //    inserted arm.
++            //  - Missing after the arm, with no arms after. In this case we want to insert a
++            //    comma before the newly inserted arm. It can not be necessary if there arm
++            //    body is a block, but we don't bother to check that.
++            //  - Missing after the arm with arms after, if the arm body is a block. In this case
++            //    we don't want to insert a comma at all.
++            let has_comma_after =
++                std::iter::successors(match_arm.syntax().last_child_or_token(), |it| {
++                    it.prev_sibling_or_token()
++                })
++                .map(|it| it.kind())
++                .skip_while(|it| it.is_trivia())
++                .next()
++                    == Some(T![,]);
++            let has_arms_after = neighbor(&match_arm, Direction::Next).is_some();
++            if !has_comma_after && !has_arms_after {
++                insert_after_old_arm.push(make::token(T![,]).into());
++            }
++
++            let indent = IndentLevel::from_node(match_arm.syntax());
++            insert_after_old_arm.push(make::tokens::whitespace(&format!("\n{indent}")).into());
++
++            insert_after_old_arm.push(new_match_arm.syntax().clone().into());
++
++            ted::insert_all_raw(Position::after(match_arm.syntax()), insert_after_old_arm);
++
++            if has_comma_after {
++                ted::insert_raw(
++                    Position::last_child_of(new_match_arm.syntax()),
++                    make::token(T![,]),
++                );
++            }
++
++            edit.replace(old_parent_range, new_parent.to_string());
++        },
++    )
++}
++
++#[cfg(test)]
++mod tests {
++    use crate::tests::{check_assist, check_assist_not_applicable};
++
++    use super::*;
++
++    #[test]
++    fn unmerge_match_arm_single_pipe() {
++        check_assist(
++            unmerge_match_arm,
++            r#"
++#[derive(Debug)]
++enum X { A, B, C }
++
++fn main() {
++    let x = X::A;
++    let y = match x {
++        X::A $0| X::B => { 1i32 }
++        X::C => { 2i32 }
++    };
++}
++"#,
++            r#"
++#[derive(Debug)]
++enum X { A, B, C }
++
++fn main() {
++    let x = X::A;
++    let y = match x {
++        X::A => { 1i32 }
++        X::B => { 1i32 }
++        X::C => { 2i32 }
++    };
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn unmerge_match_arm_guard() {
++        check_assist(
++            unmerge_match_arm,
++            r#"
++#[derive(Debug)]
++enum X { A, B, C }
++
++fn main() {
++    let x = X::A;
++    let y = match x {
++        X::A $0| X::B if true => { 1i32 }
++        _ => { 2i32 }
++    };
++}
++"#,
++            r#"
++#[derive(Debug)]
++enum X { A, B, C }
++
++fn main() {
++    let x = X::A;
++    let y = match x {
++        X::A if true => { 1i32 }
++        X::B if true => { 1i32 }
++        _ => { 2i32 }
++    };
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn unmerge_match_arm_leading_pipe() {
++        check_assist_not_applicable(
++            unmerge_match_arm,
++            r#"
++
++fn main() {
++    let y = match 0 {
++        |$0 0 => { 1i32 }
++        1 => { 2i32 }
++    };
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn unmerge_match_arm_multiple_pipes() {
++        check_assist(
++            unmerge_match_arm,
++            r#"
++#[derive(Debug)]
++enum X { A, B, C, D, E }
++
++fn main() {
++    let x = X::A;
++    let y = match x {
++        X::A | X::B |$0 X::C | X::D => 1i32,
++        X::E => 2i32,
++    };
++}
++"#,
++            r#"
++#[derive(Debug)]
++enum X { A, B, C, D, E }
++
++fn main() {
++    let x = X::A;
++    let y = match x {
++        X::A | X::B => 1i32,
++        X::C | X::D => 1i32,
++        X::E => 2i32,
++    };
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn unmerge_match_arm_inserts_comma_if_required() {
++        check_assist(
++            unmerge_match_arm,
++            r#"
++#[derive(Debug)]
++enum X { A, B }
++
++fn main() {
++    let x = X::A;
++    let y = match x {
++        X::A $0| X::B => 1i32
++    };
++}
++"#,
++            r#"
++#[derive(Debug)]
++enum X { A, B }
++
++fn main() {
++    let x = X::A;
++    let y = match x {
++        X::A => 1i32,
++        X::B => 1i32
++    };
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn unmerge_match_arm_inserts_comma_if_had_after() {
++        check_assist(
++            unmerge_match_arm,
++            r#"
++#[derive(Debug)]
++enum X { A, B }
++
++fn main() {
++    let x = X::A;
++    match x {
++        X::A $0| X::B => {},
++    }
++}
++"#,
++            r#"
++#[derive(Debug)]
++enum X { A, B }
++
++fn main() {
++    let x = X::A;
++    match x {
++        X::A => {},
++        X::B => {},
++    }
++}
++"#,
++        );
++    }
++}
index 7fb35143fa2ff1303459cedde3579f16221d7fa7,0000000000000000000000000000000000000000..e52544db5f530ff969735c4a25b305c64c5491ae
mode 100644,000000..100644
--- /dev/null
@@@ -1,310 -1,0 +1,317 @@@
 +//! `assists` crate provides a bunch of code assists, also known as code actions
 +//! (in LSP) or intentions (in IntelliJ).
 +//!
 +//! An assist is a micro-refactoring, which is automatically activated in
 +//! certain context. For example, if the cursor is over `,`, a "swap `,`" assist
 +//! becomes available.
 +//!
 +//! ## Assists Guidelines
 +//!
 +//! Assists are the main mechanism to deliver advanced IDE features to the user,
 +//! so we should pay extra attention to the UX.
 +//!
 +//! The power of assists comes from their context-awareness. The main problem
 +//! with IDE features is that there are a lot of them, and it's hard to teach
 +//! the user what's available. Assists solve this problem nicely: 💡 signifies
 +//! that *something* is possible, and clicking on it reveals a *short* list of
 +//! actions. Contrast it with Emacs `M-x`, which just spits an infinite list of
 +//! all the features.
 +//!
 +//! Here are some considerations when creating a new assist:
 +//!
 +//! * It's good to preserve semantics, and it's good to keep the code compiling,
 +//!   but it isn't necessary. Example: "flip binary operation" might change
 +//!   semantics.
 +//! * Assist shouldn't necessary make the code "better". A lot of assist come in
 +//!   pairs: "if let <-> match".
 +//! * Assists should have as narrow scope as possible. Each new assists greatly
 +//!   improves UX for cases where the user actually invokes it, but it makes UX
 +//!   worse for every case where the user clicks 💡 to invoke some *other*
 +//!   assist. So, a rarely useful assist which is always applicable can be a net
 +//!   negative.
 +//! * Rarely useful actions are tricky. Sometimes there are features which are
 +//!   clearly useful to some users, but are just noise most of the time. We
 +//!   don't have a good solution here, our current approach is to make this
 +//!   functionality available only if assist is applicable to the whole
 +//!   selection. Example: `sort_items` sorts items alphabetically. Naively, it
 +//!   should be available more or less everywhere, which isn't useful. So
 +//!   instead we only show it if the user *selects* the items they want to sort.
 +//! * Consider grouping related assists together (see [`Assists::add_group`]).
 +//! * Make assists robust. If the assist depends on results of type-inference too
 +//!   much, it might only fire in fully-correct code. This makes assist less
 +//!   useful and (worse) less predictable. The user should have a clear
 +//!   intuition when each particular assist is available.
 +//! * Make small assists, which compose. Example: rather than auto-importing
 +//!   enums in `add_missing_match_arms`, we use fully-qualified names. There's a
 +//!   separate assist to shorten a fully-qualified name.
 +//! * Distinguish between assists and fixits for diagnostics. Internally, fixits
 +//!   and assists are equivalent. They have the same "show a list + invoke a
 +//!   single element" workflow, and both use [`Assist`] data structure. The main
 +//!   difference is in the UX: while 💡 looks only at the cursor position,
 +//!   diagnostics squigglies and fixits are calculated for the whole file and
 +//!   are presented to the user eagerly. So, diagnostics should be fixable
 +//!   errors, while assists can be just suggestions for an alternative way to do
 +//!   something. If something *could* be a diagnostic, it should be a
 +//!   diagnostic. Conversely, it might be valuable to turn a diagnostic with a
 +//!   lot of false errors into an assist.
 +//!
 +//! See also this post:
 +//! <https://rust-analyzer.github.io/blog/2020/09/28/how-to-make-a-light-bulb.html>
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +
 +#[allow(unused)]
 +macro_rules! eprintln {
 +    ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
 +}
 +
 +mod assist_config;
 +mod assist_context;
 +#[cfg(test)]
 +mod tests;
 +pub mod utils;
 +
 +use hir::Semantics;
 +use ide_db::{base_db::FileRange, RootDatabase};
 +use syntax::TextRange;
 +
 +pub(crate) use crate::assist_context::{AssistContext, Assists};
 +
 +pub use assist_config::AssistConfig;
 +pub use ide_db::assists::{
 +    Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel, SingleResolve,
 +};
 +
 +/// Return all the assists applicable at the given position.
 +///
 +// NOTE: We don't have a `Feature: ` section for assists, they are special-cased
 +// in the manual.
 +pub fn assists(
 +    db: &RootDatabase,
 +    config: &AssistConfig,
 +    resolve: AssistResolveStrategy,
 +    range: FileRange,
 +) -> Vec<Assist> {
 +    let sema = Semantics::new(db);
 +    let ctx = AssistContext::new(sema, config, range);
 +    let mut acc = Assists::new(&ctx, resolve);
 +    handlers::all().iter().for_each(|handler| {
 +        handler(&mut acc, &ctx);
 +    });
 +    acc.finish()
 +}
 +
 +mod handlers {
 +    use crate::{AssistContext, Assists};
 +
 +    pub(crate) type Handler = fn(&mut Assists, &AssistContext<'_>) -> Option<()>;
 +
 +    mod add_explicit_type;
 +    mod add_label_to_loop;
 +    mod add_lifetime_to_type;
 +    mod add_missing_impl_members;
 +    mod add_turbo_fish;
 +    mod apply_demorgan;
 +    mod auto_import;
 +    mod change_visibility;
 +    mod convert_bool_then;
 +    mod convert_comment_block;
 +    mod convert_integer_literal;
 +    mod convert_into_to_from;
 +    mod convert_iter_for_each_to_for;
 +    mod convert_let_else_to_match;
 +    mod convert_tuple_struct_to_named_struct;
 +    mod convert_to_guarded_return;
++    mod convert_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 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 sort_items;
 +    mod toggle_ignore;
 +    mod unmerge_use;
 +    mod unnecessary_async;
 +    mod unwrap_block;
 +    mod unwrap_result_return_type;
 +    mod wrap_return_type_in_result;
 +
 +    pub(crate) fn all() -> &'static [Handler] {
 +        &[
 +            // These are alphabetic for the foolish consistency
 +            add_explicit_type::add_explicit_type,
 +            add_label_to_loop::add_label_to_loop,
 +            add_missing_match_arms::add_missing_match_arms,
 +            add_lifetime_to_type::add_lifetime_to_type,
 +            add_return_type::add_return_type,
 +            add_turbo_fish::add_turbo_fish,
 +            apply_demorgan::apply_demorgan,
 +            auto_import::auto_import,
 +            change_visibility::change_visibility,
 +            convert_bool_then::convert_bool_then_to_if,
 +            convert_bool_then::convert_if_to_bool_then,
 +            convert_comment_block::convert_comment_block,
 +            convert_integer_literal::convert_integer_literal,
 +            convert_into_to_from::convert_into_to_from,
 +            convert_iter_for_each_to_for::convert_iter_for_each_to_for,
 +            convert_iter_for_each_to_for::convert_for_loop_with_for_each,
 +            convert_let_else_to_match::convert_let_else_to_match,
 +            convert_to_guarded_return::convert_to_guarded_return,
 +            convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
++            convert_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_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,
 +            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 22319f36134fb6b6d0ee259ae1f2245754d36917,0000000000000000000000000000000000000000..a8c8622c1c1d89cdcab5caf4d489f96f454112f2
mode 100644,000000..100644
--- /dev/null
@@@ -1,2284 -1,0 +1,2370 @@@
 +//! Generated by `sourcegen_assists_docs`, do not edit by hand.
 +
 +use super::check_doc_test;
 +
 +#[test]
 +fn doctest_add_explicit_type() {
 +    check_doc_test(
 +        "add_explicit_type",
 +        r#####"
 +fn main() {
 +    let x$0 = 92;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let x: i32 = 92;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_hash() {
 +    check_doc_test(
 +        "add_hash",
 +        r#####"
 +fn main() {
 +    r#"Hello,$0 World!"#;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    r##"Hello, World!"##;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_impl_default_members() {
 +    check_doc_test(
 +        "add_impl_default_members",
 +        r#####"
 +trait Trait {
 +    type X;
 +    fn foo(&self);
 +    fn bar(&self) {}
 +}
 +
 +impl Trait for () {
 +    type X = ();
 +    fn foo(&self) {}$0
 +}
 +"#####,
 +        r#####"
 +trait Trait {
 +    type X;
 +    fn foo(&self);
 +    fn bar(&self) {}
 +}
 +
 +impl Trait for () {
 +    type X = ();
 +    fn foo(&self) {}
 +
 +    $0fn bar(&self) {}
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_impl_missing_members() {
 +    check_doc_test(
 +        "add_impl_missing_members",
 +        r#####"
 +trait Trait<T> {
 +    type X;
 +    fn foo(&self) -> T;
 +    fn bar(&self) {}
 +}
 +
 +impl Trait<u32> for () {$0
 +
 +}
 +"#####,
 +        r#####"
 +trait Trait<T> {
 +    type X;
 +    fn foo(&self) -> T;
 +    fn bar(&self) {}
 +}
 +
 +impl Trait<u32> for () {
 +    $0type X;
 +
 +    fn foo(&self) -> u32 {
 +        todo!()
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_label_to_loop() {
 +    check_doc_test(
 +        "add_label_to_loop",
 +        r#####"
 +fn main() {
 +    loop$0 {
 +        break;
 +        continue;
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    'l: loop {
 +        break 'l;
 +        continue 'l;
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_lifetime_to_type() {
 +    check_doc_test(
 +        "add_lifetime_to_type",
 +        r#####"
 +struct Point {
 +    x: &$0u32,
 +    y: u32,
 +}
 +"#####,
 +        r#####"
 +struct Point<'a> {
 +    x: &'a u32,
 +    y: u32,
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_missing_match_arms() {
 +    check_doc_test(
 +        "add_missing_match_arms",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        $0
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        $0Action::Move { distance } => todo!(),
 +        Action::Stop => todo!(),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_return_type() {
 +    check_doc_test(
 +        "add_return_type",
 +        r#####"
 +fn foo() { 4$02i32 }
 +"#####,
 +        r#####"
 +fn foo() -> i32 { 42i32 }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_add_turbo_fish() {
 +    check_doc_test(
 +        "add_turbo_fish",
 +        r#####"
 +fn make<T>() -> T { todo!() }
 +fn main() {
 +    let x = make$0();
 +}
 +"#####,
 +        r#####"
 +fn make<T>() -> T { todo!() }
 +fn main() {
 +    let x = make::<${0:_}>();
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_apply_demorgan() {
 +    check_doc_test(
 +        "apply_demorgan",
 +        r#####"
 +fn main() {
 +    if x != 4 ||$0 y < 3.14 {}
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    if !(x == 4 && y >= 3.14) {}
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_auto_import() {
 +    check_doc_test(
 +        "auto_import",
 +        r#####"
 +fn main() {
 +    let map = HashMap$0::new();
 +}
 +pub mod std { pub mod collections { pub struct HashMap { } } }
 +"#####,
 +        r#####"
 +use std::collections::HashMap;
 +
 +fn main() {
 +    let map = HashMap::new();
 +}
 +pub mod std { pub mod collections { pub struct HashMap { } } }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_change_visibility() {
 +    check_doc_test(
 +        "change_visibility",
 +        r#####"
 +$0fn frobnicate() {}
 +"#####,
 +        r#####"
 +pub(crate) fn frobnicate() {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_bool_then_to_if() {
 +    check_doc_test(
 +        "convert_bool_then_to_if",
 +        r#####"
 +//- minicore: bool_impl
 +fn main() {
 +    (0 == 0).then$0(|| val)
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    if 0 == 0 {
 +        Some(val)
 +    } else {
 +        None
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_for_loop_with_for_each() {
 +    check_doc_test(
 +        "convert_for_loop_with_for_each",
 +        r#####"
 +fn main() {
 +    let x = vec![1, 2, 3];
 +    for$0 v in x {
 +        let y = v * 2;
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let x = vec![1, 2, 3];
 +    x.into_iter().for_each(|v| {
 +        let y = v * 2;
 +    });
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_if_to_bool_then() {
 +    check_doc_test(
 +        "convert_if_to_bool_then",
 +        r#####"
 +//- minicore: option
 +fn main() {
 +    if$0 cond {
 +        Some(val)
 +    } else {
 +        None
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    cond.then(|| val)
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_integer_literal() {
 +    check_doc_test(
 +        "convert_integer_literal",
 +        r#####"
 +const _: i32 = 10$0;
 +"#####,
 +        r#####"
 +const _: i32 = 0b1010;
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_into_to_from() {
 +    check_doc_test(
 +        "convert_into_to_from",
 +        r#####"
 +//- minicore: from
 +impl $0Into<Thing> for usize {
 +    fn into(self) -> Thing {
 +        Thing {
 +            b: self.to_string(),
 +            a: self
 +        }
 +    }
 +}
 +"#####,
 +        r#####"
 +impl From<usize> for Thing {
 +    fn from(val: usize) -> Self {
 +        Thing {
 +            b: val.to_string(),
 +            a: val
 +        }
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_iter_for_each_to_for() {
 +    check_doc_test(
 +        "convert_iter_for_each_to_for",
 +        r#####"
 +//- minicore: iterators
 +use core::iter;
 +fn main() {
 +    let iter = iter::repeat((9, 2));
 +    iter.for_each$0(|(x, y)| {
 +        println!("x: {}, y: {}", x, y);
 +    });
 +}
 +"#####,
 +        r#####"
 +use core::iter;
 +fn main() {
 +    let iter = iter::repeat((9, 2));
 +    for (x, y) in iter {
 +        println!("x: {}, y: {}", x, y);
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_let_else_to_match() {
 +    check_doc_test(
 +        "convert_let_else_to_match",
 +        r#####"
 +fn main() {
 +    let Ok(mut x) = f() else$0 { return };
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let mut x = match f() {
 +        Ok(x) => x,
 +        _ => return,
 +    };
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_to_guarded_return() {
 +    check_doc_test(
 +        "convert_to_guarded_return",
 +        r#####"
 +fn main() {
 +    $0if cond {
 +        foo();
 +        bar();
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    if !cond {
 +        return;
 +    }
 +    foo();
 +    bar();
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_convert_tuple_struct_to_named_struct() {
 +    check_doc_test(
 +        "convert_tuple_struct_to_named_struct",
 +        r#####"
 +struct Point$0(f32, f32);
 +
 +impl Point {
 +    pub fn new(x: f32, y: f32) -> Self {
 +        Point(x, y)
 +    }
 +
 +    pub fn x(&self) -> f32 {
 +        self.0
 +    }
 +
 +    pub fn y(&self) -> f32 {
 +        self.1
 +    }
 +}
 +"#####,
 +        r#####"
 +struct Point { field1: f32, field2: f32 }
 +
 +impl Point {
 +    pub fn new(x: f32, y: f32) -> Self {
 +        Point { field1: x, field2: y }
 +    }
 +
 +    pub fn x(&self) -> f32 {
 +        self.field1
 +    }
 +
 +    pub fn y(&self) -> f32 {
 +        self.field2
 +    }
 +}
 +"#####,
 +    )
 +}
 +
++#[test]
++fn doctest_convert_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#####"
 +type A = i32;
 +fn id(x: i32) -> i32 {
 +    x
 +};
 +fn foo() {
 +    let _: i32 = 3;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_introduce_named_generic() {
 +    check_doc_test(
 +        "introduce_named_generic",
 +        r#####"
 +fn foo(bar: $0impl Bar) {}
 +"#####,
 +        r#####"
 +fn foo<B: Bar>(bar: B) {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_introduce_named_lifetime() {
 +    check_doc_test(
 +        "introduce_named_lifetime",
 +        r#####"
 +impl Cursor<'_$0> {
 +    fn node(self) -> &SyntaxNode {
 +        match self {
 +            Cursor::Replace(node) | Cursor::Before(node) => node,
 +        }
 +    }
 +}
 +"#####,
 +        r#####"
 +impl<'a> Cursor<'a> {
 +    fn node(self) -> &SyntaxNode {
 +        match self {
 +            Cursor::Replace(node) | Cursor::Before(node) => node,
 +        }
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_invert_if() {
 +    check_doc_test(
 +        "invert_if",
 +        r#####"
 +fn main() {
 +    if$0 !y { A } else { B }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    if y { B } else { A }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_line_to_block() {
 +    check_doc_test(
 +        "line_to_block",
 +        r#####"
 +   // Multi-line$0
 +   // comment
 +"#####,
 +        r#####"
 +  /*
 +  Multi-line
 +  comment
 +  */
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_make_raw_string() {
 +    check_doc_test(
 +        "make_raw_string",
 +        r#####"
 +fn main() {
 +    "Hello,$0 World!";
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    r#"Hello, World!"#;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_make_usual_string() {
 +    check_doc_test(
 +        "make_usual_string",
 +        r#####"
 +fn main() {
 +    r#"Hello,$0 "World!""#;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    "Hello, \"World!\"";
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_merge_imports() {
 +    check_doc_test(
 +        "merge_imports",
 +        r#####"
 +use std::$0fmt::Formatter;
 +use std::io;
 +"#####,
 +        r#####"
 +use std::{fmt::Formatter, io};
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_merge_match_arms() {
 +    check_doc_test(
 +        "merge_match_arms",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        $0Action::Move(..) => foo(),
 +        Action::Stop => foo(),
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move(..) | Action::Stop => foo(),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_arm_cond_to_match_guard() {
 +    check_doc_test(
 +        "move_arm_cond_to_match_guard",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move { distance } => $0if distance > 10 { foo() },
 +        _ => (),
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move { distance } if distance > 10 => foo(),
 +        _ => (),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_bounds_to_where_clause() {
 +    check_doc_test(
 +        "move_bounds_to_where_clause",
 +        r#####"
 +fn apply<T, U, $0F: FnOnce(T) -> U>(f: F, x: T) -> U {
 +    f(x)
 +}
 +"#####,
 +        r#####"
 +fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U {
 +    f(x)
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_from_mod_rs() {
 +    check_doc_test(
 +        "move_from_mod_rs",
 +        r#####"
 +//- /main.rs
 +mod a;
 +//- /a/mod.rs
 +$0fn t() {}$0
 +"#####,
 +        r#####"
 +fn t() {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_guard_to_arm_body() {
 +    check_doc_test(
 +        "move_guard_to_arm_body",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move { distance } $0if distance > 10 => foo(),
 +        _ => (),
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move { distance } => if distance > 10 {
 +            foo()
 +        },
 +        _ => (),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_module_to_file() {
 +    check_doc_test(
 +        "move_module_to_file",
 +        r#####"
 +mod $0foo {
 +    fn t() {}
 +}
 +"#####,
 +        r#####"
 +mod foo;
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_move_to_mod_rs() {
 +    check_doc_test(
 +        "move_to_mod_rs",
 +        r#####"
 +//- /main.rs
 +mod a;
 +//- /a.rs
 +$0fn t() {}$0
 +"#####,
 +        r#####"
 +fn t() {}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_promote_local_to_const() {
 +    check_doc_test(
 +        "promote_local_to_const",
 +        r#####"
 +fn main() {
 +    let foo$0 = true;
 +
 +    if foo {
 +        println!("It's true");
 +    } else {
 +        println!("It's false");
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    const $0FOO: bool = true;
 +
 +    if FOO {
 +        println!("It's true");
 +    } else {
 +        println!("It's false");
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_pull_assignment_up() {
 +    check_doc_test(
 +        "pull_assignment_up",
 +        r#####"
 +fn main() {
 +    let mut foo = 6;
 +
 +    if true {
 +        $0foo = 5;
 +    } else {
 +        foo = 4;
 +    }
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    let mut foo = 6;
 +
 +    foo = if true {
 +        5
 +    } else {
 +        4
 +    };
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_qualify_method_call() {
 +    check_doc_test(
 +        "qualify_method_call",
 +        r#####"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {}
 +}
 +fn main() {
 +    let foo = Foo;
 +    foo.fo$0o();
 +}
 +"#####,
 +        r#####"
 +struct Foo;
 +impl Foo {
 +    fn foo(&self) {}
 +}
 +fn main() {
 +    let foo = Foo;
 +    Foo::foo(&foo);
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_qualify_path() {
 +    check_doc_test(
 +        "qualify_path",
 +        r#####"
 +fn main() {
 +    let map = HashMap$0::new();
 +}
 +pub mod std { pub mod collections { pub struct HashMap { } } }
 +"#####,
 +        r#####"
 +fn main() {
 +    let map = std::collections::HashMap::new();
 +}
 +pub mod std { pub mod collections { pub struct HashMap { } } }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_reformat_number_literal() {
 +    check_doc_test(
 +        "reformat_number_literal",
 +        r#####"
 +const _: i32 = 1012345$0;
 +"#####,
 +        r#####"
 +const _: i32 = 1_012_345;
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_remove_dbg() {
 +    check_doc_test(
 +        "remove_dbg",
 +        r#####"
 +fn main() {
 +    $0dbg!(92);
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    92;
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_remove_hash() {
 +    check_doc_test(
 +        "remove_hash",
 +        r#####"
 +fn main() {
 +    r#"Hello,$0 World!"#;
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    r"Hello, World!";
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_remove_mut() {
 +    check_doc_test(
 +        "remove_mut",
 +        r#####"
 +impl Walrus {
 +    fn feed(&mut$0 self, amount: u32) {}
 +}
 +"#####,
 +        r#####"
 +impl Walrus {
 +    fn feed(&self, amount: u32) {}
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_remove_unused_param() {
 +    check_doc_test(
 +        "remove_unused_param",
 +        r#####"
 +fn frobnicate(x: i32$0) {}
 +
 +fn main() {
 +    frobnicate(92);
 +}
 +"#####,
 +        r#####"
 +fn frobnicate() {}
 +
 +fn main() {
 +    frobnicate();
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_reorder_fields() {
 +    check_doc_test(
 +        "reorder_fields",
 +        r#####"
 +struct Foo {foo: i32, bar: i32};
 +const test: Foo = $0Foo {bar: 0, foo: 1}
 +"#####,
 +        r#####"
 +struct Foo {foo: i32, bar: i32};
 +const test: Foo = Foo {foo: 1, bar: 0}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_reorder_impl_items() {
 +    check_doc_test(
 +        "reorder_impl_items",
 +        r#####"
 +trait Foo {
 +    type A;
 +    const B: u8;
 +    fn c();
 +}
 +
 +struct Bar;
 +$0impl Foo for Bar {
 +    const B: u8 = 17;
 +    fn c() {}
 +    type A = String;
 +}
 +"#####,
 +        r#####"
 +trait Foo {
 +    type A;
 +    const B: u8;
 +    fn c();
 +}
 +
 +struct Bar;
 +impl Foo for Bar {
 +    type A = String;
 +    const B: u8 = 17;
 +    fn c() {}
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_char_with_string() {
 +    check_doc_test(
 +        "replace_char_with_string",
 +        r#####"
 +fn main() {
 +    find('{$0');
 +}
 +"#####,
 +        r#####"
 +fn main() {
 +    find("{");
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_derive_with_manual_impl() {
 +    check_doc_test(
 +        "replace_derive_with_manual_impl",
 +        r#####"
 +//- minicore: derive
 +trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
 +#[derive(Deb$0ug, Display)]
 +struct S;
 +"#####,
 +        r#####"
 +trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
 +#[derive(Display)]
 +struct S;
 +
 +impl Debug for S {
 +    $0fn fmt(&self, f: &mut Formatter) -> Result<()> {
 +        f.debug_struct("S").finish()
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_if_let_with_match() {
 +    check_doc_test(
 +        "replace_if_let_with_match",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    $0if let Action::Move { distance } = action {
 +        foo(distance)
 +    } else {
 +        bar()
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    match action {
 +        Action::Move { distance } => foo(distance),
 +        _ => bar(),
 +    }
 +}
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_let_with_if_let() {
 +    check_doc_test(
 +        "replace_let_with_if_let",
 +        r#####"
 +enum Option<T> { Some(T), None }
 +
 +fn main(action: Action) {
 +    $0let x = compute();
 +}
 +
 +fn compute() -> Option<i32> { None }
 +"#####,
 +        r#####"
 +enum Option<T> { Some(T), None }
 +
 +fn main(action: Action) {
 +    if let Some(x) = compute() {
 +    }
 +}
 +
 +fn compute() -> Option<i32> { None }
 +"#####,
 +    )
 +}
 +
 +#[test]
 +fn doctest_replace_match_with_if_let() {
 +    check_doc_test(
 +        "replace_match_with_if_let",
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    $0match action {
 +        Action::Move { distance } => foo(distance),
 +        _ => bar(),
 +    }
 +}
 +"#####,
 +        r#####"
 +enum Action { Move { distance: u32 }, Stop }
 +
 +fn handle(action: Action) {
 +    if let Action::Move { distance } = action {
 +        foo(distance)
 +    } else {
 +        bar()
 +    }
 +}
 +"#####,
 +    )
 +}
 +
++#[test]
++fn doctest_replace_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_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 4d66af9e8d5b8b0933b785d685d55114caf91bfe,0000000000000000000000000000000000000000..588b52cc1ee3a72090d66899fdf89756ad6c48f3
mode 100644,000000..100644
--- /dev/null
@@@ -1,300 -1,0 +1,312 @@@
-                     if let Some(ty) = innermost_ret_ty {
 +//! Completion of names from the current scope in expression position.
 +
 +use hir::ScopeDef;
 +use syntax::ast;
 +
 +use crate::{
 +    completions::record::add_default_update,
 +    context::{ExprCtx, PathCompletionCtx, Qualified},
 +    CompletionContext, Completions,
 +};
 +
 +pub(crate) fn complete_expr_path(
 +    acc: &mut Completions,
 +    ctx: &CompletionContext<'_>,
 +    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
 +    expr_ctx: &ExprCtx,
 +) {
 +    let _p = profile::span("complete_expr_path");
 +    if !ctx.qualifier_ctx.none() {
 +        return;
 +    }
 +
 +    let &ExprCtx {
 +        in_block_expr,
 +        in_loop_body,
 +        after_if_expr,
 +        in_condition,
 +        incomplete_let,
 +        ref ref_expr_parent,
 +        ref is_func_update,
 +        ref innermost_ret_ty,
 +        ref impl_,
 +        in_match_guard,
 +        ..
 +    } = expr_ctx;
 +
 +    let wants_mut_token =
 +        ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false);
 +
 +    let scope_def_applicable = |def| match def {
 +        ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => false,
 +        ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
 +        _ => true,
 +    };
 +
 +    let add_assoc_item = |acc: &mut Completions, item| match item {
 +        hir::AssocItem::Function(func) => acc.add_function(ctx, path_ctx, func, None),
 +        hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
 +        hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
 +    };
 +
 +    match qualified {
 +        Qualified::TypeAnchor { ty: None, trait_: None } => ctx
 +            .traits_in_scope()
 +            .iter()
 +            .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
 +            .for_each(|item| add_assoc_item(acc, item)),
 +        Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
 +            trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item))
 +        }
 +        Qualified::TypeAnchor { ty: Some(ty), trait_: None } => {
 +            if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
 +                cov_mark::hit!(completes_variant_through_alias);
 +                acc.add_enum_variants(ctx, path_ctx, e);
 +            }
 +
 +            ctx.iterate_path_candidates(&ty, |item| {
 +                add_assoc_item(acc, item);
 +            });
 +
 +            // Iterate assoc types separately
 +            ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
 +                if let hir::AssocItem::TypeAlias(ty) = item {
 +                    acc.add_type_alias(ctx, ty)
 +                }
 +                None::<()>
 +            });
 +        }
 +        Qualified::With { resolution: None, .. } => {}
 +        Qualified::With { resolution: Some(resolution), .. } => {
 +            // Add associated types on type parameters and `Self`.
 +            ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| {
 +                acc.add_type_alias(ctx, alias);
 +                None::<()>
 +            });
 +            match resolution {
 +                hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
 +                    let module_scope = module.scope(ctx.db, Some(ctx.module));
 +                    for (name, def) in module_scope {
 +                        if scope_def_applicable(def) {
 +                            acc.add_path_resolution(ctx, path_ctx, name, def);
 +                        }
 +                    }
 +                }
 +                hir::PathResolution::Def(
 +                    def @ (hir::ModuleDef::Adt(_)
 +                    | hir::ModuleDef::TypeAlias(_)
 +                    | hir::ModuleDef::BuiltinType(_)),
 +                ) => {
 +                    let ty = match def {
 +                        hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
 +                        hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
 +                        hir::ModuleDef::BuiltinType(builtin) => {
 +                            cov_mark::hit!(completes_primitive_assoc_const);
 +                            builtin.ty(ctx.db)
 +                        }
 +                        _ => return,
 +                    };
 +
 +                    if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
 +                        cov_mark::hit!(completes_variant_through_alias);
 +                        acc.add_enum_variants(ctx, path_ctx, e);
 +                    }
 +
 +                    // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
 +                    // (where AssocType is defined on a trait, not an inherent impl)
 +
 +                    ctx.iterate_path_candidates(&ty, |item| {
 +                        add_assoc_item(acc, item);
 +                    });
 +
 +                    // Iterate assoc types separately
 +                    ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
 +                        if let hir::AssocItem::TypeAlias(ty) = item {
 +                            acc.add_type_alias(ctx, ty)
 +                        }
 +                        None::<()>
 +                    });
 +                }
 +                hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
 +                    // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
 +                    for item in t.items(ctx.db) {
 +                        add_assoc_item(acc, item);
 +                    }
 +                }
 +                hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
 +                    let ty = match resolution {
 +                        hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
 +                        hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
 +                        _ => return,
 +                    };
 +
 +                    if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
 +                        cov_mark::hit!(completes_variant_through_self);
 +                        acc.add_enum_variants(ctx, path_ctx, e);
 +                    }
 +
 +                    ctx.iterate_path_candidates(&ty, |item| {
 +                        add_assoc_item(acc, item);
 +                    });
 +                }
 +                _ => (),
 +            }
 +        }
 +        Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
 +        Qualified::No => {
 +            acc.add_nameref_keywords_with_colon(ctx);
 +            if let Some(adt) =
 +                ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
 +            {
 +                let self_ty = (|| ctx.sema.to_def(impl_.as_ref()?)?.self_ty(ctx.db).as_adt())();
 +                let complete_self = self_ty == Some(adt);
 +
 +                match adt {
 +                    hir::Adt::Struct(strukt) => {
 +                        let path = ctx
 +                            .module
 +                            .find_use_path(ctx.db, hir::ModuleDef::from(strukt))
 +                            .filter(|it| it.len() > 1);
 +
 +                        acc.add_struct_literal(ctx, path_ctx, strukt, path, None);
 +
 +                        if complete_self {
 +                            acc.add_struct_literal(
 +                                ctx,
 +                                path_ctx,
 +                                strukt,
 +                                None,
 +                                Some(hir::known::SELF_TYPE),
 +                            );
 +                        }
 +                    }
 +                    hir::Adt::Union(un) => {
 +                        let path = ctx
 +                            .module
 +                            .find_use_path(ctx.db, hir::ModuleDef::from(un))
 +                            .filter(|it| it.len() > 1);
 +
 +                        acc.add_union_literal(ctx, un, path, None);
 +                        if complete_self {
 +                            acc.add_union_literal(ctx, un, None, Some(hir::known::SELF_TYPE));
 +                        }
 +                    }
 +                    hir::Adt::Enum(e) => {
 +                        super::enum_variants_with_paths(
 +                            acc,
 +                            ctx,
 +                            e,
 +                            impl_,
 +                            |acc, ctx, variant, path| {
 +                                acc.add_qualified_enum_variant(ctx, path_ctx, variant, path)
 +                            },
 +                        );
 +                    }
 +                }
 +            }
 +            ctx.process_all_names(&mut |name, def| match def {
 +                ScopeDef::ModuleDef(hir::ModuleDef::Trait(t)) => {
 +                    let assocs = t.items_with_supertraits(ctx.db);
 +                    match &*assocs {
 +                        // traits with no assoc items are unusable as expressions since
 +                        // there is no associated item path that can be constructed with them
 +                        [] => (),
 +                        // FIXME: Render the assoc item with the trait qualified
 +                        &[_item] => acc.add_path_resolution(ctx, path_ctx, name, def),
 +                        // FIXME: Append `::` to the thing here, since a trait on its own won't work
 +                        [..] => acc.add_path_resolution(ctx, path_ctx, name, def),
 +                    }
 +                }
 +                _ if scope_def_applicable(def) => acc.add_path_resolution(ctx, path_ctx, name, def),
 +                _ => (),
 +            });
 +
 +            match is_func_update {
 +                Some(record_expr) => {
 +                    let ty = ctx.sema.type_of_expr(&ast::Expr::RecordExpr(record_expr.clone()));
 +
 +                    match ty.as_ref().and_then(|t| t.original.as_adt()) {
 +                        Some(hir::Adt::Union(_)) => (),
 +                        _ => {
 +                            cov_mark::hit!(functional_update);
 +                            let missing_fields =
 +                                ctx.sema.record_literal_missing_fields(record_expr);
 +                            if !missing_fields.is_empty() {
 +                                add_default_update(acc, ctx, ty);
 +                            }
 +                        }
 +                    };
 +                }
 +                None => {
 +                    let mut add_keyword = |kw, snippet| {
 +                        acc.add_keyword_snippet_expr(ctx, incomplete_let, kw, snippet)
 +                    };
 +
 +                    if !in_block_expr {
 +                        add_keyword("unsafe", "unsafe {\n    $0\n}");
 +                    }
 +                    add_keyword("match", "match $1 {\n    $0\n}");
 +                    add_keyword("while", "while $1 {\n    $0\n}");
 +                    add_keyword("while let", "while let $1 = $2 {\n    $0\n}");
 +                    add_keyword("loop", "loop {\n    $0\n}");
 +                    if in_match_guard {
 +                        add_keyword("if", "if $0");
 +                    } else {
 +                        add_keyword("if", "if $1 {\n    $0\n}");
 +                    }
 +                    add_keyword("if let", "if let $1 = $2 {\n    $0\n}");
 +                    add_keyword("for", "for $1 in $2 {\n    $0\n}");
 +                    add_keyword("true", "true");
 +                    add_keyword("false", "false");
 +
 +                    if in_condition || in_block_expr {
 +                        add_keyword("let", "let");
 +                    }
 +
 +                    if after_if_expr {
 +                        add_keyword("else", "else {\n    $0\n}");
 +                        add_keyword("else if", "else if $1 {\n    $0\n}");
 +                    }
 +
 +                    if wants_mut_token {
 +                        add_keyword("mut", "mut ");
 +                    }
 +
 +                    if in_loop_body {
 +                        if in_block_expr {
 +                            add_keyword("continue", "continue;");
 +                            add_keyword("break", "break;");
 +                        } else {
 +                            add_keyword("continue", "continue");
 +                            add_keyword("break", "break");
 +                        }
 +                    }
 +
-                             match (in_block_expr, ty.is_unit()) {
-                                 (true, true) => "return ;",
-                                 (true, false) => "return;",
-                                 (false, true) => "return $0",
-                                 (false, false) => "return",
++                    if let Some(ret_ty) = innermost_ret_ty {
 +                        add_keyword(
 +                            "return",
++                            match (ret_ty.is_unit(), in_block_expr) {
++                                (true, true) => {
++                                    cov_mark::hit!(return_unit_block);
++                                    "return;"
++                                }
++                                (true, false) => {
++                                    cov_mark::hit!(return_unit_no_block);
++                                    "return"
++                                }
++                                (false, true) => {
++                                    cov_mark::hit!(return_value_block);
++                                    "return $0;"
++                                }
++                                (false, false) => {
++                                    cov_mark::hit!(return_value_no_block);
++                                    "return $0"
++                                }
 +                            },
 +                        );
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
index 925081ebf66025552c5a5a1e03bbbf0c2e058176,0000000000000000000000000000000000000000..38e24ebc732d497aa4250f6fe23d06a2c2614f61
mode 100644,000000..100644
--- /dev/null
@@@ -1,672 -1,0 +1,708 @@@
- use crate::tests::{completion_list, BASE_ITEMS_FIXTURE};
 +//! Completion tests for expressions.
 +use expect_test::{expect, Expect};
 +
++use crate::tests::{check_edit, completion_list, BASE_ITEMS_FIXTURE};
 +
 +fn check(ra_fixture: &str, expect: Expect) {
 +    let actual = completion_list(&format!("{}{}", BASE_ITEMS_FIXTURE, ra_fixture));
 +    expect.assert_eq(&actual)
 +}
 +
 +fn check_empty(ra_fixture: &str, expect: Expect) {
 +    let actual = completion_list(ra_fixture);
 +    expect.assert_eq(&actual);
 +}
 +
 +#[test]
 +fn complete_literal_struct_with_a_private_field() {
 +    // `FooDesc.bar` is private, the completion should not be triggered.
 +    check(
 +        r#"
 +mod _69latrick {
 +    pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, bar: bool }
 +    pub fn create_foo(foo_desc: &FooDesc) -> () { () }
 +}
 +
 +fn baz() {
 +    use _69latrick::*;
 +
 +    let foo = create_foo(&$0);
 +}
 +            "#,
 +        // This should not contain `FooDesc {…}`.
 +        expect![[r#"
 +            ct CONST
 +            en Enum
 +            fn baz()         fn()
 +            fn create_foo(…) fn(&FooDesc)
 +            fn function()    fn()
 +            ma makro!(…)     macro_rules! makro
 +            md _69latrick
 +            md module
 +            sc STATIC
 +            st FooDesc
 +            st Record
 +            st Tuple
 +            st Unit
 +            un Union
 +            ev TupleV(…)     TupleV(u32)
 +            bt u32
 +            kw crate::
 +            kw false
 +            kw for
 +            kw if
 +            kw if let
 +            kw loop
 +            kw match
 +            kw mut
 +            kw return
 +            kw self::
 +            kw true
 +            kw unsafe
 +            kw while
 +            kw while let
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn completes_various_bindings() {
 +    check_empty(
 +        r#"
 +fn func(param0 @ (param1, param2): (i32, i32)) {
 +    let letlocal = 92;
 +    if let ifletlocal = 100 {
 +        match 0 {
 +            matcharm => 1 + $0,
 +            otherwise => (),
 +        }
 +    }
 +    let letlocal2 = 44;
 +}
 +"#,
 +        expect![[r#"
 +            fn func(…)    fn((i32, i32))
 +            lc ifletlocal i32
 +            lc letlocal   i32
 +            lc matcharm   i32
 +            lc param0     (i32, i32)
 +            lc param1     i32
 +            lc param2     i32
 +            bt u32
 +            kw crate::
 +            kw false
 +            kw for
 +            kw if
 +            kw if let
 +            kw loop
 +            kw match
 +            kw return
 +            kw self::
 +            kw true
 +            kw unsafe
 +            kw while
 +            kw while let
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn completes_all_the_things_in_fn_body() {
 +    check(
 +        r#"
 +use non_existant::Unresolved;
 +mod qualified { pub enum Enum { Variant } }
 +
 +impl Unit {
 +    fn foo<'lifetime, TypeParam, const CONST_PARAM: usize>(self) {
 +        fn local_func() {}
 +        $0
 +    }
 +}
 +"#,
 +        // `self` is in here twice, once as the module, once as the local
 +        expect![[r#"
 +            ct CONST
 +            cp CONST_PARAM
 +            en Enum
 +            fn function()   fn()
 +            fn local_func() fn()
 +            lc self         Unit
 +            ma makro!(…)    macro_rules! makro
 +            md module
 +            md qualified
 +            sp Self
 +            sc STATIC
 +            st Record
 +            st Tuple
 +            st Unit
 +            tp TypeParam
 +            un Union
 +            ev TupleV(…)    TupleV(u32)
 +            bt u32
 +            kw const
 +            kw crate::
 +            kw enum
 +            kw extern
 +            kw false
 +            kw fn
 +            kw for
 +            kw if
 +            kw if let
 +            kw impl
 +            kw let
 +            kw loop
 +            kw match
 +            kw mod
 +            kw return
 +            kw self::
 +            kw static
 +            kw struct
 +            kw trait
 +            kw true
 +            kw type
 +            kw union
 +            kw unsafe
 +            kw use
 +            kw while
 +            kw while let
 +            me self.foo()   fn(self)
 +            sn macro_rules
 +            sn pd
 +            sn ppd
 +            ?? Unresolved
 +        "#]],
 +    );
 +    check(
 +        r#"
 +use non_existant::Unresolved;
 +mod qualified { pub enum Enum { Variant } }
 +
 +impl Unit {
 +    fn foo<'lifetime, TypeParam, const CONST_PARAM: usize>(self) {
 +        fn local_func() {}
 +        self::$0
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            ct CONST
 +            en Enum
 +            fn function() fn()
 +            ma makro!(…)  macro_rules! makro
 +            md module
 +            md qualified
 +            sc STATIC
 +            st Record
 +            st Tuple
 +            st Unit
 +            tt Trait
 +            un Union
 +            ev TupleV(…)  TupleV(u32)
 +            ?? Unresolved
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn complete_in_block() {
 +    check_empty(
 +        r#"
 +    fn foo() {
 +        if true {
 +            $0
 +        }
 +    }
 +"#,
 +        expect![[r#"
 +            fn foo()       fn()
 +            bt u32
 +            kw const
 +            kw crate::
 +            kw enum
 +            kw extern
 +            kw false
 +            kw fn
 +            kw for
 +            kw if
 +            kw if let
 +            kw impl
 +            kw let
 +            kw loop
 +            kw match
 +            kw mod
 +            kw return
 +            kw self::
 +            kw static
 +            kw struct
 +            kw trait
 +            kw true
 +            kw type
 +            kw union
 +            kw unsafe
 +            kw use
 +            kw while
 +            kw while let
 +            sn macro_rules
 +            sn pd
 +            sn ppd
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn complete_after_if_expr() {
 +    check_empty(
 +        r#"
 +    fn foo() {
 +        if true {}
 +        $0
 +    }
 +"#,
 +        expect![[r#"
 +            fn foo()       fn()
 +            bt u32
 +            kw const
 +            kw crate::
 +            kw else
 +            kw else if
 +            kw enum
 +            kw extern
 +            kw false
 +            kw fn
 +            kw for
 +            kw if
 +            kw if let
 +            kw impl
 +            kw let
 +            kw loop
 +            kw match
 +            kw mod
 +            kw return
 +            kw self::
 +            kw static
 +            kw struct
 +            kw trait
 +            kw true
 +            kw type
 +            kw union
 +            kw unsafe
 +            kw use
 +            kw while
 +            kw while let
 +            sn macro_rules
 +            sn pd
 +            sn ppd
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn complete_in_match_arm() {
 +    check_empty(
 +        r#"
 +    fn foo() {
 +        match () {
 +            () => $0
 +        }
 +    }
 +"#,
 +        expect![[r#"
 +            fn foo()     fn()
 +            bt u32
 +            kw crate::
 +            kw false
 +            kw for
 +            kw if
 +            kw if let
 +            kw loop
 +            kw match
 +            kw return
 +            kw self::
 +            kw true
 +            kw unsafe
 +            kw while
 +            kw while let
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn completes_in_loop_ctx() {
 +    check_empty(
 +        r"fn my() { loop { $0 } }",
 +        expect![[r#"
 +            fn my()        fn()
 +            bt u32
 +            kw break
 +            kw const
 +            kw continue
 +            kw crate::
 +            kw enum
 +            kw extern
 +            kw false
 +            kw fn
 +            kw for
 +            kw if
 +            kw if let
 +            kw impl
 +            kw let
 +            kw loop
 +            kw match
 +            kw mod
 +            kw return
 +            kw self::
 +            kw static
 +            kw struct
 +            kw trait
 +            kw true
 +            kw type
 +            kw union
 +            kw unsafe
 +            kw use
 +            kw while
 +            kw while let
 +            sn macro_rules
 +            sn pd
 +            sn ppd
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn completes_in_let_initializer() {
 +    check_empty(
 +        r#"fn main() { let _ = $0 }"#,
 +        expect![[r#"
 +            fn main()    fn()
 +            bt u32
 +            kw crate::
 +            kw false
 +            kw for
 +            kw if
 +            kw if let
 +            kw loop
 +            kw match
 +            kw return
 +            kw self::
 +            kw true
 +            kw unsafe
 +            kw while
 +            kw while let
 +        "#]],
 +    )
 +}
 +
 +#[test]
 +fn struct_initializer_field_expr() {
 +    check_empty(
 +        r#"
 +struct Foo {
 +    pub f: i32,
 +}
 +fn foo() {
 +    Foo {
 +        f: $0
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            fn foo()     fn()
 +            st Foo
 +            bt u32
 +            kw crate::
 +            kw false
 +            kw for
 +            kw if
 +            kw if let
 +            kw loop
 +            kw match
 +            kw return
 +            kw self::
 +            kw true
 +            kw unsafe
 +            kw while
 +            kw while let
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn shadowing_shows_single_completion() {
 +    cov_mark::check!(shadowing_shows_single_completion);
 +
 +    check_empty(
 +        r#"
 +fn foo() {
 +    let bar = 92;
 +    {
 +        let bar = 62;
 +        drop($0)
 +    }
 +}
 +"#,
 +        expect![[r#"
 +            fn foo()     fn()
 +            lc bar       i32
 +            bt u32
 +            kw crate::
 +            kw false
 +            kw for
 +            kw if
 +            kw if let
 +            kw loop
 +            kw match
 +            kw return
 +            kw self::
 +            kw true
 +            kw unsafe
 +            kw while
 +            kw while let
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn in_macro_expr_frag() {
 +    check_empty(
 +        r#"
 +macro_rules! m { ($e:expr) => { $e } }
 +fn quux(x: i32) {
 +    m!($0);
 +}
 +"#,
 +        expect![[r#"
 +            fn quux(…)   fn(i32)
 +            lc x         i32
 +            ma m!(…)     macro_rules! m
 +            bt u32
 +            kw crate::
 +            kw false
 +            kw for
 +            kw if
 +            kw if let
 +            kw loop
 +            kw match
 +            kw return
 +            kw self::
 +            kw true
 +            kw unsafe
 +            kw while
 +            kw while let
 +        "#]],
 +    );
 +    check_empty(
 +        r"
 +macro_rules! m { ($e:expr) => { $e } }
 +fn quux(x: i32) {
 +    m!(x$0);
 +}
 +",
 +        expect![[r#"
 +            fn quux(…)   fn(i32)
 +            lc x         i32
 +            ma m!(…)     macro_rules! m
 +            bt u32
 +            kw crate::
 +            kw false
 +            kw for
 +            kw if
 +            kw if let
 +            kw loop
 +            kw match
 +            kw return
 +            kw self::
 +            kw true
 +            kw unsafe
 +            kw while
 +            kw while let
 +        "#]],
 +    );
 +    check_empty(
 +        r#"
 +macro_rules! m { ($e:expr) => { $e } }
 +fn quux(x: i32) {
 +    let y = 92;
 +    m!(x$0
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +}
 +
 +#[test]
 +fn enum_qualified() {
 +    check(
 +        r#"
 +impl Enum {
 +    type AssocType = ();
 +    const ASSOC_CONST: () = ();
 +    fn assoc_fn() {}
 +}
 +fn func() {
 +    Enum::$0
 +}
 +"#,
 +        expect![[r#"
 +            ct ASSOC_CONST const ASSOC_CONST: ()
 +            fn assoc_fn()  fn()
 +            ta AssocType   type AssocType = ()
 +            ev RecordV {…} RecordV { field: u32 }
 +            ev TupleV(…)   TupleV(u32)
 +            ev UnitV       UnitV
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn ty_qualified_no_drop() {
 +    check_empty(
 +        r#"
 +//- minicore: drop
 +struct Foo;
 +impl Drop for Foo {
 +    fn drop(&mut self) {}
 +}
 +fn func() {
 +    Foo::$0
 +}
 +"#,
 +        expect![[r#""#]],
 +    );
 +}
 +
 +#[test]
 +fn with_parens() {
 +    check_empty(
 +        r#"
 +enum Enum {
 +    Variant()
 +}
 +impl Enum {
 +    fn variant() -> Self { Enum::Variant() }
 +}
 +fn func() {
 +    Enum::$0()
 +}
 +"#,
 +        expect![[r#"
 +            fn variant fn() -> Enum
 +            ev Variant Variant
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn detail_impl_trait_in_return_position() {
 +    check_empty(
 +        r"
 +//- minicore: sized
 +trait Trait<T> {}
 +fn foo<U>() -> impl Trait<U> {}
 +fn main() {
 +    self::$0
 +}
 +",
 +        expect![[r#"
 +            fn foo()  fn() -> impl Trait<U>
 +            fn main() fn()
 +            tt Trait
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn detail_async_fn() {
 +    check_empty(
 +        r#"
 +//- minicore: future, sized
 +trait Trait<T> {}
 +async fn foo() -> u8 {}
 +async fn bar<U>() -> impl Trait<U> {}
 +fn main() {
 +    self::$0
 +}
 +"#,
 +        expect![[r#"
 +            fn bar()  async fn() -> impl Trait<U>
 +            fn foo()  async fn() -> u8
 +            fn main() fn()
 +            tt Trait
 +        "#]],
 +    );
 +}
 +
 +#[test]
 +fn detail_impl_trait_in_argument_position() {
 +    check_empty(
 +        r"
 +//- minicore: sized
 +trait Trait<T> {}
 +struct Foo;
 +impl Foo {
 +    fn bar<U>(_: impl Trait<U>) {}
 +}
 +fn main() {
 +    Foo::$0
 +}
 +",
 +        expect![[r"
 +            fn bar(…) fn(impl Trait<U>)
 +        "]],
 +    );
 +}
 +
 +#[test]
 +fn complete_record_expr_path() {
 +    check(
 +        r#"
 +struct Zulu;
 +impl Zulu {
 +    fn test() -> Self { }
 +}
 +fn boi(val: Zulu) { }
 +fn main() {
 +    boi(Zulu:: $0 {});
 +}
 +"#,
 +        expect![[r#"
 +            fn test() fn() -> Zulu
 +        "#]],
 +    );
 +}
++
++#[test]
++fn return_unit_block() {
++    cov_mark::check!(return_unit_block);
++    check_edit("return", r#"fn f() { if true { $0 } }"#, r#"fn f() { if true { return; } }"#);
++}
++
++#[test]
++fn return_unit_no_block() {
++    cov_mark::check!(return_unit_no_block);
++    check_edit(
++        "return",
++        r#"fn f() { match () { () => $0 } }"#,
++        r#"fn f() { match () { () => return } }"#,
++    );
++}
++
++#[test]
++fn return_value_block() {
++    cov_mark::check!(return_value_block);
++    check_edit(
++        "return",
++        r#"fn f() -> i32 { if true { $0 } }"#,
++        r#"fn f() -> i32 { if true { return $0; } }"#,
++    );
++}
++
++#[test]
++fn return_value_no_block() {
++    cov_mark::check!(return_value_no_block);
++    check_edit(
++        "return",
++        r#"fn f() -> i32 { match () { () => $0 } }"#,
++        r#"fn f() -> i32 { match () { () => return $0 } }"#,
++    );
++}
index 84bde4d44dbb34dda5249336ec315966d1f0c881,0000000000000000000000000000000000000000..b890e2b58df8f2688923c1262665e7361a747881
mode 100644,000000..100644
--- /dev/null
@@@ -1,460 -1,0 +1,459 @@@
-         | ast::Expr::MacroStmts(_)
 +//! Various helper functions to work with SyntaxNodes.
 +use itertools::Itertools;
 +use parser::T;
 +use syntax::{
 +    ast::{self, HasLoopBody, PathSegmentKind, VisibilityKind},
 +    AstNode, 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)
 +}
index d12594a4ce5c5f77c0f101870c890214ef50731d,0000000000000000000000000000000000000000..0c92e706b3916f65c73df4b6e3945b4e6501a052
mode 100644,000000..100644
--- /dev/null
@@@ -1,30 -1,0 +1,142 @@@
-         "break outside of loop",
 +use crate::{Diagnostic, DiagnosticsContext};
 +
 +// Diagnostic: break-outside-of-loop
 +//
 +// This diagnostic is triggered if the `break` keyword is used outside of a loop.
 +pub(crate) fn break_outside_of_loop(
 +    ctx: &DiagnosticsContext<'_>,
 +    d: &hir::BreakOutsideOfLoop,
 +) -> Diagnostic {
++    let construct = if d.is_break { "break" } else { "continue" };
 +    Diagnostic::new(
 +        "break-outside-of-loop",
-     fn break_outside_of_loop() {
++        format!("{construct} outside of loop"),
 +        ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
 +    )
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::check_diagnostics;
 +
 +    #[test]
- fn foo() { break; }
-          //^^^^^ error: break outside of loop
++    fn outside_of_loop() {
 +        check_diagnostics(
 +            r#"
++fn foo() {
++    break;
++  //^^^^^ error: break outside of loop
++    break 'a;
++  //^^^^^^^^ error: break outside of loop
++    continue;
++  //^^^^^^^^ error: continue outside of loop
++    continue 'a;
++  //^^^^^^^^^^^ error: continue outside of loop
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn try_blocks_are_borders() {
++        check_diagnostics(
++            r#"
++fn foo() {
++    'a: loop {
++        try {
++                break;
++              //^^^^^ error: break outside of loop
++                break 'a;
++              //^^^^^^^^ error: break outside of loop
++                continue;
++              //^^^^^^^^ error: continue outside of loop
++                continue 'a;
++              //^^^^^^^^^^^ error: continue outside of loop
++        };
++    }
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn async_blocks_are_borders() {
++        check_diagnostics(
++            r#"
++fn foo() {
++    'a: loop {
++        try {
++                break;
++              //^^^^^ error: break outside of loop
++                break 'a;
++              //^^^^^^^^ error: break outside of loop
++                continue;
++              //^^^^^^^^ error: continue outside of loop
++                continue 'a;
++              //^^^^^^^^^^^ error: continue outside of loop
++        };
++    }
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn closures_are_borders() {
++        check_diagnostics(
++            r#"
++fn foo() {
++    'a: loop {
++        try {
++                break;
++              //^^^^^ error: break outside of loop
++                break 'a;
++              //^^^^^^^^ error: break outside of loop
++                continue;
++              //^^^^^^^^ error: continue outside of loop
++                continue 'a;
++              //^^^^^^^^^^^ error: continue outside of loop
++        };
++    }
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn blocks_pass_through() {
++        check_diagnostics(
++            r#"
++fn foo() {
++    'a: loop {
++        {
++            break;
++            break 'a;
++            continue;
++            continue 'a;
++        }
++    }
++}
++"#,
++        );
++    }
++
++    #[test]
++    fn label_blocks() {
++        check_diagnostics(
++            r#"
++fn foo() {
++    'a: {
++        break;
++      //^^^^^ error: break outside of loop
++        break 'a;
++        continue;
++      //^^^^^^^^ error: continue outside of loop
++        continue 'a;
++      //^^^^^^^^^^^ error: continue outside of loop
++    }
++}
 +"#,
 +        );
 +    }
 +}
index 5fcaf405b14b94887cc6e81c1dd05db061eac143,0000000000000000000000000000000000000000..c24430ce604692de844a2cc86cea6e0e2bc24abe
mode 100644,000000..100644
--- /dev/null
@@@ -1,1012 -1,0 +1,1056 @@@
 +use hir::InFile;
 +
 +use crate::{Diagnostic, DiagnosticsContext};
 +
 +// Diagnostic: missing-match-arm
 +//
 +// This diagnostic is triggered if `match` block is missing one or more match arms.
 +pub(crate) fn missing_match_arms(
 +    ctx: &DiagnosticsContext<'_>,
 +    d: &hir::MissingMatchArms,
 +) -> Diagnostic {
 +    Diagnostic::new(
 +        "missing-match-arm",
 +        format!("missing match arm: {}", d.uncovered_patterns),
 +        ctx.sema.diagnostics_display_range(InFile::new(d.file, d.match_expr.clone().into())).range,
 +    )
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::tests::check_diagnostics;
 +
 +    fn check_diagnostics_no_bails(ra_fixture: &str) {
 +        cov_mark::check_count!(validate_match_bailed_out, 0);
 +        crate::tests::check_diagnostics(ra_fixture)
 +    }
 +
 +    #[test]
 +    fn empty_tuple() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match () { }
 +        //^^ error: missing match arm: type `()` is non-empty
 +    match (()) { }
 +        //^^^^ error: missing match arm: type `()` is non-empty
 +
 +    match () { _ => (), }
 +    match () { () => (), }
 +    match (()) { (()) => (), }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn tuple_of_two_empty_tuple() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match ((), ()) { }
 +        //^^^^^^^^ error: missing match arm: type `((), ())` is non-empty
 +
 +    match ((), ()) { ((), ()) => (), }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn boolean() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn test_main() {
 +    match false { }
 +        //^^^^^ error: missing match arm: type `bool` is non-empty
 +    match false { true => (), }
 +        //^^^^^ error: missing match arm: `false` not covered
 +    match (false, true) {}
 +        //^^^^^^^^^^^^^ error: missing match arm: type `(bool, bool)` is non-empty
 +    match (false, true) { (true, true) => (), }
 +        //^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
 +    match (false, true) {
 +        //^^^^^^^^^^^^^ error: missing match arm: `(true, true)` not covered
 +        (false, true) => (),
 +        (false, false) => (),
 +        (true, false) => (),
 +    }
 +    match (false, true) { (true, _x) => (), }
 +        //^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
 +
 +    match false { true => (), false => (), }
 +    match (false, true) {
 +        (false, _) => (),
 +        (true, false) => (),
 +        (_, true) => (),
 +    }
 +    match (false, true) {
 +        (true, true) => (),
 +        (true, false) => (),
 +        (false, true) => (),
 +        (false, false) => (),
 +    }
 +    match (false, true) {
 +        (true, _x) => (),
 +        (false, true) => (),
 +        (false, false) => (),
 +    }
 +    match (false, true, false) {
 +        (false, ..) => (),
 +        (true, ..) => (),
 +    }
 +    match (false, true, false) {
 +        (.., false) => (),
 +        (.., true) => (),
 +    }
 +    match (false, true, false) { (..) => (), }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn tuple_of_tuple_and_bools() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match (false, ((), false)) {}
 +        //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: type `(bool, ((), bool))` is non-empty
 +    match (false, ((), false)) { (true, ((), true)) => (), }
 +        //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
 +    match (false, ((), false)) { (true, _) => (), }
 +        //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
 +
 +    match (false, ((), false)) {
 +        (true, ((), true)) => (),
 +        (true, ((), false)) => (),
 +        (false, ((), true)) => (),
 +        (false, ((), false)) => (),
 +    }
 +    match (false, ((), false)) {
 +        (true, ((), true)) => (),
 +        (true, ((), false)) => (),
 +        (false, _) => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enums() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either { A, B, }
 +
 +fn main() {
 +    match Either::A { }
 +        //^^^^^^^^^ error: missing match arm: `A` and `B` not covered
 +    match Either::B { Either::A => (), }
 +        //^^^^^^^^^ error: missing match arm: `B` not covered
 +
 +    match &Either::B {
 +        //^^^^^^^^^^ error: missing match arm: `&B` not covered
 +        Either::A => (),
 +    }
 +
 +    match Either::B {
 +        Either::A => (), Either::B => (),
 +    }
 +    match &Either::B {
 +        Either::A => (), Either::B => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_containing_bool() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either { A(bool), B }
 +
 +fn main() {
 +    match Either::B { }
 +        //^^^^^^^^^ error: missing match arm: `A(_)` and `B` not covered
 +    match Either::B {
 +        //^^^^^^^^^ error: missing match arm: `A(false)` not covered
 +        Either::A(true) => (), Either::B => ()
 +    }
 +
 +    match Either::B {
 +        Either::A(true) => (),
 +        Either::A(false) => (),
 +        Either::B => (),
 +    }
 +    match Either::B {
 +        Either::B => (),
 +        _ => (),
 +    }
 +    match Either::B {
 +        Either::A(_) => (),
 +        Either::B => (),
 +    }
 +
 +}
 +        "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_different_sizes() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either { A(bool), B(bool, bool) }
 +
 +fn main() {
 +    match Either::A(false) {
 +        //^^^^^^^^^^^^^^^^ error: missing match arm: `B(true, _)` not covered
 +        Either::A(_) => (),
 +        Either::B(false, _) => (),
 +    }
 +
 +    match Either::A(false) {
 +        Either::A(_) => (),
 +        Either::B(true, _) => (),
 +        Either::B(false, _) => (),
 +    }
 +    match Either::A(false) {
 +        Either::A(true) | Either::A(false) => (),
 +        Either::B(true, _) => (),
 +        Either::B(false, _) => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn tuple_of_enum_no_diagnostic() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either { A(bool), B(bool, bool) }
 +enum Either2 { C, D }
 +
 +fn main() {
 +    match (Either::A(false), Either2::C) {
 +        (Either::A(true), _) | (Either::A(false), _) => (),
 +        (Either::B(true, _), Either2::C) => (),
 +        (Either::B(false, _), Either2::C) => (),
 +        (Either::B(_, _), Either2::D) => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn or_pattern_no_diagnostic() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either {A, B}
 +
 +fn main() {
 +    match (Either::A, Either::B) {
 +        (Either::A | Either::B, _) => (),
 +    }
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn mismatched_types() {
 +        cov_mark::check_count!(validate_match_bailed_out, 4);
 +        // Match statements with arms that don't match the
 +        // expression pattern do not fire this diagnostic.
 +        check_diagnostics(
 +            r#"
 +enum Either { A, B }
 +enum Either2 { C, D }
 +
 +fn main() {
 +    match Either::A {
 +        Either2::C => (),
 +        Either2::D => (),
 +    }
 +    match (true, false) {
 +        (true, false, true) => (),
 +        (true) => (),
 +      // ^^^^  error: expected (bool, bool), found bool
 +    }
 +    match (true, false) { (true,) => {} }
 +    match (0) { () => () }
 +    match Unresolved::Bar { Unresolved::Baz => () }
 +}
 +        "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn mismatched_types_in_or_patterns() {
 +        cov_mark::check_count!(validate_match_bailed_out, 2);
 +        check_diagnostics(
 +            r#"
 +fn main() {
 +    match false { true | () => {} }
 +    match (false,) { (true | (),) => {} }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn malformed_match_arm_tuple_enum_missing_pattern() {
 +        // We are testing to be sure we don't panic here when the match
 +        // arm `Either::B` is missing its pattern.
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either { A, B(u32) }
 +
 +fn main() {
 +    match Either::A {
 +        Either::A => (),
 +        Either::B() => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn malformed_match_arm_extra_fields() {
 +        cov_mark::check_count!(validate_match_bailed_out, 2);
 +        check_diagnostics(
 +            r#"
 +enum A { B(isize, isize), C }
 +fn main() {
 +    match A::B(1, 2) {
 +        A::B(_, _, _) => (),
 +    }
 +    match A::B(1, 2) {
 +        A::C(_) => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn expr_diverges() {
 +        cov_mark::check_count!(validate_match_bailed_out, 2);
 +        check_diagnostics(
 +            r#"
 +enum Either { A, B }
 +
 +fn main() {
 +    match loop {} {
 +        Either::A => (),
 +        Either::B => (),
 +    }
 +    match loop {} {
 +        Either::A => (),
 +    }
 +    match loop { break Foo::A } {
 +        //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `B` not covered
 +        Either::A => (),
 +    }
 +    match loop { break Foo::A } {
 +        Either::A => (),
 +        Either::B => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn expr_partially_diverges() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either<T> { A(T), B }
 +
 +fn foo() -> Either<!> { Either::B }
 +fn main() -> u32 {
 +    match foo() {
 +        Either::A(val) => val,
 +        Either::B => 0,
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_record() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either { A { foo: bool }, B }
 +
 +fn main() {
 +    let a = Either::A { foo: true };
 +    match a { }
 +        //^ error: missing match arm: `A { .. }` and `B` not covered
 +    match a { Either::A { foo: true } => () }
 +        //^ error: missing match arm: `B` not covered
 +    match a {
 +        Either::A { } => (),
 +      //^^^^^^^^^ 💡 error: missing structure fields:
 +      //        | - foo
 +        Either::B => (),
 +    }
 +    match a {
 +        //^ error: missing match arm: `B` not covered
 +        Either::A { } => (),
 +    } //^^^^^^^^^ 💡 error: missing structure fields:
 +      //        | - foo
 +
 +    match a {
 +        Either::A { foo: true } => (),
 +        Either::A { foo: false } => (),
 +        Either::B => (),
 +    }
 +    match a {
 +        Either::A { foo: _ } => (),
 +        Either::B => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_record_fields_out_of_order() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either {
 +    A { foo: bool, bar: () },
 +    B,
 +}
 +
 +fn main() {
 +    let a = Either::A { foo: true, bar: () };
 +    match a {
 +        //^ error: missing match arm: `B` not covered
 +        Either::A { bar: (), foo: false } => (),
 +        Either::A { foo: true, bar: () } => (),
 +    }
 +
 +    match a {
 +        Either::A { bar: (), foo: false } => (),
 +        Either::A { foo: true, bar: () } => (),
 +        Either::B => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_record_ellipsis() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either {
 +    A { foo: bool, bar: bool },
 +    B,
 +}
 +
 +fn main() {
 +    let a = Either::B;
 +    match a {
 +        //^ error: missing match arm: `A { foo: false, .. }` not covered
 +        Either::A { foo: true, .. } => (),
 +        Either::B => (),
 +    }
 +    match a {
 +        //^ error: missing match arm: `B` not covered
 +        Either::A { .. } => (),
 +    }
 +
 +    match a {
 +        Either::A { foo: true, .. } => (),
 +        Either::A { foo: false, .. } => (),
 +        Either::B => (),
 +    }
 +
 +    match a {
 +        Either::A { .. } => (),
 +        Either::B => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_tuple_partial_ellipsis() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Either {
 +    A(bool, bool, bool, bool),
 +    B,
 +}
 +
 +fn main() {
 +    match Either::B {
 +        //^^^^^^^^^ error: missing match arm: `A(false, _, _, true)` not covered
 +        Either::A(true, .., true) => (),
 +        Either::A(true, .., false) => (),
 +        Either::A(false, .., false) => (),
 +        Either::B => (),
 +    }
 +    match Either::B {
 +        //^^^^^^^^^ error: missing match arm: `A(false, _, _, false)` not covered
 +        Either::A(true, .., true) => (),
 +        Either::A(true, .., false) => (),
 +        Either::A(.., true) => (),
 +        Either::B => (),
 +    }
 +
 +    match Either::B {
 +        Either::A(true, .., true) => (),
 +        Either::A(true, .., false) => (),
 +        Either::A(false, .., true) => (),
 +        Either::A(false, .., false) => (),
 +        Either::B => (),
 +    }
 +    match Either::B {
 +        Either::A(true, .., true) => (),
 +        Either::A(true, .., false) => (),
 +        Either::A(.., true) => (),
 +        Either::A(.., false) => (),
 +        Either::B => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn never() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Never {}
 +
 +fn enum_(never: Never) {
 +    match never {}
 +}
 +fn enum_ref(never: &Never) {
 +    match never {}
 +        //^^^^^ error: missing match arm: type `&Never` is non-empty
 +}
 +fn bang(never: !) {
 +    match never {}
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn unknown_type() {
 +        cov_mark::check_count!(validate_match_bailed_out, 1);
 +
 +        check_diagnostics(
 +            r#"
 +enum Option<T> { Some(T), None }
 +
 +fn main() {
 +    // `Never` is deliberately not defined so that it's an uninferred type.
 +    match Option::<Never>::None {
 +        None => (),
 +        Some(never) => match never {},
 +    }
 +    match Option::<Never>::None {
 +        //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `None` not covered
 +        Option::Some(_never) => {},
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match (false, true, false) {
 +        //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(true, _, _)` not covered
 +        (false, ..) => (),
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match (false, true, false) {
 +        //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(_, _, true)` not covered
 +        (.., false) => (),
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match (false, true, false) {
 +        //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(false, _, _)` not covered
 +        (true, .., false) => (),
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn record_struct() {
 +        check_diagnostics_no_bails(
 +            r#"struct Foo { a: bool }
 +fn main(f: Foo) {
 +    match f {}
 +        //^ error: missing match arm: type `Foo` is non-empty
 +    match f { Foo { a: true } => () }
 +        //^ error: missing match arm: `Foo { a: false }` not covered
 +    match &f { Foo { a: true } => () }
 +        //^^ error: missing match arm: `&Foo { a: false }` not covered
 +    match f { Foo { a: _ } => () }
 +    match f {
 +        Foo { a: true } => (),
 +        Foo { a: false } => (),
 +    }
 +    match &f {
 +        Foo { a: true } => (),
 +        Foo { a: false } => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn tuple_struct() {
 +        check_diagnostics_no_bails(
 +            r#"struct Foo(bool);
 +fn main(f: Foo) {
 +    match f {}
 +        //^ error: missing match arm: type `Foo` is non-empty
 +    match f { Foo(true) => () }
 +        //^ error: missing match arm: `Foo(false)` not covered
 +    match f {
 +        Foo(true) => (),
 +        Foo(false) => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn unit_struct() {
 +        check_diagnostics_no_bails(
 +            r#"struct Foo;
 +fn main(f: Foo) {
 +    match f {}
 +        //^ error: missing match arm: type `Foo` is non-empty
 +    match f { Foo => () }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn record_struct_ellipsis() {
 +        check_diagnostics_no_bails(
 +            r#"struct Foo { foo: bool, bar: bool }
 +fn main(f: Foo) {
 +    match f { Foo { foo: true, .. } => () }
 +        //^ error: missing match arm: `Foo { foo: false, .. }` not covered
 +    match f {
 +        //^ error: missing match arm: `Foo { foo: false, bar: true }` not covered
 +        Foo { foo: true, .. } => (),
 +        Foo { bar: false, .. } => ()
 +    }
 +    match f { Foo { .. } => () }
 +    match f {
 +        Foo { foo: true, .. } => (),
 +        Foo { foo: false, .. } => ()
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn internal_or() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    enum Either { A(bool), B }
 +    match Either::B {
 +        //^^^^^^^^^ error: missing match arm: `B` not covered
 +        Either::A(true | false) => (),
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn no_panic_at_unimplemented_subpattern_type() {
 +        cov_mark::check_count!(validate_match_bailed_out, 1);
 +
 +        check_diagnostics(
 +            r#"
 +struct S { a: char}
 +fn main(v: S) {
 +    match v { S{ a }      => {} }
 +    match v { S{ a: _x }  => {} }
 +    match v { S{ a: 'a' } => {} }
 +    match v { S{..}       => {} }
 +    match v { _           => {} }
 +    match v { }
 +        //^ error: missing match arm: type `S` is non-empty
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn binding() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match true {
 +        _x @ true => {}
 +        false     => {}
 +    }
 +    match true { _x @ true => {} }
 +        //^^^^ error: missing match arm: `false` not covered
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn binding_ref_has_correct_type() {
 +        cov_mark::check_count!(validate_match_bailed_out, 1);
 +
 +        // Asserts `PatKind::Binding(ref _x): bool`, not &bool.
 +        // If that's not true match checking will panic with "incompatible constructors"
 +        // FIXME: make facilities to test this directly like `tests::check_infer(..)`
 +        check_diagnostics(
 +            r#"
 +enum Foo { A }
 +fn main() {
 +    // FIXME: this should not bail out but current behavior is such as the old algorithm.
 +    // ExprValidator::validate_match(..) checks types of top level patterns incorrectly.
 +    match Foo::A {
 +        ref _x => {}
 +        Foo::A => {}
 +    }
 +    match (true,) {
 +        (ref _x,) => {}
 +        (true,) => {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn enum_non_exhaustive() {
 +        check_diagnostics_no_bails(
 +            r#"
 +//- /lib.rs crate:lib
 +#[non_exhaustive]
 +pub enum E { A, B }
 +fn _local() {
 +    match E::A { _ => {} }
 +    match E::A {
 +        E::A => {}
 +        E::B => {}
 +    }
 +    match E::A {
 +        E::A | E::B => {}
 +    }
 +}
 +
 +//- /main.rs crate:main deps:lib
 +use lib::E;
 +fn main() {
 +    match E::A { _ => {} }
 +    match E::A {
 +        //^^^^ error: missing match arm: `_` not covered
 +        E::A => {}
 +        E::B => {}
 +    }
 +    match E::A {
 +        //^^^^ error: missing match arm: `_` not covered
 +        E::A | E::B => {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn match_guard() {
 +        check_diagnostics_no_bails(
 +            r#"
 +fn main() {
 +    match true {
 +        true if false => {}
 +        true          => {}
 +        false         => {}
 +    }
 +    match true {
 +        //^^^^ error: missing match arm: `true` not covered
 +        true if false => {}
 +        false         => {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn pattern_type_is_of_substitution() {
 +        check_diagnostics_no_bails(
 +            r#"
 +struct Foo<T>(T);
 +struct Bar;
 +fn main() {
 +    match Foo(Bar) {
 +        _ | Foo(Bar) => {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn record_struct_no_such_field() {
 +        cov_mark::check_count!(validate_match_bailed_out, 1);
 +
 +        check_diagnostics(
 +            r#"
 +struct Foo { }
 +fn main(f: Foo) {
 +    match f { Foo { bar } => () }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn match_ergonomics_issue_9095() {
 +        check_diagnostics_no_bails(
 +            r#"
 +enum Foo<T> { A(T) }
 +fn main() {
 +    match &Foo::A(true) {
 +        _ => {}
 +        Foo::A(_) => {}
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn normalize_field_ty() {
 +        check_diagnostics_no_bails(
 +            r"
 +trait Trait { type Projection; }
 +enum E {Foo, Bar}
 +struct A;
 +impl Trait for A { type Projection = E; }
 +struct Next<T: Trait>(T::Projection);
 +static __: () = {
 +    let n: Next<A> = Next(E::Foo);
 +    match n { Next(E::Foo) => {} }
 +    //    ^ error: missing match arm: `Next(Bar)` not covered
 +    match n { Next(E::Foo | E::Bar) => {} }
 +    match n { Next(E::Foo | _     ) => {} }
 +    match n { Next(_      | E::Bar) => {} }
 +    match n {      _ | Next(E::Bar) => {} }
 +    match &n { Next(E::Foo | E::Bar) => {} }
 +    match &n {      _ | Next(E::Bar) => {} }
 +};",
 +        );
 +    }
 +
 +    #[test]
 +    fn binding_mode_by_ref() {
 +        check_diagnostics_no_bails(
 +            r"
 +enum E{ A, B }
 +fn foo() {
 +    match &E::A {
 +        E::A => {}
 +        x => {}
 +    }
 +}",
 +        );
 +    }
 +
 +    #[test]
 +    fn macro_or_pat() {
 +        check_diagnostics_no_bails(
 +            r#"
 +macro_rules! m {
 +    () => {
 +        Enum::Type1 | Enum::Type2
 +    };
 +}
 +
 +enum Enum {
 +    Type1,
 +    Type2,
 +    Type3,
 +}
 +
 +fn f(ty: Enum) {
 +    match ty {
 +        //^^ error: missing match arm: `Type3` not covered
 +        m!() => (),
 +    }
 +
 +    match ty {
 +        m!() | Enum::Type3 => ()
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn unexpected_ty_fndef() {
 +        cov_mark::check!(validate_match_bailed_out);
 +        check_diagnostics(
 +            r"
 +enum Exp {
 +    Tuple(()),
 +}
 +fn f() {
 +    match __unknown {
 +        Exp::Tuple => {}
 +    }
 +}",
 +        );
 +    }
 +
++    mod rust_unstable {
++        use super::*;
++
++        #[test]
++        fn rfc_1872_exhaustive_patterns() {
++            check_diagnostics_no_bails(
++                r"
++//- minicore: option, result
++#![feature(exhaustive_patterns)]
++enum Void {}
++fn test() {
++    match None::<!> { None => () }
++    match Result::<u8, !>::Ok(2) { Ok(_) => () }
++    match Result::<u8, Void>::Ok(2) { Ok(_) => () }
++    match (2, loop {}) {}
++    match Result::<!, !>::Ok(loop {}) {}
++    match (&loop {}) {} // https://github.com/rust-lang/rust/issues/50642#issuecomment-388234919
++    //    ^^^^^^^^^^ error: missing match arm: type `&!` is non-empty
++}",
++            );
++        }
++
++        #[test]
++        fn rfc_1872_private_uninhabitedness() {
++            check_diagnostics_no_bails(
++                r"
++//- minicore: option
++//- /lib.rs crate:lib
++#![feature(exhaustive_patterns)]
++pub struct PrivatelyUninhabited { private_field: Void }
++enum Void {}
++fn test_local(x: Option<PrivatelyUninhabited>) {
++    match x {}
++} //      ^ error: missing match arm: `None` not covered
++//- /main.rs crate:main deps:lib
++#![feature(exhaustive_patterns)]
++fn test(x: Option<lib::PrivatelyUninhabited>) {
++    match x {}
++    //    ^ error: missing match arm: `None` and `Some(_)` not covered
++}",
++            );
++        }
++    }
++
 +    mod false_negatives {
 +        //! The implementation of match checking here is a work in progress. As we roll this out, we
 +        //! prefer false negatives to false positives (ideally there would be no false positives). This
 +        //! test module should document known false negatives. Eventually we will have a complete
 +        //! implementation of match checking and this module will be empty.
 +        //!
 +        //! The reasons for documenting known false negatives:
 +        //!
 +        //!   1. It acts as a backlog of work that can be done to improve the behavior of the system.
 +        //!   2. It ensures the code doesn't panic when handling these cases.
 +        use super::*;
 +
 +        #[test]
 +        fn integers() {
 +            cov_mark::check_count!(validate_match_bailed_out, 1);
 +
 +            // We don't currently check integer exhaustiveness.
 +            check_diagnostics(
 +                r#"
 +fn main() {
 +    match 5 {
 +        10 => (),
 +        11..20 => (),
 +    }
 +}
 +"#,
 +            );
 +        }
 +
 +        #[test]
 +        fn reference_patterns_at_top_level() {
 +            cov_mark::check_count!(validate_match_bailed_out, 1);
 +
 +            check_diagnostics(
 +                r#"
 +fn main() {
 +    match &false {
 +        &true => {}
 +    }
 +}
 +            "#,
 +            );
 +        }
 +
 +        #[test]
 +        fn reference_patterns_in_fields() {
 +            cov_mark::check_count!(validate_match_bailed_out, 2);
 +
 +            check_diagnostics(
 +                r#"
 +fn main() {
 +    match (&false,) {
 +        (true,) => {}
 +    }
 +    match (&false,) {
 +        (&true,) => {}
 +    }
 +}
 +            "#,
 +            );
 +        }
 +    }
 +}
index ed19784d1fa49d11355835d94be8b83983f75792,0000000000000000000000000000000000000000..e9034daefa8d46c1dea2afce1e07683f52f82f66
mode 100644,000000..100644
--- /dev/null
@@@ -1,2818 -1,0 +1,2818 @@@
- trait Sync {}
 +use either::Either;
 +use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo};
 +use ide_db::{
 +    base_db::FileRange, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, FxHashMap,
 +    RootDatabase,
 +};
 +use itertools::Itertools;
 +use stdx::to_lower_snake_case;
 +use syntax::{
 +    ast::{self, AstNode, HasArgList, HasGenericParams, HasName, UnaryOp},
 +    match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
 +    TextSize, T,
 +};
 +
 +use crate::FileId;
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub struct InlayHintsConfig {
 +    pub render_colons: bool,
 +    pub type_hints: bool,
 +    pub parameter_hints: bool,
 +    pub chaining_hints: bool,
 +    pub reborrow_hints: ReborrowHints,
 +    pub closure_return_type_hints: ClosureReturnTypeHints,
 +    pub binding_mode_hints: bool,
 +    pub lifetime_elision_hints: LifetimeElisionHints,
 +    pub param_names_for_lifetime_elision_hints: bool,
 +    pub hide_named_constructor_hints: bool,
 +    pub hide_closure_initialization_hints: bool,
 +    pub max_length: Option<usize>,
 +    pub closing_brace_hints_min_lines: Option<usize>,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum ClosureReturnTypeHints {
 +    Always,
 +    WithBlock,
 +    Never,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum LifetimeElisionHints {
 +    Always,
 +    SkipTrivial,
 +    Never,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum ReborrowHints {
 +    Always,
 +    MutableOnly,
 +    Never,
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +pub enum InlayKind {
 +    BindingModeHint,
 +    ChainingHint,
 +    ClosingBraceHint,
 +    ClosureReturnTypeHint,
 +    GenericParamListHint,
 +    ImplicitReborrowHint,
 +    LifetimeHint,
 +    ParameterHint,
 +    TypeHint,
 +}
 +
 +#[derive(Debug)]
 +pub struct InlayHint {
 +    pub range: TextRange,
 +    pub kind: InlayKind,
 +    pub label: String,
 +    pub tooltip: Option<InlayTooltip>,
 +}
 +
 +#[derive(Debug)]
 +pub enum InlayTooltip {
 +    String(String),
 +    HoverRanged(FileId, TextRange),
 +    HoverOffset(FileId, TextSize),
 +}
 +
 +// Feature: Inlay Hints
 +//
 +// rust-analyzer shows additional information inline with the source code.
 +// Editors usually render this using read-only virtual text snippets interspersed with code.
 +//
 +// rust-analyzer by default shows hints for
 +//
 +// * types of local variables
 +// * names of function arguments
 +// * types of chained expressions
 +//
 +// Optionally, one can enable additional hints for
 +//
 +// * return types of closure expressions
 +// * elided lifetimes
 +// * compiler inserted reborrows
 +//
 +// |===
 +// | Editor  | Action Name
 +//
 +// | VS Code | **rust-analyzer: Toggle inlay hints*
 +// |===
 +//
 +// image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[]
 +pub(crate) fn inlay_hints(
 +    db: &RootDatabase,
 +    file_id: FileId,
 +    range_limit: Option<FileRange>,
 +    config: &InlayHintsConfig,
 +) -> Vec<InlayHint> {
 +    let _p = profile::span("inlay_hints");
 +    let sema = Semantics::new(db);
 +    let file = sema.parse(file_id);
 +    let file = file.syntax();
 +
 +    let mut acc = Vec::new();
 +
 +    if let Some(scope) = sema.scope(&file) {
 +        let famous_defs = FamousDefs(&sema, scope.krate());
 +
 +        let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node);
 +        match range_limit {
 +            Some(FileRange { range, .. }) => match file.covering_element(range) {
 +                NodeOrToken::Token(_) => return acc,
 +                NodeOrToken::Node(n) => n
 +                    .descendants()
 +                    .filter(|descendant| range.intersect(descendant.text_range()).is_some())
 +                    .for_each(hints),
 +            },
 +            None => file.descendants().for_each(hints),
 +        };
 +    }
 +
 +    acc
 +}
 +
 +fn hints(
 +    hints: &mut Vec<InlayHint>,
 +    famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
 +    config: &InlayHintsConfig,
 +    file_id: FileId,
 +    node: SyntaxNode,
 +) {
 +    closing_brace_hints(hints, sema, config, file_id, node.clone());
 +    match_ast! {
 +        match node {
 +            ast::Expr(expr) => {
 +                chaining_hints(hints, sema, &famous_defs, config, file_id, &expr);
 +                match expr {
 +                    ast::Expr::CallExpr(it) => param_name_hints(hints, sema, config, ast::Expr::from(it)),
 +                    ast::Expr::MethodCallExpr(it) => {
 +                        param_name_hints(hints, sema, config, ast::Expr::from(it))
 +                    }
 +                    ast::Expr::ClosureExpr(it) => closure_ret_hints(hints, sema, &famous_defs, config, file_id, it),
 +                    // We could show reborrows for all expressions, but usually that is just noise to the user
 +                    // and the main point here is to show why "moving" a mutable reference doesn't necessarily move it
 +                    ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
 +                    _ => None,
 +                }
 +            },
 +            ast::Pat(it) => {
 +                binding_mode_hints(hints, sema, config, &it);
 +                if let ast::Pat::IdentPat(it) = it {
 +                    bind_pat_hints(hints, sema, config, file_id, &it);
 +                }
 +                Some(())
 +            },
 +            ast::Item(it) => match it {
 +                // FIXME: record impl lifetimes so they aren't being reused in assoc item lifetime inlay hints
 +                ast::Item::Impl(_) => None,
 +                ast::Item::Fn(it) => fn_lifetime_fn_hints(hints, config, it),
 +                // static type elisions
 +                ast::Item::Static(it) => implicit_static_hints(hints, config, Either::Left(it)),
 +                ast::Item::Const(it) => implicit_static_hints(hints, config, Either::Right(it)),
 +                _ => None,
 +            },
 +            // FIXME: fn-ptr type, dyn fn type, and trait object type elisions
 +            ast::Type(_) => None,
 +            _ => None,
 +        }
 +    };
 +}
 +
 +fn closing_brace_hints(
 +    acc: &mut Vec<InlayHint>,
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &InlayHintsConfig,
 +    file_id: FileId,
 +    node: SyntaxNode,
 +) -> Option<()> {
 +    let min_lines = config.closing_brace_hints_min_lines?;
 +
 +    let name = |it: ast::Name| it.syntax().text_range().start();
 +
 +    let mut closing_token;
 +    let (label, name_offset) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
 +        closing_token = item_list.r_curly_token()?;
 +
 +        let parent = item_list.syntax().parent()?;
 +        match_ast! {
 +            match parent {
 +                ast::Impl(imp) => {
 +                    let imp = sema.to_def(&imp)?;
 +                    let ty = imp.self_ty(sema.db);
 +                    let trait_ = imp.trait_(sema.db);
 +
 +                    (match trait_ {
 +                        Some(tr) => format!("impl {} for {}", tr.name(sema.db), ty.display_truncated(sema.db, config.max_length)),
 +                        None => format!("impl {}", ty.display_truncated(sema.db, config.max_length)),
 +                    }, None)
 +                },
 +                ast::Trait(tr) => {
 +                    (format!("trait {}", tr.name()?), tr.name().map(name))
 +                },
 +                _ => return None,
 +            }
 +        }
 +    } else if let Some(list) = ast::ItemList::cast(node.clone()) {
 +        closing_token = list.r_curly_token()?;
 +
 +        let module = ast::Module::cast(list.syntax().parent()?)?;
 +        (format!("mod {}", module.name()?), module.name().map(name))
 +    } else if let Some(block) = ast::BlockExpr::cast(node.clone()) {
 +        closing_token = block.stmt_list()?.r_curly_token()?;
 +
 +        let parent = block.syntax().parent()?;
 +        match_ast! {
 +            match parent {
 +                ast::Fn(it) => {
 +                    // FIXME: this could include parameters, but `HirDisplay` prints too much info
 +                    // and doesn't respect the max length either, so the hints end up way too long
 +                    (format!("fn {}", it.name()?), it.name().map(name))
 +                },
 +                ast::Static(it) => (format!("static {}", it.name()?), it.name().map(name)),
 +                ast::Const(it) => {
 +                    if it.underscore_token().is_some() {
 +                        ("const _".into(), None)
 +                    } else {
 +                        (format!("const {}", it.name()?), it.name().map(name))
 +                    }
 +                },
 +                _ => return None,
 +            }
 +        }
 +    } else if let Some(mac) = ast::MacroCall::cast(node.clone()) {
 +        let last_token = mac.syntax().last_token()?;
 +        if last_token.kind() != T![;] && last_token.kind() != SyntaxKind::R_CURLY {
 +            return None;
 +        }
 +        closing_token = last_token;
 +
 +        (
 +            format!("{}!", mac.path()?),
 +            mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range().start()),
 +        )
 +    } else {
 +        return None;
 +    };
 +
 +    if let Some(mut next) = closing_token.next_token() {
 +        if next.kind() == T![;] {
 +            if let Some(tok) = next.next_token() {
 +                closing_token = next;
 +                next = tok;
 +            }
 +        }
 +        if !(next.kind() == SyntaxKind::WHITESPACE && next.text().contains('\n')) {
 +            // Only display the hint if the `}` is the last token on the line
 +            return None;
 +        }
 +    }
 +
 +    let mut lines = 1;
 +    node.text().for_each_chunk(|s| lines += s.matches('\n').count());
 +    if lines < min_lines {
 +        return None;
 +    }
 +
 +    acc.push(InlayHint {
 +        range: closing_token.text_range(),
 +        kind: InlayKind::ClosingBraceHint,
 +        label,
 +        tooltip: name_offset.map(|it| InlayTooltip::HoverOffset(file_id, it)),
 +    });
 +
 +    None
 +}
 +
 +fn implicit_static_hints(
 +    acc: &mut Vec<InlayHint>,
 +    config: &InlayHintsConfig,
 +    statik_or_const: Either<ast::Static, ast::Const>,
 +) -> Option<()> {
 +    if config.lifetime_elision_hints != LifetimeElisionHints::Always {
 +        return None;
 +    }
 +
 +    if let Either::Right(it) = &statik_or_const {
 +        if ast::AssocItemList::can_cast(
 +            it.syntax().parent().map_or(SyntaxKind::EOF, |it| it.kind()),
 +        ) {
 +            return None;
 +        }
 +    }
 +
 +    if let Some(ast::Type::RefType(ty)) = statik_or_const.either(|it| it.ty(), |it| it.ty()) {
 +        if ty.lifetime().is_none() {
 +            let t = ty.amp_token()?;
 +            acc.push(InlayHint {
 +                range: t.text_range(),
 +                kind: InlayKind::LifetimeHint,
 +                label: "'static".to_owned(),
 +                tooltip: Some(InlayTooltip::String("Elided static lifetime".into())),
 +            });
 +        }
 +    }
 +
 +    Some(())
 +}
 +
 +fn fn_lifetime_fn_hints(
 +    acc: &mut Vec<InlayHint>,
 +    config: &InlayHintsConfig,
 +    func: ast::Fn,
 +) -> Option<()> {
 +    if config.lifetime_elision_hints == LifetimeElisionHints::Never {
 +        return None;
 +    }
 +
 +    let mk_lt_hint = |t: SyntaxToken, label| InlayHint {
 +        range: t.text_range(),
 +        kind: InlayKind::LifetimeHint,
 +        label,
 +        tooltip: Some(InlayTooltip::String("Elided lifetime".into())),
 +    };
 +
 +    let param_list = func.param_list()?;
 +    let generic_param_list = func.generic_param_list();
 +    let ret_type = func.ret_type();
 +    let self_param = param_list.self_param().filter(|it| it.amp_token().is_some());
 +
 +    let is_elided = |lt: &Option<ast::Lifetime>| match lt {
 +        Some(lt) => matches!(lt.text().as_str(), "'_"),
 +        None => true,
 +    };
 +
 +    let potential_lt_refs = {
 +        let mut acc: Vec<_> = vec![];
 +        if let Some(self_param) = &self_param {
 +            let lifetime = self_param.lifetime();
 +            let is_elided = is_elided(&lifetime);
 +            acc.push((None, self_param.amp_token(), lifetime, is_elided));
 +        }
 +        param_list.params().filter_map(|it| Some((it.pat(), it.ty()?))).for_each(|(pat, ty)| {
 +            // FIXME: check path types
 +            walk_ty(&ty, &mut |ty| match ty {
 +                ast::Type::RefType(r) => {
 +                    let lifetime = r.lifetime();
 +                    let is_elided = is_elided(&lifetime);
 +                    acc.push((
 +                        pat.as_ref().and_then(|it| match it {
 +                            ast::Pat::IdentPat(p) => p.name(),
 +                            _ => None,
 +                        }),
 +                        r.amp_token(),
 +                        lifetime,
 +                        is_elided,
 +                    ))
 +                }
 +                _ => (),
 +            })
 +        });
 +        acc
 +    };
 +
 +    // allocate names
 +    let mut gen_idx_name = {
 +        let mut gen = (0u8..).map(|idx| match idx {
 +            idx if idx < 10 => SmolStr::from_iter(['\'', (idx + 48) as char]),
 +            idx => format!("'{idx}").into(),
 +        });
 +        move || gen.next().unwrap_or_default()
 +    };
 +    let mut allocated_lifetimes = vec![];
 +
 +    let mut used_names: FxHashMap<SmolStr, usize> =
 +        match config.param_names_for_lifetime_elision_hints {
 +            true => generic_param_list
 +                .iter()
 +                .flat_map(|gpl| gpl.lifetime_params())
 +                .filter_map(|param| param.lifetime())
 +                .filter_map(|lt| Some((SmolStr::from(lt.text().as_str().get(1..)?), 0)))
 +                .collect(),
 +            false => Default::default(),
 +        };
 +    {
 +        let mut potential_lt_refs = potential_lt_refs.iter().filter(|&&(.., is_elided)| is_elided);
 +        if let Some(_) = &self_param {
 +            if let Some(_) = potential_lt_refs.next() {
 +                allocated_lifetimes.push(if config.param_names_for_lifetime_elision_hints {
 +                    // self can't be used as a lifetime, so no need to check for collisions
 +                    "'self".into()
 +                } else {
 +                    gen_idx_name()
 +                });
 +            }
 +        }
 +        potential_lt_refs.for_each(|(name, ..)| {
 +            let name = match name {
 +                Some(it) if config.param_names_for_lifetime_elision_hints => {
 +                    if let Some(c) = used_names.get_mut(it.text().as_str()) {
 +                        *c += 1;
 +                        SmolStr::from(format!("'{text}{c}", text = it.text().as_str()))
 +                    } else {
 +                        used_names.insert(it.text().as_str().into(), 0);
 +                        SmolStr::from_iter(["\'", it.text().as_str()])
 +                    }
 +                }
 +                _ => gen_idx_name(),
 +            };
 +            allocated_lifetimes.push(name);
 +        });
 +    }
 +
 +    // fetch output lifetime if elision rule applies
 +    let output = match potential_lt_refs.as_slice() {
 +        [(_, _, lifetime, _), ..] if self_param.is_some() || potential_lt_refs.len() == 1 => {
 +            match lifetime {
 +                Some(lt) => match lt.text().as_str() {
 +                    "'_" => allocated_lifetimes.get(0).cloned(),
 +                    "'static" => None,
 +                    name => Some(name.into()),
 +                },
 +                None => allocated_lifetimes.get(0).cloned(),
 +            }
 +        }
 +        [..] => None,
 +    };
 +
 +    if allocated_lifetimes.is_empty() && output.is_none() {
 +        return None;
 +    }
 +
 +    // apply hints
 +    // apply output if required
 +    let mut is_trivial = true;
 +    if let (Some(output_lt), Some(r)) = (&output, ret_type) {
 +        if let Some(ty) = r.ty() {
 +            walk_ty(&ty, &mut |ty| match ty {
 +                ast::Type::RefType(ty) if ty.lifetime().is_none() => {
 +                    if let Some(amp) = ty.amp_token() {
 +                        is_trivial = false;
 +                        acc.push(mk_lt_hint(amp, output_lt.to_string()));
 +                    }
 +                }
 +                _ => (),
 +            })
 +        }
 +    }
 +
 +    if config.lifetime_elision_hints == LifetimeElisionHints::SkipTrivial && is_trivial {
 +        return None;
 +    }
 +
 +    let mut a = allocated_lifetimes.iter();
 +    for (_, amp_token, _, is_elided) in potential_lt_refs {
 +        if is_elided {
 +            let t = amp_token?;
 +            let lt = a.next()?;
 +            acc.push(mk_lt_hint(t, lt.to_string()));
 +        }
 +    }
 +
 +    // generate generic param list things
 +    match (generic_param_list, allocated_lifetimes.as_slice()) {
 +        (_, []) => (),
 +        (Some(gpl), allocated_lifetimes) => {
 +            let angle_tok = gpl.l_angle_token()?;
 +            let is_empty = gpl.generic_params().next().is_none();
 +            acc.push(InlayHint {
 +                range: angle_tok.text_range(),
 +                kind: InlayKind::LifetimeHint,
 +                label: format!(
 +                    "{}{}",
 +                    allocated_lifetimes.iter().format(", "),
 +                    if is_empty { "" } else { ", " }
 +                ),
 +                tooltip: Some(InlayTooltip::String("Elided lifetimes".into())),
 +            });
 +        }
 +        (None, allocated_lifetimes) => acc.push(InlayHint {
 +            range: func.name()?.syntax().text_range(),
 +            kind: InlayKind::GenericParamListHint,
 +            label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(),
 +            tooltip: Some(InlayTooltip::String("Elided lifetimes".into())),
 +        }),
 +    }
 +    Some(())
 +}
 +
 +fn closure_ret_hints(
 +    acc: &mut Vec<InlayHint>,
 +    sema: &Semantics<'_, RootDatabase>,
 +    famous_defs: &FamousDefs<'_, '_>,
 +    config: &InlayHintsConfig,
 +    file_id: FileId,
 +    closure: ast::ClosureExpr,
 +) -> Option<()> {
 +    if config.closure_return_type_hints == ClosureReturnTypeHints::Never {
 +        return None;
 +    }
 +
 +    if closure.ret_type().is_some() {
 +        return None;
 +    }
 +
 +    if !closure_has_block_body(&closure)
 +        && config.closure_return_type_hints == ClosureReturnTypeHints::WithBlock
 +    {
 +        return None;
 +    }
 +
 +    let param_list = closure.param_list()?;
 +
 +    let closure = sema.descend_node_into_attributes(closure.clone()).pop()?;
 +    let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure))?.adjusted();
 +    let callable = ty.as_callable(sema.db)?;
 +    let ty = callable.return_type();
 +    if ty.is_unit() {
 +        return None;
 +    }
 +    acc.push(InlayHint {
 +        range: param_list.syntax().text_range(),
 +        kind: InlayKind::ClosureReturnTypeHint,
 +        label: hint_iterator(sema, &famous_defs, config, &ty)
 +            .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string()),
 +        tooltip: Some(InlayTooltip::HoverRanged(file_id, param_list.syntax().text_range())),
 +    });
 +    Some(())
 +}
 +
 +fn reborrow_hints(
 +    acc: &mut Vec<InlayHint>,
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &InlayHintsConfig,
 +    expr: &ast::Expr,
 +) -> Option<()> {
 +    if config.reborrow_hints == ReborrowHints::Never {
 +        return None;
 +    }
 +
 +    let descended = sema.descend_node_into_attributes(expr.clone()).pop();
 +    let desc_expr = descended.as_ref().unwrap_or(expr);
 +    let mutability = sema.is_implicit_reborrow(desc_expr)?;
 +    let label = match mutability {
 +        hir::Mutability::Shared if config.reborrow_hints != ReborrowHints::MutableOnly => "&*",
 +        hir::Mutability::Mut => "&mut *",
 +        _ => return None,
 +    };
 +    acc.push(InlayHint {
 +        range: expr.syntax().text_range(),
 +        kind: InlayKind::ImplicitReborrowHint,
 +        label: label.to_string(),
 +        tooltip: Some(InlayTooltip::String("Compiler inserted reborrow".into())),
 +    });
 +    Some(())
 +}
 +
 +fn chaining_hints(
 +    acc: &mut Vec<InlayHint>,
 +    sema: &Semantics<'_, RootDatabase>,
 +    famous_defs: &FamousDefs<'_, '_>,
 +    config: &InlayHintsConfig,
 +    file_id: FileId,
 +    expr: &ast::Expr,
 +) -> Option<()> {
 +    if !config.chaining_hints {
 +        return None;
 +    }
 +
 +    if matches!(expr, ast::Expr::RecordExpr(_)) {
 +        return None;
 +    }
 +
 +    let descended = sema.descend_node_into_attributes(expr.clone()).pop();
 +    let desc_expr = descended.as_ref().unwrap_or(expr);
 +
 +    let mut tokens = expr
 +        .syntax()
 +        .siblings_with_tokens(Direction::Next)
 +        .filter_map(NodeOrToken::into_token)
 +        .filter(|t| match t.kind() {
 +            SyntaxKind::WHITESPACE if !t.text().contains('\n') => false,
 +            SyntaxKind::COMMENT => false,
 +            _ => true,
 +        });
 +
 +    // Chaining can be defined as an expression whose next sibling tokens are newline and dot
 +    // Ignoring extra whitespace and comments
 +    let next = tokens.next()?.kind();
 +    if next == SyntaxKind::WHITESPACE {
 +        let mut next_next = tokens.next()?.kind();
 +        while next_next == SyntaxKind::WHITESPACE {
 +            next_next = tokens.next()?.kind();
 +        }
 +        if next_next == T![.] {
 +            let ty = sema.type_of_expr(desc_expr)?.original;
 +            if ty.is_unknown() {
 +                return None;
 +            }
 +            if matches!(expr, ast::Expr::PathExpr(_)) {
 +                if let Some(hir::Adt::Struct(st)) = ty.as_adt() {
 +                    if st.fields(sema.db).is_empty() {
 +                        return None;
 +                    }
 +                }
 +            }
 +            acc.push(InlayHint {
 +                range: expr.syntax().text_range(),
 +                kind: InlayKind::ChainingHint,
 +                label: hint_iterator(sema, &famous_defs, config, &ty).unwrap_or_else(|| {
 +                    ty.display_truncated(sema.db, config.max_length).to_string()
 +                }),
 +                tooltip: Some(InlayTooltip::HoverRanged(file_id, expr.syntax().text_range())),
 +            });
 +        }
 +    }
 +    Some(())
 +}
 +
 +fn param_name_hints(
 +    acc: &mut Vec<InlayHint>,
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &InlayHintsConfig,
 +    expr: ast::Expr,
 +) -> Option<()> {
 +    if !config.parameter_hints {
 +        return None;
 +    }
 +
 +    let (callable, arg_list) = get_callable(sema, &expr)?;
 +    let hints = callable
 +        .params(sema.db)
 +        .into_iter()
 +        .zip(arg_list.args())
 +        .filter_map(|((param, _ty), arg)| {
 +            // Only annotate hints for expressions that exist in the original file
 +            let range = sema.original_range_opt(arg.syntax())?;
 +            let (param_name, name_syntax) = match param.as_ref()? {
 +                Either::Left(pat) => ("self".to_string(), pat.name()),
 +                Either::Right(pat) => match pat {
 +                    ast::Pat::IdentPat(it) => (it.name()?.to_string(), it.name()),
 +                    _ => return None,
 +                },
 +            };
 +            Some((name_syntax, param_name, arg, range))
 +        })
 +        .filter(|(_, param_name, arg, _)| {
 +            !should_hide_param_name_hint(sema, &callable, param_name, arg)
 +        })
 +        .map(|(param, param_name, _, FileRange { range, .. })| {
 +            let mut tooltip = None;
 +            if let Some(name) = param {
 +                if let hir::CallableKind::Function(f) = callable.kind() {
 +                    // assert the file is cached so we can map out of macros
 +                    if let Some(_) = sema.source(f) {
 +                        tooltip = sema.original_range_opt(name.syntax());
 +                    }
 +                }
 +            }
 +
 +            InlayHint {
 +                range,
 +                kind: InlayKind::ParameterHint,
 +                label: param_name,
 +                tooltip: tooltip.map(|it| InlayTooltip::HoverOffset(it.file_id, it.range.start())),
 +            }
 +        });
 +
 +    acc.extend(hints);
 +    Some(())
 +}
 +
 +fn binding_mode_hints(
 +    acc: &mut Vec<InlayHint>,
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &InlayHintsConfig,
 +    pat: &ast::Pat,
 +) -> Option<()> {
 +    if !config.binding_mode_hints {
 +        return None;
 +    }
 +
 +    let range = pat.syntax().text_range();
 +    sema.pattern_adjustments(&pat).iter().for_each(|ty| {
 +        let reference = ty.is_reference();
 +        let mut_reference = ty.is_mutable_reference();
 +        let r = match (reference, mut_reference) {
 +            (true, true) => "&mut",
 +            (true, false) => "&",
 +            _ => return,
 +        };
 +        acc.push(InlayHint {
 +            range,
 +            kind: InlayKind::BindingModeHint,
 +            label: r.to_string(),
 +            tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
 +        });
 +    });
 +    match pat {
 +        ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => {
 +            let bm = sema.binding_mode_of_pat(pat)?;
 +            let bm = match bm {
 +                hir::BindingMode::Move => return None,
 +                hir::BindingMode::Ref(Mutability::Mut) => "ref mut",
 +                hir::BindingMode::Ref(Mutability::Shared) => "ref",
 +            };
 +            acc.push(InlayHint {
 +                range,
 +                kind: InlayKind::BindingModeHint,
 +                label: bm.to_string(),
 +                tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
 +            });
 +        }
 +        _ => (),
 +    }
 +
 +    Some(())
 +}
 +
 +fn bind_pat_hints(
 +    acc: &mut Vec<InlayHint>,
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &InlayHintsConfig,
 +    file_id: FileId,
 +    pat: &ast::IdentPat,
 +) -> Option<()> {
 +    if !config.type_hints {
 +        return None;
 +    }
 +
 +    let descended = sema.descend_node_into_attributes(pat.clone()).pop();
 +    let desc_pat = descended.as_ref().unwrap_or(pat);
 +    let ty = sema.type_of_pat(&desc_pat.clone().into())?.original;
 +
 +    if should_not_display_type_hint(sema, config, pat, &ty) {
 +        return None;
 +    }
 +
 +    let krate = sema.scope(desc_pat.syntax())?.krate();
 +    let famous_defs = FamousDefs(sema, krate);
 +    let label = hint_iterator(sema, &famous_defs, config, &ty);
 +
 +    let label = match label {
 +        Some(label) => label,
 +        None => {
 +            let ty_name = ty.display_truncated(sema.db, config.max_length).to_string();
 +            if config.hide_named_constructor_hints
 +                && is_named_constructor(sema, pat, &ty_name).is_some()
 +            {
 +                return None;
 +            }
 +            ty_name
 +        }
 +    };
 +
 +    acc.push(InlayHint {
 +        range: match pat.name() {
 +            Some(name) => name.syntax().text_range(),
 +            None => pat.syntax().text_range(),
 +        },
 +        kind: InlayKind::TypeHint,
 +        label,
 +        tooltip: pat
 +            .name()
 +            .map(|it| it.syntax().text_range())
 +            .map(|it| InlayTooltip::HoverRanged(file_id, it)),
 +    });
 +
 +    Some(())
 +}
 +
 +fn is_named_constructor(
 +    sema: &Semantics<'_, RootDatabase>,
 +    pat: &ast::IdentPat,
 +    ty_name: &str,
 +) -> Option<()> {
 +    let let_node = pat.syntax().parent()?;
 +    let expr = match_ast! {
 +        match let_node {
 +            ast::LetStmt(it) => it.initializer(),
 +            ast::LetExpr(it) => it.expr(),
 +            _ => None,
 +        }
 +    }?;
 +
 +    let expr = sema.descend_node_into_attributes(expr.clone()).pop().unwrap_or(expr);
 +    // unwrap postfix expressions
 +    let expr = match expr {
 +        ast::Expr::TryExpr(it) => it.expr(),
 +        ast::Expr::AwaitExpr(it) => it.expr(),
 +        expr => Some(expr),
 +    }?;
 +    let expr = match expr {
 +        ast::Expr::CallExpr(call) => match call.expr()? {
 +            ast::Expr::PathExpr(path) => path,
 +            _ => return None,
 +        },
 +        ast::Expr::PathExpr(path) => path,
 +        _ => return None,
 +    };
 +    let path = expr.path()?;
 +
 +    let callable = sema.type_of_expr(&ast::Expr::PathExpr(expr))?.original.as_callable(sema.db);
 +    let callable_kind = callable.map(|it| it.kind());
 +    let qual_seg = match callable_kind {
 +        Some(hir::CallableKind::Function(_) | hir::CallableKind::TupleEnumVariant(_)) => {
 +            path.qualifier()?.segment()
 +        }
 +        _ => path.segment(),
 +    }?;
 +
 +    let ctor_name = match qual_seg.kind()? {
 +        ast::PathSegmentKind::Name(name_ref) => {
 +            match qual_seg.generic_arg_list().map(|it| it.generic_args()) {
 +                Some(generics) => format!("{}<{}>", name_ref, generics.format(", ")),
 +                None => name_ref.to_string(),
 +            }
 +        }
 +        ast::PathSegmentKind::Type { type_ref: Some(ty), trait_ref: None } => ty.to_string(),
 +        _ => return None,
 +    };
 +    (ctor_name == ty_name).then(|| ())
 +}
 +
 +/// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`.
 +fn hint_iterator(
 +    sema: &Semantics<'_, RootDatabase>,
 +    famous_defs: &FamousDefs<'_, '_>,
 +    config: &InlayHintsConfig,
 +    ty: &hir::Type,
 +) -> Option<String> {
 +    let db = sema.db;
 +    let strukt = ty.strip_references().as_adt()?;
 +    let krate = strukt.module(db).krate();
 +    if krate != famous_defs.core()? {
 +        return None;
 +    }
 +    let iter_trait = famous_defs.core_iter_Iterator()?;
 +    let iter_mod = famous_defs.core_iter()?;
 +
 +    // Assert that this struct comes from `core::iter`.
 +    if !(strukt.visibility(db) == hir::Visibility::Public
 +        && strukt.module(db).path_to_root(db).contains(&iter_mod))
 +    {
 +        return None;
 +    }
 +
 +    if ty.impls_trait(db, iter_trait, &[]) {
 +        let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item {
 +            hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias),
 +            _ => None,
 +        })?;
 +        if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) {
 +            const LABEL_START: &str = "impl Iterator<Item = ";
 +            const LABEL_END: &str = ">";
 +
 +            let ty_display = hint_iterator(sema, famous_defs, config, &ty)
 +                .map(|assoc_type_impl| assoc_type_impl.to_string())
 +                .unwrap_or_else(|| {
 +                    ty.display_truncated(
 +                        db,
 +                        config
 +                            .max_length
 +                            .map(|len| len.saturating_sub(LABEL_START.len() + LABEL_END.len())),
 +                    )
 +                    .to_string()
 +                });
 +            return Some(format!("{}{}{}", LABEL_START, ty_display, LABEL_END));
 +        }
 +    }
 +
 +    None
 +}
 +
 +fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &hir::Type) -> bool {
 +    if let Some(hir::Adt::Enum(enum_data)) = pat_ty.as_adt() {
 +        let pat_text = bind_pat.to_string();
 +        enum_data
 +            .variants(db)
 +            .into_iter()
 +            .map(|variant| variant.name(db).to_smol_str())
 +            .any(|enum_name| enum_name == pat_text)
 +    } else {
 +        false
 +    }
 +}
 +
 +fn should_not_display_type_hint(
 +    sema: &Semantics<'_, RootDatabase>,
 +    config: &InlayHintsConfig,
 +    bind_pat: &ast::IdentPat,
 +    pat_ty: &hir::Type,
 +) -> bool {
 +    let db = sema.db;
 +
 +    if pat_ty.is_unknown() {
 +        return true;
 +    }
 +
 +    if let Some(hir::Adt::Struct(s)) = pat_ty.as_adt() {
 +        if s.fields(db).is_empty() && s.name(db).to_smol_str() == bind_pat.to_string() {
 +            return true;
 +        }
 +    }
 +
 +    if config.hide_closure_initialization_hints {
 +        if let Some(parent) = bind_pat.syntax().parent() {
 +            if let Some(it) = ast::LetStmt::cast(parent.clone()) {
 +                if let Some(ast::Expr::ClosureExpr(closure)) = it.initializer() {
 +                    if closure_has_block_body(&closure) {
 +                        return true;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    for node in bind_pat.syntax().ancestors() {
 +        match_ast! {
 +            match node {
 +                ast::LetStmt(it) => return it.ty().is_some(),
 +                // FIXME: We might wanna show type hints in parameters for non-top level patterns as well
 +                ast::Param(it) => return it.ty().is_some(),
 +                ast::MatchArm(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
 +                ast::LetExpr(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
 +                ast::IfExpr(_) => return false,
 +                ast::WhileExpr(_) => return false,
 +                ast::ForExpr(it) => {
 +                    // We *should* display hint only if user provided "in {expr}" and we know the type of expr (and it's not unit).
 +                    // Type of expr should be iterable.
 +                    return it.in_token().is_none() ||
 +                        it.iterable()
 +                            .and_then(|iterable_expr| sema.type_of_expr(&iterable_expr))
 +                            .map(TypeInfo::original)
 +                            .map_or(true, |iterable_ty| iterable_ty.is_unknown() || iterable_ty.is_unit())
 +                },
 +                _ => (),
 +            }
 +        }
 +    }
 +    false
 +}
 +
 +fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool {
 +    matches!(closure.body(), Some(ast::Expr::BlockExpr(_)))
 +}
 +
 +fn should_hide_param_name_hint(
 +    sema: &Semantics<'_, RootDatabase>,
 +    callable: &hir::Callable,
 +    param_name: &str,
 +    argument: &ast::Expr,
 +) -> bool {
 +    // These are to be tested in the `parameter_hint_heuristics` test
 +    // hide when:
 +    // - the parameter name is a suffix of the function's name
 +    // - the argument is a qualified constructing or call expression where the qualifier is an ADT
 +    // - exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix
 +    //   of argument with _ splitting it off
 +    // - param starts with `ra_fixture`
 +    // - param is a well known name in a unary function
 +
 +    let param_name = param_name.trim_start_matches('_');
 +    if param_name.is_empty() {
 +        return true;
 +    }
 +
 +    if matches!(argument, ast::Expr::PrefixExpr(prefix) if prefix.op_kind() == Some(UnaryOp::Not)) {
 +        return false;
 +    }
 +
 +    let fn_name = match callable.kind() {
 +        hir::CallableKind::Function(it) => Some(it.name(sema.db).to_smol_str()),
 +        _ => None,
 +    };
 +    let fn_name = fn_name.as_deref();
 +    is_param_name_suffix_of_fn_name(param_name, callable, fn_name)
 +        || is_argument_similar_to_param_name(argument, param_name)
 +        || param_name.starts_with("ra_fixture")
 +        || (callable.n_params() == 1 && is_obvious_param(param_name))
 +        || is_adt_constructor_similar_to_param_name(sema, argument, param_name)
 +}
 +
 +fn is_argument_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool {
 +    // check whether param_name and argument are the same or
 +    // whether param_name is a prefix/suffix of argument(split at `_`)
 +    let argument = match get_string_representation(argument) {
 +        Some(argument) => argument,
 +        None => return false,
 +    };
 +
 +    // std is honestly too panic happy...
 +    let str_split_at = |str: &str, at| str.is_char_boundary(at).then(|| argument.split_at(at));
 +
 +    let param_name = param_name.trim_start_matches('_');
 +    let argument = argument.trim_start_matches('_');
 +
 +    match str_split_at(argument, param_name.len()) {
 +        Some((prefix, rest)) if prefix.eq_ignore_ascii_case(param_name) => {
 +            return rest.is_empty() || rest.starts_with('_');
 +        }
 +        _ => (),
 +    }
 +    match argument.len().checked_sub(param_name.len()).and_then(|at| str_split_at(argument, at)) {
 +        Some((rest, suffix)) if param_name.eq_ignore_ascii_case(suffix) => {
 +            return rest.is_empty() || rest.ends_with('_');
 +        }
 +        _ => (),
 +    }
 +    false
 +}
 +
 +/// Hide the parameter name of a unary function if it is a `_` - prefixed suffix of the function's name, or equal.
 +///
 +/// `fn strip_suffix(suffix)` will be hidden.
 +/// `fn stripsuffix(suffix)` will not be hidden.
 +fn is_param_name_suffix_of_fn_name(
 +    param_name: &str,
 +    callable: &Callable,
 +    fn_name: Option<&str>,
 +) -> bool {
 +    match (callable.n_params(), fn_name) {
 +        (1, Some(function)) => {
 +            function == param_name
 +                || function
 +                    .len()
 +                    .checked_sub(param_name.len())
 +                    .and_then(|at| function.is_char_boundary(at).then(|| function.split_at(at)))
 +                    .map_or(false, |(prefix, suffix)| {
 +                        suffix.eq_ignore_ascii_case(param_name) && prefix.ends_with('_')
 +                    })
 +        }
 +        _ => false,
 +    }
 +}
 +
 +fn is_adt_constructor_similar_to_param_name(
 +    sema: &Semantics<'_, RootDatabase>,
 +    argument: &ast::Expr,
 +    param_name: &str,
 +) -> bool {
 +    let path = match argument {
 +        ast::Expr::CallExpr(c) => c.expr().and_then(|e| match e {
 +            ast::Expr::PathExpr(p) => p.path(),
 +            _ => None,
 +        }),
 +        ast::Expr::PathExpr(p) => p.path(),
 +        ast::Expr::RecordExpr(r) => r.path(),
 +        _ => return false,
 +    };
 +    let path = match path {
 +        Some(it) => it,
 +        None => return false,
 +    };
 +    (|| match sema.resolve_path(&path)? {
 +        hir::PathResolution::Def(hir::ModuleDef::Adt(_)) => {
 +            Some(to_lower_snake_case(&path.segment()?.name_ref()?.text()) == param_name)
 +        }
 +        hir::PathResolution::Def(hir::ModuleDef::Function(_) | hir::ModuleDef::Variant(_)) => {
 +            if to_lower_snake_case(&path.segment()?.name_ref()?.text()) == param_name {
 +                return Some(true);
 +            }
 +            let qual = path.qualifier()?;
 +            match sema.resolve_path(&qual)? {
 +                hir::PathResolution::Def(hir::ModuleDef::Adt(_)) => {
 +                    Some(to_lower_snake_case(&qual.segment()?.name_ref()?.text()) == param_name)
 +                }
 +                _ => None,
 +            }
 +        }
 +        _ => None,
 +    })()
 +    .unwrap_or(false)
 +}
 +
 +fn get_string_representation(expr: &ast::Expr) -> Option<String> {
 +    match expr {
 +        ast::Expr::MethodCallExpr(method_call_expr) => {
 +            let name_ref = method_call_expr.name_ref()?;
 +            match name_ref.text().as_str() {
 +                "clone" | "as_ref" => method_call_expr.receiver().map(|rec| rec.to_string()),
 +                name_ref => Some(name_ref.to_owned()),
 +            }
 +        }
 +        ast::Expr::MacroExpr(macro_expr) => {
 +            Some(macro_expr.macro_call()?.path()?.segment()?.to_string())
 +        }
 +        ast::Expr::FieldExpr(field_expr) => Some(field_expr.name_ref()?.to_string()),
 +        ast::Expr::PathExpr(path_expr) => Some(path_expr.path()?.segment()?.to_string()),
 +        ast::Expr::PrefixExpr(prefix_expr) => get_string_representation(&prefix_expr.expr()?),
 +        ast::Expr::RefExpr(ref_expr) => get_string_representation(&ref_expr.expr()?),
 +        ast::Expr::CastExpr(cast_expr) => get_string_representation(&cast_expr.expr()?),
 +        _ => None,
 +    }
 +}
 +
 +fn is_obvious_param(param_name: &str) -> bool {
 +    // avoid displaying hints for common functions like map, filter, etc.
 +    // or other obvious words used in std
 +    let is_obvious_param_name =
 +        matches!(param_name, "predicate" | "value" | "pat" | "rhs" | "other");
 +    param_name.len() == 1 || is_obvious_param_name
 +}
 +
 +fn get_callable(
 +    sema: &Semantics<'_, RootDatabase>,
 +    expr: &ast::Expr,
 +) -> Option<(hir::Callable, ast::ArgList)> {
 +    match expr {
 +        ast::Expr::CallExpr(expr) => {
 +            let descended = sema.descend_node_into_attributes(expr.clone()).pop();
 +            let expr = descended.as_ref().unwrap_or(expr);
 +            sema.type_of_expr(&expr.expr()?)?.original.as_callable(sema.db).zip(expr.arg_list())
 +        }
 +        ast::Expr::MethodCallExpr(expr) => {
 +            let descended = sema.descend_node_into_attributes(expr.clone()).pop();
 +            let expr = descended.as_ref().unwrap_or(expr);
 +            sema.resolve_method_call_as_callable(expr).zip(expr.arg_list())
 +        }
 +        _ => None,
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use expect_test::{expect, Expect};
 +    use ide_db::base_db::FileRange;
 +    use itertools::Itertools;
 +    use syntax::{TextRange, TextSize};
 +    use test_utils::extract_annotations;
 +
 +    use crate::inlay_hints::ReborrowHints;
 +    use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
 +
 +    use super::ClosureReturnTypeHints;
 +
 +    const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig {
 +        render_colons: false,
 +        type_hints: false,
 +        parameter_hints: false,
 +        chaining_hints: false,
 +        lifetime_elision_hints: LifetimeElisionHints::Never,
 +        closure_return_type_hints: ClosureReturnTypeHints::Never,
 +        reborrow_hints: ReborrowHints::Always,
 +        binding_mode_hints: false,
 +        hide_named_constructor_hints: false,
 +        hide_closure_initialization_hints: false,
 +        param_names_for_lifetime_elision_hints: false,
 +        max_length: None,
 +        closing_brace_hints_min_lines: None,
 +    };
 +    const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
 +        type_hints: true,
 +        parameter_hints: true,
 +        chaining_hints: true,
 +        reborrow_hints: ReborrowHints::Always,
 +        closure_return_type_hints: ClosureReturnTypeHints::WithBlock,
 +        binding_mode_hints: true,
 +        lifetime_elision_hints: LifetimeElisionHints::Always,
 +        ..DISABLED_CONFIG
 +    };
 +
 +    #[track_caller]
 +    fn check(ra_fixture: &str) {
 +        check_with_config(TEST_CONFIG, ra_fixture);
 +    }
 +
 +    #[track_caller]
 +    fn check_params(ra_fixture: &str) {
 +        check_with_config(
 +            InlayHintsConfig { parameter_hints: true, ..DISABLED_CONFIG },
 +            ra_fixture,
 +        );
 +    }
 +
 +    #[track_caller]
 +    fn check_types(ra_fixture: &str) {
 +        check_with_config(InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, ra_fixture);
 +    }
 +
 +    #[track_caller]
 +    fn check_chains(ra_fixture: &str) {
 +        check_with_config(InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG }, ra_fixture);
 +    }
 +
 +    #[track_caller]
 +    fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
 +        let (analysis, file_id) = fixture::file(ra_fixture);
 +        let mut expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
 +        let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
 +        let actual = inlay_hints
 +            .into_iter()
 +            .map(|it| (it.range, it.label.to_string()))
 +            .sorted_by_key(|(range, _)| range.start())
 +            .collect::<Vec<_>>();
 +        expected.sort_by_key(|(range, _)| range.start());
 +
 +        assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual);
 +    }
 +
 +    #[track_caller]
 +    fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) {
 +        let (analysis, file_id) = fixture::file(ra_fixture);
 +        let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
 +        expect.assert_debug_eq(&inlay_hints)
 +    }
 +
 +    #[test]
 +    fn hints_disabled() {
 +        check_with_config(
 +            InlayHintsConfig { render_colons: true, ..DISABLED_CONFIG },
 +            r#"
 +fn foo(a: i32, b: i32) -> i32 { a + b }
 +fn main() {
 +    let _x = foo(4, 4);
 +}"#,
 +        );
 +    }
 +
 +    // Parameter hint tests
 +
 +    #[test]
 +    fn param_hints_only() {
 +        check_params(
 +            r#"
 +fn foo(a: i32, b: i32) -> i32 { a + b }
 +fn main() {
 +    let _x = foo(
 +        4,
 +      //^ a
 +        4,
 +      //^ b
 +    );
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn param_hints_on_closure() {
 +        check_params(
 +            r#"
 +fn main() {
 +    let clo = |a: u8, b: u8| a + b;
 +    clo(
 +        1,
 +      //^ a
 +        2,
 +      //^ b
 +    );
 +}
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn param_name_similar_to_fn_name_still_hints() {
 +        check_params(
 +            r#"
 +fn max(x: i32, y: i32) -> i32 { x + y }
 +fn main() {
 +    let _x = max(
 +        4,
 +      //^ x
 +        4,
 +      //^ y
 +    );
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn param_name_similar_to_fn_name() {
 +        check_params(
 +            r#"
 +fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore }
 +fn main() {
 +    let _x = param_with_underscore(
 +        4,
 +    );
 +}"#,
 +        );
 +        check_params(
 +            r#"
 +fn param_with_underscore(underscore: i32) -> i32 { underscore }
 +fn main() {
 +    let _x = param_with_underscore(
 +        4,
 +    );
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn param_name_same_as_fn_name() {
 +        check_params(
 +            r#"
 +fn foo(foo: i32) -> i32 { foo }
 +fn main() {
 +    let _x = foo(
 +        4,
 +    );
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn never_hide_param_when_multiple_params() {
 +        check_params(
 +            r#"
 +fn foo(foo: i32, bar: i32) -> i32 { bar + baz }
 +fn main() {
 +    let _x = foo(
 +        4,
 +      //^ foo
 +        8,
 +      //^ bar
 +    );
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn param_hints_look_through_as_ref_and_clone() {
 +        check_params(
 +            r#"
 +fn foo(bar: i32, baz: f32) {}
 +
 +fn main() {
 +    let bar = 3;
 +    let baz = &"baz";
 +    let fez = 1.0;
 +    foo(bar.clone(), bar.clone());
 +                   //^^^^^^^^^^^ baz
 +    foo(bar.as_ref(), bar.as_ref());
 +                    //^^^^^^^^^^^^ baz
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn self_param_hints() {
 +        check_params(
 +            r#"
 +struct Foo;
 +
 +impl Foo {
 +    fn foo(self: Self) {}
 +    fn bar(self: &Self) {}
 +}
 +
 +fn main() {
 +    Foo::foo(Foo);
 +           //^^^ self
 +    Foo::bar(&Foo);
 +           //^^^^ self
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn param_name_hints_show_for_literals() {
 +        check_params(
 +            r#"pub fn test(a: i32, b: i32) -> [i32; 2] { [a, b] }
 +fn main() {
 +    test(
 +        0xa_b,
 +      //^^^^^ a
 +        0xa_b,
 +      //^^^^^ b
 +    );
 +}"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn function_call_parameter_hint() {
 +        check_params(
 +            r#"
 +//- minicore: option
 +struct FileId {}
 +struct SmolStr {}
 +
 +struct TextRange {}
 +struct SyntaxKind {}
 +struct NavigationTarget {}
 +
 +struct Test {}
 +
 +impl Test {
 +    fn method(&self, mut param: i32) -> i32 { param * 2 }
 +
 +    fn from_syntax(
 +        file_id: FileId,
 +        name: SmolStr,
 +        focus_range: Option<TextRange>,
 +        full_range: TextRange,
 +        kind: SyntaxKind,
 +        docs: Option<String>,
 +    ) -> NavigationTarget {
 +        NavigationTarget {}
 +    }
 +}
 +
 +fn test_func(mut foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 {
 +    foo + bar
 +}
 +
 +fn main() {
 +    let not_literal = 1;
 +    let _: i32 = test_func(1,    2,      "hello", 3,  not_literal);
 +                         //^ foo ^ bar   ^^^^^^^ msg  ^^^^^^^^^^^ last
 +    let t: Test = Test {};
 +    t.method(123);
 +           //^^^ param
 +    Test::method(&t,      3456);
 +               //^^ self  ^^^^ param
 +    Test::from_syntax(
 +        FileId {},
 +        "impl".into(),
 +      //^^^^^^^^^^^^^ name
 +        None,
 +      //^^^^ focus_range
 +        TextRange {},
 +      //^^^^^^^^^^^^ full_range
 +        SyntaxKind {},
 +      //^^^^^^^^^^^^^ kind
 +        None,
 +      //^^^^ docs
 +    );
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn parameter_hint_heuristics() {
 +        check_params(
 +            r#"
 +fn check(ra_fixture_thing: &str) {}
 +
 +fn map(f: i32) {}
 +fn filter(predicate: i32) {}
 +
 +fn strip_suffix(suffix: &str) {}
 +fn stripsuffix(suffix: &str) {}
 +fn same(same: u32) {}
 +fn same2(_same2: u32) {}
 +
 +fn enum_matches_param_name(completion_kind: CompletionKind) {}
 +
 +fn foo(param: u32) {}
 +fn bar(param_eter: u32) {}
 +
 +enum CompletionKind {
 +    Keyword,
 +}
 +
 +fn non_ident_pat((a, b): (u32, u32)) {}
 +
 +fn main() {
 +    const PARAM: u32 = 0;
 +    foo(PARAM);
 +    foo(!PARAM);
 +     // ^^^^^^ param
 +    check("");
 +
 +    map(0);
 +    filter(0);
 +
 +    strip_suffix("");
 +    stripsuffix("");
 +              //^^ suffix
 +    same(0);
 +    same2(0);
 +
 +    enum_matches_param_name(CompletionKind::Keyword);
 +
 +    let param = 0;
 +    foo(param);
 +    foo(param as _);
 +    let param_end = 0;
 +    foo(param_end);
 +    let start_param = 0;
 +    foo(start_param);
 +    let param2 = 0;
 +    foo(param2);
 +      //^^^^^^ param
 +
 +    macro_rules! param {
 +        () => {};
 +    };
 +    foo(param!());
 +
 +    let param_eter = 0;
 +    bar(param_eter);
 +    let param_eter_end = 0;
 +    bar(param_eter_end);
 +    let start_param_eter = 0;
 +    bar(start_param_eter);
 +    let param_eter2 = 0;
 +    bar(param_eter2);
 +      //^^^^^^^^^^^ param_eter
 +
 +    non_ident_pat((0, 0));
 +}"#,
 +        );
 +    }
 +
 +    // Type-Hint tests
 +
 +    #[test]
 +    fn type_hints_only() {
 +        check_types(
 +            r#"
 +fn foo(a: i32, b: i32) -> i32 { a + b }
 +fn main() {
 +    let _x = foo(4, 4);
 +      //^^ i32
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn type_hints_bindings_after_at() {
 +        check_types(
 +            r#"
 +//- minicore: option
 +fn main() {
 +    let ref foo @ bar @ ref mut baz = 0;
 +          //^^^ &i32
 +                //^^^ i32
 +                              //^^^ &mut i32
 +    let [x @ ..] = [0];
 +       //^ [i32; 1]
 +    if let x @ Some(_) = Some(0) {}
 +         //^ Option<i32>
 +    let foo @ (bar, baz) = (3, 3);
 +      //^^^ (i32, i32)
 +             //^^^ i32
 +                  //^^^ i32
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn default_generic_types_should_not_be_displayed() {
 +        check(
 +            r#"
 +struct Test<K, T = u8> { k: K, t: T }
 +
 +fn main() {
 +    let zz = Test { t: 23u8, k: 33 };
 +      //^^ Test<i32>
 +    let zz_ref = &zz;
 +      //^^^^^^ &Test<i32>
 +    let test = || zz;
 +      //^^^^ || -> Test<i32>
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn shorten_iterators_in_associated_params() {
 +        check_types(
 +            r#"
 +//- minicore: iterators
 +use core::iter;
 +
 +pub struct SomeIter<T> {}
 +
 +impl<T> SomeIter<T> {
 +    pub fn new() -> Self { SomeIter {} }
 +    pub fn push(&mut self, t: T) {}
 +}
 +
 +impl<T> Iterator for SomeIter<T> {
 +    type Item = T;
 +    fn next(&mut self) -> Option<Self::Item> {
 +        None
 +    }
 +}
 +
 +fn main() {
 +    let mut some_iter = SomeIter::new();
 +          //^^^^^^^^^ SomeIter<Take<Repeat<i32>>>
 +      some_iter.push(iter::repeat(2).take(2));
 +    let iter_of_iters = some_iter.take(2);
 +      //^^^^^^^^^^^^^ impl Iterator<Item = impl Iterator<Item = i32>>
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn infer_call_method_return_associated_types_with_generic() {
 +        check_types(
 +            r#"
 +            pub trait Default {
 +                fn default() -> Self;
 +            }
 +            pub trait Foo {
 +                type Bar: Default;
 +            }
 +
 +            pub fn quux<T: Foo>() -> T::Bar {
 +                let y = Default::default();
 +                  //^ <T as Foo>::Bar
 +
 +                y
 +            }
 +            "#,
 +        );
 +    }
 +
 +    #[test]
 +    fn fn_hints() {
 +        check_types(
 +            r#"
 +//- minicore: fn, sized
 +fn foo() -> impl Fn() { loop {} }
 +fn foo1() -> impl Fn(f64) { loop {} }
 +fn foo2() -> impl Fn(f64, f64) { loop {} }
 +fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
 +fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
 +fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
 +fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
 +fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
 +
 +fn main() {
 +    let foo = foo();
 +     // ^^^ impl Fn()
 +    let foo = foo1();
 +     // ^^^ impl Fn(f64)
 +    let foo = foo2();
 +     // ^^^ impl Fn(f64, f64)
 +    let foo = foo3();
 +     // ^^^ impl Fn(f64, f64) -> u32
 +    let foo = foo4();
 +     // ^^^ &dyn Fn(f64, f64) -> u32
 +    let foo = foo5();
 +     // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
 +    let foo = foo6();
 +     // ^^^ impl Fn(f64, f64) -> u32
 +    let foo = foo7();
 +     // ^^^ *const impl Fn(f64, f64) -> u32
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn check_hint_range_limit() {
 +        let fixture = r#"
 +        //- minicore: fn, sized
 +        fn foo() -> impl Fn() { loop {} }
 +        fn foo1() -> impl Fn(f64) { loop {} }
 +        fn foo2() -> impl Fn(f64, f64) { loop {} }
 +        fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
 +        fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
 +        fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
 +        fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
 +        fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
 +
 +        fn main() {
 +            let foo = foo();
 +            let foo = foo1();
 +            let foo = foo2();
 +             // ^^^ impl Fn(f64, f64)
 +            let foo = foo3();
 +             // ^^^ impl Fn(f64, f64) -> u32
 +            let foo = foo4();
 +            let foo = foo5();
 +            let foo = foo6();
 +            let foo = foo7();
 +        }
 +        "#;
 +        let (analysis, file_id) = fixture::file(fixture);
 +        let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
 +        let inlay_hints = analysis
 +            .inlay_hints(
 +                &InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
 +                file_id,
 +                Some(FileRange {
 +                    file_id,
 +                    range: TextRange::new(TextSize::from(500), TextSize::from(600)),
 +                }),
 +            )
 +            .unwrap();
 +        let actual =
 +            inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>();
 +        assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual);
 +    }
 +
 +    #[test]
 +    fn fn_hints_ptr_rpit_fn_parentheses() {
 +        check_types(
 +            r#"
 +//- minicore: fn, sized
 +trait Trait {}
 +
 +fn foo1() -> *const impl Fn() { loop {} }
 +fn foo2() -> *const (impl Fn() + Sized) { loop {} }
 +fn foo3() -> *const (impl Fn() + ?Sized) { loop {} }
 +fn foo4() -> *const (impl Sized + Fn()) { loop {} }
 +fn foo5() -> *const (impl ?Sized + Fn()) { loop {} }
 +fn foo6() -> *const (impl Fn() + Trait) { loop {} }
 +fn foo7() -> *const (impl Fn() + Sized + Trait) { loop {} }
 +fn foo8() -> *const (impl Fn() + ?Sized + Trait) { loop {} }
 +fn foo9() -> *const (impl Fn() -> u8 + ?Sized) { loop {} }
 +fn foo10() -> *const (impl Fn() + Sized + ?Sized) { loop {} }
 +
 +fn main() {
 +    let foo = foo1();
 +    //  ^^^ *const impl Fn()
 +    let foo = foo2();
 +    //  ^^^ *const impl Fn()
 +    let foo = foo3();
 +    //  ^^^ *const (impl Fn() + ?Sized)
 +    let foo = foo4();
 +    //  ^^^ *const impl Fn()
 +    let foo = foo5();
 +    //  ^^^ *const (impl Fn() + ?Sized)
 +    let foo = foo6();
 +    //  ^^^ *const (impl Fn() + Trait)
 +    let foo = foo7();
 +    //  ^^^ *const (impl Fn() + Trait)
 +    let foo = foo8();
 +    //  ^^^ *const (impl Fn() + Trait + ?Sized)
 +    let foo = foo9();
 +    //  ^^^ *const (impl Fn() -> u8 + ?Sized)
 +    let foo = foo10();
 +    //  ^^^ *const impl Fn()
 +}
 +"#,
 +        )
 +    }
 +
 +    #[test]
 +    fn unit_structs_have_no_type_hints() {
 +        check_types(
 +            r#"
 +//- minicore: result
 +struct SyntheticSyntax;
 +
 +fn main() {
 +    match Ok(()) {
 +        Ok(_) => (),
 +        Err(SyntheticSyntax) => (),
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn let_statement() {
 +        check_types(
 +            r#"
 +#[derive(PartialEq)]
 +enum Option<T> { None, Some(T) }
 +
 +#[derive(PartialEq)]
 +struct Test { a: Option<u32>, b: u8 }
 +
 +fn main() {
 +    struct InnerStruct {}
 +
 +    let test = 54;
 +      //^^^^ i32
 +    let test: i32 = 33;
 +    let mut test = 33;
 +          //^^^^ i32
 +    let _ = 22;
 +    let test = "test";
 +      //^^^^ &str
 +    let test = InnerStruct {};
 +      //^^^^ InnerStruct
 +
 +    let test = unresolved();
 +
 +    let test = (42, 'a');
 +      //^^^^ (i32, char)
 +    let (a,    (b,     (c,)) = (2, (3, (9.2,));
 +       //^ i32  ^ i32   ^ f64
 +    let &x = &92;
 +       //^ i32
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn if_expr() {
 +        check_types(
 +            r#"
 +//- minicore: option
 +struct Test { a: Option<u32>, b: u8 }
 +
 +fn main() {
 +    let test = Some(Test { a: Some(3), b: 1 });
 +      //^^^^ Option<Test>
 +    if let None = &test {};
 +    if let test = &test {};
 +         //^^^^ &Option<Test>
 +    if let Some(test) = &test {};
 +              //^^^^ &Test
 +    if let Some(Test { a,             b }) = &test {};
 +                     //^ &Option<u32> ^ &u8
 +    if let Some(Test { a: x,             b: y }) = &test {};
 +                        //^ &Option<u32>    ^ &u8
 +    if let Some(Test { a: Some(x),  b: y }) = &test {};
 +                             //^ &u32  ^ &u8
 +    if let Some(Test { a: None,  b: y }) = &test {};
 +                                  //^ &u8
 +    if let Some(Test { b: y, .. }) = &test {};
 +                        //^ &u8
 +    if test == None {}
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn while_expr() {
 +        check_types(
 +            r#"
 +//- minicore: option
 +struct Test { a: Option<u32>, b: u8 }
 +
 +fn main() {
 +    let test = Some(Test { a: Some(3), b: 1 });
 +      //^^^^ Option<Test>
 +    while let Some(Test { a: Some(x),  b: y }) = &test {};
 +                                //^ &u32  ^ &u8
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn match_arm_list() {
 +        check_types(
 +            r#"
 +//- minicore: option
 +struct Test { a: Option<u32>, b: u8 }
 +
 +fn main() {
 +    match Some(Test { a: Some(3), b: 1 }) {
 +        None => (),
 +        test => (),
 +      //^^^^ Option<Test>
 +        Some(Test { a: Some(x), b: y }) => (),
 +                          //^ u32  ^ u8
 +        _ => {}
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn complete_for_hint() {
 +        check_types(
 +            r#"
 +//- minicore: iterator
 +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;
 +}
 +
 +fn main() {
 +    let mut data = Vec::new();
 +          //^^^^ Vec<&str>
 +    data.push("foo");
 +    for i in data {
 +      //^ &str
 +      let z = i;
 +        //^ &str
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn multi_dyn_trait_bounds() {
 +        check_types(
 +            r#"
 +pub struct Vec<T> {}
 +
 +impl<T> Vec<T> {
 +    pub fn new() -> Self { Vec {} }
 +}
 +
 +pub struct Box<T> {}
 +
 +trait Display {}
++auto trait Sync {}
 +
 +fn main() {
 +    // The block expression wrapping disables the constructor hint hiding logic
 +    let _v = { Vec::<Box<&(dyn Display + Sync)>>::new() };
 +      //^^ Vec<Box<&(dyn Display + Sync)>>
 +    let _v = { Vec::<Box<*const (dyn Display + Sync)>>::new() };
 +      //^^ Vec<Box<*const (dyn Display + Sync)>>
 +    let _v = { Vec::<Box<dyn Display + Sync>>::new() };
 +      //^^ Vec<Box<dyn Display + Sync>>
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn shorten_iterator_hints() {
 +        check_types(
 +            r#"
 +//- minicore: iterators
 +use core::iter;
 +
 +struct MyIter;
 +
 +impl Iterator for MyIter {
 +    type Item = ();
 +    fn next(&mut self) -> Option<Self::Item> {
 +        None
 +    }
 +}
 +
 +fn main() {
 +    let _x = MyIter;
 +      //^^ MyIter
 +    let _x = iter::repeat(0);
 +      //^^ impl Iterator<Item = i32>
 +    fn generic<T: Clone>(t: T) {
 +        let _x = iter::repeat(t);
 +          //^^ impl Iterator<Item = T>
 +        let _chained = iter::repeat(t).take(10);
 +          //^^^^^^^^ impl Iterator<Item = T>
 +    }
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn skip_constructor_and_enum_type_hints() {
 +        check_with_config(
 +            InlayHintsConfig {
 +                type_hints: true,
 +                hide_named_constructor_hints: true,
 +                ..DISABLED_CONFIG
 +            },
 +            r#"
 +//- minicore: try, option
 +use core::ops::ControlFlow;
 +
 +mod x {
 +    pub mod y { pub struct Foo; }
 +    pub struct Foo;
 +    pub enum AnotherEnum {
 +        Variant()
 +    };
 +}
 +struct Struct;
 +struct TupleStruct();
 +
 +impl Struct {
 +    fn new() -> Self {
 +        Struct
 +    }
 +    fn try_new() -> ControlFlow<(), Self> {
 +        ControlFlow::Continue(Struct)
 +    }
 +}
 +
 +struct Generic<T>(T);
 +impl Generic<i32> {
 +    fn new() -> Self {
 +        Generic(0)
 +    }
 +}
 +
 +enum Enum {
 +    Variant(u32)
 +}
 +
 +fn times2(value: i32) -> i32 {
 +    2 * value
 +}
 +
 +fn main() {
 +    let enumb = Enum::Variant(0);
 +
 +    let strukt = x::Foo;
 +    let strukt = x::y::Foo;
 +    let strukt = Struct;
 +    let strukt = Struct::new();
 +
 +    let tuple_struct = TupleStruct();
 +
 +    let generic0 = Generic::new();
 +    //  ^^^^^^^^ Generic<i32>
 +    let generic1 = Generic(0);
 +    //  ^^^^^^^^ Generic<i32>
 +    let generic2 = Generic::<i32>::new();
 +    let generic3 = <Generic<i32>>::new();
 +    let generic4 = Generic::<i32>(0);
 +
 +
 +    let option = Some(0);
 +    //  ^^^^^^ Option<i32>
 +    let func = times2;
 +    //  ^^^^ fn times2(i32) -> i32
 +    let closure = |x: i32| x * 2;
 +    //  ^^^^^^^ |i32| -> i32
 +}
 +
 +fn fallible() -> ControlFlow<()> {
 +    let strukt = Struct::try_new()?;
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn shows_constructor_type_hints_when_enabled() {
 +        check_types(
 +            r#"
 +//- minicore: try
 +use core::ops::ControlFlow;
 +
 +struct Struct;
 +struct TupleStruct();
 +
 +impl Struct {
 +    fn new() -> Self {
 +        Struct
 +    }
 +    fn try_new() -> ControlFlow<(), Self> {
 +        ControlFlow::Continue(Struct)
 +    }
 +}
 +
 +struct Generic<T>(T);
 +impl Generic<i32> {
 +    fn new() -> Self {
 +        Generic(0)
 +    }
 +}
 +
 +fn main() {
 +    let strukt = Struct::new();
 +     // ^^^^^^ Struct
 +    let tuple_struct = TupleStruct();
 +     // ^^^^^^^^^^^^ TupleStruct
 +    let generic0 = Generic::new();
 +     // ^^^^^^^^ Generic<i32>
 +    let generic1 = Generic::<i32>::new();
 +     // ^^^^^^^^ Generic<i32>
 +    let generic2 = <Generic<i32>>::new();
 +     // ^^^^^^^^ Generic<i32>
 +}
 +
 +fn fallible() -> ControlFlow<()> {
 +    let strukt = Struct::try_new()?;
 +     // ^^^^^^ Struct
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn closures() {
 +        check(
 +            r#"
 +fn main() {
 +    let mut start = 0;
 +          //^^^^^ i32
 +    (0..2).for_each(|increment      | { start += increment; });
 +                   //^^^^^^^^^ i32
 +
 +    let multiply =
 +      //^^^^^^^^ |i32, i32| -> i32
 +      | a,     b| a * b
 +      //^ i32  ^ i32
 +
 +    ;
 +
 +    let _: i32 = multiply(1,  2);
 +                        //^ a ^ b
 +    let multiply_ref = &multiply;
 +      //^^^^^^^^^^^^ &|i32, i32| -> i32
 +
 +    let return_42 = || 42;
 +      //^^^^^^^^^ || -> i32
 +      || { 42 };
 +    //^^ i32
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn return_type_hints_for_closure_without_block() {
 +        check_with_config(
 +            InlayHintsConfig {
 +                closure_return_type_hints: ClosureReturnTypeHints::Always,
 +                ..DISABLED_CONFIG
 +            },
 +            r#"
 +fn main() {
 +    let a = || { 0 };
 +          //^^ i32
 +    let b = || 0;
 +          //^^ i32
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn skip_closure_type_hints() {
 +        check_with_config(
 +            InlayHintsConfig {
 +                type_hints: true,
 +                hide_closure_initialization_hints: true,
 +                ..DISABLED_CONFIG
 +            },
 +            r#"
 +//- minicore: fn
 +fn main() {
 +    let multiple_2 = |x: i32| { x * 2 };
 +
 +    let multiple_2 = |x: i32| x * 2;
 +    //  ^^^^^^^^^^ |i32| -> i32
 +
 +    let (not) = (|x: bool| { !x });
 +    //   ^^^ |bool| -> bool
 +
 +    let (is_zero, _b) = (|x: usize| { x == 0 }, false);
 +    //   ^^^^^^^ |usize| -> bool
 +    //            ^^ bool
 +
 +    let plus_one = |x| { x + 1 };
 +    //              ^ u8
 +    foo(plus_one);
 +
 +    let add_mul = bar(|x: u8| { x + 1 });
 +    //  ^^^^^^^ impl FnOnce(u8) -> u8 + ?Sized
 +
 +    let closure = if let Some(6) = add_mul(2).checked_sub(1) {
 +    //  ^^^^^^^ fn(i32) -> i32
 +        |x: i32| { x * 2 }
 +    } else {
 +        |x: i32| { x * 3 }
 +    };
 +}
 +
 +fn foo(f: impl FnOnce(u8) -> u8) {}
 +
 +fn bar(f: impl FnOnce(u8) -> u8) -> impl FnOnce(u8) -> u8 {
 +    move |x: u8| f(x) * 2
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn hint_truncation() {
 +        check_with_config(
 +            InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG },
 +            r#"
 +struct Smol<T>(T);
 +
 +struct VeryLongOuterName<T>(T);
 +
 +fn main() {
 +    let a = Smol(0u32);
 +      //^ Smol<u32>
 +    let b = VeryLongOuterName(0usize);
 +      //^ VeryLongOuterName<…>
 +    let c = Smol(Smol(0u32))
 +      //^ Smol<Smol<…>>
 +}"#,
 +        );
 +    }
 +
 +    // Chaining hint tests
 +
 +    #[test]
 +    fn chaining_hints_ignore_comments() {
 +        check_expect(
 +            InlayHintsConfig { type_hints: false, chaining_hints: true, ..DISABLED_CONFIG },
 +            r#"
 +struct A(B);
 +impl A { fn into_b(self) -> B { self.0 } }
 +struct B(C);
 +impl B { fn into_c(self) -> C { self.0 } }
 +struct C;
 +
 +fn main() {
 +    let c = A(B(C))
 +        .into_b() // This is a comment
 +        // This is another comment
 +        .into_c();
 +}
 +"#,
 +            expect![[r#"
 +                [
 +                    InlayHint {
 +                        range: 147..172,
 +                        kind: ChainingHint,
 +                        label: "B",
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                147..172,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 147..154,
 +                        kind: ChainingHint,
 +                        label: "A",
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                147..154,
 +                            ),
 +                        ),
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn chaining_hints_without_newlines() {
 +        check_chains(
 +            r#"
 +struct A(B);
 +impl A { fn into_b(self) -> B { self.0 } }
 +struct B(C);
 +impl B { fn into_c(self) -> C { self.0 } }
 +struct C;
 +
 +fn main() {
 +    let c = A(B(C)).into_b().into_c();
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn struct_access_chaining_hints() {
 +        check_expect(
 +            InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
 +            r#"
 +struct A { pub b: B }
 +struct B { pub c: C }
 +struct C(pub bool);
 +struct D;
 +
 +impl D {
 +    fn foo(&self) -> i32 { 42 }
 +}
 +
 +fn main() {
 +    let x = A { b: B { c: C(true) } }
 +        .b
 +        .c
 +        .0;
 +    let x = D
 +        .foo();
 +}"#,
 +            expect![[r#"
 +                [
 +                    InlayHint {
 +                        range: 143..190,
 +                        kind: ChainingHint,
 +                        label: "C",
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                143..190,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 143..179,
 +                        kind: ChainingHint,
 +                        label: "B",
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                143..179,
 +                            ),
 +                        ),
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn generic_chaining_hints() {
 +        check_expect(
 +            InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
 +            r#"
 +struct A<T>(T);
 +struct B<T>(T);
 +struct C<T>(T);
 +struct X<T,R>(T, R);
 +
 +impl<T> A<T> {
 +    fn new(t: T) -> Self { A(t) }
 +    fn into_b(self) -> B<T> { B(self.0) }
 +}
 +impl<T> B<T> {
 +    fn into_c(self) -> C<T> { C(self.0) }
 +}
 +fn main() {
 +    let c = A::new(X(42, true))
 +        .into_b()
 +        .into_c();
 +}
 +"#,
 +            expect![[r#"
 +                [
 +                    InlayHint {
 +                        range: 246..283,
 +                        kind: ChainingHint,
 +                        label: "B<X<i32, bool>>",
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                246..283,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 246..265,
 +                        kind: ChainingHint,
 +                        label: "A<X<i32, bool>>",
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                246..265,
 +                            ),
 +                        ),
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn shorten_iterator_chaining_hints() {
 +        check_expect(
 +            InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
 +            r#"
 +//- minicore: iterators
 +use core::iter;
 +
 +struct MyIter;
 +
 +impl Iterator for MyIter {
 +    type Item = ();
 +    fn next(&mut self) -> Option<Self::Item> {
 +        None
 +    }
 +}
 +
 +fn main() {
 +    let _x = MyIter.by_ref()
 +        .take(5)
 +        .by_ref()
 +        .take(5)
 +        .by_ref();
 +}
 +"#,
 +            expect![[r#"
 +                [
 +                    InlayHint {
 +                        range: 174..241,
 +                        kind: ChainingHint,
 +                        label: "impl Iterator<Item = ()>",
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                174..241,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 174..224,
 +                        kind: ChainingHint,
 +                        label: "impl Iterator<Item = ()>",
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                174..224,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 174..206,
 +                        kind: ChainingHint,
 +                        label: "impl Iterator<Item = ()>",
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                174..206,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 174..189,
 +                        kind: ChainingHint,
 +                        label: "&mut MyIter",
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                174..189,
 +                            ),
 +                        ),
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_in_attr_call() {
 +        check_expect(
 +            TEST_CONFIG,
 +            r#"
 +//- proc_macros: identity, input_replace
 +struct Struct;
 +impl Struct {
 +    fn chain(self) -> Self {
 +        self
 +    }
 +}
 +#[proc_macros::identity]
 +fn main() {
 +    let strukt = Struct;
 +    strukt
 +        .chain()
 +        .chain()
 +        .chain();
 +    Struct::chain(strukt);
 +}
 +"#,
 +            expect![[r#"
 +                [
 +                    InlayHint {
 +                        range: 124..130,
 +                        kind: TypeHint,
 +                        label: "Struct",
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                124..130,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 145..185,
 +                        kind: ChainingHint,
 +                        label: "Struct",
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                145..185,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 145..168,
 +                        kind: ChainingHint,
 +                        label: "Struct",
 +                        tooltip: Some(
 +                            HoverRanged(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                145..168,
 +                            ),
 +                        ),
 +                    },
 +                    InlayHint {
 +                        range: 222..228,
 +                        kind: ParameterHint,
 +                        label: "self",
 +                        tooltip: Some(
 +                            HoverOffset(
 +                                FileId(
 +                                    0,
 +                                ),
 +                                42,
 +                            ),
 +                        ),
 +                    },
 +                ]
 +            "#]],
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_lifetimes() {
 +        check(
 +            r#"
 +fn empty() {}
 +
 +fn no_gpl(a: &()) {}
 + //^^^^^^<'0>
 +          // ^'0
 +fn empty_gpl<>(a: &()) {}
 +      //    ^'0   ^'0
 +fn partial<'b>(a: &(), b: &'b ()) {}
 +//        ^'0, $  ^'0
 +fn partial<'a>(a: &'a (), b: &()) {}
 +//        ^'0, $             ^'0
 +
 +fn single_ret(a: &()) -> &() {}
 +// ^^^^^^^^^^<'0>
 +              // ^'0     ^'0
 +fn full_mul(a: &(), b: &()) {}
 +// ^^^^^^^^<'0, '1>
 +            // ^'0     ^'1
 +
 +fn foo<'c>(a: &'c ()) -> &() {}
 +                      // ^'c
 +
 +fn nested_in(a: &   &X< &()>) {}
 +// ^^^^^^^^^<'0, '1, '2>
 +              //^'0 ^'1 ^'2
 +fn nested_out(a: &()) -> &   &X< &()>{}
 +// ^^^^^^^^^^<'0>
 +               //^'0     ^'0 ^'0 ^'0
 +
 +impl () {
 +    fn foo(&self) {}
 +    // ^^^<'0>
 +        // ^'0
 +    fn foo(&self) -> &() {}
 +    // ^^^<'0>
 +        // ^'0       ^'0
 +    fn foo(&self, a: &()) -> &() {}
 +    // ^^^<'0, '1>
 +        // ^'0       ^'1     ^'0
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_lifetimes_named() {
 +        check_with_config(
 +            InlayHintsConfig { param_names_for_lifetime_elision_hints: true, ..TEST_CONFIG },
 +            r#"
 +fn nested_in<'named>(named: &        &X<      &()>) {}
 +//          ^'named1, 'named2, 'named3, $
 +                          //^'named1 ^'named2 ^'named3
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_lifetimes_trivial_skip() {
 +        check_with_config(
 +            InlayHintsConfig {
 +                lifetime_elision_hints: LifetimeElisionHints::SkipTrivial,
 +                ..TEST_CONFIG
 +            },
 +            r#"
 +fn no_gpl(a: &()) {}
 +fn empty_gpl<>(a: &()) {}
 +fn partial<'b>(a: &(), b: &'b ()) {}
 +fn partial<'a>(a: &'a (), b: &()) {}
 +
 +fn single_ret(a: &()) -> &() {}
 +// ^^^^^^^^^^<'0>
 +              // ^'0     ^'0
 +fn full_mul(a: &(), b: &()) {}
 +
 +fn foo<'c>(a: &'c ()) -> &() {}
 +                      // ^'c
 +
 +fn nested_in(a: &   &X< &()>) {}
 +fn nested_out(a: &()) -> &   &X< &()>{}
 +// ^^^^^^^^^^<'0>
 +               //^'0     ^'0 ^'0 ^'0
 +
 +impl () {
 +    fn foo(&self) {}
 +    fn foo(&self) -> &() {}
 +    // ^^^<'0>
 +        // ^'0       ^'0
 +    fn foo(&self, a: &()) -> &() {}
 +    // ^^^<'0, '1>
 +        // ^'0       ^'1     ^'0
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_lifetimes_static() {
 +        check_with_config(
 +            InlayHintsConfig {
 +                lifetime_elision_hints: LifetimeElisionHints::Always,
 +                ..TEST_CONFIG
 +            },
 +            r#"
 +trait Trait {}
 +static S: &str = "";
 +//        ^'static
 +const C: &str = "";
 +//       ^'static
 +const C: &dyn Trait = panic!();
 +//       ^'static
 +
 +impl () {
 +    const C: &str = "";
 +    const C: &dyn Trait = panic!();
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_implicit_reborrow() {
 +        check_with_config(
 +            InlayHintsConfig {
 +                reborrow_hints: ReborrowHints::Always,
 +                parameter_hints: true,
 +                ..DISABLED_CONFIG
 +            },
 +            r#"
 +fn __() {
 +    let unique = &mut ();
 +    let r_mov = unique;
 +    let foo: &mut _ = unique;
 +                    //^^^^^^ &mut *
 +    ref_mut_id(unique);
 +             //^^^^^^ mut_ref
 +             //^^^^^^ &mut *
 +    let shared = ref_id(unique);
 +                      //^^^^^^ shared_ref
 +                      //^^^^^^ &*
 +    let mov = shared;
 +    let r_mov: &_ = shared;
 +    ref_id(shared);
 +         //^^^^^^ shared_ref
 +
 +    identity(unique);
 +    identity(shared);
 +}
 +fn identity<T>(t: T) -> T {
 +    t
 +}
 +fn ref_mut_id(mut_ref: &mut ()) -> &mut () {
 +    mut_ref
 +  //^^^^^^^ &mut *
 +}
 +fn ref_id(shared_ref: &()) -> &() {
 +    shared_ref
 +}
 +"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_binding_modes() {
 +        check_with_config(
 +            InlayHintsConfig { binding_mode_hints: true, ..DISABLED_CONFIG },
 +            r#"
 +fn __(
 +    (x,): (u32,),
 +    (x,): &(u32,),
 +  //^^^^&
 +   //^ ref
 +    (x,): &mut (u32,)
 +  //^^^^&mut
 +   //^ ref mut
 +) {
 +    let (x,) = (0,);
 +    let (x,) = &(0,);
 +      //^^^^ &
 +       //^ ref
 +    let (x,) = &mut (0,);
 +      //^^^^ &mut
 +       //^ ref mut
 +    let &mut (x,) = &mut (0,);
 +    let (ref mut x,) = &mut (0,);
 +      //^^^^^^^^^^^^ &mut
 +    let &mut (ref mut x,) = &mut (0,);
 +    let (mut x,) = &mut (0,);
 +      //^^^^^^^^ &mut
 +    match (0,) {
 +        (x,) => ()
 +    }
 +    match &(0,) {
 +        (x,) => ()
 +      //^^^^ &
 +       //^ ref
 +    }
 +    match &mut (0,) {
 +        (x,) => ()
 +      //^^^^ &mut
 +       //^ ref mut
 +    }
 +}"#,
 +        );
 +    }
 +
 +    #[test]
 +    fn hints_closing_brace() {
 +        check_with_config(
 +            InlayHintsConfig { closing_brace_hints_min_lines: Some(2), ..DISABLED_CONFIG },
 +            r#"
 +fn a() {}
 +
 +fn f() {
 +} // no hint unless `}` is the last token on the line
 +
 +fn g() {
 +  }
 +//^ fn g
 +
 +fn h<T>(with: T, arguments: u8, ...) {
 +  }
 +//^ fn h
 +
 +trait Tr {
 +    fn f();
 +    fn g() {
 +    }
 +  //^ fn g
 +  }
 +//^ trait Tr
 +impl Tr for () {
 +  }
 +//^ impl Tr for ()
 +impl dyn Tr {
 +  }
 +//^ impl dyn Tr
 +
 +static S0: () = 0;
 +static S1: () = {};
 +static S2: () = {
 + };
 +//^ static S2
 +const _: () = {
 + };
 +//^ const _
 +
 +mod m {
 +  }
 +//^ mod m
 +
 +m! {}
 +m!();
 +m!(
 + );
 +//^ m!
 +
 +m! {
 +  }
 +//^ m!
 +
 +fn f() {
 +    let v = vec![
 +    ];
 +  }
 +//^ fn f
 +"#,
 +        );
 +    }
 +}
index 8de5d33a1936d42479470854e39bee711f1916a2,0000000000000000000000000000000000000000..5dc9c6c82a14e06f0dda759607d69f9431713d07
mode 100644,000000..100644
--- /dev/null
@@@ -1,132 -1,0 +1,137 @@@
 +use super::*;
 +
 +pub(super) const PATH_FIRST: TokenSet =
 +    TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![Self], T![:], T![<]]);
 +
 +pub(super) fn is_path_start(p: &Parser<'_>) -> bool {
 +    is_use_path_start(p) || p.at(T![<]) || p.at(T![Self])
 +}
 +
 +pub(super) fn is_use_path_start(p: &Parser<'_>) -> bool {
 +    match p.current() {
 +        IDENT | T![self] | T![super] | T![crate] => true,
 +        T![:] if p.at(T![::]) => true,
 +        _ => false,
 +    }
 +}
 +
 +pub(super) fn use_path(p: &mut Parser<'_>) {
 +    path(p, Mode::Use);
 +}
 +
 +pub(crate) fn type_path(p: &mut Parser<'_>) {
 +    path(p, Mode::Type);
 +}
 +
 +pub(super) fn expr_path(p: &mut Parser<'_>) {
 +    path(p, Mode::Expr);
 +}
 +
 +pub(crate) fn type_path_for_qualifier(
 +    p: &mut Parser<'_>,
 +    qual: CompletedMarker,
 +) -> CompletedMarker {
 +    path_for_qualifier(p, Mode::Type, qual)
 +}
 +
 +#[derive(Clone, Copy, Eq, PartialEq)]
 +enum Mode {
 +    Use,
 +    Type,
 +    Expr,
 +}
 +
 +fn path(p: &mut Parser<'_>, mode: Mode) {
 +    let path = p.start();
 +    path_segment(p, mode, true);
 +    let qual = path.complete(p, PATH);
 +    path_for_qualifier(p, mode, qual);
 +}
 +
 +fn path_for_qualifier(
 +    p: &mut Parser<'_>,
 +    mode: Mode,
 +    mut qual: CompletedMarker,
 +) -> CompletedMarker {
 +    loop {
 +        let use_tree = mode == Mode::Use && matches!(p.nth(2), T![*] | T!['{']);
 +        if p.at(T![::]) && !use_tree {
 +            let path = qual.precede(p);
 +            p.bump(T![::]);
 +            path_segment(p, mode, false);
 +            let path = path.complete(p, PATH);
 +            qual = path;
 +        } else {
 +            return qual;
 +        }
 +    }
 +}
 +
 +fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) {
 +    let m = p.start();
 +    // test qual_paths
 +    // type X = <A as B>::Output;
 +    // fn foo() { <usize as Default>::default(); }
 +    if first && p.eat(T![<]) {
 +        types::type_(p);
 +        if p.eat(T![as]) {
 +            if is_use_path_start(p) {
 +                types::path_type(p);
 +            } else {
 +                p.error("expected a trait");
 +            }
 +        }
 +        p.expect(T![>]);
 +    } else {
 +        let mut empty = true;
 +        if first {
 +            p.eat(T![::]);
 +            empty = false;
 +        }
 +        match p.current() {
 +            IDENT => {
 +                name_ref(p);
 +                opt_path_type_args(p, mode);
 +            }
 +            // test crate_path
 +            // use crate::foo;
 +            T![self] | T![super] | T![crate] | T![Self] => {
 +                let m = p.start();
 +                p.bump_any();
 +                m.complete(p, NAME_REF);
 +            }
 +            _ => {
 +                p.err_recover("expected identifier", items::ITEM_RECOVERY_SET);
 +                if empty {
 +                    // test_err empty_segment
 +                    // use crate::;
 +                    m.abandon(p);
 +                    return;
 +                }
 +            }
 +        };
 +    }
 +    m.complete(p, PATH_SEGMENT);
 +}
 +
 +fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) {
 +    match mode {
 +        Mode::Use => {}
 +        Mode::Type => {
++            // test typepathfn_with_coloncolon
++            // type F = Start::(Middle) -> (Middle)::End;
++            if p.at(T![::]) && p.nth_at(2, T!['(']) {
++                p.bump(T![::]);
++            }
 +            // test path_fn_trait_args
 +            // type F = Box<Fn(i32) -> ()>;
 +            if p.at(T!['(']) {
 +                params::param_list_fn_trait(p);
 +                opt_ret_type(p);
 +            } else {
 +                generic_args::opt_generic_arg_list(p, false);
 +            }
 +        }
 +        Mode::Expr => generic_args::opt_generic_arg_list(p, true),
 +    }
 +}
index 628fa745e752d678d625ef5489173918529b265b,0000000000000000000000000000000000000000..c84f45f1f8e4ec0f059a484354a45fc042fb2e0a
mode 100644,000000..100644
--- /dev/null
@@@ -1,390 -1,0 +1,474 @@@
-         match self {
-             AS_KW | ASYNC_KW | AWAIT_KW | BOX_KW | BREAK_KW | CONST_KW | CONTINUE_KW | CRATE_KW
-             | DYN_KW | ELSE_KW | ENUM_KW | EXTERN_KW | FALSE_KW | FN_KW | FOR_KW | IF_KW
-             | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW
-             | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | SELF_TYPE_KW | STATIC_KW
-             | STRUCT_KW | SUPER_KW | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW
-             | WHERE_KW | WHILE_KW | YIELD_KW | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW
-             | RAW_KW | MACRO_RULES_KW => true,
-             _ => false,
-         }
 +//! Generated by `sourcegen_ast`, do not edit by hand.
 +
 +#![allow(bad_style, missing_docs, unreachable_pub)]
 +#[doc = r" The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`."]
 +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 +#[repr(u16)]
 +pub enum SyntaxKind {
 +    #[doc(hidden)]
 +    TOMBSTONE,
 +    #[doc(hidden)]
 +    EOF,
 +    SEMICOLON,
 +    COMMA,
 +    L_PAREN,
 +    R_PAREN,
 +    L_CURLY,
 +    R_CURLY,
 +    L_BRACK,
 +    R_BRACK,
 +    L_ANGLE,
 +    R_ANGLE,
 +    AT,
 +    POUND,
 +    TILDE,
 +    QUESTION,
 +    DOLLAR,
 +    AMP,
 +    PIPE,
 +    PLUS,
 +    STAR,
 +    SLASH,
 +    CARET,
 +    PERCENT,
 +    UNDERSCORE,
 +    DOT,
 +    DOT2,
 +    DOT3,
 +    DOT2EQ,
 +    COLON,
 +    COLON2,
 +    EQ,
 +    EQ2,
 +    FAT_ARROW,
 +    BANG,
 +    NEQ,
 +    MINUS,
 +    THIN_ARROW,
 +    LTEQ,
 +    GTEQ,
 +    PLUSEQ,
 +    MINUSEQ,
 +    PIPEEQ,
 +    AMPEQ,
 +    CARETEQ,
 +    SLASHEQ,
 +    STAREQ,
 +    PERCENTEQ,
 +    AMP2,
 +    PIPE2,
 +    SHL,
 +    SHR,
 +    SHLEQ,
 +    SHREQ,
 +    AS_KW,
 +    ASYNC_KW,
 +    AWAIT_KW,
 +    BOX_KW,
 +    BREAK_KW,
 +    CONST_KW,
 +    CONTINUE_KW,
 +    CRATE_KW,
 +    DYN_KW,
 +    ELSE_KW,
 +    ENUM_KW,
 +    EXTERN_KW,
 +    FALSE_KW,
 +    FN_KW,
 +    FOR_KW,
 +    IF_KW,
 +    IMPL_KW,
 +    IN_KW,
 +    LET_KW,
 +    LOOP_KW,
 +    MACRO_KW,
 +    MATCH_KW,
 +    MOD_KW,
 +    MOVE_KW,
 +    MUT_KW,
 +    PUB_KW,
 +    REF_KW,
 +    RETURN_KW,
 +    SELF_KW,
 +    SELF_TYPE_KW,
 +    STATIC_KW,
 +    STRUCT_KW,
 +    SUPER_KW,
 +    TRAIT_KW,
 +    TRUE_KW,
 +    TRY_KW,
 +    TYPE_KW,
 +    UNSAFE_KW,
 +    USE_KW,
 +    WHERE_KW,
 +    WHILE_KW,
 +    YIELD_KW,
 +    AUTO_KW,
 +    DEFAULT_KW,
 +    EXISTENTIAL_KW,
 +    UNION_KW,
 +    RAW_KW,
 +    MACRO_RULES_KW,
 +    INT_NUMBER,
 +    FLOAT_NUMBER,
 +    CHAR,
 +    BYTE,
 +    STRING,
 +    BYTE_STRING,
 +    ERROR,
 +    IDENT,
 +    WHITESPACE,
 +    LIFETIME_IDENT,
 +    COMMENT,
 +    SHEBANG,
 +    SOURCE_FILE,
 +    STRUCT,
 +    UNION,
 +    ENUM,
 +    FN,
 +    RET_TYPE,
 +    EXTERN_CRATE,
 +    MODULE,
 +    USE,
 +    STATIC,
 +    CONST,
 +    TRAIT,
 +    IMPL,
 +    TYPE_ALIAS,
 +    MACRO_CALL,
 +    MACRO_RULES,
 +    MACRO_ARM,
 +    TOKEN_TREE,
 +    MACRO_DEF,
 +    PAREN_TYPE,
 +    TUPLE_TYPE,
 +    MACRO_TYPE,
 +    NEVER_TYPE,
 +    PATH_TYPE,
 +    PTR_TYPE,
 +    ARRAY_TYPE,
 +    SLICE_TYPE,
 +    REF_TYPE,
 +    INFER_TYPE,
 +    FN_PTR_TYPE,
 +    FOR_TYPE,
 +    IMPL_TRAIT_TYPE,
 +    DYN_TRAIT_TYPE,
 +    OR_PAT,
 +    PAREN_PAT,
 +    REF_PAT,
 +    BOX_PAT,
 +    IDENT_PAT,
 +    WILDCARD_PAT,
 +    REST_PAT,
 +    PATH_PAT,
 +    RECORD_PAT,
 +    RECORD_PAT_FIELD_LIST,
 +    RECORD_PAT_FIELD,
 +    TUPLE_STRUCT_PAT,
 +    TUPLE_PAT,
 +    SLICE_PAT,
 +    RANGE_PAT,
 +    LITERAL_PAT,
 +    MACRO_PAT,
 +    CONST_BLOCK_PAT,
 +    TUPLE_EXPR,
 +    ARRAY_EXPR,
 +    PAREN_EXPR,
 +    PATH_EXPR,
 +    CLOSURE_EXPR,
 +    IF_EXPR,
 +    WHILE_EXPR,
 +    LOOP_EXPR,
 +    FOR_EXPR,
 +    CONTINUE_EXPR,
 +    BREAK_EXPR,
 +    LABEL,
 +    BLOCK_EXPR,
 +    STMT_LIST,
 +    RETURN_EXPR,
 +    YIELD_EXPR,
 +    LET_EXPR,
 +    UNDERSCORE_EXPR,
 +    MACRO_EXPR,
 +    MATCH_EXPR,
 +    MATCH_ARM_LIST,
 +    MATCH_ARM,
 +    MATCH_GUARD,
 +    RECORD_EXPR,
 +    RECORD_EXPR_FIELD_LIST,
 +    RECORD_EXPR_FIELD,
 +    BOX_EXPR,
 +    CALL_EXPR,
 +    INDEX_EXPR,
 +    METHOD_CALL_EXPR,
 +    FIELD_EXPR,
 +    AWAIT_EXPR,
 +    TRY_EXPR,
 +    CAST_EXPR,
 +    REF_EXPR,
 +    PREFIX_EXPR,
 +    RANGE_EXPR,
 +    BIN_EXPR,
 +    EXTERN_BLOCK,
 +    EXTERN_ITEM_LIST,
 +    VARIANT,
 +    RECORD_FIELD_LIST,
 +    RECORD_FIELD,
 +    TUPLE_FIELD_LIST,
 +    TUPLE_FIELD,
 +    VARIANT_LIST,
 +    ITEM_LIST,
 +    ASSOC_ITEM_LIST,
 +    ATTR,
 +    META,
 +    USE_TREE,
 +    USE_TREE_LIST,
 +    PATH,
 +    PATH_SEGMENT,
 +    LITERAL,
 +    RENAME,
 +    VISIBILITY,
 +    WHERE_CLAUSE,
 +    WHERE_PRED,
 +    ABI,
 +    NAME,
 +    NAME_REF,
 +    LET_STMT,
 +    LET_ELSE,
 +    EXPR_STMT,
 +    GENERIC_PARAM_LIST,
 +    GENERIC_PARAM,
 +    LIFETIME_PARAM,
 +    TYPE_PARAM,
 +    CONST_PARAM,
 +    GENERIC_ARG_LIST,
 +    LIFETIME,
 +    LIFETIME_ARG,
 +    TYPE_ARG,
 +    ASSOC_TYPE_ARG,
 +    CONST_ARG,
 +    PARAM_LIST,
 +    PARAM,
 +    SELF_PARAM,
 +    ARG_LIST,
 +    TYPE_BOUND,
 +    TYPE_BOUND_LIST,
 +    MACRO_ITEMS,
 +    MACRO_STMTS,
 +    #[doc(hidden)]
 +    __LAST,
 +}
 +use self::SyntaxKind::*;
 +impl SyntaxKind {
 +    pub fn is_keyword(self) -> bool {
-         match self {
-             SEMICOLON | COMMA | L_PAREN | R_PAREN | L_CURLY | R_CURLY | L_BRACK | R_BRACK
-             | L_ANGLE | R_ANGLE | AT | POUND | TILDE | QUESTION | DOLLAR | AMP | PIPE | PLUS
-             | STAR | SLASH | CARET | PERCENT | UNDERSCORE | DOT | DOT2 | DOT3 | DOT2EQ | COLON
-             | COLON2 | EQ | EQ2 | FAT_ARROW | BANG | NEQ | MINUS | THIN_ARROW | LTEQ | GTEQ
-             | PLUSEQ | MINUSEQ | PIPEEQ | AMPEQ | CARETEQ | SLASHEQ | STAREQ | PERCENTEQ | AMP2
-             | PIPE2 | SHL | SHR | SHLEQ | SHREQ => true,
-             _ => false,
-         }
++        matches!(
++            self,
++            AS_KW
++                | ASYNC_KW
++                | AWAIT_KW
++                | BOX_KW
++                | BREAK_KW
++                | CONST_KW
++                | CONTINUE_KW
++                | CRATE_KW
++                | DYN_KW
++                | ELSE_KW
++                | ENUM_KW
++                | EXTERN_KW
++                | FALSE_KW
++                | FN_KW
++                | FOR_KW
++                | IF_KW
++                | IMPL_KW
++                | IN_KW
++                | LET_KW
++                | LOOP_KW
++                | MACRO_KW
++                | MATCH_KW
++                | MOD_KW
++                | MOVE_KW
++                | MUT_KW
++                | PUB_KW
++                | REF_KW
++                | RETURN_KW
++                | SELF_KW
++                | SELF_TYPE_KW
++                | STATIC_KW
++                | STRUCT_KW
++                | SUPER_KW
++                | TRAIT_KW
++                | TRUE_KW
++                | TRY_KW
++                | TYPE_KW
++                | UNSAFE_KW
++                | USE_KW
++                | WHERE_KW
++                | WHILE_KW
++                | YIELD_KW
++                | AUTO_KW
++                | DEFAULT_KW
++                | EXISTENTIAL_KW
++                | UNION_KW
++                | RAW_KW
++                | MACRO_RULES_KW
++        )
 +    }
 +    pub fn is_punct(self) -> bool {
-         match self {
-             INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING => true,
-             _ => false,
-         }
++        matches!(
++            self,
++            SEMICOLON
++                | COMMA
++                | L_PAREN
++                | R_PAREN
++                | L_CURLY
++                | R_CURLY
++                | L_BRACK
++                | R_BRACK
++                | L_ANGLE
++                | R_ANGLE
++                | AT
++                | POUND
++                | TILDE
++                | QUESTION
++                | DOLLAR
++                | AMP
++                | PIPE
++                | PLUS
++                | STAR
++                | SLASH
++                | CARET
++                | PERCENT
++                | UNDERSCORE
++                | DOT
++                | DOT2
++                | DOT3
++                | DOT2EQ
++                | COLON
++                | COLON2
++                | EQ
++                | EQ2
++                | FAT_ARROW
++                | BANG
++                | NEQ
++                | MINUS
++                | THIN_ARROW
++                | LTEQ
++                | GTEQ
++                | PLUSEQ
++                | MINUSEQ
++                | PIPEEQ
++                | AMPEQ
++                | CARETEQ
++                | SLASHEQ
++                | STAREQ
++                | PERCENTEQ
++                | AMP2
++                | PIPE2
++                | SHL
++                | SHR
++                | SHLEQ
++                | SHREQ
++        )
 +    }
 +    pub fn is_literal(self) -> bool {
++        matches!(self, INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING)
 +    }
 +    pub fn from_keyword(ident: &str) -> Option<SyntaxKind> {
 +        let kw = match ident {
 +            "as" => AS_KW,
 +            "async" => ASYNC_KW,
 +            "await" => AWAIT_KW,
 +            "box" => BOX_KW,
 +            "break" => BREAK_KW,
 +            "const" => CONST_KW,
 +            "continue" => CONTINUE_KW,
 +            "crate" => CRATE_KW,
 +            "dyn" => DYN_KW,
 +            "else" => ELSE_KW,
 +            "enum" => ENUM_KW,
 +            "extern" => EXTERN_KW,
 +            "false" => FALSE_KW,
 +            "fn" => FN_KW,
 +            "for" => FOR_KW,
 +            "if" => IF_KW,
 +            "impl" => IMPL_KW,
 +            "in" => IN_KW,
 +            "let" => LET_KW,
 +            "loop" => LOOP_KW,
 +            "macro" => MACRO_KW,
 +            "match" => MATCH_KW,
 +            "mod" => MOD_KW,
 +            "move" => MOVE_KW,
 +            "mut" => MUT_KW,
 +            "pub" => PUB_KW,
 +            "ref" => REF_KW,
 +            "return" => RETURN_KW,
 +            "self" => SELF_KW,
 +            "Self" => SELF_TYPE_KW,
 +            "static" => STATIC_KW,
 +            "struct" => STRUCT_KW,
 +            "super" => SUPER_KW,
 +            "trait" => TRAIT_KW,
 +            "true" => TRUE_KW,
 +            "try" => TRY_KW,
 +            "type" => TYPE_KW,
 +            "unsafe" => UNSAFE_KW,
 +            "use" => USE_KW,
 +            "where" => WHERE_KW,
 +            "while" => WHILE_KW,
 +            "yield" => YIELD_KW,
 +            _ => return None,
 +        };
 +        Some(kw)
 +    }
 +    pub fn from_contextual_keyword(ident: &str) -> Option<SyntaxKind> {
 +        let kw = match ident {
 +            "auto" => AUTO_KW,
 +            "default" => DEFAULT_KW,
 +            "existential" => EXISTENTIAL_KW,
 +            "union" => UNION_KW,
 +            "raw" => RAW_KW,
 +            "macro_rules" => MACRO_RULES_KW,
 +            _ => return None,
 +        };
 +        Some(kw)
 +    }
 +    pub fn from_char(c: char) -> Option<SyntaxKind> {
 +        let tok = match c {
 +            ';' => SEMICOLON,
 +            ',' => COMMA,
 +            '(' => L_PAREN,
 +            ')' => R_PAREN,
 +            '{' => L_CURLY,
 +            '}' => R_CURLY,
 +            '[' => L_BRACK,
 +            ']' => R_BRACK,
 +            '<' => L_ANGLE,
 +            '>' => R_ANGLE,
 +            '@' => AT,
 +            '#' => POUND,
 +            '~' => TILDE,
 +            '?' => QUESTION,
 +            '$' => DOLLAR,
 +            '&' => AMP,
 +            '|' => PIPE,
 +            '+' => PLUS,
 +            '*' => STAR,
 +            '/' => SLASH,
 +            '^' => CARET,
 +            '%' => PERCENT,
 +            '_' => UNDERSCORE,
 +            '.' => DOT,
 +            ':' => COLON,
 +            '=' => EQ,
 +            '!' => BANG,
 +            '-' => MINUS,
 +            _ => return None,
 +        };
 +        Some(tok)
 +    }
 +}
 +#[macro_export]
 +macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
 +pub use T;
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b47a5a5c14705c4f6ec78a5e66749f6de6bc4f01
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,43 @@@
++SOURCE_FILE
++  TYPE_ALIAS
++    TYPE_KW "type"
++    WHITESPACE " "
++    NAME
++      IDENT "F"
++    WHITESPACE " "
++    EQ "="
++    WHITESPACE " "
++    PATH_TYPE
++      PATH
++        PATH
++          PATH_SEGMENT
++            NAME_REF
++              IDENT "Start"
++            COLON2 "::"
++            PARAM_LIST
++              L_PAREN "("
++              PARAM
++                PATH_TYPE
++                  PATH
++                    PATH_SEGMENT
++                      NAME_REF
++                        IDENT "Middle"
++              R_PAREN ")"
++            WHITESPACE " "
++            RET_TYPE
++              THIN_ARROW "->"
++              WHITESPACE " "
++              PAREN_TYPE
++                L_PAREN "("
++                PATH_TYPE
++                  PATH
++                    PATH_SEGMENT
++                      NAME_REF
++                        IDENT "Middle"
++                R_PAREN ")"
++        COLON2 "::"
++        PATH_SEGMENT
++          NAME_REF
++            IDENT "End"
++    SEMICOLON ";"
++  WHITESPACE "\n"
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8efd93a7ff6858281294f1453f9f51f5e88f12f5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++type F = Start::(Middle) -> (Middle)::End;
index 706e1742dffde38a695d9119413849ad8fb497ac,0000000000000000000000000000000000000000..92df4d70fd9024edc3865ddd935ae62bee437389
mode 100644,000000..100644
--- /dev/null
@@@ -1,385 -1,0 +1,387 @@@
 +//! The context or environment in which the language server functions. In our
 +//! server implementation this is know as the `WorldState`.
 +//!
 +//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
 +
 +use std::{sync::Arc, time::Instant};
 +
 +use crossbeam_channel::{unbounded, Receiver, Sender};
 +use flycheck::FlycheckHandle;
 +use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId};
 +use ide_db::base_db::{CrateId, FileLoader, SourceDatabase};
 +use lsp_types::{SemanticTokens, Url};
 +use parking_lot::{Mutex, RwLock};
 +use proc_macro_api::ProcMacroServer;
 +use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
 +use rustc_hash::FxHashMap;
 +use stdx::hash::NoHashHashMap;
 +use vfs::AnchoredPathBuf;
 +
 +use crate::{
 +    config::Config,
 +    diagnostics::{CheckFixes, DiagnosticCollection},
 +    from_proto,
 +    line_index::{LineEndings, LineIndex},
 +    lsp_ext,
 +    main_loop::Task,
 +    mem_docs::MemDocs,
 +    op_queue::OpQueue,
 +    reload::{self, SourceRootConfig},
 +    task_pool::TaskPool,
 +    to_proto::url_from_abs_path,
 +    Result,
 +};
 +
 +// Enforces drop order
 +pub(crate) struct Handle<H, C> {
 +    pub(crate) handle: H,
 +    pub(crate) receiver: C,
 +}
 +
 +pub(crate) type ReqHandler = fn(&mut GlobalState, lsp_server::Response);
 +pub(crate) type ReqQueue = lsp_server::ReqQueue<(String, Instant), ReqHandler>;
 +
 +/// `GlobalState` is the primary mutable state of the language server
 +///
 +/// The most interesting components are `vfs`, which stores a consistent
 +/// snapshot of the file systems, and `analysis_host`, which stores our
 +/// incremental salsa database.
 +///
 +/// Note that this struct has more than one impl in various modules!
 +pub(crate) struct GlobalState {
 +    sender: Sender<lsp_server::Message>,
 +    req_queue: ReqQueue,
 +    pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
 +    pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>,
 +    pub(crate) config: Arc<Config>,
 +    pub(crate) analysis_host: AnalysisHost,
 +    pub(crate) diagnostics: DiagnosticCollection,
 +    pub(crate) mem_docs: MemDocs,
 +    pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
 +    pub(crate) shutdown_requested: bool,
 +    pub(crate) proc_macro_changed: bool,
 +    pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>,
 +    pub(crate) source_root_config: SourceRootConfig,
 +    pub(crate) proc_macro_clients: Vec<Result<ProcMacroServer, String>>,
 +
 +    pub(crate) flycheck: Vec<FlycheckHandle>,
 +    pub(crate) flycheck_sender: Sender<flycheck::Message>,
 +    pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
 +
 +    pub(crate) vfs: Arc<RwLock<(vfs::Vfs, NoHashHashMap<FileId, LineEndings>)>>,
 +    pub(crate) vfs_config_version: u32,
 +    pub(crate) vfs_progress_config_version: u32,
 +    pub(crate) vfs_progress_n_total: usize,
 +    pub(crate) vfs_progress_n_done: usize,
 +
 +    /// `workspaces` field stores the data we actually use, while the `OpQueue`
 +    /// stores the result of the last fetch.
 +    ///
 +    /// If the fetch (partially) fails, we do not update the current value.
 +    ///
 +    /// The handling of build data is subtle. We fetch workspace in two phases:
 +    ///
 +    /// *First*, we run `cargo metadata`, which gives us fast results for
 +    /// initial analysis.
 +    ///
 +    /// *Second*, we run `cargo check` which runs build scripts and compiles
 +    /// proc macros.
 +    ///
 +    /// We need both for the precise analysis, but we want rust-analyzer to be
 +    /// at least partially available just after the first phase. That's because
 +    /// first phase is much faster, and is much less likely to fail.
 +    ///
 +    /// This creates a complication -- by the time the second phase completes,
 +    /// the results of the fist phase could be invalid. That is, while we run
 +    /// `cargo check`, the user edits `Cargo.toml`, we notice this, and the new
 +    /// `cargo metadata` completes before `cargo check`.
 +    ///
 +    /// An additional complication is that we want to avoid needless work. When
 +    /// the user just adds comments or whitespace to Cargo.toml, we do not want
 +    /// to invalidate any salsa caches.
 +    pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
 +    pub(crate) fetch_workspaces_queue: OpQueue<Vec<anyhow::Result<ProjectWorkspace>>>,
 +    pub(crate) fetch_build_data_queue:
 +        OpQueue<(Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>)>,
 +
 +    pub(crate) prime_caches_queue: OpQueue<()>,
 +}
 +
 +/// An immutable snapshot of the world's state at a point in time.
 +pub(crate) struct GlobalStateSnapshot {
 +    pub(crate) config: Arc<Config>,
 +    pub(crate) analysis: Analysis,
 +    pub(crate) check_fixes: CheckFixes,
 +    mem_docs: MemDocs,
 +    pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
 +    vfs: Arc<RwLock<(vfs::Vfs, NoHashHashMap<FileId, LineEndings>)>>,
 +    pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
++    pub(crate) proc_macros_loaded: bool,
 +}
 +
 +impl std::panic::UnwindSafe for GlobalStateSnapshot {}
 +
 +impl GlobalState {
 +    pub(crate) fn new(sender: Sender<lsp_server::Message>, config: Config) -> GlobalState {
 +        let loader = {
 +            let (sender, receiver) = unbounded::<vfs::loader::Message>();
 +            let handle: vfs_notify::NotifyHandle =
 +                vfs::loader::Handle::spawn(Box::new(move |msg| sender.send(msg).unwrap()));
 +            let handle = Box::new(handle) as Box<dyn vfs::loader::Handle>;
 +            Handle { handle, receiver }
 +        };
 +
 +        let task_pool = {
 +            let (sender, receiver) = unbounded();
 +            let handle = TaskPool::new(sender);
 +            Handle { handle, receiver }
 +        };
 +
 +        let analysis_host = AnalysisHost::new(config.lru_capacity());
 +        let (flycheck_sender, flycheck_receiver) = unbounded();
 +        let mut this = GlobalState {
 +            sender,
 +            req_queue: ReqQueue::default(),
 +            task_pool,
 +            loader,
 +            config: Arc::new(config.clone()),
 +            analysis_host,
 +            diagnostics: Default::default(),
 +            mem_docs: MemDocs::default(),
 +            semantic_tokens_cache: Arc::new(Default::default()),
 +            shutdown_requested: false,
 +            proc_macro_changed: false,
 +            last_reported_status: None,
 +            source_root_config: SourceRootConfig::default(),
 +            proc_macro_clients: vec![],
 +
 +            flycheck: Vec::new(),
 +            flycheck_sender,
 +            flycheck_receiver,
 +
 +            vfs: Arc::new(RwLock::new((vfs::Vfs::default(), NoHashHashMap::default()))),
 +            vfs_config_version: 0,
 +            vfs_progress_config_version: 0,
 +            vfs_progress_n_total: 0,
 +            vfs_progress_n_done: 0,
 +
 +            workspaces: Arc::new(Vec::new()),
 +            fetch_workspaces_queue: OpQueue::default(),
 +            prime_caches_queue: OpQueue::default(),
 +
 +            fetch_build_data_queue: OpQueue::default(),
 +        };
 +        // Apply any required database inputs from the config.
 +        this.update_configuration(config);
 +        this
 +    }
 +
 +    pub(crate) fn process_changes(&mut self) -> bool {
 +        let _p = profile::span("GlobalState::process_changes");
 +        // A file was added or deleted
 +        let mut has_structure_changes = false;
 +        let mut workspace_structure_change = None;
 +
 +        let (change, changed_files) = {
 +            let mut change = Change::new();
 +            let (vfs, line_endings_map) = &mut *self.vfs.write();
 +            let changed_files = vfs.take_changes();
 +            if changed_files.is_empty() {
 +                return false;
 +            }
 +
 +            for file in &changed_files {
 +                if let Some(path) = vfs.file_path(file.file_id).as_path() {
 +                    let path = path.to_path_buf();
 +                    if reload::should_refresh_for_change(&path, file.change_kind) {
 +                        workspace_structure_change = Some(path);
 +                    }
 +                    if file.is_created_or_deleted() {
 +                        has_structure_changes = true;
 +                    }
 +                }
 +
 +                // Clear native diagnostics when their file gets deleted
 +                if !file.exists() {
 +                    self.diagnostics.clear_native_for(file.file_id);
 +                }
 +
 +                let text = if file.exists() {
 +                    let bytes = vfs.file_contents(file.file_id).to_vec();
 +                    String::from_utf8(bytes).ok().and_then(|text| {
 +                        let (text, line_endings) = LineEndings::normalize(text);
 +                        line_endings_map.insert(file.file_id, line_endings);
 +                        Some(Arc::new(text))
 +                    })
 +                } else {
 +                    None
 +                };
 +                change.change_file(file.file_id, text);
 +            }
 +            if has_structure_changes {
 +                let roots = self.source_root_config.partition(vfs);
 +                change.set_roots(roots);
 +            }
 +            (change, changed_files)
 +        };
 +
 +        self.analysis_host.apply_change(change);
 +
 +        {
 +            let raw_database = self.analysis_host.raw_database();
 +            // FIXME: ideally we should only trigger a workspace fetch for non-library changes
 +            // but somethings going wrong with the source root business when we add a new local
 +            // crate see https://github.com/rust-lang/rust-analyzer/issues/13029
 +            if let Some(path) = workspace_structure_change {
 +                self.fetch_workspaces_queue
 +                    .request_op(format!("workspace vfs file change: {}", path.display()));
 +            }
 +            self.proc_macro_changed =
 +                changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| {
 +                    let crates = raw_database.relevant_crates(file.file_id);
 +                    let crate_graph = raw_database.crate_graph();
 +
 +                    crates.iter().any(|&krate| crate_graph[krate].is_proc_macro)
 +                });
 +        }
 +
 +        true
 +    }
 +
 +    pub(crate) fn snapshot(&self) -> GlobalStateSnapshot {
 +        GlobalStateSnapshot {
 +            config: Arc::clone(&self.config),
 +            workspaces: Arc::clone(&self.workspaces),
 +            analysis: self.analysis_host.analysis(),
 +            vfs: Arc::clone(&self.vfs),
 +            check_fixes: Arc::clone(&self.diagnostics.check_fixes),
 +            mem_docs: self.mem_docs.clone(),
 +            semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache),
++            proc_macros_loaded: !self.fetch_build_data_queue.last_op_result().0.is_empty(),
 +        }
 +    }
 +
 +    pub(crate) fn send_request<R: lsp_types::request::Request>(
 +        &mut self,
 +        params: R::Params,
 +        handler: ReqHandler,
 +    ) {
 +        let request = self.req_queue.outgoing.register(R::METHOD.to_string(), params, handler);
 +        self.send(request.into());
 +    }
 +
 +    pub(crate) fn complete_request(&mut self, response: lsp_server::Response) {
 +        let handler = self
 +            .req_queue
 +            .outgoing
 +            .complete(response.id.clone())
 +            .expect("received response for unknown request");
 +        handler(self, response)
 +    }
 +
 +    pub(crate) fn send_notification<N: lsp_types::notification::Notification>(
 +        &mut self,
 +        params: N::Params,
 +    ) {
 +        let not = lsp_server::Notification::new(N::METHOD.to_string(), params);
 +        self.send(not.into());
 +    }
 +
 +    pub(crate) fn register_request(
 +        &mut self,
 +        request: &lsp_server::Request,
 +        request_received: Instant,
 +    ) {
 +        self.req_queue
 +            .incoming
 +            .register(request.id.clone(), (request.method.clone(), request_received));
 +    }
 +
 +    pub(crate) fn respond(&mut self, response: lsp_server::Response) {
 +        if let Some((method, start)) = self.req_queue.incoming.complete(response.id.clone()) {
 +            if let Some(err) = &response.error {
 +                if err.message.starts_with("server panicked") {
 +                    self.poke_rust_analyzer_developer(format!("{}, check the log", err.message))
 +                }
 +            }
 +
 +            let duration = start.elapsed();
 +            tracing::debug!("handled {} - ({}) in {:0.2?}", method, response.id, duration);
 +            self.send(response.into());
 +        }
 +    }
 +
 +    pub(crate) fn cancel(&mut self, request_id: lsp_server::RequestId) {
 +        if let Some(response) = self.req_queue.incoming.cancel(request_id) {
 +            self.send(response.into());
 +        }
 +    }
 +
 +    fn send(&mut self, message: lsp_server::Message) {
 +        self.sender.send(message).unwrap()
 +    }
 +}
 +
 +impl Drop for GlobalState {
 +    fn drop(&mut self) {
 +        self.analysis_host.request_cancellation();
 +    }
 +}
 +
 +impl GlobalStateSnapshot {
 +    pub(crate) fn url_to_file_id(&self, url: &Url) -> Result<FileId> {
 +        url_to_file_id(&self.vfs.read().0, url)
 +    }
 +
 +    pub(crate) fn file_id_to_url(&self, id: FileId) -> Url {
 +        file_id_to_url(&self.vfs.read().0, id)
 +    }
 +
 +    pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancellable<LineIndex> {
 +        let endings = self.vfs.read().1[&file_id];
 +        let index = self.analysis.file_line_index(file_id)?;
 +        let res = LineIndex { index, endings, encoding: self.config.offset_encoding() };
 +        Ok(res)
 +    }
 +
 +    pub(crate) fn url_file_version(&self, url: &Url) -> Option<i32> {
 +        let path = from_proto::vfs_path(url).ok()?;
 +        Some(self.mem_docs.get(&path)?.version)
 +    }
 +
 +    pub(crate) fn anchored_path(&self, path: &AnchoredPathBuf) -> Url {
 +        let mut base = self.vfs.read().0.file_path(path.anchor);
 +        base.pop();
 +        let path = base.join(&path.path).unwrap();
 +        let path = path.as_path().unwrap();
 +        url_from_abs_path(path)
 +    }
 +
 +    pub(crate) fn cargo_target_for_crate_root(
 +        &self,
 +        crate_id: CrateId,
 +    ) -> Option<(&CargoWorkspace, Target)> {
 +        let file_id = self.analysis.crate_root(crate_id).ok()?;
 +        let path = self.vfs.read().0.file_path(file_id);
 +        let path = path.as_path()?;
 +        self.workspaces.iter().find_map(|ws| match ws {
 +            ProjectWorkspace::Cargo { cargo, .. } => {
 +                cargo.target_by_root(path).map(|it| (cargo, it))
 +            }
 +            ProjectWorkspace::Json { .. } => None,
 +            ProjectWorkspace::DetachedFiles { .. } => None,
 +        })
 +    }
 +}
 +
 +pub(crate) fn file_id_to_url(vfs: &vfs::Vfs, id: FileId) -> Url {
 +    let path = vfs.file_path(id);
 +    let path = path.as_path().unwrap();
 +    url_from_abs_path(path)
 +}
 +
 +pub(crate) fn url_to_file_id(vfs: &vfs::Vfs, url: &Url) -> Result<FileId> {
 +    let path = from_proto::vfs_path(url)?;
 +    let res = vfs.file_id(&path).ok_or_else(|| format!("file not found: {}", path))?;
 +    Ok(res)
 +}
index d89f0f5a3cf456d24c7889deec9355b3098e7a34,0000000000000000000000000000000000000000..d9b669afbe81cd3be1baea15b57d53788b842a9c
mode 100644,000000..100644
--- /dev/null
@@@ -1,1903 -1,0 +1,1911 @@@
-     let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?;
 +//! This module is responsible for implementing handlers for Language Server
 +//! Protocol. The majority of requests are fulfilled by calling into the
 +//! `ide` crate.
 +
 +use std::{
 +    io::Write as _,
 +    process::{self, Stdio},
 +};
 +
 +use anyhow::Context;
 +use ide::{
 +    AnnotationConfig, AssistKind, AssistResolveStrategy, FileId, FilePosition, FileRange,
 +    HoverAction, HoverGotoTypeData, Query, RangeInfo, Runnable, RunnableKind, SingleResolve,
 +    SourceChange, TextEdit,
 +};
 +use ide_db::SymbolKind;
 +use lsp_server::ErrorCode;
 +use lsp_types::{
 +    CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem,
 +    CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams,
 +    CodeLens, CompletionItem, Diagnostic, DiagnosticTag, DocumentFormattingParams, FoldingRange,
 +    FoldingRangeParams, HoverContents, InlayHint, InlayHintParams, Location, LocationLink,
 +    NumberOrString, Position, PrepareRenameResponse, Range, RenameParams,
 +    SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams,
 +    SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation,
 +    SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
 +};
 +use project_model::{ManifestPath, ProjectWorkspace, TargetKind};
 +use serde_json::json;
 +use stdx::{format_to, never};
 +use syntax::{algo, ast, AstNode, TextRange, TextSize, T};
 +use vfs::AbsPathBuf;
 +
 +use crate::{
 +    cargo_target_spec::CargoTargetSpec,
 +    config::{RustfmtConfig, WorkspaceSymbolConfig},
 +    diff::diff,
 +    from_proto,
 +    global_state::{GlobalState, GlobalStateSnapshot},
 +    line_index::LineEndings,
 +    lsp_ext::{self, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams},
 +    lsp_utils::{all_edits_are_disjoint, invalid_params_error},
 +    to_proto, LspError, Result,
 +};
 +
 +pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result<()> {
 +    state.proc_macro_clients.clear();
 +    state.proc_macro_changed = false;
 +    state.fetch_workspaces_queue.request_op("reload workspace request".to_string());
 +    state.fetch_build_data_queue.request_op("reload workspace request".to_string());
 +    Ok(())
 +}
 +
 +pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> Result<()> {
 +    let _p = profile::span("handle_stop_flycheck");
 +    state.flycheck.iter().for_each(|flycheck| flycheck.cancel());
 +    Ok(())
 +}
 +
 +pub(crate) fn handle_analyzer_status(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::AnalyzerStatusParams,
 +) -> Result<String> {
 +    let _p = profile::span("handle_analyzer_status");
 +
 +    let mut buf = String::new();
 +
 +    let mut file_id = None;
 +    if let Some(tdi) = params.text_document {
 +        match from_proto::file_id(&snap, &tdi.uri) {
 +            Ok(it) => file_id = Some(it),
 +            Err(_) => format_to!(buf, "file {} not found in vfs", tdi.uri),
 +        }
 +    }
 +
 +    if snap.workspaces.is_empty() {
 +        buf.push_str("No workspaces\n")
 +    } else {
 +        buf.push_str("Workspaces:\n");
 +        format_to!(
 +            buf,
 +            "Loaded {:?} packages across {} workspace{}.\n",
 +            snap.workspaces.iter().map(|w| w.n_packages()).sum::<usize>(),
 +            snap.workspaces.len(),
 +            if snap.workspaces.len() == 1 { "" } else { "s" }
 +        );
 +    }
 +    buf.push_str("\nAnalysis:\n");
 +    buf.push_str(
 +        &snap
 +            .analysis
 +            .status(file_id)
 +            .unwrap_or_else(|_| "Analysis retrieval was cancelled".to_owned()),
 +    );
 +    Ok(buf)
 +}
 +
 +pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> Result<String> {
 +    let _p = profile::span("handle_memory_usage");
 +    let mut mem = state.analysis_host.per_query_memory_usage();
 +    mem.push(("Remaining".into(), profile::memory_usage().allocated));
 +
 +    let mut out = String::new();
 +    for (name, bytes) in mem {
 +        format_to!(out, "{:>8} {}\n", bytes, name);
 +    }
 +    Ok(out)
 +}
 +
 +pub(crate) fn handle_shuffle_crate_graph(state: &mut GlobalState, _: ()) -> Result<()> {
 +    state.analysis_host.shuffle_crate_graph();
 +    Ok(())
 +}
 +
 +pub(crate) fn handle_syntax_tree(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::SyntaxTreeParams,
 +) -> Result<String> {
 +    let _p = profile::span("handle_syntax_tree");
 +    let id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(id)?;
 +    let text_range = params.range.and_then(|r| from_proto::text_range(&line_index, r).ok());
 +    let res = snap.analysis.syntax_tree(id, text_range)?;
 +    Ok(res)
 +}
 +
 +pub(crate) fn handle_view_hir(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<String> {
 +    let _p = profile::span("handle_view_hir");
 +    let position = from_proto::file_position(&snap, params)?;
 +    let res = snap.analysis.view_hir(position)?;
 +    Ok(res)
 +}
 +
 +pub(crate) fn handle_view_file_text(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentIdentifier,
 +) -> Result<String> {
 +    let file_id = from_proto::file_id(&snap, &params.uri)?;
 +    Ok(snap.analysis.file_text(file_id)?.to_string())
 +}
 +
 +pub(crate) fn handle_view_item_tree(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::ViewItemTreeParams,
 +) -> Result<String> {
 +    let _p = profile::span("handle_view_item_tree");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let res = snap.analysis.view_item_tree(file_id)?;
 +    Ok(res)
 +}
 +
 +pub(crate) fn handle_view_crate_graph(
 +    snap: GlobalStateSnapshot,
 +    params: ViewCrateGraphParams,
 +) -> Result<String> {
 +    let _p = profile::span("handle_view_crate_graph");
 +    let dot = snap.analysis.view_crate_graph(params.full)??;
 +    Ok(dot)
 +}
 +
 +pub(crate) fn handle_expand_macro(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::ExpandMacroParams,
 +) -> Result<Option<lsp_ext::ExpandedMacro>> {
 +    let _p = profile::span("handle_expand_macro");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let offset = from_proto::offset(&line_index, params.position)?;
 +
 +    let res = snap.analysis.expand_macro(FilePosition { file_id, offset })?;
 +    Ok(res.map(|it| lsp_ext::ExpandedMacro { name: it.name, expansion: it.expansion }))
 +}
 +
 +pub(crate) fn handle_selection_range(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::SelectionRangeParams,
 +) -> Result<Option<Vec<lsp_types::SelectionRange>>> {
 +    let _p = profile::span("handle_selection_range");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let res: Result<Vec<lsp_types::SelectionRange>> = params
 +        .positions
 +        .into_iter()
 +        .map(|position| {
 +            let offset = from_proto::offset(&line_index, position)?;
 +            let mut ranges = Vec::new();
 +            {
 +                let mut range = TextRange::new(offset, offset);
 +                loop {
 +                    ranges.push(range);
 +                    let frange = FileRange { file_id, range };
 +                    let next = snap.analysis.extend_selection(frange)?;
 +                    if next == range {
 +                        break;
 +                    } else {
 +                        range = next
 +                    }
 +                }
 +            }
 +            let mut range = lsp_types::SelectionRange {
 +                range: to_proto::range(&line_index, *ranges.last().unwrap()),
 +                parent: None,
 +            };
 +            for &r in ranges.iter().rev().skip(1) {
 +                range = lsp_types::SelectionRange {
 +                    range: to_proto::range(&line_index, r),
 +                    parent: Some(Box::new(range)),
 +                }
 +            }
 +            Ok(range)
 +        })
 +        .collect();
 +
 +    Ok(Some(res?))
 +}
 +
 +pub(crate) fn handle_matching_brace(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::MatchingBraceParams,
 +) -> Result<Vec<Position>> {
 +    let _p = profile::span("handle_matching_brace");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    params
 +        .positions
 +        .into_iter()
 +        .map(|position| {
 +            let offset = from_proto::offset(&line_index, position);
 +            offset.map(|offset| {
 +                let offset = match snap.analysis.matching_brace(FilePosition { file_id, offset }) {
 +                    Ok(Some(matching_brace_offset)) => matching_brace_offset,
 +                    Err(_) | Ok(None) => offset,
 +                };
 +                to_proto::position(&line_index, offset)
 +            })
 +        })
 +        .collect()
 +}
 +
 +pub(crate) fn handle_join_lines(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::JoinLinesParams,
 +) -> Result<Vec<lsp_types::TextEdit>> {
 +    let _p = profile::span("handle_join_lines");
 +
 +    let config = snap.config.join_lines();
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let mut res = TextEdit::default();
 +    for range in params.ranges {
 +        let range = from_proto::text_range(&line_index, range)?;
 +        let edit = snap.analysis.join_lines(&config, FileRange { file_id, range })?;
 +        match res.union(edit) {
 +            Ok(()) => (),
 +            Err(_edit) => {
 +                // just ignore overlapping edits
 +            }
 +        }
 +    }
 +
 +    Ok(to_proto::text_edit_vec(&line_index, res))
 +}
 +
 +pub(crate) fn handle_on_enter(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<Option<Vec<lsp_ext::SnippetTextEdit>>> {
 +    let _p = profile::span("handle_on_enter");
 +    let position = from_proto::file_position(&snap, params)?;
 +    let edit = match snap.analysis.on_enter(position)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +    let line_index = snap.file_line_index(position.file_id)?;
 +    let edit = to_proto::snippet_text_edit_vec(&line_index, true, edit);
 +    Ok(Some(edit))
 +}
 +
 +pub(crate) fn handle_on_type_formatting(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::DocumentOnTypeFormattingParams,
 +) -> Result<Option<Vec<lsp_ext::SnippetTextEdit>>> {
 +    let _p = profile::span("handle_on_type_formatting");
 +    let mut position = from_proto::file_position(&snap, params.text_document_position)?;
 +    let line_index = snap.file_line_index(position.file_id)?;
 +
 +    // in `ide`, the `on_type` invariant is that
 +    // `text.char_at(position) == typed_char`.
 +    position.offset -= TextSize::of('.');
 +    let char_typed = params.ch.chars().next().unwrap_or('\0');
 +
 +    let text = snap.analysis.file_text(position.file_id)?;
 +    if stdx::never!(!text[usize::from(position.offset)..].starts_with(char_typed)) {
 +        return Ok(None);
 +    }
 +
 +    // We have an assist that inserts ` ` after typing `->` in `fn foo() ->{`,
 +    // but it requires precise cursor positioning to work, and one can't
 +    // position the cursor with on_type formatting. So, let's just toggle this
 +    // feature off here, hoping that we'll enable it one day, 😿.
 +    if char_typed == '>' {
 +        return Ok(None);
 +    }
 +
 +    let edit =
 +        snap.analysis.on_char_typed(position, char_typed, snap.config.typing_autoclose_angle())?;
 +    let edit = match edit {
 +        Some(it) => it,
 +        None => return Ok(None),
 +    };
 +
 +    // This should be a single-file edit
 +    let (_, text_edit) = edit.source_file_edits.into_iter().next().unwrap();
 +
 +    let change = to_proto::snippet_text_edit_vec(&line_index, edit.is_snippet, text_edit);
 +    Ok(Some(change))
 +}
 +
 +pub(crate) fn handle_document_symbol(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::DocumentSymbolParams,
 +) -> Result<Option<lsp_types::DocumentSymbolResponse>> {
 +    let _p = profile::span("handle_document_symbol");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let mut parents: Vec<(lsp_types::DocumentSymbol, Option<usize>)> = Vec::new();
 +
 +    for symbol in snap.analysis.file_structure(file_id)? {
 +        let mut tags = Vec::new();
 +        if symbol.deprecated {
 +            tags.push(SymbolTag::DEPRECATED)
 +        };
 +
 +        #[allow(deprecated)]
 +        let doc_symbol = lsp_types::DocumentSymbol {
 +            name: symbol.label,
 +            detail: symbol.detail,
 +            kind: to_proto::structure_node_kind(symbol.kind),
 +            tags: Some(tags),
 +            deprecated: Some(symbol.deprecated),
 +            range: to_proto::range(&line_index, symbol.node_range),
 +            selection_range: to_proto::range(&line_index, symbol.navigation_range),
 +            children: None,
 +        };
 +        parents.push((doc_symbol, symbol.parent));
 +    }
 +
 +    // Builds hierarchy from a flat list, in reverse order (so that indices
 +    // makes sense)
 +    let document_symbols = {
 +        let mut acc = Vec::new();
 +        while let Some((mut node, parent_idx)) = parents.pop() {
 +            if let Some(children) = &mut node.children {
 +                children.reverse();
 +            }
 +            let parent = match parent_idx {
 +                None => &mut acc,
 +                Some(i) => parents[i].0.children.get_or_insert_with(Vec::new),
 +            };
 +            parent.push(node);
 +        }
 +        acc.reverse();
 +        acc
 +    };
 +
 +    let res = if snap.config.hierarchical_symbols() {
 +        document_symbols.into()
 +    } else {
 +        let url = to_proto::url(&snap, file_id);
 +        let mut symbol_information = Vec::<SymbolInformation>::new();
 +        for symbol in document_symbols {
 +            flatten_document_symbol(&symbol, None, &url, &mut symbol_information);
 +        }
 +        symbol_information.into()
 +    };
 +    return Ok(Some(res));
 +
 +    fn flatten_document_symbol(
 +        symbol: &lsp_types::DocumentSymbol,
 +        container_name: Option<String>,
 +        url: &Url,
 +        res: &mut Vec<SymbolInformation>,
 +    ) {
 +        let mut tags = Vec::new();
 +
 +        #[allow(deprecated)]
 +        if let Some(true) = symbol.deprecated {
 +            tags.push(SymbolTag::DEPRECATED)
 +        }
 +
 +        #[allow(deprecated)]
 +        res.push(SymbolInformation {
 +            name: symbol.name.clone(),
 +            kind: symbol.kind,
 +            tags: Some(tags),
 +            deprecated: symbol.deprecated,
 +            location: Location::new(url.clone(), symbol.range),
 +            container_name,
 +        });
 +
 +        for child in symbol.children.iter().flatten() {
 +            flatten_document_symbol(child, Some(symbol.name.clone()), url, res);
 +        }
 +    }
 +}
 +
 +pub(crate) fn handle_workspace_symbol(
 +    snap: GlobalStateSnapshot,
 +    params: WorkspaceSymbolParams,
 +) -> Result<Option<Vec<SymbolInformation>>> {
 +    let _p = profile::span("handle_workspace_symbol");
 +
 +    let config = snap.config.workspace_symbol();
 +    let (all_symbols, libs) = decide_search_scope_and_kind(&params, &config);
 +    let limit = config.search_limit;
 +
 +    let query = {
 +        let query: String = params.query.chars().filter(|&c| c != '#' && c != '*').collect();
 +        let mut q = Query::new(query);
 +        if !all_symbols {
 +            q.only_types();
 +        }
 +        if libs {
 +            q.libs();
 +        }
 +        q.limit(limit);
 +        q
 +    };
 +    let mut res = exec_query(&snap, query)?;
 +    if res.is_empty() && !all_symbols {
 +        let mut query = Query::new(params.query);
 +        query.limit(limit);
 +        res = exec_query(&snap, query)?;
 +    }
 +
 +    return Ok(Some(res));
 +
 +    fn decide_search_scope_and_kind(
 +        params: &WorkspaceSymbolParams,
 +        config: &WorkspaceSymbolConfig,
 +    ) -> (bool, bool) {
 +        // Support old-style parsing of markers in the query.
 +        let mut all_symbols = params.query.contains('#');
 +        let mut libs = params.query.contains('*');
 +
 +        // If no explicit marker was set, check request params. If that's also empty
 +        // use global config.
 +        if !all_symbols {
 +            let search_kind = match params.search_kind {
 +                Some(ref search_kind) => search_kind,
 +                None => &config.search_kind,
 +            };
 +            all_symbols = match search_kind {
 +                lsp_ext::WorkspaceSymbolSearchKind::OnlyTypes => false,
 +                lsp_ext::WorkspaceSymbolSearchKind::AllSymbols => true,
 +            }
 +        }
 +
 +        if !libs {
 +            let search_scope = match params.search_scope {
 +                Some(ref search_scope) => search_scope,
 +                None => &config.search_scope,
 +            };
 +            libs = match search_scope {
 +                lsp_ext::WorkspaceSymbolSearchScope::Workspace => false,
 +                lsp_ext::WorkspaceSymbolSearchScope::WorkspaceAndDependencies => true,
 +            }
 +        }
 +
 +        (all_symbols, libs)
 +    }
 +
 +    fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> {
 +        let mut res = Vec::new();
 +        for nav in snap.analysis.symbol_search(query)? {
 +            let container_name = nav.container_name.as_ref().map(|v| v.to_string());
 +
 +            #[allow(deprecated)]
 +            let info = SymbolInformation {
 +                name: nav.name.to_string(),
 +                kind: nav
 +                    .kind
 +                    .map(to_proto::symbol_kind)
 +                    .unwrap_or(lsp_types::SymbolKind::VARIABLE),
 +                tags: None,
 +                location: to_proto::location_from_nav(snap, nav)?,
 +                container_name,
 +                deprecated: None,
 +            };
 +            res.push(info);
 +        }
 +        Ok(res)
 +    }
 +}
 +
 +pub(crate) fn handle_will_rename_files(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::RenameFilesParams,
 +) -> Result<Option<lsp_types::WorkspaceEdit>> {
 +    let _p = profile::span("handle_will_rename_files");
 +
 +    let source_changes: Vec<SourceChange> = params
 +        .files
 +        .into_iter()
 +        .filter_map(|file_rename| {
 +            let from = Url::parse(&file_rename.old_uri).ok()?;
 +            let to = Url::parse(&file_rename.new_uri).ok()?;
 +
 +            let from_path = from.to_file_path().ok()?;
 +            let to_path = to.to_file_path().ok()?;
 +
 +            // Limit to single-level moves for now.
 +            match (from_path.parent(), to_path.parent()) {
 +                (Some(p1), Some(p2)) if p1 == p2 => {
 +                    if from_path.is_dir() {
 +                        // add '/' to end of url -- from `file://path/to/folder` to `file://path/to/folder/`
 +                        let mut old_folder_name = from_path.file_stem()?.to_str()?.to_string();
 +                        old_folder_name.push('/');
 +                        let from_with_trailing_slash = from.join(&old_folder_name).ok()?;
 +
 +                        let imitate_from_url = from_with_trailing_slash.join("mod.rs").ok()?;
 +                        let new_file_name = to_path.file_name()?.to_str()?;
 +                        Some((
 +                            snap.url_to_file_id(&imitate_from_url).ok()?,
 +                            new_file_name.to_string(),
 +                        ))
 +                    } else {
 +                        let old_name = from_path.file_stem()?.to_str()?;
 +                        let new_name = to_path.file_stem()?.to_str()?;
 +                        match (old_name, new_name) {
 +                            ("mod", _) => None,
 +                            (_, "mod") => None,
 +                            _ => Some((snap.url_to_file_id(&from).ok()?, new_name.to_string())),
 +                        }
 +                    }
 +                }
 +                _ => None,
 +            }
 +        })
 +        .filter_map(|(file_id, new_name)| {
 +            snap.analysis.will_rename_file(file_id, &new_name).ok()?
 +        })
 +        .collect();
 +
 +    // Drop file system edits since we're just renaming things on the same level
 +    let mut source_changes = source_changes.into_iter();
 +    let mut source_change = source_changes.next().unwrap_or_default();
 +    source_change.file_system_edits.clear();
 +    // no collect here because we want to merge text edits on same file ids
 +    source_change.extend(source_changes.flat_map(|it| it.source_file_edits));
 +    if source_change.source_file_edits.is_empty() {
 +        Ok(None)
 +    } else {
 +        to_proto::workspace_edit(&snap, source_change).map(Some)
 +    }
 +}
 +
 +pub(crate) fn handle_goto_definition(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::GotoDefinitionParams,
 +) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
 +    let _p = profile::span("handle_goto_definition");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +    let nav_info = match snap.analysis.goto_definition(position)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +    let src = FileRange { file_id: position.file_id, range: nav_info.range };
 +    let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_goto_declaration(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::request::GotoDeclarationParams,
 +) -> Result<Option<lsp_types::request::GotoDeclarationResponse>> {
 +    let _p = profile::span("handle_goto_declaration");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params.clone())?;
 +    let nav_info = match snap.analysis.goto_declaration(position)? {
 +        None => return handle_goto_definition(snap, params),
 +        Some(it) => it,
 +    };
 +    let src = FileRange { file_id: position.file_id, range: nav_info.range };
 +    let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_goto_implementation(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::request::GotoImplementationParams,
 +) -> Result<Option<lsp_types::request::GotoImplementationResponse>> {
 +    let _p = profile::span("handle_goto_implementation");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +    let nav_info = match snap.analysis.goto_implementation(position)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +    let src = FileRange { file_id: position.file_id, range: nav_info.range };
 +    let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_goto_type_definition(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::request::GotoTypeDefinitionParams,
 +) -> Result<Option<lsp_types::request::GotoTypeDefinitionResponse>> {
 +    let _p = profile::span("handle_goto_type_definition");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +    let nav_info = match snap.analysis.goto_type_definition(position)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +    let src = FileRange { file_id: position.file_id, range: nav_info.range };
 +    let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_parent_module(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
 +    let _p = profile::span("handle_parent_module");
 +    if let Ok(file_path) = &params.text_document.uri.to_file_path() {
 +        if file_path.file_name().unwrap_or_default() == "Cargo.toml" {
 +            // search workspaces for parent packages or fallback to workspace root
 +            let abs_path_buf = match AbsPathBuf::try_from(file_path.to_path_buf()).ok() {
 +                Some(abs_path_buf) => abs_path_buf,
 +                None => return Ok(None),
 +            };
 +
 +            let manifest_path = match ManifestPath::try_from(abs_path_buf).ok() {
 +                Some(manifest_path) => manifest_path,
 +                None => return Ok(None),
 +            };
 +
 +            let links: Vec<LocationLink> = snap
 +                .workspaces
 +                .iter()
 +                .filter_map(|ws| match ws {
 +                    ProjectWorkspace::Cargo { cargo, .. } => cargo.parent_manifests(&manifest_path),
 +                    _ => None,
 +                })
 +                .flatten()
 +                .map(|parent_manifest_path| LocationLink {
 +                    origin_selection_range: None,
 +                    target_uri: to_proto::url_from_abs_path(&parent_manifest_path),
 +                    target_range: Range::default(),
 +                    target_selection_range: Range::default(),
 +                })
 +                .collect::<_>();
 +            return Ok(Some(links.into()));
 +        }
 +
 +        // check if invoked at the crate root
 +        let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +        let crate_id = match snap.analysis.crate_for(file_id)?.first() {
 +            Some(&crate_id) => crate_id,
 +            None => return Ok(None),
 +        };
 +        let cargo_spec = match CargoTargetSpec::for_file(&snap, file_id)? {
 +            Some(it) => it,
 +            None => return Ok(None),
 +        };
 +
 +        if snap.analysis.crate_root(crate_id)? == file_id {
 +            let cargo_toml_url = to_proto::url_from_abs_path(&cargo_spec.cargo_toml);
 +            let res = vec![LocationLink {
 +                origin_selection_range: None,
 +                target_uri: cargo_toml_url,
 +                target_range: Range::default(),
 +                target_selection_range: Range::default(),
 +            }]
 +            .into();
 +            return Ok(Some(res));
 +        }
 +    }
 +
 +    // locate parent module by semantics
 +    let position = from_proto::file_position(&snap, params)?;
 +    let navs = snap.analysis.parent_module(position)?;
 +    let res = to_proto::goto_definition_response(&snap, None, navs)?;
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_runnables(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::RunnablesParams,
 +) -> Result<Vec<lsp_ext::Runnable>> {
 +    let _p = profile::span("handle_runnables");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let offset = params.position.and_then(|it| from_proto::offset(&line_index, it).ok());
 +    let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?;
 +
 +    let expect_test = match offset {
 +        Some(offset) => {
 +            let source_file = snap.analysis.parse(file_id)?;
 +            algo::find_node_at_offset::<ast::MacroCall>(source_file.syntax(), offset)
 +                .and_then(|it| it.path()?.segment()?.name_ref())
 +                .map_or(false, |it| it.text() == "expect" || it.text() == "expect_file")
 +        }
 +        None => false,
 +    };
 +
 +    let mut res = Vec::new();
 +    for runnable in snap.analysis.runnables(file_id)? {
 +        if should_skip_for_offset(&runnable, offset) {
 +            continue;
 +        }
 +        if should_skip_target(&runnable, cargo_spec.as_ref()) {
 +            continue;
 +        }
 +        let mut runnable = to_proto::runnable(&snap, runnable)?;
 +        if expect_test {
 +            runnable.label = format!("{} + expect", runnable.label);
 +            runnable.args.expect_test = Some(true);
 +        }
 +        res.push(runnable);
 +    }
 +
 +    // Add `cargo check` and `cargo test` for all targets of the whole package
 +    let config = snap.config.runnables();
 +    match cargo_spec {
 +        Some(spec) => {
 +            for cmd in ["check", "test"] {
 +                res.push(lsp_ext::Runnable {
 +                    label: format!("cargo {} -p {} --all-targets", cmd, spec.package),
 +                    location: None,
 +                    kind: lsp_ext::RunnableKind::Cargo,
 +                    args: lsp_ext::CargoRunnable {
 +                        workspace_root: Some(spec.workspace_root.clone().into()),
 +                        override_cargo: config.override_cargo.clone(),
 +                        cargo_args: vec![
 +                            cmd.to_string(),
 +                            "--package".to_string(),
 +                            spec.package.clone(),
 +                            "--all-targets".to_string(),
 +                        ],
 +                        cargo_extra_args: config.cargo_extra_args.clone(),
 +                        executable_args: Vec::new(),
 +                        expect_test: None,
 +                    },
 +                })
 +            }
 +        }
 +        None => {
 +            if !snap.config.linked_projects().is_empty()
 +                || !snap
 +                    .config
 +                    .discovered_projects
 +                    .as_ref()
 +                    .map(|projects| projects.is_empty())
 +                    .unwrap_or(true)
 +            {
 +                res.push(lsp_ext::Runnable {
 +                    label: "cargo check --workspace".to_string(),
 +                    location: None,
 +                    kind: lsp_ext::RunnableKind::Cargo,
 +                    args: lsp_ext::CargoRunnable {
 +                        workspace_root: None,
 +                        override_cargo: config.override_cargo,
 +                        cargo_args: vec!["check".to_string(), "--workspace".to_string()],
 +                        cargo_extra_args: config.cargo_extra_args,
 +                        executable_args: Vec::new(),
 +                        expect_test: None,
 +                    },
 +                });
 +            }
 +        }
 +    }
 +    Ok(res)
 +}
 +
 +fn should_skip_for_offset(runnable: &Runnable, offset: Option<TextSize>) -> bool {
 +    match offset {
 +        None => false,
 +        _ if matches!(&runnable.kind, RunnableKind::TestMod { .. }) => false,
 +        Some(offset) => !runnable.nav.full_range.contains_inclusive(offset),
 +    }
 +}
 +
 +pub(crate) fn handle_related_tests(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<Vec<lsp_ext::TestInfo>> {
 +    let _p = profile::span("handle_related_tests");
 +    let position = from_proto::file_position(&snap, params)?;
 +
 +    let tests = snap.analysis.related_tests(position, None)?;
 +    let mut res = Vec::new();
 +    for it in tests {
 +        if let Ok(runnable) = to_proto::runnable(&snap, it) {
 +            res.push(lsp_ext::TestInfo { runnable })
 +        }
 +    }
 +
 +    Ok(res)
 +}
 +
 +pub(crate) fn handle_completion(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::CompletionParams,
 +) -> Result<Option<lsp_types::CompletionResponse>> {
 +    let _p = profile::span("handle_completion");
 +    let text_document_position = params.text_document_position.clone();
 +    let position = from_proto::file_position(&snap, params.text_document_position)?;
 +    let completion_trigger_character =
 +        params.context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next());
 +
 +    if Some(':') == completion_trigger_character {
 +        let source_file = snap.analysis.parse(position.file_id)?;
 +        let left_token = source_file.syntax().token_at_offset(position.offset).left_biased();
 +        let completion_triggered_after_single_colon = match left_token {
 +            Some(left_token) => left_token.kind() == T![:],
 +            None => true,
 +        };
 +        if completion_triggered_after_single_colon {
 +            return Ok(None);
 +        }
 +    }
 +
 +    let completion_config = &snap.config.completion();
 +    let items = match snap.analysis.completions(
 +        completion_config,
 +        position,
 +        completion_trigger_character,
 +    )? {
 +        None => return Ok(None),
 +        Some(items) => items,
 +    };
 +    let line_index = snap.file_line_index(position.file_id)?;
 +
 +    let items =
 +        to_proto::completion_items(&snap.config, &line_index, text_document_position, items);
 +
 +    let completion_list = lsp_types::CompletionList { is_incomplete: true, items };
 +    Ok(Some(completion_list.into()))
 +}
 +
 +pub(crate) fn handle_completion_resolve(
 +    snap: GlobalStateSnapshot,
 +    mut original_completion: CompletionItem,
 +) -> Result<CompletionItem> {
 +    let _p = profile::span("handle_completion_resolve");
 +
 +    if !all_edits_are_disjoint(&original_completion, &[]) {
 +        return Err(invalid_params_error(
 +            "Received a completion with overlapping edits, this is not LSP-compliant".to_string(),
 +        )
 +        .into());
 +    }
 +
 +    let data = match original_completion.data.take() {
 +        Some(it) => it,
 +        None => return Ok(original_completion),
 +    };
 +
 +    let resolve_data: lsp_ext::CompletionResolveData = serde_json::from_value(data)?;
 +
 +    let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let offset = from_proto::offset(&line_index, resolve_data.position.position)?;
 +
 +    let additional_edits = snap
 +        .analysis
 +        .resolve_completion_edits(
 +            &snap.config.completion(),
 +            FilePosition { file_id, offset },
 +            resolve_data
 +                .imports
 +                .into_iter()
 +                .map(|import| (import.full_import_path, import.imported_name)),
 +        )?
 +        .into_iter()
 +        .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel)))
 +        .collect::<Vec<_>>();
 +
 +    if !all_edits_are_disjoint(&original_completion, &additional_edits) {
 +        return Err(LspError::new(
 +            ErrorCode::InternalError as i32,
 +            "Import edit overlaps with the original completion edits, this is not LSP-compliant"
 +                .into(),
 +        )
 +        .into());
 +    }
 +
 +    if let Some(original_additional_edits) = original_completion.additional_text_edits.as_mut() {
 +        original_additional_edits.extend(additional_edits.into_iter())
 +    } else {
 +        original_completion.additional_text_edits = Some(additional_edits);
 +    }
 +
 +    Ok(original_completion)
 +}
 +
 +pub(crate) fn handle_folding_range(
 +    snap: GlobalStateSnapshot,
 +    params: FoldingRangeParams,
 +) -> Result<Option<Vec<FoldingRange>>> {
 +    let _p = profile::span("handle_folding_range");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let folds = snap.analysis.folding_ranges(file_id)?;
 +    let text = snap.analysis.file_text(file_id)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let line_folding_only = snap.config.line_folding_only();
 +    let res = folds
 +        .into_iter()
 +        .map(|it| to_proto::folding_range(&*text, &line_index, line_folding_only, it))
 +        .collect();
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_signature_help(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::SignatureHelpParams,
 +) -> Result<Option<lsp_types::SignatureHelp>> {
 +    let _p = profile::span("handle_signature_help");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +    let help = match snap.analysis.signature_help(position)? {
 +        Some(it) => it,
 +        None => return Ok(None),
 +    };
 +    let config = snap.config.call_info();
 +    let res = to_proto::signature_help(help, config, snap.config.signature_help_label_offsets());
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_hover(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::HoverParams,
 +) -> Result<Option<lsp_ext::Hover>> {
 +    let _p = profile::span("handle_hover");
 +    let range = match params.position {
 +        PositionOrRange::Position(position) => Range::new(position, position),
 +        PositionOrRange::Range(range) => range,
 +    };
 +
 +    let file_range = from_proto::file_range(&snap, params.text_document, range)?;
 +    let info = match snap.analysis.hover(&snap.config.hover(), file_range)? {
 +        None => return Ok(None),
 +        Some(info) => info,
 +    };
 +
 +    let line_index = snap.file_line_index(file_range.file_id)?;
 +    let range = to_proto::range(&line_index, info.range);
 +    let markup_kind =
 +        snap.config.hover().documentation.map_or(ide::HoverDocFormat::Markdown, |kind| kind);
 +    let hover = lsp_ext::Hover {
 +        hover: lsp_types::Hover {
 +            contents: HoverContents::Markup(to_proto::markup_content(
 +                info.info.markup,
 +                markup_kind,
 +            )),
 +            range: Some(range),
 +        },
 +        actions: if snap.config.hover_actions().none() {
 +            Vec::new()
 +        } else {
 +            prepare_hover_actions(&snap, &info.info.actions)
 +        },
 +    };
 +
 +    Ok(Some(hover))
 +}
 +
 +pub(crate) fn handle_prepare_rename(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<Option<PrepareRenameResponse>> {
 +    let _p = profile::span("handle_prepare_rename");
 +    let position = from_proto::file_position(&snap, params)?;
 +
 +    let change = snap.analysis.prepare_rename(position)?.map_err(to_proto::rename_error)?;
 +
 +    let line_index = snap.file_line_index(position.file_id)?;
 +    let range = to_proto::range(&line_index, change.range);
 +    Ok(Some(PrepareRenameResponse::Range(range)))
 +}
 +
 +pub(crate) fn handle_rename(
 +    snap: GlobalStateSnapshot,
 +    params: RenameParams,
 +) -> Result<Option<WorkspaceEdit>> {
 +    let _p = profile::span("handle_rename");
 +    let position = from_proto::file_position(&snap, params.text_document_position)?;
 +
 +    let mut change =
 +        snap.analysis.rename(position, &*params.new_name)?.map_err(to_proto::rename_error)?;
 +
 +    // this is kind of a hack to prevent double edits from happening when moving files
 +    // When a module gets renamed by renaming the mod declaration this causes the file to move
 +    // which in turn will trigger a WillRenameFiles request to the server for which we reply with a
 +    // a second identical set of renames, the client will then apply both edits causing incorrect edits
 +    // with this we only emit source_file_edits in the WillRenameFiles response which will do the rename instead
 +    // See https://github.com/microsoft/vscode-languageserver-node/issues/752 for more info
 +    if !change.file_system_edits.is_empty() && snap.config.will_rename() {
 +        change.source_file_edits.clear();
 +    }
 +    let workspace_edit = to_proto::workspace_edit(&snap, change)?;
 +    Ok(Some(workspace_edit))
 +}
 +
 +pub(crate) fn handle_references(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::ReferenceParams,
 +) -> Result<Option<Vec<Location>>> {
 +    let _p = profile::span("handle_references");
 +    let position = from_proto::file_position(&snap, params.text_document_position)?;
 +
 +    let refs = match snap.analysis.find_all_refs(position, None)? {
 +        None => return Ok(None),
 +        Some(refs) => refs,
 +    };
 +
 +    let include_declaration = params.context.include_declaration;
 +    let locations = refs
 +        .into_iter()
 +        .flat_map(|refs| {
 +            let decl = if include_declaration {
 +                refs.declaration.map(|decl| FileRange {
 +                    file_id: decl.nav.file_id,
 +                    range: decl.nav.focus_or_full_range(),
 +                })
 +            } else {
 +                None
 +            };
 +            refs.references
 +                .into_iter()
 +                .flat_map(|(file_id, refs)| {
 +                    refs.into_iter().map(move |(range, _)| FileRange { file_id, range })
 +                })
 +                .chain(decl)
 +        })
 +        .filter_map(|frange| to_proto::location(&snap, frange).ok())
 +        .collect();
 +
 +    Ok(Some(locations))
 +}
 +
 +pub(crate) fn handle_formatting(
 +    snap: GlobalStateSnapshot,
 +    params: DocumentFormattingParams,
 +) -> Result<Option<Vec<lsp_types::TextEdit>>> {
 +    let _p = profile::span("handle_formatting");
 +
 +    run_rustfmt(&snap, params.text_document, None)
 +}
 +
 +pub(crate) fn handle_range_formatting(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::DocumentRangeFormattingParams,
 +) -> Result<Option<Vec<lsp_types::TextEdit>>> {
 +    let _p = profile::span("handle_range_formatting");
 +
 +    run_rustfmt(&snap, params.text_document, Some(params.range))
 +}
 +
 +pub(crate) fn handle_code_action(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::CodeActionParams,
 +) -> Result<Option<Vec<lsp_ext::CodeAction>>> {
 +    let _p = profile::span("handle_code_action");
 +
 +    if !snap.config.code_action_literals() {
 +        // We intentionally don't support command-based actions, as those either
 +        // require either custom client-code or server-initiated edits. Server
 +        // initiated edits break causality, so we avoid those.
 +        return Ok(None);
 +    }
 +
 +    let line_index =
 +        snap.file_line_index(from_proto::file_id(&snap, &params.text_document.uri)?)?;
 +    let frange = from_proto::file_range(&snap, params.text_document.clone(), params.range)?;
 +
 +    let mut assists_config = snap.config.assist();
 +    assists_config.allowed = params
 +        .context
 +        .only
 +        .clone()
 +        .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect());
 +
 +    let mut res: Vec<lsp_ext::CodeAction> = Vec::new();
 +
 +    let code_action_resolve_cap = snap.config.code_action_resolve();
 +    let resolve = if code_action_resolve_cap {
 +        AssistResolveStrategy::None
 +    } else {
 +        AssistResolveStrategy::All
 +    };
 +    let assists = snap.analysis.assists_with_fixes(
 +        &assists_config,
 +        &snap.config.diagnostics(),
 +        resolve,
 +        frange,
 +    )?;
 +    for (index, assist) in assists.into_iter().enumerate() {
 +        let resolve_data =
 +            if code_action_resolve_cap { Some((index, params.clone())) } else { None };
 +        let code_action = to_proto::code_action(&snap, assist, resolve_data)?;
 +        res.push(code_action)
 +    }
 +
 +    // Fixes from `cargo check`.
 +    for fix in
 +        snap.check_fixes.values().filter_map(|it| it.get(&frange.file_id)).into_iter().flatten()
 +    {
 +        // FIXME: this mapping is awkward and shouldn't exist. Refactor
 +        // `snap.check_fixes` to not convert to LSP prematurely.
 +        let intersect_fix_range = fix
 +            .ranges
 +            .iter()
 +            .copied()
 +            .filter_map(|range| from_proto::text_range(&line_index, range).ok())
 +            .any(|fix_range| fix_range.intersect(frange.range).is_some());
 +        if intersect_fix_range {
 +            res.push(fix.action.clone());
 +        }
 +    }
 +
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_code_action_resolve(
 +    snap: GlobalStateSnapshot,
 +    mut code_action: lsp_ext::CodeAction,
 +) -> Result<lsp_ext::CodeAction> {
 +    let _p = profile::span("handle_code_action_resolve");
 +    let params = match code_action.data.take() {
 +        Some(it) => it,
 +        None => return Err(invalid_params_error("code action without data".to_string()).into()),
 +    };
 +
 +    let file_id = from_proto::file_id(&snap, &params.code_action_params.text_document.uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let range = from_proto::text_range(&line_index, params.code_action_params.range)?;
 +    let frange = FileRange { file_id, range };
 +
 +    let mut assists_config = snap.config.assist();
 +    assists_config.allowed = params
 +        .code_action_params
 +        .context
 +        .only
 +        .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect());
 +
 +    let (assist_index, assist_resolve) = match parse_action_id(&params.id) {
 +        Ok(parsed_data) => parsed_data,
 +        Err(e) => {
 +            return Err(invalid_params_error(format!(
 +                "Failed to parse action id string '{}': {}",
 +                params.id, e
 +            ))
 +            .into())
 +        }
 +    };
 +
 +    let expected_assist_id = assist_resolve.assist_id.clone();
 +    let expected_kind = assist_resolve.assist_kind;
 +
 +    let assists = snap.analysis.assists_with_fixes(
 +        &assists_config,
 +        &snap.config.diagnostics(),
 +        AssistResolveStrategy::Single(assist_resolve),
 +        frange,
 +    )?;
 +
 +    let assist = match assists.get(assist_index) {
 +        Some(assist) => assist,
 +        None => return Err(invalid_params_error(format!(
 +            "Failed to find the assist for index {} provided by the resolve request. Resolve request assist id: {}",
 +            assist_index, params.id,
 +        ))
 +        .into())
 +    };
 +    if assist.id.0 != expected_assist_id || assist.id.1 != expected_kind {
 +        return Err(invalid_params_error(format!(
 +            "Mismatching assist at index {} for the resolve parameters given. Resolve request assist id: {}, actual id: {:?}.",
 +            assist_index, params.id, assist.id
 +        ))
 +        .into());
 +    }
 +    let ca = to_proto::code_action(&snap, assist.clone(), None)?;
 +    code_action.edit = ca.edit;
 +    code_action.command = ca.command;
 +    Ok(code_action)
 +}
 +
 +fn parse_action_id(action_id: &str) -> Result<(usize, SingleResolve), String> {
 +    let id_parts = action_id.split(':').collect::<Vec<_>>();
 +    match id_parts.as_slice() {
 +        [assist_id_string, assist_kind_string, index_string] => {
 +            let assist_kind: AssistKind = assist_kind_string.parse()?;
 +            let index: usize = match index_string.parse() {
 +                Ok(index) => index,
 +                Err(e) => return Err(format!("Incorrect index string: {}", e)),
 +            };
 +            Ok((index, SingleResolve { assist_id: assist_id_string.to_string(), assist_kind }))
 +        }
 +        _ => Err("Action id contains incorrect number of segments".to_string()),
 +    }
 +}
 +
 +pub(crate) fn handle_code_lens(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::CodeLensParams,
 +) -> Result<Option<Vec<CodeLens>>> {
 +    let _p = profile::span("handle_code_lens");
 +
 +    let lens_config = snap.config.lens();
 +    if lens_config.none() {
 +        // early return before any db query!
 +        return Ok(Some(Vec::default()));
 +    }
 +
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let cargo_target_spec = CargoTargetSpec::for_file(&snap, file_id)?;
 +
 +    let annotations = snap.analysis.annotations(
 +        &AnnotationConfig {
 +            binary_target: cargo_target_spec
 +                .map(|spec| {
 +                    matches!(
 +                        spec.target_kind,
 +                        TargetKind::Bin | TargetKind::Example | TargetKind::Test
 +                    )
 +                })
 +                .unwrap_or(false),
 +            annotate_runnables: lens_config.runnable(),
 +            annotate_impls: lens_config.implementations,
 +            annotate_references: lens_config.refs_adt,
 +            annotate_method_references: lens_config.method_refs,
 +            annotate_enum_variant_references: lens_config.enum_variant_refs,
 +        },
 +        file_id,
 +    )?;
 +
 +    let mut res = Vec::new();
 +    for a in annotations {
 +        to_proto::code_lens(&mut res, &snap, a)?;
 +    }
 +
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_code_lens_resolve(
 +    snap: GlobalStateSnapshot,
 +    code_lens: CodeLens,
 +) -> Result<CodeLens> {
 +    let annotation = from_proto::annotation(&snap, code_lens.clone())?;
 +    let annotation = snap.analysis.resolve_annotation(annotation)?;
 +
 +    let mut acc = Vec::new();
 +    to_proto::code_lens(&mut acc, &snap, annotation)?;
 +
 +    let res = match acc.pop() {
 +        Some(it) if acc.is_empty() => it,
 +        _ => {
 +            never!();
 +            code_lens
 +        }
 +    };
 +
 +    Ok(res)
 +}
 +
 +pub(crate) fn handle_document_highlight(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::DocumentHighlightParams,
 +) -> Result<Option<Vec<lsp_types::DocumentHighlight>>> {
 +    let _p = profile::span("handle_document_highlight");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +    let line_index = snap.file_line_index(position.file_id)?;
 +
 +    let refs = match snap.analysis.highlight_related(snap.config.highlight_related(), position)? {
 +        None => return Ok(None),
 +        Some(refs) => refs,
 +    };
 +    let res = refs
 +        .into_iter()
 +        .map(|ide::HighlightedRange { range, category }| lsp_types::DocumentHighlight {
 +            range: to_proto::range(&line_index, range),
 +            kind: category.map(to_proto::document_highlight_kind),
 +        })
 +        .collect();
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_ssr(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::SsrParams,
 +) -> Result<lsp_types::WorkspaceEdit> {
 +    let _p = profile::span("handle_ssr");
 +    let selections = params
 +        .selections
 +        .iter()
 +        .map(|range| from_proto::file_range(&snap, params.position.text_document.clone(), *range))
 +        .collect::<Result<Vec<_>, _>>()?;
 +    let position = from_proto::file_position(&snap, params.position)?;
 +    let source_change = snap.analysis.structural_search_replace(
 +        &params.query,
 +        params.parse_only,
 +        position,
 +        selections,
 +    )??;
 +    to_proto::workspace_edit(&snap, source_change)
 +}
 +
 +pub(crate) fn publish_diagnostics(
 +    snap: &GlobalStateSnapshot,
 +    file_id: FileId,
 +) -> Result<Vec<Diagnostic>> {
 +    let _p = profile::span("publish_diagnostics");
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let diagnostics: Vec<Diagnostic> = snap
 +        .analysis
 +        .diagnostics(&snap.config.diagnostics(), AssistResolveStrategy::None, file_id)?
 +        .into_iter()
 +        .map(|d| Diagnostic {
 +            range: to_proto::range(&line_index, d.range),
 +            severity: Some(to_proto::diagnostic_severity(d.severity)),
 +            code: Some(NumberOrString::String(d.code.as_str().to_string())),
 +            code_description: Some(lsp_types::CodeDescription {
 +                href: lsp_types::Url::parse(&format!(
 +                    "https://rust-analyzer.github.io/manual.html#{}",
 +                    d.code.as_str()
 +                ))
 +                .unwrap(),
 +            }),
 +            source: Some("rust-analyzer".to_string()),
 +            message: d.message,
 +            related_information: None,
 +            tags: if d.unused { Some(vec![DiagnosticTag::UNNECESSARY]) } else { None },
 +            data: None,
 +        })
 +        .collect();
 +    Ok(diagnostics)
 +}
 +
 +pub(crate) fn handle_inlay_hints(
 +    snap: GlobalStateSnapshot,
 +    params: InlayHintParams,
 +) -> Result<Option<Vec<InlayHint>>> {
 +    let _p = profile::span("handle_inlay_hints");
 +    let document_uri = &params.text_document.uri;
 +    let file_id = from_proto::file_id(&snap, document_uri)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +    let range = from_proto::file_range(
 +        &snap,
 +        TextDocumentIdentifier::new(document_uri.to_owned()),
 +        params.range,
 +    )?;
 +    let inlay_hints_config = snap.config.inlay_hints();
 +    Ok(Some(
 +        snap.analysis
 +            .inlay_hints(&inlay_hints_config, file_id, Some(range))?
 +            .into_iter()
 +            .map(|it| {
 +                to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it)
 +            })
 +            .collect(),
 +    ))
 +}
 +
 +pub(crate) fn handle_inlay_hints_resolve(
 +    snap: GlobalStateSnapshot,
 +    mut hint: InlayHint,
 +) -> Result<InlayHint> {
 +    let _p = profile::span("handle_inlay_hints_resolve");
 +    let data = match hint.data.take() {
 +        Some(it) => it,
 +        None => return Ok(hint),
 +    };
 +
 +    let resolve_data: lsp_ext::InlayHintResolveData = serde_json::from_value(data)?;
 +
 +    let file_range = from_proto::file_range(
 +        &snap,
 +        resolve_data.text_document,
 +        match resolve_data.position {
 +            PositionOrRange::Position(pos) => Range::new(pos, pos),
 +            PositionOrRange::Range(range) => range,
 +        },
 +    )?;
 +    let info = match snap.analysis.hover(&snap.config.hover(), file_range)? {
 +        None => return Ok(hint),
 +        Some(info) => info,
 +    };
 +
 +    let markup_kind =
 +        snap.config.hover().documentation.map_or(ide::HoverDocFormat::Markdown, |kind| kind);
 +
 +    // FIXME: hover actions?
 +    hint.tooltip = Some(lsp_types::InlayHintTooltip::MarkupContent(to_proto::markup_content(
 +        info.info.markup,
 +        markup_kind,
 +    )));
 +    Ok(hint)
 +}
 +
 +pub(crate) fn handle_call_hierarchy_prepare(
 +    snap: GlobalStateSnapshot,
 +    params: CallHierarchyPrepareParams,
 +) -> Result<Option<Vec<CallHierarchyItem>>> {
 +    let _p = profile::span("handle_call_hierarchy_prepare");
 +    let position = from_proto::file_position(&snap, params.text_document_position_params)?;
 +
 +    let nav_info = match snap.analysis.call_hierarchy(position)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +
 +    let RangeInfo { range: _, info: navs } = nav_info;
 +    let res = navs
 +        .into_iter()
 +        .filter(|it| it.kind == Some(SymbolKind::Function))
 +        .map(|it| to_proto::call_hierarchy_item(&snap, it))
 +        .collect::<Result<Vec<_>>>()?;
 +
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_call_hierarchy_incoming(
 +    snap: GlobalStateSnapshot,
 +    params: CallHierarchyIncomingCallsParams,
 +) -> Result<Option<Vec<CallHierarchyIncomingCall>>> {
 +    let _p = profile::span("handle_call_hierarchy_incoming");
 +    let item = params.item;
 +
 +    let doc = TextDocumentIdentifier::new(item.uri);
 +    let frange = from_proto::file_range(&snap, doc, item.selection_range)?;
 +    let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
 +
 +    let call_items = match snap.analysis.incoming_calls(fpos)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +
 +    let mut res = vec![];
 +
 +    for call_item in call_items.into_iter() {
 +        let file_id = call_item.target.file_id;
 +        let line_index = snap.file_line_index(file_id)?;
 +        let item = to_proto::call_hierarchy_item(&snap, call_item.target)?;
 +        res.push(CallHierarchyIncomingCall {
 +            from: item,
 +            from_ranges: call_item
 +                .ranges
 +                .into_iter()
 +                .map(|it| to_proto::range(&line_index, it))
 +                .collect(),
 +        });
 +    }
 +
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_call_hierarchy_outgoing(
 +    snap: GlobalStateSnapshot,
 +    params: CallHierarchyOutgoingCallsParams,
 +) -> Result<Option<Vec<CallHierarchyOutgoingCall>>> {
 +    let _p = profile::span("handle_call_hierarchy_outgoing");
 +    let item = params.item;
 +
 +    let doc = TextDocumentIdentifier::new(item.uri);
 +    let frange = from_proto::file_range(&snap, doc, item.selection_range)?;
 +    let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
 +
 +    let call_items = match snap.analysis.outgoing_calls(fpos)? {
 +        None => return Ok(None),
 +        Some(it) => it,
 +    };
 +
 +    let mut res = vec![];
 +
 +    for call_item in call_items.into_iter() {
 +        let file_id = call_item.target.file_id;
 +        let line_index = snap.file_line_index(file_id)?;
 +        let item = to_proto::call_hierarchy_item(&snap, call_item.target)?;
 +        res.push(CallHierarchyOutgoingCall {
 +            to: item,
 +            from_ranges: call_item
 +                .ranges
 +                .into_iter()
 +                .map(|it| to_proto::range(&line_index, it))
 +                .collect(),
 +        });
 +    }
 +
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_semantic_tokens_full(
 +    snap: GlobalStateSnapshot,
 +    params: SemanticTokensParams,
 +) -> Result<Option<SemanticTokensResult>> {
 +    let _p = profile::span("handle_semantic_tokens_full");
 +
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let text = snap.analysis.file_text(file_id)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +
-     let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?;
++    let mut highlight_config = snap.config.highlighting_config();
++    // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
++    highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded;
++
++    let highlights = snap.analysis.highlight(highlight_config, file_id)?;
 +    let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 +
 +    // Unconditionally cache the tokens
 +    snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens.clone());
 +
 +    Ok(Some(semantic_tokens.into()))
 +}
 +
 +pub(crate) fn handle_semantic_tokens_full_delta(
 +    snap: GlobalStateSnapshot,
 +    params: SemanticTokensDeltaParams,
 +) -> Result<Option<SemanticTokensFullDeltaResult>> {
 +    let _p = profile::span("handle_semantic_tokens_full_delta");
 +
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let text = snap.analysis.file_text(file_id)?;
 +    let line_index = snap.file_line_index(file_id)?;
 +
++    let mut highlight_config = snap.config.highlighting_config();
++    // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
++    highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded;
++
++    let highlights = snap.analysis.highlight(highlight_config, file_id)?;
 +    let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 +
 +    let mut cache = snap.semantic_tokens_cache.lock();
 +    let cached_tokens = cache.entry(params.text_document.uri).or_default();
 +
 +    if let Some(prev_id) = &cached_tokens.result_id {
 +        if *prev_id == params.previous_result_id {
 +            let delta = to_proto::semantic_token_delta(cached_tokens, &semantic_tokens);
 +            *cached_tokens = semantic_tokens;
 +            return Ok(Some(delta.into()));
 +        }
 +    }
 +
 +    *cached_tokens = semantic_tokens.clone();
 +
 +    Ok(Some(semantic_tokens.into()))
 +}
 +
 +pub(crate) fn handle_semantic_tokens_range(
 +    snap: GlobalStateSnapshot,
 +    params: SemanticTokensRangeParams,
 +) -> Result<Option<SemanticTokensRangeResult>> {
 +    let _p = profile::span("handle_semantic_tokens_range");
 +
 +    let frange = from_proto::file_range(&snap, params.text_document, params.range)?;
 +    let text = snap.analysis.file_text(frange.file_id)?;
 +    let line_index = snap.file_line_index(frange.file_id)?;
 +
 +    let highlights = snap.analysis.highlight_range(snap.config.highlighting_config(), frange)?;
 +    let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 +    Ok(Some(semantic_tokens.into()))
 +}
 +
 +pub(crate) fn handle_open_docs(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_types::TextDocumentPositionParams,
 +) -> Result<Option<lsp_types::Url>> {
 +    let _p = profile::span("handle_open_docs");
 +    let position = from_proto::file_position(&snap, params)?;
 +
 +    let remote = snap.analysis.external_docs(position)?;
 +
 +    Ok(remote.and_then(|remote| Url::parse(&remote).ok()))
 +}
 +
 +pub(crate) fn handle_open_cargo_toml(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::OpenCargoTomlParams,
 +) -> Result<Option<lsp_types::GotoDefinitionResponse>> {
 +    let _p = profile::span("handle_open_cargo_toml");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +
 +    let cargo_spec = match CargoTargetSpec::for_file(&snap, file_id)? {
 +        Some(it) => it,
 +        None => return Ok(None),
 +    };
 +
 +    let cargo_toml_url = to_proto::url_from_abs_path(&cargo_spec.cargo_toml);
 +    let res: lsp_types::GotoDefinitionResponse =
 +        Location::new(cargo_toml_url, Range::default()).into();
 +    Ok(Some(res))
 +}
 +
 +pub(crate) fn handle_move_item(
 +    snap: GlobalStateSnapshot,
 +    params: lsp_ext::MoveItemParams,
 +) -> Result<Vec<lsp_ext::SnippetTextEdit>> {
 +    let _p = profile::span("handle_move_item");
 +    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 +    let range = from_proto::file_range(&snap, params.text_document, params.range)?;
 +
 +    let direction = match params.direction {
 +        lsp_ext::MoveItemDirection::Up => ide::Direction::Up,
 +        lsp_ext::MoveItemDirection::Down => ide::Direction::Down,
 +    };
 +
 +    match snap.analysis.move_item(range, direction)? {
 +        Some(text_edit) => {
 +            let line_index = snap.file_line_index(file_id)?;
 +            Ok(to_proto::snippet_text_edit_vec(&line_index, true, text_edit))
 +        }
 +        None => Ok(vec![]),
 +    }
 +}
 +
 +fn to_command_link(command: lsp_types::Command, tooltip: String) -> lsp_ext::CommandLink {
 +    lsp_ext::CommandLink { tooltip: Some(tooltip), command }
 +}
 +
 +fn show_impl_command_link(
 +    snap: &GlobalStateSnapshot,
 +    position: &FilePosition,
 +) -> Option<lsp_ext::CommandLinkGroup> {
 +    if snap.config.hover_actions().implementations && snap.config.client_commands().show_reference {
 +        if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) {
 +            let uri = to_proto::url(snap, position.file_id);
 +            let line_index = snap.file_line_index(position.file_id).ok()?;
 +            let position = to_proto::position(&line_index, position.offset);
 +            let locations: Vec<_> = nav_data
 +                .info
 +                .into_iter()
 +                .filter_map(|nav| to_proto::location_from_nav(snap, nav).ok())
 +                .collect();
 +            let title = to_proto::implementation_title(locations.len());
 +            let command = to_proto::command::show_references(title, &uri, position, locations);
 +
 +            return Some(lsp_ext::CommandLinkGroup {
 +                commands: vec![to_command_link(command, "Go to implementations".into())],
 +                ..Default::default()
 +            });
 +        }
 +    }
 +    None
 +}
 +
 +fn show_ref_command_link(
 +    snap: &GlobalStateSnapshot,
 +    position: &FilePosition,
 +) -> Option<lsp_ext::CommandLinkGroup> {
 +    if snap.config.hover_actions().references && snap.config.client_commands().show_reference {
 +        if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) {
 +            let uri = to_proto::url(snap, position.file_id);
 +            let line_index = snap.file_line_index(position.file_id).ok()?;
 +            let position = to_proto::position(&line_index, position.offset);
 +            let locations: Vec<_> = ref_search_res
 +                .into_iter()
 +                .flat_map(|res| res.references)
 +                .flat_map(|(file_id, ranges)| {
 +                    ranges.into_iter().filter_map(move |(range, _)| {
 +                        to_proto::location(snap, FileRange { file_id, range }).ok()
 +                    })
 +                })
 +                .collect();
 +            let title = to_proto::reference_title(locations.len());
 +            let command = to_proto::command::show_references(title, &uri, position, locations);
 +
 +            return Some(lsp_ext::CommandLinkGroup {
 +                commands: vec![to_command_link(command, "Go to references".into())],
 +                ..Default::default()
 +            });
 +        }
 +    }
 +    None
 +}
 +
 +fn runnable_action_links(
 +    snap: &GlobalStateSnapshot,
 +    runnable: Runnable,
 +) -> Option<lsp_ext::CommandLinkGroup> {
 +    let hover_actions_config = snap.config.hover_actions();
 +    if !hover_actions_config.runnable() {
 +        return None;
 +    }
 +
 +    let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?;
 +    if should_skip_target(&runnable, cargo_spec.as_ref()) {
 +        return None;
 +    }
 +
 +    let client_commands_config = snap.config.client_commands();
 +    if !(client_commands_config.run_single || client_commands_config.debug_single) {
 +        return None;
 +    }
 +
 +    let title = runnable.title();
 +    let r = to_proto::runnable(snap, runnable).ok()?;
 +
 +    let mut group = lsp_ext::CommandLinkGroup::default();
 +
 +    if hover_actions_config.run && client_commands_config.run_single {
 +        let run_command = to_proto::command::run_single(&r, &title);
 +        group.commands.push(to_command_link(run_command, r.label.clone()));
 +    }
 +
 +    if hover_actions_config.debug && client_commands_config.debug_single {
 +        let dbg_command = to_proto::command::debug_single(&r);
 +        group.commands.push(to_command_link(dbg_command, r.label));
 +    }
 +
 +    Some(group)
 +}
 +
 +fn goto_type_action_links(
 +    snap: &GlobalStateSnapshot,
 +    nav_targets: &[HoverGotoTypeData],
 +) -> Option<lsp_ext::CommandLinkGroup> {
 +    if !snap.config.hover_actions().goto_type_def
 +        || nav_targets.is_empty()
 +        || !snap.config.client_commands().goto_location
 +    {
 +        return None;
 +    }
 +
 +    Some(lsp_ext::CommandLinkGroup {
 +        title: Some("Go to ".into()),
 +        commands: nav_targets
 +            .iter()
 +            .filter_map(|it| {
 +                to_proto::command::goto_location(snap, &it.nav)
 +                    .map(|cmd| to_command_link(cmd, it.mod_path.clone()))
 +            })
 +            .collect(),
 +    })
 +}
 +
 +fn prepare_hover_actions(
 +    snap: &GlobalStateSnapshot,
 +    actions: &[HoverAction],
 +) -> Vec<lsp_ext::CommandLinkGroup> {
 +    actions
 +        .iter()
 +        .filter_map(|it| match it {
 +            HoverAction::Implementation(position) => show_impl_command_link(snap, position),
 +            HoverAction::Reference(position) => show_ref_command_link(snap, position),
 +            HoverAction::Runnable(r) => runnable_action_links(snap, r.clone()),
 +            HoverAction::GoToType(targets) => goto_type_action_links(snap, targets),
 +        })
 +        .collect()
 +}
 +
 +fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>) -> bool {
 +    match runnable.kind {
 +        RunnableKind::Bin => {
 +            // Do not suggest binary run on other target than binary
 +            match &cargo_spec {
 +                Some(spec) => !matches!(
 +                    spec.target_kind,
 +                    TargetKind::Bin | TargetKind::Example | TargetKind::Test
 +                ),
 +                None => true,
 +            }
 +        }
 +        _ => false,
 +    }
 +}
 +
 +fn run_rustfmt(
 +    snap: &GlobalStateSnapshot,
 +    text_document: TextDocumentIdentifier,
 +    range: Option<lsp_types::Range>,
 +) -> Result<Option<Vec<lsp_types::TextEdit>>> {
 +    let file_id = from_proto::file_id(snap, &text_document.uri)?;
 +    let file = snap.analysis.file_text(file_id)?;
 +    let crate_ids = snap.analysis.crate_for(file_id)?;
 +
 +    let line_index = snap.file_line_index(file_id)?;
 +
 +    let mut command = match snap.config.rustfmt() {
 +        RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => {
 +            let mut cmd = process::Command::new(toolchain::rustfmt());
 +            cmd.args(extra_args);
 +            // try to chdir to the file so we can respect `rustfmt.toml`
 +            // FIXME: use `rustfmt --config-path` once
 +            // https://github.com/rust-lang/rustfmt/issues/4660 gets fixed
 +            match text_document.uri.to_file_path() {
 +                Ok(mut path) => {
 +                    // pop off file name
 +                    if path.pop() && path.is_dir() {
 +                        cmd.current_dir(path);
 +                    }
 +                }
 +                Err(_) => {
 +                    tracing::error!(
 +                        "Unable to get file path for {}, rustfmt.toml might be ignored",
 +                        text_document.uri
 +                    );
 +                }
 +            }
 +            if let Some(&crate_id) = crate_ids.first() {
 +                // Assume all crates are in the same edition
 +                let edition = snap.analysis.crate_edition(crate_id)?;
 +                cmd.arg("--edition");
 +                cmd.arg(edition.to_string());
 +            }
 +
 +            if let Some(range) = range {
 +                if !enable_range_formatting {
 +                    return Err(LspError::new(
 +                        ErrorCode::InvalidRequest as i32,
 +                        String::from(
 +                            "rustfmt range formatting is unstable. \
 +                            Opt-in by using a nightly build of rustfmt and setting \
 +                            `rustfmt.rangeFormatting.enable` to true in your LSP configuration",
 +                        ),
 +                    )
 +                    .into());
 +                }
 +
 +                let frange = from_proto::file_range(snap, text_document, range)?;
 +                let start_line = line_index.index.line_col(frange.range.start()).line;
 +                let end_line = line_index.index.line_col(frange.range.end()).line;
 +
 +                cmd.arg("--unstable-features");
 +                cmd.arg("--file-lines");
 +                cmd.arg(
 +                    json!([{
 +                        "file": "stdin",
 +                        "range": [start_line, end_line]
 +                    }])
 +                    .to_string(),
 +                );
 +            }
 +
 +            cmd
 +        }
 +        RustfmtConfig::CustomCommand { command, args } => {
 +            let mut cmd = process::Command::new(command);
 +            cmd.args(args);
 +            cmd
 +        }
 +    };
 +
 +    let mut rustfmt = command
 +        .stdin(Stdio::piped())
 +        .stdout(Stdio::piped())
 +        .stderr(Stdio::piped())
 +        .spawn()
 +        .context(format!("Failed to spawn {:?}", command))?;
 +
 +    rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?;
 +
 +    let output = rustfmt.wait_with_output()?;
 +    let captured_stdout = String::from_utf8(output.stdout)?;
 +    let captured_stderr = String::from_utf8(output.stderr).unwrap_or_default();
 +
 +    if !output.status.success() {
 +        let rustfmt_not_installed =
 +            captured_stderr.contains("not installed") || captured_stderr.contains("not available");
 +
 +        return match output.status.code() {
 +            Some(1) if !rustfmt_not_installed => {
 +                // While `rustfmt` doesn't have a specific exit code for parse errors this is the
 +                // likely cause exiting with 1. Most Language Servers swallow parse errors on
 +                // formatting because otherwise an error is surfaced to the user on top of the
 +                // syntax error diagnostics they're already receiving. This is especially jarring
 +                // if they have format on save enabled.
 +                tracing::warn!(
 +                    ?command,
 +                    %captured_stderr,
 +                    "rustfmt exited with status 1"
 +                );
 +                Ok(None)
 +            }
 +            _ => {
 +                // Something else happened - e.g. `rustfmt` is missing or caught a signal
 +                Err(LspError::new(
 +                    -32900,
 +                    format!(
 +                        r#"rustfmt exited with:
 +                           Status: {}
 +                           stdout: {}
 +                           stderr: {}"#,
 +                        output.status, captured_stdout, captured_stderr,
 +                    ),
 +                )
 +                .into())
 +            }
 +        };
 +    }
 +
 +    let (new_text, new_line_endings) = LineEndings::normalize(captured_stdout);
 +
 +    if line_index.endings != new_line_endings {
 +        // If line endings are different, send the entire file.
 +        // Diffing would not work here, as the line endings might be the only
 +        // difference.
 +        Ok(Some(to_proto::text_edit_vec(
 +            &line_index,
 +            TextEdit::replace(TextRange::up_to(TextSize::of(&*file)), new_text),
 +        )))
 +    } else if *file == new_text {
 +        // The document is already formatted correctly -- no edits needed.
 +        Ok(None)
 +    } else {
 +        Ok(Some(to_proto::text_edit_vec(&line_index, diff(&file, &new_text))))
 +    }
 +}
index ceb2a6d703d959ad819f422ae27d0e807f1d25d9,0000000000000000000000000000000000000000..f23bbca6387659aa24d32e97036154883bea9a33
mode 100644,000000..100644
--- /dev/null
@@@ -1,722 -1,0 +1,722 @@@
-                     .collect();
-             }
 +//! Project loading & configuration updates.
 +//!
 +//! This is quite tricky. The main problem is time and changes -- there's no
 +//! fixed "project" rust-analyzer is working with, "current project" is itself
 +//! mutable state. For example, when the user edits `Cargo.toml` by adding a new
 +//! dependency, project model changes. What's more, switching project model is
 +//! not instantaneous -- it takes time to run `cargo metadata` and (for proc
 +//! macros) `cargo check`.
 +//!
 +//! The main guiding principle here is, as elsewhere in rust-analyzer,
 +//! robustness. We try not to assume that the project model exists or is
 +//! correct. Instead, we try to provide a best-effort service. Even if the
 +//! project is currently loading and we don't have a full project model, we
 +//! still want to respond to various  requests.
 +use std::{mem, sync::Arc};
 +
 +use flycheck::{FlycheckConfig, FlycheckHandle};
 +use hir::db::DefDatabase;
 +use ide::Change;
 +use ide_db::base_db::{
 +    CrateGraph, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind,
 +    ProcMacroLoadResult, SourceRoot, VfsPath,
 +};
 +use proc_macro_api::{MacroDylib, ProcMacroServer};
 +use project_model::{ProjectWorkspace, WorkspaceBuildScripts};
 +use syntax::SmolStr;
 +use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};
 +
 +use crate::{
 +    config::{Config, FilesWatcher, LinkedProject},
 +    global_state::GlobalState,
 +    lsp_ext,
 +    main_loop::Task,
 +    op_queue::Cause,
 +};
 +
 +#[derive(Debug)]
 +pub(crate) enum ProjectWorkspaceProgress {
 +    Begin,
 +    Report(String),
 +    End(Vec<anyhow::Result<ProjectWorkspace>>),
 +}
 +
 +#[derive(Debug)]
 +pub(crate) enum BuildDataProgress {
 +    Begin,
 +    Report(String),
 +    End((Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>)),
 +}
 +
 +impl GlobalState {
 +    pub(crate) fn is_quiescent(&self) -> bool {
 +        !(self.fetch_workspaces_queue.op_in_progress()
 +            || self.fetch_build_data_queue.op_in_progress()
 +            || self.vfs_progress_config_version < self.vfs_config_version
 +            || self.vfs_progress_n_done < self.vfs_progress_n_total)
 +    }
 +
 +    pub(crate) fn update_configuration(&mut self, config: Config) {
 +        let _p = profile::span("GlobalState::update_configuration");
 +        let old_config = mem::replace(&mut self.config, Arc::new(config));
 +        if self.config.lru_capacity() != old_config.lru_capacity() {
 +            self.analysis_host.update_lru_capacity(self.config.lru_capacity());
 +        }
 +        if self.config.linked_projects() != old_config.linked_projects() {
 +            self.fetch_workspaces_queue.request_op("linked projects changed".to_string())
 +        } else if self.config.flycheck() != old_config.flycheck() {
 +            self.reload_flycheck();
 +        }
 +
 +        if self.analysis_host.raw_database().enable_proc_attr_macros()
 +            != self.config.expand_proc_attr_macros()
 +        {
 +            self.analysis_host
 +                .raw_database_mut()
 +                .set_enable_proc_attr_macros(self.config.expand_proc_attr_macros());
 +        }
 +    }
 +
 +    pub(crate) fn current_status(&self) -> lsp_ext::ServerStatusParams {
 +        let mut status = lsp_ext::ServerStatusParams {
 +            health: lsp_ext::Health::Ok,
 +            quiescent: self.is_quiescent(),
 +            message: None,
 +        };
 +
 +        if self.proc_macro_changed {
 +            status.health = lsp_ext::Health::Warning;
 +            status.message =
 +                Some("Reload required due to source changes of a procedural macro.".into())
 +        }
 +        if let Err(_) = self.fetch_build_data_error() {
 +            status.health = lsp_ext::Health::Warning;
 +            status.message =
 +                Some("Failed to run build scripts of some packages, check the logs.".to_string());
 +        }
 +        if !self.config.cargo_autoreload()
 +            && self.is_quiescent()
 +            && self.fetch_workspaces_queue.op_requested()
 +        {
 +            status.health = lsp_ext::Health::Warning;
 +            status.message = Some("Workspace reload required".to_string())
 +        }
 +
 +        if let Err(error) = self.fetch_workspace_error() {
 +            status.health = lsp_ext::Health::Error;
 +            status.message = Some(error)
 +        }
 +        status
 +    }
 +
 +    pub(crate) fn fetch_workspaces(&mut self, cause: Cause) {
 +        tracing::info!(%cause, "will fetch workspaces");
 +
 +        self.task_pool.handle.spawn_with_sender({
 +            let linked_projects = self.config.linked_projects();
 +            let detached_files = self.config.detached_files().to_vec();
 +            let cargo_config = self.config.cargo();
 +
 +            move |sender| {
 +                let progress = {
 +                    let sender = sender.clone();
 +                    move |msg| {
 +                        sender
 +                            .send(Task::FetchWorkspace(ProjectWorkspaceProgress::Report(msg)))
 +                            .unwrap()
 +                    }
 +                };
 +
 +                sender.send(Task::FetchWorkspace(ProjectWorkspaceProgress::Begin)).unwrap();
 +
 +                let mut workspaces = linked_projects
 +                    .iter()
 +                    .map(|project| match project {
 +                        LinkedProject::ProjectManifest(manifest) => {
 +                            project_model::ProjectWorkspace::load(
 +                                manifest.clone(),
 +                                &cargo_config,
 +                                &progress,
 +                            )
 +                        }
 +                        LinkedProject::InlineJsonProject(it) => {
 +                            project_model::ProjectWorkspace::load_inline(
 +                                it.clone(),
 +                                cargo_config.target.as_deref(),
 +                            )
 +                        }
 +                    })
 +                    .collect::<Vec<_>>();
 +
 +                if !detached_files.is_empty() {
 +                    workspaces
 +                        .push(project_model::ProjectWorkspace::load_detached_files(detached_files));
 +                }
 +
 +                tracing::info!("did fetch workspaces {:?}", workspaces);
 +                sender
 +                    .send(Task::FetchWorkspace(ProjectWorkspaceProgress::End(workspaces)))
 +                    .unwrap();
 +            }
 +        });
 +    }
 +
 +    pub(crate) fn fetch_build_data(&mut self, cause: Cause) {
 +        tracing::info!(%cause, "will fetch build data");
 +        let workspaces = Arc::clone(&self.workspaces);
 +        let config = self.config.cargo();
 +        self.task_pool.handle.spawn_with_sender(move |sender| {
 +            sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap();
 +
 +            let progress = {
 +                let sender = sender.clone();
 +                move |msg| {
 +                    sender.send(Task::FetchBuildData(BuildDataProgress::Report(msg))).unwrap()
 +                }
 +            };
 +            let mut res = Vec::new();
 +            for ws in workspaces.iter() {
 +                res.push(ws.run_build_scripts(&config, &progress));
 +            }
 +            sender.send(Task::FetchBuildData(BuildDataProgress::End((workspaces, res)))).unwrap();
 +        });
 +    }
 +
 +    pub(crate) fn switch_workspaces(&mut self, cause: Cause) {
 +        let _p = profile::span("GlobalState::switch_workspaces");
 +        tracing::info!(%cause, "will switch workspaces");
 +
 +        if let Err(error_message) = self.fetch_workspace_error() {
 +            self.show_and_log_error(error_message, None);
 +            if !self.workspaces.is_empty() {
 +                // It only makes sense to switch to a partially broken workspace
 +                // if we don't have any workspace at all yet.
 +                return;
 +            }
 +        }
 +
 +        if let Err(error) = self.fetch_build_data_error() {
 +            self.show_and_log_error("failed to run build scripts".to_string(), Some(error));
 +        }
 +
 +        let workspaces = self
 +            .fetch_workspaces_queue
 +            .last_op_result()
 +            .iter()
 +            .filter_map(|res| res.as_ref().ok().cloned())
 +            .collect::<Vec<_>>();
 +
 +        fn eq_ignore_build_data<'a>(
 +            left: &'a ProjectWorkspace,
 +            right: &'a ProjectWorkspace,
 +        ) -> bool {
 +            let key = |p: &'a ProjectWorkspace| match p {
 +                ProjectWorkspace::Cargo {
 +                    cargo,
 +                    sysroot,
 +                    rustc,
 +                    rustc_cfg,
 +                    cfg_overrides,
 +
 +                    build_scripts: _,
 +                    toolchain: _,
 +                } => Some((cargo, sysroot, rustc, rustc_cfg, cfg_overrides)),
 +                _ => None,
 +            };
 +            match (key(left), key(right)) {
 +                (Some(lk), Some(rk)) => lk == rk,
 +                _ => left == right,
 +            }
 +        }
 +
 +        let same_workspaces = workspaces.len() == self.workspaces.len()
 +            && workspaces
 +                .iter()
 +                .zip(self.workspaces.iter())
 +                .all(|(l, r)| eq_ignore_build_data(l, r));
 +
 +        if same_workspaces {
 +            let (workspaces, build_scripts) = self.fetch_build_data_queue.last_op_result();
 +            if Arc::ptr_eq(workspaces, &self.workspaces) {
 +                tracing::debug!("set build scripts to workspaces");
 +
 +                let workspaces = workspaces
 +                    .iter()
 +                    .cloned()
 +                    .zip(build_scripts)
 +                    .map(|(mut ws, bs)| {
 +                        ws.set_build_scripts(bs.as_ref().ok().cloned().unwrap_or_default());
 +                        ws
 +                    })
 +                    .collect::<Vec<_>>();
 +
 +                // Workspaces are the same, but we've updated build data.
 +                self.workspaces = Arc::new(workspaces);
 +            } else {
 +                tracing::info!("build scripts do not match the version of the active workspace");
 +                // Current build scripts do not match the version of the active
 +                // workspace, so there's nothing for us to update.
 +                return;
 +            }
 +        } else {
 +            tracing::debug!("abandon build scripts for workspaces");
 +
 +            // Here, we completely changed the workspace (Cargo.toml edit), so
 +            // we don't care about build-script results, they are stale.
 +            self.workspaces = Arc::new(workspaces)
 +        }
 +
 +        if let FilesWatcher::Client = self.config.files().watcher {
 +            let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions {
 +                watchers: self
 +                    .workspaces
 +                    .iter()
 +                    .flat_map(|ws| ws.to_roots())
 +                    .filter(|it| it.is_local)
 +                    .flat_map(|root| {
 +                        root.include.into_iter().flat_map(|it| {
 +                            [
 +                                format!("{}/**/*.rs", it.display()),
 +                                format!("{}/**/Cargo.toml", it.display()),
 +                                format!("{}/**/Cargo.lock", it.display()),
 +                            ]
 +                        })
 +                    })
 +                    .map(|glob_pattern| lsp_types::FileSystemWatcher { glob_pattern, kind: None })
 +                    .collect(),
 +            };
 +            let registration = lsp_types::Registration {
 +                id: "workspace/didChangeWatchedFiles".to_string(),
 +                method: "workspace/didChangeWatchedFiles".to_string(),
 +                register_options: Some(serde_json::to_value(registration_options).unwrap()),
 +            };
 +            self.send_request::<lsp_types::request::RegisterCapability>(
 +                lsp_types::RegistrationParams { registrations: vec![registration] },
 +                |_, _| (),
 +            );
 +        }
 +
 +        let mut change = Change::new();
 +
 +        let files_config = self.config.files();
 +        let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
 +
 +        let standalone_server_name =
 +            format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
 +
 +        if self.proc_macro_clients.is_empty() {
 +            if let Some((path, args)) = self.config.proc_macro_srv() {
 +                tracing::info!("Spawning proc-macro servers");
 +                self.proc_macro_clients = self
 +                    .workspaces
 +                    .iter()
 +                    .map(|ws| {
 +                        let mut args = args.clone();
 +                        let mut path = path.clone();
 +
 +                        if let ProjectWorkspace::Cargo { sysroot, .. } = ws {
 +                            tracing::debug!("Found a cargo workspace...");
 +                            if let Some(sysroot) = sysroot.as_ref() {
 +                                tracing::debug!("Found a cargo workspace with a sysroot...");
 +                                let server_path =
 +                                    sysroot.root().join("libexec").join(&standalone_server_name);
 +                                if std::fs::metadata(&server_path).is_ok() {
 +                                    tracing::debug!(
 +                                        "And the server exists at {}",
 +                                        server_path.display()
 +                                    );
 +                                    path = server_path;
 +                                    args = vec![];
 +                                } else {
 +                                    tracing::debug!(
 +                                        "And the server does not exist at {}",
 +                                        server_path.display()
 +                                    );
 +                                }
 +                            }
 +                        }
 +
 +                        tracing::info!(?args, "Using proc-macro server at {}", path.display(),);
 +                        ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| {
 +                            let error = format!(
 +                                "Failed to run proc-macro server from path {}, error: {:?}",
 +                                path.display(),
 +                                err
 +                            );
 +                            tracing::error!(error);
 +                            error
 +                        })
 +                    })
++                    .collect()
++            };
 +        }
 +
 +        let watch = match files_config.watcher {
 +            FilesWatcher::Client => vec![],
 +            FilesWatcher::Server => project_folders.watch,
 +        };
 +        self.vfs_config_version += 1;
 +        self.loader.handle.set_config(vfs::loader::Config {
 +            load: project_folders.load,
 +            watch,
 +            version: self.vfs_config_version,
 +        });
 +
 +        // Create crate graph from all the workspaces
 +        let crate_graph = {
 +            let dummy_replacements = self.config.dummy_replacements();
 +
 +            let vfs = &mut self.vfs.write().0;
 +            let loader = &mut self.loader;
 +            let mem_docs = &self.mem_docs;
 +            let mut load = move |path: &AbsPath| {
 +                let _p = profile::span("GlobalState::load");
 +                let vfs_path = vfs::VfsPath::from(path.to_path_buf());
 +                if !mem_docs.contains(&vfs_path) {
 +                    let contents = loader.handle.load_sync(path);
 +                    vfs.set_file_contents(vfs_path.clone(), contents);
 +                }
 +                let res = vfs.file_id(&vfs_path);
 +                if res.is_none() {
 +                    tracing::warn!("failed to load {}", path.display())
 +                }
 +                res
 +            };
 +
 +            let mut crate_graph = CrateGraph::default();
 +            for (idx, ws) in self.workspaces.iter().enumerate() {
 +                let proc_macro_client = match self.proc_macro_clients.get(idx) {
 +                    Some(res) => res.as_ref().map_err(|e| &**e),
 +                    None => Err("Proc macros are disabled"),
 +                };
 +                let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| {
 +                    load_proc_macro(
 +                        proc_macro_client,
 +                        path,
 +                        dummy_replacements.get(crate_name).map(|v| &**v).unwrap_or_default(),
 +                    )
 +                };
 +                crate_graph.extend(ws.to_crate_graph(&mut load_proc_macro, &mut load));
 +            }
 +            crate_graph
 +        };
 +        change.set_crate_graph(crate_graph);
 +
 +        self.source_root_config = project_folders.source_root_config;
 +
 +        self.analysis_host.apply_change(change);
 +        self.process_changes();
 +        self.reload_flycheck();
 +        tracing::info!("did switch workspaces");
 +    }
 +
 +    fn fetch_workspace_error(&self) -> Result<(), String> {
 +        let mut buf = String::new();
 +
 +        for ws in self.fetch_workspaces_queue.last_op_result() {
 +            if let Err(err) = ws {
 +                stdx::format_to!(buf, "rust-analyzer failed to load workspace: {:#}\n", err);
 +            }
 +        }
 +
 +        if buf.is_empty() {
 +            return Ok(());
 +        }
 +
 +        Err(buf)
 +    }
 +
 +    fn fetch_build_data_error(&self) -> Result<(), String> {
 +        let mut buf = String::new();
 +
 +        for ws in &self.fetch_build_data_queue.last_op_result().1 {
 +            match ws {
 +                Ok(data) => match data.error() {
 +                    Some(stderr) => stdx::format_to!(buf, "{:#}\n", stderr),
 +                    _ => (),
 +                },
 +                // io errors
 +                Err(err) => stdx::format_to!(buf, "{:#}\n", err),
 +            }
 +        }
 +
 +        if buf.is_empty() {
 +            Ok(())
 +        } else {
 +            Err(buf)
 +        }
 +    }
 +
 +    fn reload_flycheck(&mut self) {
 +        let _p = profile::span("GlobalState::reload_flycheck");
 +        let config = match self.config.flycheck() {
 +            Some(it) => it,
 +            None => {
 +                self.flycheck = Vec::new();
 +                self.diagnostics.clear_check_all();
 +                return;
 +            }
 +        };
 +
 +        let sender = self.flycheck_sender.clone();
 +        self.flycheck = self
 +            .workspaces
 +            .iter()
 +            .enumerate()
 +            .filter_map(|(id, w)| match w {
 +                ProjectWorkspace::Cargo { cargo, .. } => Some((id, cargo.workspace_root())),
 +                ProjectWorkspace::Json { project, .. } => {
 +                    // Enable flychecks for json projects if a custom flycheck command was supplied
 +                    // in the workspace configuration.
 +                    match config {
 +                        FlycheckConfig::CustomCommand { .. } => Some((id, project.path())),
 +                        _ => None,
 +                    }
 +                }
 +                ProjectWorkspace::DetachedFiles { .. } => None,
 +            })
 +            .map(|(id, root)| {
 +                let sender = sender.clone();
 +                FlycheckHandle::spawn(
 +                    id,
 +                    Box::new(move |msg| sender.send(msg).unwrap()),
 +                    config.clone(),
 +                    root.to_path_buf(),
 +                )
 +            })
 +            .collect();
 +    }
 +}
 +
 +#[derive(Default)]
 +pub(crate) struct ProjectFolders {
 +    pub(crate) load: Vec<vfs::loader::Entry>,
 +    pub(crate) watch: Vec<usize>,
 +    pub(crate) source_root_config: SourceRootConfig,
 +}
 +
 +impl ProjectFolders {
 +    pub(crate) fn new(
 +        workspaces: &[ProjectWorkspace],
 +        global_excludes: &[AbsPathBuf],
 +    ) -> ProjectFolders {
 +        let mut res = ProjectFolders::default();
 +        let mut fsc = FileSetConfig::builder();
 +        let mut local_filesets = vec![];
 +
 +        for root in workspaces.iter().flat_map(|ws| ws.to_roots()) {
 +            let file_set_roots: Vec<VfsPath> =
 +                root.include.iter().cloned().map(VfsPath::from).collect();
 +
 +            let entry = {
 +                let mut dirs = vfs::loader::Directories::default();
 +                dirs.extensions.push("rs".into());
 +                dirs.include.extend(root.include);
 +                dirs.exclude.extend(root.exclude);
 +                for excl in global_excludes {
 +                    if dirs
 +                        .include
 +                        .iter()
 +                        .any(|incl| incl.starts_with(excl) || excl.starts_with(incl))
 +                    {
 +                        dirs.exclude.push(excl.clone());
 +                    }
 +                }
 +
 +                vfs::loader::Entry::Directories(dirs)
 +            };
 +
 +            if root.is_local {
 +                res.watch.push(res.load.len());
 +            }
 +            res.load.push(entry);
 +
 +            if root.is_local {
 +                local_filesets.push(fsc.len());
 +            }
 +            fsc.add_file_set(file_set_roots)
 +        }
 +
 +        let fsc = fsc.build();
 +        res.source_root_config = SourceRootConfig { fsc, local_filesets };
 +
 +        res
 +    }
 +}
 +
 +#[derive(Default, Debug)]
 +pub(crate) struct SourceRootConfig {
 +    pub(crate) fsc: FileSetConfig,
 +    pub(crate) local_filesets: Vec<usize>,
 +}
 +
 +impl SourceRootConfig {
 +    pub(crate) fn partition(&self, vfs: &vfs::Vfs) -> Vec<SourceRoot> {
 +        let _p = profile::span("SourceRootConfig::partition");
 +        self.fsc
 +            .partition(vfs)
 +            .into_iter()
 +            .enumerate()
 +            .map(|(idx, file_set)| {
 +                let is_local = self.local_filesets.contains(&idx);
 +                if is_local {
 +                    SourceRoot::new_local(file_set)
 +                } else {
 +                    SourceRoot::new_library(file_set)
 +                }
 +            })
 +            .collect()
 +    }
 +}
 +
 +/// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace`
 +/// with an identity dummy expander.
 +pub(crate) fn load_proc_macro(
 +    server: Result<&ProcMacroServer, &str>,
 +    path: &AbsPath,
 +    dummy_replace: &[Box<str>],
 +) -> ProcMacroLoadResult {
 +    let res: Result<Vec<_>, String> = (|| {
 +        let dylib = MacroDylib::new(path.to_path_buf())
 +            .map_err(|io| format!("Proc-macro dylib loading failed: {io}"))?;
 +        let server = server.map_err(ToOwned::to_owned)?;
 +        let vec = server.load_dylib(dylib).map_err(|e| format!("{e}"))?;
 +        if vec.is_empty() {
 +            return Err("proc macro library returned no proc macros".to_string());
 +        }
 +        Ok(vec
 +            .into_iter()
 +            .map(|expander| expander_to_proc_macro(expander, dummy_replace))
 +            .collect())
 +    })();
 +    return match res {
 +        Ok(proc_macros) => {
 +            tracing::info!(
 +                "Loaded proc-macros for {}: {:?}",
 +                path.display(),
 +                proc_macros.iter().map(|it| it.name.clone()).collect::<Vec<_>>()
 +            );
 +            Ok(proc_macros)
 +        }
 +        Err(e) => {
 +            tracing::warn!("proc-macro loading for {} failed: {e}", path.display());
 +            Err(e)
 +        }
 +    };
 +
 +    fn expander_to_proc_macro(
 +        expander: proc_macro_api::ProcMacro,
 +        dummy_replace: &[Box<str>],
 +    ) -> ProcMacro {
 +        let name = SmolStr::from(expander.name());
 +        let kind = match expander.kind() {
 +            proc_macro_api::ProcMacroKind::CustomDerive => ProcMacroKind::CustomDerive,
 +            proc_macro_api::ProcMacroKind::FuncLike => ProcMacroKind::FuncLike,
 +            proc_macro_api::ProcMacroKind::Attr => ProcMacroKind::Attr,
 +        };
 +        let expander: Arc<dyn ProcMacroExpander> =
 +            if dummy_replace.iter().any(|replace| &**replace == name) {
 +                match kind {
 +                    ProcMacroKind::Attr => Arc::new(IdentityExpander),
 +                    _ => Arc::new(EmptyExpander),
 +                }
 +            } else {
 +                Arc::new(Expander(expander))
 +            };
 +        ProcMacro { name, kind, expander }
 +    }
 +
 +    #[derive(Debug)]
 +    struct Expander(proc_macro_api::ProcMacro);
 +
 +    impl ProcMacroExpander for Expander {
 +        fn expand(
 +            &self,
 +            subtree: &tt::Subtree,
 +            attrs: Option<&tt::Subtree>,
 +            env: &Env,
 +        ) -> Result<tt::Subtree, ProcMacroExpansionError> {
 +            let env = env.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect();
 +            match self.0.expand(subtree, attrs, env) {
 +                Ok(Ok(subtree)) => Ok(subtree),
 +                Ok(Err(err)) => Err(ProcMacroExpansionError::Panic(err.0)),
 +                Err(err) => Err(ProcMacroExpansionError::System(err.to_string())),
 +            }
 +        }
 +    }
 +
 +    /// Dummy identity expander, used for attribute proc-macros that are deliberately ignored by the user.
 +    #[derive(Debug)]
 +    struct IdentityExpander;
 +
 +    impl ProcMacroExpander for IdentityExpander {
 +        fn expand(
 +            &self,
 +            subtree: &tt::Subtree,
 +            _: Option<&tt::Subtree>,
 +            _: &Env,
 +        ) -> Result<tt::Subtree, ProcMacroExpansionError> {
 +            Ok(subtree.clone())
 +        }
 +    }
 +
 +    /// Empty expander, used for proc-macros that are deliberately ignored by the user.
 +    #[derive(Debug)]
 +    struct EmptyExpander;
 +
 +    impl ProcMacroExpander for EmptyExpander {
 +        fn expand(
 +            &self,
 +            _: &tt::Subtree,
 +            _: Option<&tt::Subtree>,
 +            _: &Env,
 +        ) -> Result<tt::Subtree, ProcMacroExpansionError> {
 +            Ok(tt::Subtree::default())
 +        }
 +    }
 +}
 +
 +pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool {
 +    const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
 +    const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"];
 +
 +    let file_name = match path.file_name().unwrap_or_default().to_str() {
 +        Some(it) => it,
 +        None => return false,
 +    };
 +
 +    if let "Cargo.toml" | "Cargo.lock" = file_name {
 +        return true;
 +    }
 +    if change_kind == ChangeKind::Modify {
 +        return false;
 +    }
 +
 +    // .cargo/config{.toml}
 +    if path.extension().unwrap_or_default() != "rs" {
 +        let is_cargo_config = matches!(file_name, "config.toml" | "config")
 +            && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")).unwrap_or(false);
 +        return is_cargo_config;
 +    }
 +
 +    if IMPLICIT_TARGET_FILES.iter().any(|it| path.as_ref().ends_with(it)) {
 +        return true;
 +    }
 +    let parent = match path.parent() {
 +        Some(it) => it,
 +        None => return false,
 +    };
 +    if IMPLICIT_TARGET_DIRS.iter().any(|it| parent.as_ref().ends_with(it)) {
 +        return true;
 +    }
 +    if file_name == "main.rs" {
 +        let grand_parent = match parent.parent() {
 +            Some(it) => it,
 +            None => return false,
 +        };
 +        if IMPLICIT_TARGET_DIRS.iter().any(|it| grand_parent.as_ref().ends_with(it)) {
 +            return true;
 +        }
 +    }
 +    false
 +}
index 62aa47839942a42b596723d7da9b241f128afc58,0000000000000000000000000000000000000000..894795435451c8e2691fe805253987719cd80313
mode 100644,000000..100644
--- /dev/null
@@@ -1,667 -1,0 +1,666 @@@
- | MacroStmts
 +// Rust Un-Grammar.
 +//
 +// This grammar specifies the structure of Rust's concrete syntax tree.
 +// It does not specify parsing rules (ambiguities, precedence, etc are out of scope).
 +// Tokens are processed -- contextual keywords are recognised, compound operators glued.
 +//
 +// Legend:
 +//
 +//   //          -- comment
 +//   Name =      -- non-terminal definition
 +//   'ident'     -- token (terminal)
 +//   A B         -- sequence
 +//   A | B       -- alternation
 +//   A*          -- zero or more repetition
 +//   A?          -- zero or one repetition
 +//   (A)         -- same as A
 +//   label:A     -- suggested name for field of AST node
 +
 +//*************************//
 +// Names, Paths and Macros //
 +//*************************//
 +
 +Name =
 +  'ident' | 'self'
 +
 +NameRef =
 +  'ident' | 'int_number' | 'self' | 'super' | 'crate' | 'Self'
 +
 +Lifetime =
 +  'lifetime_ident'
 +
 +Path =
 +  (qualifier:Path '::')? segment:PathSegment
 +
 +PathSegment =
 +  '::'? NameRef
 +| NameRef GenericArgList?
 +| NameRef ParamList RetType?
 +| '<' PathType ('as' PathType)? '>'
 +
 +GenericArgList =
 +  '::'? '<' (GenericArg (',' GenericArg)* ','?)? '>'
 +
 +GenericArg =
 +  TypeArg
 +| AssocTypeArg
 +| LifetimeArg
 +| ConstArg
 +
 +TypeArg =
 +  Type
 +
 +AssocTypeArg =
 +  NameRef GenericParamList? (':' TypeBoundList | ('=' Type | ConstArg))
 +
 +LifetimeArg =
 +  Lifetime
 +
 +ConstArg =
 +  Expr
 +
 +MacroCall =
 +  Attr* Path '!' TokenTree ';'?
 +
 +TokenTree =
 +  '(' ')'
 +| '{' '}'
 +| '[' ']'
 +
 +MacroItems =
 +  Item*
 +
 +MacroStmts =
 +  statements:Stmt*
 +  Expr?
 +
 +//*************************//
 +//          Items          //
 +//*************************//
 +
 +SourceFile =
 +  'shebang'?
 +  Attr*
 +  Item*
 +
 +Item =
 +  Const
 +| Enum
 +| ExternBlock
 +| ExternCrate
 +| Fn
 +| Impl
 +| MacroCall
 +| MacroRules
 +| MacroDef
 +| Module
 +| Static
 +| Struct
 +| Trait
 +| TypeAlias
 +| Union
 +| Use
 +
 +MacroRules =
 +  Attr* Visibility?
 +  'macro_rules' '!' Name
 +  TokenTree
 +
 +MacroDef =
 +  Attr* Visibility?
 +  'macro' Name args:TokenTree?
 +  body:TokenTree
 +
 +Module =
 +  Attr* Visibility?
 +  'mod' Name
 +  (ItemList | ';')
 +
 +ItemList =
 +  '{' Attr* Item* '}'
 +
 +ExternCrate =
 +  Attr* Visibility?
 +  'extern' 'crate' NameRef Rename? ';'
 +
 +Rename =
 +  'as' (Name | '_')
 +
 +Use =
 +  Attr* Visibility?
 +  'use' UseTree ';'
 +
 +UseTree =
 +  (Path? '::')? ('*' | UseTreeList)
 +| Path Rename?
 +
 +UseTreeList =
 +  '{' (UseTree (',' UseTree)* ','?)? '}'
 +
 +Fn =
 + Attr* Visibility?
 + 'default'? 'const'? 'async'? 'unsafe'? Abi?
 + 'fn' Name GenericParamList? ParamList RetType? WhereClause?
 + (body:BlockExpr | ';')
 +
 +Abi =
 +  'extern' 'string'?
 +
 +ParamList =
 +  '('(
 +    SelfParam
 +  | (SelfParam ',')? (Param (',' Param)* ','?)?
 +  )')'
 +| '|' (Param (',' Param)* ','?)? '|'
 +
 +SelfParam =
 +  Attr* (
 +    ('&' Lifetime?)? 'mut'? Name
 +  | 'mut'? Name ':' Type
 +  )
 +
 +Param =
 +  Attr* (
 +    Pat (':' Type)?
 +  | Type
 +  | '...'
 +  )
 +
 +RetType =
 +  '->' Type
 +
 +TypeAlias =
 +  Attr* Visibility?
 +  'default'?
 +  'type' Name GenericParamList? (':' TypeBoundList?)? WhereClause?
 +  ('=' Type)? ';'
 +
 +Struct =
 +  Attr* Visibility?
 +  'struct' Name GenericParamList? (
 +    WhereClause? (RecordFieldList | ';')
 +  | TupleFieldList WhereClause? ';'
 +  )
 +
 +RecordFieldList =
 + '{' fields:(RecordField (',' RecordField)* ','?)? '}'
 +
 +RecordField =
 +  Attr* Visibility?
 +  Name ':' Type
 +
 +TupleFieldList =
 +  '(' fields:(TupleField (',' TupleField)* ','?)? ')'
 +
 +TupleField =
 +  Attr* Visibility?
 +  Type
 +
 +FieldList =
 +  RecordFieldList
 +| TupleFieldList
 +
 +Enum =
 +  Attr* Visibility?
 +  'enum' Name GenericParamList? WhereClause?
 +  VariantList
 +
 +VariantList =
 + '{' (Variant (',' Variant)* ','?)? '}'
 +
 +Variant =
 +  Attr* Visibility?
 +  Name FieldList? ('=' Expr)?
 +
 +Union =
 +  Attr* Visibility?
 +  'union' Name GenericParamList? WhereClause?
 +  RecordFieldList
 +
 +// A Data Type.
 +//
 +// Not used directly in the grammar, but handy to have anyway.
 +Adt =
 +  Enum
 +| Struct
 +| Union
 +
 +Const =
 +  Attr* Visibility?
 +  'default'?
 +  'const' (Name | '_') ':' Type
 +  ('=' body:Expr)? ';'
 +
 +Static =
 +  Attr* Visibility?
 +  'static' 'mut'? Name ':' Type
 +  ('=' body:Expr)? ';'
 +
 +Trait =
 +  Attr* Visibility?
 +  'unsafe'? 'auto'?
 +  'trait' Name GenericParamList? (':' TypeBoundList?)? WhereClause?
 +  AssocItemList
 +
 +AssocItemList =
 +  '{' Attr* AssocItem* '}'
 +
 +AssocItem =
 +  Const
 +| Fn
 +| MacroCall
 +| TypeAlias
 +
 +Impl =
 +  Attr* Visibility?
 +  'default'? 'unsafe'?
 +  'impl' GenericParamList? ('const'? '!'? trait:Type 'for')? self_ty:Type WhereClause?
 +  AssocItemList
 +
 +ExternBlock =
 +  Attr* 'unsafe'? Abi ExternItemList
 +
 +ExternItemList =
 +  '{' Attr* ExternItem* '}'
 +
 +ExternItem =
 +  Fn
 +| MacroCall
 +| Static
 +| TypeAlias
 +
 +GenericParamList =
 +  '<' (GenericParam (',' GenericParam)* ','?)? '>'
 +
 +GenericParam =
 +  ConstParam
 +| LifetimeParam
 +| TypeParam
 +
 +TypeParam =
 +  Attr* Name (':' TypeBoundList?)?
 +  ('=' default_type:Type)?
 +
 +ConstParam =
 +  Attr* 'const' Name ':' Type
 +  ('=' default_val:Expr)?
 +
 +LifetimeParam =
 +  Attr* Lifetime (':' TypeBoundList?)?
 +
 +WhereClause =
 +  'where' predicates:(WherePred (',' WherePred)* ','?)
 +
 +WherePred =
 +  ('for' GenericParamList)?  (Lifetime | Type) ':' TypeBoundList?
 +
 +Visibility =
 +  'pub' ('(' 'in'? Path ')')?
 +
 +Attr =
 +  '#' '!'? '[' Meta ']'
 +
 +Meta =
 +  Path ('=' Expr | TokenTree)?
 +
 +//****************************//
 +// Statements and Expressions //
 +//****************************//
 +
 +Stmt =
 +  ';'
 +| ExprStmt
 +| Item
 +| LetStmt
 +
 +LetStmt =
 +  Attr* 'let' Pat (':' Type)?
 +  '=' initializer:Expr
 +  LetElse?
 +  ';'
 +
 +LetElse =
 +  'else' BlockExpr
 +
 +ExprStmt =
 +  Expr ';'?
 +
 +Expr =
 +  ArrayExpr
 +| AwaitExpr
 +| BinExpr
 +| BlockExpr
 +| BoxExpr
 +| BreakExpr
 +| CallExpr
 +| CastExpr
 +| ClosureExpr
 +| ContinueExpr
 +| FieldExpr
 +| ForExpr
 +| IfExpr
 +| IndexExpr
 +| Literal
 +| LoopExpr
 +| MacroExpr
 +| MatchExpr
 +| MethodCallExpr
 +| ParenExpr
 +| PathExpr
 +| PrefixExpr
 +| RangeExpr
 +| RecordExpr
 +| RefExpr
 +| ReturnExpr
 +| TryExpr
 +| TupleExpr
 +| WhileExpr
 +| YieldExpr
 +| LetExpr
 +| UnderscoreExpr
 +
 +MacroExpr =
 +  MacroCall
 +
 +Literal =
 +  Attr* value:(
 +    'int_number' | 'float_number'
 +  | 'string' | 'raw_string'
 +  | 'byte_string' | 'raw_byte_string'
 +  | 'true' | 'false'
 +  | 'char' | 'byte'
 +  )
 +
 +PathExpr =
 +  Attr* Path
 +
 +StmtList =
 +  '{'
 +    Attr*
 +    statements:Stmt*
 +    tail_expr:Expr?
 +  '}'
 +
 +RefExpr =
 +  Attr* '&' ('raw' | 'mut' | 'const') Expr
 +
 +TryExpr =
 +  Attr* Expr '?'
 +
 +BlockExpr =
 +  Attr* Label? ('try' | 'unsafe' | 'async' | 'const') StmtList
 +
 +PrefixExpr =
 +  Attr* op:('-' | '!' | '*') Expr
 +
 +BinExpr =
 +  Attr*
 +  lhs:Expr
 +  op:(
 +    '||' | '&&'
 +  | '==' | '!=' | '<=' | '>=' | '<' | '>'
 +  | '+' | '*' | '-' | '/' | '%' | '<<' | '>>' | '^' | '|' | '&'
 +  | '=' | '+=' | '/=' | '*=' | '%=' | '>>=' | '<<=' | '-=' | '|=' | '&=' | '^='
 +  )
 +  rhs:Expr
 +
 +CastExpr =
 +  Attr* Expr 'as' Type
 +
 +ParenExpr =
 +  Attr* '(' Attr* Expr ')'
 +
 +ArrayExpr =
 +  Attr* '[' Attr* (
 +    (Expr (',' Expr)* ','?)?
 +  | Expr ';' Expr
 +  ) ']'
 +
 +IndexExpr =
 +  Attr* base:Expr '[' index:Expr ']'
 +
 +TupleExpr =
 +  Attr* '(' Attr* fields:(Expr (',' Expr)* ','?)? ')'
 +
 +RecordExpr =
 +  Path RecordExprFieldList
 +
 +RecordExprFieldList =
 +  '{'
 +    Attr*
 +    fields:(RecordExprField (',' RecordExprField)* ','?)?
 +    ('..' spread:Expr?)?
 +  '}'
 +
 +RecordExprField =
 +  Attr* (NameRef ':')? Expr
 +
 +CallExpr =
 +  Attr* Expr ArgList
 +
 +ArgList =
 +  '(' args:(Expr (',' Expr)* ','?)? ')'
 +
 +MethodCallExpr =
 +  Attr* receiver:Expr '.' NameRef GenericArgList? ArgList
 +
 +FieldExpr =
 +  Attr* Expr '.' NameRef
 +
 +ClosureExpr =
 +  Attr* ('for' GenericParamList)? 'static'? 'async'? 'move'?  ParamList RetType?
 +  body:Expr
 +
 +IfExpr =
 +  Attr* 'if' condition:Expr then_branch:BlockExpr
 +  ('else' else_branch:(IfExpr | BlockExpr))?
 +
 +LoopExpr =
 +  Attr* Label? 'loop'
 +  loop_body:BlockExpr
 +
 +ForExpr =
 +  Attr* Label? 'for' Pat 'in' iterable:Expr
 +  loop_body:BlockExpr
 +
 +WhileExpr =
 +  Attr* Label? 'while' condition:Expr
 +  loop_body:BlockExpr
 +
 +Label =
 +  Lifetime ':'
 +
 +BreakExpr =
 +  Attr* 'break' Lifetime? Expr?
 +
 +ContinueExpr =
 +  Attr* 'continue' Lifetime?
 +
 +RangeExpr =
 +  Attr* start:Expr? op:('..' | '..=') end:Expr?
 +
 +MatchExpr =
 +  Attr* 'match' Expr MatchArmList
 +
 +MatchArmList =
 +  '{'
 +    Attr*
 +    arms:MatchArm*
 +  '}'
 +
 +MatchArm =
 +  Attr* Pat guard:MatchGuard? '=>' Expr ','?
 +
 +MatchGuard =
 +  'if' condition:Expr
 +
 +ReturnExpr =
 +  Attr* 'return' Expr?
 +
 +YieldExpr =
 +  Attr* 'yield' Expr?
 +
 +LetExpr =
 +  Attr* 'let' Pat '=' Expr
 +
 +UnderscoreExpr =
 +  Attr* '_'
 +
 +AwaitExpr =
 +  Attr* Expr '.' 'await'
 +
 +BoxExpr =
 +  Attr* 'box' Expr
 +
 +//*************************//
 +//          Types          //
 +//*************************//
 +
 +Type =
 +  ArrayType
 +| DynTraitType
 +| FnPtrType
 +| ForType
 +| ImplTraitType
 +| InferType
 +| MacroType
 +| NeverType
 +| ParenType
 +| PathType
 +| PtrType
 +| RefType
 +| SliceType
 +| TupleType
 +
 +ParenType =
 +  '(' Type ')'
 +
 +NeverType =
 +  '!'
 +
 +MacroType =
 +  MacroCall
 +
 +PathType =
 +  Path
 +
 +TupleType =
 +  '(' fields:(Type (',' Type)* ','?)? ')'
 +
 +PtrType =
 +  '*' ('const' | 'mut') Type
 +
 +RefType =
 +  '&' Lifetime? 'mut'? Type
 +
 +ArrayType =
 +  '[' Type ';' Expr ']'
 +
 +SliceType =
 +  '[' Type ']'
 +
 +InferType =
 +  '_'
 +
 +FnPtrType =
 +  'const'? 'async'? 'unsafe'? Abi? 'fn' ParamList RetType?
 +
 +ForType =
 +  'for' GenericParamList Type
 +
 +ImplTraitType =
 +  'impl' TypeBoundList
 +
 +DynTraitType =
 +  'dyn' TypeBoundList
 +
 +TypeBoundList =
 +  bounds:(TypeBound ('+' TypeBound)* '+'?)
 +
 +TypeBound =
 +  Lifetime
 +| ('?' | '~' 'const')? Type
 +
 +//************************//
 +//        Patterns        //
 +//************************//
 +
 +Pat =
 +  IdentPat
 +| BoxPat
 +| RestPat
 +| LiteralPat
 +| MacroPat
 +| OrPat
 +| ParenPat
 +| PathPat
 +| WildcardPat
 +| RangePat
 +| RecordPat
 +| RefPat
 +| SlicePat
 +| TuplePat
 +| TupleStructPat
 +| ConstBlockPat
 +
 +LiteralPat =
 +  Literal
 +
 +IdentPat =
 +  Attr* 'ref'? 'mut'? Name ('@' Pat)?
 +
 +WildcardPat =
 +  '_'
 +
 +RangePat =
 +  // 1..
 +  start:Pat op:('..' | '..=')
 +  // 1..2
 +  | start:Pat op:('..' | '..=') end:Pat
 +  // ..2
 +  | op:('..' | '..=') end:Pat
 +
 +RefPat =
 +  '&' 'mut'? Pat
 +
 +RecordPat =
 +  Path RecordPatFieldList
 +
 +RecordPatFieldList =
 +  '{'
 +    fields:(RecordPatField (',' RecordPatField)* ','?)?
 +    RestPat?
 +  '}'
 +
 +RecordPatField =
 +  Attr* (NameRef ':')? Pat
 +
 +TupleStructPat =
 +   Path '(' fields:(Pat (',' Pat)* ','?)? ')'
 +
 +TuplePat =
 +   '(' fields:(Pat (',' Pat)* ','?)? ')'
 +
 +ParenPat =
 +  '(' Pat ')'
 +
 +SlicePat =
 +  '[' (Pat (',' Pat)* ','?)? ']'
 +
 +PathPat =
 +  Path
 +
 +OrPat =
 +  (Pat ('|' Pat)* '|'?)
 +
 +BoxPat =
 +  'box' Pat
 +
 +RestPat =
 +  Attr* '..'
 +
 +MacroPat =
 +  MacroCall
 +
 +ConstBlockPat =
 +  'const' BlockExpr
index 63309a155219e55ebec99bcfd3b416ede648df38,0000000000000000000000000000000000000000..449402e5f5b30af4f6e69e3b26c27aa234a2b93c
mode 100644,000000..100644
--- /dev/null
@@@ -1,4806 -1,0 +1,4865 @@@
-     MacroStmts(MacroStmts),
 +//! Generated by `sourcegen_ast`, do not edit by hand.
 +
 +#![allow(non_snake_case)]
 +use crate::{
 +    ast::{self, support, AstChildren, AstNode},
 +    SyntaxKind::{self, *},
 +    SyntaxNode, SyntaxToken, T,
 +};
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Name {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl Name {
 +    pub fn ident_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ident]) }
 +    pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct NameRef {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl NameRef {
 +    pub fn ident_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ident]) }
 +    pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) }
 +    pub fn super_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![super]) }
 +    pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) }
 +    pub fn Self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![Self]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Lifetime {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl Lifetime {
 +    pub fn lifetime_ident_token(&self) -> Option<SyntaxToken> {
 +        support::token(&self.syntax, T![lifetime_ident])
 +    }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Path {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl Path {
 +    pub fn qualifier(&self) -> Option<Path> { support::child(&self.syntax) }
 +    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
 +    pub fn segment(&self) -> Option<PathSegment> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct PathSegment {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl PathSegment {
 +    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
 +    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
 +    pub fn generic_arg_list(&self) -> Option<GenericArgList> { support::child(&self.syntax) }
 +    pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
 +    pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
 +    pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
 +    pub fn path_type(&self) -> Option<PathType> { support::child(&self.syntax) }
 +    pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
 +    pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct GenericArgList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl GenericArgList {
 +    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
 +    pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
 +    pub fn generic_args(&self) -> AstChildren<GenericArg> { support::children(&self.syntax) }
 +    pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ParamList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ParamList {
 +    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
 +    pub fn self_param(&self) -> Option<SelfParam> { support::child(&self.syntax) }
 +    pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
 +    pub fn params(&self) -> AstChildren<Param> { support::children(&self.syntax) }
 +    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 +    pub fn pipe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![|]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct RetType {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl RetType {
 +    pub fn thin_arrow_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![->]) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct PathType {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl PathType {
 +    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct TypeArg {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl TypeArg {
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct AssocTypeArg {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasTypeBounds for AssocTypeArg {}
 +impl AssocTypeArg {
 +    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
 +    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
 +    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +    pub fn const_arg(&self) -> Option<ConstArg> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct LifetimeArg {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl LifetimeArg {
 +    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ConstArg {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ConstArg {
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct GenericParamList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl GenericParamList {
 +    pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
 +    pub fn generic_params(&self) -> AstChildren<GenericParam> { support::children(&self.syntax) }
 +    pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct TypeBoundList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl TypeBoundList {
 +    pub fn bounds(&self) -> AstChildren<TypeBound> { support::children(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct MacroCall {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for MacroCall {}
 +impl ast::HasDocComments for MacroCall {}
 +impl MacroCall {
 +    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
 +    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
 +    pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
 +    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Attr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl Attr {
 +    pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
 +    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
 +    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
 +    pub fn meta(&self) -> Option<Meta> { support::child(&self.syntax) }
 +    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct TokenTree {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl TokenTree {
 +    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
 +    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 +    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
 +    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 +    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
 +    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct MacroItems {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasModuleItem for MacroItems {}
 +impl MacroItems {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct MacroStmts {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl MacroStmts {
 +    pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct SourceFile {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for SourceFile {}
 +impl ast::HasModuleItem for SourceFile {}
 +impl ast::HasDocComments for SourceFile {}
 +impl SourceFile {
 +    pub fn shebang_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![shebang]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Const {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for Const {}
 +impl ast::HasName for Const {}
 +impl ast::HasVisibility for Const {}
 +impl ast::HasDocComments for Const {}
 +impl Const {
 +    pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
 +    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
 +    pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
 +    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
 +    pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Enum {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for Enum {}
 +impl ast::HasName for Enum {}
 +impl ast::HasVisibility for Enum {}
 +impl ast::HasGenericParams for Enum {}
 +impl ast::HasDocComments for Enum {}
 +impl Enum {
 +    pub fn enum_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![enum]) }
 +    pub fn variant_list(&self) -> Option<VariantList> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ExternBlock {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for ExternBlock {}
 +impl ast::HasDocComments for ExternBlock {}
 +impl ExternBlock {
 +    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
 +    pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) }
 +    pub fn extern_item_list(&self) -> Option<ExternItemList> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ExternCrate {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for ExternCrate {}
 +impl ast::HasVisibility for ExternCrate {}
 +impl ast::HasDocComments for ExternCrate {}
 +impl ExternCrate {
 +    pub fn extern_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![extern]) }
 +    pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) }
 +    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
 +    pub fn rename(&self) -> Option<Rename> { support::child(&self.syntax) }
 +    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Fn {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for Fn {}
 +impl ast::HasName for Fn {}
 +impl ast::HasVisibility for Fn {}
 +impl ast::HasGenericParams for Fn {}
 +impl ast::HasDocComments for Fn {}
 +impl Fn {
 +    pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
 +    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
 +    pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
 +    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
 +    pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) }
 +    pub fn fn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![fn]) }
 +    pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
 +    pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
 +    pub fn body(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
 +    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Impl {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for Impl {}
 +impl ast::HasVisibility for Impl {}
 +impl ast::HasGenericParams for Impl {}
 +impl ast::HasDocComments for Impl {}
 +impl Impl {
 +    pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
 +    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
 +    pub fn impl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![impl]) }
 +    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
 +    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
 +    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
 +    pub fn assoc_item_list(&self) -> Option<AssocItemList> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct MacroRules {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for MacroRules {}
 +impl ast::HasName for MacroRules {}
 +impl ast::HasVisibility for MacroRules {}
 +impl ast::HasDocComments for MacroRules {}
 +impl MacroRules {
 +    pub fn macro_rules_token(&self) -> Option<SyntaxToken> {
 +        support::token(&self.syntax, T![macro_rules])
 +    }
 +    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
 +    pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct MacroDef {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for MacroDef {}
 +impl ast::HasName for MacroDef {}
 +impl ast::HasVisibility for MacroDef {}
 +impl ast::HasDocComments for MacroDef {}
 +impl MacroDef {
 +    pub fn macro_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![macro]) }
 +    pub fn args(&self) -> Option<TokenTree> { support::child(&self.syntax) }
 +    pub fn body(&self) -> Option<TokenTree> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Module {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for Module {}
 +impl ast::HasName for Module {}
 +impl ast::HasVisibility for Module {}
 +impl ast::HasDocComments for Module {}
 +impl Module {
 +    pub fn mod_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mod]) }
 +    pub fn item_list(&self) -> Option<ItemList> { support::child(&self.syntax) }
 +    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Static {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for Static {}
 +impl ast::HasName for Static {}
 +impl ast::HasVisibility for Static {}
 +impl ast::HasDocComments for Static {}
 +impl Static {
 +    pub fn static_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![static]) }
 +    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
 +    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
 +    pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Struct {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for Struct {}
 +impl ast::HasName for Struct {}
 +impl ast::HasVisibility for Struct {}
 +impl ast::HasGenericParams for Struct {}
 +impl ast::HasDocComments for Struct {}
 +impl Struct {
 +    pub fn struct_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![struct]) }
 +    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 +    pub fn field_list(&self) -> Option<FieldList> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Trait {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for Trait {}
 +impl ast::HasName for Trait {}
 +impl ast::HasVisibility for Trait {}
 +impl ast::HasGenericParams for Trait {}
 +impl ast::HasTypeBounds for Trait {}
 +impl ast::HasDocComments for Trait {}
 +impl Trait {
 +    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
 +    pub fn auto_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![auto]) }
 +    pub fn trait_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![trait]) }
 +    pub fn assoc_item_list(&self) -> Option<AssocItemList> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct TypeAlias {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for TypeAlias {}
 +impl ast::HasName for TypeAlias {}
 +impl ast::HasVisibility for TypeAlias {}
 +impl ast::HasGenericParams for TypeAlias {}
 +impl ast::HasTypeBounds for TypeAlias {}
 +impl ast::HasDocComments for TypeAlias {}
 +impl TypeAlias {
 +    pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
 +    pub fn type_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![type]) }
 +    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Union {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for Union {}
 +impl ast::HasName for Union {}
 +impl ast::HasVisibility for Union {}
 +impl ast::HasGenericParams for Union {}
 +impl ast::HasDocComments for Union {}
 +impl Union {
 +    pub fn union_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![union]) }
 +    pub fn record_field_list(&self) -> Option<RecordFieldList> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Use {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for Use {}
 +impl ast::HasVisibility for Use {}
 +impl ast::HasDocComments for Use {}
 +impl Use {
 +    pub fn use_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![use]) }
 +    pub fn use_tree(&self) -> Option<UseTree> { support::child(&self.syntax) }
 +    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Visibility {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl Visibility {
 +    pub fn pub_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![pub]) }
 +    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
 +    pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
 +    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
 +    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ItemList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for ItemList {}
 +impl ast::HasModuleItem for ItemList {}
 +impl ItemList {
 +    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
 +    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Rename {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasName for Rename {}
 +impl Rename {
 +    pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
 +    pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct UseTree {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl UseTree {
 +    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
 +    pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
 +    pub fn star_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![*]) }
 +    pub fn use_tree_list(&self) -> Option<UseTreeList> { support::child(&self.syntax) }
 +    pub fn rename(&self) -> Option<Rename> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct UseTreeList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl UseTreeList {
 +    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
 +    pub fn use_trees(&self) -> AstChildren<UseTree> { support::children(&self.syntax) }
 +    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Abi {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl Abi {
 +    pub fn extern_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![extern]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct WhereClause {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl WhereClause {
 +    pub fn where_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![where]) }
 +    pub fn predicates(&self) -> AstChildren<WherePred> { support::children(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct BlockExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for BlockExpr {}
 +impl BlockExpr {
 +    pub fn label(&self) -> Option<Label> { support::child(&self.syntax) }
 +    pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) }
 +    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
 +    pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
 +    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
 +    pub fn stmt_list(&self) -> Option<StmtList> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct SelfParam {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for SelfParam {}
 +impl ast::HasName for SelfParam {}
 +impl SelfParam {
 +    pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
 +    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
 +    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
 +    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Param {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for Param {}
 +impl Param {
 +    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
 +    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +    pub fn dotdotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![...]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct RecordFieldList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl RecordFieldList {
 +    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
 +    pub fn fields(&self) -> AstChildren<RecordField> { support::children(&self.syntax) }
 +    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct TupleFieldList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl TupleFieldList {
 +    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
 +    pub fn fields(&self) -> AstChildren<TupleField> { support::children(&self.syntax) }
 +    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct RecordField {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for RecordField {}
 +impl ast::HasName for RecordField {}
 +impl ast::HasVisibility for RecordField {}
 +impl ast::HasDocComments for RecordField {}
 +impl RecordField {
 +    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct TupleField {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for TupleField {}
 +impl ast::HasVisibility for TupleField {}
 +impl ast::HasDocComments for TupleField {}
 +impl TupleField {
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct VariantList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl VariantList {
 +    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
 +    pub fn variants(&self) -> AstChildren<Variant> { support::children(&self.syntax) }
 +    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Variant {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for Variant {}
 +impl ast::HasName for Variant {}
 +impl ast::HasVisibility for Variant {}
 +impl ast::HasDocComments for Variant {}
 +impl Variant {
 +    pub fn field_list(&self) -> Option<FieldList> { support::child(&self.syntax) }
 +    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct AssocItemList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for AssocItemList {}
 +impl AssocItemList {
 +    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
 +    pub fn assoc_items(&self) -> AstChildren<AssocItem> { support::children(&self.syntax) }
 +    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ExternItemList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for ExternItemList {}
 +impl ExternItemList {
 +    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
 +    pub fn extern_items(&self) -> AstChildren<ExternItem> { support::children(&self.syntax) }
 +    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ConstParam {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for ConstParam {}
 +impl ast::HasName for ConstParam {}
 +impl ConstParam {
 +    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
 +    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
 +    pub fn default_val(&self) -> Option<Expr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct LifetimeParam {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for LifetimeParam {}
 +impl ast::HasTypeBounds for LifetimeParam {}
 +impl LifetimeParam {
 +    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct TypeParam {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for TypeParam {}
 +impl ast::HasName for TypeParam {}
 +impl ast::HasTypeBounds for TypeParam {}
 +impl TypeParam {
 +    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
 +    pub fn default_type(&self) -> Option<Type> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct WherePred {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasTypeBounds for WherePred {}
 +impl WherePred {
 +    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
 +    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
 +    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Meta {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl Meta {
 +    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
 +    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ExprStmt {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ExprStmt {
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct LetStmt {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for LetStmt {}
 +impl LetStmt {
 +    pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
 +    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
 +    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
 +    pub fn initializer(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn let_else(&self) -> Option<LetElse> { support::child(&self.syntax) }
 +    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct LetElse {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl LetElse {
 +    pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
 +    pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ArrayExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for ArrayExpr {}
 +impl ArrayExpr {
 +    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
 +    pub fn exprs(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 +    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct AwaitExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for AwaitExpr {}
 +impl AwaitExpr {
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
 +    pub fn await_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![await]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct BinExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for BinExpr {}
 +impl BinExpr {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct BoxExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for BoxExpr {}
 +impl BoxExpr {
 +    pub fn box_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![box]) }
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct BreakExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for BreakExpr {}
 +impl BreakExpr {
 +    pub fn break_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![break]) }
 +    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct CallExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for CallExpr {}
 +impl ast::HasArgList for CallExpr {}
 +impl CallExpr {
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct CastExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for CastExpr {}
 +impl CastExpr {
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ClosureExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for ClosureExpr {}
 +impl ClosureExpr {
 +    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
 +    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
 +    pub fn static_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![static]) }
 +    pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
 +    pub fn move_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![move]) }
 +    pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
 +    pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
 +    pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ContinueExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for ContinueExpr {}
 +impl ContinueExpr {
 +    pub fn continue_token(&self) -> Option<SyntaxToken> {
 +        support::token(&self.syntax, T![continue])
 +    }
 +    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct FieldExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for FieldExpr {}
 +impl FieldExpr {
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
 +    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ForExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for ForExpr {}
 +impl ForExpr {
 +    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
 +    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
 +    pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct IfExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for IfExpr {}
 +impl IfExpr {
 +    pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
 +    pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct IndexExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for IndexExpr {}
 +impl IndexExpr {
 +    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
 +    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Literal {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for Literal {}
 +impl Literal {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct LoopExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for LoopExpr {}
 +impl ast::HasLoopBody for LoopExpr {}
 +impl LoopExpr {
 +    pub fn loop_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![loop]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct MacroExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl MacroExpr {
 +    pub fn macro_call(&self) -> Option<MacroCall> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct MatchExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for MatchExpr {}
 +impl MatchExpr {
 +    pub fn match_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![match]) }
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn match_arm_list(&self) -> Option<MatchArmList> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct MethodCallExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for MethodCallExpr {}
 +impl ast::HasArgList for MethodCallExpr {}
 +impl MethodCallExpr {
 +    pub fn receiver(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
 +    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
 +    pub fn generic_arg_list(&self) -> Option<GenericArgList> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ParenExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for ParenExpr {}
 +impl ParenExpr {
 +    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct PathExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for PathExpr {}
 +impl PathExpr {
 +    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct PrefixExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for PrefixExpr {}
 +impl PrefixExpr {
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct RangeExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for RangeExpr {}
 +impl RangeExpr {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct RecordExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl RecordExpr {
 +    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
 +    pub fn record_expr_field_list(&self) -> Option<RecordExprFieldList> {
 +        support::child(&self.syntax)
 +    }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct RefExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for RefExpr {}
 +impl RefExpr {
 +    pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
 +    pub fn raw_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![raw]) }
 +    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
 +    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ReturnExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for ReturnExpr {}
 +impl ReturnExpr {
 +    pub fn return_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![return]) }
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct TryExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for TryExpr {}
 +impl TryExpr {
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct TupleExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for TupleExpr {}
 +impl TupleExpr {
 +    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
 +    pub fn fields(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
 +    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct WhileExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for WhileExpr {}
 +impl WhileExpr {
 +    pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct YieldExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for YieldExpr {}
 +impl YieldExpr {
 +    pub fn yield_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![yield]) }
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct LetExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for LetExpr {}
 +impl LetExpr {
 +    pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
 +    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
 +    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct UnderscoreExpr {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for UnderscoreExpr {}
 +impl UnderscoreExpr {
 +    pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct StmtList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for StmtList {}
 +impl StmtList {
 +    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
 +    pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
 +    pub fn tail_expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct Label {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl Label {
 +    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
 +    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct RecordExprFieldList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for RecordExprFieldList {}
 +impl RecordExprFieldList {
 +    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
 +    pub fn fields(&self) -> AstChildren<RecordExprField> { support::children(&self.syntax) }
 +    pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) }
 +    pub fn spread(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct RecordExprField {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for RecordExprField {}
 +impl RecordExprField {
 +    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
 +    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ArgList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ArgList {
 +    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
 +    pub fn args(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
 +    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct MatchArmList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for MatchArmList {}
 +impl MatchArmList {
 +    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
 +    pub fn arms(&self) -> AstChildren<MatchArm> { support::children(&self.syntax) }
 +    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct MatchArm {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for MatchArm {}
 +impl MatchArm {
 +    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
 +    pub fn guard(&self) -> Option<MatchGuard> { support::child(&self.syntax) }
 +    pub fn fat_arrow_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=>]) }
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct MatchGuard {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl MatchGuard {
 +    pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ArrayType {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ArrayType {
 +    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 +    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 +    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct DynTraitType {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl DynTraitType {
 +    pub fn dyn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![dyn]) }
 +    pub fn type_bound_list(&self) -> Option<TypeBoundList> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct FnPtrType {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl FnPtrType {
 +    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
 +    pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
 +    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
 +    pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) }
 +    pub fn fn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![fn]) }
 +    pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
 +    pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ForType {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ForType {
 +    pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
 +    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ImplTraitType {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ImplTraitType {
 +    pub fn impl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![impl]) }
 +    pub fn type_bound_list(&self) -> Option<TypeBoundList> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct InferType {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl InferType {
 +    pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct MacroType {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl MacroType {
 +    pub fn macro_call(&self) -> Option<MacroCall> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct NeverType {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl NeverType {
 +    pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ParenType {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ParenType {
 +    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct PtrType {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl PtrType {
 +    pub fn star_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![*]) }
 +    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
 +    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct RefType {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl RefType {
 +    pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
 +    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
 +    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct SliceType {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl SliceType {
 +    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct TupleType {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl TupleType {
 +    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
 +    pub fn fields(&self) -> AstChildren<Type> { support::children(&self.syntax) }
 +    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct TypeBound {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl TypeBound {
 +    pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
 +    pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
 +    pub fn tilde_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![~]) }
 +    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
 +    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct IdentPat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for IdentPat {}
 +impl ast::HasName for IdentPat {}
 +impl IdentPat {
 +    pub fn ref_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ref]) }
 +    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
 +    pub fn at_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![@]) }
 +    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct BoxPat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl BoxPat {
 +    pub fn box_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![box]) }
 +    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct RestPat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for RestPat {}
 +impl RestPat {
 +    pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct LiteralPat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl LiteralPat {
 +    pub fn literal(&self) -> Option<Literal> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct MacroPat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl MacroPat {
 +    pub fn macro_call(&self) -> Option<MacroCall> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct OrPat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl OrPat {
 +    pub fn pats(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ParenPat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ParenPat {
 +    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
 +    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
 +    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct PathPat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl PathPat {
 +    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct WildcardPat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl WildcardPat {
 +    pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct RangePat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl RangePat {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct RecordPat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl RecordPat {
 +    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
 +    pub fn record_pat_field_list(&self) -> Option<RecordPatFieldList> {
 +        support::child(&self.syntax)
 +    }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct RefPat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl RefPat {
 +    pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
 +    pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
 +    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct SlicePat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl SlicePat {
 +    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
 +    pub fn pats(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
 +    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct TuplePat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl TuplePat {
 +    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
 +    pub fn fields(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
 +    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct TupleStructPat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl TupleStructPat {
 +    pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
 +    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
 +    pub fn fields(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
 +    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct ConstBlockPat {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ConstBlockPat {
 +    pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
 +    pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct RecordPatFieldList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl RecordPatFieldList {
 +    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
 +    pub fn fields(&self) -> AstChildren<RecordPatField> { support::children(&self.syntax) }
 +    pub fn rest_pat(&self) -> Option<RestPat> { support::child(&self.syntax) }
 +    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct RecordPatField {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for RecordPatField {}
 +impl RecordPatField {
 +    pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
 +    pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
 +    pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum GenericArg {
 +    TypeArg(TypeArg),
 +    AssocTypeArg(AssocTypeArg),
 +    LifetimeArg(LifetimeArg),
 +    ConstArg(ConstArg),
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum Type {
 +    ArrayType(ArrayType),
 +    DynTraitType(DynTraitType),
 +    FnPtrType(FnPtrType),
 +    ForType(ForType),
 +    ImplTraitType(ImplTraitType),
 +    InferType(InferType),
 +    MacroType(MacroType),
 +    NeverType(NeverType),
 +    ParenType(ParenType),
 +    PathType(PathType),
 +    PtrType(PtrType),
 +    RefType(RefType),
 +    SliceType(SliceType),
 +    TupleType(TupleType),
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum Expr {
 +    ArrayExpr(ArrayExpr),
 +    AwaitExpr(AwaitExpr),
 +    BinExpr(BinExpr),
 +    BlockExpr(BlockExpr),
 +    BoxExpr(BoxExpr),
 +    BreakExpr(BreakExpr),
 +    CallExpr(CallExpr),
 +    CastExpr(CastExpr),
 +    ClosureExpr(ClosureExpr),
 +    ContinueExpr(ContinueExpr),
 +    FieldExpr(FieldExpr),
 +    ForExpr(ForExpr),
 +    IfExpr(IfExpr),
 +    IndexExpr(IndexExpr),
 +    Literal(Literal),
 +    LoopExpr(LoopExpr),
 +    MacroExpr(MacroExpr),
-         match kind {
-             TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG => true,
-             _ => false,
-         }
 +    MatchExpr(MatchExpr),
 +    MethodCallExpr(MethodCallExpr),
 +    ParenExpr(ParenExpr),
 +    PathExpr(PathExpr),
 +    PrefixExpr(PrefixExpr),
 +    RangeExpr(RangeExpr),
 +    RecordExpr(RecordExpr),
 +    RefExpr(RefExpr),
 +    ReturnExpr(ReturnExpr),
 +    TryExpr(TryExpr),
 +    TupleExpr(TupleExpr),
 +    WhileExpr(WhileExpr),
 +    YieldExpr(YieldExpr),
 +    LetExpr(LetExpr),
 +    UnderscoreExpr(UnderscoreExpr),
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum Item {
 +    Const(Const),
 +    Enum(Enum),
 +    ExternBlock(ExternBlock),
 +    ExternCrate(ExternCrate),
 +    Fn(Fn),
 +    Impl(Impl),
 +    MacroCall(MacroCall),
 +    MacroRules(MacroRules),
 +    MacroDef(MacroDef),
 +    Module(Module),
 +    Static(Static),
 +    Struct(Struct),
 +    Trait(Trait),
 +    TypeAlias(TypeAlias),
 +    Union(Union),
 +    Use(Use),
 +}
 +impl ast::HasAttrs for Item {}
 +impl ast::HasDocComments for Item {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum Stmt {
 +    ExprStmt(ExprStmt),
 +    Item(Item),
 +    LetStmt(LetStmt),
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum Pat {
 +    IdentPat(IdentPat),
 +    BoxPat(BoxPat),
 +    RestPat(RestPat),
 +    LiteralPat(LiteralPat),
 +    MacroPat(MacroPat),
 +    OrPat(OrPat),
 +    ParenPat(ParenPat),
 +    PathPat(PathPat),
 +    WildcardPat(WildcardPat),
 +    RangePat(RangePat),
 +    RecordPat(RecordPat),
 +    RefPat(RefPat),
 +    SlicePat(SlicePat),
 +    TuplePat(TuplePat),
 +    TupleStructPat(TupleStructPat),
 +    ConstBlockPat(ConstBlockPat),
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum FieldList {
 +    RecordFieldList(RecordFieldList),
 +    TupleFieldList(TupleFieldList),
 +}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum Adt {
 +    Enum(Enum),
 +    Struct(Struct),
 +    Union(Union),
 +}
 +impl ast::HasAttrs for Adt {}
 +impl ast::HasDocComments for Adt {}
 +impl ast::HasGenericParams for Adt {}
 +impl ast::HasName for Adt {}
 +impl ast::HasVisibility for Adt {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum AssocItem {
 +    Const(Const),
 +    Fn(Fn),
 +    MacroCall(MacroCall),
 +    TypeAlias(TypeAlias),
 +}
 +impl ast::HasAttrs for AssocItem {}
 +impl ast::HasDocComments for AssocItem {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum ExternItem {
 +    Fn(Fn),
 +    MacroCall(MacroCall),
 +    Static(Static),
 +    TypeAlias(TypeAlias),
 +}
 +impl ast::HasAttrs for ExternItem {}
 +impl ast::HasDocComments for ExternItem {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub enum GenericParam {
 +    ConstParam(ConstParam),
 +    LifetimeParam(LifetimeParam),
 +    TypeParam(TypeParam),
 +}
 +impl ast::HasAttrs for GenericParam {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct AnyHasArgList {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasArgList for AnyHasArgList {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct AnyHasAttrs {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasAttrs for AnyHasAttrs {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct AnyHasDocComments {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasDocComments for AnyHasDocComments {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct AnyHasGenericParams {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasGenericParams for AnyHasGenericParams {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct AnyHasLoopBody {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasLoopBody for AnyHasLoopBody {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct AnyHasModuleItem {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasModuleItem for AnyHasModuleItem {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct AnyHasName {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasName for AnyHasName {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct AnyHasTypeBounds {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasTypeBounds for AnyHasTypeBounds {}
 +
 +#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +pub struct AnyHasVisibility {
 +    pub(crate) syntax: SyntaxNode,
 +}
 +impl ast::HasVisibility for AnyHasVisibility {}
 +impl AstNode for Name {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == NAME }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for NameRef {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == NAME_REF }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Lifetime {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Path {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for PathSegment {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_SEGMENT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for GenericArgList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_ARG_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ParamList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for RetType {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == RET_TYPE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for PathType {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_TYPE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for TypeArg {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ARG }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for AssocTypeArg {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_TYPE_ARG }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for LifetimeArg {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_ARG }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ConstArg {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_ARG }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for GenericParamList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for TypeBoundList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for MacroCall {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_CALL }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Attr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == ATTR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for TokenTree {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == TOKEN_TREE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for MacroItems {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_ITEMS }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for MacroStmts {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_STMTS }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for SourceFile {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == SOURCE_FILE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Const {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == CONST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Enum {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == ENUM }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ExternBlock {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_BLOCK }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ExternCrate {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_CRATE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Fn {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == FN }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Impl {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for MacroRules {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_RULES }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for MacroDef {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_DEF }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Module {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Static {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == STATIC }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Struct {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == STRUCT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Trait {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == TRAIT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for TypeAlias {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ALIAS }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Union {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == UNION }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Use {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == USE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Visibility {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == VISIBILITY }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ItemList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == ITEM_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Rename {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == RENAME }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for UseTree {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for UseTreeList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Abi {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == ABI }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for WhereClause {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_CLAUSE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for BlockExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == BLOCK_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for SelfParam {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == SELF_PARAM }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Param {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for RecordFieldList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for TupleFieldList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for RecordField {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for TupleField {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for VariantList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Variant {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for AssocItemList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_ITEM_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ExternItemList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_ITEM_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ConstParam {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_PARAM }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for LifetimeParam {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_PARAM }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for TypeParam {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_PARAM }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for WherePred {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_PRED }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Meta {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == META }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ExprStmt {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STMT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for LetStmt {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == LET_STMT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for LetElse {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == LET_ELSE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ArrayExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for AwaitExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == AWAIT_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for BinExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == BIN_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for BoxExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == BOX_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for BreakExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == BREAK_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for CallExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == CALL_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for CastExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == CAST_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ClosureExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == CLOSURE_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ContinueExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == CONTINUE_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for FieldExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == FIELD_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ForExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for IfExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == IF_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for IndexExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == INDEX_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Literal {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for LoopExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == LOOP_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for MacroExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for MatchExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for MethodCallExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == METHOD_CALL_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ParenExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for PathExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for PrefixExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == PREFIX_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for RangeExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for RecordExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for RefExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == REF_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ReturnExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for TryExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for TupleExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for WhileExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == WHILE_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for YieldExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == YIELD_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for LetExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == LET_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for UnderscoreExpr {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == UNDERSCORE_EXPR }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for StmtList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for Label {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == LABEL }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for RecordExprFieldList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for RecordExprField {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ArgList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == ARG_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for MatchArmList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for MatchArm {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for MatchGuard {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_GUARD }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ArrayType {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_TYPE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for DynTraitType {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == DYN_TRAIT_TYPE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for FnPtrType {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == FN_PTR_TYPE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ForType {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_TYPE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ImplTraitType {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL_TRAIT_TYPE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for InferType {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == INFER_TYPE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for MacroType {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_TYPE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for NeverType {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == NEVER_TYPE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ParenType {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_TYPE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for PtrType {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == PTR_TYPE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for RefType {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == REF_TYPE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for SliceType {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_TYPE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for TupleType {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_TYPE }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for TypeBound {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for IdentPat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for BoxPat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == BOX_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for RestPat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == REST_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for LiteralPat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for MacroPat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for OrPat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == OR_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ParenPat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for PathPat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for WildcardPat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == WILDCARD_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for RangePat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for RecordPat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for RefPat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == REF_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for SlicePat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for TuplePat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for TupleStructPat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_STRUCT_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for ConstBlockPat {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_BLOCK_PAT }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for RecordPatFieldList {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD_LIST }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AstNode for RecordPatField {
 +    fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        if Self::can_cast(syntax.kind()) {
 +            Some(Self { syntax })
 +        } else {
 +            None
 +        }
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl From<TypeArg> for GenericArg {
 +    fn from(node: TypeArg) -> GenericArg { GenericArg::TypeArg(node) }
 +}
 +impl From<AssocTypeArg> for GenericArg {
 +    fn from(node: AssocTypeArg) -> GenericArg { GenericArg::AssocTypeArg(node) }
 +}
 +impl From<LifetimeArg> for GenericArg {
 +    fn from(node: LifetimeArg) -> GenericArg { GenericArg::LifetimeArg(node) }
 +}
 +impl From<ConstArg> for GenericArg {
 +    fn from(node: ConstArg) -> GenericArg { GenericArg::ConstArg(node) }
 +}
 +impl AstNode for GenericArg {
 +    fn can_cast(kind: SyntaxKind) -> bool {
-         match kind {
-             ARRAY_TYPE | DYN_TRAIT_TYPE | FN_PTR_TYPE | FOR_TYPE | IMPL_TRAIT_TYPE | INFER_TYPE
-             | MACRO_TYPE | NEVER_TYPE | PAREN_TYPE | PATH_TYPE | PTR_TYPE | REF_TYPE
-             | SLICE_TYPE | TUPLE_TYPE => true,
-             _ => false,
-         }
++        matches!(kind, TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG)
 +    }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        let res = match syntax.kind() {
 +            TYPE_ARG => GenericArg::TypeArg(TypeArg { syntax }),
 +            ASSOC_TYPE_ARG => GenericArg::AssocTypeArg(AssocTypeArg { syntax }),
 +            LIFETIME_ARG => GenericArg::LifetimeArg(LifetimeArg { syntax }),
 +            CONST_ARG => GenericArg::ConstArg(ConstArg { syntax }),
 +            _ => return None,
 +        };
 +        Some(res)
 +    }
 +    fn syntax(&self) -> &SyntaxNode {
 +        match self {
 +            GenericArg::TypeArg(it) => &it.syntax,
 +            GenericArg::AssocTypeArg(it) => &it.syntax,
 +            GenericArg::LifetimeArg(it) => &it.syntax,
 +            GenericArg::ConstArg(it) => &it.syntax,
 +        }
 +    }
 +}
 +impl From<ArrayType> for Type {
 +    fn from(node: ArrayType) -> Type { Type::ArrayType(node) }
 +}
 +impl From<DynTraitType> for Type {
 +    fn from(node: DynTraitType) -> Type { Type::DynTraitType(node) }
 +}
 +impl From<FnPtrType> for Type {
 +    fn from(node: FnPtrType) -> Type { Type::FnPtrType(node) }
 +}
 +impl From<ForType> for Type {
 +    fn from(node: ForType) -> Type { Type::ForType(node) }
 +}
 +impl From<ImplTraitType> for Type {
 +    fn from(node: ImplTraitType) -> Type { Type::ImplTraitType(node) }
 +}
 +impl From<InferType> for Type {
 +    fn from(node: InferType) -> Type { Type::InferType(node) }
 +}
 +impl From<MacroType> for Type {
 +    fn from(node: MacroType) -> Type { Type::MacroType(node) }
 +}
 +impl From<NeverType> for Type {
 +    fn from(node: NeverType) -> Type { Type::NeverType(node) }
 +}
 +impl From<ParenType> for Type {
 +    fn from(node: ParenType) -> Type { Type::ParenType(node) }
 +}
 +impl From<PathType> for Type {
 +    fn from(node: PathType) -> Type { Type::PathType(node) }
 +}
 +impl From<PtrType> for Type {
 +    fn from(node: PtrType) -> Type { Type::PtrType(node) }
 +}
 +impl From<RefType> for Type {
 +    fn from(node: RefType) -> Type { Type::RefType(node) }
 +}
 +impl From<SliceType> for Type {
 +    fn from(node: SliceType) -> Type { Type::SliceType(node) }
 +}
 +impl From<TupleType> for Type {
 +    fn from(node: TupleType) -> Type { Type::TupleType(node) }
 +}
 +impl AstNode for Type {
 +    fn can_cast(kind: SyntaxKind) -> bool {
- impl From<MacroStmts> for Expr {
-     fn from(node: MacroStmts) -> Expr { Expr::MacroStmts(node) }
- }
++        matches!(
++            kind,
++            ARRAY_TYPE
++                | DYN_TRAIT_TYPE
++                | FN_PTR_TYPE
++                | FOR_TYPE
++                | IMPL_TRAIT_TYPE
++                | INFER_TYPE
++                | MACRO_TYPE
++                | NEVER_TYPE
++                | PAREN_TYPE
++                | PATH_TYPE
++                | PTR_TYPE
++                | REF_TYPE
++                | SLICE_TYPE
++                | TUPLE_TYPE
++        )
 +    }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        let res = match syntax.kind() {
 +            ARRAY_TYPE => Type::ArrayType(ArrayType { syntax }),
 +            DYN_TRAIT_TYPE => Type::DynTraitType(DynTraitType { syntax }),
 +            FN_PTR_TYPE => Type::FnPtrType(FnPtrType { syntax }),
 +            FOR_TYPE => Type::ForType(ForType { syntax }),
 +            IMPL_TRAIT_TYPE => Type::ImplTraitType(ImplTraitType { syntax }),
 +            INFER_TYPE => Type::InferType(InferType { syntax }),
 +            MACRO_TYPE => Type::MacroType(MacroType { syntax }),
 +            NEVER_TYPE => Type::NeverType(NeverType { syntax }),
 +            PAREN_TYPE => Type::ParenType(ParenType { syntax }),
 +            PATH_TYPE => Type::PathType(PathType { syntax }),
 +            PTR_TYPE => Type::PtrType(PtrType { syntax }),
 +            REF_TYPE => Type::RefType(RefType { syntax }),
 +            SLICE_TYPE => Type::SliceType(SliceType { syntax }),
 +            TUPLE_TYPE => Type::TupleType(TupleType { syntax }),
 +            _ => return None,
 +        };
 +        Some(res)
 +    }
 +    fn syntax(&self) -> &SyntaxNode {
 +        match self {
 +            Type::ArrayType(it) => &it.syntax,
 +            Type::DynTraitType(it) => &it.syntax,
 +            Type::FnPtrType(it) => &it.syntax,
 +            Type::ForType(it) => &it.syntax,
 +            Type::ImplTraitType(it) => &it.syntax,
 +            Type::InferType(it) => &it.syntax,
 +            Type::MacroType(it) => &it.syntax,
 +            Type::NeverType(it) => &it.syntax,
 +            Type::ParenType(it) => &it.syntax,
 +            Type::PathType(it) => &it.syntax,
 +            Type::PtrType(it) => &it.syntax,
 +            Type::RefType(it) => &it.syntax,
 +            Type::SliceType(it) => &it.syntax,
 +            Type::TupleType(it) => &it.syntax,
 +        }
 +    }
 +}
 +impl From<ArrayExpr> for Expr {
 +    fn from(node: ArrayExpr) -> Expr { Expr::ArrayExpr(node) }
 +}
 +impl From<AwaitExpr> for Expr {
 +    fn from(node: AwaitExpr) -> Expr { Expr::AwaitExpr(node) }
 +}
 +impl From<BinExpr> for Expr {
 +    fn from(node: BinExpr) -> Expr { Expr::BinExpr(node) }
 +}
 +impl From<BlockExpr> for Expr {
 +    fn from(node: BlockExpr) -> Expr { Expr::BlockExpr(node) }
 +}
 +impl From<BoxExpr> for Expr {
 +    fn from(node: BoxExpr) -> Expr { Expr::BoxExpr(node) }
 +}
 +impl From<BreakExpr> for Expr {
 +    fn from(node: BreakExpr) -> Expr { Expr::BreakExpr(node) }
 +}
 +impl From<CallExpr> for Expr {
 +    fn from(node: CallExpr) -> Expr { Expr::CallExpr(node) }
 +}
 +impl From<CastExpr> for Expr {
 +    fn from(node: CastExpr) -> Expr { Expr::CastExpr(node) }
 +}
 +impl From<ClosureExpr> for Expr {
 +    fn from(node: ClosureExpr) -> Expr { Expr::ClosureExpr(node) }
 +}
 +impl From<ContinueExpr> for Expr {
 +    fn from(node: ContinueExpr) -> Expr { Expr::ContinueExpr(node) }
 +}
 +impl From<FieldExpr> for Expr {
 +    fn from(node: FieldExpr) -> Expr { Expr::FieldExpr(node) }
 +}
 +impl From<ForExpr> for Expr {
 +    fn from(node: ForExpr) -> Expr { Expr::ForExpr(node) }
 +}
 +impl From<IfExpr> for Expr {
 +    fn from(node: IfExpr) -> Expr { Expr::IfExpr(node) }
 +}
 +impl From<IndexExpr> for Expr {
 +    fn from(node: IndexExpr) -> Expr { Expr::IndexExpr(node) }
 +}
 +impl From<Literal> for Expr {
 +    fn from(node: Literal) -> Expr { Expr::Literal(node) }
 +}
 +impl From<LoopExpr> for Expr {
 +    fn from(node: LoopExpr) -> Expr { Expr::LoopExpr(node) }
 +}
 +impl From<MacroExpr> for Expr {
 +    fn from(node: MacroExpr) -> Expr { Expr::MacroExpr(node) }
 +}
-         match kind {
-             ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR
-             | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | FIELD_EXPR | FOR_EXPR | IF_EXPR
-             | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_EXPR | MACRO_STMTS | MATCH_EXPR
-             | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
-             | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
-             | YIELD_EXPR | LET_EXPR | UNDERSCORE_EXPR => true,
-             _ => false,
-         }
 +impl From<MatchExpr> for Expr {
 +    fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) }
 +}
 +impl From<MethodCallExpr> for Expr {
 +    fn from(node: MethodCallExpr) -> Expr { Expr::MethodCallExpr(node) }
 +}
 +impl From<ParenExpr> for Expr {
 +    fn from(node: ParenExpr) -> Expr { Expr::ParenExpr(node) }
 +}
 +impl From<PathExpr> for Expr {
 +    fn from(node: PathExpr) -> Expr { Expr::PathExpr(node) }
 +}
 +impl From<PrefixExpr> for Expr {
 +    fn from(node: PrefixExpr) -> Expr { Expr::PrefixExpr(node) }
 +}
 +impl From<RangeExpr> for Expr {
 +    fn from(node: RangeExpr) -> Expr { Expr::RangeExpr(node) }
 +}
 +impl From<RecordExpr> for Expr {
 +    fn from(node: RecordExpr) -> Expr { Expr::RecordExpr(node) }
 +}
 +impl From<RefExpr> for Expr {
 +    fn from(node: RefExpr) -> Expr { Expr::RefExpr(node) }
 +}
 +impl From<ReturnExpr> for Expr {
 +    fn from(node: ReturnExpr) -> Expr { Expr::ReturnExpr(node) }
 +}
 +impl From<TryExpr> for Expr {
 +    fn from(node: TryExpr) -> Expr { Expr::TryExpr(node) }
 +}
 +impl From<TupleExpr> for Expr {
 +    fn from(node: TupleExpr) -> Expr { Expr::TupleExpr(node) }
 +}
 +impl From<WhileExpr> for Expr {
 +    fn from(node: WhileExpr) -> Expr { Expr::WhileExpr(node) }
 +}
 +impl From<YieldExpr> for Expr {
 +    fn from(node: YieldExpr) -> Expr { Expr::YieldExpr(node) }
 +}
 +impl From<LetExpr> for Expr {
 +    fn from(node: LetExpr) -> Expr { Expr::LetExpr(node) }
 +}
 +impl From<UnderscoreExpr> for Expr {
 +    fn from(node: UnderscoreExpr) -> Expr { Expr::UnderscoreExpr(node) }
 +}
 +impl AstNode for Expr {
 +    fn can_cast(kind: SyntaxKind) -> bool {
-             MACRO_STMTS => Expr::MacroStmts(MacroStmts { syntax }),
++        matches!(
++            kind,
++            ARRAY_EXPR
++                | AWAIT_EXPR
++                | BIN_EXPR
++                | BLOCK_EXPR
++                | BOX_EXPR
++                | BREAK_EXPR
++                | CALL_EXPR
++                | CAST_EXPR
++                | CLOSURE_EXPR
++                | CONTINUE_EXPR
++                | FIELD_EXPR
++                | FOR_EXPR
++                | IF_EXPR
++                | INDEX_EXPR
++                | LITERAL
++                | LOOP_EXPR
++                | MACRO_EXPR
++                | MATCH_EXPR
++                | METHOD_CALL_EXPR
++                | PAREN_EXPR
++                | PATH_EXPR
++                | PREFIX_EXPR
++                | RANGE_EXPR
++                | RECORD_EXPR
++                | REF_EXPR
++                | RETURN_EXPR
++                | TRY_EXPR
++                | TUPLE_EXPR
++                | WHILE_EXPR
++                | YIELD_EXPR
++                | LET_EXPR
++                | UNDERSCORE_EXPR
++        )
 +    }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        let res = match syntax.kind() {
 +            ARRAY_EXPR => Expr::ArrayExpr(ArrayExpr { syntax }),
 +            AWAIT_EXPR => Expr::AwaitExpr(AwaitExpr { syntax }),
 +            BIN_EXPR => Expr::BinExpr(BinExpr { syntax }),
 +            BLOCK_EXPR => Expr::BlockExpr(BlockExpr { syntax }),
 +            BOX_EXPR => Expr::BoxExpr(BoxExpr { syntax }),
 +            BREAK_EXPR => Expr::BreakExpr(BreakExpr { syntax }),
 +            CALL_EXPR => Expr::CallExpr(CallExpr { syntax }),
 +            CAST_EXPR => Expr::CastExpr(CastExpr { syntax }),
 +            CLOSURE_EXPR => Expr::ClosureExpr(ClosureExpr { syntax }),
 +            CONTINUE_EXPR => Expr::ContinueExpr(ContinueExpr { syntax }),
 +            FIELD_EXPR => Expr::FieldExpr(FieldExpr { syntax }),
 +            FOR_EXPR => Expr::ForExpr(ForExpr { syntax }),
 +            IF_EXPR => Expr::IfExpr(IfExpr { syntax }),
 +            INDEX_EXPR => Expr::IndexExpr(IndexExpr { syntax }),
 +            LITERAL => Expr::Literal(Literal { syntax }),
 +            LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }),
 +            MACRO_EXPR => Expr::MacroExpr(MacroExpr { syntax }),
-             Expr::MacroStmts(it) => &it.syntax,
 +            MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }),
 +            METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }),
 +            PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }),
 +            PATH_EXPR => Expr::PathExpr(PathExpr { syntax }),
 +            PREFIX_EXPR => Expr::PrefixExpr(PrefixExpr { syntax }),
 +            RANGE_EXPR => Expr::RangeExpr(RangeExpr { syntax }),
 +            RECORD_EXPR => Expr::RecordExpr(RecordExpr { syntax }),
 +            REF_EXPR => Expr::RefExpr(RefExpr { syntax }),
 +            RETURN_EXPR => Expr::ReturnExpr(ReturnExpr { syntax }),
 +            TRY_EXPR => Expr::TryExpr(TryExpr { syntax }),
 +            TUPLE_EXPR => Expr::TupleExpr(TupleExpr { syntax }),
 +            WHILE_EXPR => Expr::WhileExpr(WhileExpr { syntax }),
 +            YIELD_EXPR => Expr::YieldExpr(YieldExpr { syntax }),
 +            LET_EXPR => Expr::LetExpr(LetExpr { syntax }),
 +            UNDERSCORE_EXPR => Expr::UnderscoreExpr(UnderscoreExpr { syntax }),
 +            _ => return None,
 +        };
 +        Some(res)
 +    }
 +    fn syntax(&self) -> &SyntaxNode {
 +        match self {
 +            Expr::ArrayExpr(it) => &it.syntax,
 +            Expr::AwaitExpr(it) => &it.syntax,
 +            Expr::BinExpr(it) => &it.syntax,
 +            Expr::BlockExpr(it) => &it.syntax,
 +            Expr::BoxExpr(it) => &it.syntax,
 +            Expr::BreakExpr(it) => &it.syntax,
 +            Expr::CallExpr(it) => &it.syntax,
 +            Expr::CastExpr(it) => &it.syntax,
 +            Expr::ClosureExpr(it) => &it.syntax,
 +            Expr::ContinueExpr(it) => &it.syntax,
 +            Expr::FieldExpr(it) => &it.syntax,
 +            Expr::ForExpr(it) => &it.syntax,
 +            Expr::IfExpr(it) => &it.syntax,
 +            Expr::IndexExpr(it) => &it.syntax,
 +            Expr::Literal(it) => &it.syntax,
 +            Expr::LoopExpr(it) => &it.syntax,
 +            Expr::MacroExpr(it) => &it.syntax,
-         match kind {
-             CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL | MACRO_CALL | MACRO_RULES
-             | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true,
-             _ => false,
-         }
 +            Expr::MatchExpr(it) => &it.syntax,
 +            Expr::MethodCallExpr(it) => &it.syntax,
 +            Expr::ParenExpr(it) => &it.syntax,
 +            Expr::PathExpr(it) => &it.syntax,
 +            Expr::PrefixExpr(it) => &it.syntax,
 +            Expr::RangeExpr(it) => &it.syntax,
 +            Expr::RecordExpr(it) => &it.syntax,
 +            Expr::RefExpr(it) => &it.syntax,
 +            Expr::ReturnExpr(it) => &it.syntax,
 +            Expr::TryExpr(it) => &it.syntax,
 +            Expr::TupleExpr(it) => &it.syntax,
 +            Expr::WhileExpr(it) => &it.syntax,
 +            Expr::YieldExpr(it) => &it.syntax,
 +            Expr::LetExpr(it) => &it.syntax,
 +            Expr::UnderscoreExpr(it) => &it.syntax,
 +        }
 +    }
 +}
 +impl From<Const> for Item {
 +    fn from(node: Const) -> Item { Item::Const(node) }
 +}
 +impl From<Enum> for Item {
 +    fn from(node: Enum) -> Item { Item::Enum(node) }
 +}
 +impl From<ExternBlock> for Item {
 +    fn from(node: ExternBlock) -> Item { Item::ExternBlock(node) }
 +}
 +impl From<ExternCrate> for Item {
 +    fn from(node: ExternCrate) -> Item { Item::ExternCrate(node) }
 +}
 +impl From<Fn> for Item {
 +    fn from(node: Fn) -> Item { Item::Fn(node) }
 +}
 +impl From<Impl> for Item {
 +    fn from(node: Impl) -> Item { Item::Impl(node) }
 +}
 +impl From<MacroCall> for Item {
 +    fn from(node: MacroCall) -> Item { Item::MacroCall(node) }
 +}
 +impl From<MacroRules> for Item {
 +    fn from(node: MacroRules) -> Item { Item::MacroRules(node) }
 +}
 +impl From<MacroDef> for Item {
 +    fn from(node: MacroDef) -> Item { Item::MacroDef(node) }
 +}
 +impl From<Module> for Item {
 +    fn from(node: Module) -> Item { Item::Module(node) }
 +}
 +impl From<Static> for Item {
 +    fn from(node: Static) -> Item { Item::Static(node) }
 +}
 +impl From<Struct> for Item {
 +    fn from(node: Struct) -> Item { Item::Struct(node) }
 +}
 +impl From<Trait> for Item {
 +    fn from(node: Trait) -> Item { Item::Trait(node) }
 +}
 +impl From<TypeAlias> for Item {
 +    fn from(node: TypeAlias) -> Item { Item::TypeAlias(node) }
 +}
 +impl From<Union> for Item {
 +    fn from(node: Union) -> Item { Item::Union(node) }
 +}
 +impl From<Use> for Item {
 +    fn from(node: Use) -> Item { Item::Use(node) }
 +}
 +impl AstNode for Item {
 +    fn can_cast(kind: SyntaxKind) -> bool {
-         match kind {
-             IDENT_PAT | BOX_PAT | REST_PAT | LITERAL_PAT | MACRO_PAT | OR_PAT | PAREN_PAT
-             | PATH_PAT | WILDCARD_PAT | RANGE_PAT | RECORD_PAT | REF_PAT | SLICE_PAT
-             | TUPLE_PAT | TUPLE_STRUCT_PAT | CONST_BLOCK_PAT => true,
-             _ => false,
-         }
++        matches!(
++            kind,
++            CONST
++                | ENUM
++                | EXTERN_BLOCK
++                | EXTERN_CRATE
++                | FN
++                | IMPL
++                | MACRO_CALL
++                | MACRO_RULES
++                | MACRO_DEF
++                | MODULE
++                | STATIC
++                | STRUCT
++                | TRAIT
++                | TYPE_ALIAS
++                | UNION
++                | USE
++        )
 +    }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        let res = match syntax.kind() {
 +            CONST => Item::Const(Const { syntax }),
 +            ENUM => Item::Enum(Enum { syntax }),
 +            EXTERN_BLOCK => Item::ExternBlock(ExternBlock { syntax }),
 +            EXTERN_CRATE => Item::ExternCrate(ExternCrate { syntax }),
 +            FN => Item::Fn(Fn { syntax }),
 +            IMPL => Item::Impl(Impl { syntax }),
 +            MACRO_CALL => Item::MacroCall(MacroCall { syntax }),
 +            MACRO_RULES => Item::MacroRules(MacroRules { syntax }),
 +            MACRO_DEF => Item::MacroDef(MacroDef { syntax }),
 +            MODULE => Item::Module(Module { syntax }),
 +            STATIC => Item::Static(Static { syntax }),
 +            STRUCT => Item::Struct(Struct { syntax }),
 +            TRAIT => Item::Trait(Trait { syntax }),
 +            TYPE_ALIAS => Item::TypeAlias(TypeAlias { syntax }),
 +            UNION => Item::Union(Union { syntax }),
 +            USE => Item::Use(Use { syntax }),
 +            _ => return None,
 +        };
 +        Some(res)
 +    }
 +    fn syntax(&self) -> &SyntaxNode {
 +        match self {
 +            Item::Const(it) => &it.syntax,
 +            Item::Enum(it) => &it.syntax,
 +            Item::ExternBlock(it) => &it.syntax,
 +            Item::ExternCrate(it) => &it.syntax,
 +            Item::Fn(it) => &it.syntax,
 +            Item::Impl(it) => &it.syntax,
 +            Item::MacroCall(it) => &it.syntax,
 +            Item::MacroRules(it) => &it.syntax,
 +            Item::MacroDef(it) => &it.syntax,
 +            Item::Module(it) => &it.syntax,
 +            Item::Static(it) => &it.syntax,
 +            Item::Struct(it) => &it.syntax,
 +            Item::Trait(it) => &it.syntax,
 +            Item::TypeAlias(it) => &it.syntax,
 +            Item::Union(it) => &it.syntax,
 +            Item::Use(it) => &it.syntax,
 +        }
 +    }
 +}
 +impl From<ExprStmt> for Stmt {
 +    fn from(node: ExprStmt) -> Stmt { Stmt::ExprStmt(node) }
 +}
 +impl From<Item> for Stmt {
 +    fn from(node: Item) -> Stmt { Stmt::Item(node) }
 +}
 +impl From<LetStmt> for Stmt {
 +    fn from(node: LetStmt) -> Stmt { Stmt::LetStmt(node) }
 +}
 +impl From<IdentPat> for Pat {
 +    fn from(node: IdentPat) -> Pat { Pat::IdentPat(node) }
 +}
 +impl From<BoxPat> for Pat {
 +    fn from(node: BoxPat) -> Pat { Pat::BoxPat(node) }
 +}
 +impl From<RestPat> for Pat {
 +    fn from(node: RestPat) -> Pat { Pat::RestPat(node) }
 +}
 +impl From<LiteralPat> for Pat {
 +    fn from(node: LiteralPat) -> Pat { Pat::LiteralPat(node) }
 +}
 +impl From<MacroPat> for Pat {
 +    fn from(node: MacroPat) -> Pat { Pat::MacroPat(node) }
 +}
 +impl From<OrPat> for Pat {
 +    fn from(node: OrPat) -> Pat { Pat::OrPat(node) }
 +}
 +impl From<ParenPat> for Pat {
 +    fn from(node: ParenPat) -> Pat { Pat::ParenPat(node) }
 +}
 +impl From<PathPat> for Pat {
 +    fn from(node: PathPat) -> Pat { Pat::PathPat(node) }
 +}
 +impl From<WildcardPat> for Pat {
 +    fn from(node: WildcardPat) -> Pat { Pat::WildcardPat(node) }
 +}
 +impl From<RangePat> for Pat {
 +    fn from(node: RangePat) -> Pat { Pat::RangePat(node) }
 +}
 +impl From<RecordPat> for Pat {
 +    fn from(node: RecordPat) -> Pat { Pat::RecordPat(node) }
 +}
 +impl From<RefPat> for Pat {
 +    fn from(node: RefPat) -> Pat { Pat::RefPat(node) }
 +}
 +impl From<SlicePat> for Pat {
 +    fn from(node: SlicePat) -> Pat { Pat::SlicePat(node) }
 +}
 +impl From<TuplePat> for Pat {
 +    fn from(node: TuplePat) -> Pat { Pat::TuplePat(node) }
 +}
 +impl From<TupleStructPat> for Pat {
 +    fn from(node: TupleStructPat) -> Pat { Pat::TupleStructPat(node) }
 +}
 +impl From<ConstBlockPat> for Pat {
 +    fn from(node: ConstBlockPat) -> Pat { Pat::ConstBlockPat(node) }
 +}
 +impl AstNode for Pat {
 +    fn can_cast(kind: SyntaxKind) -> bool {
-     fn can_cast(kind: SyntaxKind) -> bool {
-         match kind {
-             RECORD_FIELD_LIST | TUPLE_FIELD_LIST => true,
-             _ => false,
-         }
-     }
++        matches!(
++            kind,
++            IDENT_PAT
++                | BOX_PAT
++                | REST_PAT
++                | LITERAL_PAT
++                | MACRO_PAT
++                | OR_PAT
++                | PAREN_PAT
++                | PATH_PAT
++                | WILDCARD_PAT
++                | RANGE_PAT
++                | RECORD_PAT
++                | REF_PAT
++                | SLICE_PAT
++                | TUPLE_PAT
++                | TUPLE_STRUCT_PAT
++                | CONST_BLOCK_PAT
++        )
 +    }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        let res = match syntax.kind() {
 +            IDENT_PAT => Pat::IdentPat(IdentPat { syntax }),
 +            BOX_PAT => Pat::BoxPat(BoxPat { syntax }),
 +            REST_PAT => Pat::RestPat(RestPat { syntax }),
 +            LITERAL_PAT => Pat::LiteralPat(LiteralPat { syntax }),
 +            MACRO_PAT => Pat::MacroPat(MacroPat { syntax }),
 +            OR_PAT => Pat::OrPat(OrPat { syntax }),
 +            PAREN_PAT => Pat::ParenPat(ParenPat { syntax }),
 +            PATH_PAT => Pat::PathPat(PathPat { syntax }),
 +            WILDCARD_PAT => Pat::WildcardPat(WildcardPat { syntax }),
 +            RANGE_PAT => Pat::RangePat(RangePat { syntax }),
 +            RECORD_PAT => Pat::RecordPat(RecordPat { syntax }),
 +            REF_PAT => Pat::RefPat(RefPat { syntax }),
 +            SLICE_PAT => Pat::SlicePat(SlicePat { syntax }),
 +            TUPLE_PAT => Pat::TuplePat(TuplePat { syntax }),
 +            TUPLE_STRUCT_PAT => Pat::TupleStructPat(TupleStructPat { syntax }),
 +            CONST_BLOCK_PAT => Pat::ConstBlockPat(ConstBlockPat { syntax }),
 +            _ => return None,
 +        };
 +        Some(res)
 +    }
 +    fn syntax(&self) -> &SyntaxNode {
 +        match self {
 +            Pat::IdentPat(it) => &it.syntax,
 +            Pat::BoxPat(it) => &it.syntax,
 +            Pat::RestPat(it) => &it.syntax,
 +            Pat::LiteralPat(it) => &it.syntax,
 +            Pat::MacroPat(it) => &it.syntax,
 +            Pat::OrPat(it) => &it.syntax,
 +            Pat::ParenPat(it) => &it.syntax,
 +            Pat::PathPat(it) => &it.syntax,
 +            Pat::WildcardPat(it) => &it.syntax,
 +            Pat::RangePat(it) => &it.syntax,
 +            Pat::RecordPat(it) => &it.syntax,
 +            Pat::RefPat(it) => &it.syntax,
 +            Pat::SlicePat(it) => &it.syntax,
 +            Pat::TuplePat(it) => &it.syntax,
 +            Pat::TupleStructPat(it) => &it.syntax,
 +            Pat::ConstBlockPat(it) => &it.syntax,
 +        }
 +    }
 +}
 +impl From<RecordFieldList> for FieldList {
 +    fn from(node: RecordFieldList) -> FieldList { FieldList::RecordFieldList(node) }
 +}
 +impl From<TupleFieldList> for FieldList {
 +    fn from(node: TupleFieldList) -> FieldList { FieldList::TupleFieldList(node) }
 +}
 +impl AstNode for FieldList {
-     fn can_cast(kind: SyntaxKind) -> bool {
-         match kind {
-             ENUM | STRUCT | UNION => true,
-             _ => false,
-         }
-     }
++    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, RECORD_FIELD_LIST | TUPLE_FIELD_LIST) }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        let res = match syntax.kind() {
 +            RECORD_FIELD_LIST => FieldList::RecordFieldList(RecordFieldList { syntax }),
 +            TUPLE_FIELD_LIST => FieldList::TupleFieldList(TupleFieldList { syntax }),
 +            _ => return None,
 +        };
 +        Some(res)
 +    }
 +    fn syntax(&self) -> &SyntaxNode {
 +        match self {
 +            FieldList::RecordFieldList(it) => &it.syntax,
 +            FieldList::TupleFieldList(it) => &it.syntax,
 +        }
 +    }
 +}
 +impl From<Enum> for Adt {
 +    fn from(node: Enum) -> Adt { Adt::Enum(node) }
 +}
 +impl From<Struct> for Adt {
 +    fn from(node: Struct) -> Adt { Adt::Struct(node) }
 +}
 +impl From<Union> for Adt {
 +    fn from(node: Union) -> Adt { Adt::Union(node) }
 +}
 +impl AstNode for Adt {
-     fn can_cast(kind: SyntaxKind) -> bool {
-         match kind {
-             CONST | FN | MACRO_CALL | TYPE_ALIAS => true,
-             _ => false,
-         }
-     }
++    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, ENUM | STRUCT | UNION) }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        let res = match syntax.kind() {
 +            ENUM => Adt::Enum(Enum { syntax }),
 +            STRUCT => Adt::Struct(Struct { syntax }),
 +            UNION => Adt::Union(Union { syntax }),
 +            _ => return None,
 +        };
 +        Some(res)
 +    }
 +    fn syntax(&self) -> &SyntaxNode {
 +        match self {
 +            Adt::Enum(it) => &it.syntax,
 +            Adt::Struct(it) => &it.syntax,
 +            Adt::Union(it) => &it.syntax,
 +        }
 +    }
 +}
 +impl From<Const> for AssocItem {
 +    fn from(node: Const) -> AssocItem { AssocItem::Const(node) }
 +}
 +impl From<Fn> for AssocItem {
 +    fn from(node: Fn) -> AssocItem { AssocItem::Fn(node) }
 +}
 +impl From<MacroCall> for AssocItem {
 +    fn from(node: MacroCall) -> AssocItem { AssocItem::MacroCall(node) }
 +}
 +impl From<TypeAlias> for AssocItem {
 +    fn from(node: TypeAlias) -> AssocItem { AssocItem::TypeAlias(node) }
 +}
 +impl AstNode for AssocItem {
-     fn can_cast(kind: SyntaxKind) -> bool {
-         match kind {
-             FN | MACRO_CALL | STATIC | TYPE_ALIAS => true,
-             _ => false,
-         }
-     }
++    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CONST | FN | MACRO_CALL | TYPE_ALIAS) }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        let res = match syntax.kind() {
 +            CONST => AssocItem::Const(Const { syntax }),
 +            FN => AssocItem::Fn(Fn { syntax }),
 +            MACRO_CALL => AssocItem::MacroCall(MacroCall { syntax }),
 +            TYPE_ALIAS => AssocItem::TypeAlias(TypeAlias { syntax }),
 +            _ => return None,
 +        };
 +        Some(res)
 +    }
 +    fn syntax(&self) -> &SyntaxNode {
 +        match self {
 +            AssocItem::Const(it) => &it.syntax,
 +            AssocItem::Fn(it) => &it.syntax,
 +            AssocItem::MacroCall(it) => &it.syntax,
 +            AssocItem::TypeAlias(it) => &it.syntax,
 +        }
 +    }
 +}
 +impl From<Fn> for ExternItem {
 +    fn from(node: Fn) -> ExternItem { ExternItem::Fn(node) }
 +}
 +impl From<MacroCall> for ExternItem {
 +    fn from(node: MacroCall) -> ExternItem { ExternItem::MacroCall(node) }
 +}
 +impl From<Static> for ExternItem {
 +    fn from(node: Static) -> ExternItem { ExternItem::Static(node) }
 +}
 +impl From<TypeAlias> for ExternItem {
 +    fn from(node: TypeAlias) -> ExternItem { ExternItem::TypeAlias(node) }
 +}
 +impl AstNode for ExternItem {
-         match kind {
-             CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM => true,
-             _ => false,
-         }
++    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FN | MACRO_CALL | STATIC | TYPE_ALIAS) }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        let res = match syntax.kind() {
 +            FN => ExternItem::Fn(Fn { syntax }),
 +            MACRO_CALL => ExternItem::MacroCall(MacroCall { syntax }),
 +            STATIC => ExternItem::Static(Static { syntax }),
 +            TYPE_ALIAS => ExternItem::TypeAlias(TypeAlias { syntax }),
 +            _ => return None,
 +        };
 +        Some(res)
 +    }
 +    fn syntax(&self) -> &SyntaxNode {
 +        match self {
 +            ExternItem::Fn(it) => &it.syntax,
 +            ExternItem::MacroCall(it) => &it.syntax,
 +            ExternItem::Static(it) => &it.syntax,
 +            ExternItem::TypeAlias(it) => &it.syntax,
 +        }
 +    }
 +}
 +impl From<ConstParam> for GenericParam {
 +    fn from(node: ConstParam) -> GenericParam { GenericParam::ConstParam(node) }
 +}
 +impl From<LifetimeParam> for GenericParam {
 +    fn from(node: LifetimeParam) -> GenericParam { GenericParam::LifetimeParam(node) }
 +}
 +impl From<TypeParam> for GenericParam {
 +    fn from(node: TypeParam) -> GenericParam { GenericParam::TypeParam(node) }
 +}
 +impl AstNode for GenericParam {
 +    fn can_cast(kind: SyntaxKind) -> bool {
-     fn can_cast(kind: SyntaxKind) -> bool {
-         match kind {
-             CALL_EXPR | METHOD_CALL_EXPR => true,
-             _ => false,
-         }
-     }
++        matches!(kind, CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM)
 +    }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        let res = match syntax.kind() {
 +            CONST_PARAM => GenericParam::ConstParam(ConstParam { syntax }),
 +            LIFETIME_PARAM => GenericParam::LifetimeParam(LifetimeParam { syntax }),
 +            TYPE_PARAM => GenericParam::TypeParam(TypeParam { syntax }),
 +            _ => return None,
 +        };
 +        Some(res)
 +    }
 +    fn syntax(&self) -> &SyntaxNode {
 +        match self {
 +            GenericParam::ConstParam(it) => &it.syntax,
 +            GenericParam::LifetimeParam(it) => &it.syntax,
 +            GenericParam::TypeParam(it) => &it.syntax,
 +        }
 +    }
 +}
 +impl AnyHasArgList {
 +    #[inline]
 +    pub fn new<T: ast::HasArgList>(node: T) -> AnyHasArgList {
 +        AnyHasArgList { syntax: node.syntax().clone() }
 +    }
 +}
 +impl AstNode for AnyHasArgList {
-         match kind {
++    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CALL_EXPR | METHOD_CALL_EXPR) }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        Self::can_cast(syntax.kind()).then(|| AnyHasArgList { syntax })
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AnyHasAttrs {
 +    #[inline]
 +    pub fn new<T: ast::HasAttrs>(node: T) -> AnyHasAttrs {
 +        AnyHasAttrs { syntax: node.syntax().clone() }
 +    }
 +}
 +impl AstNode for AnyHasAttrs {
 +    fn can_cast(kind: SyntaxKind) -> bool {
-             | SOURCE_FILE
-             | CONST
-             | ENUM
-             | EXTERN_BLOCK
-             | EXTERN_CRATE
-             | FN
-             | IMPL
-             | MACRO_RULES
-             | MACRO_DEF
-             | MODULE
-             | STATIC
-             | STRUCT
-             | TRAIT
-             | TYPE_ALIAS
-             | UNION
-             | USE
-             | ITEM_LIST
-             | BLOCK_EXPR
-             | SELF_PARAM
-             | PARAM
-             | RECORD_FIELD
-             | TUPLE_FIELD
-             | VARIANT
-             | ASSOC_ITEM_LIST
-             | EXTERN_ITEM_LIST
-             | CONST_PARAM
-             | LIFETIME_PARAM
-             | TYPE_PARAM
-             | LET_STMT
-             | ARRAY_EXPR
-             | AWAIT_EXPR
-             | BIN_EXPR
-             | BOX_EXPR
-             | BREAK_EXPR
-             | CALL_EXPR
-             | CAST_EXPR
-             | CLOSURE_EXPR
-             | CONTINUE_EXPR
-             | FIELD_EXPR
-             | FOR_EXPR
-             | IF_EXPR
-             | INDEX_EXPR
-             | LITERAL
-             | LOOP_EXPR
-             | MATCH_EXPR
-             | METHOD_CALL_EXPR
-             | PAREN_EXPR
-             | PATH_EXPR
-             | PREFIX_EXPR
-             | RANGE_EXPR
-             | REF_EXPR
-             | RETURN_EXPR
-             | TRY_EXPR
-             | TUPLE_EXPR
-             | WHILE_EXPR
-             | YIELD_EXPR
-             | LET_EXPR
-             | UNDERSCORE_EXPR
-             | STMT_LIST
-             | RECORD_EXPR_FIELD_LIST
-             | RECORD_EXPR_FIELD
-             | MATCH_ARM_LIST
-             | MATCH_ARM
-             | IDENT_PAT
-             | REST_PAT
-             | RECORD_PAT_FIELD => true,
-             _ => false,
-         }
++        matches!(
++            kind,
 +            MACRO_CALL
-         match kind {
-             MACRO_CALL | SOURCE_FILE | CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL
-             | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION
-             | USE | RECORD_FIELD | TUPLE_FIELD | VARIANT => true,
-             _ => false,
-         }
++                | SOURCE_FILE
++                | CONST
++                | ENUM
++                | EXTERN_BLOCK
++                | EXTERN_CRATE
++                | FN
++                | IMPL
++                | MACRO_RULES
++                | MACRO_DEF
++                | MODULE
++                | STATIC
++                | STRUCT
++                | TRAIT
++                | TYPE_ALIAS
++                | UNION
++                | USE
++                | ITEM_LIST
++                | BLOCK_EXPR
++                | SELF_PARAM
++                | PARAM
++                | RECORD_FIELD
++                | TUPLE_FIELD
++                | VARIANT
++                | ASSOC_ITEM_LIST
++                | EXTERN_ITEM_LIST
++                | CONST_PARAM
++                | LIFETIME_PARAM
++                | TYPE_PARAM
++                | LET_STMT
++                | ARRAY_EXPR
++                | AWAIT_EXPR
++                | BIN_EXPR
++                | BOX_EXPR
++                | BREAK_EXPR
++                | CALL_EXPR
++                | CAST_EXPR
++                | CLOSURE_EXPR
++                | CONTINUE_EXPR
++                | FIELD_EXPR
++                | FOR_EXPR
++                | IF_EXPR
++                | INDEX_EXPR
++                | LITERAL
++                | LOOP_EXPR
++                | MATCH_EXPR
++                | METHOD_CALL_EXPR
++                | PAREN_EXPR
++                | PATH_EXPR
++                | PREFIX_EXPR
++                | RANGE_EXPR
++                | REF_EXPR
++                | RETURN_EXPR
++                | TRY_EXPR
++                | TUPLE_EXPR
++                | WHILE_EXPR
++                | YIELD_EXPR
++                | LET_EXPR
++                | UNDERSCORE_EXPR
++                | STMT_LIST
++                | RECORD_EXPR_FIELD_LIST
++                | RECORD_EXPR_FIELD
++                | MATCH_ARM_LIST
++                | MATCH_ARM
++                | IDENT_PAT
++                | REST_PAT
++                | RECORD_PAT_FIELD
++        )
 +    }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        Self::can_cast(syntax.kind()).then(|| AnyHasAttrs { syntax })
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AnyHasDocComments {
 +    #[inline]
 +    pub fn new<T: ast::HasDocComments>(node: T) -> AnyHasDocComments {
 +        AnyHasDocComments { syntax: node.syntax().clone() }
 +    }
 +}
 +impl AstNode for AnyHasDocComments {
 +    fn can_cast(kind: SyntaxKind) -> bool {
-         match kind {
-             ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION => true,
-             _ => false,
-         }
++        matches!(
++            kind,
++            MACRO_CALL
++                | SOURCE_FILE
++                | CONST
++                | ENUM
++                | EXTERN_BLOCK
++                | EXTERN_CRATE
++                | FN
++                | IMPL
++                | MACRO_RULES
++                | MACRO_DEF
++                | MODULE
++                | STATIC
++                | STRUCT
++                | TRAIT
++                | TYPE_ALIAS
++                | UNION
++                | USE
++                | RECORD_FIELD
++                | TUPLE_FIELD
++                | VARIANT
++        )
 +    }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        Self::can_cast(syntax.kind()).then(|| AnyHasDocComments { syntax })
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AnyHasGenericParams {
 +    #[inline]
 +    pub fn new<T: ast::HasGenericParams>(node: T) -> AnyHasGenericParams {
 +        AnyHasGenericParams { syntax: node.syntax().clone() }
 +    }
 +}
 +impl AstNode for AnyHasGenericParams {
 +    fn can_cast(kind: SyntaxKind) -> bool {
-     fn can_cast(kind: SyntaxKind) -> bool {
-         match kind {
-             FOR_EXPR | LOOP_EXPR | WHILE_EXPR => true,
-             _ => false,
-         }
-     }
++        matches!(kind, ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION)
 +    }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        Self::can_cast(syntax.kind()).then(|| AnyHasGenericParams { syntax })
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AnyHasLoopBody {
 +    #[inline]
 +    pub fn new<T: ast::HasLoopBody>(node: T) -> AnyHasLoopBody {
 +        AnyHasLoopBody { syntax: node.syntax().clone() }
 +    }
 +}
 +impl AstNode for AnyHasLoopBody {
-     fn can_cast(kind: SyntaxKind) -> bool {
-         match kind {
-             MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => true,
-             _ => false,
-         }
-     }
++    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FOR_EXPR | LOOP_EXPR | WHILE_EXPR) }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        Self::can_cast(syntax.kind()).then(|| AnyHasLoopBody { syntax })
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AnyHasModuleItem {
 +    #[inline]
 +    pub fn new<T: ast::HasModuleItem>(node: T) -> AnyHasModuleItem {
 +        AnyHasModuleItem { syntax: node.syntax().clone() }
 +    }
 +}
 +impl AstNode for AnyHasModuleItem {
-         match kind {
-             CONST | ENUM | FN | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT
-             | TYPE_ALIAS | UNION | RENAME | SELF_PARAM | RECORD_FIELD | VARIANT | CONST_PARAM
-             | TYPE_PARAM | IDENT_PAT => true,
-             _ => false,
-         }
++    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, MACRO_ITEMS | SOURCE_FILE | ITEM_LIST) }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        Self::can_cast(syntax.kind()).then(|| AnyHasModuleItem { syntax })
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AnyHasName {
 +    #[inline]
 +    pub fn new<T: ast::HasName>(node: T) -> AnyHasName {
 +        AnyHasName { syntax: node.syntax().clone() }
 +    }
 +}
 +impl AstNode for AnyHasName {
 +    fn can_cast(kind: SyntaxKind) -> bool {
-         match kind {
-             ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED => true,
-             _ => false,
-         }
++        matches!(
++            kind,
++            CONST
++                | ENUM
++                | FN
++                | MACRO_RULES
++                | MACRO_DEF
++                | MODULE
++                | STATIC
++                | STRUCT
++                | TRAIT
++                | TYPE_ALIAS
++                | UNION
++                | RENAME
++                | SELF_PARAM
++                | RECORD_FIELD
++                | VARIANT
++                | CONST_PARAM
++                | TYPE_PARAM
++                | IDENT_PAT
++        )
 +    }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        Self::can_cast(syntax.kind()).then(|| AnyHasName { syntax })
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AnyHasTypeBounds {
 +    #[inline]
 +    pub fn new<T: ast::HasTypeBounds>(node: T) -> AnyHasTypeBounds {
 +        AnyHasTypeBounds { syntax: node.syntax().clone() }
 +    }
 +}
 +impl AstNode for AnyHasTypeBounds {
 +    fn can_cast(kind: SyntaxKind) -> bool {
-         match kind {
-             CONST | ENUM | EXTERN_CRATE | FN | IMPL | MACRO_RULES | MACRO_DEF | MODULE | STATIC
-             | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE | RECORD_FIELD | TUPLE_FIELD | VARIANT => {
-                 true
-             }
-             _ => false,
-         }
++        matches!(
++            kind,
++            ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED
++        )
 +    }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        Self::can_cast(syntax.kind()).then(|| AnyHasTypeBounds { syntax })
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl AnyHasVisibility {
 +    #[inline]
 +    pub fn new<T: ast::HasVisibility>(node: T) -> AnyHasVisibility {
 +        AnyHasVisibility { syntax: node.syntax().clone() }
 +    }
 +}
 +impl AstNode for AnyHasVisibility {
 +    fn can_cast(kind: SyntaxKind) -> bool {
++        matches!(
++            kind,
++            CONST
++                | ENUM
++                | EXTERN_CRATE
++                | FN
++                | IMPL
++                | MACRO_RULES
++                | MACRO_DEF
++                | MODULE
++                | STATIC
++                | STRUCT
++                | TRAIT
++                | TYPE_ALIAS
++                | UNION
++                | USE
++                | RECORD_FIELD
++                | TUPLE_FIELD
++                | VARIANT
++        )
 +    }
 +    fn cast(syntax: SyntaxNode) -> Option<Self> {
 +        Self::can_cast(syntax.kind()).then(|| AnyHasVisibility { syntax })
 +    }
 +    fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +}
 +impl std::fmt::Display for GenericArg {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Type {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Expr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Item {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Stmt {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Pat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for FieldList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Adt {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for AssocItem {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ExternItem {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for GenericParam {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Name {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for NameRef {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Lifetime {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Path {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for PathSegment {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for GenericArgList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ParamList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for RetType {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for PathType {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for TypeArg {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for AssocTypeArg {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for LifetimeArg {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ConstArg {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for GenericParamList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for TypeBoundList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for MacroCall {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Attr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for TokenTree {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for MacroItems {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for MacroStmts {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for SourceFile {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Const {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Enum {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ExternBlock {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ExternCrate {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Fn {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Impl {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for MacroRules {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for MacroDef {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Module {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Static {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Struct {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Trait {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for TypeAlias {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Union {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Use {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Visibility {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ItemList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Rename {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for UseTree {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for UseTreeList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Abi {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for WhereClause {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for BlockExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for SelfParam {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Param {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for RecordFieldList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for TupleFieldList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for RecordField {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for TupleField {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for VariantList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Variant {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for AssocItemList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ExternItemList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ConstParam {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for LifetimeParam {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for TypeParam {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for WherePred {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Meta {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ExprStmt {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for LetStmt {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for LetElse {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ArrayExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for AwaitExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for BinExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for BoxExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for BreakExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for CallExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for CastExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ClosureExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ContinueExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for FieldExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ForExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for IfExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for IndexExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Literal {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for LoopExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for MacroExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for MatchExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for MethodCallExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ParenExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for PathExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for PrefixExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for RangeExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for RecordExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for RefExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ReturnExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for TryExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for TupleExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for WhileExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for YieldExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for LetExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for UnderscoreExpr {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for StmtList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for Label {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for RecordExprFieldList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for RecordExprField {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ArgList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for MatchArmList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for MatchArm {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for MatchGuard {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ArrayType {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for DynTraitType {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for FnPtrType {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ForType {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ImplTraitType {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for InferType {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for MacroType {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for NeverType {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ParenType {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for PtrType {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for RefType {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for SliceType {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for TupleType {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for TypeBound {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for IdentPat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for BoxPat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for RestPat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for LiteralPat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for MacroPat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for OrPat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ParenPat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for PathPat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for WildcardPat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for RangePat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for RecordPat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for RefPat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for SlicePat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for TuplePat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for TupleStructPat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for ConstBlockPat {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for RecordPatFieldList {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
 +impl std::fmt::Display for RecordPatField {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        std::fmt::Display::fmt(self.syntax(), f)
 +    }
 +}
index 037de876d45c94f16955502621129bc2872b2b85,0000000000000000000000000000000000000000..83f8bbac5880bfd5fa542f03e90af2110039d169
mode 100644,000000..100644
--- /dev/null
@@@ -1,904 -1,0 +1,905 @@@
-             ast_from_text(&format!("fn f({}: ())", text))
 +//! 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 {
-         expr_from_text(&format!("{}::default()", ty))
++            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!("{}::new()", ty))
++        expr_from_text(&format!("{ty}::default()"))
 +    }
 +    pub fn expr_ty_new(ty: &ast::Type) -> ast::Expr {
-         ty_from_text(&format!("Option<{}>", t))
++        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_bool() -> ast::Type {
 +        ty_path(ident_path("bool"))
 +    }
 +    pub fn ty_option(t: ast::Type) -> ast::Type {
-         ty_from_text(&format!("Result<{}, {}>", t, e))
++        ty_from_text(&format!("Option<{t}>"))
 +    }
 +    pub fn ty_result(t: ast::Type, e: ast::Type) -> ast::Type {
- pub fn name(text: &str) -> ast::Name {
-     ast_from_text(&format!("mod {}{};", raw_ident_esc(text), text))
++        ty_from_text(&format!("Result<{t}, {e}>"))
 +    }
 +}
 +
- pub fn name_ref(text: &str) -> ast::NameRef {
-     ast_from_text(&format!("fn f() {{ {}{}; }}", raw_ident_esc(text), text))
++pub fn name(name: &str) -> ast::Name {
++    let raw_escape = raw_ident_esc(name);
++    ast_from_text(&format!("mod {raw_escape}{name};"))
 +}
-         tmp = format!("'{}", text);
++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('\'')) {
-     ast_from_text(&format!("fn f<{}>() {{ }}", text))
++        tmp = format!("'{text}");
 +        text = &tmp;
 +    }
-     ty_from_text(&format!("({})", contents))
++    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(&if exclusive { format!("&mut {}", target) } else { format!("&{}", target) })
++    ty_from_text(&format!("({contents})"))
 +}
 +pub fn ty_ref(target: ast::Type, exclusive: bool) -> ast::Type {
-     ast_from_text(&format!("type _T = {};", text))
++    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!("impl{} {}{} {{}}", params, ty, ty_params))
++    ast_from_text(&format!("type _T = {text};"))
 +}
 +
 +pub fn assoc_item_list() -> ast::AssocItemList {
 +    ast_from_text("impl C for D {}")
 +}
 +
 +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{2} {} for {}{2} {{}}", trait_, ty, ty_params))
++    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!("type __ = {};", name_ref))
++    ast_from_text(&format!("impl{ty_params} {trait_} for {ty}{ty_params} {{}}"))
 +}
 +
 +pub(crate) fn generic_arg_list() -> ast::GenericArgList {
 +    ast_from_text("const S: T<> = ();")
 +}
 +
 +pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
-         Some(trait_ref) => format!("fn f(x: <{} as {}>) {{}}", type_ref, trait_ref),
-         None => format!("fn f(x: <{}>) {{}}", type_ref),
++    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 {
-     ast_from_text(&format!("type __ = {};", segment))
++        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!("{}::{}", qual, segment))
++    ast_from_text(&format!("type __ = {segment};"))
 +}
 +
 +pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path {
-     ast_from_text(&format!("type __ = {}::{};", first, second))
++    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 {
-         format!("fn f(x: ::{}) {{}}", segments)
++    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)
++        format!("fn f(x: ::{segments}) {{}}")
 +    } else {
-     ast_from_text(&format!("type __ = {};", paths))
++        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!("fn main() {{ let test = {}; }}", text))
++    ast_from_text(&format!("type __ = {paths};"))
 +}
 +
 +// FIXME: should not be pub
 +pub fn path_from_text(text: &str) -> ast::Path {
-         format_to!(buf, "::{}", use_tree_list);
++    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, " {}", alias);
++        format_to!(buf, "::{use_tree_list}");
 +    }
 +    if add_star {
 +        buf += "::*";
 +    }
 +
 +    if let Some(alias) = alias {
-     ast_from_text(&format!("use {{{}}};", use_trees))
++        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(", ");
-         Some(it) => format!("{} ", it),
++    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(),
-     ast_from_text(&format!("{}use {};", visibility, use_tree))
++        Some(it) => format!("{it} "),
 +    };
-     ast_from_text(&format!("fn f() {{ {} {} }}", path, fields))
++    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() {{ S {{ {} }} }}", fields))
++    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(", ");
-         Some(expr) => from_text(&format!("{}: {}", name, expr)),
++    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 {
-         ast_from_text(&format!("fn f() {{ S {{ {}, }} }}", text))
++        Some(expr) => from_text(&format!("{name}: {expr}")),
 +        None => from_text(&name.to_string()),
 +    };
 +
 +    fn from_text(text: &str) -> ast::RecordExprField {
-         Some(it) => format!("{} ", it),
++        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(),
-     ast_from_text(&format!("struct S {{ {}{}: {}, }}", visibility, name, ty))
++        Some(it) => format!("{it} "),
 +    };
-         format_to!(buf, "    {}\n", stmt);
++    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, "    {}\n", tail_expr);
++        format_to!(buf, "    {stmt}\n");
 +    }
 +    if let Some(tail_expr) = tail_expr {
-     ast_from_text(&format!("fn f() {}", buf))
++        format_to!(buf, "    {tail_expr}\n");
 +    }
 +    buf += "}";
-             rowan::NodeOrToken::Node(n) => format_to!(buf, "    {}\n", n),
++    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 {
-                 format_to!(buf, "    {}\n", t)
++            rowan::NodeOrToken::Node(n) => format_to!(buf, "    {n}\n"),
 +            rowan::NodeOrToken::Token(t) if t.kind() == SyntaxKind::COMMENT => {
-         format_to!(buf, "    {}\n", tail_expr);
++                format_to!(buf, "    {t}\n")
 +            }
 +            _ => (),
 +        }
 +    }
 +    if let Some(tail_expr) = tail_expr {
-     ast_from_text(&format!("fn f() {}", buf))
++        format_to!(buf, "    {tail_expr}\n");
 +    }
 +    buf += "}";
-     ast_from_text(&format!("fn f() {{ let _ = {}; }}", text))
++    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);
-         Some(label) => expr_from_text(&format!("continue {}", label)),
++    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 {
-     expr_from_text(&format!("{} {} {}", lhs, op, rhs))
++        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 {
-         format_to!(s, " {}", label);
++    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, " {}", expr);
++        format_to!(s, " {label}");
 +    }
 +
 +    if let Some(expr) = expr {
-         Some(expr) => expr_from_text(&format!("return {}", expr)),
++        format_to!(s, " {expr}");
 +    }
 +
 +    expr_from_text(&s)
 +}
 +pub fn expr_return(expr: Option<ast::Expr>) -> ast::Expr {
 +    match expr {
-     expr_from_text(&format!("{}?", 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!("{}.await", expr))
++    expr_from_text(&format!("{expr}?"))
 +}
 +pub fn expr_await(expr: ast::Expr) -> ast::Expr {
-     expr_from_text(&format!("match {} {}", expr, match_arm_list))
++    expr_from_text(&format!("{expr}.await"))
 +}
 +pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
-         Some(ast::ElseBranch::Block(block)) => format!("else {}", block),
-         Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {}", if_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 {
-     expr_from_text(&format!("if {} {} {}", condition, then_branch, 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!("for {} in {} {}", pat, expr, block))
++    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!("loop {}", block))
++    expr_from_text(&format!("for {pat} in {expr} {block}"))
 +}
 +
 +pub fn expr_loop(block: ast::BlockExpr) -> ast::Expr {
-     expr_from_text(&format!("{}{}", token, 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!("{}{}", f, arg_list))
++    expr_from_text(&format!("{token}{expr}"))
 +}
 +pub fn expr_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr {
-     expr_from_text(&format!("{}.{}{}", receiver, method, arg_list))
++    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!("{}!{}", f, arg_list))
++    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(&if exclusive { format!("&mut {}", expr) } else { format!("&{}", expr) })
++    expr_from_text(&format!("{f}!{arg_list}"))
 +}
 +pub fn expr_ref(expr: ast::Expr, exclusive: bool) -> ast::Expr {
-     expr_from_text(&format!("|{}| {}", params, 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!("{}.{}", receiver, field))
++    expr_from_text(&format!("|{params}| {expr}"))
 +}
 +pub fn expr_field(receiver: ast::Expr, field: &str) -> ast::Expr {
-     expr_from_text(&format!("({})", expr))
++    expr_from_text(&format!("{receiver}.{field}"))
 +}
 +pub fn expr_paren(expr: ast::Expr) -> ast::Expr {
-     expr_from_text(&format!("({})", 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!("{} = {}", lhs, rhs))
++    expr_from_text(&format!("({expr})"))
 +}
 +pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
-     ast_from_text(&format!("const C: () = {};", text))
++    expr_from_text(&format!("{lhs} = {rhs}"))
 +}
 +fn expr_from_text(text: &str) -> ast::Expr {
-     ast_from_text(&format!("const _: () = while let {} = {} {{}};", pattern, expr))
++    ast_from_text(&format!("const C: () = {text};"))
 +}
 +pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
-     ast_from_text(&format!("fn main() {{ ()({}) }}", args.into_iter().format(", ")))
++    ast_from_text(&format!("const _: () = while let {pattern} = {expr} {{}};"))
 +}
 +
 +pub fn arg_list(args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList {
-     format_to!(s, "{}", name);
++    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 ");
 +    }
-         ast_from_text(&format!("fn f({}: ())", text))
++    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() {{ match x {{ {} => {{}} }} }}", text))
++        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 {
-     return from_text(&format!("({})", pats_str));
++        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(',');
 +    }
-         ast_from_text(&format!("fn f({}: ())", text))
++    return from_text(&format!("({pats_str})"));
 +
 +    fn from_text(text: &str) -> ast::TuplePat {
-     return from_text(&format!("{}({})", path, pats_str));
++        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(", ");
-         ast_from_text(&format!("fn f({}: ())", text))
++    return from_text(&format!("{path}({pats_str})"));
 +
 +    fn from_text(text: &str) -> ast::TupleStructPat {
-     return from_text(&format!("{} {{ {} }}", path, pats_str));
++        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(", ");
-         ast_from_text(&format!("fn f({}: ())", text))
++    return from_text(&format!("{path} {{ {pats_str} }}"));
 +
 +    fn from_text(text: &str) -> ast::RecordPat {
-     ast_from_text(&format!("fn f({} {}: ()))", path, fields))
++        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(S {{ {} }}: ()))", fields))
++    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 {{ {}: {} }}: ()))", name_ref, pat))
++    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))
++    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({}: ())", text))
++    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 {
-         Some(guard) => from_text(&format!("{} if {} => {}", pats_str, guard, expr)),
-         None => from_text(&format!("{} => {}", pats_str, expr)),
++        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 {
-         ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text))
++        Some(guard) => from_text(&format!("{pats_str} if {guard} => {expr}")),
++        None => from_text(&format!("{pats_str} => {expr}")),
 +    };
 +
 +    fn from_text(text: &str) -> ast::MatchArm {
-     return from_text(&format!("{} if {} => {}", pats_str, guard, expr));
++        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(" | ");
-         ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text))
++    return from_text(&format!("{pats_str} if {guard} => {expr}"));
 +
 +    fn from_text(text: &str) -> ast::MatchArm {
-             format!("    {}{}\n", arm.syntax(), comma)
++        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 { "" };
-         ast_from_text(&format!("fn f() {{ match () {{\n{}}} }}", text))
++            let arm = arm.syntax();
++            format!("    {arm}{comma}\n")
 +        })
 +        .collect::<String>();
 +    return from_text(&arms_str);
 +
 +    fn from_text(text: &str) -> ast::MatchArmList {
-     return from_text(&format!("{}: {}", path, bounds));
++        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(" + ");
-         ast_from_text(&format!("fn f() where {} {{ }}", text))
++    return from_text(&format!("{path}: {bounds}"));
 +
 +    fn from_text(text: &str) -> ast::WherePred {
-         ast_from_text(&format!("fn f() where {} {{ }}", text))
++        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 {
-     format_to!(text, "let {}", pattern);
++        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, ": {}", ty);
++    format_to!(text, "let {pattern}");
 +    if let Some(ty) = ty {
-         Some(it) => format_to!(text, " = {};", it),
++        format_to!(text, ": {ty}");
 +    }
 +    match initializer {
-     ast_from_text(&format!("fn f() {{ {} }}", text))
++        Some(it) => format_to!(text, " = {it};"),
 +        None => format_to!(text, ";"),
 +    };
-     ast_from_text(&format!("fn f() {{ {}{} (); }}", expr, semi))
++    ast_from_text(&format!("fn f() {{ {text} }}"))
 +}
 +pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt {
 +    let semi = if expr.is_block_like() { "" } else { ";" };
-         Some(it) => format!("{} ", it),
++    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(),
-     ast_from_text(&format!("{} const {}: {} = {};", visibility, name, ty, expr))
++        Some(it) => format!("{it} "),
 +    };
-     ast_from_text(&format!("fn f({}: {}) {{ }}", pat, ty))
++    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() -> {} {{ }}", ty))
++    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 {
-         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(&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(it) => format!(": {}", it),
++        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 {
-     ast_from_text(&format!("fn f<{}{}>() {{ }}", name, bound))
++        Some(it) => format!(": {it}"),
 +        None => String::new(),
 +    };
-     ast_from_text(&format!("fn f<{}>() {{ }}", lifetime))
++    ast_from_text(&format!("fn f<{name}{bound}>() {{ }}"))
 +}
 +
 +pub fn lifetime_param(lifetime: ast::Lifetime) -> ast::LifetimeParam {
-     ast_from_text(&format!("fn f<{}>() {{ }}", args))
++    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!("struct f({});", fields))
++    ast_from_text(&format!("fn f<{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))
++    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(", ");
-         Some(it) => format!("{} ", it),
++    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(),
-     ast_from_text(&format!("struct f({}{});", visibility, ty))
++        Some(it) => format!("{it} "),
 +    };
-             ast::FieldList::RecordFieldList(record) => format!(" {}", record),
-             ast::FieldList::TupleFieldList(tuple) => format!("{}", tuple),
++    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_from_text(&format!("enum f {{ {}{} }}", name, field_list))
++            ast::FieldList::RecordFieldList(record) => format!(" {record}"),
++            ast::FieldList::TupleFieldList(tuple) => format!("{tuple}"),
 +        },
 +    };
-         Some(type_params) => format!("{}", type_params),
++    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(ret_type) => format!("{} ", ret_type),
++        Some(type_params) => format!("{type_params}"),
 +        None => "".into(),
 +    };
 +    let ret_type = match ret_type {
-         Some(it) => format!("{} ", it),
++        Some(ret_type) => format!("{ret_type} "),
 +        None => "".into(),
 +    };
 +    let visibility = match visibility {
 +        None => String::new(),
-         "{}{}fn {}{}{} {}{}",
-         visibility, async_literal, fn_name, type_params, params, ret_type, body
++        Some(it) => format!("{it} "),
 +    };
 +
 +    let async_literal = if is_async { "async " } else { "" };
 +
 +    ast_from_text(&format!(
-         Some(it) => format!("{} ", it),
++        "{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(),
-     ast_from_text(&format!(
-         "{}struct {}{}{}{}",
-         visibility, strukt_name, type_params, field_list, semicolon
-     ))
++        Some(it) => format!("{it} "),
 +    };
 +
-             panic!("Failed to make ast node `{}` from text {}", std::any::type_name::<N>(), text)
++    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 => {
-         .unwrap_or_else(|| panic!("unhandled token: {:?}", kind))
++            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)
-         let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {}; }}", text));
++        .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 28976d837b88a142e44d26c06a11d2108606d24c,0000000000000000000000000000000000000000..ba72e64425b23c095063a54e3aa7cf1edef2e618
mode 100644,000000..100644
--- /dev/null
@@@ -1,472 -1,0 +1,489 @@@
-         text.parse::<f64>().ok()
 +//! There are many AstNodes, but only a few tokens, so we hand-write them here.
 +
 +use std::borrow::Cow;
 +
 +use rustc_lexer::unescape::{unescape_byte, unescape_char, unescape_literal, Mode};
 +
 +use crate::{
 +    ast::{self, AstToken},
 +    TextRange, TextSize,
 +};
 +
 +impl ast::Comment {
 +    pub fn kind(&self) -> CommentKind {
 +        CommentKind::from_text(self.text())
 +    }
 +
 +    pub fn is_doc(&self) -> bool {
 +        self.kind().doc.is_some()
 +    }
 +
 +    pub fn is_inner(&self) -> bool {
 +        self.kind().doc == Some(CommentPlacement::Inner)
 +    }
 +
 +    pub fn is_outer(&self) -> bool {
 +        self.kind().doc == Some(CommentPlacement::Outer)
 +    }
 +
 +    pub fn prefix(&self) -> &'static str {
 +        let &(prefix, _kind) = CommentKind::BY_PREFIX
 +            .iter()
 +            .find(|&(prefix, kind)| self.kind() == *kind && self.text().starts_with(prefix))
 +            .unwrap();
 +        prefix
 +    }
 +
 +    /// Returns the textual content of a doc comment node as a single string with prefix and suffix
 +    /// removed.
 +    pub fn doc_comment(&self) -> Option<&str> {
 +        let kind = self.kind();
 +        match kind {
 +            CommentKind { shape, doc: Some(_) } => {
 +                let prefix = kind.prefix();
 +                let text = &self.text()[prefix.len()..];
 +                let text = if shape == CommentShape::Block {
 +                    text.strip_suffix("*/").unwrap_or(text)
 +                } else {
 +                    text
 +                };
 +                Some(text)
 +            }
 +            _ => None,
 +        }
 +    }
 +}
 +
 +#[derive(Debug, PartialEq, Eq, Clone, Copy)]
 +pub struct CommentKind {
 +    pub shape: CommentShape,
 +    pub doc: Option<CommentPlacement>,
 +}
 +
 +#[derive(Debug, PartialEq, Eq, Clone, Copy)]
 +pub enum CommentShape {
 +    Line,
 +    Block,
 +}
 +
 +impl CommentShape {
 +    pub fn is_line(self) -> bool {
 +        self == CommentShape::Line
 +    }
 +
 +    pub fn is_block(self) -> bool {
 +        self == CommentShape::Block
 +    }
 +}
 +
 +#[derive(Debug, PartialEq, Eq, Clone, Copy)]
 +pub enum CommentPlacement {
 +    Inner,
 +    Outer,
 +}
 +
 +impl CommentKind {
 +    const BY_PREFIX: [(&'static str, CommentKind); 9] = [
 +        ("/**/", CommentKind { shape: CommentShape::Block, doc: None }),
 +        ("/***", CommentKind { shape: CommentShape::Block, doc: None }),
 +        ("////", CommentKind { shape: CommentShape::Line, doc: None }),
 +        ("///", CommentKind { shape: CommentShape::Line, doc: Some(CommentPlacement::Outer) }),
 +        ("//!", CommentKind { shape: CommentShape::Line, doc: Some(CommentPlacement::Inner) }),
 +        ("/**", CommentKind { shape: CommentShape::Block, doc: Some(CommentPlacement::Outer) }),
 +        ("/*!", CommentKind { shape: CommentShape::Block, doc: Some(CommentPlacement::Inner) }),
 +        ("//", CommentKind { shape: CommentShape::Line, doc: None }),
 +        ("/*", CommentKind { shape: CommentShape::Block, doc: None }),
 +    ];
 +
 +    pub(crate) fn from_text(text: &str) -> CommentKind {
 +        let &(_prefix, kind) = CommentKind::BY_PREFIX
 +            .iter()
 +            .find(|&(prefix, _kind)| text.starts_with(prefix))
 +            .unwrap();
 +        kind
 +    }
 +
 +    pub fn prefix(&self) -> &'static str {
 +        let &(prefix, _) =
 +            CommentKind::BY_PREFIX.iter().rev().find(|(_, kind)| kind == self).unwrap();
 +        prefix
 +    }
 +}
 +
 +impl ast::Whitespace {
 +    pub fn spans_multiple_lines(&self) -> bool {
 +        let text = self.text();
 +        text.find('\n').map_or(false, |idx| text[idx + 1..].contains('\n'))
 +    }
 +}
 +
 +pub struct QuoteOffsets {
 +    pub quotes: (TextRange, TextRange),
 +    pub contents: TextRange,
 +}
 +
 +impl QuoteOffsets {
 +    fn new(literal: &str) -> Option<QuoteOffsets> {
 +        let left_quote = literal.find('"')?;
 +        let right_quote = literal.rfind('"')?;
 +        if left_quote == right_quote {
 +            // `literal` only contains one quote
 +            return None;
 +        }
 +
 +        let start = TextSize::from(0);
 +        let left_quote = TextSize::try_from(left_quote).unwrap() + TextSize::of('"');
 +        let right_quote = TextSize::try_from(right_quote).unwrap();
 +        let end = TextSize::of(literal);
 +
 +        let res = QuoteOffsets {
 +            quotes: (TextRange::new(start, left_quote), TextRange::new(right_quote, end)),
 +            contents: TextRange::new(left_quote, right_quote),
 +        };
 +        Some(res)
 +    }
 +}
 +
 +pub trait IsString: AstToken {
 +    fn quote_offsets(&self) -> Option<QuoteOffsets> {
 +        let text = self.text();
 +        let offsets = QuoteOffsets::new(text)?;
 +        let o = self.syntax().text_range().start();
 +        let offsets = QuoteOffsets {
 +            quotes: (offsets.quotes.0 + o, offsets.quotes.1 + o),
 +            contents: offsets.contents + o,
 +        };
 +        Some(offsets)
 +    }
 +    fn text_range_between_quotes(&self) -> Option<TextRange> {
 +        self.quote_offsets().map(|it| it.contents)
 +    }
 +    fn open_quote_text_range(&self) -> Option<TextRange> {
 +        self.quote_offsets().map(|it| it.quotes.0)
 +    }
 +    fn close_quote_text_range(&self) -> Option<TextRange> {
 +        self.quote_offsets().map(|it| it.quotes.1)
 +    }
 +    fn escaped_char_ranges(
 +        &self,
 +        cb: &mut dyn FnMut(TextRange, Result<char, rustc_lexer::unescape::EscapeError>),
 +    ) {
 +        let text_range_no_quotes = match self.text_range_between_quotes() {
 +            Some(it) => it,
 +            None => return,
 +        };
 +
 +        let start = self.syntax().text_range().start();
 +        let text = &self.text()[text_range_no_quotes - start];
 +        let offset = text_range_no_quotes.start() - start;
 +
 +        unescape_literal(text, Mode::Str, &mut |range, unescaped_char| {
 +            let text_range =
 +                TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap());
 +            cb(text_range + offset, unescaped_char);
 +        });
 +    }
 +}
 +
 +impl IsString for ast::String {}
 +
 +impl ast::String {
 +    pub fn is_raw(&self) -> bool {
 +        self.text().starts_with('r')
 +    }
 +    pub fn map_range_up(&self, range: TextRange) -> Option<TextRange> {
 +        let contents_range = self.text_range_between_quotes()?;
 +        assert!(TextRange::up_to(contents_range.len()).contains_range(range));
 +        Some(range + contents_range.start())
 +    }
 +
 +    pub fn value(&self) -> Option<Cow<'_, str>> {
 +        if self.is_raw() {
 +            let text = self.text();
 +            let text =
 +                &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
 +            return Some(Cow::Borrowed(text));
 +        }
 +
 +        let text = self.text();
 +        let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
 +
 +        let mut buf = String::new();
 +        let mut text_iter = text.chars();
 +        let mut has_error = false;
 +        unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match (
 +            unescaped_char,
 +            buf.capacity() == 0,
 +        ) {
 +            (Ok(c), false) => buf.push(c),
 +            (Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (),
 +            (Ok(c), true) => {
 +                buf.reserve_exact(text.len());
 +                buf.push_str(&text[..char_range.start]);
 +                buf.push(c);
 +            }
 +            (Err(_), _) => has_error = true,
 +        });
 +
 +        match (has_error, buf.capacity() == 0) {
 +            (true, _) => None,
 +            (false, true) => Some(Cow::Borrowed(text)),
 +            (false, false) => Some(Cow::Owned(buf)),
 +        }
 +    }
 +}
 +
 +impl IsString for ast::ByteString {}
 +
 +impl ast::ByteString {
 +    pub fn is_raw(&self) -> bool {
 +        self.text().starts_with("br")
 +    }
 +
 +    pub fn value(&self) -> Option<Cow<'_, [u8]>> {
 +        if self.is_raw() {
 +            let text = self.text();
 +            let text =
 +                &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
 +            return Some(Cow::Borrowed(text.as_bytes()));
 +        }
 +
 +        let text = self.text();
 +        let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
 +
 +        let mut buf: Vec<u8> = Vec::new();
 +        let mut text_iter = text.chars();
 +        let mut has_error = false;
 +        unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match (
 +            unescaped_char,
 +            buf.capacity() == 0,
 +        ) {
 +            (Ok(c), false) => buf.push(c as u8),
 +            (Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (),
 +            (Ok(c), true) => {
 +                buf.reserve_exact(text.len());
 +                buf.extend_from_slice(text[..char_range.start].as_bytes());
 +                buf.push(c as u8);
 +            }
 +            (Err(_), _) => has_error = true,
 +        });
 +
 +        match (has_error, buf.capacity() == 0) {
 +            (true, _) => None,
 +            (false, true) => Some(Cow::Borrowed(text.as_bytes())),
 +            (false, false) => Some(Cow::Owned(buf)),
 +        }
 +    }
 +}
 +
 +impl ast::IntNumber {
 +    pub fn radix(&self) -> Radix {
 +        match self.text().get(..2).unwrap_or_default() {
 +            "0b" => Radix::Binary,
 +            "0o" => Radix::Octal,
 +            "0x" => Radix::Hexadecimal,
 +            _ => Radix::Decimal,
 +        }
 +    }
 +
 +    pub fn split_into_parts(&self) -> (&str, &str, &str) {
 +        let radix = self.radix();
 +        let (prefix, mut text) = self.text().split_at(radix.prefix_len());
 +
 +        let is_suffix_start: fn(&(usize, char)) -> bool = match radix {
 +            Radix::Hexadecimal => |(_, c)| matches!(c, 'g'..='z' | 'G'..='Z'),
 +            _ => |(_, c)| c.is_ascii_alphabetic(),
 +        };
 +
 +        let mut suffix = "";
 +        if let Some((suffix_start, _)) = text.char_indices().find(is_suffix_start) {
 +            let (text2, suffix2) = text.split_at(suffix_start);
 +            text = text2;
 +            suffix = suffix2;
 +        };
 +
 +        (prefix, text, suffix)
 +    }
 +
 +    pub fn value(&self) -> Option<u128> {
 +        let (_, text, _) = self.split_into_parts();
 +        let value = u128::from_str_radix(&text.replace('_', ""), self.radix() as u32).ok()?;
 +        Some(value)
 +    }
 +
 +    pub fn suffix(&self) -> Option<&str> {
 +        let (_, _, suffix) = self.split_into_parts();
 +        if suffix.is_empty() {
 +            None
 +        } else {
 +            Some(suffix)
 +        }
 +    }
 +
 +    pub fn float_value(&self) -> Option<f64> {
 +        let (_, text, _) = self.split_into_parts();
-         text.parse::<f64>().ok()
++        text.replace('_', "").parse::<f64>().ok()
 +    }
 +}
 +
 +impl ast::FloatNumber {
 +    pub fn split_into_parts(&self) -> (&str, &str) {
 +        let text = self.text();
 +        let mut float_text = self.text();
 +        let mut suffix = "";
 +        let mut indices = text.char_indices();
 +        if let Some((mut suffix_start, c)) = indices.by_ref().find(|(_, c)| c.is_ascii_alphabetic())
 +        {
 +            if c == 'e' || c == 'E' {
 +                if let Some(suffix_start_tuple) = indices.find(|(_, c)| c.is_ascii_alphabetic()) {
 +                    suffix_start = suffix_start_tuple.0;
 +
 +                    float_text = &text[..suffix_start];
 +                    suffix = &text[suffix_start..];
 +                }
 +            } else {
 +                float_text = &text[..suffix_start];
 +                suffix = &text[suffix_start..];
 +            }
 +        }
 +
 +        (float_text, suffix)
 +    }
 +
 +    pub fn suffix(&self) -> Option<&str> {
 +        let (_, suffix) = self.split_into_parts();
 +        if suffix.is_empty() {
 +            None
 +        } else {
 +            Some(suffix)
 +        }
 +    }
 +
 +    pub fn value(&self) -> Option<f64> {
 +        let (text, _) = self.split_into_parts();
++        text.replace('_', "").parse::<f64>().ok()
 +    }
 +}
 +
 +#[derive(Debug, PartialEq, Eq, Copy, Clone)]
 +pub enum Radix {
 +    Binary = 2,
 +    Octal = 8,
 +    Decimal = 10,
 +    Hexadecimal = 16,
 +}
 +
 +impl Radix {
 +    pub const ALL: &'static [Radix] =
 +        &[Radix::Binary, Radix::Octal, Radix::Decimal, Radix::Hexadecimal];
 +
 +    const fn prefix_len(self) -> usize {
 +        match self {
 +            Self::Decimal => 0,
 +            _ => 2,
 +        }
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use crate::ast::{self, make, FloatNumber, IntNumber};
 +
 +    fn check_float_suffix<'a>(lit: &str, expected: impl Into<Option<&'a str>>) {
 +        assert_eq!(FloatNumber { syntax: make::tokens::literal(lit) }.suffix(), expected.into());
 +    }
 +
 +    fn check_int_suffix<'a>(lit: &str, expected: impl Into<Option<&'a str>>) {
 +        assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.suffix(), expected.into());
 +    }
 +
++    fn check_float_value(lit: &str, expected: impl Into<Option<f64>> + Copy) {
++        assert_eq!(FloatNumber { syntax: make::tokens::literal(lit) }.value(), expected.into());
++        assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.float_value(), expected.into());
++    }
++
++    fn check_int_value(lit: &str, expected: impl Into<Option<u128>>) {
++        assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.value(), expected.into());
++    }
++
 +    #[test]
 +    fn test_float_number_suffix() {
 +        check_float_suffix("123.0", None);
 +        check_float_suffix("123f32", "f32");
 +        check_float_suffix("123.0e", None);
 +        check_float_suffix("123.0e4", None);
 +        check_float_suffix("123.0ef32", "f32");
 +        check_float_suffix("123.0E4f32", "f32");
 +        check_float_suffix("1_2_3.0_f32", "f32");
 +    }
 +
 +    #[test]
 +    fn test_int_number_suffix() {
 +        check_int_suffix("123", None);
 +        check_int_suffix("123i32", "i32");
 +        check_int_suffix("1_0_1_l_o_l", "l_o_l");
 +        check_int_suffix("0b11", None);
 +        check_int_suffix("0o11", None);
 +        check_int_suffix("0xff", None);
 +        check_int_suffix("0b11u32", "u32");
 +        check_int_suffix("0o11u32", "u32");
 +        check_int_suffix("0xffu32", "u32");
 +    }
 +
 +    fn check_string_value<'a>(lit: &str, expected: impl Into<Option<&'a str>>) {
 +        assert_eq!(
 +            ast::String { syntax: make::tokens::literal(&format!("\"{}\"", lit)) }
 +                .value()
 +                .as_deref(),
 +            expected.into()
 +        );
 +    }
 +
 +    #[test]
 +    fn test_string_escape() {
 +        check_string_value(r"foobar", "foobar");
 +        check_string_value(r"\foobar", None);
 +        check_string_value(r"\nfoobar", "\nfoobar");
 +        check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\");
 +    }
++
++    #[test]
++    fn test_value_underscores() {
++        check_float_value("3.141592653589793_f64", 3.141592653589793_f64);
++        check_float_value("1__0.__0__f32", 10.0);
++        check_int_value("0b__1_0_", 2);
++        check_int_value("1_1_1_1_1_1", 111111);
++    }
 +}
 +
 +impl ast::Char {
 +    pub fn value(&self) -> Option<char> {
 +        let mut text = self.text();
 +        if text.starts_with('\'') {
 +            text = &text[1..];
 +        } else {
 +            return None;
 +        }
 +        if text.ends_with('\'') {
 +            text = &text[0..text.len() - 1];
 +        }
 +
 +        unescape_char(text).ok()
 +    }
 +}
 +
 +impl ast::Byte {
 +    pub fn value(&self) -> Option<u8> {
 +        let mut text = self.text();
 +        if text.starts_with("b\'") {
 +            text = &text[2..];
 +        } else {
 +            return None;
 +        }
 +        if text.ends_with('\'') {
 +            text = &text[0..text.len() - 1];
 +        }
 +
 +        unescape_byte(text).ok()
 +    }
 +}
index 6d2766225103f7b0aa2406a99939031a973b7274,0000000000000000000000000000000000000000..70b54843dbaab5d6f328d18546e8cac979fd25f6
mode 100644,000000..100644
--- /dev/null
@@@ -1,862 -1,0 +1,849 @@@
-                             match kind {
-                                 #(#kinds)|* => true,
-                                 _ => false,
-                             }
 +//! This module generates AST datatype used by rust-analyzer.
 +//!
 +//! Specifically, it generates the `SyntaxKind` enum and a number of newtype
 +//! wrappers around `SyntaxNode` which implement `syntax::AstNode`.
 +
 +use std::{
 +    collections::{BTreeSet, HashSet},
 +    fmt::Write,
 +};
 +
 +use itertools::Itertools;
 +use proc_macro2::{Punct, Spacing};
 +use quote::{format_ident, quote};
 +use ungrammar::{Grammar, Rule};
 +
 +use crate::tests::ast_src::{
 +    AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC,
 +};
 +
 +#[test]
 +fn sourcegen_ast() {
 +    let syntax_kinds = generate_syntax_kinds(KINDS_SRC);
 +    let syntax_kinds_file =
 +        sourcegen::project_root().join("crates/parser/src/syntax_kind/generated.rs");
 +    sourcegen::ensure_file_contents(syntax_kinds_file.as_path(), &syntax_kinds);
 +
 +    let grammar =
 +        include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/rust.ungram")).parse().unwrap();
 +    let ast = lower(&grammar);
 +
 +    let ast_tokens = generate_tokens(&ast);
 +    let ast_tokens_file =
 +        sourcegen::project_root().join("crates/syntax/src/ast/generated/tokens.rs");
 +    sourcegen::ensure_file_contents(ast_tokens_file.as_path(), &ast_tokens);
 +
 +    let ast_nodes = generate_nodes(KINDS_SRC, &ast);
 +    let ast_nodes_file = sourcegen::project_root().join("crates/syntax/src/ast/generated/nodes.rs");
 +    sourcegen::ensure_file_contents(ast_nodes_file.as_path(), &ast_nodes);
 +}
 +
 +fn generate_tokens(grammar: &AstSrc) -> String {
 +    let tokens = grammar.tokens.iter().map(|token| {
 +        let name = format_ident!("{}", token);
 +        let kind = format_ident!("{}", to_upper_snake_case(token));
 +        quote! {
 +            #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +            pub struct #name {
 +                pub(crate) syntax: SyntaxToken,
 +            }
 +            impl std::fmt::Display for #name {
 +                fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +                    std::fmt::Display::fmt(&self.syntax, f)
 +                }
 +            }
 +            impl AstToken for #name {
 +                fn can_cast(kind: SyntaxKind) -> bool { kind == #kind }
 +                fn cast(syntax: SyntaxToken) -> Option<Self> {
 +                    if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
 +                }
 +                fn syntax(&self) -> &SyntaxToken { &self.syntax }
 +            }
 +        }
 +    });
 +
 +    sourcegen::add_preamble(
 +        "sourcegen_ast",
 +        sourcegen::reformat(
 +            quote! {
 +                use crate::{SyntaxKind::{self, *}, SyntaxToken, ast::AstToken};
 +                #(#tokens)*
 +            }
 +            .to_string(),
 +        ),
 +    )
 +    .replace("#[derive", "\n#[derive")
 +}
 +
 +fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
 +    let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
 +        .nodes
 +        .iter()
 +        .map(|node| {
 +            let name = format_ident!("{}", node.name);
 +            let kind = format_ident!("{}", to_upper_snake_case(&node.name));
 +            let traits = node
 +                .traits
 +                .iter()
 +                .filter(|trait_name| {
 +                    // Loops have two expressions so this might collide, therefor manual impl it
 +                    node.name != "ForExpr" && node.name != "WhileExpr"
 +                        || trait_name.as_str() != "HasLoopBody"
 +                })
 +                .map(|trait_name| {
 +                    let trait_name = format_ident!("{}", trait_name);
 +                    quote!(impl ast::#trait_name for #name {})
 +                });
 +
 +            let methods = node.fields.iter().map(|field| {
 +                let method_name = field.method_name();
 +                let ty = field.ty();
 +
 +                if field.is_many() {
 +                    quote! {
 +                        pub fn #method_name(&self) -> AstChildren<#ty> {
 +                            support::children(&self.syntax)
 +                        }
 +                    }
 +                } else if let Some(token_kind) = field.token_kind() {
 +                    quote! {
 +                        pub fn #method_name(&self) -> Option<#ty> {
 +                            support::token(&self.syntax, #token_kind)
 +                        }
 +                    }
 +                } else {
 +                    quote! {
 +                        pub fn #method_name(&self) -> Option<#ty> {
 +                            support::child(&self.syntax)
 +                        }
 +                    }
 +                }
 +            });
 +            (
 +                quote! {
 +                    #[pretty_doc_comment_placeholder_workaround]
 +                    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +                    pub struct #name {
 +                        pub(crate) syntax: SyntaxNode,
 +                    }
 +
 +                    #(#traits)*
 +
 +                    impl #name {
 +                        #(#methods)*
 +                    }
 +                },
 +                quote! {
 +                    impl AstNode for #name {
 +                        fn can_cast(kind: SyntaxKind) -> bool {
 +                            kind == #kind
 +                        }
 +                        fn cast(syntax: SyntaxNode) -> Option<Self> {
 +                            if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
 +                        }
 +                        fn syntax(&self) -> &SyntaxNode { &self.syntax }
 +                    }
 +                },
 +            )
 +        })
 +        .unzip();
 +
 +    let (enum_defs, enum_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
 +        .enums
 +        .iter()
 +        .map(|en| {
 +            let variants: Vec<_> = en.variants.iter().map(|var| format_ident!("{}", var)).collect();
 +            let name = format_ident!("{}", en.name);
 +            let kinds: Vec<_> = variants
 +                .iter()
 +                .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))
 +                .collect();
 +            let traits = en.traits.iter().map(|trait_name| {
 +                let trait_name = format_ident!("{}", trait_name);
 +                quote!(impl ast::#trait_name for #name {})
 +            });
 +
 +            let ast_node = if en.name == "Stmt" {
 +                quote! {}
 +            } else {
 +                quote! {
 +                    impl AstNode for #name {
 +                        fn can_cast(kind: SyntaxKind) -> bool {
-                             match kind {
-                                 #(#kinds)|* => true,
-                                 _ => false,
-                             }
++                            matches!(kind, #(#kinds)|*)
 +                        }
 +                        fn cast(syntax: SyntaxNode) -> Option<Self> {
 +                            let res = match syntax.kind() {
 +                                #(
 +                                #kinds => #name::#variants(#variants { syntax }),
 +                                )*
 +                                _ => return None,
 +                            };
 +                            Some(res)
 +                        }
 +                        fn syntax(&self) -> &SyntaxNode {
 +                            match self {
 +                                #(
 +                                #name::#variants(it) => &it.syntax,
 +                                )*
 +                            }
 +                        }
 +                    }
 +                }
 +            };
 +
 +            (
 +                quote! {
 +                    #[pretty_doc_comment_placeholder_workaround]
 +                    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +                    pub enum #name {
 +                        #(#variants(#variants),)*
 +                    }
 +
 +                    #(#traits)*
 +                },
 +                quote! {
 +                    #(
 +                        impl From<#variants> for #name {
 +                            fn from(node: #variants) -> #name {
 +                                #name::#variants(node)
 +                            }
 +                        }
 +                    )*
 +                    #ast_node
 +                },
 +            )
 +        })
 +        .unzip();
 +
 +    let (any_node_defs, any_node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
 +        .nodes
 +        .iter()
 +        .flat_map(|node| node.traits.iter().map(move |t| (t, node)))
 +        .into_group_map()
 +        .into_iter()
 +        .sorted_by_key(|(k, _)| *k)
 +        .map(|(trait_name, nodes)| {
 +            let name = format_ident!("Any{}", trait_name);
 +            let trait_name = format_ident!("{}", trait_name);
 +            let kinds: Vec<_> = nodes
 +                .iter()
 +                .map(|name| format_ident!("{}", to_upper_snake_case(&name.name.to_string())))
 +                .collect();
 +
 +            (
 +                quote! {
 +                    #[pretty_doc_comment_placeholder_workaround]
 +                    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 +                    pub struct #name {
 +                        pub(crate) syntax: SyntaxNode,
 +                    }
 +                    impl ast::#trait_name for #name {}
 +                },
 +                quote! {
 +                    impl #name {
 +                        #[inline]
 +                        pub fn new<T: ast::#trait_name>(node: T) -> #name {
 +                            #name {
 +                                syntax: node.syntax().clone()
 +                            }
 +                        }
 +                    }
 +                    impl AstNode for #name {
 +                        fn can_cast(kind: SyntaxKind) -> bool {
-                 match self {
-                     #(#all_keywords)|* => true,
-                     _ => false,
-                 }
++                            matches!(kind, #(#kinds)|*)
 +                        }
 +                        fn cast(syntax: SyntaxNode) -> Option<Self> {
 +                            Self::can_cast(syntax.kind()).then(|| #name { syntax })
 +                        }
 +                        fn syntax(&self) -> &SyntaxNode {
 +                            &self.syntax
 +                        }
 +                    }
 +                },
 +            )
 +        })
 +        .unzip();
 +
 +    let enum_names = grammar.enums.iter().map(|it| &it.name);
 +    let node_names = grammar.nodes.iter().map(|it| &it.name);
 +
 +    let display_impls =
 +        enum_names.chain(node_names.clone()).map(|it| format_ident!("{}", it)).map(|name| {
 +            quote! {
 +                impl std::fmt::Display for #name {
 +                    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +                        std::fmt::Display::fmt(self.syntax(), f)
 +                    }
 +                }
 +            }
 +        });
 +
 +    let defined_nodes: HashSet<_> = node_names.collect();
 +
 +    for node in kinds
 +        .nodes
 +        .iter()
 +        .map(|kind| to_pascal_case(kind))
 +        .filter(|name| !defined_nodes.iter().any(|&it| it == name))
 +    {
 +        drop(node)
 +        // FIXME: restore this
 +        // eprintln!("Warning: node {} not defined in ast source", node);
 +    }
 +
 +    let ast = quote! {
 +        #![allow(non_snake_case)]
 +        use crate::{
 +            SyntaxNode, SyntaxToken, SyntaxKind::{self, *},
 +            ast::{self, AstNode, AstChildren, support},
 +            T,
 +        };
 +
 +        #(#node_defs)*
 +        #(#enum_defs)*
 +        #(#any_node_defs)*
 +        #(#node_boilerplate_impls)*
 +        #(#enum_boilerplate_impls)*
 +        #(#any_node_boilerplate_impls)*
 +        #(#display_impls)*
 +    };
 +
 +    let ast = ast.to_string().replace("T ! [", "T![");
 +
 +    let mut res = String::with_capacity(ast.len() * 2);
 +
 +    let mut docs =
 +        grammar.nodes.iter().map(|it| &it.doc).chain(grammar.enums.iter().map(|it| &it.doc));
 +
 +    for chunk in ast.split("# [pretty_doc_comment_placeholder_workaround] ") {
 +        res.push_str(chunk);
 +        if let Some(doc) = docs.next() {
 +            write_doc_comment(doc, &mut res);
 +        }
 +    }
 +
 +    let res = sourcegen::add_preamble("sourcegen_ast", sourcegen::reformat(res));
 +    res.replace("#[derive", "\n#[derive")
 +}
 +
 +fn write_doc_comment(contents: &[String], dest: &mut String) {
 +    for line in contents {
 +        writeln!(dest, "///{}", line).unwrap();
 +    }
 +}
 +
 +fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> String {
 +    let (single_byte_tokens_values, single_byte_tokens): (Vec<_>, Vec<_>) = grammar
 +        .punct
 +        .iter()
 +        .filter(|(token, _name)| token.len() == 1)
 +        .map(|(token, name)| (token.chars().next().unwrap(), format_ident!("{}", name)))
 +        .unzip();
 +
 +    let punctuation_values = grammar.punct.iter().map(|(token, _name)| {
 +        if "{}[]()".contains(token) {
 +            let c = token.chars().next().unwrap();
 +            quote! { #c }
 +        } else {
 +            let cs = token.chars().map(|c| Punct::new(c, Spacing::Joint));
 +            quote! { #(#cs)* }
 +        }
 +    });
 +    let punctuation =
 +        grammar.punct.iter().map(|(_token, name)| format_ident!("{}", name)).collect::<Vec<_>>();
 +
 +    let x = |&name| match name {
 +        "Self" => format_ident!("SELF_TYPE_KW"),
 +        name => format_ident!("{}_KW", to_upper_snake_case(name)),
 +    };
 +    let full_keywords_values = grammar.keywords;
 +    let full_keywords = full_keywords_values.iter().map(x);
 +
 +    let contextual_keywords_values = &grammar.contextual_keywords;
 +    let contextual_keywords = contextual_keywords_values.iter().map(x);
 +
 +    let all_keywords_values = grammar
 +        .keywords
 +        .iter()
 +        .chain(grammar.contextual_keywords.iter())
 +        .copied()
 +        .collect::<Vec<_>>();
 +    let all_keywords_idents = all_keywords_values.iter().map(|kw| format_ident!("{}", kw));
 +    let all_keywords = all_keywords_values.iter().map(x).collect::<Vec<_>>();
 +
 +    let literals =
 +        grammar.literals.iter().map(|name| format_ident!("{}", name)).collect::<Vec<_>>();
 +
 +    let tokens = grammar.tokens.iter().map(|name| format_ident!("{}", name)).collect::<Vec<_>>();
 +
 +    let nodes = grammar.nodes.iter().map(|name| format_ident!("{}", name)).collect::<Vec<_>>();
 +
 +    let ast = quote! {
 +        #![allow(bad_style, missing_docs, unreachable_pub)]
 +        /// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`.
 +        #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 +        #[repr(u16)]
 +        pub enum SyntaxKind {
 +            // Technical SyntaxKinds: they appear temporally during parsing,
 +            // but never end up in the final tree
 +            #[doc(hidden)]
 +            TOMBSTONE,
 +            #[doc(hidden)]
 +            EOF,
 +            #(#punctuation,)*
 +            #(#all_keywords,)*
 +            #(#literals,)*
 +            #(#tokens,)*
 +            #(#nodes,)*
 +
 +            // Technical kind so that we can cast from u16 safely
 +            #[doc(hidden)]
 +            __LAST,
 +        }
 +        use self::SyntaxKind::*;
 +
 +        impl SyntaxKind {
 +            pub fn is_keyword(self) -> bool {
-                 match self {
-                     #(#punctuation)|* => true,
-                     _ => false,
-                 }
++                matches!(self, #(#all_keywords)|*)
 +            }
 +
 +            pub fn is_punct(self) -> bool {
-                 match self {
-                     #(#literals)|* => true,
-                     _ => false,
-                 }
++
++                matches!(self, #(#punctuation)|*)
++
 +            }
 +
 +            pub fn is_literal(self) -> bool {
++                matches!(self, #(#literals)|*)
 +            }
 +
 +            pub fn from_keyword(ident: &str) -> Option<SyntaxKind> {
 +                let kw = match ident {
 +                    #(#full_keywords_values => #full_keywords,)*
 +                    _ => return None,
 +                };
 +                Some(kw)
 +            }
 +
 +            pub fn from_contextual_keyword(ident: &str) -> Option<SyntaxKind> {
 +                let kw = match ident {
 +                    #(#contextual_keywords_values => #contextual_keywords,)*
 +                    _ => return None,
 +                };
 +                Some(kw)
 +            }
 +
 +            pub fn from_char(c: char) -> Option<SyntaxKind> {
 +                let tok = match c {
 +                    #(#single_byte_tokens_values => #single_byte_tokens,)*
 +                    _ => return None,
 +                };
 +                Some(tok)
 +            }
 +        }
 +
 +        #[macro_export]
 +        macro_rules! T {
 +            #([#punctuation_values] => { $crate::SyntaxKind::#punctuation };)*
 +            #([#all_keywords_idents] => { $crate::SyntaxKind::#all_keywords };)*
 +            [lifetime_ident] => { $crate::SyntaxKind::LIFETIME_IDENT };
 +            [ident] => { $crate::SyntaxKind::IDENT };
 +            [shebang] => { $crate::SyntaxKind::SHEBANG };
 +        }
 +        pub use T;
 +    };
 +
 +    sourcegen::add_preamble("sourcegen_ast", sourcegen::reformat(ast.to_string()))
 +}
 +
 +fn to_upper_snake_case(s: &str) -> String {
 +    let mut buf = String::with_capacity(s.len());
 +    let mut prev = false;
 +    for c in s.chars() {
 +        if c.is_ascii_uppercase() && prev {
 +            buf.push('_')
 +        }
 +        prev = true;
 +
 +        buf.push(c.to_ascii_uppercase());
 +    }
 +    buf
 +}
 +
 +fn to_lower_snake_case(s: &str) -> String {
 +    let mut buf = String::with_capacity(s.len());
 +    let mut prev = false;
 +    for c in s.chars() {
 +        if c.is_ascii_uppercase() && prev {
 +            buf.push('_')
 +        }
 +        prev = true;
 +
 +        buf.push(c.to_ascii_lowercase());
 +    }
 +    buf
 +}
 +
 +fn to_pascal_case(s: &str) -> String {
 +    let mut buf = String::with_capacity(s.len());
 +    let mut prev_is_underscore = true;
 +    for c in s.chars() {
 +        if c == '_' {
 +            prev_is_underscore = true;
 +        } else if prev_is_underscore {
 +            buf.push(c.to_ascii_uppercase());
 +            prev_is_underscore = false;
 +        } else {
 +            buf.push(c.to_ascii_lowercase());
 +        }
 +    }
 +    buf
 +}
 +
 +fn pluralize(s: &str) -> String {
 +    format!("{}s", s)
 +}
 +
 +impl Field {
 +    fn is_many(&self) -> bool {
 +        matches!(self, Field::Node { cardinality: Cardinality::Many, .. })
 +    }
 +    fn token_kind(&self) -> Option<proc_macro2::TokenStream> {
 +        match self {
 +            Field::Token(token) => {
 +                let token: proc_macro2::TokenStream = token.parse().unwrap();
 +                Some(quote! { T![#token] })
 +            }
 +            _ => None,
 +        }
 +    }
 +    fn method_name(&self) -> proc_macro2::Ident {
 +        match self {
 +            Field::Token(name) => {
 +                let name = match name.as_str() {
 +                    ";" => "semicolon",
 +                    "->" => "thin_arrow",
 +                    "'{'" => "l_curly",
 +                    "'}'" => "r_curly",
 +                    "'('" => "l_paren",
 +                    "')'" => "r_paren",
 +                    "'['" => "l_brack",
 +                    "']'" => "r_brack",
 +                    "<" => "l_angle",
 +                    ">" => "r_angle",
 +                    "=" => "eq",
 +                    "!" => "excl",
 +                    "*" => "star",
 +                    "&" => "amp",
 +                    "_" => "underscore",
 +                    "." => "dot",
 +                    ".." => "dotdot",
 +                    "..." => "dotdotdot",
 +                    "..=" => "dotdoteq",
 +                    "=>" => "fat_arrow",
 +                    "@" => "at",
 +                    ":" => "colon",
 +                    "::" => "coloncolon",
 +                    "#" => "pound",
 +                    "?" => "question_mark",
 +                    "," => "comma",
 +                    "|" => "pipe",
 +                    "~" => "tilde",
 +                    _ => name,
 +                };
 +                format_ident!("{}_token", name)
 +            }
 +            Field::Node { name, .. } => {
 +                if name == "type" {
 +                    format_ident!("ty")
 +                } else {
 +                    format_ident!("{}", name)
 +                }
 +            }
 +        }
 +    }
 +    fn ty(&self) -> proc_macro2::Ident {
 +        match self {
 +            Field::Token(_) => format_ident!("SyntaxToken"),
 +            Field::Node { ty, .. } => format_ident!("{}", ty),
 +        }
 +    }
 +}
 +
 +fn lower(grammar: &Grammar) -> AstSrc {
 +    let mut res = AstSrc {
 +        tokens: "Whitespace Comment String ByteString IntNumber FloatNumber Char Byte Ident"
 +            .split_ascii_whitespace()
 +            .map(|it| it.to_string())
 +            .collect::<Vec<_>>(),
 +        ..Default::default()
 +    };
 +
 +    let nodes = grammar.iter().collect::<Vec<_>>();
 +
 +    for &node in &nodes {
 +        let name = grammar[node].name.clone();
 +        let rule = &grammar[node].rule;
 +        match lower_enum(grammar, rule) {
 +            Some(variants) => {
 +                let enum_src = AstEnumSrc { doc: Vec::new(), name, traits: Vec::new(), variants };
 +                res.enums.push(enum_src);
 +            }
 +            None => {
 +                let mut fields = Vec::new();
 +                lower_rule(&mut fields, grammar, None, rule);
 +                res.nodes.push(AstNodeSrc { doc: Vec::new(), name, traits: Vec::new(), fields });
 +            }
 +        }
 +    }
 +
 +    deduplicate_fields(&mut res);
 +    extract_enums(&mut res);
 +    extract_struct_traits(&mut res);
 +    extract_enum_traits(&mut res);
 +    res
 +}
 +
 +fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
 +    let alternatives = match rule {
 +        Rule::Alt(it) => it,
 +        _ => return None,
 +    };
 +    let mut variants = Vec::new();
 +    for alternative in alternatives {
 +        match alternative {
 +            Rule::Node(it) => variants.push(grammar[*it].name.clone()),
 +            Rule::Token(it) if grammar[*it].name == ";" => (),
 +            _ => return None,
 +        }
 +    }
 +    Some(variants)
 +}
 +
 +fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, rule: &Rule) {
 +    if lower_comma_list(acc, grammar, label, rule) {
 +        return;
 +    }
 +
 +    match rule {
 +        Rule::Node(node) => {
 +            let ty = grammar[*node].name.clone();
 +            let name = label.cloned().unwrap_or_else(|| to_lower_snake_case(&ty));
 +            let field = Field::Node { name, ty, cardinality: Cardinality::Optional };
 +            acc.push(field);
 +        }
 +        Rule::Token(token) => {
 +            assert!(label.is_none());
 +            let mut name = grammar[*token].name.clone();
 +            if name != "int_number" && name != "string" {
 +                if "[]{}()".contains(&name) {
 +                    name = format!("'{}'", name);
 +                }
 +                let field = Field::Token(name);
 +                acc.push(field);
 +            }
 +        }
 +        Rule::Rep(inner) => {
 +            if let Rule::Node(node) = &**inner {
 +                let ty = grammar[*node].name.clone();
 +                let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
 +                let field = Field::Node { name, ty, cardinality: Cardinality::Many };
 +                acc.push(field);
 +                return;
 +            }
 +            panic!("unhandled rule: {:?}", rule)
 +        }
 +        Rule::Labeled { label: l, rule } => {
 +            assert!(label.is_none());
 +            let manually_implemented = matches!(
 +                l.as_str(),
 +                "lhs"
 +                    | "rhs"
 +                    | "then_branch"
 +                    | "else_branch"
 +                    | "start"
 +                    | "end"
 +                    | "op"
 +                    | "index"
 +                    | "base"
 +                    | "value"
 +                    | "trait"
 +                    | "self_ty"
 +                    | "iterable"
 +                    | "condition"
 +            );
 +            if manually_implemented {
 +                return;
 +            }
 +            lower_rule(acc, grammar, Some(l), rule);
 +        }
 +        Rule::Seq(rules) | Rule::Alt(rules) => {
 +            for rule in rules {
 +                lower_rule(acc, grammar, label, rule)
 +            }
 +        }
 +        Rule::Opt(rule) => lower_rule(acc, grammar, label, rule),
 +    }
 +}
 +
 +// (T (',' T)* ','?)
 +fn lower_comma_list(
 +    acc: &mut Vec<Field>,
 +    grammar: &Grammar,
 +    label: Option<&String>,
 +    rule: &Rule,
 +) -> bool {
 +    let rule = match rule {
 +        Rule::Seq(it) => it,
 +        _ => return false,
 +    };
 +    let (node, repeat, trailing_comma) = match rule.as_slice() {
 +        [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_comma)] => {
 +            (node, repeat, trailing_comma)
 +        }
 +        _ => return false,
 +    };
 +    let repeat = match &**repeat {
 +        Rule::Seq(it) => it,
 +        _ => return false,
 +    };
 +    match repeat.as_slice() {
 +        [comma, Rule::Node(n)] if comma == &**trailing_comma && n == node => (),
 +        _ => return false,
 +    }
 +    let ty = grammar[*node].name.clone();
 +    let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
 +    let field = Field::Node { name, ty, cardinality: Cardinality::Many };
 +    acc.push(field);
 +    true
 +}
 +
 +fn deduplicate_fields(ast: &mut AstSrc) {
 +    for node in &mut ast.nodes {
 +        let mut i = 0;
 +        'outer: while i < node.fields.len() {
 +            for j in 0..i {
 +                let f1 = &node.fields[i];
 +                let f2 = &node.fields[j];
 +                if f1 == f2 {
 +                    node.fields.remove(i);
 +                    continue 'outer;
 +                }
 +            }
 +            i += 1;
 +        }
 +    }
 +}
 +
 +fn extract_enums(ast: &mut AstSrc) {
 +    for node in &mut ast.nodes {
 +        for enm in &ast.enums {
 +            let mut to_remove = Vec::new();
 +            for (i, field) in node.fields.iter().enumerate() {
 +                let ty = field.ty().to_string();
 +                if enm.variants.iter().any(|it| it == &ty) {
 +                    to_remove.push(i);
 +                }
 +            }
 +            if to_remove.len() == enm.variants.len() {
 +                node.remove_field(to_remove);
 +                let ty = enm.name.clone();
 +                let name = to_lower_snake_case(&ty);
 +                node.fields.push(Field::Node { name, ty, cardinality: Cardinality::Optional });
 +            }
 +        }
 +    }
 +}
 +
 +fn extract_struct_traits(ast: &mut AstSrc) {
 +    let traits: &[(&str, &[&str])] = &[
 +        ("HasAttrs", &["attrs"]),
 +        ("HasName", &["name"]),
 +        ("HasVisibility", &["visibility"]),
 +        ("HasGenericParams", &["generic_param_list", "where_clause"]),
 +        ("HasTypeBounds", &["type_bound_list", "colon_token"]),
 +        ("HasModuleItem", &["items"]),
 +        ("HasLoopBody", &["label", "loop_body"]),
 +        ("HasArgList", &["arg_list"]),
 +    ];
 +
 +    for node in &mut ast.nodes {
 +        for (name, methods) in traits {
 +            extract_struct_trait(node, name, methods);
 +        }
 +    }
 +
 +    let nodes_with_doc_comments = [
 +        "SourceFile",
 +        "Fn",
 +        "Struct",
 +        "Union",
 +        "RecordField",
 +        "TupleField",
 +        "Enum",
 +        "Variant",
 +        "Trait",
 +        "Module",
 +        "Static",
 +        "Const",
 +        "TypeAlias",
 +        "Impl",
 +        "ExternBlock",
 +        "ExternCrate",
 +        "MacroCall",
 +        "MacroRules",
 +        "MacroDef",
 +        "Use",
 +    ];
 +
 +    for node in &mut ast.nodes {
 +        if nodes_with_doc_comments.contains(&&*node.name) {
 +            node.traits.push("HasDocComments".into());
 +        }
 +    }
 +}
 +
 +fn extract_struct_trait(node: &mut AstNodeSrc, trait_name: &str, methods: &[&str]) {
 +    let mut to_remove = Vec::new();
 +    for (i, field) in node.fields.iter().enumerate() {
 +        let method_name = field.method_name().to_string();
 +        if methods.iter().any(|&it| it == method_name) {
 +            to_remove.push(i);
 +        }
 +    }
 +    if to_remove.len() == methods.len() {
 +        node.traits.push(trait_name.to_string());
 +        node.remove_field(to_remove);
 +    }
 +}
 +
 +fn extract_enum_traits(ast: &mut AstSrc) {
 +    for enm in &mut ast.enums {
 +        if enm.name == "Stmt" {
 +            continue;
 +        }
 +        let nodes = &ast.nodes;
 +        let mut variant_traits = enm
 +            .variants
 +            .iter()
 +            .map(|var| nodes.iter().find(|it| &it.name == var).unwrap())
 +            .map(|node| node.traits.iter().cloned().collect::<BTreeSet<_>>());
 +
 +        let mut enum_traits = match variant_traits.next() {
 +            Some(it) => it,
 +            None => continue,
 +        };
 +        for traits in variant_traits {
 +            enum_traits = enum_traits.intersection(&traits).cloned().collect();
 +        }
 +        enm.traits = enum_traits.into_iter().collect();
 +    }
 +}
 +
 +impl AstNodeSrc {
 +    fn remove_field(&mut self, to_remove: Vec<usize>) {
 +        to_remove.into_iter().rev().for_each(|idx| {
 +            self.fields.remove(idx);
 +        });
 +    }
 +}
index 50e8d06b66049795bedc69b320bad4be62d7a811,0000000000000000000000000000000000000000..ccaaf3991769ec737833da7eb0bec769d36a501a
mode 100644,000000..100644
--- /dev/null
@@@ -1,375 -1,0 +1,412 @@@
 +//! Yet another index-based arena.
 +
 +#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 +#![warn(missing_docs)]
 +
 +use std::{
 +    fmt,
 +    hash::{Hash, Hasher},
 +    marker::PhantomData,
 +    ops::{Index, IndexMut, Range, RangeInclusive},
 +};
 +
 +mod map;
 +pub use map::{ArenaMap, Entry, OccupiedEntry, VacantEntry};
 +
 +/// The raw index of a value in an arena.
 +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 +pub struct RawIdx(u32);
 +
 +impl From<RawIdx> for u32 {
 +    fn from(raw: RawIdx) -> u32 {
 +        raw.0
 +    }
 +}
 +
 +impl From<u32> for RawIdx {
 +    fn from(idx: u32) -> RawIdx {
 +        RawIdx(idx)
 +    }
 +}
 +
 +impl fmt::Debug for RawIdx {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        self.0.fmt(f)
 +    }
 +}
 +
 +impl fmt::Display for RawIdx {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        self.0.fmt(f)
 +    }
 +}
 +
 +/// The index of a value allocated in an arena that holds `T`s.
 +pub struct Idx<T> {
 +    raw: RawIdx,
 +    _ty: PhantomData<fn() -> T>,
 +}
 +
 +impl<T> Clone for Idx<T> {
 +    fn clone(&self) -> Self {
 +        *self
 +    }
 +}
 +impl<T> Copy for Idx<T> {}
 +
 +impl<T> PartialEq for Idx<T> {
 +    fn eq(&self, other: &Idx<T>) -> bool {
 +        self.raw == other.raw
 +    }
 +}
 +impl<T> Eq for Idx<T> {}
 +
 +impl<T> Hash for Idx<T> {
 +    fn hash<H: Hasher>(&self, state: &mut H) {
 +        self.raw.hash(state);
 +    }
 +}
 +
 +impl<T> fmt::Debug for Idx<T> {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        let mut type_name = std::any::type_name::<T>();
 +        if let Some(idx) = type_name.rfind(':') {
 +            type_name = &type_name[idx + 1..];
 +        }
 +        write!(f, "Idx::<{}>({})", type_name, self.raw)
 +    }
 +}
 +
 +impl<T> Idx<T> {
 +    /// Creates a new index from a [`RawIdx`].
 +    pub fn from_raw(raw: RawIdx) -> Self {
 +        Idx { raw, _ty: PhantomData }
 +    }
 +
 +    /// Converts this index into the underlying [`RawIdx`].
 +    pub fn into_raw(self) -> RawIdx {
 +        self.raw
 +    }
 +}
 +
 +/// A range of densely allocated arena values.
 +pub struct IdxRange<T> {
 +    range: Range<u32>,
 +    _p: PhantomData<T>,
 +}
 +
 +impl<T> IdxRange<T> {
 +    /// Creates a new index range
 +    /// inclusive of the start value and exclusive of the end value.
 +    ///
 +    /// ```
 +    /// let mut arena = la_arena::Arena::new();
 +    /// let a = arena.alloc("a");
 +    /// let b = arena.alloc("b");
 +    /// let c = arena.alloc("c");
 +    /// let d = arena.alloc("d");
 +    ///
 +    /// let range = la_arena::IdxRange::new(b..d);
 +    /// assert_eq!(&arena[range], &["b", "c"]);
 +    /// ```
 +    pub fn new(range: Range<Idx<T>>) -> Self {
 +        Self { range: range.start.into_raw().into()..range.end.into_raw().into(), _p: PhantomData }
 +    }
 +
 +    /// Creates a new index range
 +    /// inclusive of the start value and end value.
 +    ///
 +    /// ```
 +    /// let mut arena = la_arena::Arena::new();
 +    /// let foo = arena.alloc("foo");
 +    /// let bar = arena.alloc("bar");
 +    /// let baz = arena.alloc("baz");
 +    ///
 +    /// let range = la_arena::IdxRange::new_inclusive(foo..=baz);
 +    /// assert_eq!(&arena[range], &["foo", "bar", "baz"]);
 +    ///
 +    /// let range = la_arena::IdxRange::new_inclusive(foo..=foo);
 +    /// assert_eq!(&arena[range], &["foo"]);
 +    /// ```
 +    pub fn new_inclusive(range: RangeInclusive<Idx<T>>) -> Self {
 +        Self {
 +            range: u32::from(range.start().into_raw())..u32::from(range.end().into_raw()) + 1,
 +            _p: PhantomData,
 +        }
 +    }
 +
 +    /// Returns whether the index range is empty.
 +    ///
 +    /// ```
 +    /// let mut arena = la_arena::Arena::new();
 +    /// let one = arena.alloc(1);
 +    /// let two = arena.alloc(2);
 +    ///
 +    /// assert!(la_arena::IdxRange::new(one..one).is_empty());
 +    /// ```
 +    pub fn is_empty(&self) -> bool {
 +        self.range.is_empty()
 +    }
 +}
 +
 +impl<T> Iterator for IdxRange<T> {
 +    type Item = Idx<T>;
 +    fn next(&mut self) -> Option<Self::Item> {
 +        self.range.next().map(|raw| Idx::from_raw(raw.into()))
 +    }
 +}
 +
 +impl<T> DoubleEndedIterator for IdxRange<T> {
 +    fn next_back(&mut self) -> Option<Self::Item> {
 +        self.range.next_back().map(|raw| Idx::from_raw(raw.into()))
 +    }
 +}
 +
 +impl<T> fmt::Debug for IdxRange<T> {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        f.debug_tuple(&format!("IdxRange::<{}>", std::any::type_name::<T>()))
 +            .field(&self.range)
 +            .finish()
 +    }
 +}
 +
 +impl<T> Clone for IdxRange<T> {
 +    fn clone(&self) -> Self {
 +        Self { range: self.range.clone(), _p: PhantomData }
 +    }
 +}
 +
 +impl<T> PartialEq for IdxRange<T> {
 +    fn eq(&self, other: &Self) -> bool {
 +        self.range == other.range
 +    }
 +}
 +
 +impl<T> Eq for IdxRange<T> {}
 +
 +/// Yet another index-based arena.
 +#[derive(Clone, PartialEq, Eq, Hash)]
 +pub struct Arena<T> {
 +    data: Vec<T>,
 +}
 +
 +impl<T: fmt::Debug> fmt::Debug for Arena<T> {
 +    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        fmt.debug_struct("Arena").field("len", &self.len()).field("data", &self.data).finish()
 +    }
 +}
 +
 +impl<T> Arena<T> {
 +    /// Creates a new empty arena.
 +    ///
 +    /// ```
 +    /// let arena: la_arena::Arena<i32> = la_arena::Arena::new();
 +    /// assert!(arena.is_empty());
 +    /// ```
 +    pub const fn new() -> Arena<T> {
 +        Arena { data: Vec::new() }
 +    }
 +
 +    /// Create a new empty arena with specific capacity.
 +    ///
 +    /// ```
 +    /// let arena: la_arena::Arena<i32> = la_arena::Arena::with_capacity(42);
 +    /// assert!(arena.is_empty());
 +    /// ```
 +    pub fn with_capacity(capacity: usize) -> Arena<T> {
 +        Arena { data: Vec::with_capacity(capacity) }
 +    }
 +
 +    /// Empties the arena, removing all contained values.
 +    ///
 +    /// ```
 +    /// let mut arena = la_arena::Arena::new();
 +    ///
 +    /// arena.alloc(1);
 +    /// arena.alloc(2);
 +    /// arena.alloc(3);
 +    /// assert_eq!(arena.len(), 3);
 +    ///
 +    /// arena.clear();
 +    /// assert!(arena.is_empty());
 +    /// ```
 +    pub fn clear(&mut self) {
 +        self.data.clear();
 +    }
 +
 +    /// Returns the length of the arena.
 +    ///
 +    /// ```
 +    /// let mut arena = la_arena::Arena::new();
 +    /// assert_eq!(arena.len(), 0);
 +    ///
 +    /// arena.alloc("foo");
 +    /// assert_eq!(arena.len(), 1);
 +    ///
 +    /// arena.alloc("bar");
 +    /// assert_eq!(arena.len(), 2);
 +    ///
 +    /// arena.alloc("baz");
 +    /// assert_eq!(arena.len(), 3);
 +    /// ```
 +    pub fn len(&self) -> usize {
 +        self.data.len()
 +    }
 +
 +    /// Returns whether the arena contains no elements.
 +    ///
 +    /// ```
 +    /// let mut arena = la_arena::Arena::new();
 +    /// assert!(arena.is_empty());
 +    ///
 +    /// arena.alloc(0.5);
 +    /// assert!(!arena.is_empty());
 +    /// ```
 +    pub fn is_empty(&self) -> bool {
 +        self.data.is_empty()
 +    }
 +
 +    /// Allocates a new value on the arena, returning the value’s index.
 +    ///
 +    /// ```
 +    /// let mut arena = la_arena::Arena::new();
 +    /// let idx = arena.alloc(50);
 +    ///
 +    /// assert_eq!(arena[idx], 50);
 +    /// ```
 +    pub fn alloc(&mut self, value: T) -> Idx<T> {
 +        let idx = self.next_idx();
 +        self.data.push(value);
 +        idx
 +    }
 +
 +    /// Returns an iterator over the arena’s elements.
 +    ///
 +    /// ```
 +    /// let mut arena = la_arena::Arena::new();
 +    /// let idx1 = arena.alloc(20);
 +    /// let idx2 = arena.alloc(40);
 +    /// let idx3 = arena.alloc(60);
 +    ///
 +    /// let mut iterator = arena.iter();
 +    /// assert_eq!(iterator.next(), Some((idx1, &20)));
 +    /// assert_eq!(iterator.next(), Some((idx2, &40)));
 +    /// assert_eq!(iterator.next(), Some((idx3, &60)));
 +    /// ```
 +    pub fn iter(
 +        &self,
 +    ) -> impl Iterator<Item = (Idx<T>, &T)> + ExactSizeIterator + DoubleEndedIterator {
 +        self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawIdx(idx as u32)), value))
 +    }
 +
 +    /// Returns an iterator over the arena’s mutable elements.
 +    ///
 +    /// ```
 +    /// let mut arena = la_arena::Arena::new();
 +    /// let idx1 = arena.alloc(20);
 +    ///
 +    /// assert_eq!(arena[idx1], 20);
 +    ///
 +    /// let mut iterator = arena.iter_mut();
 +    /// *iterator.next().unwrap().1 = 10;
 +    /// drop(iterator);
 +    ///
 +    /// assert_eq!(arena[idx1], 10);
 +    /// ```
 +    pub fn iter_mut(
 +        &mut self,
 +    ) -> impl Iterator<Item = (Idx<T>, &mut T)> + ExactSizeIterator + DoubleEndedIterator {
 +        self.data
 +            .iter_mut()
 +            .enumerate()
 +            .map(|(idx, value)| (Idx::from_raw(RawIdx(idx as u32)), value))
 +    }
 +
++    /// Returns an iterator over the arena’s values.
++    ///
++    /// ```
++    /// let mut arena = la_arena::Arena::new();
++    /// let idx1 = arena.alloc(20);
++    /// let idx2 = arena.alloc(40);
++    /// let idx3 = arena.alloc(60);
++    ///
++    /// let mut iterator = arena.values();
++    /// assert_eq!(iterator.next(), Some(&20));
++    /// assert_eq!(iterator.next(), Some(&40));
++    /// assert_eq!(iterator.next(), Some(&60));
++    /// ```
++    pub fn values(&mut self) -> impl Iterator<Item = &T> + ExactSizeIterator + DoubleEndedIterator {
++        self.data.iter()
++    }
++
++    /// Returns an iterator over the arena’s mutable values.
++    ///
++    /// ```
++    /// let mut arena = la_arena::Arena::new();
++    /// let idx1 = arena.alloc(20);
++    ///
++    /// assert_eq!(arena[idx1], 20);
++    ///
++    /// let mut iterator = arena.values_mut();
++    /// *iterator.next().unwrap() = 10;
++    /// drop(iterator);
++    ///
++    /// assert_eq!(arena[idx1], 10);
++    /// ```
++    pub fn values_mut(
++        &mut self,
++    ) -> impl Iterator<Item = &mut T> + ExactSizeIterator + DoubleEndedIterator {
++        self.data.iter_mut()
++    }
++
 +    /// Reallocates the arena to make it take up as little space as possible.
 +    pub fn shrink_to_fit(&mut self) {
 +        self.data.shrink_to_fit();
 +    }
 +
 +    /// Returns the index of the next value allocated on the arena.
 +    ///
 +    /// This method should remain private to make creating invalid `Idx`s harder.
 +    fn next_idx(&self) -> Idx<T> {
 +        Idx::from_raw(RawIdx(self.data.len() as u32))
 +    }
 +}
 +
 +impl<T> Default for Arena<T> {
 +    fn default() -> Arena<T> {
 +        Arena { data: Vec::new() }
 +    }
 +}
 +
 +impl<T> Index<Idx<T>> for Arena<T> {
 +    type Output = T;
 +    fn index(&self, idx: Idx<T>) -> &T {
 +        let idx = idx.into_raw().0 as usize;
 +        &self.data[idx]
 +    }
 +}
 +
 +impl<T> IndexMut<Idx<T>> for Arena<T> {
 +    fn index_mut(&mut self, idx: Idx<T>) -> &mut T {
 +        let idx = idx.into_raw().0 as usize;
 +        &mut self.data[idx]
 +    }
 +}
 +
 +impl<T> Index<IdxRange<T>> for Arena<T> {
 +    type Output = [T];
 +    fn index(&self, range: IdxRange<T>) -> &[T] {
 +        let start = range.range.start as usize;
 +        let end = range.range.end as usize;
 +        &self.data[start..end]
 +    }
 +}
 +
 +impl<T> FromIterator<T> for Arena<T> {
 +    fn from_iter<I>(iter: I) -> Self
 +    where
 +        I: IntoIterator<Item = T>,
 +    {
 +        Arena { data: Vec::from_iter(iter) }
 +    }
 +}