Repository: rust-lang/rust-analyzer
Pull request #13158 (2022-08-31 16:55:01)

feat: make clicking a closing brace inlay hint go to the opening brace


Patch:
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 1563ee0b14..a70252fa65 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -6,15 +6,15 @@ on:
   pull_request:
   push:
     branches:
-      - auto
-      - try
+    - auto
+    - try
 
 env:
   CARGO_INCREMENTAL: 0
   CARGO_NET_RETRY: 10
   CI: 1
   RUST_BACKTRACE: short
-  RUSTFLAGS: "-D warnings -W unreachable-pub -W bare-trait-objects"
+  RUSTFLAGS: "-D warnings -W unreachable-pub -W rust-2021-compatibility"
   RUSTUP_MAX_RETRIES: 10
 
 jobs:
@@ -31,25 +31,25 @@ jobs:
         os: [ubuntu-latest, windows-latest, macos-latest]
 
     steps:
-      - name: Checkout repository
-        uses: actions/checkout@v3
-        with:
-          ref: ${{ github.event.pull_request.head.sha }}
-          fetch-depth: 20
+    - name: Checkout repository
+      uses: actions/checkout@v3
+      with:
+        ref: ${{ github.event.pull_request.head.sha }}
+        fetch-depth: 20
 
-      - name: Install Rust toolchain
-        run: |
-          rustup update --no-self-update stable
-          rustup component add rustfmt rust-src
+    - name: Install Rust toolchain
+      run: |
+        rustup update --no-self-update stable
+        rustup component add rustfmt rust-src
 
-      - name: Cache Dependencies
-        uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
+    - name: Cache Dependencies
+      uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
 
-      - name: Compile
-        run: cargo test --no-run --locked
+    - name: Compile
+      run: cargo test --no-run --locked
 
-      - name: Test
-        run: cargo test -- --nocapture --quiet
+    - name: Test
+      run: cargo test -- --nocapture --quiet
 
   # Weird targets to catch non-portable code
   rust-cross:
@@ -64,25 +64,25 @@ jobs:
       targets_ide: "wasm32-unknown-unknown"
 
     steps:
-      - name: Checkout repository
-        uses: actions/checkout@v3
-
-      - name: Install Rust toolchain
-        run: |
-          rustup update --no-self-update stable
-          rustup target add ${{ env.targets }} ${{ env.targets_ide }}
-
-      - name: Cache Dependencies
-        uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
-
-      - name: Check
-        run: |
-          for target in ${{ env.targets }}; do
-            cargo check --target=$target --all-targets
-          done
-          for target in ${{ env.targets_ide }}; do
-            cargo check -p ide --target=$target --all-targets
-          done
+    - 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'
@@ -95,47 +95,47 @@ jobs:
     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
+    - 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
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 303a10615b..b2e5db6f68 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -248,7 +248,7 @@ jobs:
         if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
         working-directory: ./editors/code
         # token from https://dev.azure.com/rust-analyzer/
-        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
+        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
 
       - name: Publish Extension (Code Marketplace, nightly)
         if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
@@ -258,4 +258,4 @@ jobs:
       - 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
+        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs
index 22f5fb9926..1d818d9626 100644
--- a/crates/hir-def/src/body.rs
+++ b/crates/hir-def/src/body.rs
@@ -250,10 +250,6 @@ 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
@@ -268,18 +264,18 @@ pub type FieldSource = InFile<FieldPtr>;
 #[derive(Default, Debug, Eq, PartialEq)]
 pub struct BodySourceMap {
     expr_map: FxHashMap<ExprSource, ExprId>,
-    expr_map_back: ArenaMap<ExprId, ExprSource>,
+    expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
 
     pat_map: FxHashMap<PatSource, PatId>,
-    pat_map_back: ArenaMap<PatId, PatSource>,
+    pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>,
 
     label_map: FxHashMap<LabelSource, LabelId>,
     label_map_back: ArenaMap<LabelId, LabelSource>,
 
     /// We don't create explicit nodes for record fields (`S { record_field: 92 }`).
     /// Instead, we use id of expression (`92`) to identify the field.
-    field_map: FxHashMap<FieldSource, ExprId>,
-    field_map_back: FxHashMap<ExprId, FieldSource>,
+    field_map: FxHashMap<InFile<AstPtr<ast::RecordExprField>>, ExprId>,
+    field_map_back: FxHashMap<ExprId, InFile<AstPtr<ast::RecordExprField>>>,
 
     expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
 
@@ -424,7 +420,7 @@ impl Index<LabelId> for Body {
 // Perhaps `expr_syntax` and `expr_id`?
 impl BodySourceMap {
     pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
-        self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax)
+        self.expr_map_back[expr].clone()
     }
 
     pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
@@ -438,7 +434,7 @@ impl BodySourceMap {
     }
 
     pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
-        self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
+        self.pat_map_back[pat].clone()
     }
 
     pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
@@ -460,10 +456,9 @@ impl BodySourceMap {
         self.label_map.get(&src).cloned()
     }
 
-    pub fn field_syntax(&self, expr: ExprId) -> FieldSource {
+    pub fn field_syntax(&self, expr: ExprId) -> InFile<AstPtr<ast::RecordExprField>> {
         self.field_map_back[&expr].clone()
     }
-
     pub fn node_field(&self, node: InFile<&ast::RecordExprField>) -> Option<ExprId> {
         let src = node.map(AstPtr::new);
         self.field_map.get(&src).cloned()
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index 3b3297f781..8ebac5cb1c 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -24,7 +24,7 @@ use syntax::{
 
 use crate::{
     adt::StructKind,
-    body::{Body, BodySourceMap, Expander, ExprPtr, LabelPtr, LabelSource, PatPtr},
+    body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
     body::{BodyDiagnostic, ExprSource, PatSource},
     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
     db::DefDatabase,
@@ -150,21 +150,21 @@ impl ExprCollector<'_> {
         LowerCtx::new(self.db, self.expander.current_file_id)
     }
 
-    fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
+    fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
         let src = self.expander.to_source(ptr);
-        let id = self.make_expr(expr, src.clone());
+        let id = self.make_expr(expr, Ok(src.clone()));
         self.source_map.expr_map.insert(src, id);
         id
     }
     // desugared exprs don't have ptr, that's wrong and should be fixed
     // somehow.
     fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
-        self.body.exprs.alloc(expr)
+        self.make_expr(expr, Err(SyntheticSyntax))
     }
     fn missing_expr(&mut self) -> ExprId {
         self.alloc_expr_desugared(Expr::Missing)
     }
-    fn make_expr(&mut self, expr: Expr, src: ExprSource) -> ExprId {
+    fn make_expr(&mut self, expr: Expr, src: Result<ExprSource, SyntheticSyntax>) -> ExprId {
         let id = self.body.exprs.alloc(expr);
         self.source_map.expr_map_back.insert(id, src);
         id
@@ -172,20 +172,20 @@ impl ExprCollector<'_> {
 
     fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
         let src = self.expander.to_source(ptr);
-        let id = self.make_pat(pat, src.clone());
+        let id = self.make_pat(pat, Ok(src.clone()));
         self.source_map.pat_map.insert(src, id);
         id
     }
     fn missing_pat(&mut self) -> PatId {
-        self.body.pats.alloc(Pat::Missing)
+        self.make_pat(Pat::Missing, Err(SyntheticSyntax))
     }
-    fn make_pat(&mut self, pat: Pat, src: PatSource) -> PatId {
+    fn make_pat(&mut self, pat: Pat, src: Result<PatSource, SyntheticSyntax>) -> PatId {
         let id = self.body.pats.alloc(pat);
         self.source_map.pat_map_back.insert(id, src);
         id
     }
 
-    fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId {
+    fn alloc_label(&mut self, label: Label, ptr: AstPtr<ast::Label>) -> LabelId {
         let src = self.expander.to_source(ptr);
         let id = self.make_label(label, src.clone());
         self.source_map.label_map.insert(src, id);
diff --git a/crates/hir-def/src/body/scope.rs b/crates/hir-def/src/body/scope.rs
index 45f64ebb06..9b28e38029 100644
--- a/crates/hir-def/src/body/scope.rs
+++ b/crates/hir-def/src/body/scope.rs
@@ -47,9 +47,16 @@ pub struct ScopeData {
 impl ExprScopes {
     pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> {
         let body = db.body(def);
-        let mut scopes = ExprScopes::new(&*body);
-        scopes.shrink_to_fit();
-        Arc::new(scopes)
+        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
     }
 
     pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
@@ -82,17 +89,6 @@ impl ExprScopes {
     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![] })
@@ -142,13 +138,6 @@ impl ExprScopes {
     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(
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 2e392f741b..45f631936d 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -64,7 +64,7 @@ use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId};
 use itertools::Itertools;
 use la_arena::Arena;
 use profile::Count;
-use rustc_hash::{FxHashMap, FxHashSet};
+use rustc_hash::FxHashMap;
 use stdx::format_to;
 use syntax::{ast, SmolStr};
 
@@ -98,11 +98,7 @@ pub struct DefMap {
     /// 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.
@@ -118,8 +114,6 @@ pub struct DefMap {
     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>,
@@ -290,7 +284,6 @@ impl DefMap {
             modules,
             registered_attrs: Vec::new(),
             registered_tools: Vec::new(),
-            unstable_features: FxHashSet::default(),
             diagnostics: Vec::new(),
         }
     }
@@ -321,10 +314,6 @@ impl DefMap {
         &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
     }
@@ -494,7 +483,6 @@ impl DefMap {
             registered_tools,
             fn_proc_macro_mapping,
             derive_helpers_in_scope,
-            unstable_features,
             proc_macro_loading_error: _,
             block: _,
             edition: _,
@@ -512,7 +500,6 @@ impl DefMap {
         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();
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 495bbe4579..8a6bb929c3 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -294,17 +294,6 @@ impl DefCollector<'_> {
                     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 {
@@ -512,9 +501,10 @@ impl DefCollector<'_> {
             Edition::Edition2021 => name![rust_2021],
         };
 
-        let path_kind = match self.def_map.edition {
-            Edition::Edition2015 => PathKind::Plain,
-            _ => PathKind::Abs,
+        let path_kind = if self.def_map.edition == Edition::Edition2015 {
+            PathKind::Plain
+        } else {
+            PathKind::Abs
         };
         let path =
             ModPath::from_segments(path_kind, [krate.clone(), name![prelude], edition].into_iter());
@@ -534,6 +524,7 @@ impl DefCollector<'_> {
             match per_ns.types {
                 Some((ModuleDefId::ModuleId(m), _)) => {
                     self.def_map.prelude = Some(m);
+                    return;
                 }
                 types => {
                     tracing::debug!(
@@ -848,10 +839,7 @@ impl DefCollector<'_> {
                 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 import.is_extern_crate && 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);
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index 8aa5973cac..3163fa0f93 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -31,10 +31,12 @@ pub struct Resolver {
     ///
     /// When using, you generally want to process the scopes in reverse order,
     /// there's `scopes` *method* for that.
+    ///
+    /// Invariant: There exists at least one Scope::ModuleScope at the start of the vec.
     scopes: Vec<Scope>,
-    module_scope: ModuleItemMap,
 }
 
+// FIXME how to store these best
 #[derive(Debug, Clone)]
 struct ModuleItemMap {
     def_map: Arc<DefMap>,
@@ -51,7 +53,7 @@ struct ExprScope {
 #[derive(Debug, Clone)]
 enum Scope {
     /// All the items and imported names of a module
-    BlockScope(ModuleItemMap),
+    ModuleScope(ModuleItemMap),
     /// Brings the generic parameters of an item into scope
     GenericParams { def: GenericDefId, params: Interned<GenericParams> },
     /// Brings `Self` in `impl` block into scope
@@ -125,6 +127,24 @@ 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.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
+    }
+
     pub fn resolve_module_path_in_items(&self, db: &dyn DefDatabase, path: &ModPath) -> PerNs {
         self.resolve_module_path(db, path, BuiltinShadowMode::Module)
     }
@@ -135,7 +155,7 @@ impl Resolver {
         db: &dyn DefDatabase,
         path: &ModPath,
     ) -> Option<PerNs> {
-        let (item_map, module) = self.item_scope();
+        let (item_map, module) = self.module_scope();
         let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module);
         match module_res.take_types()? {
             ModuleDefId::TraitId(it) => {
@@ -163,38 +183,37 @@ impl Resolver {
     ) -> 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,
+                Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue,
+
                 Scope::GenericParams { params, def } => {
                     if let Some(id) = params.find_type_by_name(first_name, *def) {
-                        return Some((TypeNs::GenericParam(id), remaining_idx()));
+                        let idx = if path.segments().len() == 1 { None } else { Some(1) };
+                        return Some((TypeNs::GenericParam(id), idx));
                     }
                 }
-                &Scope::ImplDefScope(impl_) => {
+                Scope::ImplDefScope(impl_) => {
                     if first_name == &name![Self] {
-                        return Some((TypeNs::SelfType(impl_), remaining_idx()));
+                        let idx = if path.segments().len() == 1 { None } else { Some(1) };
+                        return Some((TypeNs::SelfType(*impl_), idx));
                     }
                 }
-                &Scope::AdtScope(adt) => {
+                Scope::AdtScope(adt) => {
                     if first_name == &name![Self] {
-                        return Some((TypeNs::AdtSelfType(adt), remaining_idx()));
+                        let idx = if path.segments().len() == 1 { None } else { Some(1) };
+                        return Some((TypeNs::AdtSelfType(*adt), idx));
                     }
                 }
-                Scope::BlockScope(m) => {
+                Scope::ModuleScope(m) => {
                     if let Some(res) = m.resolve_path_in_type_ns(db, path) {
                         return Some(res);
                     }
                 }
             }
         }
-        self.module_scope.resolve_path_in_type_ns(db, path)
+        None
     }
 
     pub fn resolve_path_in_type_ns_fully(
@@ -216,7 +235,7 @@ impl Resolver {
     ) -> Option<Visibility> {
         match visibility {
             RawVisibility::Module(_) => {
-                let (item_map, module) = self.item_scope();
+                let (item_map, module) = self.module_scope();
                 item_map.resolve_visibility(db, module, visibility)
             }
             RawVisibility::Public => Some(Visibility::Public),
@@ -232,14 +251,18 @@ impl Resolver {
         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(_) if n_segments > 1 => continue,
-                Scope::ExprScope(scope) => {
+                Scope::AdtScope(_)
+                | Scope::ExprScope(_)
+                | Scope::GenericParams { .. }
+                | Scope::ImplDefScope(_)
+                    if skip_to_mod =>
+                {
+                    continue
+                }
+
+                Scope::ExprScope(scope) if n_segments <= 1 => {
                     let entry = scope
                         .expr_scopes
                         .entries(scope.scope_id)
@@ -250,39 +273,44 @@ impl Resolver {
                         return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat())));
                     }
                 }
+                Scope::ExprScope(_) => continue,
+
                 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 { .. } if n_segments != 1 => continue,
-                Scope::GenericParams { params, def } => {
+                Scope::GenericParams { params, def } if n_segments == 1 => {
                     if let Some(id) = params.find_const_by_name(first_name, *def) {
                         let val = ValueNs::GenericParam(id);
                         return Some(ResolveValueResult::ValueNs(val));
                     }
                 }
+                Scope::GenericParams { .. } => continue,
 
-                &Scope::ImplDefScope(impl_) => {
+                Scope::ImplDefScope(impl_) => {
                     if first_name == &name![Self] {
-                        return Some(if n_segments > 1 {
-                            ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1)
+                        if n_segments > 1 {
+                            let ty = TypeNs::SelfType(*impl_);
+                            return Some(ResolveValueResult::Partial(ty, 1));
                         } else {
-                            ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_))
-                        });
+                            return Some(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) => {
+                    if n_segments == 1 {
+                        // bare `Self` doesn't work in the value namespace in a struct/enum definition
+                        continue;
+                    }
                     if first_name == &name![Self] {
                         let ty = TypeNs::AdtSelfType(*adt);
                         return Some(ResolveValueResult::Partial(ty, 1));
                     }
                 }
 
-                Scope::BlockScope(m) => {
+                Scope::ModuleScope(m) => {
                     if let Some(def) = m.resolve_path_in_value_ns(db, path) {
                         return Some(def);
                     }
@@ -290,16 +318,15 @@ impl Resolver {
             }
         }
 
-        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 {
-            if let Some(builtin) = BuiltinType::by_name(&path.segments()[0]) {
-                return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1));
+            match BuiltinType::by_name(&path.segments()[0]) {
+                Some(builtin) => {
+                    return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1));
+                }
+                None => {}
             }
         }
 
@@ -318,7 +345,7 @@ impl Resolver {
     }
 
     pub fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroId> {
-        let (item_map, module) = self.item_scope();
+        let (item_map, module) = self.module_scope();
         item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros()
     }
 
@@ -368,43 +395,30 @@ impl Resolver {
         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 {
-                Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()),
+                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::<()>
+                    });
+                }
                 &Scope::ImplDefScope(impl_) => {
                     if let Some(target_trait) = &db.impl_data(impl_).target_trait {
                         if let Some(TypeNs::TraitId(trait_)) =
@@ -417,28 +431,35 @@ impl Resolver {
                 _ => (),
             }
         }
-
-        // 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
     }
 
+    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")
+    }
+
     pub fn module(&self) -> ModuleId {
-        let (def_map, local_id) = self.item_scope();
+        let (def_map, local_id) = self.module_scope();
         def_map.module_id(local_id)
     }
 
     pub fn krate(&self) -> CrateId {
-        self.module_scope.def_map.krate()
+        self.def_map().krate()
     }
 
     pub fn def_map(&self) -> &DefMap {
-        self.item_scope().0
+        self.scopes
+            .get(0)
+            .and_then(|scope| match scope {
+                Scope::ModuleScope(m) => Some(&m.def_map),
+                _ => None,
+            })
+            .expect("module scope invariant violated")
     }
 
     pub fn where_predicates_in_scope(
@@ -467,36 +488,6 @@ impl Resolver {
     }
 }
 
-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),
@@ -511,7 +502,14 @@ pub enum ScopeDef {
 impl Scope {
     fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) {
         match self {
-            Scope::BlockScope(m) => {
+            Scope::ModuleScope(m) => {
+                // FIXME: should we provide `self` here?
+                // f(
+                //     Name::self_param(),
+                //     PerNs::types(Resolution::Def {
+                //         def: m.module.into(),
+                //     }),
+                // );
                 m.def_map[m.module_id].scope.entries().for_each(|(name, def)| {
                     acc.add_per_ns(name, def);
                 });
@@ -523,6 +521,18 @@ impl Scope {
                         );
                     })
                 });
+                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::GenericParams { params, def: parent } => {
                 let parent = *parent;
@@ -586,7 +596,7 @@ pub fn resolver_for_scope(
         if let Some(block) = scopes.block(scope) {
             if let Some(def_map) = db.block_def_map(block) {
                 let root = def_map.root();
-                r = r.push_block_scope(def_map, root);
+                r = r.push_module_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?
@@ -613,8 +623,8 @@ impl Resolver {
         self.push_scope(Scope::ImplDefScope(impl_def))
     }
 
-    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_module_scope(self, def_map: Arc<DefMap>, module_id: LocalModuleId) -> Resolver {
+        self.push_scope(Scope::ModuleScope(ModuleItemMap { def_map, module_id }))
     }
 
     fn push_expr_scope(
@@ -758,19 +768,14 @@ pub trait HasResolver: Copy {
 impl HasResolver for ModuleId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
         let mut def_map = self.def_map(db);
-        let mut modules: SmallVec<[_; 1]> = smallvec![];
-        let mut module_id = self.local_id;
+        let mut modules: SmallVec<[_; 2]> = smallvec![(def_map.clone(), self.local_id)];
         while let Some(parent) = def_map.parent() {
-            modules.push((def_map, module_id));
             def_map = parent.def_map(db);
-            module_id = parent.local_id;
+            modules.push((def_map.clone(), parent.local_id));
         }
-        let mut resolver = Resolver {
-            scopes: Vec::with_capacity(modules.len()),
-            module_scope: ModuleItemMap { def_map, module_id },
-        };
+        let mut resolver = Resolver { scopes: Vec::with_capacity(modules.len()) };
         for (def_map, module) in modules.into_iter().rev() {
-            resolver = resolver.push_block_scope(def_map, module);
+            resolver = resolver.push_module_scope(def_map, module);
         }
         resolver
     }
diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs
index 4ce21a5796..2b859f7750 100644
--- a/crates/hir-expand/src/name.rs
+++ b/crates/hir-expand/src/name.rs
@@ -336,7 +336,6 @@ pub mod known {
         test,
         test_case,
         recursion_limit,
-        feature,
         // Safe intrinsics
         abort,
         add_with_overflow,
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs
index 344036dd81..b6f226dbfd 100644
--- a/crates/hir-ty/src/autoderef.rs
+++ b/crates/hir-ty/src/autoderef.rs
@@ -104,7 +104,8 @@ pub(crate) fn deref(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
 
 fn builtin_deref(ty: &Ty) -> Option<&Ty> {
     match ty.kind(Interner) {
-        TyKind::Ref(.., ty) | TyKind::Raw(.., ty) => Some(ty),
+        TyKind::Ref(.., ty) => Some(ty),
+        TyKind::Raw(.., ty) => Some(ty),
         _ => None,
     }
 }
diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs
index 4a5533c648..a9c124b42d 100644
--- a/crates/hir-ty/src/chalk_ext.rs
+++ b/crates/hir-ty/src/chalk_ext.rs
@@ -164,8 +164,6 @@ impl TyExt for Ty {
 
     fn dyn_trait(&self) -> Option<TraitId> {
         let trait_ref = match self.kind(Interner) {
-            // The principal trait bound should be the first element of the bounds. This is an
-            // invariant ensured by `TyLoweringContext::lower_dyn_trait()`.
             TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
                 match b.skip_binders() {
                     WhereClause::Implemented(trait_ref) => Some(trait_ref),
diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs
index c8df4c796e..642e03edd2 100644
--- a/crates/hir-ty/src/diagnostics/expr.rs
+++ b/crates/hir-ty/src/diagnostics/expr.rs
@@ -159,7 +159,12 @@ impl ExprValidator {
         }
 
         let pattern_arena = Arena::new();
-        let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db, &pattern_arena);
+        let cx = MatchCheckCtx {
+            module: self.owner.module(db.upcast()),
+            body: self.owner,
+            db,
+            pattern_arena: &pattern_arena,
+        };
 
         let mut m_arms = Vec::with_capacity(arms.len());
         let mut has_lowering_errors = false;
diff --git a/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
index 47d60fc41e..bbbe539c13 100644
--- a/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
+++ b/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
@@ -52,10 +52,7 @@ use hir_def::{EnumVariantId, HasModule, LocalFieldId, VariantId};
 use smallvec::{smallvec, SmallVec};
 use stdx::never;
 
-use crate::{
-    infer::normalize, inhabitedness::is_enum_variant_uninhabited_from, AdtId, Interner, Scalar, Ty,
-    TyExt, TyKind,
-};
+use crate::{infer::normalize, AdtId, Interner, Scalar, Ty, TyExt, TyKind};
 
 use super::{
     is_box,
@@ -560,8 +557,8 @@ impl SplitWildcard {
             TyKind::Scalar(Scalar::Bool) => smallvec![make_range(0, 1, Scalar::Bool)],
             // TyKind::Array(..) if ... => unhandled(),
             TyKind::Array(..) | TyKind::Slice(..) => unhandled(),
-            TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), subst) => {
-                let enum_data = cx.db.enum_data(*enum_id);
+            &TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ..) => {
+                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.
@@ -594,15 +591,14 @@ impl SplitWildcard {
                 let mut ctors: SmallVec<[_; 1]> = enum_data
                     .variants
                     .iter()
-                    .map(|(local_id, _)| EnumVariantId { parent: *enum_id, local_id })
-                    .filter(|&variant| {
+                    .filter(|&(_, _v)| {
                         // If `exhaustive_patterns` is enabled, we exclude variants known to be
                         // uninhabited.
                         let is_uninhabited = is_exhaustive_pat_feature
-                            && is_enum_variant_uninhabited_from(variant, subst, cx.module, cx.db);
+                            && unimplemented!("after MatchCheckCtx.feature_exhaustive_patterns()");
                         !is_uninhabited
                     })
-                    .map(Variant)
+                    .map(|(local_id, _)| Variant(EnumVariantId { parent: enum_id, local_id }))
                     .collect();
 
                 if is_secretly_empty || is_declared_nonexhaustive {
diff --git a/crates/hir-ty/src/diagnostics/match_check/usefulness.rs b/crates/hir-ty/src/diagnostics/match_check/usefulness.rs
index c4d709a975..1221327b95 100644
--- a/crates/hir-ty/src/diagnostics/match_check/usefulness.rs
+++ b/crates/hir-ty/src/diagnostics/match_check/usefulness.rs
@@ -277,7 +277,7 @@ use hir_def::{AdtId, DefWithBodyId, HasModule, ModuleId};
 use smallvec::{smallvec, SmallVec};
 use typed_arena::Arena;
 
-use crate::{db::HirDatabase, inhabitedness::is_ty_uninhabited_from, Ty, TyExt};
+use crate::{db::HirDatabase, Ty, TyExt};
 
 use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard};
 
@@ -289,27 +289,13 @@ pub(crate) struct MatchCheckCtx<'a, 'p> {
     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> {
-    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
-        }
+    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
     }
 
     /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
@@ -325,9 +311,10 @@ impl<'a, 'p> MatchCheckCtx<'a, 'p> {
         }
     }
 
-    // Rust's unstable feature described as "Allows exhaustive pattern matching on types that contain uninhabited types."
+    // Rust feature described as "Allows exhaustive pattern matching on types that contain uninhabited types."
     pub(super) fn feature_exhaustive_patterns(&self) -> bool {
-        self.exhaustive_patterns
+        // FIXME see MatchCheckCtx::is_uninhabited
+        false
     }
 }
 
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 10ffde87ee..5df48e5fdc 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -182,7 +182,7 @@ pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub enum InferenceDiagnostic {
     NoSuchField { expr: ExprId },
-    BreakOutsideOfLoop { expr: ExprId, is_break: bool },
+    BreakOutsideOfLoop { expr: ExprId },
     MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
 }
 
@@ -418,45 +418,18 @@ pub(crate) struct InferenceContext<'a> {
 
 #[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),
+        Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label),
+        None => ctxs.last_mut(),
     }
 }
 
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 2d04a864a2..a42a00ea59 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -10,7 +10,7 @@ use chalk_ir::{
     cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
 };
 use hir_def::{
-    expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, LabelId, Literal, Statement, UnaryOp},
+    expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Statement, UnaryOp},
     generics::TypeOrConstParamData,
     path::{GenericArg, GenericArgs},
     resolver::resolver_for_expr,
@@ -23,7 +23,7 @@ use syntax::ast::RangeOp;
 use crate::{
     autoderef::{self, Autoderef},
     consteval,
-    infer::{coerce::CoerceMany, find_continuable, BreakableKind},
+    infer::coerce::CoerceMany,
     lower::{
         const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
     },
@@ -120,37 +120,32 @@ impl<'a> InferenceContext<'a> {
                 let ty = match label {
                     Some(_) => {
                         let break_ty = self.table.new_type_var();
-                        let (breaks, ty) = self.with_breakable_ctx(
-                            BreakableKind::Block,
-                            break_ty.clone(),
-                            *label,
-                            |this| {
-                                this.infer_block(
-                                    tgt_expr,
-                                    statements,
-                                    *tail,
-                                    &Expectation::has_type(break_ty),
-                                )
-                            },
+                        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),
                         );
-                        breaks.unwrap_or(ty)
+                        let ctxt = self.breakables.pop().expect("breakable stack broken");
+                        if ctxt.may_break {
+                            ctxt.coerce.complete()
+                        } else {
+                            ty
+                        }
                     }
                     None => self.infer_block(tgt_expr, statements, *tail, expected),
                 };
                 self.resolver = old_resolver;
                 ty
             }
-            Expr::Unsafe { body } => self.infer_expr(*body, expected),
-            Expr::Const { body } => {
-                self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
-                    this.infer_expr(*body, expected)
-                })
-                .1
-            }
+            Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected),
             Expr::TryBlock { body } => {
-                self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
-                    let _inner = this.infer_expr(*body, expected);
-                });
+                let _inner = self.infer_expr(*body, expected);
                 // FIXME should be std::result::Result<{inner}, _>
                 self.err_ty()
             }
@@ -159,10 +154,7 @@ impl<'a> InferenceContext<'a> {
                 let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
                 let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
 
-                let (_, inner_ty) =
-                    self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
-                        this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty))
-                    });
+                let inner_ty = self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
 
                 self.diverges = prev_diverges;
                 self.return_ty = prev_ret_ty;
@@ -174,44 +166,54 @@ impl<'a> InferenceContext<'a> {
                 TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty))
                     .intern(Interner)
             }
-            &Expr::Loop { body, label } => {
-                let ty = self.table.new_type_var();
-                let (breaks, ()) =
-                    self.with_breakable_ctx(BreakableKind::Loop, ty, label, |this| {
-                        this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
-                    });
+            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()));
 
-                match breaks {
-                    Some(breaks) => {
-                        self.diverges = Diverges::Maybe;
-                        breaks
-                    }
-                    None => TyKind::Never.intern(Interner),
+                let ctxt = self.breakables.pop().expect("breakable stack broken");
+
+                if ctxt.may_break {
+                    self.diverges = Diverges::Maybe;
+                    ctxt.coerce.complete()
+                } else {
+                    TyKind::Never.intern(Interner)
                 }
             }
-            &Expr::While { condition, body, label } => {
-                self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
-                    this.infer_expr(
-                        condition,
-                        &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
-                    );
-                    this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
+            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()),
                 });
-
+                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");
                 // the body may not run, so it diverging doesn't mean we diverge
                 self.diverges = Diverges::Maybe;
                 TyBuilder::unit()
             }
-            &Expr::For { iterable, body, pat, label } => {
-                let iterable_ty = self.infer_expr(iterable, &Expectation::none());
+            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()),
+                });
                 let pat_ty =
                     self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
 
-                self.infer_pat(pat, &pat_ty, BindingMode::default());
-                self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
-                    this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
-                });
+                self.infer_pat(*pat, &pat_ty, BindingMode::default());
 
+                self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
+                let _ctxt = self.breakables.pop().expect("breakable stack broken");
                 // the body may not run, so it diverging doesn't mean we diverge
                 self.diverges = Diverges::Maybe;
                 TyBuilder::unit()
@@ -267,9 +269,7 @@ impl<'a> InferenceContext<'a> {
                 let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
                 let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
 
-                self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
-                    this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
-                });
+                self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
 
                 self.diverges = prev_diverges;
                 self.return_ty = prev_ret_ty;
@@ -372,45 +372,37 @@ impl<'a> InferenceContext<'a> {
                 let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
                 self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or_else(|| self.err_ty())
             }
-            Expr::Continue { label } => {
-                if let None = find_continuable(&mut self.breakables, label.as_ref()) {
-                    self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
-                        expr: tgt_expr,
-                        is_break: false,
-                    });
-                };
-                TyKind::Never.intern(Interner)
-            }
+            Expr::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()),
+                };
+
                 let val_ty = if let Some(expr) = *expr {
                     self.infer_expr(expr, &Expectation::none())
                 } else {
                     TyBuilder::unit()
                 };
 
-                match find_breakable(&mut self.breakables, label.as_ref()) {
-                    Some(ctxt) => {
-                        // avoiding the borrowck
-                        let mut coerce = mem::replace(
-                            &mut ctxt.coerce,
-                            CoerceMany::new(self.result.standard_types.unknown.clone()),
-                        );
+                // FIXME: create a synthetic `()` during lowering so we have something to refer to here?
+                coerce.coerce(self, *expr, &val_ty);
 
-                        // FIXME: create a synthetic `()` during lowering so we have something to refer to here?
-                        coerce.coerce(self, *expr, &val_ty);
+                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,
+                    });
+                };
 
-                        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 } => {
@@ -1480,20 +1472,4 @@ impl<'a> InferenceContext<'a> {
             },
         })
     }
-
-    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)
-    }
 }
diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs
deleted file mode 100644
index 0c547192ac..0000000000
--- a/crates/hir-ty/src/inhabitedness.rs
+++ /dev/null
@@ -1,173 +0,0 @@
-//! 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,
-    }
-}
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index a82a331d4b..5a5d610e36 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -14,7 +14,6 @@ mod chalk_db;
 mod chalk_ext;
 pub mod consteval;
 mod infer;
-mod inhabitedness;
 mod interner;
 mod lower;
 mod mapping;
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 532544fee5..4a37a79453 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -981,72 +981,43 @@ impl<'a> TyLoweringContext<'a> {
 
     fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
         let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
-        // INVARIANT: The principal trait bound must come first. Others may be in any order but
-        // should be in the same order for the same set but possibly different order of bounds in
-        // the input.
-        // This invariant is used by `TyExt::dyn_trait()` and chalk.
         let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
-            let mut bounds: Vec<_> = bounds
-                .iter()
-                .flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false))
-                .collect();
-
-            let mut multiple_regular_traits = false;
-            let mut multiple_same_projection = false;
-            bounds.sort_unstable_by(|lhs, rhs| {
-                use std::cmp::Ordering;
-                match (lhs.skip_binders(), rhs.skip_binders()) {
-                    (WhereClause::Implemented(lhs), WhereClause::Implemented(rhs)) => {
-                        let lhs_id = lhs.trait_id;
-                        let lhs_is_auto = ctx.db.trait_data(from_chalk_trait_id(lhs_id)).is_auto;
-                        let rhs_id = rhs.trait_id;
-                        let rhs_is_auto = ctx.db.trait_data(from_chalk_trait_id(rhs_id)).is_auto;
-
-                        if !lhs_is_auto && !rhs_is_auto {
-                            multiple_regular_traits = true;
-                        }
-                        // Note that the ordering here is important; this ensures the invariant
-                        // mentioned above.
-                        (lhs_is_auto, lhs_id).cmp(&(rhs_is_auto, rhs_id))
-                    }
-                    (WhereClause::Implemented(_), _) => Ordering::Less,
-                    (_, WhereClause::Implemented(_)) => Ordering::Greater,
-                    (WhereClause::AliasEq(lhs), WhereClause::AliasEq(rhs)) => {
-                        match (&lhs.alias, &rhs.alias) {
-                            (AliasTy::Projection(lhs_proj), AliasTy::Projection(rhs_proj)) => {
-                                // We only compare the `associated_ty_id`s. We shouldn't have
-                                // multiple bounds for an associated type in the correct Rust code,
-                                // and if we do, we error out.
-                                if lhs_proj.associated_ty_id == rhs_proj.associated_ty_id {
-                                    multiple_same_projection = true;
-                                }
-                                lhs_proj.associated_ty_id.cmp(&rhs_proj.associated_ty_id)
-                            }
-                            // We don't produce `AliasTy::Opaque`s yet.
-                            _ => unreachable!(),
-                        }
+            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);
                     }
-                    // We don't produce `WhereClause::{TypeOutlives, LifetimeOutlives}` yet.
-                    _ => unreachable!(),
+                } else {
+                    other_bounds.push(bound);
                 }
-            });
+            }
 
-            if multiple_regular_traits || multiple_same_projection {
+            if regular_traits.len() > 1 {
                 return None;
             }
 
-            // As multiple occurrences of the same auto traits *are* permitted, we dedulicate the
-            // bounds. We shouldn't have repeated elements besides auto traits at this point.
-            bounds.dedup();
+            auto_traits.sort_unstable_by_key(|b| b.trait_id().unwrap());
+            auto_traits.dedup();
 
-            Some(QuantifiedWhereClauses::from_iter(Interner, bounds))
+            Some(QuantifiedWhereClauses::from_iter(
+                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 or associated type rebound)
+            // FIXME: report error (additional non-auto traits)
             TyKind::Error.intern(Interner)
         }
     }
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 5edc16d8bc..50374f4b3f 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -124,7 +124,6 @@ pub struct NoSuchField {
 #[derive(Debug)]
 pub struct BreakOutsideOfLoop {
     pub expr: InFile<AstPtr<ast::Expr>>,
-    pub is_break: bool,
 }
 
 #[derive(Debug)]
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index e4bb63a864..6dccf2ed20 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1216,11 +1216,11 @@ impl DefWithBody {
                     let field = source_map.field_syntax(*expr);
                     acc.push(NoSuchField { field }.into())
                 }
-                &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
+                hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
                     let expr = source_map
-                        .expr_syntax(expr)
+                        .expr_syntax(*expr)
                         .expect("break outside of loop in synthetic syntax");
-                    acc.push(BreakOutsideOfLoop { expr, is_break }.into())
+                    acc.push(BreakOutsideOfLoop { expr }.into())
                 }
                 hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
                     match source_map.expr_syntax(*call_expr) {
diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index 1a7919a5a1..b16f6fe03a 100644
--- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -5,7 +5,6 @@ use hir::{Adt, Crate, HasAttrs, HasSource, ModuleDef, Semantics};
 use ide_db::RootDatabase;
 use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
 use itertools::Itertools;
-use syntax::ast::edit_in_place::Removable;
 use syntax::ast::{self, make, AstNode, HasName, MatchArmList, MatchExpr, Pat};
 
 use crate::{
diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs
index 9f51cdaf8b..96890ad51a 100644
--- a/crates/ide-assists/src/handlers/inline_call.rs
+++ b/crates/ide-assists/src/handlers/inline_call.rs
@@ -7,7 +7,6 @@ use ide_db::{
     imports::insert_use::remove_path_if_in_use_stmt,
     path_transform::PathTransform,
     search::{FileReference, SearchScope},
-    source_change::SourceChangeBuilder,
     syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref},
     RootDatabase,
 };
@@ -101,7 +100,18 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) ->
                 builder.edit_file(file_id);
                 let count = refs.len();
                 // The collects are required as we are otherwise iterating while mutating 🙅‍♀️🙅‍♂️
-                let (name_refs, name_refs_use) = split_refs_and_uses(builder, refs, Some);
+                let (name_refs, name_refs_use): (Vec<_>, Vec<_>) = refs
+                    .into_iter()
+                    .filter_map(|file_ref| match file_ref.name {
+                        ast::NameLike::NameRef(name_ref) => Some(name_ref),
+                        _ => None,
+                    })
+                    .partition_map(|name_ref| {
+                        match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) {
+                            Some(use_tree) => Either::Right(builder.make_mut(use_tree)),
+                            None => Either::Left(name_ref),
+                        }
+                    });
                 let call_infos: Vec<_> = name_refs
                     .into_iter()
                     .filter_map(CallInfo::from_name_ref)
@@ -120,7 +130,11 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) ->
                     .count();
                 if replaced + name_refs_use.len() == count {
                     // we replaced all usages in this file, so we can remove the imports
-                    name_refs_use.iter().for_each(remove_path_if_in_use_stmt);
+                    name_refs_use.into_iter().for_each(|use_tree| {
+                        if let Some(path) = use_tree.path() {
+                            remove_path_if_in_use_stmt(&path);
+                        }
+                    })
                 } else {
                     remove_def = false;
                 }
@@ -139,23 +153,6 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     )
 }
 
-pub(super) fn split_refs_and_uses<T: ast::AstNode>(
-    builder: &mut SourceChangeBuilder,
-    iter: impl IntoIterator<Item = FileReference>,
-    mut map_ref: impl FnMut(ast::NameRef) -> Option<T>,
-) -> (Vec<T>, Vec<ast::Path>) {
-    iter.into_iter()
-        .filter_map(|file_ref| match file_ref.name {
-            ast::NameLike::NameRef(name_ref) => Some(name_ref),
-            _ => None,
-        })
-        .filter_map(|name_ref| match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) {
-            Some(use_tree) => builder.make_mut(use_tree).path().map(Either::Right),
-            None => map_ref(name_ref).map(Either::Left),
-        })
-        .partition_map(|either| either)
-}
-
 // Assist: inline_call
 //
 // Inlines a function or method body creating a `let` statement per parameter unless the parameter
diff --git a/crates/ide-assists/src/handlers/inline_type_alias.rs b/crates/ide-assists/src/handlers/inline_type_alias.rs
index 353d467ed1..9adf6381c1 100644
--- a/crates/ide-assists/src/handlers/inline_type_alias.rs
+++ b/crates/ide-assists/src/handlers/inline_type_alias.rs
@@ -3,10 +3,7 @@
 // - Remove unused aliases if there are no longer any users, see inline_call.rs.
 
 use hir::{HasSource, PathResolution};
-use ide_db::{
-    defs::Definition, imports::insert_use::ast_to_remove_for_path_in_use_stmt,
-    search::FileReference,
-};
+use ide_db::{defs::Definition, search::FileReference};
 use itertools::Itertools;
 use std::collections::HashMap;
 use syntax::{
@@ -19,8 +16,6 @@ use crate::{
     AssistId, AssistKind,
 };
 
-use super::inline_call::split_refs_and_uses;
-
 // Assist: inline_type_alias_uses
 //
 // Inline a type alias into all of its uses where possible.
@@ -36,7 +31,7 @@ use super::inline_call::split_refs_and_uses;
 // ```
 // ->
 // ```
-//
+// type A = i32;
 // fn id(x: i32) -> i32 {
 //     x
 // };
@@ -63,20 +58,20 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>)
         name.syntax().text_range(),
         |builder| {
             let usages = usages.all();
-            let mut definition_deleted = false;
 
             let mut inline_refs_for_file = |file_id, refs: Vec<FileReference>| {
                 builder.edit_file(file_id);
 
-                let (path_types, path_type_uses) =
-                    split_refs_and_uses(builder, refs, |path_type| {
-                        path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast)
-                    });
+                let path_types: Vec<ast::PathType> = refs
+                    .into_iter()
+                    .filter_map(|file_ref| match file_ref.name {
+                        ast::NameLike::NameRef(path_type) => {
+                            path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast)
+                        }
+                        _ => None,
+                    })
+                    .collect();
 
-                path_type_uses
-                    .iter()
-                    .flat_map(ast_to_remove_for_path_in_use_stmt)
-                    .for_each(|x| builder.delete(x.syntax().text_range()));
                 for (target, replacement) in path_types.into_iter().filter_map(|path_type| {
                     let replacement = inline(&ast_alias, &path_type)?.to_text(&concrete_type);
                     let target = path_type.syntax().text_range();
@@ -84,20 +79,11 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>)
                 }) {
                     builder.replace(target, replacement);
                 }
-
-                if file_id == ctx.file_id() {
-                    builder.delete(ast_alias.syntax().text_range());
-                    definition_deleted = true;
-                }
             };
 
             for (file_id, refs) in usages.into_iter() {
                 inline_refs_for_file(file_id, refs);
             }
-            if !definition_deleted {
-                builder.edit_file(ctx.file_id());
-                builder.delete(ast_alias.syntax().text_range());
-            }
         },
     )
 }
@@ -943,7 +929,7 @@ fn foo() {
 }
 "#,
                 r#"
-
+type A = u32;
 
 fn foo() {
     let _: u32 = 3;
@@ -974,13 +960,13 @@ fn foo() {
                 r#"
 //- /lib.rs
 mod foo;
-
+type T<E> = Vec<E>;
 fn f() -> Vec<&str> {
     vec!["hello"]
 }
 
 //- /foo.rs
-
+use super::T;
 fn foo() {
     let _: Vec<i8> = Vec::new();
 }
@@ -1004,12 +990,7 @@ fn foo() {
 }
 "#,
                 r#"
-//- /lib.rs
-mod foo;
-
-
-//- /foo.rs
-
+use super::I;
 fn foo() {
     let _: i32 = 0;
 }
diff --git a/crates/ide-assists/src/handlers/merge_imports.rs b/crates/ide-assists/src/handlers/merge_imports.rs
index 2bdbec93b1..7e102ceba8 100644
--- a/crates/ide-assists/src/handlers/merge_imports.rs
+++ b/crates/ide-assists/src/handlers/merge_imports.rs
@@ -1,10 +1,6 @@
 use either::Either;
 use ide_db::imports::merge_imports::{try_merge_imports, try_merge_trees, MergeBehavior};
-use syntax::{
-    algo::neighbor,
-    ast::{self, edit_in_place::Removable},
-    match_ast, ted, AstNode, SyntaxElement, SyntaxNode,
-};
+use syntax::{algo::neighbor, ast, match_ast, ted, AstNode, SyntaxElement, SyntaxNode};
 
 use crate::{
     assist_context::{AssistContext, Assists},
@@ -80,7 +76,7 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
                 .collect();
             for edit in edits_mut {
                 match edit {
-                    Remove(it) => it.as_ref().either(Removable::remove, Removable::remove),
+                    Remove(it) => it.as_ref().either(ast::Use::remove, ast::UseTree::remove),
                     Replace(old, new) => ted::replace(old, new),
                 }
             }
diff --git a/crates/ide-assists/src/handlers/move_bounds.rs b/crates/ide-assists/src/handlers/move_bounds.rs
index 1dd376ac3f..176a3bf580 100644
--- a/crates/ide-assists/src/handlers/move_bounds.rs
+++ b/crates/ide-assists/src/handlers/move_bounds.rs
@@ -1,9 +1,5 @@
 use syntax::{
-    ast::{
-        self,
-        edit_in_place::{GenericParamsOwnerEdit, Removable},
-        make, AstNode, HasName, HasTypeBounds,
-    },
+    ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode, HasName, HasTypeBounds},
     match_ast,
 };
 
diff --git a/crates/ide-assists/src/handlers/unmerge_use.rs b/crates/ide-assists/src/handlers/unmerge_use.rs
index dac216b69b..3ce028e930 100644
--- a/crates/ide-assists/src/handlers/unmerge_use.rs
+++ b/crates/ide-assists/src/handlers/unmerge_use.rs
@@ -1,5 +1,5 @@
 use syntax::{
-    ast::{self, edit_in_place::Removable, make, HasVisibility},
+    ast::{self, make, HasVisibility},
     ted::{self, Position},
     AstNode, SyntaxKind,
 };
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index 4ab6e2627f..103e3259fa 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -12,7 +12,7 @@ use syntax::{
     ast::{
         self,
         edit::{self, AstNodeEdit},
-        edit_in_place::{AttrsOwnerEdit, Removable},
+        edit_in_place::AttrsOwnerEdit,
         make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
     },
     ted, AstNode, AstToken, Direction, SmolStr, SourceFile,
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index 588b52cc1e..4d66af9e8d 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -282,26 +282,14 @@ pub(crate) fn complete_expr_path(
                         }
                     }
 
-                    if let Some(ret_ty) = innermost_ret_ty {
+                    if let Some(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"
-                                }
+                            match (in_block_expr, ty.is_unit()) {
+                                (true, true) => "return ;",
+                                (true, false) => "return;",
+                                (false, true) => "return $0",
+                                (false, false) => "return",
                             },
                         );
                     }
diff --git a/crates/ide-db/src/active_parameter.rs b/crates/ide-db/src/active_parameter.rs
index 7109c6fd18..7303ef8b7b 100644
--- a/crates/ide-db/src/active_parameter.rs
+++ b/crates/ide-db/src/active_parameter.rs
@@ -12,7 +12,7 @@ use crate::RootDatabase;
 #[derive(Debug)]
 pub struct ActiveParameter {
     pub ty: Type,
-    pub pat: Option<Either<ast::SelfParam, ast::Pat>>,
+    pub pat: Either<ast::SelfParam, ast::Pat>,
 }
 
 impl ActiveParameter {
@@ -27,12 +27,12 @@ impl ActiveParameter {
             return None;
         }
         let (pat, ty) = params.swap_remove(idx);
-        Some(ActiveParameter { ty, pat })
+        pat.map(|pat| ActiveParameter { ty, pat })
     }
 
     pub fn ident(&self) -> Option<ast::Name> {
-        self.pat.as_ref().and_then(|param| match param {
-            Either::Right(ast::Pat::IdentPat(ident)) => ident.name(),
+        self.pat.as_ref().right().and_then(|param| match param {
+            ast::Pat::IdentPat(ident) => ident.name(),
             _ => None,
         })
     }
diff --git a/crates/ide-db/src/imports/insert_use.rs b/crates/ide-db/src/imports/insert_use.rs
index 9be1d36634..c14182279d 100644
--- a/crates/ide-db/src/imports/insert_use.rs
+++ b/crates/ide-db/src/imports/insert_use.rs
@@ -7,10 +7,7 @@ use std::cmp::Ordering;
 use hir::Semantics;
 use syntax::{
     algo,
-    ast::{
-        self, edit_in_place::Removable, make, AstNode, HasAttrs, HasModuleItem, HasVisibility,
-        PathSegmentKind,
-    },
+    ast::{self, make, AstNode, HasAttrs, HasModuleItem, HasVisibility, PathSegmentKind},
     ted, Direction, NodeOrToken, SyntaxKind, SyntaxNode,
 };
 
@@ -195,24 +192,20 @@ pub fn insert_use(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) {
     insert_use_(scope, &path, cfg.group, use_item);
 }
 
-pub fn ast_to_remove_for_path_in_use_stmt(path: &ast::Path) -> Option<Box<dyn Removable>> {
+pub fn remove_path_if_in_use_stmt(path: &ast::Path) {
     // FIXME: improve this
     if path.parent_path().is_some() {
-        return None;
-    }
-    let use_tree = path.syntax().parent().and_then(ast::UseTree::cast)?;
-    if use_tree.use_tree_list().is_some() || use_tree.star_token().is_some() {
-        return None;
+        return;
     }
-    if let Some(use_) = use_tree.syntax().parent().and_then(ast::Use::cast) {
-        return Some(Box::new(use_));
-    }
-    Some(Box::new(use_tree))
-}
-
-pub fn remove_path_if_in_use_stmt(path: &ast::Path) {
-    if let Some(node) = ast_to_remove_for_path_in_use_stmt(path) {
-        node.remove();
+    if let Some(use_tree) = path.syntax().parent().and_then(ast::UseTree::cast) {
+        if use_tree.use_tree_list().is_some() || use_tree.star_token().is_some() {
+            return;
+        }
+        if let Some(use_) = use_tree.syntax().parent().and_then(ast::Use::cast) {
+            use_.remove();
+            return;
+        }
+        use_tree.remove();
     }
 }
 
diff --git a/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs b/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs
index 8bc093a85a..f54ae6c920 100644
--- a/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs
+++ b/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs
@@ -95,7 +95,7 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode {
             AS_KW | DYN_KW | IMPL_KW | CONST_KW => {
                 mods.push(do_ws(after, tok));
             }
-            T![;] if is_next(|it| it != R_CURLY, true) => {
+            T![;] => {
                 if indent > 0 {
                     mods.push(do_indent(after, tok, indent));
                 }
diff --git a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
index 0c92e706b3..d12594a4ce 100644
--- a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
+++ b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
@@ -7,10 +7,9 @@ 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",
-        format!("{construct} outside of loop"),
+        "break outside of loop",
         ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
     )
 }
@@ -20,122 +19,11 @@ mod tests {
     use crate::tests::check_diagnostics;
 
     #[test]
-    fn outside_of_loop() {
+    fn break_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
-    }
-}
+fn foo() { break; }
+         //^^^^^ error: break outside of loop
 "#,
         );
     }
diff --git a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index c24430ce60..5fcaf405b1 100644
--- a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -947,50 +947,6 @@ fn f() {
         );
     }
 
-    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
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index c5c50d88dd..d52adaee53 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -2,13 +2,12 @@
 use std::fmt::Display;
 
 use either::Either;
-use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo};
+use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HirDisplay, Semantics, TypeInfo};
 use ide_db::{
     base_db::SourceDatabase,
     defs::Definition,
     famous_defs::FamousDefs,
     generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
-    syntax_helpers::insert_whitespace_into_node,
     RootDatabase,
 };
 use itertools::Itertools;
@@ -351,24 +350,10 @@ pub(super) fn definition(
             let body = it.eval(db);
             match body {
                 Ok(x) => Some(format!("{}", x)),
-                Err(_) => {
-                    let source = it.source(db)?;
-                    let mut body = source.value.body()?.syntax().clone();
-                    if source.file_id.is_macro() {
-                        body = insert_whitespace_into_node::insert_ws_into(body);
-                    }
-                    Some(body.to_string())
-                }
-            }
-        }),
-        Definition::Static(it) => label_value_and_docs(db, it, |it| {
-            let source = it.source(db)?;
-            let mut body = source.value.body()?.syntax().clone();
-            if source.file_id.is_macro() {
-                body = insert_whitespace_into_node::insert_ws_into(body);
+                Err(_) => it.value(db).map(|x| format!("{}", x)),
             }
-            Some(body.to_string())
         }),
+        Definition::Static(it) => label_value_and_docs(db, it, |it| it.value(db)),
         Definition::Trait(it) => label_and_docs(db, it),
         Definition::TypeAlias(it) => label_and_docs(db, it),
         Definition::BuiltinType(it) => {
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index e9034daefa..d1b1d2c331 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1,3 +1,5 @@
+use std::fmt;
+
 use either::Either;
 use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo};
 use ide_db::{
@@ -69,7 +71,7 @@ pub enum InlayKind {
 pub struct InlayHint {
     pub range: TextRange,
     pub kind: InlayKind,
-    pub label: String,
+    pub label: InlayHintLabel,
     pub tooltip: Option<InlayTooltip>,
 }
 
@@ -80,6 +82,83 @@ pub enum InlayTooltip {
     HoverOffset(FileId, TextSize),
 }
 
+pub struct InlayHintLabel {
+    pub parts: Vec<InlayHintLabelPart>,
+}
+
+impl InlayHintLabel {
+    pub fn as_simple_str(&self) -> Option<&str> {
+        match &*self.parts {
+            [part] => part.as_simple_str(),
+            _ => None,
+        }
+    }
+
+    pub fn prepend_str(&mut self, s: &str) {
+        match &mut *self.parts {
+            [part, ..] if part.as_simple_str().is_some() => part.text = format!("{s}{}", part.text),
+            _ => self.parts.insert(0, InlayHintLabelPart { text: s.into(), linked_location: None }),
+        }
+    }
+
+    pub fn append_str(&mut self, s: &str) {
+        match &mut *self.parts {
+            [.., part] if part.as_simple_str().is_some() => part.text.push_str(s),
+            _ => self.parts.push(InlayHintLabelPart { text: s.into(), linked_location: None }),
+        }
+    }
+}
+
+impl From<String> for InlayHintLabel {
+    fn from(s: String) -> Self {
+        Self { parts: vec![InlayHintLabelPart { text: s, linked_location: None }] }
+    }
+}
+
+impl fmt::Display for InlayHintLabel {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.parts.iter().map(|part| &part.text).format(""))
+    }
+}
+
+impl fmt::Debug for InlayHintLabel {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(&self.parts).finish()
+    }
+}
+
+pub struct InlayHintLabelPart {
+    pub text: String,
+    /// Source location represented by this label part. The client will use this to fetch the part's
+    /// hover tooltip, and Ctrl+Clicking the label part will navigate to the definition the location
+    /// refers to (not necessarily the location itself).
+    /// When setting this, no tooltip must be set on the containing hint, or VS Code will display
+    /// them both.
+    pub linked_location: Option<FileRange>,
+}
+
+impl InlayHintLabelPart {
+    pub fn as_simple_str(&self) -> Option<&str> {
+        match self {
+            Self { text, linked_location: None } => Some(text),
+            _ => None,
+        }
+    }
+}
+
+impl fmt::Debug for InlayHintLabelPart {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.as_simple_str() {
+            Some(string) => string.fmt(f),
+            None => f
+                .debug_struct("InlayHintLabelPart")
+                .field("text", &self.text)
+                .field("linked_location", &self.linked_location)
+                .finish(),
+        }
+    }
+}
+
 // Feature: Inlay Hints
 //
 // rust-analyzer shows additional information inline with the source code.
@@ -192,10 +271,10 @@ fn closing_brace_hints(
 ) -> Option<()> {
     let min_lines = config.closing_brace_hints_min_lines?;
 
-    let name = |it: ast::Name| it.syntax().text_range().start();
+    let name = |it: ast::Name| it.syntax().text_range();
 
     let mut closing_token;
-    let (label, name_offset) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
+    let (label, name_range) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
         closing_token = item_list.r_curly_token()?;
 
         let parent = item_list.syntax().parent()?;
@@ -205,11 +284,11 @@ fn closing_brace_hints(
                     let imp = sema.to_def(&imp)?;
                     let ty = imp.self_ty(sema.db);
                     let trait_ = imp.trait_(sema.db);
-
-                    (match trait_ {
+                    let hint_text = 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)
+                    };
+                    (hint_text, None)
                 },
                 ast::Trait(tr) => {
                     (format!("trait {}", tr.name()?), tr.name().map(name))
@@ -253,7 +332,7 @@ fn closing_brace_hints(
 
         (
             format!("{}!", mac.path()?),
-            mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range().start()),
+            mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range()),
         )
     } else {
         return None;
@@ -278,11 +357,12 @@ fn closing_brace_hints(
         return None;
     }
 
+    let linked_location = name_range.map(|range| FileRange { file_id, range });
     acc.push(InlayHint {
         range: closing_token.text_range(),
         kind: InlayKind::ClosingBraceHint,
-        label,
-        tooltip: name_offset.map(|it| InlayTooltip::HoverOffset(file_id, it)),
+        label: InlayHintLabel { parts: vec![InlayHintLabelPart { text: label, linked_location }] },
+        tooltip: None, // provided by label part location
     });
 
     None
@@ -311,7 +391,7 @@ fn implicit_static_hints(
             acc.push(InlayHint {
                 range: t.text_range(),
                 kind: InlayKind::LifetimeHint,
-                label: "'static".to_owned(),
+                label: "'static".to_owned().into(),
                 tooltip: Some(InlayTooltip::String("Elided static lifetime".into())),
             });
         }
@@ -329,10 +409,10 @@ fn fn_lifetime_fn_hints(
         return None;
     }
 
-    let mk_lt_hint = |t: SyntaxToken, label| InlayHint {
+    let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint {
         range: t.text_range(),
         kind: InlayKind::LifetimeHint,
-        label,
+        label: label.into(),
         tooltip: Some(InlayTooltip::String("Elided lifetime".into())),
     };
 
@@ -486,7 +566,8 @@ fn fn_lifetime_fn_hints(
                     "{}{}",
                     allocated_lifetimes.iter().format(", "),
                     if is_empty { "" } else { ", " }
-                ),
+                )
+                .into(),
                 tooltip: Some(InlayTooltip::String("Elided lifetimes".into())),
             });
         }
@@ -535,7 +616,8 @@ fn closure_ret_hints(
         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()),
+            .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string())
+            .into(),
         tooltip: Some(InlayTooltip::HoverRanged(file_id, param_list.syntax().text_range())),
     });
     Some(())
@@ -562,7 +644,7 @@ fn reborrow_hints(
     acc.push(InlayHint {
         range: expr.syntax().text_range(),
         kind: InlayKind::ImplicitReborrowHint,
-        label: label.to_string(),
+        label: label.to_string().into(),
         tooltip: Some(InlayTooltip::String("Compiler inserted reborrow".into())),
     });
     Some(())
@@ -620,9 +702,9 @@ fn chaining_hints(
             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()
-                }),
+                label: hint_iterator(sema, &famous_defs, config, &ty)
+                    .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string())
+                    .into(),
                 tooltip: Some(InlayTooltip::HoverRanged(file_id, expr.syntax().text_range())),
             });
         }
@@ -674,7 +756,7 @@ fn param_name_hints(
             InlayHint {
                 range,
                 kind: InlayKind::ParameterHint,
-                label: param_name,
+                label: param_name.into(),
                 tooltip: tooltip.map(|it| InlayTooltip::HoverOffset(it.file_id, it.range.start())),
             }
         });
@@ -705,7 +787,7 @@ fn binding_mode_hints(
         acc.push(InlayHint {
             range,
             kind: InlayKind::BindingModeHint,
-            label: r.to_string(),
+            label: r.to_string().into(),
             tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
         });
     });
@@ -720,7 +802,7 @@ fn binding_mode_hints(
             acc.push(InlayHint {
                 range,
                 kind: InlayKind::BindingModeHint,
-                label: bm.to_string(),
+                label: bm.to_string().into(),
                 tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
             });
         }
@@ -772,7 +854,7 @@ fn bind_pat_hints(
             None => pat.syntax().text_range(),
         },
         kind: InlayKind::TypeHint,
-        label,
+        label: label.into(),
         tooltip: pat
             .name()
             .map(|it| it.syntax().text_range())
@@ -2223,7 +2305,9 @@ fn main() {
                     InlayHint {
                         range: 147..172,
                         kind: ChainingHint,
-                        label: "B",
+                        label: [
+                            "B",
+                        ],
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2236,7 +2320,9 @@ fn main() {
                     InlayHint {
                         range: 147..154,
                         kind: ChainingHint,
-                        label: "A",
+                        label: [
+                            "A",
+                        ],
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2294,7 +2380,9 @@ fn main() {
                     InlayHint {
                         range: 143..190,
                         kind: ChainingHint,
-                        label: "C",
+                        label: [
+                            "C",
+                        ],
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2307,7 +2395,9 @@ fn main() {
                     InlayHint {
                         range: 143..179,
                         kind: ChainingHint,
-                        label: "B",
+                        label: [
+                            "B",
+                        ],
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2350,7 +2440,9 @@ fn main() {
                     InlayHint {
                         range: 246..283,
                         kind: ChainingHint,
-                        label: "B<X<i32, bool>>",
+                        label: [
+                            "B<X<i32, bool>>",
+                        ],
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2363,7 +2455,9 @@ fn main() {
                     InlayHint {
                         range: 246..265,
                         kind: ChainingHint,
-                        label: "A<X<i32, bool>>",
+                        label: [
+                            "A<X<i32, bool>>",
+                        ],
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2408,7 +2502,9 @@ fn main() {
                     InlayHint {
                         range: 174..241,
                         kind: ChainingHint,
-                        label: "impl Iterator<Item = ()>",
+                        label: [
+                            "impl Iterator<Item = ()>",
+                        ],
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2421,7 +2517,9 @@ fn main() {
                     InlayHint {
                         range: 174..224,
                         kind: ChainingHint,
-                        label: "impl Iterator<Item = ()>",
+                        label: [
+                            "impl Iterator<Item = ()>",
+                        ],
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2434,7 +2532,9 @@ fn main() {
                     InlayHint {
                         range: 174..206,
                         kind: ChainingHint,
-                        label: "impl Iterator<Item = ()>",
+                        label: [
+                            "impl Iterator<Item = ()>",
+                        ],
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2447,7 +2547,9 @@ fn main() {
                     InlayHint {
                         range: 174..189,
                         kind: ChainingHint,
-                        label: "&mut MyIter",
+                        label: [
+                            "&mut MyIter",
+                        ],
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2489,7 +2591,9 @@ fn main() {
                     InlayHint {
                         range: 124..130,
                         kind: TypeHint,
-                        label: "Struct",
+                        label: [
+                            "Struct",
+                        ],
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2502,7 +2606,9 @@ fn main() {
                     InlayHint {
                         range: 145..185,
                         kind: ChainingHint,
-                        label: "Struct",
+                        label: [
+                            "Struct",
+                        ],
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2515,7 +2621,9 @@ fn main() {
                     InlayHint {
                         range: 145..168,
                         kind: ChainingHint,
-                        label: "Struct",
+                        label: [
+                            "Struct",
+                        ],
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2528,7 +2636,9 @@ fn main() {
                     InlayHint {
                         range: 222..228,
                         kind: ParameterHint,
-                        label: "self",
+                        label: [
+                            "self",
+                        ],
                         tooltip: Some(
                             HoverOffset(
                                 FileId(
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index d61d69a090..0552330814 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -82,8 +82,8 @@ pub use crate::{
     highlight_related::{HighlightRelatedConfig, HighlightedRange},
     hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
     inlay_hints::{
-        ClosureReturnTypeHints, InlayHint, InlayHintsConfig, InlayKind, InlayTooltip,
-        LifetimeElisionHints, ReborrowHints,
+        ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
+        InlayTooltip, LifetimeElisionHints, ReborrowHints,
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs
index 5dc9c6c82a..8de5d33a19 100644
--- a/crates/parser/src/grammar/paths.rs
+++ b/crates/parser/src/grammar/paths.rs
@@ -118,11 +118,6 @@ 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!['(']) {
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 92df4d70fd..706e1742df 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -116,7 +116,6 @@ pub(crate) struct GlobalStateSnapshot {
     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 {}
@@ -257,7 +256,6 @@ impl GlobalState {
             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(),
         }
     }
 
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index d9b669afbe..3a661ddf06 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -1362,7 +1362,7 @@ pub(crate) fn handle_inlay_hints(
             .map(|it| {
                 to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it)
             })
-            .collect(),
+            .collect::<Result<Vec<_>>>()?,
     ))
 }
 
@@ -1504,11 +1504,7 @@ pub(crate) fn handle_semantic_tokens_full(
     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 highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?;
     let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 
     // Unconditionally cache the tokens
@@ -1527,11 +1523,7 @@ pub(crate) fn handle_semantic_tokens_full_delta(
     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 highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?;
     let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 
     let mut cache = snap.semantic_tokens_cache.lock();
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index e47f70fff3..ceb2a6d703 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -314,9 +314,7 @@ impl GlobalState {
                         let mut args = args.clone();
                         let mut path = path.clone();
 
-                        if let ProjectWorkspace::Cargo { sysroot, .. }
-                        | ProjectWorkspace::Json { sysroot, .. } = ws
-                        {
+                        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...");
@@ -349,8 +347,8 @@ impl GlobalState {
                             error
                         })
                     })
-                    .collect()
-            };
+                    .collect();
+            }
         }
 
         let watch = match files_config.watcher {
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 102cd60295..e083b9d0e3 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -9,8 +9,9 @@ use ide::{
     Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem,
     CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit,
     Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint,
-    InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity,
-    SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
+    InlayHintLabel, InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable,
+    Severity, SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange,
+    TextSize,
 };
 use itertools::Itertools;
 use serde_json::to_value;
@@ -426,9 +427,16 @@ pub(crate) fn inlay_hint(
     snap: &GlobalStateSnapshot,
     line_index: &LineIndex,
     render_colons: bool,
-    inlay_hint: InlayHint,
-) -> lsp_types::InlayHint {
-    lsp_types::InlayHint {
+    mut inlay_hint: InlayHint,
+) -> Result<lsp_types::InlayHint> {
+    match inlay_hint.kind {
+        InlayKind::ParameterHint if render_colons => inlay_hint.label.append_str(":"),
+        InlayKind::TypeHint if render_colons => inlay_hint.label.prepend_str(": "),
+        InlayKind::ClosureReturnTypeHint => inlay_hint.label.prepend_str(" -> "),
+        _ => {}
+    }
+
+    Ok(lsp_types::InlayHint {
         position: match inlay_hint.kind {
             // before annotated thing
             InlayKind::ParameterHint
@@ -459,15 +467,9 @@ pub(crate) fn inlay_hint(
             | InlayKind::ImplicitReborrowHint
             | InlayKind::TypeHint
             | InlayKind::ClosingBraceHint => false,
-            InlayKind::BindingModeHint => inlay_hint.label != "&",
+            InlayKind::BindingModeHint => inlay_hint.label.as_simple_str() != Some("&"),
             InlayKind::ParameterHint | InlayKind::LifetimeHint => true,
         }),
-        label: lsp_types::InlayHintLabel::String(match inlay_hint.kind {
-            InlayKind::ParameterHint if render_colons => format!("{}:", inlay_hint.label),
-            InlayKind::TypeHint if render_colons => format!(": {}", inlay_hint.label),
-            InlayKind::ClosureReturnTypeHint => format!(" -> {}", inlay_hint.label),
-            _ => inlay_hint.label.clone(),
-        }),
         kind: match inlay_hint.kind {
             InlayKind::ParameterHint => Some(lsp_types::InlayHintKind::PARAMETER),
             InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => {
@@ -506,9 +508,36 @@ pub(crate) fn inlay_hint(
         })(),
         tooltip: Some(match inlay_hint.tooltip {
             Some(ide::InlayTooltip::String(s)) => lsp_types::InlayHintTooltip::String(s),
-            _ => lsp_types::InlayHintTooltip::String(inlay_hint.label),
+            _ => lsp_types::InlayHintTooltip::String(inlay_hint.label.to_string()),
         }),
-    }
+        label: inlay_hint_label(snap, inlay_hint.label)?,
+    })
+}
+
+fn inlay_hint_label(
+    snap: &GlobalStateSnapshot,
+    label: InlayHintLabel,
+) -> Result<lsp_types::InlayHintLabel> {
+    Ok(match label.as_simple_str() {
+        Some(s) => lsp_types::InlayHintLabel::String(s.into()),
+        None => lsp_types::InlayHintLabel::LabelParts(
+            label
+                .parts
+                .into_iter()
+                .map(|part| {
+                    Ok(lsp_types::InlayHintLabelPart {
+                        value: part.text,
+                        tooltip: None,
+                        location: part
+                            .linked_location
+                            .map(|range| location(snap, range))
+                            .transpose()?,
+                        command: None,
+                    })
+                })
+                .collect::<Result<Vec<_>>>()?,
+        ),
+    })
 }
 
 static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1);
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index eadebbe8a2..8efd58e2c3 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -248,12 +248,8 @@ impl ast::WhereClause {
     }
 }
 
-pub trait Removable: AstNode {
-    fn remove(&self);
-}
-
-impl Removable for ast::TypeBoundList {
-    fn remove(&self) {
+impl ast::TypeBoundList {
+    pub fn remove(&self) {
         match self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) {
             Some(colon) => ted::remove_all(colon..=self.syntax().clone().into()),
             None => ted::remove(self.syntax()),
@@ -271,8 +267,8 @@ impl ast::PathSegment {
     }
 }
 
-impl Removable for ast::UseTree {
-    fn remove(&self) {
+impl ast::UseTree {
+    pub fn remove(&self) {
         for dir in [Direction::Next, Direction::Prev] {
             if let Some(next_use_tree) = neighbor(self, dir) {
                 let separators = self
@@ -286,9 +282,7 @@ impl Removable for ast::UseTree {
         }
         ted::remove(self.syntax());
     }
-}
 
-impl ast::UseTree {
     pub fn get_or_create_use_tree_list(&self) -> ast::UseTreeList {
         match self.use_tree_list() {
             Some(it) => it,
@@ -379,8 +373,8 @@ impl ast::UseTreeList {
     }
 }
 
-impl Removable for ast::Use {
-    fn remove(&self) {
+impl ast::Use {
+    pub fn remove(&self) {
         let next_ws = self
             .syntax()
             .next_sibling_or_token()
@@ -450,8 +444,8 @@ impl ast::Fn {
     }
 }
 
-impl Removable for ast::MatchArm {
-    fn remove(&self) {
+impl ast::MatchArm {
+    pub fn remove(&self) {
         if let Some(sibling) = self.syntax().prev_sibling_or_token() {
             if sibling.kind() == SyntaxKind::WHITESPACE {
                 ted::remove(sibling);
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index ba72e64425..28976d837b 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -322,7 +322,7 @@ impl ast::IntNumber {
 
     pub fn float_value(&self) -> Option<f64> {
         let (_, text, _) = self.split_into_parts();
-        text.replace('_', "").parse::<f64>().ok()
+        text.parse::<f64>().ok()
     }
 }
 
@@ -361,7 +361,7 @@ impl ast::FloatNumber {
 
     pub fn value(&self) -> Option<f64> {
         let (text, _) = self.split_into_parts();
-        text.replace('_', "").parse::<f64>().ok()
+        text.parse::<f64>().ok()
     }
 }
 
@@ -397,15 +397,6 @@ mod tests {
         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);
@@ -446,14 +437,6 @@ mod tests {
         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 {
diff --git a/lib/la-arena/src/lib.rs b/lib/la-arena/src/lib.rs
index ccaaf39917..50e8d06b66 100644
--- a/lib/la-arena/src/lib.rs
+++ b/lib/la-arena/src/lib.rs
@@ -322,43 +322,6 @@ impl<T> Arena<T> {
             .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();


Test patch:
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 4ea103e5d9..707e9e8450 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -3069,17 +3069,3 @@ fn main() {
         "#,
     );
 }
-
-#[test]
-fn nested_break() {
-    check_no_mismatches(
-        r#"
-fn func() {
-    let int = loop {
-        break 0;
-        break (break 0);
-    };
-}
-    "#,
-    );
-}
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index 21a8631976..e67c27aa2d 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -3900,34 +3900,6 @@ fn g(t: &(dyn Sync + T<Proj = ()> + Send)) {
     );
 }
 
-#[test]
-fn dyn_multiple_projection_bounds() {
-    check_no_mismatches(
-        r#"
-trait Trait {
-    type T;
-    type U;
-}
-
-fn f(t: &dyn Trait<T = (), U = ()>) {}
-fn g(t: &dyn Trait<U = (), T = ()>) {
-    f(t);
-}
-        "#,
-    );
-
-    check_types(
-        r#"
-trait Trait {
-    type T;
-}
-
-fn f(t: &dyn Trait<T = (), T = ()>) {}
-   //^&{unknown}
-        "#,
-    );
-}
-
 #[test]
 fn dyn_duplicate_auto_trait() {
     check_no_mismatches(
diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs
index 227e2300f9..a8c8622c1c 100644
--- a/crates/ide-assists/src/tests/generated.rs
+++ b/crates/ide-assists/src/tests/generated.rs
@@ -1390,7 +1390,7 @@ fn foo() {
 }
 "#####,
         r#####"
-
+type A = i32;
 fn id(x: i32) -> i32 {
     x
 };
diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs
index 8e26d889f9..925081ebf6 100644
--- a/crates/ide-completion/src/tests/expression.rs
+++ b/crates/ide-completion/src/tests/expression.rs
@@ -1,7 +1,7 @@
 //! Completion tests for expressions.
 use expect_test::{expect, Expect};
 
-use crate::tests::{check_edit, completion_list, BASE_ITEMS_FIXTURE};
+use crate::tests::{completion_list, BASE_ITEMS_FIXTURE};
 
 fn check(ra_fixture: &str, expect: Expect) {
     let actual = completion_list(&format!("{}{}", BASE_ITEMS_FIXTURE, ra_fixture));
@@ -670,78 +670,3 @@ fn main() {
         "#]],
     );
 }
-
-#[test]
-fn varaiant_with_struct() {
-    check_empty(
-        r#"
-pub struct YoloVariant {
-    pub f: usize
-}
-
-pub enum HH {
-    Yolo(YoloVariant),
-}
-
-fn brr() {
-    let t = HH::Yolo(Y$0);
-}
-"#,
-        expect![[r#"
-            en HH
-            fn brr()           fn()
-            st YoloVariant
-            st YoloVariant {…} YoloVariant { f: usize }
-            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 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 } }"#,
-    );
-}
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 4b8b47783d..685eb4521e 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -5113,61 +5113,3 @@ fn f() {
         "#]],
     );
 }
-
-#[test]
-fn static_const_macro_expanded_body() {
-    check(
-        r#"
-macro_rules! m {
-    () => {
-        pub const V: i8 = {
-            let e = 123;
-            f(e) // Prevent const eval from evaluating this constant, we want to print the body's code.
-        };
-    };
-}
-m!();
-fn main() { $0V; }
-"#,
-        expect![[r#"
-            *V*
-
-            ```rust
-            test
-            ```
-
-            ```rust
-            pub const V: i8 = {
-              let e = 123;
-              f(e)
-            }
-            ```
-        "#]],
-    );
-    check(
-        r#"
-macro_rules! m {
-    () => {
-        pub static V: i8 = {
-            let e = 123;
-        };
-    };
-}
-m!();
-fn main() { $0V; }
-"#,
-        expect![[r#"
-            *V*
-
-            ```rust
-            test
-            ```
-
-            ```rust
-            pub static V: i8 = {
-              let e = 123;
-            }
-            ```
-        "#]],
-    );
-}
diff --git a/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast b/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast
deleted file mode 100644
index b47a5a5c14..0000000000
--- a/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast
+++ /dev/null
@@ -1,43 +0,0 @@
-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"
diff --git a/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs b/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs
deleted file mode 100644
index 8efd93a7ff..0000000000
--- a/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-type F = Start::(Middle) -> (Middle)::End;